From 7ed2ee82bf13e8e4d97298391c099a7b8050128f Mon Sep 17 00:00:00 2001 From: Timothy Teakettle <59849408+timothyteakettle@users.noreply.github.com> Date: Thu, 4 Aug 2022 14:11:42 +0100 Subject: [PATCH] core changes --- code/datums/components/dullahan.dm | 81 +++++++++++++++++++ code/datums/mutable_appearance.dm | 3 + .../sprite_accessories/_sprite_accessories.dm | 2 + .../new_player/sprite_accessories/ears.dm | 1 + .../sprite_accessories/hair_face.dm | 1 + .../sprite_accessories/hair_head.dm | 1 + .../new_player/sprite_accessories/horns.dm | 1 + .../sprite_accessories/ipc_synths.dm | 1 + .../new_player/sprite_accessories/snouts.dm | 1 + .../new_player/sprite_accessories/synthliz.dm | 1 + .../mob/living/carbon/human/species.dm | 14 +++- .../mob/living/carbon/human/update_icons.dm | 5 +- code/modules/surgery/bodyparts/head.dm | 16 ++-- tgstation.dme | 1 + 14 files changed, 120 insertions(+), 9 deletions(-) create mode 100644 code/datums/components/dullahan.dm diff --git a/code/datums/components/dullahan.dm b/code/datums/components/dullahan.dm new file mode 100644 index 0000000000..ee6d5beef0 --- /dev/null +++ b/code/datums/components/dullahan.dm @@ -0,0 +1,81 @@ +/datum/component/dullahan + var/obj/item/dullahan_head/dullahan_head + + +/datum/component/dullahan/Initialize() + var/mob/living/carbon/human/H = parent + if(!H) + return + + dullahan_head = new(get_turf(H)) + + dullahan_head.name = "[H.name]'s head" + dullahan_head.desc = "the decapitated head of [H.name]" + dullahan_head.owner = H + + // make sure the brain can't decay or fall out + var/obj/item/organ/brain/B = H.getorganslot(ORGAN_SLOT_BRAIN) + B.zone = "abstract" // it exists in the ethereal plain + B.organ_flags = ORGAN_NO_SPOIL | ORGAN_NO_DISMEMBERMENT | ORGAN_VITAL + + // moving the brain's zone means we don't need the head to survive + var/obj/item/bodypart/head/head = H.get_bodypart(BODY_ZONE_HEAD) + head.drop_limb() + qdel(head) + + dullahan_head.update_appearance() + +/obj/item/dullahan_head + name = "coders lament" + desc = "you shouldn't be reading this" + flags_1 = HEAR_1 + var/mob/living/carbon/human/owner + // this is for keeping track of the overlays because you can't read the actual overlays list as it's a special byond var + var/list/overlays_standing + +// allow the 'fake' head to relay speech back to the mob +/obj/item/dullahan_head/Hear(message, atom/movable/speaker, datum/language/message_language, raw_message, radio_freq, list/spans, message_mode) + if(owner) + var/namepart = "[speaker.GetVoice()][speaker.get_alt_name()]" + var/hrefpart = "" + var/treated_message = lang_treat(speaker, message_language, raw_message, spans, message_mode) + var/rendered = "[hrefpart][namepart] [treated_message]" + + if (owner.client?.prefs.chat_on_map && (owner.client.prefs.see_chat_non_mob || ismob(speaker))) + owner.create_chat_message(speaker, message_language, raw_message, spans, message_mode) + owner.show_message(rendered, MSG_AUDIBLE) + +// update head sprite +/obj/item/dullahan_head/proc/remove_head_overlays() + overlays_standing = list() + cut_overlays() + +/obj/item/dullahan_head/proc/add_head_overlay(var/overlay) + overlays_standing += overlay + add_overlay(overlay) + +/obj/item/dullahan_head/update_appearance() + remove_head_overlays() + // to do this without duplicating large amounts of code + // it's best to regenerate the head, then remove it once we have the overlays we want + owner.regenerate_limb(BODY_ZONE_HEAD, TRUE) // don't heal them + owner.regenerate_icons() // yes i know it's expensive but do you want me to rewrite our entire overlay system + var/obj/item/bodypart/head/head = owner.get_bodypart(BODY_ZONE_HEAD) + add_overlay(head.get_limb_icon(FALSE, TRUE, TRUE)) + for(var/overlay in owner.overlays_standing) + if(istype(overlay, /mutable_appearance)) + var/mutable_appearance/mutable = overlay + message_admins("category is [mutable.category] and icon is [mutable.icon_state]") + if(mutable.category == "HEAD") + add_head_overlay(mutable) + else + if(islist(overlay)) + var/list/list_appearances = overlay + for(var/overlay2 in list_appearances) + if(istype(overlay2, /mutable_appearance)) + var/mutable_appearance/mutable = overlay2 + message_admins("category is [mutable.category] and icon is [mutable.icon_state]") + if(mutable.category == "HEAD") + add_head_overlay(mutable) + //head.drop_limb() + //qdel(head) \ No newline at end of file diff --git a/code/datums/mutable_appearance.dm b/code/datums/mutable_appearance.dm index b04f55ef0e..104147ebeb 100644 --- a/code/datums/mutable_appearance.dm +++ b/code/datums/mutable_appearance.dm @@ -4,6 +4,9 @@ // Mutable appearances are children of images, just so you know. +/mutable_appearance + var/category // listen i want to store some meta information on mutable appearances don't judge me + /mutable_appearance/New() ..() plane = FLOAT_PLANE // No clue why this is 0 by default yet images are on FLOAT_PLANE diff --git a/code/modules/mob/dead/new_player/sprite_accessories/_sprite_accessories.dm b/code/modules/mob/dead/new_player/sprite_accessories/_sprite_accessories.dm index 08ae75d728..964a171e59 100644 --- a/code/modules/mob/dead/new_player/sprite_accessories/_sprite_accessories.dm +++ b/code/modules/mob/dead/new_player/sprite_accessories/_sprite_accessories.dm @@ -77,6 +77,8 @@ //For soft-restricting markings to species IDs var/list/recommended_species + var/mutable_category // simply do not worry about this value + /datum/sprite_accessory/proc/is_not_visible(var/mob/living/carbon/human/H, var/tauric) //return if the accessory shouldn't be shown return FALSE diff --git a/code/modules/mob/dead/new_player/sprite_accessories/ears.dm b/code/modules/mob/dead/new_player/sprite_accessories/ears.dm index 628a5e53ac..294c3b78f2 100644 --- a/code/modules/mob/dead/new_player/sprite_accessories/ears.dm +++ b/code/modules/mob/dead/new_player/sprite_accessories/ears.dm @@ -2,6 +2,7 @@ icon = 'icons/mob/mutant_bodyparts.dmi' mutant_part_string = "ears" relevant_layers = list(BODY_BEHIND_LAYER, BODY_ADJ_LAYER, BODY_FRONT_LAYER) + mutable_category = "HEAD" /datum/sprite_accessory/ears/is_not_visible(var/mob/living/carbon/human/H, var/tauric) var/obj/item/bodypart/head/HD = H.get_bodypart(BODY_ZONE_HEAD) diff --git a/code/modules/mob/dead/new_player/sprite_accessories/hair_face.dm b/code/modules/mob/dead/new_player/sprite_accessories/hair_face.dm index f3e179e802..06d4c34f72 100644 --- a/code/modules/mob/dead/new_player/sprite_accessories/hair_face.dm +++ b/code/modules/mob/dead/new_player/sprite_accessories/hair_face.dm @@ -4,6 +4,7 @@ /datum/sprite_accessory/facial_hair icon = 'icons/mob/hair.dmi' gender = MALE // barf (unless you're a dorf, dorfs dig chix w/ beards :P) + mutable_category = "HEAD" // please make sure they're sorted alphabetically and categorized /datum/sprite_accessory/facial_hair/shaved //this is exempt from the alphabetical sort diff --git a/code/modules/mob/dead/new_player/sprite_accessories/hair_head.dm b/code/modules/mob/dead/new_player/sprite_accessories/hair_head.dm index e002fa369d..9e868d69c6 100644 --- a/code/modules/mob/dead/new_player/sprite_accessories/hair_head.dm +++ b/code/modules/mob/dead/new_player/sprite_accessories/hair_head.dm @@ -3,6 +3,7 @@ ////////////////////// /datum/sprite_accessory/hair icon = 'icons/mob/hair.dmi' // default icon for all hairs + mutable_category = "HEAD" // please make sure they're sorted alphabetically and, where needed, categorized // try to capitalize the names please~ diff --git a/code/modules/mob/dead/new_player/sprite_accessories/horns.dm b/code/modules/mob/dead/new_player/sprite_accessories/horns.dm index 0d097b24f0..14e340fc2e 100644 --- a/code/modules/mob/dead/new_player/sprite_accessories/horns.dm +++ b/code/modules/mob/dead/new_player/sprite_accessories/horns.dm @@ -2,6 +2,7 @@ icon = 'icons/mob/mutant_bodyparts.dmi' color_src = HORNCOLOR relevant_layers = list(HORNS_LAYER) + mutable_category = "HEAD" /datum/sprite_accessory/horns/is_not_visible(var/mob/living/carbon/human/H, var/tauric) var/obj/item/bodypart/head/HD = H.get_bodypart(BODY_ZONE_HEAD) diff --git a/code/modules/mob/dead/new_player/sprite_accessories/ipc_synths.dm b/code/modules/mob/dead/new_player/sprite_accessories/ipc_synths.dm index 8bda196faa..f73a4a35a1 100644 --- a/code/modules/mob/dead/new_player/sprite_accessories/ipc_synths.dm +++ b/code/modules/mob/dead/new_player/sprite_accessories/ipc_synths.dm @@ -6,6 +6,7 @@ icon = 'modular_citadel/icons/mob/ipc_screens.dmi' color_src = null relevant_layers = list(BODY_ADJ_LAYER) + mutable_category = "HEAD" /datum/sprite_accessory/screen/blank name = "Blank" diff --git a/code/modules/mob/dead/new_player/sprite_accessories/snouts.dm b/code/modules/mob/dead/new_player/sprite_accessories/snouts.dm index 75b62e8c0f..aa9ec41dcc 100644 --- a/code/modules/mob/dead/new_player/sprite_accessories/snouts.dm +++ b/code/modules/mob/dead/new_player/sprite_accessories/snouts.dm @@ -2,6 +2,7 @@ icon = 'icons/mob/mutant_bodyparts.dmi' mutant_part_string = "snout" relevant_layers = list(BODY_ADJ_LAYER, BODY_FRONT_LAYER) + mutable_category = "HEAD" /datum/sprite_accessory/snouts/is_not_visible(var/mob/living/carbon/human/H, var/tauric) var/obj/item/bodypart/head/HD = H.get_bodypart(BODY_ZONE_HEAD) diff --git a/code/modules/mob/dead/new_player/sprite_accessories/synthliz.dm b/code/modules/mob/dead/new_player/sprite_accessories/synthliz.dm index 08897ade34..870f4f5ba4 100644 --- a/code/modules/mob/dead/new_player/sprite_accessories/synthliz.dm +++ b/code/modules/mob/dead/new_player/sprite_accessories/synthliz.dm @@ -5,6 +5,7 @@ color_src = MUTCOLORS name = "Synthetic Lizard - Snout" icon_state = "synthliz_basic" + mutable_category = "HEAD" /datum/sprite_accessory/snouts/mam_snouts/synthliz/synthliz_under icon = 'modular_citadel/icons/mob/synthliz_snouts.dmi' diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm index ddbb23741b..c8cc58c916 100644 --- a/code/modules/mob/living/carbon/human/species.dm +++ b/code/modules/mob/living/carbon/human/species.dm @@ -697,6 +697,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) fhair_file = 'icons/mob/facialhair_extensions.dmi' var/mutable_appearance/facial_overlay = mutable_appearance(fhair_file, fhair_state, -HAIR_LAYER) + facial_overlay.category = "HEAD" if(!forced_colour) if(hair_color) @@ -734,8 +735,10 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) if(!hair_hidden || dynamic_hair_suffix) var/mutable_appearance/hair_overlay = mutable_appearance(layer = -HAIR_LAYER) + hair_overlay.category = "HEAD" var/mutable_appearance/gradient_overlay = mutable_appearance(layer = -HAIR_LAYER) - if(!hair_hidden && !H.getorgan(/obj/item/organ/brain)) //Applies the debrained overlay if there is no brain + gradient_overlay.category = "HEAD" + if(!hair_hidden && !H.getorgan(/obj/item/organ/brain) && !H.GetComponent(/datum/component/dullahan)) //Applies the debrained overlay if there is no brain (ignore if they are dullahan) if(!(NOBLOOD in species_traits)) hair_overlay.icon = 'icons/mob/human_parts.dmi' hair_overlay.icon_state = "debrained" @@ -811,6 +814,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) // lipstick if(H.lip_style && (LIPS in species_traits)) var/mutable_appearance/lip_overlay = mutable_appearance('icons/mob/lips.dmi', "lips_[H.lip_style]", -BODY_LAYER) + lip_overlay.category = "HEAD" lip_overlay.color = H.lip_color if(OFFSET_LIPS in H.dna.species.offset_features) @@ -822,8 +826,9 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) // eyes if(!(NOEYES in species_traits)) var/has_eyes = H.getorganslot(ORGAN_SLOT_EYES) - if(!has_eyes) + if(!has_eyes && !H.GetComponent(/datum/component/dullahan)) standing += mutable_appearance('icons/mob/eyes.dmi', "eyes_missing", -BODY_LAYER) + message_admins("EYES MISSING APPLIED 2") else var/left_state = DEFAULT_LEFT_EYE_STATE var/right_state = DEFAULT_RIGHT_EYE_STATE @@ -832,6 +837,8 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) right_state = eye_type + "_right_eye" var/mutable_appearance/left_eye = mutable_appearance('icons/mob/eyes.dmi', left_state, -BODY_LAYER) var/mutable_appearance/right_eye = mutable_appearance('icons/mob/eyes.dmi', right_state, -BODY_LAYER) + left_eye.category = "HEAD" + right_eye.category = "HEAD" if((EYECOLOR in species_traits) && has_eyes) left_eye.color = "#" + H.left_eye_color right_eye.color = "#" + H.right_eye_color @@ -1009,6 +1016,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) for(var/bodypart in relevant_layers[layer]) var/datum/sprite_accessory/S = bodypart var/mutable_appearance/accessory_overlay = mutable_appearance(S.icon, layer = -layernum) + accessory_overlay.category = S.mutable_category bodypart = S.mutant_part_string || dna_feature_as_text_string[S] if(S.gender_specific) @@ -1113,6 +1121,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) if(S.extra) //apply the extra overlay, if there is one var/mutable_appearance/extra_accessory_overlay = mutable_appearance(S.icon, layer = -layernum) + extra_accessory_overlay.category = S.mutable_category if(S.gender_specific) extra_accessory_overlay.icon_state = "[g]_[bodypart]_extra_[S.icon_state]_[layertext]" else @@ -1159,6 +1168,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) if(S.extra2) //apply the extra overlay, if there is one var/mutable_appearance/extra2_accessory_overlay = mutable_appearance(S.icon, layer = -layernum) + extra2_accessory_overlay.category = S.mutable_category if(S.gender_specific) extra2_accessory_overlay.icon_state = "[g]_[bodypart]_extra2_[S.icon_state]_[layertext]" else diff --git a/code/modules/mob/living/carbon/human/update_icons.dm b/code/modules/mob/living/carbon/human/update_icons.dm index a0620c8990..f225afdd79 100644 --- a/code/modules/mob/living/carbon/human/update_icons.dm +++ b/code/modules/mob/living/carbon/human/update_icons.dm @@ -791,8 +791,9 @@ use_mob_overlay_icon: if FALSE, it will always use the default_icon_file even if // eyes if(!(NOEYES in dna.species.species_traits)) var/has_eyes = getorganslot(ORGAN_SLOT_EYES) - if(!has_eyes) + if(!has_eyes && !GetComponent(/datum/component/dullahan)) add_overlay(mutable_appearance('icons/mob/eyes.dmi', "eyes_missing", -BODY_LAYER)) + message_admins("EYES MISSING APPLIED") else var/left_state = DEFAULT_LEFT_EYE_STATE var/right_state = DEFAULT_RIGHT_EYE_STATE @@ -803,6 +804,8 @@ use_mob_overlay_icon: if FALSE, it will always use the default_icon_file even if right_state = eye_type + "_right_eye" var/mutable_appearance/left_eye = mutable_appearance('icons/mob/eyes.dmi', left_state, -BODY_LAYER) var/mutable_appearance/right_eye = mutable_appearance('icons/mob/eyes.dmi', right_state, -BODY_LAYER) + left_eye.category = "HEAD" + right_eye.category = "HEAD" if((EYECOLOR in dna.species.species_traits) && has_eyes) left_eye.color = "#" + left_eye_color right_eye.color = "#" + right_eye_color diff --git a/code/modules/surgery/bodyparts/head.dm b/code/modules/surgery/bodyparts/head.dm index 8c283f5ebc..7278dc6888 100644 --- a/code/modules/surgery/bodyparts/head.dm +++ b/code/modules/surgery/bodyparts/head.dm @@ -134,7 +134,7 @@ I.pixel_y = px_y add_overlay(standing) -/obj/item/bodypart/head/get_limb_icon(dropped) +/obj/item/bodypart/head/get_limb_icon(dropped, ignore_brain = FALSE, ignore_eyes = FALSE) if(custom_head) return cut_overlays() @@ -152,7 +152,7 @@ . += facial_overlay //Applies the debrained overlay if there is no brain - if(!brain) + if(!brain && !ignore_brain) var/image/debrain_overlay = image(layer = -HAIR_LAYER, dir = SOUTH) if(animal_origin == ALIEN_BODYPART) debrain_overlay.icon = 'icons/mob/animal_parts.dmi' @@ -175,12 +175,13 @@ // lipstick if(lip_style) - var/image/lips_overlay = image('icons/mob/lips.dmi', "lips_[lip_style]", -BODY_LAYER, SOUTH) + var/mutable_appearance/lips_overlay = mutable_appearance('icons/mob/lips.dmi', "lips_[lip_style]", -BODY_LAYER, SOUTH) + lips_overlay.category = "HEAD" lips_overlay.color = lip_color . += lips_overlay // eyes - if(eyes) + if(eyes || ignore_eyes) var/left_state = DEFAULT_LEFT_EYE_STATE var/right_state = DEFAULT_RIGHT_EYE_STATE if(owner && owner.dna.species) @@ -189,17 +190,20 @@ left_state = eye_type + "_left_eye" right_state = eye_type + "_right_eye" if(left_state != DEFAULT_NO_EYE_STATE) - var/image/left_eye = image('icons/mob/hair.dmi', left_state, -BODY_LAYER, SOUTH) + var/mutable_appearance/left_eye = mutable_appearance('icons/mob/hair.dmi', left_state, -BODY_LAYER, SOUTH) + left_eye.category = "HEAD" if(eyes.left_eye_color) left_eye.color = "#" + eyes.left_eye_color . += left_eye if(right_state != DEFAULT_NO_EYE_STATE) - var/image/right_eye = image('icons/mob/hair.dmi', right_state, -BODY_LAYER, SOUTH) + var/mutable_appearance/right_eye = mutable_appearance('icons/mob/hair.dmi', right_state, -BODY_LAYER, SOUTH) + right_eye.category = "HEAD" if(eyes.right_eye_color) right_eye.color = "#" + eyes.right_eye_color . += right_eye else var/eyes_overlay = image('icons/mob/hair.dmi', "eyes_missing", -BODY_LAYER, SOUTH) + message_admins("EYES MISSING ALSO IGNORE EYES IS [ignore_eyes]") . += eyes_overlay /obj/item/bodypart/head/monkey diff --git a/tgstation.dme b/tgstation.dme index 4fb3920c45..9fd6194e67 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -521,6 +521,7 @@ #include "code\datums\components\combat_mode.dm" #include "code\datums\components\construction.dm" #include "code\datums\components\dejavu.dm" +#include "code\datums\components\dullahan.dm" #include "code\datums\components\earprotection.dm" #include "code\datums\components\edible.dm" #include "code\datums\components\edit_complainer.dm"