From f030b3b5aa8dcd4e06820d892208127f7325d6c6 Mon Sep 17 00:00:00 2001 From: ChungusGamer666 <82850673+ChungusGamer666@users.noreply.github.com> Date: Thu, 22 Jun 2023 05:23:19 -0300 Subject: [PATCH] SPECIES NUKING 2023: Refactors a bunch of species traits into flags for the head bodypart (#76074) ## About The Pull Request Title. I saw a comment on psyker code complaining about these species traits (which admittedly, they suck) and heeded the call to turn all of this crap into something defined almost entirely by the head bodypart. ## Why It's Good For The Game Potential to simplify species code further in the future, by delegating more visuals to bodyparts, which is where most of them should be handled. ## Changelog Should not be player facing, unless I fucked up. --------- Co-authored-by: Time-Green --- code/__DEFINES/DNA.dm | 33 +-- code/__DEFINES/colors.dm | 1 + code/__DEFINES/sprite_accessories.dm | 9 + code/__DEFINES/surgery.dm | 18 ++ code/_globalvars/bitfields.dm | 10 + code/datums/mutations/body.dm | 11 +- code/datums/wounds/_wounds.dm | 4 +- code/game/objects/items/cosmetics.dm | 253 +++++++++--------- .../nightmare/nightmare_species.dm | 6 +- .../modules/client/preferences/_preference.dm | 4 + .../preferences/species_features/basic.dm | 18 +- code/modules/clothing/head/wig.dm | 6 +- code/modules/clothing/suits/wiz_robe.dm | 2 +- .../exploration_events/resource.dm | 4 +- .../mob/dead/new_player/sprite_accessories.dm | 10 +- code/modules/mob/dead/observer/observer.dm | 10 +- .../mob/living/carbon/carbon_update_icons.dm | 41 ++- .../carbon/human/{species.dm => _species.dm} | 81 +++--- .../living/carbon/human/human_update_icons.dm | 21 +- .../carbon/human/species_types/abductors.dm | 2 - .../carbon/human/species_types/android.dm | 1 - .../carbon/human/species_types/dullahan.dm | 7 +- .../carbon/human/species_types/ethereal.dm | 3 +- .../carbon/human/species_types/golems.dm | 1 - .../carbon/human/species_types/humans.dm | 7 +- .../carbon/human/species_types/jellypeople.dm | 6 +- .../human/species_types/lizardpeople.dm | 4 - .../carbon/human/species_types/monkeys.dm | 3 - .../carbon/human/species_types/mothmen.dm | 1 - .../carbon/human/species_types/mushpeople.dm | 3 +- .../carbon/human/species_types/plasmamen.dm | 1 - .../carbon/human/species_types/podpeople.dm | 1 - .../human/species_types/shadowpeople.dm | 4 +- .../carbon/human/species_types/skeletons.dm | 2 - .../carbon/human/species_types/vampire.dm | 4 - .../chemistry/reagents/other_reagents.dm | 13 +- code/modules/religion/burdened/psyker.dm | 14 +- code/modules/surgery/bodyparts/_bodyparts.dm | 11 +- .../surgery/bodyparts/dismemberment.dm | 6 +- code/modules/surgery/bodyparts/head.dm | 172 +++++++----- .../{hair.dm => head_hair_and_lips.dm} | 78 +++--- code/modules/surgery/bodyparts/helpers.dm | 2 +- .../surgery/bodyparts/robot_bodyparts.dm | 2 + .../species_parts/ethereal_bodyparts.dm | 1 + .../species_parts/lizard_bodyparts.dm | 1 + .../bodyparts/species_parts/misc_bodyparts.dm | 12 + .../bodyparts/species_parts/moth_bodyparts.dm | 1 + .../species_parts/plasmaman_bodyparts.dm | 1 + code/modules/surgery/organs/eyes.dm | 23 +- ...s__datum_species_human_krokodil_addict.png | Bin 1072 -> 1072 bytes tgstation.dme | 5 +- 51 files changed, 494 insertions(+), 440 deletions(-) create mode 100644 code/__DEFINES/sprite_accessories.dm rename code/modules/mob/living/carbon/human/{species.dm => _species.dm} (97%) rename code/modules/surgery/bodyparts/{hair.dm => head_hair_and_lips.dm} (70%) diff --git a/code/__DEFINES/DNA.dm b/code/__DEFINES/DNA.dm index b6420551702..3ec37afc5de 100644 --- a/code/__DEFINES/DNA.dm +++ b/code/__DEFINES/DNA.dm @@ -62,33 +62,24 @@ #define DNA_MUTATION_BLOCKS 8 #define DNA_UNIQUE_ENZYMES_LEN 32 -//species traits for mutantraces +// species_traits list on /datum/species, please avoid adding more and use inherent_traits instead where possible #define MUTCOLORS 1 -#define HAIR 2 -#define FACEHAIR 3 -#define EYECOLOR 4 -#define LIPS 5 -#define NOTRANSSTING 7 -#define NOZOMBIE 8 -#define NO_UNDERWEAR 9 -#define NO_DNA_COPY 10 -#define DRINKSBLOOD 11 - +#define NOTRANSSTING 2 +#define NOZOMBIE 3 +#define NO_UNDERWEAR 4 +#define NO_DNA_COPY 5 +#define DRINKSBLOOD 6 /// Use this if you want to change the race's color without the player being able to pick their own color. AKA special color shifting -#define DYNCOLORS 12 -#define AGENDER 13 -/// Do not draw eyes or eyeless overlay -#define NOEYESPRITES 14 +#define DYNCOLORS 7 +#define AGENDER 8 ///If we have a limb-specific overlay sprite -#define HAS_MARKINGS 15 +#define HAS_MARKINGS 9 /// Do not draw blood overlay -#define NOBLOODOVERLAY 16 +#define NOBLOODOVERLAY 10 ///No augments, for monkeys in specific because they will turn into fucking freakazoids https://cdn.discordapp.com/attachments/326831214667235328/791313258912153640/102707682-fa7cad80-4294-11eb-8f13-8c689468aeb0.png -#define NOAUGMENTS 17 +#define NOAUGMENTS 11 ///will be assigned a universal vampire themed last name shared by their department. this is preferenced! -#define BLOOD_CLANS 18 -/// Similar to NOEYESPRITES but only excludes the eyeless overlay -#define NOEYEHOLES 19 +#define BLOOD_CLANS 12 //organ slots #define ORGAN_SLOT_ADAMANTINE_RESONATOR "adamantine_resonator" diff --git a/code/__DEFINES/colors.dm b/code/__DEFINES/colors.dm index ebc5ad3cded..3c27ede813f 100644 --- a/code/__DEFINES/colors.dm +++ b/code/__DEFINES/colors.dm @@ -55,6 +55,7 @@ #define COLOR_ASSISTANT_OLIVE "#828163" #define COLOR_VIBRANT_LIME "#00FF00" #define COLOR_SERVICE_LIME "#58C800" +#define COLOR_JADE "#5EFB6E" #define COLOR_LIME "#32CD32" #define COLOR_DARK_LIME "#00aa00" #define COLOR_VERY_PALE_LIME_GREEN "#DDFFD3" diff --git a/code/__DEFINES/sprite_accessories.dm b/code/__DEFINES/sprite_accessories.dm new file mode 100644 index 00000000000..9c9471130e6 --- /dev/null +++ b/code/__DEFINES/sprite_accessories.dm @@ -0,0 +1,9 @@ +// ~color source defines for sprite accessories +/// Color of the sprite accessory will match the owner's mutant color, which is granted by certain species +#define MUTANT_COLOR "mutant_color" +/// Color of the sprite accessory will match the owner's hair color +#define HAIR_COLOR "hair_color" +/// Color of the sprite accessory will match the owner's facial hair color +#define FACIAL_HAIR_COLOR "facial_hair_color" +/// Color of the sprite accessory will match the owner's (left) eye color +#define EYE_COLOR "eye_color" diff --git a/code/__DEFINES/surgery.dm b/code/__DEFINES/surgery.dm index 5f698598d73..3a068666090 100644 --- a/code/__DEFINES/surgery.dm +++ b/code/__DEFINES/surgery.dm @@ -28,6 +28,24 @@ ///Bodypart does not get replaced during set_species() #define BP_BLOCK_CHANGE_SPECIES (1<<0) +// Flags for the head_flags var on /obj/item/bodypart/head +/// Head can have hair +#define HEAD_HAIR (1<<0) +/// Head can have facial hair +#define HEAD_FACIAL_HAIR (1<<1) +/// Head can have lips +#define HEAD_LIPS (1<<2) +/// Head can have eye sprites +#define HEAD_EYESPRITES (1<<3) +/// Head will have colored eye sprites +#define HEAD_EYECOLOR (1<<4) +/// Head can have eyeholes when missing eyes +#define HEAD_EYEHOLES (1<<5) +/// Head can have debrain overlay +#define HEAD_DEBRAIN (1<<6) +/// All head flags, default for most heads +#define HEAD_ALL_FEATURES (HEAD_HAIR|HEAD_FACIAL_HAIR|HEAD_LIPS|HEAD_EYESPRITES|HEAD_EYECOLOR|HEAD_EYEHOLES|HEAD_DEBRAIN) + /// When the surgery step fails :( #define SURGERY_STEP_FAIL -1 diff --git a/code/_globalvars/bitfields.dm b/code/_globalvars/bitfields.dm index d2c3459d751..12c6646dbd9 100644 --- a/code/_globalvars/bitfields.dm +++ b/code/_globalvars/bitfields.dm @@ -390,6 +390,16 @@ DEFINE_BITFIELD(change_exempt_flags, list( "BP_BLOCK_CHANGE_SPECIES" = BP_BLOCK_CHANGE_SPECIES, )) +DEFINE_BITFIELD(head_flags, list( + "HEAD_HAIR" = HEAD_HAIR, + "HEAD_FACIAL_HAIR" = HEAD_FACIAL_HAIR, + "HEAD_LIPS" = HEAD_LIPS, + "HEAD_EYESPRITES" = HEAD_EYESPRITES, + "HEAD_EYECOLOR" = HEAD_EYECOLOR, + "HEAD_EYEHOLES" = HEAD_EYEHOLES, + "HEAD_DEBRAIN" = HEAD_DEBRAIN, +)) + DEFINE_BITFIELD(supports_variations_flags, list( "CLOTHING_NO_VARIATION" = CLOTHING_NO_VARIATION, "CLOTHING_DIGITIGRADE_VARIATION" = CLOTHING_DIGITIGRADE_VARIATION, diff --git a/code/datums/mutations/body.dm b/code/datums/mutations/body.dm index 050dc055ef8..21c76f4ad92 100644 --- a/code/datums/mutations/body.dm +++ b/code/datums/mutations/body.dm @@ -497,6 +497,7 @@ . = ..() if(.)//cant add return TRUE + var/obj/item/organ/internal/brain/brain = owner.get_organ_slot(ORGAN_SLOT_BRAIN) if(brain) brain.zone = BODY_ZONE_CHEST @@ -505,11 +506,10 @@ if(head) owner.visible_message(span_warning("[owner]'s head splatters with a sickening crunch!"), ignored_mobs = list(owner)) new /obj/effect/gibspawner/generic(get_turf(owner), owner) - head.dismember(BRUTE) + head.dismember(dam_type = BRUTE, silent = TRUE) head.drop_organs() qdel(head) - owner.regenerate_icons() - RegisterSignal(owner, COMSIG_ATTEMPT_CARBON_ATTACH_LIMB, PROC_REF(abortattachment)) + RegisterSignal(owner, COMSIG_ATTEMPT_CARBON_ATTACH_LIMB, PROC_REF(abort_attachment)) /datum/mutation/human/headless/on_losing() . = ..() @@ -517,7 +517,7 @@ return TRUE var/obj/item/organ/internal/brain/brain = owner.get_organ_slot(ORGAN_SLOT_BRAIN) if(brain) //so this doesn't instantly kill you. we could delete the brain, but it lets people cure brain issues they /really/ shouldn't be - brain.zone = BODY_ZONE_HEAD + brain.zone = initial(brain.zone) UnregisterSignal(owner, COMSIG_ATTEMPT_CARBON_ATTACH_LIMB) var/successful = owner.regenerate_limb(BODY_ZONE_HEAD) if(!successful) @@ -528,8 +528,7 @@ owner.visible_message(span_warning("[owner]'s head returns with a sickening crunch!"), span_warning("Your head regrows with a sickening crack! Ouch.")) new /obj/effect/gibspawner/generic(get_turf(owner), owner) - -/datum/mutation/human/headless/proc/abortattachment(datum/source, obj/item/bodypart/new_limb, special) //you aren't getting your head back +/datum/mutation/human/headless/proc/abort_attachment(datum/source, obj/item/bodypart/new_limb, special) //you aren't getting your head back SIGNAL_HANDLER if(istype(new_limb, /obj/item/bodypart/head)) diff --git a/code/datums/wounds/_wounds.dm b/code/datums/wounds/_wounds.dm index 49986be64ce..6137e8820db 100644 --- a/code/datums/wounds/_wounds.dm +++ b/code/datums/wounds/_wounds.dm @@ -140,9 +140,7 @@ set_limb(L) LAZYADD(victim.all_wounds, src) LAZYADD(limb.wounds, src) - //it's ok to not typecheck, humans are the only ones that deal with wounds - var/mob/living/carbon/human/human_victim = victim - no_bleeding = HAS_TRAIT(human_victim, TRAIT_NOBLOOD) + no_bleeding = HAS_TRAIT(victim, TRAIT_NOBLOOD) update_descriptions() limb.update_wounds() if(status_effect_type) diff --git a/code/game/objects/items/cosmetics.dm b/code/game/objects/items/cosmetics.dm index b2ccded220b..3a54a579088 100644 --- a/code/game/objects/items/cosmetics.dm +++ b/code/game/objects/items/cosmetics.dm @@ -6,8 +6,9 @@ icon_state = "lipstick" inhand_icon_state = "lipstick" w_class = WEIGHT_CLASS_TINY - var/colour = "red" var/open = FALSE + /// Actual color of the lipstick, also gets applied to the human + var/lipstick_color = COLOR_RED /// A trait that's applied while someone has this lipstick applied, and is removed when the lipstick is removed var/lipstick_trait @@ -31,33 +32,32 @@ if(!open) return var/mutable_appearance/colored_overlay = mutable_appearance(icon, "lipstick_uncap_color") - colored_overlay.color = colour + colored_overlay.color = lipstick_color . += colored_overlay /obj/item/lipstick/purple name = "purple lipstick" - colour = "purple" + lipstick_color = COLOR_PURPLE /obj/item/lipstick/jade - //It's still called Jade, but theres no HTML color for jade, so we use lime. name = "jade lipstick" - colour = "lime" + lipstick_color = COLOR_JADE /obj/item/lipstick/blue name = "blue lipstick" - colour = "blue" + lipstick_color = COLOR_BLUE /obj/item/lipstick/green name = "green lipstick" - colour = "green" + lipstick_color = COLOR_GREEN /obj/item/lipstick/white name = "white lipstick" - colour = "white" + lipstick_color = COLOR_WHITE /obj/item/lipstick/black name = "black lipstick" - colour = "black" + lipstick_color = COLOR_BLACK /obj/item/lipstick/black/death name = "\improper Kiss of Death" @@ -71,8 +71,16 @@ /obj/item/lipstick/random/Initialize(mapload) . = ..() icon_state = "lipstick" - colour = pick("red","purple","lime","black","green","blue","white") - name = "[colour] lipstick" + var/static/list/possible_colors + if(!possible_colors) + possible_colors = list() + for(var/obj/item/lipstick/lipstick_path as anything in (typesof(/obj/item/lipstick) - src.type)) + if(!initial(lipstick_path.lipstick_color)) + continue + possible_colors[initial(lipstick_path.lipstick_color)] = initial(lipstick_path.name) + lipstick_color = pick(possible_colors) + name = possible_colors[lipstick_color] + update_appearance() /obj/item/lipstick/attack_self(mob/user) to_chat(user, span_notice("You twist [src] [open ? "closed" : "open"].")) @@ -98,7 +106,7 @@ if(target == user) user.visible_message(span_notice("[user] does [user.p_their()] lips with \the [src]."), \ span_notice("You take a moment to apply \the [src]. Perfect!")) - target.update_lips("lipstick", colour, lipstick_trait) + target.update_lips("lipstick", lipstick_color, lipstick_trait) return user.visible_message(span_warning("[user] begins to do [target]'s lips with \the [src]."), \ @@ -107,8 +115,7 @@ return user.visible_message(span_notice("[user] does [target]'s lips with \the [src]."), \ span_notice("You apply \the [src] on [target]'s lips.")) - target.update_lips("lipstick", colour, lipstick_trait) - + target.update_lips("lipstick", lipstick_color, lipstick_trait) //you can wipe off lipstick with paper! /obj/item/paper/attack(mob/M, mob/user) @@ -129,7 +136,6 @@ span_notice("You wipe off [target]'s lipstick.")) target.update_lips(null) - /obj/item/razor name = "electric razor" desc = "The latest and greatest power razor born from the science of shaving." @@ -145,125 +151,130 @@ shave(user, BODY_ZONE_HEAD)//doesnt need to be BODY_ZONE_HEAD specifically, but whatever return BRUTELOSS -/obj/item/razor/proc/shave(mob/living/carbon/human/H, location = BODY_ZONE_PRECISE_MOUTH) +/obj/item/razor/proc/shave(mob/living/carbon/human/skinhead, location = BODY_ZONE_PRECISE_MOUTH) if(location == BODY_ZONE_PRECISE_MOUTH) - H.facial_hairstyle = "Shaved" + skinhead.facial_hairstyle = "Shaved" else - H.hairstyle = "Skinhead" + skinhead.hairstyle = "Skinhead" - H.update_body_parts() + skinhead.update_body_parts() playsound(loc, 'sound/items/welder2.ogg', 20, TRUE) -/obj/item/razor/attack(mob/M, mob/living/user) - if(ishuman(M)) - var/mob/living/carbon/human/H = M - var/location = user.zone_selected - if((location in list(BODY_ZONE_PRECISE_EYES, BODY_ZONE_PRECISE_MOUTH, BODY_ZONE_HEAD)) && !H.get_bodypart(BODY_ZONE_HEAD)) - to_chat(user, span_warning("[H] doesn't have a head!")) - return - if(location == BODY_ZONE_PRECISE_MOUTH) - if(!user.combat_mode) - if(H.gender == MALE) - if (H == user) - to_chat(user, span_warning("You need a mirror to properly style your own facial hair!")) - return - if(!user.can_perform_action(src, FORBID_TELEKINESIS_REACH)) - return - var/new_style = tgui_input_list(user, "Select a facial hairstyle", "Grooming", GLOB.facial_hairstyles_list) - if(isnull(new_style)) - return - if(!get_location_accessible(H, location)) - to_chat(user, span_warning("The mask is in the way!")) - return - if(HAS_TRAIT(H, TRAIT_SHAVED)) - to_chat(user, span_warning("[H] is just way too shaved. Like, really really shaved.")) - return - user.visible_message(span_notice("[user] tries to change [H]'s facial hairstyle using [src]."), span_notice("You try to change [H]'s facial hairstyle using [src].")) - if(new_style && do_after(user, 60, target = H)) - user.visible_message(span_notice("[user] successfully changes [H]'s facial hairstyle using [src]."), span_notice("You successfully change [H]'s facial hairstyle using [src].")) - H.facial_hairstyle = new_style - H.update_body_parts() - return - else - return - - else - if(!(FACEHAIR in H.dna.species.species_traits)) - to_chat(user, span_warning("There is no facial hair to shave!")) - return - if(!get_location_accessible(H, location)) - to_chat(user, span_warning("The mask is in the way!")) - return - if(H.facial_hairstyle == "Shaved") - to_chat(user, span_warning("Already clean-shaven!")) - return - - if(H == user) //shaving yourself - user.visible_message(span_notice("[user] starts to shave [user.p_their()] facial hair with [src]."), \ - span_notice("You take a moment to shave your facial hair with [src]...")) - if(do_after(user, 50, target = H)) - user.visible_message(span_notice("[user] shaves [user.p_their()] facial hair clean with [src]."), \ - span_notice("You finish shaving with [src]. Fast and clean!")) - shave(H, location) - else - user.visible_message(span_warning("[user] tries to shave [H]'s facial hair with [src]."), \ - span_notice("You start shaving [H]'s facial hair...")) - if(do_after(user, 50, target = H)) - user.visible_message(span_warning("[user] shaves off [H]'s facial hair with [src]."), \ - span_notice("You shave [H]'s facial hair clean off.")) - shave(H, location) - - else if(location == BODY_ZONE_HEAD) - if(!user.combat_mode) - if (H == user) - to_chat(user, span_warning("You need a mirror to properly style your own hair!")) +/obj/item/razor/attack(mob/target_mob, mob/living/user, params) + if(!ishuman(target_mob)) + return ..() + var/mob/living/carbon/human/human_target = target_mob + var/obj/item/bodypart/head/noggin = human_target.get_bodypart(BODY_ZONE_HEAD) + var/location = user.zone_selected + var/static/list/head_zones = list(BODY_ZONE_PRECISE_EYES, BODY_ZONE_PRECISE_MOUTH, BODY_ZONE_HEAD) + if(!noggin && (location in head_zones)) + to_chat(user, span_warning("[human_target] doesn't have a head!")) + return + if(location == BODY_ZONE_PRECISE_MOUTH) + if(!user.combat_mode) + if(human_target.gender == MALE) + if(human_target == user) + to_chat(user, span_warning("You need a mirror to properly style your own facial hair!")) return if(!user.can_perform_action(src, FORBID_TELEKINESIS_REACH)) return - var/new_style = tgui_input_list(user, "Select a hairstyle", "Grooming", GLOB.hairstyles_list) + var/new_style = tgui_input_list(user, "Select a facial hairstyle", "Grooming", GLOB.facial_hairstyles_list) if(isnull(new_style)) return - if(!get_location_accessible(H, location)) + if(!get_location_accessible(human_target, location)) to_chat(user, span_warning("The headgear is in the way!")) return - if(HAS_TRAIT(H, TRAIT_BALD)) - to_chat(user, span_warning("[H] is just way too bald. Like, really really bald.")) + if(!(noggin.head_flags & HEAD_FACIAL_HAIR)) + to_chat(user, span_warning("There is no facial hair to style!")) return - user.visible_message(span_notice("[user] tries to change [H]'s hairstyle using [src]."), span_notice("You try to change [H]'s hairstyle using [src].")) - if(new_style && do_after(user, 60, target = H)) - user.visible_message(span_notice("[user] successfully changes [H]'s hairstyle using [src]."), span_notice("You successfully change [H]'s hairstyle using [src].")) - H.hairstyle = new_style - H.update_body_parts() + if(HAS_TRAIT(human_target, TRAIT_SHAVED)) + to_chat(user, span_warning("[human_target] is just way too shaved. Like, really really shaved.")) + return + user.visible_message(span_notice("[user] tries to change [human_target]'s facial hairstyle using [src]."), span_notice("You try to change [human_target]'s facial hairstyle using [src].")) + if(new_style && do_after(user, 6 SECONDS, target = human_target)) + user.visible_message(span_notice("[user] successfully changes [human_target]'s facial hairstyle using [src]."), span_notice("You successfully change [human_target]'s facial hairstyle using [src].")) + human_target.facial_hairstyle = new_style + human_target.update_body_parts(update_limb_data = TRUE) return - else - if(!(HAIR in H.dna.species.species_traits)) - to_chat(user, span_warning("There is no hair to shave!")) - return - if(!get_location_accessible(H, location)) - to_chat(user, span_warning("The headgear is in the way!")) - return - if(H.hairstyle == "Bald" || H.hairstyle == "Balding Hair" || H.hairstyle == "Skinhead") - to_chat(user, span_warning("There is not enough hair left to shave!")) - return - - if(H == user) //shaving yourself - user.visible_message(span_notice("[user] starts to shave [user.p_their()] head with [src]."), \ - span_notice("You start to shave your head with [src]...")) - if(do_after(user, 5, target = H)) - user.visible_message(span_notice("[user] shaves [user.p_their()] head with [src]."), \ - span_notice("You finish shaving with [src].")) - shave(H, location) - else - var/turf/H_loc = H.loc - user.visible_message(span_warning("[user] tries to shave [H]'s head with [src]!"), \ - span_notice("You start shaving [H]'s head...")) - if(do_after(user, 50, target = H)) - if(H_loc == H.loc) - user.visible_message(span_warning("[user] shaves [H]'s head bald with [src]!"), \ - span_notice("You shave [H]'s head bald.")) - shave(H, location) + return else - ..() - else - ..() + if(!get_location_accessible(human_target, location)) + to_chat(user, span_warning("The mask is in the way!")) + return + if(!(noggin.head_flags & HEAD_FACIAL_HAIR)) + to_chat(user, span_warning("There is no facial hair to shave!")) + return + if(human_target.facial_hairstyle == "Shaved") + to_chat(user, span_warning("Already clean-shaven!")) + return + + if(human_target == user) //shaving yourself + user.visible_message(span_notice("[user] starts to shave [user.p_their()] facial hair with [src]."), \ + span_notice("You take a moment to shave your facial hair with [src]...")) + if(do_after(user, 5 SECONDS, target = user)) + user.visible_message(span_notice("[user] shaves [user.p_their()] facial hair clean with [src]."), \ + span_notice("You finish shaving with [src]. Fast and clean!")) + shave(user, location) + return + else + user.visible_message(span_warning("[user] tries to shave [human_target]'s facial hair with [src]."), \ + span_notice("You start shaving [human_target]'s facial hair...")) + if(do_after(user, 5 SECONDS, target = human_target)) + user.visible_message(span_warning("[user] shaves off [human_target]'s facial hair with [src]."), \ + span_notice("You shave [human_target]'s facial hair clean off.")) + shave(human_target, location) + return + else if(location == BODY_ZONE_HEAD) + if(!user.combat_mode) + if(human_target == user) + to_chat(user, span_warning("You need a mirror to properly style your own hair!")) + return + if(!user.can_perform_action(src, FORBID_TELEKINESIS_REACH)) + return + var/new_style = tgui_input_list(user, "Select a hairstyle", "Grooming", GLOB.hairstyles_list) + if(isnull(new_style)) + return + if(!get_location_accessible(human_target, location)) + to_chat(user, span_warning("The headgear is in the way!")) + return + if(!(noggin.head_flags & HEAD_HAIR)) + to_chat(user, span_warning("There is no hair to style!")) + return + if(HAS_TRAIT(human_target, TRAIT_BALD)) + to_chat(user, span_warning("[human_target] is just way too bald. Like, really really bald.")) + return + user.visible_message(span_notice("[user] tries to change [human_target]'s hairstyle using [src]."), span_notice("You try to change [human_target]'s hairstyle using [src].")) + if(new_style && do_after(user, 6 SECONDS, target = human_target)) + user.visible_message(span_notice("[user] successfully changes [human_target]'s hairstyle using [src]."), span_notice("You successfully change [human_target]'s hairstyle using [src].")) + human_target.hairstyle = new_style + human_target.update_body_parts(update_limb_data = TRUE) + return + else + if(!get_location_accessible(human_target, location)) + to_chat(user, span_warning("The headgear is in the way!")) + return + if(!(noggin.head_flags & HEAD_HAIR)) + to_chat(user, span_warning("There is no hair to shave!")) + return + if(human_target.hairstyle == "Bald" || human_target.hairstyle == "Balding Hair" || human_target.hairstyle == "Skinhead") + to_chat(user, span_warning("There is not enough hair left to shave!")) + return + + if(human_target == user) //shaving yourself + user.visible_message(span_notice("[user] starts to shave [user.p_their()] head with [src]."), \ + span_notice("You start to shave your head with [src]...")) + if(do_after(user, 5 SECONDS, target = user)) + user.visible_message(span_notice("[user] shaves [user.p_their()] head with [src]."), \ + span_notice("You finish shaving with [src].")) + shave(user, location) + return + else + user.visible_message(span_warning("[user] tries to shave [human_target]'s head with [src]!"), \ + span_notice("You start shaving [human_target]'s head...")) + if(do_after(user, 5 SECONDS, target = human_target)) + user.visible_message(span_warning("[user] shaves [human_target]'s head bald with [src]!"), \ + span_notice("You shave [human_target]'s head bald.")) + shave(human_target, location) + return + return ..() diff --git a/code/modules/antagonists/nightmare/nightmare_species.dm b/code/modules/antagonists/nightmare/nightmare_species.dm index fa8c0da16e6..32d12cffc33 100644 --- a/code/modules/antagonists/nightmare/nightmare_species.dm +++ b/code/modules/antagonists/nightmare/nightmare_species.dm @@ -7,7 +7,11 @@ examine_limb_id = SPECIES_SHADOW changesource_flags = MIRROR_BADMIN | WABBAJACK | MIRROR_PRIDE no_equip_flags = ITEM_SLOT_MASK | ITEM_SLOT_OCLOTHING | ITEM_SLOT_GLOVES | ITEM_SLOT_FEET | ITEM_SLOT_ICLOTHING | ITEM_SLOT_SUITSTORE - species_traits = list(NO_UNDERWEAR,NO_DNA_COPY,NOTRANSSTING,NOEYESPRITES) + species_traits = list( + NO_UNDERWEAR, + NO_DNA_COPY, + NOTRANSSTING, + ) inherent_traits = list( TRAIT_ADVANCEDTOOLUSER, TRAIT_CAN_STRIP, diff --git a/code/modules/client/preferences/_preference.dm b/code/modules/client/preferences/_preference.dm index 54695d937b1..d74bd71d723 100644 --- a/code/modules/client/preferences/_preference.dm +++ b/code/modules/client/preferences/_preference.dm @@ -109,6 +109,10 @@ GLOBAL_LIST_INIT(preference_entries_by_key, init_preference_entries_by_key()) /// will show the feature as selectable. var/relevant_external_organ = null + /// If the selected species has this head_flag by default, + /// will show the feature as selectable. + var/relevant_head_flag = null + /// Called on the saved input when retrieving. /// Also called by the value sent from the user through UI. Do not trust it. /// Input is the value inside the savefile, output is to tell other code diff --git a/code/modules/client/preferences/species_features/basic.dm b/code/modules/client/preferences/species_features/basic.dm index 257269070bc..1af8211208d 100644 --- a/code/modules/client/preferences/species_features/basic.dm +++ b/code/modules/client/preferences/species_features/basic.dm @@ -26,7 +26,7 @@ savefile_key = "eye_color" savefile_identifier = PREFERENCE_CHARACTER category = PREFERENCE_CATEGORY_SECONDARY_FEATURES - relevant_species_trait = EYECOLOR + relevant_head_flag = HEAD_EYECOLOR /datum/preference/color/eye_color/apply_to_human(mob/living/carbon/human/target, value) var/hetero = target.eye_color_heterochromatic @@ -59,7 +59,7 @@ category = PREFERENCE_CATEGORY_FEATURES main_feature_name = "Facial hair" should_generate_icons = TRUE - relevant_species_trait = FACEHAIR + relevant_head_flag = HEAD_FACIAL_HAIR /datum/preference/choiced/facial_hairstyle/init_possible_values() return generate_possible_values_for_sprite_accessories_on_head(GLOB.facial_hairstyles_list) @@ -79,7 +79,7 @@ savefile_key = "facial_hair_color" savefile_identifier = PREFERENCE_CHARACTER category = PREFERENCE_CATEGORY_SUPPLEMENTAL_FEATURES - relevant_species_trait = FACEHAIR + relevant_head_flag = HEAD_FACIAL_HAIR /datum/preference/color/facial_hair_color/apply_to_human(mob/living/carbon/human/target, value) target.facial_hair_color = value @@ -89,7 +89,7 @@ category = PREFERENCE_CATEGORY_SECONDARY_FEATURES savefile_identifier = PREFERENCE_CHARACTER savefile_key = "facial_hair_gradient" - relevant_species_trait = FACEHAIR + relevant_head_flag = HEAD_FACIAL_HAIR /datum/preference/choiced/facial_hair_gradient/init_possible_values() return assoc_to_keys_features(GLOB.facial_hair_gradients_list) @@ -106,7 +106,7 @@ category = PREFERENCE_CATEGORY_SECONDARY_FEATURES savefile_identifier = PREFERENCE_CHARACTER savefile_key = "facial_hair_gradient_color" - relevant_species_trait = FACEHAIR + relevant_head_flag = HEAD_FACIAL_HAIR /datum/preference/color/facial_hair_gradient/apply_to_human(mob/living/carbon/human/target, value) LAZYSETLEN(target.grad_color, GRADIENTS_LEN) @@ -122,7 +122,7 @@ savefile_key = "hair_color" savefile_identifier = PREFERENCE_CHARACTER category = PREFERENCE_CATEGORY_SUPPLEMENTAL_FEATURES - relevant_species_trait = HAIR + relevant_head_flag = HEAD_HAIR /datum/preference/color/hair_color/apply_to_human(mob/living/carbon/human/target, value) target.hair_color = value @@ -133,7 +133,7 @@ category = PREFERENCE_CATEGORY_FEATURES main_feature_name = "Hairstyle" should_generate_icons = TRUE - relevant_species_trait = HAIR + relevant_head_flag = HEAD_HAIR /datum/preference/choiced/hairstyle/init_possible_values() return generate_possible_values_for_sprite_accessories_on_head(GLOB.hairstyles_list) @@ -152,7 +152,7 @@ category = PREFERENCE_CATEGORY_SECONDARY_FEATURES savefile_identifier = PREFERENCE_CHARACTER savefile_key = "hair_gradient" - relevant_species_trait = HAIR + relevant_head_flag = HEAD_HAIR /datum/preference/choiced/hair_gradient/init_possible_values() return assoc_to_keys_features(GLOB.hair_gradients_list) @@ -169,7 +169,7 @@ category = PREFERENCE_CATEGORY_SECONDARY_FEATURES savefile_identifier = PREFERENCE_CHARACTER savefile_key = "hair_gradient_color" - relevant_species_trait = HAIR + relevant_head_flag = HEAD_HAIR /datum/preference/color/hair_gradient/apply_to_human(mob/living/carbon/human/target, value) LAZYSETLEN(target.grad_color, GRADIENTS_LEN) diff --git a/code/modules/clothing/head/wig.dm b/code/modules/clothing/head/wig.dm index 62c8f803a7a..c71e5672c70 100644 --- a/code/modules/clothing/head/wig.dm +++ b/code/modules/clothing/head/wig.dm @@ -70,6 +70,10 @@ if((head.flags_inv & HIDEHAIR) && !istype(head, /obj/item/clothing/head/wig)) to_chat(user, span_warning("You can't get a good look at [target.p_their()] hair!")) return + var/obj/item/bodypart/head/noggin = target.get_bodypart(BODY_ZONE_HEAD) + if(!noggin) + to_chat(user, span_warning("[target.p_they(TRUE)] have no head!")) + return var/selected_hairstyle = null var/selected_hairstyle_color = null @@ -77,7 +81,7 @@ var/obj/item/clothing/head/wig/wig = target.head selected_hairstyle = wig.hairstyle selected_hairstyle_color = wig.color - else if((HAIR in target.dna.species.species_traits) && target.hairstyle != "Bald") + else if((noggin.head_flags & HEAD_HAIR) && target.hairstyle != "Bald") selected_hairstyle = target.hairstyle selected_hairstyle_color = "[target.hair_color]" diff --git a/code/modules/clothing/suits/wiz_robe.dm b/code/modules/clothing/suits/wiz_robe.dm index a802c3ad4bf..63044cbc20f 100644 --- a/code/modules/clothing/suits/wiz_robe.dm +++ b/code/modules/clothing/suits/wiz_robe.dm @@ -66,7 +66,7 @@ inhand_icon_state = "tapehat" dog_fashion = null worn_y_offset = 6 - body_parts_covered = HEAD|HAIR + body_parts_covered = HEAD //this used to also cover HAIR, but that was never valid code as HAIR is not actually a body_part define! flags_inv = HIDEFACE|HIDEHAIR|HIDEFACIALHAIR /obj/item/clothing/head/wizard/magus diff --git a/code/modules/explorer_drone/exploration_events/resource.dm b/code/modules/explorer_drone/exploration_events/resource.dm index aa334f5685e..01f8c083c63 100644 --- a/code/modules/explorer_drone/exploration_events/resource.dm +++ b/code/modules/explorer_drone/exploration_events/resource.dm @@ -242,8 +242,8 @@ var/mob/living/carbon/human/head_species_source = new head_species_source.set_species(/datum/species/skeleton) head_species_source.real_name = "spaced locker victim" - var/obj/item/bodypart/head/skeleton_head = new - skeleton_head.update_limb(FALSE,head_species_source) + var/obj/item/bodypart/head/skeleton_head = head_species_source.get_bodypart(BODY_ZONE_HEAD) + skeleton_head.drop_limb(FALSE) qdel(head_species_source) drone.try_transfer(skeleton_head) diff --git a/code/modules/mob/dead/new_player/sprite_accessories.dm b/code/modules/mob/dead/new_player/sprite_accessories.dm index 289a92cf16b..ad8e7645ee2 100644 --- a/code/modules/mob/dead/new_player/sprite_accessories.dm +++ b/code/modules/mob/dead/new_player/sprite_accessories.dm @@ -62,7 +62,7 @@ * Currently only used by mutantparts so don't worry about hair and stuff. * This is the source that this accessory will get its color from. Default is MUTCOLOR, but can also be HAIR, FACEHAIR, EYECOLOR and 0 if none. */ - var/color_src = MUTCOLORS + var/color_src = MUTANT_COLOR /// Decides if this sprite has an "inner" part, such as the fleshy parts on ears. var/hasinner = FALSE /// Is this part locked from roundstart selection? Used for parts that apply effects. @@ -1767,7 +1767,7 @@ name = "Cat" icon = 'icons/mob/species/human/cat_features.dmi' icon_state = "default" - color_src = HAIR + color_src = HAIR_COLOR /datum/sprite_accessory/tails/monkey name = "Monkey" @@ -1879,14 +1879,14 @@ name = "Cat" icon_state = "cat" hasinner = TRUE - color_src = HAIR + color_src = HAIR_COLOR /datum/sprite_accessory/ears/fox icon = 'icons/mob/species/human/fox_features.dmi' name = "Fox" icon_state = "fox" hasinner = TRUE - color_src = HAIR + color_src = HAIR_COLOR locked = TRUE /datum/sprite_accessory/wings/none @@ -2105,7 +2105,7 @@ /datum/sprite_accessory/caps icon = 'icons/mob/species/mush_cap.dmi' - color_src = HAIR + color_src = HAIR_COLOR em_block = TRUE /datum/sprite_accessory/caps/round diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm index d1e001b54af..aee4f11d9d1 100644 --- a/code/modules/mob/dead/observer/observer.dm +++ b/code/modules/mob/dead/observer/observer.dm @@ -106,10 +106,11 @@ GLOBAL_VAR_INIT(observer_default_invisibility, INVISIBILITY_OBSERVER) if(ishuman(body)) var/mob/living/carbon/human/body_human = body - if(HAIR in body_human.dna.species.species_traits) + var/datum/species/human_species = body_human.dna.species + if(human_species.check_head_flags(HEAD_HAIR)) hairstyle = body_human.hairstyle hair_color = brighten_color(body_human.hair_color) - if(FACEHAIR in body_human.dna.species.species_traits) + if(human_species.check_head_flags(HEAD_FACIAL_HAIR)) facial_hairstyle = body_human.facial_hairstyle facial_hair_color = brighten_color(body_human.facial_hair_color) @@ -827,12 +828,11 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp var/species_type = client.prefs.read_preference(/datum/preference/choiced/species) var/datum/species/species = new species_type - - if(HAIR in species.species_traits) + if(species.check_head_flags(HEAD_HAIR)) hairstyle = client.prefs.read_preference(/datum/preference/choiced/hairstyle) hair_color = brighten_color(client.prefs.read_preference(/datum/preference/color/hair_color)) - if(FACEHAIR in species.species_traits) + if(species.check_head_flags(HEAD_FACIAL_HAIR)) facial_hairstyle = client.prefs.read_preference(/datum/preference/choiced/facial_hairstyle) facial_hair_color = brighten_color(client.prefs.read_preference(/datum/preference/color/facial_hair_color)) diff --git a/code/modules/mob/living/carbon/carbon_update_icons.dm b/code/modules/mob/living/carbon/carbon_update_icons.dm index f3ba4e25cb1..b722693c146 100644 --- a/code/modules/mob/living/carbon/carbon_update_icons.dm +++ b/code/modules/mob/living/carbon/carbon_update_icons.dm @@ -599,29 +599,46 @@ /obj/item/bodypart/head/generate_icon_key() . = ..() - . += "-[facial_hairstyle]" - . += "-[facial_hair_color]" - if(facial_hair_gradient_style) - . += "-[facial_hair_gradient_style]" - if(hair_gradient_color) - . += "-[facial_hair_gradient_color]" + if(lip_style) + . += "-[lip_style]" + . += "-[lip_color]" + if(facial_hair_hidden) . += "-FACIAL_HAIR_HIDDEN" + else + . += "-[facial_hairstyle]" + . += "-[override_hair_color || fixed_hair_color || facial_hair_color]" + . += "-[facial_hair_alpha]" + if(facial_hair_gradient_style) + . += "-[facial_hair_gradient_style]" + . += "-[facial_hair_gradient_color]" + + if(show_missing_eyes) + . += "-SHOW_MISSING_EYES" if(show_debrained) . += "-SHOW_DEBRAINED" return . - . += "-[hair_style]" - . += "-[fixed_hair_color || override_hair_color || hair_color]" - if(hair_gradient_style) - . += "-[hair_gradient_style]" - if(hair_gradient_color) - . += "-[hair_gradient_color]" if(hair_hidden) . += "-HAIR_HIDDEN" + else + . += "-[hair_style]" + . += "-[override_hair_color || fixed_hair_color || hair_color]" + . += "-[hair_alpha]" + if(hair_gradient_style) + . += "-[hair_gradient_style]" + . += "-[hair_gradient_color]" return . +/obj/item/bodypart/head/generate_husk_key() + . = ..() + if(show_missing_eyes) + . += "-SHOW_MISSING_EYES" + if(show_debrained) + . += "-SHOW_DEBRAINED" + return . + GLOBAL_LIST_EMPTY(masked_leg_icons_cache) /** diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/_species.dm similarity index 97% rename from code/modules/mob/living/carbon/human/species.dm rename to code/modules/mob/living/carbon/human/_species.dm index 602c021b1d7..4f4f38469dc 100644 --- a/code/modules/mob/living/carbon/human/species.dm +++ b/code/modules/mob/living/carbon/human/_species.dm @@ -32,6 +32,8 @@ GLOBAL_LIST_EMPTY(features_by_species) var/hair_color ///The alpha used by the hair. 255 is completely solid, 0 is invisible. var/hair_alpha = 255 + ///The alpha used by the facial hair. 255 is completely solid, 0 is invisible. + var/facial_hair_alpha = 255 ///This is used for children, it will determine their default limb ID for use of examine. See [/mob/living/carbon/human/proc/examine]. var/examine_limb_id @@ -180,9 +182,6 @@ GLOBAL_LIST_EMPTY(features_by_species) ///List of results you get from knife-butchering. null means you cant butcher it. Associated by resulting type - value of amount var/list/knife_butcher_results - ///List of visual overlays created by handle_body() - var/list/body_vis_overlays = list() - /// Should we preload this species's organs? var/preload = TRUE @@ -610,53 +609,25 @@ GLOBAL_LIST_EMPTY(features_by_species) return handle_mutant_bodyparts(species_human) var/list/standing = list() - var/obj/item/bodypart/head/noggin = species_human.get_bodypart(BODY_ZONE_HEAD) - - if(noggin && !(HAS_TRAIT(species_human, TRAIT_HUSK))) - // lipstick - if(species_human.lip_style && (LIPS in species_traits)) - var/mutable_appearance/lip_overlay = mutable_appearance('icons/mob/species/human/human_face.dmi', "lips_[species_human.lip_style]", -BODY_LAYER) - lip_overlay.color = species_human.lip_color - noggin.worn_face_offset?.apply_offset(lip_overlay) - lip_overlay.pixel_y += height_offset - standing += lip_overlay - - // eyes - if(!(NOEYESPRITES in species_traits)) + if(!HAS_TRAIT(species_human, TRAIT_HUSK)) + var/obj/item/bodypart/head/noggin = species_human.get_bodypart(BODY_ZONE_HEAD) + if(noggin?.head_flags & HEAD_EYESPRITES) + // eyes (missing eye sprites get handled by the head itself, but sadly we have to do this stupid shit here, for now) var/obj/item/organ/internal/eyes/eye_organ = species_human.get_organ_slot(ORGAN_SLOT_EYES) - var/mutable_appearance/no_eyeslay - var/add_pixel_x = 0 - var/add_pixel_y = 0 - //cut any possible vis overlays - if(body_vis_overlays.len) - SSvis_overlays.remove_vis_overlay(species_human, body_vis_overlays) - var/list/feature_offset = noggin.worn_face_offset?.get_offset() - if(feature_offset) - add_pixel_x = feature_offset["x"] - add_pixel_y = feature_offset["y"] - add_pixel_y += height_offset - if(eye_organ) eye_organ.refresh(call_update = FALSE) for(var/mutable_appearance/eye_overlay in eye_organ.generate_body_overlay(species_human)) eye_overlay.pixel_y += height_offset standing += eye_overlay - else if (!(NOEYEHOLES in species_traits)) - no_eyeslay = mutable_appearance('icons/mob/species/human/human_face.dmi', "eyes_missing", -BODY_LAYER) - no_eyeslay.pixel_x += add_pixel_x - no_eyeslay.pixel_y += add_pixel_y - standing += no_eyeslay - // organic body markings - if(HAS_MARKINGS in species_traits) - var/obj/item/bodypart/chest/chest = species_human.get_bodypart(BODY_ZONE_CHEST) - var/obj/item/bodypart/arm/right/right_arm = species_human.get_bodypart(BODY_ZONE_R_ARM) - var/obj/item/bodypart/arm/left/left_arm = species_human.get_bodypart(BODY_ZONE_L_ARM) - var/obj/item/bodypart/leg/right/right_leg = species_human.get_bodypart(BODY_ZONE_R_LEG) - var/obj/item/bodypart/leg/left/left_leg = species_human.get_bodypart(BODY_ZONE_L_LEG) - var/datum/sprite_accessory/markings = GLOB.moth_markings_list[species_human.dna.features["moth_markings"]] - - if(!HAS_TRAIT(species_human, TRAIT_HUSK)) + // organic body markings (oh my god this is terrible please rework this to be done on the limbs themselves i beg you) + if(HAS_MARKINGS in species_traits) + var/obj/item/bodypart/chest/chest = species_human.get_bodypart(BODY_ZONE_CHEST) + var/obj/item/bodypart/arm/right/right_arm = species_human.get_bodypart(BODY_ZONE_R_ARM) + var/obj/item/bodypart/arm/left/left_arm = species_human.get_bodypart(BODY_ZONE_L_ARM) + var/obj/item/bodypart/leg/right/right_leg = species_human.get_bodypart(BODY_ZONE_R_LEG) + var/obj/item/bodypart/leg/left/left_leg = species_human.get_bodypart(BODY_ZONE_L_LEG) + var/datum/sprite_accessory/markings = GLOB.moth_markings_list[species_human.dna.features["moth_markings"]] if(noggin && (IS_ORGANIC_LIMB(noggin))) var/mutable_appearance/markings_head_overlay = mutable_appearance(markings.icon, "[markings.icon_state]_head", -BODY_LAYER) markings_head_overlay.pixel_y += height_offset @@ -789,21 +760,21 @@ GLOBAL_LIST_EMPTY(features_by_species) if(!(HAS_TRAIT(source, TRAIT_HUSK))) if(!forced_colour) switch(accessory.color_src) - if(MUTCOLORS) + if(MUTANT_COLOR) if(fixed_mut_color) accessory_overlay.color = fixed_mut_color else accessory_overlay.color = source.dna.features["mcolor"] - if(HAIR) + if(HAIR_COLOR) if(hair_color == "mutcolor") accessory_overlay.color = source.dna.features["mcolor"] else if(hair_color == "fixedmutcolor") accessory_overlay.color = fixed_mut_color else accessory_overlay.color = source.hair_color - if(FACEHAIR) + if(FACIAL_HAIR_COLOR) accessory_overlay.color = source.facial_hair_color - if(EYECOLOR) + if(EYE_COLOR) accessory_overlay.color = source.eye_color_left else accessory_overlay.color = forced_colour @@ -1098,7 +1069,8 @@ GLOBAL_LIST_EMPTY(features_by_species) source.domutcheck() if(time_since_irradiated > RAD_MOB_HAIRLOSS && SPT_PROB(RAD_MOB_HAIRLOSS_PROB, seconds_per_tick)) - if(!(source.hairstyle == "Bald") && (HAIR in species_traits)) + var/obj/item/bodypart/head/head = source.get_bodypart(BODY_ZONE_HEAD) + if(!(source.hairstyle == "Bald") && (head?.head_flags & HEAD_HAIR|HEAD_FACIAL_HAIR)) to_chat(source, span_danger("Your hair starts to fall out in clumps...")) addtimer(CALLBACK(src, PROC_REF(go_bald), source), 5 SECONDS) @@ -1814,7 +1786,8 @@ GLOBAL_LIST_EMPTY(features_by_species) if ( \ (preference.relevant_mutant_bodypart in mutant_bodyparts) \ || (preference.relevant_species_trait in species_traits) \ - || (preference.relevant_external_organ in external_organs) + || (preference.relevant_external_organ in external_organs) \ + || (preference.relevant_head_flag && check_head_flags(preference.relevant_head_flag)) \ ) features += preference.savefile_key @@ -2331,3 +2304,13 @@ GLOBAL_LIST_EMPTY(features_by_species) /// Creates body parts for the target completely from scratch based on the species /datum/species/proc/create_fresh_body(mob/living/carbon/target) target.create_bodyparts(bodypart_overrides) + +/** + * Checks if the species has a head with these head flags, by default. + * Admittedly, this is a very weird and seemingly redundant proc, but it + * gets used by some preferences (such as hair style) to determine whether + * or not they are accessible. + **/ +/datum/species/proc/check_head_flags(check_flags = NONE) + var/obj/item/bodypart/head/fake_head = bodypart_overrides[BODY_ZONE_HEAD] + return (initial(fake_head.head_flags) & check_flags) diff --git a/code/modules/mob/living/carbon/human/human_update_icons.dm b/code/modules/mob/living/carbon/human/human_update_icons.dm index 7592ab7aa96..7377f65e791 100644 --- a/code/modules/mob/living/carbon/human/human_update_icons.dm +++ b/code/modules/mob/living/carbon/human/human_update_icons.dm @@ -759,31 +759,12 @@ generate/load female uniform sprites matching all previously decided variables var/obj/item/bodypart/head/my_head = get_bodypart(BODY_ZONE_HEAD) - if (!istype(my_head)) + if(!istype(my_head)) return my_head.update_limb(is_creating = update_limb_data) add_overlay(my_head.get_limb_icon()) - update_damage_overlays() - - if(my_head && !(HAS_TRAIT(src, TRAIT_HUSK))) - // lipstick - if(lip_style && (LIPS in dna.species.species_traits)) - var/mutable_appearance/lip_overlay = mutable_appearance('icons/mob/species/human/human_face.dmi', "lips_[lip_style]", -BODY_LAYER) - lip_overlay.color = lip_color - my_head.worn_face_offset?.apply_offset(lip_overlay) - add_overlay(lip_overlay) - - // eyes - if(!(NOEYESPRITES in dna.species.species_traits)) - var/obj/item/organ/internal/eyes/parent_eyes = get_organ_slot(ORGAN_SLOT_EYES) - if(parent_eyes) - add_overlay(parent_eyes.generate_body_overlay(src)) - else - var/mutable_appearance/missing_eyes = mutable_appearance('icons/mob/species/human/human_face.dmi', "eyes_missing", -BODY_LAYER) - my_head.worn_face_offset?.apply_offset(missing_eyes) - add_overlay(missing_eyes) update_worn_head() update_worn_mask() diff --git a/code/modules/mob/living/carbon/human/species_types/abductors.dm b/code/modules/mob/living/carbon/human/species_types/abductors.dm index 8aa309a84cc..8796bc41493 100644 --- a/code/modules/mob/living/carbon/human/species_types/abductors.dm +++ b/code/modules/mob/living/carbon/human/species_types/abductors.dm @@ -3,7 +3,6 @@ id = SPECIES_ABDUCTOR sexes = FALSE species_traits = list( - NOEYESPRITES, NO_UNDERWEAR, ) inherent_traits = list( @@ -11,7 +10,6 @@ TRAIT_NOHUNGER, TRAIT_VIRUSIMMUNE, TRAIT_NOBLOOD, - TRAIT_NO_DEBRAIN_OVERLAY, TRAIT_CHUNKYFINGERS_IGNORE_BATON, ) mutanttongue = /obj/item/organ/internal/tongue/abductor diff --git a/code/modules/mob/living/carbon/human/species_types/android.dm b/code/modules/mob/living/carbon/human/species_types/android.dm index 41828bdf1b4..152d5609b45 100644 --- a/code/modules/mob/living/carbon/human/species_types/android.dm +++ b/code/modules/mob/living/carbon/human/species_types/android.dm @@ -23,7 +23,6 @@ TRAIT_RESISTHIGHPRESSURE, TRAIT_TOXIMMUNE, TRAIT_NOBLOOD, - TRAIT_NO_DEBRAIN_OVERLAY, ) inherent_biotypes = MOB_ROBOTIC|MOB_HUMANOID diff --git a/code/modules/mob/living/carbon/human/species_types/dullahan.dm b/code/modules/mob/living/carbon/human/species_types/dullahan.dm index e0169ed5359..fff80507fe0 100644 --- a/code/modules/mob/living/carbon/human/species_types/dullahan.dm +++ b/code/modules/mob/living/carbon/human/species_types/dullahan.dm @@ -1,12 +1,7 @@ /datum/species/dullahan name = "Dullahan" id = SPECIES_DULLAHAN - species_traits = list( - EYECOLOR, - HAIR, - FACEHAIR, - LIPS, - ) + species_traits = list() inherent_traits = list( TRAIT_NOBREATH, TRAIT_NOHUNGER, diff --git a/code/modules/mob/living/carbon/human/species_types/ethereal.dm b/code/modules/mob/living/carbon/human/species_types/ethereal.dm index 3a74cb2ff88..43bb221c64e 100644 --- a/code/modules/mob/living/carbon/human/species_types/ethereal.dm +++ b/code/modules/mob/living/carbon/human/species_types/ethereal.dm @@ -14,8 +14,6 @@ DYNCOLORS, AGENDER, NO_UNDERWEAR, - HAIR, - FACEHAIR, ) changesource_flags = MIRROR_BADMIN | WABBAJACK | MIRROR_PRIDE | MIRROR_MAGIC | RACE_SWAP | ERT_SPAWN | SLIME_EXTRACT species_cookie = /obj/item/food/energybar @@ -29,6 +27,7 @@ bodytemp_cold_damage_limit = (T20C - 10) // about 10c hair_color = "fixedmutcolor" hair_alpha = 140 + facial_hair_alpha = 140 bodypart_overrides = list( BODY_ZONE_L_ARM = /obj/item/bodypart/arm/left/ethereal, diff --git a/code/modules/mob/living/carbon/human/species_types/golems.dm b/code/modules/mob/living/carbon/human/species_types/golems.dm index 38be9757777..1d7ea3d0c21 100644 --- a/code/modules/mob/living/carbon/human/species_types/golems.dm +++ b/code/modules/mob/living/carbon/human/species_types/golems.dm @@ -6,7 +6,6 @@ NO_DNA_COPY, NOTRANSSTING, NO_UNDERWEAR, - NOEYEHOLES, NOAUGMENTS, ) inherent_traits = list( diff --git a/code/modules/mob/living/carbon/human/species_types/humans.dm b/code/modules/mob/living/carbon/human/species_types/humans.dm index 1cb700ed7d9..33d845ce04c 100644 --- a/code/modules/mob/living/carbon/human/species_types/humans.dm +++ b/code/modules/mob/living/carbon/human/species_types/humans.dm @@ -1,12 +1,7 @@ /datum/species/human name = "\improper Human" id = SPECIES_HUMAN - species_traits = list( - EYECOLOR, - HAIR, - FACEHAIR, - LIPS, - ) + species_traits = list() inherent_traits = list( TRAIT_CAN_USE_FLIGHT_POTION, ) diff --git a/code/modules/mob/living/carbon/human/species_types/jellypeople.dm b/code/modules/mob/living/carbon/human/species_types/jellypeople.dm index eeba96849a0..c96a8e3e4e1 100644 --- a/code/modules/mob/living/carbon/human/species_types/jellypeople.dm +++ b/code/modules/mob/living/carbon/human/species_types/jellypeople.dm @@ -12,7 +12,6 @@ id = SPECIES_JELLYPERSON species_traits = list( MUTCOLORS, - EYECOLOR, ) inherent_traits = list( TRAIT_TOXINLOVER, @@ -176,9 +175,12 @@ name = "\improper Slimeperson" plural_form = "Slimepeople" id = SPECIES_SLIMEPERSON - species_traits = list(MUTCOLORS,EYECOLOR,HAIR,FACEHAIR) + species_traits = list( + MUTCOLORS, + ) hair_color = "mutcolor" hair_alpha = 150 + facial_hair_alpha = 150 changesource_flags = MIRROR_BADMIN | WABBAJACK | MIRROR_PRIDE | RACE_SWAP | ERT_SPAWN | SLIME_EXTRACT mutanteyes = /obj/item/organ/internal/eyes var/datum/action/innate/split_body/slime_split diff --git a/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm b/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm index 707df141132..e93efbae906 100644 --- a/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm +++ b/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm @@ -5,8 +5,6 @@ id = SPECIES_LIZARD species_traits = list( MUTCOLORS, - EYECOLOR, - LIPS, ) inherent_traits = list( TRAIT_CAN_USE_FLIGHT_POTION, @@ -142,8 +140,6 @@ Lizard subspecies: ASHWALKERS mutantbrain = /obj/item/organ/internal/brain/primitive species_traits = list( MUTCOLORS, - EYECOLOR, - LIPS, ) inherent_traits = list( //TRAIT_LITERATE, diff --git a/code/modules/mob/living/carbon/human/species_types/monkeys.dm b/code/modules/mob/living/carbon/human/species_types/monkeys.dm index 4ad0895d6c3..f3080d4274a 100644 --- a/code/modules/mob/living/carbon/human/species_types/monkeys.dm +++ b/code/modules/mob/living/carbon/human/species_types/monkeys.dm @@ -14,15 +14,12 @@ knife_butcher_results = list(/obj/item/food/meat/slab/monkey = 5, /obj/item/stack/sheet/animalhide/monkey = 1) species_traits = list( NO_UNDERWEAR, - LIPS, - NOEYESPRITES, NOBLOODOVERLAY, NOTRANSSTING, NOAUGMENTS, ) inherent_traits = list( TRAIT_GUN_NATURAL, - //TRAIT_LITERATE, TRAIT_VENTCRAWLER_NUDE, TRAIT_WEAK_SOUL, ) diff --git a/code/modules/mob/living/carbon/human/species_types/mothmen.dm b/code/modules/mob/living/carbon/human/species_types/mothmen.dm index b2767c3b0b9..be33d8dd553 100644 --- a/code/modules/mob/living/carbon/human/species_types/mothmen.dm +++ b/code/modules/mob/living/carbon/human/species_types/mothmen.dm @@ -3,7 +3,6 @@ plural_form = "Mothmen" id = SPECIES_MOTH species_traits = list( - LIPS, HAS_MARKINGS, ) inherent_traits = list( diff --git a/code/modules/mob/living/carbon/human/species_types/mushpeople.dm b/code/modules/mob/living/carbon/human/species_types/mushpeople.dm index 2b9ef4ef16d..93d7eee8a1e 100644 --- a/code/modules/mob/living/carbon/human/species_types/mushpeople.dm +++ b/code/modules/mob/living/carbon/human/species_types/mushpeople.dm @@ -10,7 +10,6 @@ species_traits = list( MUTCOLORS, - NOEYESPRITES, NO_UNDERWEAR, ) inherent_traits = list( @@ -28,7 +27,6 @@ mutanteyes = /obj/item/organ/internal/eyes/night_vision/mushroom mutantlungs = null use_skintones = FALSE - var/datum/martial_art/mushpunch/mush species_language_holder = /datum/language_holder/mushroom bodypart_overrides = list( @@ -39,6 +37,7 @@ BODY_ZONE_R_LEG = /obj/item/bodypart/leg/right/mushroom, BODY_ZONE_CHEST = /obj/item/bodypart/chest/mushroom, ) + var/datum/martial_art/mushpunch/mush /datum/species/mush/check_roundstart_eligible() return FALSE //hard locked out of roundstart on the order of design lead kor, this can be removed in the future when planetstation is here OR SOMETHING but right now we have a problem with races. diff --git a/code/modules/mob/living/carbon/human/species_types/plasmamen.dm b/code/modules/mob/living/carbon/human/species_types/plasmamen.dm index 6d6cb9f985c..6a82ef96a40 100644 --- a/code/modules/mob/living/carbon/human/species_types/plasmamen.dm +++ b/code/modules/mob/living/carbon/human/species_types/plasmamen.dm @@ -14,7 +14,6 @@ TRAIT_RADIMMUNE, TRAIT_RESISTCOLD, TRAIT_NOBLOOD, - TRAIT_NO_DEBRAIN_OVERLAY, ) inherent_biotypes = MOB_HUMANOID|MOB_MINERAL diff --git a/code/modules/mob/living/carbon/human/species_types/podpeople.dm b/code/modules/mob/living/carbon/human/species_types/podpeople.dm index 5296d0e823a..89e03756e19 100644 --- a/code/modules/mob/living/carbon/human/species_types/podpeople.dm +++ b/code/modules/mob/living/carbon/human/species_types/podpeople.dm @@ -5,7 +5,6 @@ id = SPECIES_PODPERSON species_traits = list( MUTCOLORS, - EYECOLOR, ) inherent_traits = list( TRAIT_PLANT_SAFE, diff --git a/code/modules/mob/living/carbon/human/species_types/shadowpeople.dm b/code/modules/mob/living/carbon/human/species_types/shadowpeople.dm index a15e03717e5..844e52a35c5 100644 --- a/code/modules/mob/living/carbon/human/species_types/shadowpeople.dm +++ b/code/modules/mob/living/carbon/human/species_types/shadowpeople.dm @@ -5,9 +5,7 @@ id = SPECIES_SHADOW sexes = 0 meat = /obj/item/food/meat/slab/human/mutant/shadow - species_traits = list( - NOEYESPRITES, - ) + species_traits = list() inherent_traits = list( TRAIT_NOBREATH, TRAIT_RADIMMUNE, diff --git a/code/modules/mob/living/carbon/human/species_types/skeletons.dm b/code/modules/mob/living/carbon/human/species_types/skeletons.dm index 73a41863145..7e63318de3b 100644 --- a/code/modules/mob/living/carbon/human/species_types/skeletons.dm +++ b/code/modules/mob/living/carbon/human/species_types/skeletons.dm @@ -6,7 +6,6 @@ meat = /obj/item/food/meat/slab/human/mutant/skeleton species_traits = list( NOTRANSSTING, - NOEYESPRITES, NO_DNA_COPY, NO_UNDERWEAR, ) @@ -28,7 +27,6 @@ TRAIT_TOXIMMUNE, TRAIT_XENO_IMMUNE, TRAIT_NOBLOOD, - TRAIT_NO_DEBRAIN_OVERLAY, ) inherent_biotypes = MOB_UNDEAD|MOB_HUMANOID mutanttongue = /obj/item/organ/internal/tongue/bone diff --git a/code/modules/mob/living/carbon/human/species_types/vampire.dm b/code/modules/mob/living/carbon/human/species_types/vampire.dm index 6dd778affc7..34c1ddd41ad 100644 --- a/code/modules/mob/living/carbon/human/species_types/vampire.dm +++ b/code/modules/mob/living/carbon/human/species_types/vampire.dm @@ -8,10 +8,6 @@ name = "Vampire" id = SPECIES_VAMPIRE species_traits = list( - EYECOLOR, - HAIR, - FACEHAIR, - LIPS, DRINKSBLOOD, BLOOD_CLANS, ) diff --git a/code/modules/reagents/chemistry/reagents/other_reagents.dm b/code/modules/reagents/chemistry/reagents/other_reagents.dm index 2bd7c352779..baf56000220 100644 --- a/code/modules/reagents/chemistry/reagents/other_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/other_reagents.dm @@ -550,8 +550,9 @@ affected_human.facial_hairstyle = "Shaved" affected_human.facial_hair_color = "#000000" affected_human.hair_color = "#000000" - if(!(HAIR in affected_human.dna.species.species_traits)) //No hair? No problem! - affected_human.dna.species.species_traits += HAIR + var/obj/item/bodypart/head/head = affected_human.get_bodypart(BODY_ZONE_HEAD) + if(head) + head.head_flags |= HEAD_HAIR //No hair? No problem! if(affected_human.dna.species.use_skintones) affected_human.skin_tone = "orange" else if(MUTCOLORS in affected_human.dna.species.species_traits) //Aliens with custom colors simply get turned orange @@ -2114,12 +2115,10 @@ var/mob/living/carbon/human/human_mob = affected_mob if(creation_purity == 1 && human_mob.has_quirk(/datum/quirk/item_quirk/bald)) human_mob.remove_quirk(/datum/quirk/item_quirk/bald) - var/datum/species/species_datum = human_mob.dna?.species - if(!species_datum) + var/obj/item/bodypart/head/head = human_mob.get_bodypart(BODY_ZONE_HEAD) + if(!head || (head.head_flags & HEAD_HAIR)) return - if(species_datum.species_traits.Find(HAIR)) - return - species_datum.species_traits |= HAIR + head.head_flags |= HEAD_HAIR var/message if(HAS_TRAIT(affected_mob, TRAIT_BALD)) message = span_warning("You feel your scalp mutate, but you are still hopelessly bald.") diff --git a/code/modules/religion/burdened/psyker.dm b/code/modules/religion/burdened/psyker.dm index 537d163161d..474634bb71b 100644 --- a/code/modules/religion/burdened/psyker.dm +++ b/code/modules/religion/burdened/psyker.dm @@ -36,28 +36,16 @@ is_dimorphic = FALSE should_draw_greyscale = FALSE bodypart_traits = list(TRAIT_DISFIGURED, TRAIT_BALD, TRAIT_SHAVED) + head_flags = HEAD_LIPS|HEAD_EYEHOLES|HEAD_DEBRAIN /obj/item/bodypart/head/psyker/try_attach_limb(mob/living/carbon/new_head_owner, special, abort) . = ..() if(!.) return new_head_owner.become_blind(limb_id) - if(!new_head_owner.dna?.species) - return - - new_head_owner.dna.species.species_traits |= NOEYESPRITES //MAKE VISUALS TIED TO BODYPARTS ARGHH - new_head_owner.update_body() /obj/item/bodypart/head/psyker/drop_limb(special, dismembered) owner.cure_blind(limb_id) - if(!owner.dna?.species) - return ..() - - if(initial(owner.dna.species.species_traits) & NOEYESPRITES) - return ..() - - owner.dna.species.species_traits &= ~NOEYESPRITES - owner.update_body() return ..() /// flavorful variant of psykerizing that deals damage and sends messages before calling psykerize() diff --git a/code/modules/surgery/bodyparts/_bodyparts.dm b/code/modules/surgery/bodyparts/_bodyparts.dm index 2aadd04459d..04fdc6ae98b 100644 --- a/code/modules/surgery/bodyparts/_bodyparts.dm +++ b/code/modules/surgery/bodyparts/_bodyparts.dm @@ -110,6 +110,10 @@ var/px_x = 0 var/px_y = 0 + /** + * A copy of the original owner's species datum species_traits list (very hacky) + * It sucks that we have to do this, but due to MUTCOLORS and others, we have to. For now. + */ var/species_flags_list = list() ///the type of damage overlay (if any) to use when this bodypart is bruised/burned. var/dmg_overlay_type = "human" @@ -791,7 +795,7 @@ // No, xenos don't actually use bodyparts. Don't ask. var/mob/living/carbon/human/human_owner = owner var/datum/species/owner_species = human_owner.dna.species - species_flags_list = owner_species.species_traits + species_flags_list = owner_species.species_traits.Copy() limb_gender = (human_owner.physique == MALE) ? "m" : "f" if(owner_species.use_skintones) @@ -911,8 +915,9 @@ . += aux_em_block //EMISSIVE CODE END - //Ok so legs are a bit goofy in regards to layering, and we will need two images instead of one to fix that - if((body_zone == BODY_ZONE_R_LEG) || (body_zone == BODY_ZONE_L_LEG)) + //No need to handle leg layering if dropped, we only face south anyways + if(!dropped && ((body_zone == BODY_ZONE_R_LEG) || (body_zone == BODY_ZONE_L_LEG))) + //Legs are a bit goofy in regards to layering, and we will need two images instead of one to fix that var/obj/item/bodypart/leg/leg_source = src for(var/image/limb_image in .) //remove the old, unmasked image diff --git a/code/modules/surgery/bodyparts/dismemberment.dm b/code/modules/surgery/bodyparts/dismemberment.dm index a648d686ebc..d0114361595 100644 --- a/code/modules/surgery/bodyparts/dismemberment.dm +++ b/code/modules/surgery/bodyparts/dismemberment.dm @@ -91,7 +91,7 @@ SEND_SIGNAL(owner, COMSIG_CARBON_REMOVE_LIMB, src, dismembered) SEND_SIGNAL(src, COMSIG_BODYPART_REMOVED, owner, dismembered) - update_limb(TRUE) + update_limb(dropping_limb = TRUE) //limb is out and about, it can't really be considered an implant bodypart_flags &= ~BODYPART_IMPLANTED owner.remove_bodypart(src) @@ -372,7 +372,7 @@ SEND_SIGNAL(new_limb_owner, COMSIG_CARBON_POST_ATTACH_LIMB, src, special) return TRUE -/obj/item/bodypart/head/try_attach_limb(mob/living/carbon/new_head_owner, special = FALSE, abort = FALSE) +/obj/item/bodypart/head/try_attach_limb(mob/living/carbon/new_head_owner, special = FALSE) // These are stored before calling super. This is so that if the head is from a different body, it persists its appearance. var/real_name = src.real_name @@ -415,6 +415,8 @@ sexy_chad.grad_color[GRADIENT_HAIR_KEY] = hair_gradient_color sexy_chad.grad_style[GRADIENT_FACIAL_HAIR_KEY] = facial_hair_gradient_style sexy_chad.grad_color[GRADIENT_FACIAL_HAIR_KEY] = facial_hair_gradient_color + sexy_chad.lip_style = lip_style + sexy_chad.lip_color = lip_color new_head_owner.updatehealth() new_head_owner.update_body() diff --git a/code/modules/surgery/bodyparts/head.dm b/code/modules/surgery/bodyparts/head.dm index 592a96de7fc..2cdad406fc2 100644 --- a/code/modules/surgery/bodyparts/head.dm +++ b/code/modules/surgery/bodyparts/head.dm @@ -36,36 +36,55 @@ var/show_organs_on_examine = TRUE //Limb appearance info: - var/real_name = "" //Replacement name - ///Hair color source + /// Replacement name + var/real_name = "" + /// Flags related to appearance, such as hair, lips, etc + var/head_flags = HEAD_ALL_FEATURES + + /// Hair style + var/hair_style = "Bald" + /// Hair color source var/hair_color_source = null - ///Hair colour and style + /// Hair colour and style var/hair_color = "#000000" - ///An override color that can be cleared later. + /// Hair alpha + var/hair_alpha = 255 + /// Hair gradient style, if any + var/hair_gradient_style = null + /// Hair gradient color, if any + var/hair_gradient_color = null + /// Is the hair currently hidden by something? + var/hair_hidden = FALSE + + ///Facial hair style + var/facial_hairstyle = "Shaved" + ///Facial hair color + var/facial_hair_color = "#000000" + ///Facial hair alpha + var/facial_hair_alpha = 255 + ///Facial hair gradient style, if any + var/facial_hair_gradient_style = null + ///Facial hair gradient color, if any + var/facial_hair_gradient_color = null + ///Is the facial hair currently hidden by something? + var/facial_hair_hidden = FALSE + + /// An override color that can be cleared later, affects both hair and facial hair var/override_hair_color = null - ///An override that cannot be cleared under any circumstances + /// An override that cannot be cleared under any circumstances, affects both hair and facial hair var/fixed_hair_color = null - var/hair_style = "Bald" - var/hair_alpha = 255 - var/hair_gradient_style = null - var/hair_gradient_color = null - //Facial hair colour and style - var/facial_hair_color = "#000000" - var/facial_hairstyle = "Shaved" - var/facial_hair_gradient_style = null - var/facial_hair_gradient_color = null - ///Is the hair currently hidden by something? - var/hair_hidden - ///Is the facial hair currently hidden by something? - var/facial_hair_hidden + ///Type of lipstick being used, basically + var/lip_style + ///Lipstick color + var/lip_color = "white" + ///Current lipstick trait, if any (such as TRAIT_KISS_OF_DEATH) + var/stored_lipstick_trait + ///Draw this head as "debrained" VAR_PROTECTED/show_debrained = FALSE - - - - var/lip_style - var/lip_color = "white" + ///Draw this head as missing eyes + VAR_PROTECTED/show_missing_eyes = FALSE /// Offset to apply to equipment worn on the ears var/datum/worn_feature_offset/worn_ears_offset @@ -78,7 +97,8 @@ /// Offset to apply to overlays placed on the face var/datum/worn_feature_offset/worn_face_offset - var/stored_lipstick_trait + ///The image for lipstick + var/mutable_appearance/lip_overlay ///The image for hair var/mutable_appearance/hair_overlay ///The image for hair gradient @@ -196,75 +216,96 @@ facial_hairstyle = "Shaved" lip_style = null stored_lipstick_trait = null - update_hair_and_lips() + update_hair_and_lips(dropping_limb, is_creating) ///////////////////////////////////////////////////////////////////////////////////////////////////////////////// /obj/item/bodypart/head/get_limb_icon(dropped, draw_external_organs) - cut_overlays() . = ..() - if(dropped) //certain overlays only appear when the limb is being detached from its owner. - - if(IS_ORGANIC_LIMB(src)) //having a robotic head hides certain features. - //facial hair - if(facial_hairstyle && (FACEHAIR in species_flags_list)) - var/datum/sprite_accessory/sprite = GLOB.facial_hairstyles_list[facial_hairstyle] - if(sprite) - var/image/facial_overlay = image(sprite.icon, "[sprite.icon_state]", -HAIR_LAYER, SOUTH) - facial_overlay.color = facial_hair_color - facial_overlay.alpha = hair_alpha - . += facial_overlay - - if(!eyes && !(NOEYEHOLES in species_flags_list) && !(NOEYESPRITES in species_flags_list)) - var/image/no_eyes = image('icons/mob/species/human/human_face.dmi', "eyes_missing", -BODY_LAYER, SOUTH) - worn_glasses_offset?.apply_offset(no_eyes) - . += no_eyes - - //Applies the debrained overlay if there is no brain - if(!brain) - . += get_debrain_overlay(can_rotate = FALSE) - else - var/datum/sprite_accessory/sprite2 = GLOB.hairstyles_list[hair_style] - if(sprite2 && (HAIR in species_flags_list)) - var/image/hair_overlay = image(sprite2.icon, "[sprite2.icon_state]", -HAIR_LAYER, SOUTH) - hair_overlay.color = hair_color - hair_overlay.alpha = hair_alpha - . += hair_overlay - + // logic for the overlays changes when dropped (ugh, rework this later if possible) + if(dropped) + //BAHHHH don't do any of this if we are husked + if(is_husked) + return . // lipstick - if(lip_style) + if(lip_style && (head_flags & HEAD_LIPS)) var/image/lips_overlay = image('icons/mob/species/human/human_face.dmi', "lips_[lip_style]", -BODY_LAYER, SOUTH) lips_overlay.color = lip_color + worn_face_offset?.apply_offset(lips_overlay) . += lips_overlay + //facial hair + if(facial_hairstyle && (head_flags & HEAD_FACIAL_HAIR)) + var/datum/sprite_accessory/facial_hair_sprite = GLOB.facial_hairstyles_list[facial_hairstyle] + if(facial_hair_sprite) + var/image/facial_overlay = image(facial_hair_sprite.icon, "[facial_hair_sprite.icon_state]", -HAIR_LAYER, SOUTH) + facial_overlay.color = facial_hair_color + facial_overlay.alpha = hair_alpha + . += facial_overlay + + //Applies the debrained overlay if there is no brain + if(!brain && (head_flags & HEAD_DEBRAIN)) + . += get_debrain_overlay(can_rotate = FALSE) + //Otherwise, applies hair + else if(hair_style && (head_flags & HEAD_HAIR)) + var/datum/sprite_accessory/hair_sprite = GLOB.hairstyles_list[hair_style] + if(hair_sprite && (head_flags & HEAD_HAIR)) + var/image/hair_overlay = image(hair_sprite.icon, "[hair_sprite.icon_state]", -HAIR_LAYER, SOUTH) + hair_overlay.color = hair_color + hair_overlay.alpha = hair_alpha + . += hair_overlay + // eyes - if(eyes && eyes.eye_icon_state && !(NOEYESPRITES in species_flags_list)) // This is a bit of copy/paste code from eyes.dm:generate_body_overlay + // This is a bit of copy/paste code from eyes.dm:generate_body_overlay + if(eyes?.eye_icon_state && (head_flags & HEAD_EYESPRITES)) var/image/eye_left = image('icons/mob/species/human/human_face.dmi', "[eyes.eye_icon_state]_l", -BODY_LAYER, SOUTH) var/image/eye_right = image('icons/mob/species/human/human_face.dmi', "[eyes.eye_icon_state]_r", -BODY_LAYER, SOUTH) - if(eyes.eye_color_left) - eye_left.color = eyes.eye_color_left - if(eyes.eye_color_right) - eye_right.color = eyes.eye_color_right + if(head_flags & HEAD_EYECOLOR) + if(eyes.eye_color_left) + eye_left.color = eyes.eye_color_left + if(eyes.eye_color_right) + eye_right.color = eyes.eye_color_right + if(eyes.overlay_ignore_lighting) + eye_left.overlays += emissive_appearance(eye_left.icon, eye_left.icon_state, src, alpha = eye_left.alpha) + eye_right.overlays += emissive_appearance(eye_right.icon, eye_right.icon_state, src, alpha = eye_right.alpha) + if(worn_face_offset) + worn_face_offset.apply_offset(eye_left) + worn_face_offset.apply_offset(eye_right) . += eye_left . += eye_right + else if(!eyes && (head_flags & HEAD_EYEHOLES)) + var/image/no_eyes = image('icons/mob/species/human/human_face.dmi', "eyes_missing", -BODY_LAYER, SOUTH) + worn_face_offset?.apply_offset(no_eyes) + . += no_eyes else - if(!facial_hair_hidden && facial_overlay && (FACEHAIR in species_flags_list)) + if(lip_overlay && (head_flags & HEAD_LIPS)) + worn_face_offset?.apply_offset(lip_overlay) + . += lip_overlay + + if(!facial_hair_hidden && facial_overlay && (head_flags & HEAD_FACIAL_HAIR)) facial_overlay.alpha = hair_alpha . += facial_overlay if(facial_gradient_overlay) . += facial_gradient_overlay - if(show_debrained) + if(show_debrained && (head_flags & HEAD_DEBRAIN)) . += get_debrain_overlay(can_rotate = TRUE) - else if(!hair_hidden && hair_overlay && (HAIR in species_flags_list)) + else if(!hair_hidden && hair_overlay && (head_flags & HEAD_HAIR)) hair_overlay.alpha = hair_alpha . += hair_overlay if(hair_gradient_overlay) . += hair_gradient_overlay + if(show_missing_eyes && (head_flags && HEAD_EYEHOLES)) + var/mutable_appearance/no_eyes = mutable_appearance('icons/mob/species/human/human_face.dmi', "eyes_missing", -BODY_LAYER) + worn_face_offset?.apply_offset(no_eyes) + . += no_eyes + + return + /// Returns an appropriate debrained icon state /obj/item/bodypart/head/proc/get_debrain_overlay(can_rotate = TRUE) var/debrain_icon = 'icons/mob/species/human/human_face.dmi' @@ -278,11 +319,9 @@ else if(bodytype & BODYTYPE_GOLEM) debrain_icon = 'icons/mob/species/golems.dmi' debrain_icon_state = "debrained" - else if((TRAIT_NOBLOOD in species_flags_list)) - return null var/image/debrain_overlay - if (can_rotate) + if(can_rotate) debrain_overlay = mutable_appearance(debrain_icon, debrain_icon_state, HAIR_LAYER) else debrain_overlay = image(debrain_icon, debrain_icon_state, -HAIR_LAYER, SOUTH) @@ -336,6 +375,7 @@ should_draw_greyscale = FALSE dmg_overlay_type = SPECIES_MONKEY is_dimorphic = FALSE + head_flags = HEAD_LIPS|HEAD_DEBRAIN /obj/item/bodypart/head/alien icon = 'icons/mob/species/alien/bodyparts.dmi' diff --git a/code/modules/surgery/bodyparts/hair.dm b/code/modules/surgery/bodyparts/head_hair_and_lips.dm similarity index 70% rename from code/modules/surgery/bodyparts/hair.dm rename to code/modules/surgery/bodyparts/head_hair_and_lips.dm index 2d1690f9125..d68e3bea3f2 100644 --- a/code/modules/surgery/bodyparts/hair.dm +++ b/code/modules/surgery/bodyparts/head_hair_and_lips.dm @@ -1,65 +1,62 @@ -#define SET_OVERLAY_VALUE(X,Y,Z) if(X) X.Y = Z +#define SET_OVERLAY_VALUE(overlay,variable,value) if(overlay) overlay.variable = value -///Part of `update_limb()`, this proc does what the name implies. -/obj/item/bodypart/head/proc/update_hair_and_lips() +/// Part of `update_limb()`, this proc does what the name implies. +/obj/item/bodypart/head/proc/update_hair_and_lips(dropping_limb, is_creating) + // THIS PROC DOES NOT WORK FOR DROPPED HEADS. YET. + if(!owner) + return var/mob/living/carbon/human/human_head_owner = owner var/datum/species/owner_species = human_head_owner.dna.species - if(human_head_owner.lip_style && (LIPS in owner_species.species_traits)) - lip_style = human_head_owner.lip_style - lip_color = human_head_owner.lip_color - else - lip_style = null - lip_color = "white" - - ///FACIAL HAIR CHECKS START - //we check if our hat or helmet hides our facial hair. + //HIDDEN CHECKS START + hair_hidden = FALSE facial_hair_hidden = FALSE if(human_head_owner.head) var/obj/item/hat = human_head_owner.head + if(hat.flags_inv & HIDEHAIR) + hair_hidden = TRUE if(hat.flags_inv & HIDEFACIALHAIR) facial_hair_hidden = TRUE if(human_head_owner.wear_mask) var/obj/item/mask = human_head_owner.wear_mask + if(mask.flags_inv & HIDEHAIR) + hair_hidden = TRUE if(mask.flags_inv & HIDEFACIALHAIR) facial_hair_hidden = TRUE - ///FACIAL HAIR CHECKS END - - ///HAIR CHECKS START - hair_hidden = FALSE - if(human_head_owner.head) - var/obj/item/hat = human_head_owner.head - if(hat.flags_inv & HIDEHAIR) - hair_hidden = TRUE if(human_head_owner.w_uniform) var/obj/item/item_uniform = human_head_owner.w_uniform if(item_uniform.flags_inv & HIDEHAIR) hair_hidden = TRUE - - if(human_head_owner.wear_mask) - var/obj/item/mask = human_head_owner.wear_mask - if(mask.flags_inv & HIDEHAIR) - hair_hidden = TRUE - ///HAIR CHECKS END - //invisibility stuff - if(HAS_TRAIT(human_head_owner, TRAIT_INVISIBLE_MAN)) + if(item_uniform.flags_inv & HIDEFACIALHAIR) + facial_hair_hidden = TRUE + //invisibility and husk stuff + if(HAS_TRAIT(human_head_owner, TRAIT_INVISIBLE_MAN) || HAS_TRAIT(human_head_owner, TRAIT_HUSK)) hair_hidden = TRUE facial_hair_hidden = TRUE + //HIDDEN CHECKS END - if(!hair_hidden && !owner.get_organ_slot(ORGAN_SLOT_BRAIN) && !HAS_TRAIT(owner, TRAIT_NO_DEBRAIN_OVERLAY)) + if(!hair_hidden && !owner.get_organ_slot(ORGAN_SLOT_BRAIN) && (head_flags & HEAD_DEBRAIN) && !HAS_TRAIT(owner, TRAIT_NO_DEBRAIN_OVERLAY)) show_debrained = TRUE else show_debrained = FALSE + if(!owner.get_organ_slot(ORGAN_SLOT_EYES) && (head_flags & HEAD_EYEHOLES)) + show_missing_eyes = TRUE + else + show_missing_eyes = FALSE + var/datum/sprite_accessory/sprite_accessory + lip_overlay = null facial_overlay = null facial_gradient_overlay = null hair_overlay = null hair_gradient_overlay = null + lip_style = human_head_owner.lip_style + lip_color = human_head_owner.lip_color hair_alpha = owner_species.hair_alpha hair_color = human_head_owner.hair_color facial_hair_color = human_head_owner.facial_hair_color @@ -69,31 +66,38 @@ var/atom/location = loc || owner || src - if(facial_hairstyle && !facial_hair_hidden && (FACEHAIR in species_flags_list)) + if(!facial_hair_hidden && lip_style && (head_flags & HEAD_LIPS)) + lip_overlay = mutable_appearance('icons/mob/species/human/human_face.dmi', "lips_[lip_style]", -BODY_LAYER) + lip_overlay.color = lip_color + + if(!facial_hair_hidden && facial_hairstyle && (head_flags & HEAD_FACIAL_HAIR)) sprite_accessory = GLOB.facial_hairstyles_list[facial_hairstyle] if(sprite_accessory) - //Create the overlay + //Overlay facial_overlay = mutable_appearance(sprite_accessory.icon, sprite_accessory.icon_state, -HAIR_LAYER) - facial_overlay.overlays += emissive_blocker(facial_overlay.icon, facial_overlay.icon_state, location, alpha = hair_alpha) + facial_overlay.alpha = facial_hair_alpha //Gradients facial_hair_gradient_style = LAZYACCESS(human_head_owner.grad_style, GRADIENT_FACIAL_HAIR_KEY) if(facial_hair_gradient_style) facial_hair_gradient_color = LAZYACCESS(human_head_owner.grad_color, GRADIENT_FACIAL_HAIR_KEY) facial_gradient_overlay = make_gradient_overlay(sprite_accessory.icon, sprite_accessory.icon_state, HAIR_LAYER, GLOB.facial_hair_gradients_list[facial_hair_gradient_style], facial_hair_gradient_color) + //Emissive + facial_overlay.overlays += emissive_blocker(facial_overlay.icon, facial_overlay.icon_state, location, alpha = facial_hair_alpha) - facial_overlay.overlays += emissive_blocker(sprite_accessory.icon, sprite_accessory.icon_state, location, alpha = hair_alpha) - - if(!hair_hidden && !show_debrained && (HAIR in species_flags_list)) + if(!show_debrained && !hair_hidden && hair_style && (head_flags & HEAD_HAIR)) sprite_accessory = GLOB.hairstyles_list[hair_style] if(sprite_accessory) + //Overlay hair_overlay = mutable_appearance(sprite_accessory.icon, sprite_accessory.icon_state, -HAIR_LAYER) - hair_overlay.overlays += emissive_blocker(hair_overlay.icon, hair_overlay.icon_state, location, alpha = hair_alpha) + hair_overlay.alpha = hair_alpha + //Gradients hair_gradient_style = LAZYACCESS(human_head_owner.grad_style, GRADIENT_HAIR_KEY) if(hair_gradient_style) hair_gradient_color = LAZYACCESS(human_head_owner.grad_color, GRADIENT_HAIR_KEY) hair_gradient_overlay = make_gradient_overlay(sprite_accessory.icon, sprite_accessory.icon_state, HAIR_LAYER, GLOB.hair_gradients_list[hair_gradient_style], hair_gradient_color) + //Emissive + hair_overlay.overlays += emissive_blocker(hair_overlay.icon, hair_overlay.icon_state, location, alpha = hair_alpha) - //CREATION-ONLY END //HAIR COLOR START if(!override_hair_color) if(hair_color_source) diff --git a/code/modules/surgery/bodyparts/helpers.dm b/code/modules/surgery/bodyparts/helpers.dm index 18ebc4a96e3..96a67e848d4 100644 --- a/code/modules/surgery/bodyparts/helpers.dm +++ b/code/modules/surgery/bodyparts/helpers.dm @@ -166,7 +166,7 @@ if(BODY_ZONE_CHEST) new_bodypart = new /obj/item/bodypart/chest/alien() if(new_bodypart) - new_bodypart.update_limb(src) + new_bodypart.update_limb(is_creating = TRUE) diff --git a/code/modules/surgery/bodyparts/robot_bodyparts.dm b/code/modules/surgery/bodyparts/robot_bodyparts.dm index 7e52016748a..7328b3b85b8 100644 --- a/code/modules/surgery/bodyparts/robot_bodyparts.dm +++ b/code/modules/surgery/bodyparts/robot_bodyparts.dm @@ -301,6 +301,8 @@ damage_examines = list(BRUTE = ROBOTIC_BRUTE_EXAMINE_TEXT, BURN = ROBOTIC_BURN_EXAMINE_TEXT, CLONE = DEFAULT_CLONE_EXAMINE_TEXT) + head_flags = HEAD_EYESPRITES + var/obj/item/assembly/flash/handheld/flash1 = null var/obj/item/assembly/flash/handheld/flash2 = null diff --git a/code/modules/surgery/bodyparts/species_parts/ethereal_bodyparts.dm b/code/modules/surgery/bodyparts/species_parts/ethereal_bodyparts.dm index 076d4f684a1..a41f06a0e17 100644 --- a/code/modules/surgery/bodyparts/species_parts/ethereal_bodyparts.dm +++ b/code/modules/surgery/bodyparts/species_parts/ethereal_bodyparts.dm @@ -7,6 +7,7 @@ unarmed_attack_sound = 'sound/weapons/etherealhit.ogg' unarmed_miss_sound = 'sound/weapons/etherealmiss.ogg' brute_modifier = 1.25 //ethereal are weak to brute damage + head_flags = HEAD_HAIR|HEAD_FACIAL_HAIR|HEAD_EYESPRITES|HEAD_EYEHOLES|HEAD_DEBRAIN /obj/item/bodypart/head/ethereal/update_limb(dropping_limb, is_creating) . = ..() diff --git a/code/modules/surgery/bodyparts/species_parts/lizard_bodyparts.dm b/code/modules/surgery/bodyparts/species_parts/lizard_bodyparts.dm index 1c24a849e39..15a6176891a 100644 --- a/code/modules/surgery/bodyparts/species_parts/lizard_bodyparts.dm +++ b/code/modules/surgery/bodyparts/species_parts/lizard_bodyparts.dm @@ -2,6 +2,7 @@ icon_greyscale = 'icons/mob/species/lizard/bodyparts.dmi' limb_id = SPECIES_LIZARD is_dimorphic = FALSE + head_flags = HEAD_LIPS|HEAD_EYESPRITES|HEAD_EYECOLOR|HEAD_EYEHOLES|HEAD_DEBRAIN /obj/item/bodypart/chest/lizard icon_greyscale = 'icons/mob/species/lizard/bodyparts.dmi' diff --git a/code/modules/surgery/bodyparts/species_parts/misc_bodyparts.dm b/code/modules/surgery/bodyparts/species_parts/misc_bodyparts.dm index fe298dc0e01..59e42912b67 100644 --- a/code/modules/surgery/bodyparts/species_parts/misc_bodyparts.dm +++ b/code/modules/surgery/bodyparts/species_parts/misc_bodyparts.dm @@ -3,6 +3,7 @@ limb_id = SPECIES_SNAIL is_dimorphic = FALSE burn_modifier = 2 + head_flags = HEAD_EYESPRITES|HEAD_DEBRAIN /obj/item/bodypart/chest/snail limb_id = SPECIES_SNAIL @@ -39,6 +40,7 @@ limb_id = SPECIES_ABDUCTOR is_dimorphic = FALSE should_draw_greyscale = FALSE + head_flags = NONE /obj/item/bodypart/chest/abductor biological_state = BIO_INORGANIC @@ -75,6 +77,7 @@ is_dimorphic = TRUE dmg_overlay_type = null burn_modifier = 0.5 // = 1/2x generic burn damage + head_flags = HEAD_ALL_FEATURES /obj/item/bodypart/chest/jelly biological_state = BIO_INORGANIC @@ -112,6 +115,7 @@ biological_state = BIO_INORGANIC limb_id = SPECIES_SLIMEPERSON is_dimorphic = FALSE + head_flags = HEAD_ALL_FEATURES /obj/item/bodypart/chest/slime biological_state = BIO_INORGANIC @@ -139,6 +143,7 @@ biological_state = BIO_INORGANIC limb_id = SPECIES_LUMINESCENT is_dimorphic = TRUE + head_flags = HEAD_ALL_FEATURES /obj/item/bodypart/chest/luminescent biological_state = BIO_INORGANIC @@ -166,6 +171,7 @@ limb_id = SPECIES_ZOMBIE is_dimorphic = FALSE should_draw_greyscale = FALSE + head_flags = HEAD_EYESPRITES|HEAD_DEBRAIN /obj/item/bodypart/chest/zombie limb_id = SPECIES_ZOMBIE @@ -193,6 +199,7 @@ limb_id = SPECIES_PODPERSON is_dimorphic = TRUE burn_modifier = 1.25 + head_flags = HEAD_EYESPRITES|HEAD_EYECOLOR|HEAD_EYEHOLES|HEAD_DEBRAIN /obj/item/bodypart/chest/pod limb_id = SPECIES_PODPERSON @@ -228,6 +235,7 @@ limb_id = SPECIES_FLYPERSON is_dimorphic = FALSE should_draw_greyscale = FALSE + head_flags = HEAD_EYESPRITES|HEAD_EYEHOLES|HEAD_DEBRAIN /obj/item/bodypart/chest/fly limb_id = SPECIES_FLYPERSON @@ -257,6 +265,7 @@ is_dimorphic = FALSE should_draw_greyscale = FALSE burn_modifier = 1.5 + head_flags = NONE /obj/item/bodypart/chest/shadow biological_state = BIO_INORGANIC @@ -302,6 +311,7 @@ is_dimorphic = FALSE should_draw_greyscale = FALSE dmg_overlay_type = null + head_flags = NONE /obj/item/bodypart/chest/skeleton biological_state = BIO_BONE @@ -339,6 +349,7 @@ limb_id = SPECIES_MUSHROOM is_dimorphic = TRUE burn_modifier = 1.25 + head_flags = NONE /obj/item/bodypart/chest/mushroom limb_id = SPECIES_MUSHROOM @@ -385,6 +396,7 @@ is_dimorphic = FALSE should_draw_greyscale = FALSE dmg_overlay_type = null + head_flags = NONE /obj/item/bodypart/head/golem/Initialize(mapload) worn_ears_offset = new( diff --git a/code/modules/surgery/bodyparts/species_parts/moth_bodyparts.dm b/code/modules/surgery/bodyparts/species_parts/moth_bodyparts.dm index c23b935176b..232dd44d505 100644 --- a/code/modules/surgery/bodyparts/species_parts/moth_bodyparts.dm +++ b/code/modules/surgery/bodyparts/species_parts/moth_bodyparts.dm @@ -5,6 +5,7 @@ limb_id = SPECIES_MOTH is_dimorphic = FALSE should_draw_greyscale = FALSE + head_flags = HEAD_LIPS|HEAD_EYESPRITES|HEAD_EYEHOLES|HEAD_DEBRAIN //what the fuck, moths have lips? /obj/item/bodypart/chest/moth icon = 'icons/mob/species/moth/bodyparts.dmi' diff --git a/code/modules/surgery/bodyparts/species_parts/plasmaman_bodyparts.dm b/code/modules/surgery/bodyparts/species_parts/plasmaman_bodyparts.dm index b77c89da323..d9bbee1ea03 100644 --- a/code/modules/surgery/bodyparts/species_parts/plasmaman_bodyparts.dm +++ b/code/modules/surgery/bodyparts/species_parts/plasmaman_bodyparts.dm @@ -9,6 +9,7 @@ dmg_overlay_type = null brute_modifier = 1.5 //Plasmemes are weak burn_modifier = 1.5 //Plasmemes are weak + head_flags = HEAD_EYESPRITES /obj/item/bodypart/chest/plasmaman icon = 'icons/mob/species/plasmaman/bodyparts.dmi' diff --git a/code/modules/surgery/organs/eyes.dm b/code/modules/surgery/organs/eyes.dm index 051f94cbfe9..583781f026e 100644 --- a/code/modules/surgery/organs/eyes.dm +++ b/code/modules/surgery/organs/eyes.dm @@ -56,7 +56,7 @@ return eye_recipient.cure_blind(NO_EYES) apply_damaged_eye_effects() - refresh(eye_recipient, inserting = TRUE) + refresh(eye_recipient, inserting = TRUE, call_update = TRUE) /// Refreshes the visuals of the eyes /// If call_update is TRUE, we also will call update_body @@ -85,7 +85,7 @@ affected_human.add_fov_trait(type, native_fov) if(call_update) - affected_human.dna?.species?.handle_body(affected_human) //updates eye icon + affected_human.update_body() /obj/item/organ/internal/eyes/Remove(mob/living/carbon/eye_owner, special = FALSE) . = ..() @@ -95,9 +95,9 @@ human_owner.eye_color_left = old_eye_color_left if(initial(eye_color_right)) human_owner.eye_color_right = old_eye_color_right - human_owner.update_body() if(native_fov) eye_owner.remove_fov_trait(type) + human_owner.update_body() // Cure blindness from eye damage eye_owner.cure_blind(EYE_DAMAGE) @@ -125,11 +125,6 @@ var/mutable_appearance/eye_left = mutable_appearance('icons/mob/species/human/human_face.dmi', "[eye_icon_state]_l", -BODY_LAYER) var/mutable_appearance/eye_right = mutable_appearance('icons/mob/species/human/human_face.dmi', "[eye_icon_state]_r", -BODY_LAYER) - var/list/overlays = list(eye_left, eye_right) - - if(EYECOLOR in parent.dna?.species.species_traits) - eye_right.color = eye_color_right - eye_left.color = eye_color_left var/obscured = parent.check_obscured_slots(TRUE) if(overlay_ignore_lighting && !(obscured & ITEM_SLOT_EYES)) @@ -137,11 +132,15 @@ eye_right.overlays += emissive_appearance(eye_right.icon, eye_right.icon_state, parent, alpha = eye_right.alpha) var/obj/item/bodypart/head/my_head = parent.get_bodypart(BODY_ZONE_HEAD) - if(my_head?.worn_face_offset) - for(var/mutable_appearance/overlay in overlays) - my_head.worn_face_offset.apply_offset(overlay) + if(my_head) + if(my_head.head_flags & HEAD_EYECOLOR) + eye_right.color = eye_color_right + eye_left.color = eye_color_left + if(my_head.worn_face_offset) + my_head.worn_face_offset.apply_offset(eye_left) + my_head.worn_face_offset.apply_offset(eye_right) - return overlays + return list(eye_left, eye_right) #undef OFFSET_X #undef OFFSET_Y diff --git a/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_human_krokodil_addict.png b/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_human_krokodil_addict.png index 30f9080a6c3c773a7f9231295abc62b4fb8105d1..e9251e73cc5494b39f532b644e462225e558005c 100644 GIT binary patch delta 22 ecmdnMv4LYkF!TTa|0jk;u{`KYf3$H+4Ko0JmJ2ih delta 22 ecmdnMv4LYkFf#)K!^E&CmcElU2R3f0VFmzFp$HQI diff --git a/tgstation.dme b/tgstation.dme index c045b3e69ca..e05361bd286 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -206,6 +206,7 @@ #include "code\__DEFINES\spatial_gridmap.dm" #include "code\__DEFINES\species_clothing_paths.dm" #include "code\__DEFINES\speech_channels.dm" +#include "code\__DEFINES\sprite_accessories.dm" #include "code\__DEFINES\stack_trace.dm" #include "code\__DEFINES\stat.dm" #include "code\__DEFINES\stat_tracking.dm" @@ -4095,6 +4096,7 @@ #include "code\modules\mob\living\carbon\alien\larva\powers.dm" #include "code\modules\mob\living\carbon\alien\special\alien_embryo.dm" #include "code\modules\mob\living\carbon\alien\special\facehugger.dm" +#include "code\modules\mob\living\carbon\human\_species.dm" #include "code\modules\mob\living\carbon\human\damage_procs.dm" #include "code\modules\mob\living\carbon\human\death.dm" #include "code\modules\mob\living\carbon\human\dummy.dm" @@ -4115,7 +4117,6 @@ #include "code\modules\mob\living\carbon\human\life.dm" #include "code\modules\mob\living\carbon\human\login.dm" #include "code\modules\mob\living\carbon\human\physiology.dm" -#include "code\modules\mob\living\carbon\human\species.dm" #include "code\modules\mob\living\carbon\human\status_procs.dm" #include "code\modules\mob\living\carbon\human\suicides.dm" #include "code\modules\mob\living\carbon\human\monkey\monkey.dm" @@ -5019,8 +5020,8 @@ #include "code\modules\surgery\advanced\bioware\vein_threading.dm" #include "code\modules\surgery\bodyparts\_bodyparts.dm" #include "code\modules\surgery\bodyparts\dismemberment.dm" -#include "code\modules\surgery\bodyparts\hair.dm" #include "code\modules\surgery\bodyparts\head.dm" +#include "code\modules\surgery\bodyparts\head_hair_and_lips.dm" #include "code\modules\surgery\bodyparts\helpers.dm" #include "code\modules\surgery\bodyparts\parts.dm" #include "code\modules\surgery\bodyparts\robot_bodyparts.dm"