diff --git a/code/__HELPERS/mobs.dm b/code/__HELPERS/mobs.dm index 454206da..66758c5d 100644 --- a/code/__HELPERS/mobs.dm +++ b/code/__HELPERS/mobs.dm @@ -1,41 +1,39 @@ -proc/random_hair_style(gender, species = "Human") - var/h_style = "Bald" - - var/list/valid_hairstyles = list() - for(var/hairstyle in hair_styles_list) - var/datum/sprite_accessory/S = hair_styles_list[hairstyle] - if(gender == MALE && S.gender == FEMALE) - continue - if(gender == FEMALE && S.gender == MALE) - continue +proc/valid_sprite_accessories(gender,species,test_list) + var/list/valid = list() + for(var/style in test_list) + var/datum/sprite_accessory/S = test_list[style] if( !(species in S.species_allowed)) continue - valid_hairstyles[hairstyle] = hair_styles_list[hairstyle] + if (S.gender!=NEUTER) + if (S.gender!=gender) + continue + valid[style] = S + return valid + +proc/get_valid_hairstyles(gender, species = "Human") + return valid_sprite_accessories(gender,species,hair_styles_list) + + +proc/get_valid_facialhairstyles(gender, species = "Human") + return valid_sprite_accessories(gender,species,facial_hair_styles_list) + + +proc/random_hair_style(gender, species = "Human") + var/h_style = "Bald" + var/list/valid_hairstyles = get_valid_hairstyles(gender,species) if(valid_hairstyles.len) h_style = pick(valid_hairstyles) - return h_style + proc/random_facial_hair_style(gender, species = "Human") var/f_style = "Shaved" - - var/list/valid_facialhairstyles = list() - for(var/facialhairstyle in facial_hair_styles_list) - var/datum/sprite_accessory/S = facial_hair_styles_list[facialhairstyle] - if(gender == MALE && S.gender == FEMALE) - continue - if(gender == FEMALE && S.gender == MALE) - continue - if( !(species in S.species_allowed)) - continue - - valid_facialhairstyles[facialhairstyle] = facial_hair_styles_list[facialhairstyle] - + var/list/valid_facialhairstyles = get_valid_facialhairstyles(gender,species) if(valid_facialhairstyles.len) f_style = pick(valid_facialhairstyles) - - return f_style + return f_style + proc/random_name(gender, species = "Human") if(gender==FEMALE) return capitalize(pick(first_names_female)) + " " + capitalize(pick(last_names)) diff --git a/code/__HELPERS/text.dm b/code/__HELPERS/text.dm index 3bbd38bf..e13226e3 100644 --- a/code/__HELPERS/text.dm +++ b/code/__HELPERS/text.dm @@ -241,6 +241,9 @@ proc/checkhtml(var/t, var/whitelist = paper_tag_whitelist) //Returns a string with the first element of the string capitalized. /proc/capitalize(var/t as text) return uppertext(copytext(t, 1, 2)) + copytext(t, 2) + +/proc/capitalized(var/t as text) + return capitalize(lowertext(t)) //Centers text by adding spaces to either side of the string. /proc/dd_centertext(message, length) diff --git a/code/__HELPERS/type2type.dm b/code/__HELPERS/type2type.dm index b15a1116..08f0a069 100644 --- a/code/__HELPERS/type2type.dm +++ b/code/__HELPERS/type2type.dm @@ -82,6 +82,9 @@ hex = text("0[]", hex) return hex +/proc/colour_to_html(r,g,b) + return "'#[num2hex(r)][num2hex(g)][num2hex(b)]'" + // Concatenates a list of strings into a single string. A seperator may optionally be provided. /proc/list2text(list/ls, sep) diff --git a/code/game/objects/structures/mirror.dm b/code/game/objects/structures/mirror.dm index 21071711..34ae4ac5 100644 --- a/code/game/objects/structures/mirror.dm +++ b/code/game/objects/structures/mirror.dm @@ -14,42 +14,23 @@ if(ishuman(user)) var/mob/living/carbon/human/H = user - var/userloc = H.loc - - //see code/modules/mob/new_player/preferences.dm at approx line 545 for comments! - //this is largely copypasted from there. - - //handle facial hair (if necessary) - if(H.gender == MALE) - var/list/species_facial_hair = list() - if(H.species) - for(var/i in facial_hair_styles_list) - var/datum/sprite_accessory/facial_hair/tmp_facial = facial_hair_styles_list[i] - if(H.species.name in tmp_facial.species_allowed) - species_facial_hair += i - else - species_facial_hair = facial_hair_styles_list - - var/new_style = input(user, "Select a facial hair style", "Grooming") as null|anything in species_facial_hair + + var/list/hair_styles = H.valid_hairstyles_for_this_mob() + var/list/facial_styles = H.valid_facialhairstyles_for_this_mob() + + if (facial_styles.len > 1) //handle facial hair (if necessary) + var/new_style = input(user, "Select a facial hair style", "Grooming") as null|anything in facial_styles if(userloc != H.loc) return //no tele-grooming if(new_style) H.f_style = new_style //handle normal hair - var/list/species_hair = list() - if(H.species) - for(var/i in hair_styles_list) - var/datum/sprite_accessory/hair/tmp_hair = hair_styles_list[i] - if(H.species.name in tmp_hair.species_allowed) - species_hair += i - else - species_hair = hair_styles_list - - var/new_style = input(user, "Select a hair style", "Grooming") as null|anything in species_hair - if(userloc != H.loc) return //no tele-grooming - if(new_style) - H.h_style = new_style + if (hair_styles.len) + var/new_style = input(user, "Select a hair style", "Grooming") as null|anything in hair_styles + if(userloc != H.loc) return //no tele-grooming + if(new_style) + H.h_style = new_style H.update_hair() diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm index dd6963e3..5f12b74f 100644 --- a/code/modules/client/preferences.dm +++ b/code/modules/client/preferences.dm @@ -78,6 +78,8 @@ datum/preferences var/species = "Human" //Species datum to use. var/language = "None" //Secondary language var/list/gear //Custom/fluff item loadout. + var/covering_type = null //synth covering type + var/machine_brain_type = "Posibrain" //synth brain type //Some faction information. var/home_system = "Unset" //System of birth. @@ -315,43 +317,21 @@ datum/preferences dat += "Skin Tone: [-s_tone + 35]/220
" //dat += "Skin pattern: Adjust
" dat += "Needs Glasses: [disabilities == 0 ? "No" : "Yes"]
" + if (species=="Machine") // brain and covering type for shells + dat += "Brain Type: [machine_brain_type]
" + dat += "Exterior Coating: [isnull(covering_type) ? "None" : covering_type]
" dat += "Limbs: Adjust
" dat += "Internal Organs: Adjust
" //display limbs below var/ind = 0 + var/list/organ_names = get_limb_name_to_descriptive_name() + var/mechanical_organ_string = (species!="Machine" ? "Mechanical" : "Custom") for(var/name in organ_data) //world << "[ind] \ [organ_data.len]" var/status = organ_data[name] - var/organ_name = null - switch(name) - if("l_arm") - organ_name = "left arm" - if("r_arm") - organ_name = "right arm" - if("l_leg") - organ_name = "left leg" - if("r_leg") - organ_name = "right leg" - if("l_foot") - organ_name = "left foot" - if("r_foot") - organ_name = "right foot" - if("l_hand") - organ_name = "left hand" - if("r_hand") - organ_name = "right hand" - if("heart") - organ_name = "heart" - if("eyes") - organ_name = "eyes" - - if(status == "cyborg") - ++ind - if(ind > 1) - dat += ", " - dat += "\tMechanical [organ_name] prothesis" - else if(status == "amputated") + var/organ_name = organ_names[name] + if(status == "amputated") ++ind if(ind > 1) dat += ", " @@ -374,10 +354,20 @@ datum/preferences dat += "\tRetinal overlayed [organ_name]" else dat += "\tMechanically assisted [organ_name]" + var/list/status_as_list=status + if (istype(status_as_list)) // we got a robot here + ++ind + if(ind > 1) + dat += ", " + + var/color_string=colour_to_html(status_as_list[2],status_as_list[3],status_as_list[4]) + dat += "\t[mechanical_organ_string] [organ_name] covered in [lowertext(status_as_list[1])]" + + if(!ind) dat += "\[...\]

" else - dat += "

" + dat += ".

" if(gender == MALE) dat += "Underwear: [underwear_m[underwear]]
" @@ -1112,6 +1102,7 @@ datum/preferences if(new_age) age = max(min( round(text2num(new_age)), AGE_MAX),AGE_MIN) if("species") + config.usealienwhitelist=0 // REMOVE ME var/list/new_species = list("Human") var/prev_species = species @@ -1131,42 +1122,9 @@ datum/preferences if(prev_species != species) //grab one of the valid hair styles for the newly chosen species - var/list/valid_hairstyles = list() - for(var/hairstyle in hair_styles_list) - var/datum/sprite_accessory/S = hair_styles_list[hairstyle] - if(gender == MALE && S.gender == FEMALE) - continue - if(gender == FEMALE && S.gender == MALE) - continue - if( !(species in S.species_allowed)) - continue - valid_hairstyles[hairstyle] = hair_styles_list[hairstyle] - - if(valid_hairstyles.len) - h_style = pick(valid_hairstyles) - else - //this shouldn't happen - h_style = hair_styles_list["Bald"] - - //grab one of the valid facial hair styles for the newly chosen species - var/list/valid_facialhairstyles = list() - for(var/facialhairstyle in facial_hair_styles_list) - var/datum/sprite_accessory/S = facial_hair_styles_list[facialhairstyle] - if(gender == MALE && S.gender == FEMALE) - continue - if(gender == FEMALE && S.gender == MALE) - continue - if( !(species in S.species_allowed)) - continue - - valid_facialhairstyles[facialhairstyle] = facial_hair_styles_list[facialhairstyle] - - if(valid_facialhairstyles.len) - f_style = pick(valid_facialhairstyles) - else - //this shouldn't happen - f_style = facial_hair_styles_list["Shaved"] - + h_style = random_hair_style(gender,species) + f_style = random_facial_hair_style(gender,species) + //reset hair colour and skin colour r_hair = 0//hex2num(copytext(new_hair, 2, 4)) g_hair = 0//hex2num(copytext(new_hair, 4, 6)) @@ -1208,24 +1166,15 @@ datum/preferences b_type = new_b_type if("hair") - if(species == "Human" || species == "Unathi" || species == "Tajaran" || species == "Skrell") - var/new_hair = input(user, "Choose your character's hair colour:", "Character Preference") as color|null - if(new_hair) - r_hair = hex2num(copytext(new_hair, 2, 4)) - g_hair = hex2num(copytext(new_hair, 4, 6)) - b_hair = hex2num(copytext(new_hair, 6, 8)) - else if (species == "Machine") - alert("Please select the Body Color instead.") + var/new_hair = input(user, "Choose your character's hair colour:", "Character Preference") as color|null + if(new_hair) + r_hair = hex2num(copytext(new_hair, 2, 4)) + g_hair = hex2num(copytext(new_hair, 4, 6)) + b_hair = hex2num(copytext(new_hair, 6, 8)) if("h_style") - var/list/valid_hairstyles = list() - for(var/hairstyle in hair_styles_list) - var/datum/sprite_accessory/S = hair_styles_list[hairstyle] - if( !(species in S.species_allowed)) - continue - - valid_hairstyles[hairstyle] = hair_styles_list[hairstyle] - + world << "Hair species [get_hair_species()]" + var/list/valid_hairstyles = get_valid_hairstyles(gender,get_hair_species()) var/new_h_style = input(user, "Choose your character's hair style:", "Character Preference") as null|anything in valid_hairstyles if(new_h_style) h_style = new_h_style @@ -1238,18 +1187,7 @@ datum/preferences b_facial = hex2num(copytext(new_facial, 6, 8)) if("f_style") - var/list/valid_facialhairstyles = list() - for(var/facialhairstyle in facial_hair_styles_list) - var/datum/sprite_accessory/S = facial_hair_styles_list[facialhairstyle] - if(gender == MALE && S.gender == FEMALE) - continue - if(gender == FEMALE && S.gender == MALE) - continue - if( !(species in S.species_allowed)) - continue - - valid_facialhairstyles[facialhairstyle] = facial_hair_styles_list[facialhairstyle] - + var/list/valid_facialhairstyles = get_valid_facialhairstyles(gender,get_hair_species()) var/new_f_style = input(user, "Choose your character's facial-hair style:", "Character Preference") as null|anything in valid_facialhairstyles if(new_f_style) f_style = new_f_style @@ -1296,10 +1234,6 @@ datum/preferences r_skin = hex2num(copytext(new_skin, 2, 4)) g_skin = hex2num(copytext(new_skin, 4, 6)) b_skin = hex2num(copytext(new_skin, 6, 8)) - if(species == "Machine") - r_hair = r_skin - g_hair = g_skin - b_hair = b_skin if("ooccolor") var/new_ooccolor = input(user, "Choose your OOC colour:", "Game Preference") as color|null @@ -1324,58 +1258,20 @@ datum/preferences return else user << browse(null, "window=disabil") - + + if("set_machine_brain") // shell customization junk + var/new_brain = input(user, "Choose your brain.", "Character Preference") as null|anything in list("MMI", "Posibrain") // not differentiating brain species at the moment + if(new_brain) + machine_brain_type=new_brain + + if("set_machine_covering") + var/new_coating = input(user, "Choose your exterior coating.", "Character Preference") as null|anything in get_limb_covering_names() + if(new_coating) + covering_type=(new_coating!="None" ? new_coating : null) + if("limbs") - var/limb_name = input(user, "Which limb do you want to change?") as null|anything in list("Left Leg","Right Leg","Left Arm","Right Arm","Left Foot","Right Foot","Left Hand","Right Hand") - if(!limb_name) return - - var/limb = null - var/second_limb = null // if you try to change the arm, the hand should also change - var/third_limb = null // if you try to unchange the hand, the arm should also change - switch(limb_name) - if("Left Leg") - limb = "l_leg" - second_limb = "l_foot" - if("Right Leg") - limb = "r_leg" - second_limb = "r_foot" - if("Left Arm") - limb = "l_arm" - second_limb = "l_hand" - if("Right Arm") - limb = "r_arm" - second_limb = "r_hand" - if("Left Foot") - limb = "l_foot" - third_limb = "l_leg" - if("Right Foot") - limb = "r_foot" - third_limb = "r_leg" - if("Left Hand") - limb = "l_hand" - third_limb = "l_arm" - if("Right Hand") - limb = "r_hand" - third_limb = "r_arm" - - var/new_state = input(user, "What state do you wish the limb to be in?") as null|anything in list("Normal","Amputated","Prothesis") - if(!new_state) return - - switch(new_state) - if("Normal") - organ_data[limb] = null - if(third_limb) - organ_data[third_limb] = null - if("Amputated") - organ_data[limb] = "amputated" - if(second_limb) - organ_data[second_limb] = "amputated" - if("Prothesis") - organ_data[limb] = "cyborg" - if(second_limb) - organ_data[second_limb] = "cyborg" - if(third_limb && organ_data[third_limb] == "amputated") - organ_data[third_limb] = null + customize_limbs(user,species!="Machine") + if("organs") var/organ_name = input(user, "Which internal function do you want to change?") as null|anything in list("Heart", "Eyes") if(!organ_name) return @@ -1597,26 +1493,42 @@ datum/preferences character.skills = skills character.used_skillpoints = used_skillpoints + + var/list/covering_name_to_type = get_limb_covering_list() + // provide default covering for shells + if (species=="Machine") // provide default covering for shells + for (var/datum/organ/external/organ in character.organs) + if (organ) // gotta make sure we're getting an actual organ here + if (covering_type) + var/covering_path = covering_name_to_type[covering_type] + world << "Skin [r_skin],[g_skin],b_skin]" + organ.covering = new covering_path(organ,r_skin,g_skin,b_skin) + organ.covering.limb_datum=organ + + // Destroy/cyborgize organs - for(var/name in organ_data) var/datum/organ/external/O = character.organs_by_name[name] var/datum/organ/internal/I = character.internal_organs_by_name[name] var/status = organ_data[name] - if(status == "amputated") O.amputated = 1 O.status |= ORGAN_DESTROYED O.destspawn = 1 - if(status == "cyborg") - O.status |= ORGAN_ROBOT if(status == "assisted") I.mechassist() - else if(status == "mechanical") + if(status == "mechanical") I.mechanize() - - else continue + var/list/status_as_list=status + if (istype(status_as_list)) // we got a robot here + world << "We setting this junk" + O.status |= ORGAN_ROBOT + O.covering = null // wipe any old covering we might have + if (status_as_list[1]!="None") + var/covering_path = covering_name_to_type[status_as_list[1]] + O.covering = new covering_path(O,status_as_list[2],status_as_list[3],status_as_list[4]) + O.covering.limb_datum=O if(underwear > underwear_m.len || underwear < 1) underwear = 0 //I'm sure this is 100% unnecessary, but I'm paranoid... sue me. //HAH NOW NO MORE MAGIC CLONING UNDIES @@ -1659,3 +1571,104 @@ datum/preferences /datum/preferences/proc/close_load_dialog(mob/user) user << browse(null, "window=saves") + + +/datum/preferences/proc/get_hair_species() + // this is incredibly snowflakey but I don't see an alternative + if (!species=="Machine") + return species + var/head_coat=covering_type // we get the base coating + if (organ_data["Head"]) // if we're customizing the head we should get their coating + head_coat=organ_data["Head"][0] + if (!head_coat) + return + var/list/refs=get_limb_covering_references() + for(var/skin_type in refs) + var/datum/synthetic_limb_cover/temp=refs[skin_type] + if (temp.icon_key_type==head_coat) + return temp.hair_species + + +/datum/preferences/proc/custom_robot_limb(mob/user,) + var/covering_name = input(user, "What kind of covering do you want?") as null|anything in get_limb_covering_names() + if (!covering_name) + return + if (covering_name=="None") // don't want no colour + return list(covering_name,128,128,128) + var/new_colour = input(user, "Pick the colour for your limb:", "Character Preference") as color|null + if(!new_colour) + return + return list(covering_name,hex2num(copytext(new_colour, 2, 4)),hex2num(copytext(new_colour, 4, 6)),hex2num(copytext(new_colour, 6, 8))) + + +var/list/limb_name_to_descriptive_names +/datum/preferences/proc/get_limb_name_to_descriptive_name() + if (isnull(limb_name_to_descriptive_names)) + limb_name_to_descriptive_names=list() + for(var/organ_type in typesof(/datum/organ/external)-/datum/organ/external) + var/datum/organ/external/temp = new organ_type() + limb_name_to_descriptive_names[temp.name]=temp.display_name + del(temp) + return limb_name_to_descriptive_names + + +var/list/limb_connection_data +/datum/preferences/proc/get_limb_connection_data() + if (isnull(limb_connection_data)) + limb_connection_data = list() + limb_connection_data["Left Leg"]=list("l_leg","l_foot",null) + limb_connection_data["Right Leg"]=list("r_leg","r_foot",null) + limb_connection_data["Left Arm"]=list("l_arm","l_hand",null) + limb_connection_data["Right Arm"]=list("r_arm","r_hand",null) + limb_connection_data["Left Foot"]=list("l_foot",null,"l_leg") + limb_connection_data["Right Foot"]=list("r_foot",null,"r_leg") + limb_connection_data["Left Hand"]=list("l_hand",null,"l_arm") + limb_connection_data["Right Hand"]=list("r_hand",null,"r_arm") + limb_connection_data["Chest"]=list("chest",null,null) + limb_connection_data["Groin"]=list("groin",null,null) + limb_connection_data["Head"]=list("head",null,null) + return limb_connection_data + + +/datum/preferences/proc/pick_organ_to_customize(mob/user,var/is_organic_species) + var/list/valid_targets = list("Left Leg","Right Leg","Left Arm","Right Arm","Left Foot","Right Foot","Left Hand","Right Hand") + if (!is_organic_species) + valid_targets.Add(list("Head","Chest","Groin")) + var/limb_name = input(user, "Which limb do you want to change?") as null|anything in valid_targets + if(!limb_name) // you have picked nothing + return + var/list/limb_info=get_limb_connection_data() + return limb_info[limb_name] + + +/datum/preferences/proc/customize_limbs(mob/user,var/is_organic_species) + var/list/limb_info = pick_organ_to_customize(user,is_organic_species) + world << "We done picked! [limb_info]" + if (!limb_info) + return + var/limb=limb_info[1] + var/limb_child=limb_info[2] + var/limb_parent=limb_info[3] + world << "LIMB STUFF [limb] [limb_child] [limb_parent]" + var/new_state = input(user, "What state do you wish the limb to be in?") as null|anything in (is_organic_species ? list("Normal","Amputated","Prosthesis") : list("Normal","Custom")) + if(!new_state) + return // cancel + switch(new_state) + if("Normal") + organ_data[limb] = null + if(limb_parent) + organ_data[limb_parent] = null + if("Amputated") + organ_data[limb] = "amputated" + if(limb_child) + organ_data[limb_child] = "amputated" + if("Prosthesis") + var/list/custom = custom_robot_limb(user) + organ_data[limb] = custom + world << "[organ_data[limb][1]] [organ_data[limb][2]] [organ_data[limb][3]][organ_data[limb][4]]" + if(limb_child) + organ_data[limb_child] = custom + if(limb_parent && organ_data[limb_parent] == "amputated") + organ_data[limb_parent] = null + if("Custom") + organ_data[limb] = custom_robot_limb(user) // robots have no dependencies \ No newline at end of file diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index decf0bf3..a78c9d65 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -1659,3 +1659,82 @@ if(eyes && istype(eyes) && !eyes.status & ORGAN_CUT_AWAY) return 1 return 0 + +/mob/living/carbon/human/proc/hair_species_name() + var/datum/organ/external/head/head_organ = get_organ("head") + if (head_organ.covering) + return head_organ.covering.hair_species + return species.name + + +/mob/living/carbon/human/proc/valid_hairstyles_for_this_mob() + return get_valid_hairstyles(gender, hair_species_name()) + + +/mob/living/carbon/human/proc/valid_facialhairstyles_for_this_mob() + return get_valid_facialhairstyles(gender, hair_species_name()) + + +/mob/living/carbon/human/proc/should_we_show_hair() + var/datum/organ/external/head/head_organ = get_organ("head") + if(!head_organ || (head_organ.status & ORGAN_DESTROYED)) + return + if( (head && (head.flags & BLOCKHAIR)) || (wear_mask && (wear_mask.flags & BLOCKHAIR))) + return + return TRUE + +/mob/living/carbon/human/proc/validate_hair() + var/list/hair=valid_hairstyles_for_this_mob() + if (!(h_style in hair)) + h_style=null + var/list/face=valid_facialhairstyles_for_this_mob() + if (!(f_style in face)) + f_style=null + + +/mob/living/carbon/human/proc/hair_icon() + if (h_style) + var/datum/sprite_accessory/hair_style = hair_styles_list[h_style] + var/icon/hair = new/icon("icon" = hair_style.icon, "icon_state" = "[hair_style.icon_state]_s") + if(hair_style.do_colouration) + hair.Blend(rgb(r_hair, g_hair, b_hair), ICON_ADD) + return hair + + +/mob/living/carbon/human/proc/facial_hair_icon() + if (f_style) + var/datum/sprite_accessory/facial_hair_style = facial_hair_styles_list[f_style] + 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) + return facial_s + + +/mob/living/carbon/human/proc/get_eye_icon_state() + var/datum/organ/external/head/head_organ = get_organ("head") + if (head_organ.covering) + return head_organ.covering.eyes_state + return species.eyes + + +/mob/living/carbon/human/proc/eye_icon() + var/icon/result_icon = new/icon('icons/mob/human_face.dmi', get_eye_icon_state()) + result_icon.Blend(rgb(r_eyes, g_eyes, b_eyes), ICON_ADD) + return result_icon + + +/mob/living/carbon/human/proc/tail_icon_state() + var/datum/organ/external/groin/groin_organ = get_organ("groin") + if (groin_organ.covering) + return groin_organ.covering.tail + if (species.tail) + return species.tail + + +/mob/living/carbon/human/proc/tail_icon() + var/tail_name = tail_icon_state() + if (tail_name) + 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" = "[tail_name]_s") + tail_s.Blend(rgb(r_skin, g_skin, b_skin), ICON_ADD) + return tail_s \ No newline at end of file diff --git a/code/modules/mob/living/carbon/human/human_species.dm b/code/modules/mob/living/carbon/human/human_species.dm index c313c601..ea550240 100644 --- a/code/modules/mob/living/carbon/human/human_species.dm +++ b/code/modules/mob/living/carbon/human/human_species.dm @@ -30,5 +30,5 @@ ..(new_loc, "Diona") /mob/living/carbon/human/machine/New(var/new_loc) - h_style = "blue IPC screen" + h_style = "Bald" ..(new_loc, "Machine") \ No newline at end of file diff --git a/code/modules/mob/living/carbon/human/update_icons.dm b/code/modules/mob/living/carbon/human/update_icons.dm index 8c52146b..38cd24aa 100644 --- a/code/modules/mob/living/carbon/human/update_icons.dm +++ b/code/modules/mob/living/carbon/human/update_icons.dm @@ -234,6 +234,49 @@ proc/get_damage_icon_part(damage_state, body_part) overlays_standing[DAMAGE_LAYER] = standing_image if(update_icons) update_icons() + + +/mob/living/carbon/human/proc/get_skin_tone_key() + if (species.flags & HAS_SKIN_COLOR) + return "[r_skin],[g_skin],[b_skin]" + if(species.flags & HAS_SKIN_TONE) + return "[s_tone]" + return "" + + +/mob/living/carbon/human/proc/get_icon_key(var/list/mutations=list()) + if (!mutations) + mutations=get_visible_mutations() + var/icon_key = "[species.race_key][(gender == FEMALE ? "f" : "m")][get_skin_tone_key()]" + for(var/datum/organ/external/part in organs) // get the part icon keys + icon_key = "[icon_key][part.get_icon_key()]" + return "[icon_key][mutations["husk"]][mutations["fat"]][mutations["hulk"]][mutations["skeleton"]]" + + +/mob/living/carbon/human/proc/get_visible_mutations() + return list("husk"=(HUSK in src.mutations), + "hulk"=(HULK in src.mutations), + "skeleton"=(SKELETON in src.mutations), + "fat"=(FAT in src.mutations)) + + +/mob/living/carbon/human/proc/skin_colour_info(var/list/mutations=list()) + if (!mutations) + mutations=get_visible_mutations() + var/icon_blend=ICON_ADD + var/colour=rgb(127,127,127) + var/good=FALSE + if (species.flags & HAS_SKIN_COLOR) + colour=rgb(r_skin,g_skin,b_skin) + good=TRUE + if(!mutations["husk"] && !mutations["hulk"]) // if we have regular skin + if(species.flags & HAS_SKIN_TONE) + icon_blend=(s_tone >= 0 ? ICON_ADD : ICON_SUBTRACT) + var/res=(s_tone >= 0 ? s_tone : -s_tone) + colour=rgb(res,res,res) + good=TRUE + return list("rgb"=colour,"mode"=icon_blend,"blend"=good) + //BASE MOB SPRITE /mob/living/carbon/human/proc/update_body(var/update_icons=1) @@ -242,13 +285,8 @@ proc/get_damage_icon_part(damage_state, body_part) var/hulk_color_mod = rgb(48,224,40) var/necrosis_color_mod = rgb(10,50,0) - var/husk = (HUSK in src.mutations) - var/fat = (FAT in src.mutations) - var/hulk = (HULK in src.mutations) - var/skeleton = (SKELETON in src.mutations) - + var/list/mutations = get_visible_mutations() var/g = (gender == FEMALE ? "f" : "m") - var/has_head = 0 //CACHING: Generate an index key from visible bodyparts. //0 = destroyed, 1 = normal, 2 = robotic, 3 = necrotic. @@ -259,22 +297,9 @@ proc/get_damage_icon_part(damage_state, body_part) stand_icon = new(species.icon_template ? species.icon_template : 'icons/mob/human.dmi',"blank") - var/icon_key = "[species.race_key][g][s_tone]" - for(var/datum/organ/external/part in organs) - if(istype(part,/datum/organ/external/head) && !(part.status & ORGAN_DESTROYED)) - has_head = 1 - - if(part.status & ORGAN_DESTROYED) - icon_key = "[icon_key]0" - else if(part.status & ORGAN_ROBOT) - icon_key = "[icon_key]2" - else if(part.status & ORGAN_DEAD) - icon_key = "[icon_key]3" - else - icon_key = "[icon_key]1" - - icon_key = "[icon_key][husk ? 1 : 0][fat ? 1 : 0][hulk ? 1 : 0][skeleton ? 1 : 0][s_tone]" + // GENERATE THE ICON KEY + var/icon_key = get_icon_key(mutations) var/icon/base_icon if(human_icon_cache[icon_key]) @@ -287,14 +312,18 @@ proc/get_damage_icon_part(damage_state, body_part) //BEGIN CACHED ICON GENERATION. - // Why don't we just make skeletons/shadows/golems a species? ~Z - var/race_icon = (skeleton ? 'icons/mob/human_races/r_skeleton.dmi' : species.icobase) - var/deform_icon = (skeleton ? 'icons/mob/human_races/r_skeleton.dmi' : species.icobase) + // Why don't we just make mutations["skeleton"]s/shadows/golems a species? ~Z + var/race_icon = (mutations["skeleton"] ? 'icons/mob/human_races/r_skeleton.dmi' : species.icobase) + var/deform_icon = (mutations["skeleton"] ? 'icons/mob/human_races/r_skeleton.dmi' : species.icobase) + var/list/skin_info = skin_colour_info(mutations) // get the skin tone info + //Robotic limbs are handled in get_icon() so all we worry about are missing or dead limbs. //No icon stored, so we need to start with a basic one. var/datum/organ/external/chest = get_organ("chest") - base_icon = chest.get_icon(race_icon,deform_icon,g) + base_icon = chest.get_icon(race_icon,deform_icon,skin_info) + + if(chest.status & ORGAN_DEAD) base_icon.ColorTone(necrosis_color_mod) @@ -307,10 +336,7 @@ proc/get_damage_icon_part(damage_state, body_part) if(part.status & ORGAN_DESTROYED) continue - if (istype(part, /datum/organ/external/groin) || istype(part, /datum/organ/external/head)) - temp = part.get_icon(race_icon,deform_icon,g) - else - temp = part.get_icon(race_icon,deform_icon) + temp = part.get_icon(race_icon,deform_icon,skin_info) // synthetics are handled here if(part.status & ORGAN_DEAD) temp.ColorTone(necrosis_color_mod) @@ -345,48 +371,33 @@ proc/get_damage_icon_part(damage_state, body_part) base_icon.Blend(temp, ICON_OVERLAY) - if(!skeleton) - if(husk) + if(!mutations["skeleton"]) + if(mutations["husk"]) base_icon.ColorTone(husk_color_mod) - else if(hulk) + else if(mutations["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) + //Handle mutations["husk"] overlay. + if(mutations["husk"]) var/icon/mask = new(base_icon) var/icon/husk_over = new(race_icon,"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) - - //Skin tone. - if(!husk && !hulk) - if(species.flags & HAS_SKIN_TONE) - if(s_tone >= 0) - base_icon.Blend(rgb(s_tone, s_tone, s_tone), ICON_ADD) - else - base_icon.Blend(rgb(-s_tone, -s_tone, -s_tone), ICON_SUBTRACT) - human_icon_cache[icon_key] = base_icon //log_debug("Generated new cached mob icon ([icon_key] \icon[human_icon_cache[icon_key]]) for [src]. [human_icon_cache.len] cached mob icons.") //END CACHED ICON GENERATION. - stand_icon.Blend(base_icon,ICON_OVERLAY) - //Skin colour. Not in cache because highly variable (and relatively benign). - if (species.flags & HAS_SKIN_COLOR) - stand_icon.Blend(rgb(r_skin, g_skin, b_skin), ICON_ADD) - - if(has_head) + var/datum/organ/external/head = get_organ("head") // check if we have a head + if(head ? (head.status & ORGAN_DESTROYED ? 0 : 1) : 0) // we need a head and that head needs to not be destroyed //Eyes - if(!skeleton) - var/icon/eyes = new/icon('icons/mob/human_face.dmi', species.eyes) - eyes.Blend(rgb(r_eyes, g_eyes, b_eyes), ICON_ADD) - stand_icon.Blend(eyes, ICON_OVERLAY) + if(!mutations["skeleton"]) + stand_icon.Blend(eye_icon(), ICON_OVERLAY) //Mouth (lipstick!) if(lip_style && (species && species.flags & HAS_LIPS)) //skeletons are allowed to wear lipstick no matter what you think, agouri. @@ -394,7 +405,7 @@ proc/get_damage_icon_part(damage_state, body_part) //Underwear if(underwear >0 && underwear < 12 && species.flags & HAS_UNDERWEAR) - if(!fat && !skeleton) + if(!mutations["fat"] && !mutations["skeleton"]) stand_icon.Blend(new /icon('icons/mob/human.dmi', "underwear[underwear]_[g]_s"), ICON_OVERLAY) if(undershirt>0 && undershirt <= undershirt_t.len && species.flags & HAS_UNDERWEAR) @@ -407,47 +418,27 @@ proc/get_damage_icon_part(damage_state, body_part) update_tail_showing(0) +/mob/living/carbon/human/proc/create_hair_icon() + if(!should_we_show_hair()) // if we're missing our head or we're wearing a mask, no hair + return + validate_hair() // make sure our hair is valid + var/icon/face_standing = new /icon('icons/mob/human_face.dmi',"bald_s") //base icons + var/icon/facial_s = facial_hair_icon() + if (facial_s) + face_standing.Blend(facial_s, ICON_OVERLAY) + var/icon/hair_s = hair_icon() + if (hair_s) + face_standing.Blend(hair_s, ICON_OVERLAY) + overlays_standing[HAIR_LAYER] = image(face_standing) //HAIR OVERLAY /mob/living/carbon/human/proc/update_hair(var/update_icons=1) - //Reset our hair - overlays_standing[HAIR_LAYER] = null - - var/datum/organ/external/head/head_organ = get_organ("head") - if( !head_organ || (head_organ.status & ORGAN_DESTROYED) ) - if(update_icons) update_icons() - return - - //masks and helmets can obscure our hair. - 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 && 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) - - if(h_style && !(head && (head.flags & BLOCKHEADHAIR))) - var/datum/sprite_accessory/hair_style = hair_styles_list[h_style] - if(hair_style && 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) - - overlays_standing[HAIR_LAYER] = image(face_standing) - - if(update_icons) update_icons() + overlays_standing[HAIR_LAYER] = null //Reset our hair + create_hair_icon() // do the hair blending + if(update_icons) + update_icons() + /mob/living/carbon/human/update_mutations(var/update_icons=1) var/fat @@ -988,16 +979,12 @@ proc/get_damage_icon_part(damage_state, body_part) overlays_standing[L_HAND_LAYER] = null if(update_icons) update_icons() + /mob/living/carbon/human/proc/update_tail_showing(var/update_icons=1) overlays_standing[TAIL_LAYER] = null - - if(species.tail) - 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) - + var/icon/tail_s = tail_icon() + if (tail_s) + overlays_standing[TAIL_LAYER] = image(tail_s) if(update_icons) update_icons() diff --git a/code/modules/mob/living/carbon/species.dm b/code/modules/mob/living/carbon/species.dm index 8837307a..b5043fd2 100644 --- a/code/modules/mob/living/carbon/species.dm +++ b/code/modules/mob/living/carbon/species.dm @@ -105,6 +105,11 @@ //H.jitteriness = 0 H.update_hair() return + + +/datum/species/proc/get_eye_icon() + return eyes + /datum/species/human name = "Human" @@ -328,6 +333,9 @@ blood_color = "#1F181F" flesh_color = "#575757" + + var/brain_type = 'posibrain' // default is robots + //Species unarmed attacks diff --git a/code/modules/organs/organ_external.dm b/code/modules/organs/organ_external.dm index fe20acd3..3375be3a 100644 --- a/code/modules/organs/organ_external.dm +++ b/code/modules/organs/organ_external.dm @@ -43,6 +43,10 @@ // how often wounds should be updated, a higher number means less often var/wound_update_accuracy = 1 + + var/datum/synthetic_limb_cover/covering = null // paint or synth skin + + var/gendered = FALSE /datum/organ/external/New(var/datum/organ/external/P) @@ -804,14 +808,52 @@ Note that amputating the affected organ does in fact remove the infection from t return 1 return 0 -/datum/organ/external/get_icon(var/icon/race_icon, var/icon/deform_icon,gender="") - if (status & ORGAN_ROBOT && !(owner.species && owner.species.flags & IS_SYNTHETIC)) - return new /icon('icons/mob/human_races/robotic.dmi', "[icon_name][gender ? "_[gender]" : ""]") + +/datum/organ/external/proc/get_icon_key() + if (status & ORGAN_DESTROYED) + return "L" // l for lost + if (status & ORGAN_DEAD) + return "D" // d for dead + if (status & ORGAN_ROBOT) + return get_synthetic_icon_key() + return "G" // regular old limb - if (status & ORGAN_MUTATED) - return new /icon(deform_icon, "[icon_name][gender ? "_[gender]" : ""]") - return new /icon(race_icon, "[icon_name][gender ? "_[gender]" : ""]") +/datum/organ/external/proc/valid_covering() + if (status & ORGAN_ROBOT) + if (covering) + return (covering.coverage) // is our covering working? + return FALSE // if we have no covering at all + return TRUE // squishies always have skin + + +/datum/organ/external/proc/get_synthetic_icon_key() + if (!covering) // no covering at all, this should not happen + return "R" // regular old robot + return covering.get_icon_key() + + +/datum/organ/external/proc/get_synthetic_icon() + if (!covering) // no covering at all, this should not happen + return new /icon('icons/mob/human_races/robotic.dmi', "[icon_name][get_gender_string()]") + return covering.get_icon() + + +/datum/organ/external/proc/get_gender_string() + if (!gendered) // most organs aren't gender specific + return "" + if (owner) // if we're a gender specific organ with an owner + return (owner.gender == FEMALE ? "_f" : "_m") + return "_f" + + +/datum/organ/external/get_icon(var/icon/race_icon, var/icon/deform_icon, var/list/skin_info) + if (status & ORGAN_ROBOT) + return get_synthetic_icon() + var/icon/result = new /icon((status & ORGAN_MUTATED) ? deform_icon : race_icon, "[icon_name][get_gender_string()]") + if (skin_info["blend"]) + result.Blend(skin_info["rgb"],skin_info["mode"]) + return result /datum/organ/external/proc/is_usable() @@ -867,6 +909,7 @@ Note that amputating the affected organ does in fact remove the infection from t body_part = UPPER_TORSO vital = 1 encased = "ribcage" + gendered = TRUE /datum/organ/external/groin name = "groin" @@ -876,6 +919,7 @@ Note that amputating the affected organ does in fact remove the infection from t min_broken_damage = 30 body_part = LOWER_TORSO vital = 1 + gendered = TRUE /datum/organ/external/l_arm name = "l_arm" @@ -971,16 +1015,7 @@ Note that amputating the affected organ does in fact remove the infection from t var/disfigured = 0 vital = 1 encased = "skull" - -/datum/organ/external/head/get_icon(var/icon/race_icon, var/icon/deform_icon) - if (!owner) - return ..() - var/g = "m" - if(owner.gender == FEMALE) g = "f" - if (status & ORGAN_MUTATED) - . = new /icon(deform_icon, "[icon_name]_[g]") - else - . = new /icon(race_icon, "[icon_name]_[g]") + gendered = TRUE /datum/organ/external/head/take_damage(brute, burn, sharp, edge, used_weapon = null, list/forbidden_limbs = list()) ..(brute, burn, sharp, edge, used_weapon, forbidden_limbs) @@ -1012,6 +1047,7 @@ obj/item/weapon/organ icon = 'icons/mob/human_races/r_human.dmi' var/op_stage = 0 var/list/organs_internal = list() + obj/item/weapon/organ/New(loc, mob/living/carbon/human/H) ..(loc) @@ -1039,24 +1075,13 @@ obj/item/weapon/organ/New(loc, mob/living/carbon/human/H) base = icon(H.species.icobase) else base = icon('icons/mob/human_races/r_human.dmi') - - if(base) - //Changing limb's skin tone to match owner - if(!H.species || H.species.flags & HAS_SKIN_TONE) - if (H.s_tone >= 0) - base.Blend(rgb(H.s_tone, H.s_tone, H.s_tone), ICON_ADD) - else - base.Blend(rgb(-H.s_tone, -H.s_tone, -H.s_tone), ICON_SUBTRACT) - - if(base) - //Changing limb's skin color to match owner - if(!H.species || H.species.flags & HAS_SKIN_COLOR) - base.Blend(rgb(H.r_skin, H.g_skin, H.b_skin), ICON_ADD) - + if(base) // handle skin colours + var/list/skin_info = H.skin_colour_info() // get the skin tone info + base.Blend(skin_info["rgb"],skin_info["mode"]) icon = base set_dir(SOUTH) src.transform = turn(src.transform, rand(70,130)) - + /**************************************************** EXTERNAL ORGAN ITEMS DEFINES diff --git a/code/modules/organs/synth_skin.dm b/code/modules/organs/synth_skin.dm new file mode 100644 index 00000000..ece7ca76 --- /dev/null +++ b/code/modules/organs/synth_skin.dm @@ -0,0 +1,127 @@ +/* + +We need to mix blending into limb object code, this will slow shit down a lot. + +*/ + +#define SYNTHETIC_COVERING_WORKING 1 +#define SYNTHETIC_COVERING_DAMAGED 0 + +datum/synthetic_limb_cover + var/coverage // + var/colour_r = 128 // the colour of the limb + var/colour_g = 128// the colour of the limb + var/colour_b = 128// the colour of the limb + var/datum/organ/external/limb_datum // the limb in question + var/obj/item/robot_parts/limb_item // also the limb in question (if dismembered) + var/main_icon = 'icons/mob/human_races/robotic.dmi' + var/damage_icon = 'icons/mob/human_races/robotic.dmi' + var/icon_key_type="BAD" + var/hair_species=null + var/eyes_state = "blank_eyes" + var/tail = null + + +datum/synthetic_limb_cover/New( var/datum/organ/external/datum_target=null,var/input_colour_r=null,var/input_colour_g=null,var/input_colour_b=null) + world << "Making cover : [src]" + limb_datum=datum_target + coverage=SYNTHETIC_COVERING_WORKING // start working + if(input_colour_r) + colour_r=input_colour_r + if(input_colour_g) + colour_g=input_colour_g + if(input_colour_b) + colour_b=input_colour_b + + world << "COLOUR is [colour_r]-[colour_g]-[colour_b]" + + +datum/synthetic_limb_cover/proc/get_icon() // default mechanical limbs return robo versions + var/icon/temp = new /icon((coverage ? main_icon : damage_icon), "[limb_datum.icon_name][limb_datum.get_gender_string()]") // only add a gender if it's necessary + var/icon/result = icon(temp) + result.GrayScale() + result.Blend(rgb(colour_r,colour_g,colour_b), ICON_ADD) + return result + + +datum/synthetic_limb_cover/proc/repair() + coverage = SYNTHETIC_COVERING_WORKING + + +datum/synthetic_limb_cover/proc/damage() + coverage = SYNTHETIC_COVERING_DAMAGED + + +datum/synthetic_limb_cover/proc/recolour(var/paint_colour_r, var/paint_colour_g, var/paint_colour_b, var/update=FALSE) + colour_r=paint_colour_r + colour_g=paint_colour_g + colour_b=paint_colour_b + if (update) + if (limb_datum) + if (limb_datum.owner) + limb_datum.owner.update_body() + + +datum/synthetic_limb_cover/proc/get_icon_key() // this is going to wreck the icon cache but to do custom colour per limb this is necessary + return "SYNTH:[icon_key_type]:[colour_r][colour_g][colour_b]" + + +datum/synthetic_limb_cover/paint + main_icon = 'icons/mob/human_races/r_machine.dmi' + icon_key_type = "Paint" + hair_species = "Machine" + + +datum/synthetic_limb_cover/skin + main_icon = 'icons/mob/human_races/r_human_grey.dmi' + icon_key_type = "Skin" + hair_species = "Human" + eyes_state="eyes_s" + + +datum/synthetic_limb_cover/fur + main_icon = 'icons/mob/human_races/r_tajaran.dmi' + icon_key_type = "Fur" + hair_species = "Tajaran" + eyes_state="eyes_s" + tail = "tajtail" + + +datum/synthetic_limb_cover/scales + main_icon = 'icons/mob/human_races/r_lizard.dmi' + icon_key_type = "Scales" + hair_species = "Unathi" + eyes_state="eyes_s" + tail = "sogtail" + + +var/list/limb_covering_references +/proc/get_limb_covering_references() + if (isnull(limb_covering_references)) + limb_covering_references = list() + for(var/skin_type in typesof(/datum/synthetic_limb_cover)-/datum/synthetic_limb_cover) + var/datum/synthetic_limb_cover/temp_cover = new skin_type() + limb_covering_references[skin_type]=temp_cover + return limb_covering_references + + +var/list/limb_covering_names +/proc/get_limb_covering_names() + if (isnull(limb_covering_names)) + limb_covering_names=list("None") + var/list/refs=get_limb_covering_references() + for(var/skin_type in refs) + var/datum/synthetic_limb_cover/temp=refs[skin_type] + limb_covering_names.Add(temp.icon_key_type) + return limb_covering_names + + +var/list/limb_covering_list +/proc/get_limb_covering_list() + if(isnull(limb_covering_list)) + limb_covering_list=list("None"=null) + var/list/refs=get_limb_covering_references() + for(var/skin_type in refs) + var/datum/synthetic_limb_cover/temp=refs[skin_type] + limb_covering_list[temp.icon_key_type]=skin_type + return limb_covering_list \ No newline at end of file diff --git a/icons/mob/human_face.dmi b/icons/mob/human_face.dmi index 0f28d76a..1f65c43f 100644 Binary files a/icons/mob/human_face.dmi and b/icons/mob/human_face.dmi differ diff --git a/icons/mob/human_races/r_human_grey.dmi b/icons/mob/human_races/r_human_grey.dmi new file mode 100644 index 00000000..0404ad8f Binary files /dev/null and b/icons/mob/human_races/r_human_grey.dmi differ