diff --git a/code/__DEFINES/flags.dm b/code/__DEFINES/flags.dm index 3b69f39a553..5f77bb2fe6f 100644 --- a/code/__DEFINES/flags.dm +++ b/code/__DEFINES/flags.dm @@ -65,6 +65,7 @@ #define TAIL_WAGGING 4096 #define NO_EYES 8192 #define HAS_FUR 16384 +#define HAS_ALT_HEADS 32768 //Species Diet Flags #define DIET_CARN 1 diff --git a/code/__DEFINES/mob.dm b/code/__DEFINES/mob.dm index 82ca895b42d..6ce30fd0526 100644 --- a/code/__DEFINES/mob.dm +++ b/code/__DEFINES/mob.dm @@ -79,8 +79,9 @@ #define APPEARANCE_HEAD_ACCESSORY 512 #define APPEARANCE_MARKINGS 1024 #define APPEARANCE_BODY_ACCESSORY 2048 -#define APPEARANCE_ALL_BODY APPEARANCE_ALL_HAIR|APPEARANCE_HEAD_ACCESSORY|APPEARANCE_MARKINGS|APPEARANCE_BODY_ACCESSORY -#define APPEARANCE_ALL 4095 +#define APPEARANCE_ALT_HEAD 4096 +#define APPEARANCE_ALL_BODY APPEARANCE_ALL_HAIR|APPEARANCE_HEAD_ACCESSORY|APPEARANCE_MARKINGS|APPEARANCE_BODY_ACCESSORY|APPEARANCE_ALT_HEAD +#define APPEARANCE_ALL 8191 // Intents #define I_HELP "help" diff --git a/code/game/dna/genes/vg_powers.dm b/code/game/dna/genes/vg_powers.dm index a47ec1f0f93..54eb33d5be2 100644 --- a/code/game/dna/genes/vg_powers.dm +++ b/code/game/dna/genes/vg_powers.dm @@ -51,6 +51,13 @@ M.b_eyes = hex2num(copytext(new_eyes, 6, 8)) M.change_eye_color(M.r_eyes, M.g_eyes, M.b_eyes) + //Alt heads. + if(head_organ.species.bodyflags & HAS_ALT_HEADS) + var/list/valid_alt_heads = M.generate_valid_alt_heads() + var/new_alt_head = input("Please select alternate head", "Character Generation", head_organ.alt_head) as null|anything in valid_alt_heads + if(new_alt_head) + M.change_alt_head(new_alt_head) + // hair var/list/valid_hairstyles = M.generate_valid_hairstyles() var/new_style = input("Please select hair style", "Character Generation", head_organ.h_style) as null|anything in valid_hairstyles diff --git a/code/modules/client/preference/preferences.dm b/code/modules/client/preference/preferences.dm index 8802d937904..edd6cc8b818 100644 --- a/code/modules/client/preference/preferences.dm +++ b/code/modules/client/preference/preferences.dm @@ -1184,7 +1184,6 @@ var/global/list/special_role_times = list( //minimum age (in days) for accounts if(new_age) age = max(min( round(text2num(new_age)), AGE_MAX),AGE_MIN) if("species") - var/list/new_species = list("Human", "Tajaran", "Skrell", "Unathi", "Diona", "Vulpkanin") var/prev_species = species // var/whitelisted = 0 @@ -1269,6 +1268,7 @@ var/global/list/special_role_times = list( //minimum age (in days) for accounts m_styles = "head=None;\ body=None;\ tail=None" // No Unathi markings on Tajara + alt_head = null //No alt heads on species that don't have them. body_accessory = null //no vulptail on humans damnit @@ -1379,7 +1379,7 @@ var/global/list/special_role_times = list( //minimum age (in days) for accounts if("alt_head") if(organ_data["head"] == "cyborg") return - if(species in list("Unathi")) //Species with head accessories. + if(species in list("Unathi")) //Species with alt heads. var/list/valid_alt_heads = list() valid_alt_heads["None"] = alt_heads_list["None"] //The only null entry should be the "None" option for(var/alternate_head in alt_heads_list) diff --git a/code/modules/mob/living/carbon/human/appearance.dm b/code/modules/mob/living/carbon/human/appearance.dm index e01211a0f94..5d6fb9260b7 100644 --- a/code/modules/mob/living/carbon/human/appearance.dm +++ b/code/modules/mob/living/carbon/human/appearance.dm @@ -4,13 +4,7 @@ AC.ui_interact(user, state = state) /mob/living/carbon/human/proc/change_species(var/new_species) - if(!new_species) - return - - if(species == new_species) - return - - if(!(new_species in all_species)) + if(!new_species || species == new_species || !(new_species in all_species)) return set_species(new_species) @@ -40,13 +34,7 @@ /mob/living/carbon/human/proc/change_hair(var/hair_style) var/obj/item/organ/external/head/H = get_organ("head") - if(!hair_style) - return - - if(H.h_style == hair_style) - return - - if(!(hair_style in hair_styles_list)) + if(!hair_style || H.h_style == hair_style || !(hair_style in hair_styles_list)) return H.h_style = hair_style @@ -56,13 +44,7 @@ /mob/living/carbon/human/proc/change_facial_hair(var/facial_hair_style) var/obj/item/organ/external/head/H = get_organ("head") - if(!facial_hair_style) - return - - if(H.f_style == facial_hair_style) - return - - if(!(facial_hair_style in facial_hair_styles_list)) + if(!facial_hair_style || H.f_style == facial_hair_style || !(facial_hair_style in facial_hair_styles_list)) return H.f_style = facial_hair_style @@ -72,13 +54,7 @@ /mob/living/carbon/human/proc/change_head_accessory(var/head_accessory_style) var/obj/item/organ/external/head/H = get_organ("head") - if(!head_accessory_style) - return - - if(H.ha_style == head_accessory_style) - return - - if(!(head_accessory_style in head_accessory_styles_list)) + if(!head_accessory_style || H.ha_style == head_accessory_style || !(head_accessory_style in head_accessory_styles_list)) return H.ha_style = head_accessory_style @@ -87,13 +63,8 @@ return 1 /mob/living/carbon/human/proc/change_markings(var/marking_style, var/location = "body") - if(!marking_style) - return var/list/marking_styles = params2list(m_styles) - if(marking_styles[location] == marking_style) - return - - if(!(marking_style in marking_styles_list)) + if(!marking_style || marking_styles[location] == marking_style || !(marking_style in marking_styles_list)) return var/datum/sprite_accessory/body_markings/marking = marking_styles_list[marking_style] @@ -101,9 +72,9 @@ return var/obj/item/organ/external/head/head_organ = get_organ("head") - if(location == "head" && head_organ.alt_head) - var/datum/sprite_accessory/body_markings/head/H - if(!H.heads_allowed || !(head_organ.alt_head in H.heads_allowed)) + if(location == "head" && head_organ.alt_head && head_organ.alt_head != "None") + var/datum/sprite_accessory/body_markings/head/H = marking_styles_list[marking_style] + if(marking.name != "None" && (!H.heads_allowed || !(head_organ.alt_head in H.heads_allowed))) return marking_styles[location] = marking_style @@ -117,13 +88,9 @@ /mob/living/carbon/human/proc/change_body_accessory(var/body_accessory_style) var/found - if(!body_accessory_style) + if(!body_accessory_style || (src.body_accessory && src.body_accessory.name == body_accessory_style)) return - if(src.body_accessory) - if(src.body_accessory.name == body_accessory_style) - return - for(var/B in body_accessory_by_name) if(B == body_accessory_style) src.body_accessory = body_accessory_by_name[body_accessory_style] @@ -138,6 +105,26 @@ update_tail_layer() return 1 +/mob/living/carbon/human/proc/change_alt_head(var/alternate_head) + var/obj/item/organ/external/head/H = get_organ("head") + if(H.alt_head == alternate_head || (H.status & ORGAN_ROBOT) || !(species.bodyflags & HAS_ALT_HEADS) || !(alternate_head in alt_heads_list)) + return + + H.alt_head = alternate_head + + //Handle head markings if they're incompatible with the new alt head. + var/list/marking_styles = params2list(m_styles) + if(marking_styles["head"]) + var/head_marking = marking_styles["head"] + var/datum/sprite_accessory/body_markings/head/head_marking_style = marking_styles_list[head_marking] + if(!head_marking_style.heads_allowed || !(H.alt_head in head_marking_style.heads_allowed)) + marking_styles["head"] = "None" + m_styles = list2params(marking_styles) + update_markings() + + update_body(1, 1) //Update the body and force limb icon regeneration to update the head with the new icon. + return 1 + /mob/living/carbon/human/proc/reset_hair() reset_head_hair() reset_facial_hair() @@ -298,11 +285,7 @@ var/datum/species/current_species = all_species[current_species_name] if(check_whitelist && config.usealienwhitelist && !check_rights(R_ADMIN, 0, src)) //If we're using the whitelist, make sure to check it! - if(whitelist.len && !(current_species_name in whitelist)) - continue - if(blacklist.len && (current_species_name in blacklist)) - continue - if((current_species.flags & IS_WHITELISTED) && !is_alien_whitelisted(src, current_species_name)) + if((whitelist.len && !(current_species_name in whitelist)) || (blacklist.len && (current_species_name in blacklist)) || ((current_species.flags & IS_WHITELISTED) && !is_alien_whitelisted(src, current_species_name))) continue valid_species += current_species_name @@ -315,9 +298,7 @@ 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) + if((gender == MALE && S.gender == FEMALE) || (gender == FEMALE && S.gender == MALE)) continue if(H.species.flags & ALL_RPARTS) //If the user is a species who can have a robotic head... var/datum/robolimb/robohead = all_robolimbs[H.model] @@ -349,9 +330,7 @@ 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) + if((gender == MALE && S.gender == FEMALE) || (gender == FEMALE && S.gender == MALE)) continue if(H.species.flags & ALL_RPARTS) //If the user is a species who can have a robotic head... var/datum/robolimb/robohead = all_robolimbs[H.model] @@ -440,3 +419,15 @@ valid_body_accessories += B return valid_body_accessories + +/mob/living/carbon/human/proc/generate_valid_alt_heads() + var/list/valid_alt_heads = list() + valid_alt_heads["None"] = alt_heads_list["None"] //The only null entry should be the "None" option, and there should always be a "None" option. + for(var/alternate_head in alt_heads_list) + var/datum/sprite_accessory/alt_heads/head = alt_heads_list[alternate_head] + if(!(species.name in head.species_allowed)) + continue + + valid_alt_heads[alternate_head] = alt_heads_list[alternate_head] + + return valid_alt_heads \ No newline at end of file diff --git a/code/modules/mob/living/carbon/human/species/station.dm b/code/modules/mob/living/carbon/human/species/station.dm index 0d9418e3107..ead6406c187 100644 --- a/code/modules/mob/living/carbon/human/species/station.dm +++ b/code/modules/mob/living/carbon/human/species/station.dm @@ -40,7 +40,7 @@ flags = HAS_LIPS clothing_flags = HAS_UNDERWEAR | HAS_UNDERSHIRT | HAS_SOCKS - bodyflags = FEET_CLAWS | HAS_TAIL | HAS_HEAD_ACCESSORY | HAS_BODY_MARKINGS | HAS_HEAD_MARKINGS | HAS_SKIN_COLOR | TAIL_WAGGING + bodyflags = FEET_CLAWS | HAS_TAIL | HAS_HEAD_ACCESSORY | HAS_BODY_MARKINGS | HAS_HEAD_MARKINGS | HAS_SKIN_COLOR | HAS_ALT_HEADS | TAIL_WAGGING dietflags = DIET_CARN cold_level_1 = 280 //Default 260 - Lower is better diff --git a/code/modules/mob/living/carbon/human/update_icons.dm b/code/modules/mob/living/carbon/human/update_icons.dm index 83ca7e0bfb9..35f99724e60 100644 --- a/code/modules/mob/living/carbon/human/update_icons.dm +++ b/code/modules/mob/living/carbon/human/update_icons.dm @@ -202,7 +202,7 @@ var/global/list/damage_icon_parts = list() if(update_icons) update_icons() //BASE MOB SPRITE -/mob/living/carbon/human/proc/update_body(var/update_icons=1) +/mob/living/carbon/human/proc/update_body(var/update_icons=1, var/rebuild_base=0) var/husk_color_mod = rgb(96,88,80) var/hulk_color_mod = rgb(48,224,40) @@ -252,7 +252,7 @@ var/global/list/damage_icon_parts = list() 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]) + if(human_icon_cache[icon_key] && !rebuild_base) base_icon = human_icon_cache[icon_key] else //BEGIN CACHED ICON GENERATION. @@ -560,7 +560,7 @@ var/global/list/damage_icon_parts = list() ..() if(notransform) return update_mutations(0) - update_body(0) + update_body(0, 1) //Update the body and force limb icon regeneration. update_hair(0) update_head_accessory(0) update_fhair(0) diff --git a/code/modules/nano/modules/human_appearance.dm b/code/modules/nano/modules/human_appearance.dm index ca20b394e9a..11e702e97a0 100644 --- a/code/modules/nano/modules/human_appearance.dm +++ b/code/modules/nano/modules/human_appearance.dm @@ -11,6 +11,7 @@ var/list/valid_body_marking_styles = list() var/list/valid_tail_marking_styles = list() var/list/valid_body_accessories = list() + var/list/valid_alt_head_styles = list() var/check_whitelist var/list/whitelist @@ -174,6 +175,11 @@ if(owner.change_body_accessory(href_list["body_accessory"])) update_dna() return 1 + if(href_list["alt_head"]) + if(can_change_alt_head() && (href_list["alt_head"] in valid_alt_head_styles)) + if(owner.change_alt_head(href_list["alt_head"])) + update_dna() + return 1 return 0 @@ -259,6 +265,14 @@ BA = owner.body_accessory.name data["body_accessory_style"] = BA + data["change_alt_head"] = can_change_alt_head() + if(data["change_alt_head"]) + var/alt_head_styles[0] + for(var/alt_head_style in valid_alt_head_styles) + alt_head_styles[++alt_head_styles.len] = list("altheadstyle" = alt_head_style) + data["alt_head_styles"] = alt_head_styles + data["alt_head_style"] = head_organ.alt_head + data["change_head_accessory_color"] = can_change_head_accessory() data["change_hair_color"] = can_change(APPEARANCE_HAIR_COLOR) data["change_facial_hair_color"] = can_change(APPEARANCE_FACIAL_HAIR_COLOR) @@ -289,19 +303,29 @@ return owner && (flags & APPEARANCE_HEAD_ACCESSORY) && (head_organ.species.bodyflags & HAS_HEAD_ACCESSORY) /datum/nano_module/appearance_changer/proc/can_change_markings(var/location = "body") - var/marking_flag + var/marking_flag = HAS_BODY_MARKINGS + var/body_flags = owner.species.bodyflags if(location == "head") + var/obj/item/organ/external/head/H = owner.get_organ("head") + body_flags = H.species.bodyflags marking_flag = HAS_HEAD_MARKINGS if(location == "body") marking_flag = HAS_BODY_MARKINGS if(location == "tail") marking_flag = HAS_TAIL_MARKINGS - return owner && (flags & APPEARANCE_MARKINGS) && (owner.species.bodyflags & marking_flag) + + + return owner && (flags & APPEARANCE_MARKINGS) && (body_flags & marking_flag) /datum/nano_module/appearance_changer/proc/can_change_body_accessory() return owner && (flags & APPEARANCE_BODY_ACCESSORY) && (owner.species.bodyflags & HAS_TAIL) +/datum/nano_module/appearance_changer/proc/can_change_alt_head() + if(owner.species.bodyflags & HAS_ALT_HEADS) + to_chat(world, "has alt heads") + return owner && (flags & APPEARANCE_ALT_HEAD) && (owner.species.bodyflags & HAS_ALT_HEADS) + /datum/nano_module/appearance_changer/proc/cut_and_generate_data() // Making the assumption that the available species remain constant valid_hairstyles.Cut() @@ -311,6 +335,7 @@ valid_body_marking_styles.Cut() valid_tail_marking_styles.Cut() valid_body_accessories.Cut() + valid_alt_head_styles.Cut() generate_data() /datum/nano_module/appearance_changer/proc/generate_data() @@ -331,3 +356,5 @@ valid_tail_marking_styles = owner.generate_valid_markings("tail") if(!valid_body_accessories.len) valid_body_accessories = owner.generate_valid_body_accessories() + if(!valid_alt_head_styles.len) + valid_alt_head_styles = owner.generate_valid_alt_heads() diff --git a/code/modules/surgery/organs/subtypes/standard.dm b/code/modules/surgery/organs/subtypes/standard.dm index 060a5ba7dce..f992c1dc92b 100644 --- a/code/modules/surgery/organs/subtypes/standard.dm +++ b/code/modules/surgery/organs/subtypes/standard.dm @@ -196,7 +196,9 @@ disfigure("burn") /obj/item/organ/external/head/proc/handle_alt_icon() - if(alt_head) + if(alt_head && alt_heads_list[alt_head]) var/datum/sprite_accessory/alt_heads/alternate_head = alt_heads_list[alt_head] if(alternate_head.icon_state) icon_name = alternate_head.icon_state + else + icon_name = initial(icon_name) diff --git a/nano/templates/appearance_changer.tmpl b/nano/templates/appearance_changer.tmpl index f25ab7d6bc3..060e4df88f8 100644 --- a/nano/templates/appearance_changer.tmpl +++ b/nano/templates/appearance_changer.tmpl @@ -150,3 +150,16 @@ {{/if}} + +{{if data.change_alt_head}} +