diff --git a/code/modules/mob/living/carbon/human/update_icons.dm b/code/modules/mob/living/carbon/human/update_icons.dm index e22ad5e66dc..b768039ac29 100644 --- a/code/modules/mob/living/carbon/human/update_icons.dm +++ b/code/modules/mob/living/carbon/human/update_icons.dm @@ -1,35 +1,1045 @@ -//LOOK G-MA, I'VE JOINED CARBON PROCS THAT ARE IDENTICAL IN ALL CASES INTO ONE PROC, I'M BETTER THAN LIFE() -//I thought about mob/living but silicons and simple_animals don't want this just yet. -//Right now just handles lying down, but could handle other cases later. -//IMPORTANT: Multiple animate() calls do not stack well, so try to do them all at once if you can. -/mob/living/carbon/update_transform() - var/matrix/ntransform = matrix(transform) //aka transform.Copy() - var/final_pixel_y = pixel_y - var/final_dir = dir - var/changed = 0 - if(lying != lying_prev) - changed++ - ntransform.TurnTo(lying_prev,lying) - if(lying == 0) //Lying to standing - final_pixel_y = get_standard_pixel_y_offset() - else //if(lying != 0) - if(lying_prev == 0) //Standing to lying - pixel_y = get_standard_pixel_y_offset() - final_pixel_y = get_standard_pixel_y_offset(lying) - if(dir & (EAST|WEST)) //Facing east or west - final_dir = pick(NORTH, SOUTH) //So you fall on your side rather than your face or ass - - lying_prev = lying //so we don't try to animate until there's been another change. - - if(resize != RESIZE_DEFAULT_SIZE) - changed++ - ntransform.Scale(resize) - resize = RESIZE_DEFAULT_SIZE - - if(changed) - animate(src, transform = ntransform, time = 2, pixel_y = final_pixel_y, dir = final_dir, easing = EASE_IN|EASE_OUT) - handle_transform_change() - floating = 0 // If we were without gravity, the bouncing animation got stopped, so we make sure we restart it in next life(). - -/mob/living/carbon/proc/handle_transform_change() - return \ No newline at end of file +/* + 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. + TODO: Proper documentation + icon_key is [species.race_key][g][husk][fat][hulk][skeleton][s_tone] +*/ +var/global/list/human_icon_cache = list() + + /////////////////////// + //UPDATE_ICONS SYSTEM// + /////////////////////// +/* +Calling this a system is perhaps a bit trumped up. It is essentially update_clothing dismantled into its +core parts. The key difference is that when we generate overlays we do not generate either lying or standing +versions. Instead, we generate both and store them in two fixed-length lists, both using the same list-index +(The indexes are in update_icons.dm): Each list for humans is (at the time of writing) of length 19. +This will hopefully be reduced as the system is refined. + + var/overlays_lying[19] //For the lying down stance + var/overlays_standing[19] //For the standing stance + +When we call update_icons, the 'lying' variable is checked and then the appropriate list is assigned to our overlays! +That in itself uses a tiny bit more memory (no more than all the ridiculous lists the game has already mind you). + +On the other-hand, it should be very CPU cheap in comparison to the old system. +In the old system, we updated all our overlays every life() call, even if we were standing still inside a crate! +or dead!. 25ish overlays, all generated from scratch every second for every xeno/human/monkey and then applied. +More often than not update_clothing was being called a few times in addition to that! CPU was not the only issue, +all those icons had to be sent to every client. So really the cost was extremely cumulative. To the point where +update_clothing would frequently appear in the top 10 most CPU intensive procs during profiling. + +Another feature of this new system is that our lists are indexed. This means we can update specific overlays! +So we only regenerate icons when we need them to be updated! This is the main saving for this system. + +In practice this means that: + everytime you fall over, we just switch between precompiled lists. Which is fast and cheap. + Everytime you do something minor like take a pen out of your pocket, we only update the in-hand overlay + etc... + + +There are several things that need to be remembered: + +> Whenever we do something that should cause an overlay to update (which doesn't use standard procs + ( i.e. you do something like l_hand = /obj/item/something new(src) ) + You will need to call the relevant update_inv_* proc: + update_inv_head() + update_inv_wear_suit() + update_inv_gloves() + update_inv_shoes() + update_inv_w_uniform() + update_inv_glasse() + update_inv_l_hand() + update_inv_r_hand() + update_inv_belt() + update_inv_wear_id() + update_inv_ears() + update_inv_s_store() + update_inv_pockets() + update_inv_back() + update_inv_handcuffed() + update_inv_wear_mask() + + All of these are named after the variable they update from. They are defined at the mob/ level like + update_clothing was, so you won't cause undefined proc runtimes with usr.update_inv_wear_id() if the usr is a + slime etc. Instead, it'll just return without doing any work. So no harm in calling it for slimes and such. + + +> There are also these special cases: + update_mutations() //handles updating your appearance for certain mutations. e.g TK head-glows + update_mutantrace() //handles updating your appearance after setting the mutantrace var + UpdateDamageIcon() //handles damage overlays for brute/burn damage //(will rename this when I geta round to it) + update_body() //Handles updating your mob's icon to reflect their gender/race/complexion etc + update_hair() //Handles updating your hair overlay (used to be update_face, but mouth and + ...eyes were merged into update_body) + update_targeted() // Updates the target overlay when someone points a gun at you + +> All of these procs update our overlays_lying and overlays_standing, and then call update_icons() by default. + If you wish to update several overlays at once, you can set the argument to 0 to disable the update and call + it manually: + e.g. + update_inv_head(0) + update_inv_l_hand(0) + update_inv_r_hand() //<---calls update_icons() + + or equivillantly: + update_inv_head(0) + update_inv_l_hand(0) + update_inv_r_hand(0) + update_icons() + +> If you need to update all overlays you can use regenerate_icons(). it works exactly like update_clothing used to. + +> I reimplimented an old unused variable which was in the code called (coincidentally) var/update_icon + It can be used as another method of triggering regenerate_icons(). It's basically a flag that when set to non-zero + will call regenerate_icons() at the next life() call and then reset itself to 0. + The idea behind it is icons are regenerated only once, even if multiple events requested it. + +This system is confusing and is still a WIP. It's primary goal is speeding up the controls of the game whilst +reducing processing costs. So please bear with me while I iron out the kinks. It will be worth it, I promise. +If I can eventually free var/lying stuff from the life() process altogether, stuns/death/status stuff +will become less affected by lag-spikes and will be instantaneous! :3 + +If you have any questions/constructive-comments/bugs-to-report/or have a massivly devestated butt... +Please contact me on #coderbus IRC. ~Carn x +*/ + +//Human Overlays Indexes///////// +#define MUTANTRACE_LAYER 1 +#define MUTATIONS_LAYER 2 +#define DAMAGE_LAYER 3 +#define UNIFORM_LAYER 4 +#define ID_LAYER 5 +#define SHOES_LAYER 6 +#define GLOVES_LAYER 7 +#define EARS_LAYER 8 +#define SUIT_LAYER 9 +#define GLASSES_LAYER 10 +#define BELT_LAYER 11 //Possible make this an overlay of somethign required to wear a belt? +#define TAIL_LAYER 12 //bs12 specific. this hack is probably gonna come back to haunt me +#define SUIT_STORE_LAYER 13 +#define BACK_LAYER 14 +#define HAIR_LAYER 15 //TODO: make part of head layer? +#define FACEMASK_LAYER 16 +#define HEAD_LAYER 17 +#define COLLAR_LAYER 18 +#define HANDCUFF_LAYER 19 +#define LEGCUFF_LAYER 20 +#define L_HAND_LAYER 21 +#define R_HAND_LAYER 22 +#define TARGETED_LAYER 23 //BS12: Layer for the target overlay from weapon targeting system +#define FIRE_LAYER 24 //If you're on fire +#define TOTAL_LAYERS 24 + + + +/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 + var/icon/skeleton + + +/mob/living/carbon/human/proc/apply_overlay(cache_index) + var/image/I = overlays_standing[cache_index] + if(I) + overlays += I + +/mob/living/carbon/human/proc/remove_overlay(cache_index) + if(overlays_standing[cache_index]) + overlays -= overlays_standing[cache_index] + overlays_standing[cache_index] = null + +//UPDATES OVERLAYS FROM OVERLAYS_LYING/OVERLAYS_STANDING +//this proc is messy as I was forced to include some old laggy cloaking code to it so that I don't break cloakers +//I'll work on removing that stuff by rewriting some of the cloaking stuff at a later date. +/mob/living/carbon/human/update_icons() + + update_hud() //TODO: remove the need for this + + var/stealth = 0 + for(var/obj/item/weapon/cloaking_device/S in list(l_hand,r_hand,belt,l_store,r_store)) + if(S.active) + stealth = 1 + break + + if(stealth) + icon = 'icons/mob/human.dmi' + icon_state = "body_cloaked" + var/image/I = overlays_standing[L_HAND_LAYER] + if(istype(I)) overlays += I + I = overlays_standing[R_HAND_LAYER] + if(istype(I)) overlays += I + else + icon = stand_icon + if(overlays.len != overlays_standing.len) + overlays.Cut() + + for(var/thing in overlays_standing) + if(thing) overlays += thing + + update_transform() + +var/global/list/damage_icon_parts = list() + +//DAMAGE OVERLAYS +//constructs damage icon for each organ from mask * damage field and saves it in our overlays_ lists +/mob/living/carbon/human/UpdateDamageIcon(var/update_icons=1) + // first check whether something actually changed about damage appearance + var/damage_appearance = "" + + for(var/obj/item/organ/external/O in organs) + if(O.is_stump()) + continue + if(O.status & ORGAN_DESTROYED) damage_appearance += "d" + else + damage_appearance += O.damage_state + + if(damage_appearance == previous_damage_appearance) + // nothing to do here + return + + previous_damage_appearance = damage_appearance + + var/icon/standing = new /icon(species.damage_overlays, "00") + + var/image/standing_image = new /image("icon" = standing) + + // blend the individual damage states with our icons + for(var/obj/item/organ/external/O in organs) + if(O.is_stump()) + continue + if(!(O.status & ORGAN_DESTROYED)) + O.update_icon() + if(O.damage_state == "00") continue + var/icon/DI + var/cache_index = "[O.damage_state]/[O.icon_name]/[species.blood_color]/[species.name]" + + if(damage_icon_parts[cache_index] == null) + DI = new /icon(species.damage_overlays, O.damage_state) // the damage icon for whole human + DI.Blend(new /icon(species.damage_mask, O.icon_name), ICON_MULTIPLY) // mask with this organ's pixels + DI.Blend(species.blood_color, ICON_MULTIPLY) + damage_icon_parts[cache_index] = DI + else + DI = damage_icon_parts[cache_index] + standing_image.overlays += DI + + overlays_standing[DAMAGE_LAYER] = standing_image + + if(update_icons) update_icons() + +//BASE MOB SPRITE +/mob/living/carbon/human/proc/update_body(var/update_icons=1) + + 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) + + //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. + if(stand_icon) + qdel(stand_icon) + stand_icon = new(species.icon_template ? species.icon_template : 'icons/mob/human.dmi',"blank") + var/icon_key = "" + var/obj/item/organ/internal/eyes/eyes = get_int_organ(/obj/item/organ/internal/eyes) + + if(eyes) + icon_key += "[rgb(eyes.eye_colour[1], eyes.eye_colour[2], eyes.eye_colour[3])]" + else + icon_key += "#000000" + + 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.status & ORGAN_DESTROYED)) + icon_key += "0" + else if(part.status & ORGAN_ROBOT) + icon_key += "2[part.model ? "-[part.model]": ""]" + else if(part.status & ORGAN_DEAD) + icon_key += "3" + else + icon_key += "1" + + if(part) + icon_key += "[part.species.race_key]" + icon_key += "[part.dna.GetUIState(DNA_UI_GENDER)]" + icon_key += "[part.dna.GetUIValue(DNA_UI_SKIN_TONE)]" + if(part.s_col) + icon_key += "[rgb(part.s_col[1], part.s_col[2], part.s_col[3])]" + + icon_key = "[icon_key][husk ? 1 : 0][fat ? 1 : 0][hulk ? 1 : 0][skeleton ? 1 : 0]" + + var/icon/base_icon + if(human_icon_cache[icon_key]) + base_icon = human_icon_cache[icon_key] + else + //BEGIN CACHED ICON GENERATION. + var/obj/item/organ/external/chest = get_organ("chest") + base_icon = chest.get_icon() + + for(var/obj/item/organ/external/part in organs) + var/icon/temp = part.get_icon(skeleton) + //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('icons/mob/human.dmi',"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) + 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_UNDERLAY) + else + base_icon.Blend(temp, ICON_OVERLAY) + + if(!skeleton) + if(husk) + base_icon.ColorTone(husk_color_mod) + else if(hulk) + var/list/tone = ReadRGB(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 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) + + human_icon_cache[icon_key] = base_icon + + //END CACHED ICON GENERATION. + stand_icon.Blend(base_icon,ICON_OVERLAY) + + //Underwear + if(underwear && species.clothing_flags & HAS_UNDERWEAR) + var/datum/sprite_accessory/underwear/U = underwear_list[underwear] + if(U) + stand_icon.Blend(new /icon(U.icon, "uw_[U.icon_state]_s"), ICON_OVERLAY) + + if(undershirt && species.clothing_flags & HAS_UNDERSHIRT) + var/datum/sprite_accessory/undershirt/U2 = undershirt_list[undershirt] + if(U2) + stand_icon.Blend(new /icon(U2.icon, "us_[U2.icon_state]_s"), ICON_OVERLAY) + + + if(socks && species.clothing_flags & HAS_SOCKS) + var/datum/sprite_accessory/socks/U3 = socks_list[socks] + if(U3) + stand_icon.Blend(new /icon(U3.icon, "sk_[U3.icon_state]_s"), ICON_OVERLAY) + + + if(update_icons) + update_icons() + + if(lip_style && species && species.flags & HAS_LIPS) + var/icon/lips = icon("icon"='icons/mob/human_face.dmi', "icon_state"="lips_[lip_style]_s") + lips.Blend(lip_color, ICON_ADD) + + stand_icon.Blend(lips, ICON_OVERLAY) + + //tail + update_tail_layer(0) + + +//HAIR OVERLAY +/mob/living/carbon/human/proc/update_hair(var/update_icons=1) + //Reset our hair + overlays_standing[HAIR_LAYER] = null + + var/obj/item/organ/external/head/head_organ = get_organ("head") + if(!head_organ || head_organ.is_stump() || (head_organ.status & ORGAN_DESTROYED) ) + if(update_icons) update_icons() + return + + //masks and helmets can obscure our hair, unless we're a synthetic + if( (head && (head.flags & BLOCKHAIR)) || (wear_mask && (wear_mask.flags & BLOCKHAIR))) + if(update_icons) update_icons() + return + + //base icons + var/icon/face_standing = new /icon('icons/mob/human_face.dmi',"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) + if(src.species.name 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), ICON_ADD) + face_standing.Blend(facial_s, ICON_OVERLAY) + else + //warning("Invalid f_style for [species.name]: [f_style]") + + if(!get_int_organ(/obj/item/organ/internal/brain)) + face_standing += icon("icon"='icons/mob/human_face.dmi', "icon_state" = "debrained_s") + + if(h_style && !(head && (head.flags & BLOCKHEADHAIR) && !(isSynthetic()))) + var/datum/sprite_accessory/hair_style = hair_styles_list[h_style] + if(hair_style && hair_style.species_allowed) + if(src.species.name in hair_style.species_allowed) + var/icon/hair_s = new/icon("icon" = hair_style.icon, "icon_state" = "[hair_style.icon_state]_s") + if(hair_style.do_colouration) + hair_s.Blend(rgb(r_hair, g_hair, b_hair), ICON_ADD) + + face_standing.Blend(hair_s, ICON_OVERLAY) + else + //warning("Invalid h_style for [species.name]: [h_style]") + + overlays_standing[HAIR_LAYER] = image(face_standing) + + if(update_icons) update_icons() + +/mob/living/carbon/human/update_mutations(var/update_icons=1) + var/fat + if(FAT in mutations) + fat = "fat" + + var/image/standing = image("icon" = 'icons/effects/genetics.dmi') + var/add_image = 0 + var/g = "m" + if(gender == FEMALE) g = "f" + // DNA2 - Drawing underlays. + 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 + add_image = 1 + for(var/mut in mutations) + switch(mut) + /* + if(HULK) + if(fat) + standing.underlays += "hulk_[fat]_s" + else + standing.underlays += "hulk_[g]_s" + add_image = 1 + if(RESIST_COLD) + standing.underlays += "fire[fat]_s" + add_image = 1 + if(RESIST_HEAT) + standing.underlays += "cold[fat]_s" + add_image = 1 + if(TK) + standing.underlays += "telekinesishead[fat]_s" + add_image = 1 + */ + if(LASER) + standing.overlays += "lasereyes_s" + add_image = 1 + if((RESIST_COLD in mutations) && (RESIST_HEAT in mutations)) + standing.underlays -= "cold[fat]_s" + standing.underlays -= "fire[fat]_s" + standing.underlays += "coldfire[fat]_s" + if(add_image) + overlays_standing[MUTATIONS_LAYER] = standing + else + overlays_standing[MUTATIONS_LAYER] = null + if(update_icons) update_icons() + + +/mob/living/carbon/human/proc/update_mutantrace(var/update_icons=1) +//BS12 EDIT + var/skel = (SKELETON in src.mutations) + if(skel) + skeleton = 'icons/mob/human_races/r_skeleton.dmi' + else + skeleton = null + + update_hair(0) + if(update_icons) update_icons() + +//Call when target overlay should be added/removed +/mob/living/carbon/human/update_targeted(var/update_icons=1) + if (targeted_by && target_locked) + overlays_standing[TARGETED_LAYER] = target_locked + else if (!targeted_by && target_locked) + qdel(target_locked) + if (!targeted_by) + overlays_standing[TARGETED_LAYER] = null + if(update_icons) update_icons() + +/mob/living/carbon/human/update_fire() + remove_overlay(FIRE_LAYER) + if(on_fire) + overlays_standing[FIRE_LAYER] = image("icon"=fire_dmi, "icon_state"=fire_sprite, "layer"=-FIRE_LAYER) + else + overlays_standing[FIRE_LAYER] = null + apply_overlay(FIRE_LAYER) + +/* --------------------------------------- */ +//For legacy support. +/mob/living/carbon/human/regenerate_icons() + ..() + if(notransform) return + update_mutations(0) + update_body(0) + update_hair(0) + update_mutantrace(0) + update_inv_w_uniform(0,0) + update_inv_wear_id(0) + update_inv_gloves(0,0) + update_inv_glasses(0) + update_inv_ears(0) + update_inv_shoes(0,0) + update_inv_s_store(0) + update_inv_wear_mask(0) + update_inv_head(0,0) + update_inv_belt(0) + update_inv_back(0) + update_inv_wear_suit(0) + update_inv_r_hand(0) + update_inv_l_hand(0) + update_inv_handcuffed(0) + update_inv_legcuffed(0) + update_inv_pockets(0) + update_inv_wear_pda(0) + UpdateDamageIcon() + update_icons() + //Hud Stuff + update_hud() + update_fire() +/* --------------------------------------- */ +//vvvvvv UPDATE_INV PROCS vvvvvv + +/mob/living/carbon/human/update_inv_w_uniform(var/update_icons=1) + if(w_uniform && istype(w_uniform, /obj/item/clothing/under) ) + w_uniform.screen_loc = ui_iclothing + var/t_color = w_uniform.item_color + if(!t_color) t_color = icon_state + var/image/standing = image("icon_state" = "[t_color]_s") + + if(FAT in mutations) + if(w_uniform.flags&ONESIZEFITSALL) + standing.icon = 'icons/mob/uniform_fat.dmi' + else + src << "\red You burst out of \the [w_uniform]!" + unEquip(w_uniform) + return + else + standing.icon = 'icons/mob/uniform.dmi' + + if(w_uniform.icon_override) + standing.icon = w_uniform.icon_override + else if(w_uniform.sprite_sheets && w_uniform.sprite_sheets[species.name]) + standing.icon = w_uniform.sprite_sheets[species.name] + + if(w_uniform.blood_DNA) + var/image/bloodsies = image("icon" = species.blood_mask, "icon_state" = "uniformblood") + bloodsies.color = w_uniform.blood_color + standing.overlays += bloodsies + + if(w_uniform:accessories.len) //WE CHECKED THE TYPE ABOVE. THIS REALLY SHOULD BE FINE. + for(var/obj/item/clothing/accessory/A in w_uniform:accessories) + var/tie_color = A.item_color + if(!tie_color) tie_color = A.icon_state + standing.overlays += image("icon" = 'icons/mob/ties.dmi', "icon_state" = "[tie_color]") + + overlays_standing[UNIFORM_LAYER] = standing + else + overlays_standing[UNIFORM_LAYER] = null + // Automatically drop anything in store / id / belt if you're not wearing a uniform. //CHECK IF NECESARRY + for( var/obj/item/thing in list(r_store, l_store, wear_id, wear_pda, belt) ) // + if(thing) // + unEquip(thing) // + if (client) // + client.screen -= thing // + // + if (thing) // + thing.loc = loc // + thing.dropped(src) // + thing.layer = initial(thing.layer) + if(update_icons) update_icons() + +/mob/living/carbon/human/update_inv_wear_id(var/update_icons=1) + if(wear_id) + wear_id.screen_loc = ui_id //TODO + if(w_uniform && w_uniform:displays_id) + overlays_standing[ID_LAYER] = image("icon" = 'icons/mob/mob.dmi', "icon_state" = "id") + else + overlays_standing[ID_LAYER] = null + else + overlays_standing[ID_LAYER] = null + + if(update_icons) update_icons() + +/mob/living/carbon/human/update_inv_gloves(var/update_icons=1) + if(gloves) + var/t_state = gloves.item_state + if(!t_state) t_state = gloves.icon_state + + var/image/standing + if(gloves.icon_override) + standing = image("icon" = gloves.icon_override, "icon_state" = "[t_state]") + else if(gloves.sprite_sheets && gloves.sprite_sheets[species.name]) + standing = image("icon" = gloves.sprite_sheets[species.name], "icon_state" = "[t_state]") + else + standing = image("icon" = 'icons/mob/hands.dmi', "icon_state" = "[t_state]") + + if(gloves.blood_DNA) + var/image/bloodsies = image("icon" = species.blood_mask, "icon_state" = "bloodyhands") + bloodsies.color = gloves.blood_color + standing.overlays += bloodsies + gloves.screen_loc = ui_gloves + overlays_standing[GLOVES_LAYER] = standing + else + if(blood_DNA) + var/image/bloodsies = image("icon" = species.blood_mask, "icon_state" = "bloodyhands") + bloodsies.color = hand_blood_color + overlays_standing[GLOVES_LAYER] = bloodsies + else + overlays_standing[GLOVES_LAYER] = null + if(update_icons) update_icons() + + +/mob/living/carbon/human/update_inv_glasses(var/update_icons=1) + if(glasses) + + if(glasses.icon_override) + overlays_standing[GLASSES_LAYER] = image("icon" = glasses.icon_override, "icon_state" = "[glasses.icon_state]") + else if(glasses.sprite_sheets && glasses.sprite_sheets[species.name]) + overlays_standing[GLASSES_LAYER]= image("icon" = glasses.sprite_sheets[species.name], "icon_state" = "[glasses.icon_state]") + else + overlays_standing[GLASSES_LAYER]= image("icon" = 'icons/mob/eyes.dmi', "icon_state" = "[glasses.icon_state]") + + else + overlays_standing[GLASSES_LAYER] = null + if(update_icons) update_icons() + +/mob/living/carbon/human/update_inv_ears(var/update_icons=1) + if(l_ear || r_ear) + if(l_ear) + + var/t_type = l_ear.icon_state + if(l_ear.icon_override) + t_type = "[t_type]_l" + overlays_standing[EARS_LAYER] = image("icon" = l_ear.icon_override, "icon_state" = "[t_type]") + else if(l_ear.sprite_sheets && l_ear.sprite_sheets[species.name]) + t_type = "[t_type]_l" + overlays_standing[EARS_LAYER] = image("icon" = l_ear.sprite_sheets[species.name], "icon_state" = "[t_type]") + else + overlays_standing[EARS_LAYER] = image("icon" = 'icons/mob/ears.dmi', "icon_state" = "[t_type]") + + if(r_ear) + + var/t_type = r_ear.icon_state + if(r_ear.icon_override) + t_type = "[t_type]_r" + overlays_standing[EARS_LAYER] = image("icon" = r_ear.icon_override, "icon_state" = "[t_type]") + else if(r_ear.sprite_sheets && r_ear.sprite_sheets[species.name]) + t_type = "[t_type]_r" + overlays_standing[EARS_LAYER] = image("icon" = r_ear.sprite_sheets[species.name], "icon_state" = "[t_type]") + else + overlays_standing[EARS_LAYER] = image("icon" = 'icons/mob/ears.dmi', "icon_state" = "[t_type]") + + else + overlays_standing[EARS_LAYER] = null + if(update_icons) update_icons() + +/mob/living/carbon/human/update_inv_shoes(var/update_icons=1) + if(shoes) + + var/image/standing + if(shoes.icon_override) + standing = image("icon" = shoes.icon_override, "icon_state" = "[shoes.icon_state]") + else if(shoes.sprite_sheets && shoes.sprite_sheets[species.name]) + standing = image("icon" = shoes.sprite_sheets[species.name], "icon_state" = "[shoes.icon_state]") + else + standing = image("icon" = 'icons/mob/feet.dmi', "icon_state" = "[shoes.icon_state]") + + + if(shoes.blood_DNA) + var/image/bloodsies = image("icon" = species.blood_mask, "icon_state" = "shoeblood") + bloodsies.color = shoes.blood_color + standing.overlays += bloodsies + overlays_standing[SHOES_LAYER] = standing + else + if(feet_blood_DNA) + var/image/bloodsies = image("icon" = species.blood_mask, "icon_state" = "shoeblood") + bloodsies.color = feet_blood_color + overlays_standing[SHOES_LAYER] = bloodsies + else + overlays_standing[SHOES_LAYER] = null + if(update_icons) update_icons() + +/mob/living/carbon/human/update_inv_s_store(var/update_icons=1) + if(s_store) + var/t_state = s_store.item_state + if(!t_state) + t_state = s_store.icon_state + var/dmi='icons/mob/belt_mirror.dmi' + overlays_standing[SUIT_STORE_LAYER] = image("icon" = dmi, "icon_state" = "[t_state]") + s_store.screen_loc = ui_sstore1 //TODO + else + overlays_standing[SUIT_STORE_LAYER] = null + if(update_icons) update_icons() + + +/mob/living/carbon/human/update_inv_head(var/update_icons=1) + if(head) + head.screen_loc = ui_head //TODO + var/image/standing + if(head.icon_override) + standing = image("icon" = head.icon_override, "icon_state" = "[head.icon_state]") + else if(head.sprite_sheets && head.sprite_sheets[species.name]) + standing = image("icon" = head.sprite_sheets[species.name], "icon_state" = "[head.icon_state]") + else + standing = image("icon" = 'icons/mob/head.dmi', "icon_state" = "[head.icon_state]") + + if(head.blood_DNA) + var/image/bloodsies = image("icon" = species.blood_mask, "icon_state" = "helmetblood") + bloodsies.color = head.blood_color + standing.overlays += bloodsies + overlays_standing[HEAD_LAYER] = standing + + + else + overlays_standing[HEAD_LAYER] = null + if(update_icons) update_icons() + +/mob/living/carbon/human/update_inv_belt(var/update_icons=1) + if(belt) + belt.screen_loc = ui_belt //TODO + var/t_state = belt.item_state + if(!t_state) t_state = belt.icon_state + + if(belt.icon_override) + t_state = "[t_state]_be" + overlays_standing[BELT_LAYER] = image("icon" = belt.icon_override, "icon_state" = "[t_state]") + else if(belt.sprite_sheets && belt.sprite_sheets[species.name]) + overlays_standing[BELT_LAYER] = image("icon" = belt.sprite_sheets[species.name], "icon_state" = "[t_state]") + else + overlays_standing[BELT_LAYER] = image("icon" = 'icons/mob/belt.dmi', "icon_state" = "[t_state]") + else + overlays_standing[BELT_LAYER] = null + if(update_icons) update_icons() + + +/mob/living/carbon/human/update_inv_wear_suit(var/update_icons=1) + if( wear_suit && istype(wear_suit, /obj/item/clothing/suit) ) //TODO check this + wear_suit.screen_loc = ui_oclothing //TODO + + var/image/standing + if(wear_suit.icon_override) + standing = image("icon" = wear_suit.icon_override, "icon_state" = "[wear_suit.icon_state]") + else if(wear_suit.sprite_sheets && wear_suit.sprite_sheets[species.name]) + standing = image("icon" = wear_suit.sprite_sheets[species.name], "icon_state" = "[wear_suit.icon_state]") + else if(FAT in mutations) + if(wear_suit.flags&ONESIZEFITSALL) + standing = image("icon" = 'icons/mob/suit_fat.dmi', "icon_state" = "[wear_suit.icon_state]") + else + src << "\red You burst out of \the [wear_suit]!" + unEquip(wear_suit) + return + else + standing = image("icon" = 'icons/mob/suit.dmi', "icon_state" = "[wear_suit.icon_state]") + + + if( istype(wear_suit, /obj/item/clothing/suit/straight_jacket) ) + unEquip(handcuffed) + drop_l_hand() + drop_r_hand() + + + if(wear_suit.blood_DNA) + var/obj/item/clothing/suit/S = wear_suit + var/image/bloodsies = image("icon" = species.blood_mask, "icon_state" = "[S.blood_overlay_type]blood") + bloodsies.color = wear_suit.blood_color + standing.overlays += bloodsies + + + overlays_standing[SUIT_LAYER] = standing + + update_tail_layer(0) + + else + overlays_standing[SUIT_LAYER] = null + + update_tail_layer(0) + + update_collar(0) + + if(update_icons) update_icons() + +/mob/living/carbon/human/update_inv_pockets(var/update_icons=1) + if(l_store) l_store.screen_loc = ui_storage1 //TODO + if(r_store) r_store.screen_loc = ui_storage2 //TODO + if(update_icons) update_icons() + +/mob/living/carbon/human/update_inv_wear_pda(var/update_icons=1) + if(wear_pda) wear_pda.screen_loc = ui_pda + if(update_icons) update_icons() + +/mob/living/carbon/human/update_inv_wear_mask(var/update_icons=1) + if( wear_mask && ( istype(wear_mask, /obj/item/clothing/mask) || istype(wear_mask, /obj/item/clothing/accessory) ) ) + wear_mask.screen_loc = ui_mask //TODO + + var/image/standing + if(wear_mask.icon_override) + standing = image("icon" = wear_mask.icon_override, "icon_state" = "[wear_mask.icon_state]") + else if(wear_mask.sprite_sheets && wear_mask.sprite_sheets[species.name]) + standing = image("icon" = wear_mask.sprite_sheets[species.name], "icon_state" = "[wear_mask.icon_state]") + else + standing = image("icon" = 'icons/mob/mask.dmi', "icon_state" = "[wear_mask.icon_state]") + + if( !istype(wear_mask, /obj/item/clothing/mask/cigarette) && wear_mask.blood_DNA ) + var/image/bloodsies = image("icon" = species.blood_mask, "icon_state" = "maskblood") + bloodsies.color = wear_mask.blood_color + standing.overlays += bloodsies + overlays_standing[FACEMASK_LAYER] = standing + else + overlays_standing[FACEMASK_LAYER] = null + if(update_icons) update_icons() + + +/mob/living/carbon/human/update_inv_back(var/update_icons=1) + if(back) + back.screen_loc = ui_back //TODO + + //determine the icon to use + var/icon/overlay_icon + if(back.icon_override) + overlay_icon = back.icon_override + else if(istype(back, /obj/item/weapon/rig)) + //If this is a rig and a mob_icon is set, it will take species into account in the rig update_icon() proc. + var/obj/item/weapon/rig/rig = back + overlay_icon = rig.mob_icon + else if(back.sprite_sheets && back.sprite_sheets[species.name]) + overlay_icon = back.sprite_sheets[species.name] + else + overlay_icon = icon('icons/mob/back.dmi', "[back.icon_state]") + + //determine state to use + var/overlay_state + if(back.item_state) + overlay_state = back.item_state + else + overlay_state = back.icon_state + + //create the image + overlays_standing[BACK_LAYER] = image(icon = overlay_icon, icon_state = overlay_state) + else + overlays_standing[BACK_LAYER] = null + + if(update_icons) update_icons() + + +/mob/living/carbon/human/update_hud() //TODO: do away with this if possible + if(client) + client.screen |= contents + if(hud_used) + hud_used.hidden_inventory_update() //Updates the screenloc of the items on the 'other' inventory bar + + +/mob/living/carbon/human/update_inv_handcuffed(var/update_icons=1) + if(handcuffed) + drop_r_hand() + drop_l_hand() + stop_pulling() //TODO: should be handled elsewhere + if(hud_used) //hud handcuff icons + var/obj/screen/inventory/R = hud_used.adding[7] + var/obj/screen/inventory/L = hud_used.adding[8] + R.overlays += image("icon"='icons/mob/screen_gen.dmi', "icon_state"="markus") + L.overlays += image("icon"='icons/mob/screen_gen.dmi', "icon_state"="gabrielle") + if(istype(handcuffed, /obj/item/weapon/restraints/handcuffs/pinkcuffs)) + overlays_standing[HANDCUFF_LAYER] = image("icon" = 'icons/mob/mob.dmi', "icon_state" = "pinkcuff1") + else + overlays_standing[HANDCUFF_LAYER] = image("icon" = 'icons/mob/mob.dmi', "icon_state" = "handcuff1") + else + overlays_standing[HANDCUFF_LAYER] = null + if(hud_used) + var/obj/screen/inventory/R = hud_used.adding[7] + var/obj/screen/inventory/L = hud_used.adding[8] + R.overlays = null + L.overlays = null + if(update_icons) update_icons() + +/mob/living/carbon/human/update_inv_legcuffed(var/update_icons=1) + if(legcuffed) + overlays_standing[LEGCUFF_LAYER] = image("icon" = 'icons/mob/mob.dmi', "icon_state" = "legcuff1") + if(src.m_intent != "walk") + src.m_intent = "walk" + if(src.hud_used && src.hud_used.move_intent) + src.hud_used.move_intent.icon_state = "walking" + + else + overlays_standing[LEGCUFF_LAYER] = null + if(update_icons) update_icons() + + +/mob/living/carbon/human/update_inv_r_hand(var/update_icons=1) + if(r_hand) + r_hand.screen_loc = ui_rhand //TODO + var/t_state = r_hand.item_state + if(!t_state) t_state = r_hand.icon_state + + var/image/I = image("icon" = r_hand.righthand_file, "icon_state"="[t_state]") + I = center_image(I, r_hand.inhand_x_dimension, r_hand.inhand_y_dimension) + overlays_standing[R_HAND_LAYER] = I + + if (handcuffed) drop_r_hand() + else + overlays_standing[R_HAND_LAYER] = null + if(update_icons) update_icons() + + +/mob/living/carbon/human/update_inv_l_hand(var/update_icons=1) + if(l_hand) + l_hand.screen_loc = ui_lhand //TODO + var/t_state = l_hand.item_state + if(!t_state) t_state = l_hand.icon_state + + var/image/I = image("icon" = l_hand.lefthand_file, "icon_state"="[t_state]") + I = center_image(I, l_hand.inhand_x_dimension, l_hand.inhand_y_dimension) + overlays_standing[L_HAND_LAYER] = I + + if (handcuffed) drop_l_hand() + else + overlays_standing[L_HAND_LAYER] = null + if(update_icons) update_icons() + + + +/mob/living/carbon/human/proc/update_tail_layer(var/update_icons=1) + overlays_standing[TAIL_LAYER] = null + + if(body_accessory) + if(body_accessory.try_restrictions(src)) + var/icon/accessory_s = new/icon("icon" = body_accessory.icon, "icon_state" = body_accessory.icon_state) + accessory_s.Blend(rgb(r_skin, g_skin, b_skin), body_accessory.blend_mode) + + overlays_standing[TAIL_LAYER] = image(accessory_s, "pixel_x" = body_accessory.pixel_x_offset, "pixel_y" = body_accessory.pixel_y_offset) + + + else if(species.tail && species.bodyflags & HAS_TAIL) //no tailless tajaran + if(!wear_suit || !(wear_suit.flags_inv & HIDETAIL) && !istype(wear_suit, /obj/item/clothing/suit/space)) + var/icon/tail_s = new/icon("icon" = 'icons/effects/species.dmi', "icon_state" = "[species.tail]_s") + tail_s.Blend(rgb(r_skin, g_skin, b_skin), ICON_ADD) + + overlays_standing[TAIL_LAYER] = image(tail_s) + + if(update_icons) + update_icons() + + +/mob/living/carbon/human/proc/start_tail_wagging(var/update_icons=1) + overlays_standing[TAIL_LAYER] = null + + if(body_accessory) + var/icon/accessory_s = new/icon("icon" = body_accessory.get_animated_icon(), "icon_state" = body_accessory.get_animated_icon_state()) + accessory_s.Blend(rgb(r_skin, g_skin, b_skin), body_accessory.blend_mode) + + overlays_standing[TAIL_LAYER] = image(accessory_s, "pixel_x" = body_accessory.pixel_x_offset, "pixel_y" = body_accessory.pixel_y_offset) + + else if(species.tail && species.bodyflags & HAS_TAIL) + var/icon/tailw_s = new/icon("icon" = 'icons/effects/species.dmi', "icon_state" = "[species.tail]w_s") + tailw_s.Blend(rgb(r_skin, g_skin, b_skin), ICON_ADD) + + overlays_standing[TAIL_LAYER] = image(tailw_s) + + if(update_icons) + update_icons() + +/mob/living/carbon/human/proc/stop_tail_wagging(var/update_icons=1) + overlays_standing[TAIL_LAYER] = null + + update_tail_layer(update_icons) //just trigger a full update for normal stationary sprites + +/mob/living/carbon/human/handle_transform_change() + ..() + update_tail_layer() + +//Adds a collar overlay above the helmet layer if the suit has one +// Suit needs an identically named sprite in icons/mob/collar.dmi +/mob/living/carbon/human/proc/update_collar(var/update_icons=1) + var/icon/C = new('icons/mob/collar.dmi') + var/image/standing = null + + if(wear_suit) + if(wear_suit.icon_state in C.IconStates()) + standing = image("icon" = C, "icon_state" = "[wear_suit.icon_state]") + + overlays_standing[COLLAR_LAYER] = standing + + if(update_icons) update_icons() + + +// Used mostly for creating head items +/mob/living/carbon/human/proc/generate_head_icon() +//gender no longer matters for the mouth, although there should probably be seperate base head icons. +// var/g = "m" +// if (gender == FEMALE) g = "f" + + //base icons + var/icon/face_lying = new /icon('icons/mob/human_face.dmi',"bald_l") + + if(f_style) + var/datum/sprite_accessory/facial_hair_style = facial_hair_styles_list[f_style] + if(facial_hair_style) + var/icon/facial_l = new/icon("icon" = facial_hair_style.icon, "icon_state" = "[facial_hair_style.icon_state]_l") + facial_l.Blend(rgb(r_facial, g_facial, b_facial), ICON_ADD) + face_lying.Blend(facial_l, ICON_OVERLAY) + + if(h_style) + var/datum/sprite_accessory/hair_style = hair_styles_list[h_style] + if(hair_style) + var/icon/hair_l = new/icon("icon" = hair_style.icon, "icon_state" = "[hair_style.icon_state]_l") + hair_l.Blend(rgb(r_hair, g_hair, b_hair), ICON_ADD) + face_lying.Blend(hair_l, ICON_OVERLAY) + + //Eyes + // Note: These used to be in update_face(), and the fact they're here will make it difficult to create a disembodied head + var/icon/eyes_l = new/icon('icons/mob/human_face.dmi', "eyes_l") + eyes_l.Blend(rgb(r_eyes, g_eyes, b_eyes), ICON_ADD) + face_lying.Blend(eyes_l, ICON_OVERLAY) + + if(lip_style) + face_lying.Blend(new/icon('icons/mob/human_face.dmi', "lips_[lip_style]_l"), ICON_OVERLAY) + + var/image/face_lying_image = new /image(icon = face_lying) + return face_lying_image + +/mob/living/carbon/human/proc/force_update_limbs() + for(var/obj/item/organ/external/O in organs) + O.sync_colour_to_human(src) + update_body(0) + +//Human Overlays Indexes///////// +#undef MUTANTRACE_LAYER +#undef MUTATIONS_LAYER +#undef DAMAGE_LAYER +#undef UNIFORM_LAYER +#undef TAIL_LAYER +#undef ID_LAYER +#undef SHOES_LAYER +#undef GLOVES_LAYER +#undef EARS_LAYER +#undef SUIT_LAYER +#undef GLASSES_LAYER +#undef FACEMASK_LAYER +#undef BELT_LAYER +#undef SUIT_STORE_LAYER +#undef BACK_LAYER +#undef HAIR_LAYER +#undef HEAD_LAYER +#undef COLLAR_LAYER +#undef HANDCUFF_LAYER +#undef LEGCUFF_LAYER +#undef L_HAND_LAYER +#undef R_HAND_LAYER +#undef TARGETED_LAYER +#undef FIRE_LAYER +#undef TOTAL_LAYERS diff --git a/icons/mob/human_face.dmi b/icons/mob/human_face.dmi index ffecceda82e..1fa0f5c3a22 100644 Binary files a/icons/mob/human_face.dmi and b/icons/mob/human_face.dmi differ