diff --git a/code/__DEFINES/DNA.dm b/code/__DEFINES/DNA.dm index 6dc96b88ec16..fefc8d17f086 100644 --- a/code/__DEFINES/DNA.dm +++ b/code/__DEFINES/DNA.dm @@ -61,8 +61,9 @@ #define DNA_AVIAN_EARS_BLOCK 18 // NON-MODULE CHANGE #define DNA_AVIAN_TAIL_BLOCK 19 // NON-MODULE CHANGE #define DNA_FEATHER_COLOR_BLOCK 20 // NON-MODULE CHANGE +#define DNA_SYNTH_HEAD_COVER_BLOCK 21 // NON-MODULE CHANGE -#define DNA_FEATURE_BLOCKS 20 // NON-MODULE CHANGE +#define DNA_FEATURE_BLOCKS 21 // NON-MODULE CHANGE #define DNA_SEQUENCE_LENGTH 4 #define DNA_MUTATION_BLOCKS 8 @@ -104,6 +105,7 @@ #define ORGAN_SLOT_EXTERNAL_BODYMARKINGS "bodymarkings" #define ORGAN_SLOT_EXTERNAL_POD_HAIR "pod_hair" #define ORGAN_SLOT_EXTERNAL_HEAD_TENTACLES "head_tentacles" // NON-MODULE CHANGE +#define ORGAN_SLOT_EXTERNAL_SYNTH_HEAD_COVER "synth_head_cover" //NON-MODULE CHANGE /// Xenomorph organ slots #define ORGAN_SLOT_XENO_ACIDGLAND "acid_gland" diff --git a/code/__HELPERS/global_lists.dm b/code/__HELPERS/global_lists.dm index d9157a58cf06..928a1b13c3d2 100644 --- a/code/__HELPERS/global_lists.dm +++ b/code/__HELPERS/global_lists.dm @@ -38,6 +38,7 @@ init_sprite_accessory_subtypes(/datum/sprite_accessory/arm_wingsopen, GLOB.arm_wingsopen_list) //NON-MODULE CHANGE init_sprite_accessory_subtypes(/datum/sprite_accessory/tails/avian, GLOB.tails_list_avian) //NON-MODULE CHANGE init_sprite_accessory_subtypes(/datum/sprite_accessory/plumage, GLOB.avian_ears_list) //NON-MODULE CHANGE + init_sprite_accessory_subtypes(/datum/sprite_accessory/synth_head_cover, GLOB.synth_head_cover_list) //NON-MODULE CHANGE /// Inits GLOB.species_list. Not using GLOBAL_LIST_INIT b/c it depends on GLOB.string_lists /proc/init_species_list() diff --git a/code/datums/dna.dm b/code/datums/dna.dm index 90f8536d0c5d..2d84900d7955 100644 --- a/code/datums/dna.dm +++ b/code/datums/dna.dm @@ -242,6 +242,9 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block()) L[DNA_AVIAN_EARS_BLOCK] = construct_block(GLOB.avian_ears_list.Find(features["ears_avian"]), GLOB.avian_ears_list.len) if(features["feathers"]) // NON-MODULE CHANGE L[DNA_FEATHER_COLOR_BLOCK] = sanitize_hexcolor(features["feathers"], include_crunch = FALSE) + if(features["synth_head_cover"]) // NON-MODULE CHANGE + L[DNA_SYNTH_HEAD_COVER_BLOCK] = construct_block(GLOB.synth_head_cover_list.Find(features["synth_head_cover"]), GLOB.synth_head_cover_list.len) + for(var/blocknum in 1 to DNA_FEATURE_BLOCKS) . += L[blocknum] || random_string(GET_UI_BLOCK_LEN(blocknum), GLOB.hex_characters) @@ -388,6 +391,9 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block()) set_uni_feature_block(blocknumber, construct_block(GLOB.avian_ears_list.Find(features["ears_avian"]), GLOB.avian_ears_list.len)) if(DNA_FEATHER_COLOR_BLOCK) // NON-MODULE CHANGE set_uni_feature_block(blocknumber, sanitize_hexcolor(features["feathers"], include_crunch = FALSE)) + if(DNA_SYNTH_HEAD_COVER_BLOCK) // NON-MODULE CHANGE + set_uni_feature_block(blocknumber, construct_block(GLOB.synth_head_cover_list.Find(features["head_tentacles"]), GLOB.synth_head_cover_list.len)) + //Please use add_mutation or activate_mutation instead /datum/dna/proc/force_give(datum/mutation/human/human_mutation) @@ -696,6 +702,8 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block()) dna.features["ears_avian"] = GLOB.avian_ears_list[deconstruct_block(get_uni_feature_block(features, DNA_AVIAN_EARS_BLOCK), GLOB.avian_ears_list.len)] if(dna.features["feathers"]) // NON-MODULE CHANGE dna.features["feathers"] = sanitize_hexcolor(get_uni_feature_block(features, DNA_FEATHER_COLOR_BLOCK)) + if(dna.features["synth_head_cover"]) // NON-MODULE CHANGE + dna.features["synth_head_cover"] = GLOB.synth_head_cover_list[deconstruct_block(get_uni_feature_block(features, DNA_SYNTH_HEAD_COVER_BLOCK), GLOB.synth_head_cover_list.len)] for(var/obj/item/organ/external/external_organ in organs) external_organ.mutate_feature(features, src) diff --git a/code/modules/mob/living/carbon/human/dummy.dm b/code/modules/mob/living/carbon/human/dummy.dm index e712de2e5bc2..305bf132f721 100644 --- a/code/modules/mob/living/carbon/human/dummy.dm +++ b/code/modules/mob/living/carbon/human/dummy.dm @@ -107,6 +107,7 @@ INITIALIZE_IMMEDIATE(/mob/living/carbon/human/dummy) target.dna.features["arm_wings"] = get_consistent_feature_entry(GLOB.arm_wings_list) // NON-MODULE CHANGE target.dna.features["tail_avian"] = get_consistent_feature_entry(GLOB.tails_list_avian) // NON-MODULE CHANGE target.dna.features["ears_avian"] = get_consistent_feature_entry(GLOB.avian_ears_list) // NON-MODULE CHANGE + target.dna.features["synth_head_cover"] = get_consistent_feature_entry(GLOB.synth_head_cover_list) // NON-MODULE CHANGE target.dna.features["feathers"] = "#FF3B76" //NON-MODULE CHANGE target.dna.initialize_dna(/datum/blood_type/crew/human/o_plus, create_mutation_blocks = FALSE, randomize_features = FALSE) //NON-MODULE CHANGE // UF and UI are nondeterministic, even though the features are the same some blocks will randomize slightly diff --git a/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_synth.png b/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_synth.png index d793ca168ba0..0167a33b5126 100644 Binary files a/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_synth.png and b/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_synth.png differ diff --git a/maplestation_modules/code/modules/client/preferences/species/synth.dm b/maplestation_modules/code/modules/client/preferences/species/synth.dm index ab518f252a2a..df02a4f7ebce 100644 --- a/maplestation_modules/code/modules/client/preferences/species/synth.dm +++ b/maplestation_modules/code/modules/client/preferences/species/synth.dm @@ -75,3 +75,46 @@ /datum/preference/choiced/synth_blood/is_accessible(datum/preferences/preferences) return ..() && ispath(preferences.read_preference(/datum/preference/choiced/species), /datum/species/synth) + + + +//synth head covers (aka head design options) +/datum/preference/choiced/synth_head_cover + main_feature_name = "Head Cover" + savefile_key = "feature_synth_head_cover" + + savefile_identifier = PREFERENCE_CHARACTER + category = PREFERENCE_CATEGORY_FEATURES + can_randomize = TRUE + relevant_external_organ = /obj/item/organ/external/synth_head_cover + should_generate_icons = TRUE + +/datum/preference/choiced/synth_head_cover/init_possible_values() + return assoc_to_keys(GLOB.synth_head_cover_list) + +/datum/preference/choiced/synth_head_cover/icon_for(value) + var/datum/sprite_accessory/sprite_accessory = GLOB.synth_head_cover_list[value] + var/icon/head = icon('maplestation_modules/icons/mob/synth_heads.dmi', "synth_head", SOUTH) + + var/icon/final_icon = icon(head) + + if (!isnull(sprite_accessory)) + for(var/side in list("ADJ", "FRONT")) + var/icon/accessory_icon = icon( + icon = 'maplestation_modules/icons/mob/synth_heads.dmi', + icon_state = "m_synth_head_cover_[sprite_accessory.icon_state]_ADJ", + dir = SOUTH, + ) + final_icon.Blend(accessory_icon, ICON_OVERLAY) + + final_icon.Crop(11, 20, 23, 32) + final_icon.Scale(32, 32) + final_icon.Blend(COLOR_GRAY, ICON_MULTIPLY) + + return final_icon + +/datum/preference/choiced/synth_head_cover/apply_to_human(mob/living/carbon/human/target, value) + target.dna.features["synth_head_cover"] = value + +/datum/preference/choiced/synth_head_cover/create_default_value() + return /datum/sprite_accessory/synth_head_cover::name diff --git a/maplestation_modules/code/modules/mob/dead/new_player/sprite_accessories.dm b/maplestation_modules/code/modules/mob/dead/new_player/sprite_accessories.dm index 50c44c5db047..ecd0d34ceed1 100644 --- a/maplestation_modules/code/modules/mob/dead/new_player/sprite_accessories.dm +++ b/maplestation_modules/code/modules/mob/dead/new_player/sprite_accessories.dm @@ -256,6 +256,7 @@ icon ='maplestation_modules/icons/mob/clothing/underwear.dmi' gender = NEUTER +/// -- Frills -- /datum/sprite_accessory/frills/big name = "Big" icon_state = "big" @@ -266,6 +267,19 @@ icon_state = "divinity" icon = 'maplestation_modules/icons/mob/frills.dmi' +// -- Synth head coverings -- +/datum/sprite_accessory/synth_head_cover + icon = 'maplestation_modules/icons/mob/synth_heads.dmi' + +/datum/sprite_accessory/synth_head_cover/helm + name = "Helm" + icon_state = "helm" + +/datum/sprite_accessory/synth_head_cover/tv_blank + name = "Tv_blank" + icon_state = "tv_blank" + + /// --- Socks --- /datum/sprite_accessory/socks/pokersocks diff --git a/maplestation_modules/code/modules/mob/living/carbon/human/species_types/synth/synth.dm b/maplestation_modules/code/modules/mob/living/carbon/human/species_types/synth/synth.dm index c3e3eb93b240..757e872b57c4 100644 --- a/maplestation_modules/code/modules/mob/living/carbon/human/species_types/synth/synth.dm +++ b/maplestation_modules/code/modules/mob/living/carbon/human/species_types/synth/synth.dm @@ -1,5 +1,8 @@ // -- Synth additions (though barely functional) -- +/// GLOB list of head options +GLOBAL_LIST_EMPTY(synth_head_cover_list) + #define BODYPART_ID_SYNTH "synth" /mob/living/carbon/human/species/synth @@ -15,7 +18,7 @@ /datum/species/synth name = "Synth" id = SPECIES_SYNTH - sexes = FALSE + sexes = TRUE inherent_traits = list( TRAIT_AGEUSIA, TRAIT_NOBREATH, @@ -38,6 +41,9 @@ BODY_ZONE_R_LEG = /obj/item/bodypart/leg/right/synth, BODY_ZONE_L_LEG = /obj/item/bodypart/leg/left/synth, ) + + external_organs = list(/obj/item/organ/external/synth_head_cover = "Helm") + mutantbrain = /obj/item/organ/internal/brain/cybernetic mutanttongue = /obj/item/organ/internal/tongue/robot mutantstomach = /obj/item/organ/internal/stomach/cybernetic/tier2 @@ -45,7 +51,7 @@ mutantheart = /obj/item/organ/internal/heart/cybernetic/tier2 mutantliver = /obj/item/organ/internal/liver/cybernetic/tier2 mutantlungs = null - mutanteyes = /obj/item/organ/internal/eyes/robotic + mutanteyes = /obj/item/organ/internal/eyes/robotic/synth mutantears = /obj/item/organ/internal/ears/cybernetic species_pain_mod = 0.2 exotic_bloodtype = /datum/blood_type/oil @@ -363,8 +369,8 @@ /obj/item/bodypart/head/synth limb_id = BODYPART_ID_SYNTH - icon_static = 'icons/mob/human/bodyparts.dmi' - icon = 'icons/mob/human/bodyparts.dmi' + icon_static = 'maplestation_modules/icons/mob/synth_heads.dmi' + icon = 'maplestation_modules/icons/mob/synth_heads.dmi' icon_state = "synth_head" should_draw_greyscale = FALSE obj_flags = CONDUCTS_ELECTRICITY @@ -373,7 +379,7 @@ brute_modifier = 0.8 burn_modifier = 0.8 biological_state = BIO_ROBOTIC|BIO_BLOODED - head_flags = NONE + head_flags = HEAD_EYESPRITES | HEAD_EYECOLOR change_exempt_flags = BP_BLOCK_CHANGE_SPECIES /obj/item/bodypart/chest/synth @@ -447,4 +453,86 @@ biological_state = BIO_ROBOTIC|BIO_BLOODED change_exempt_flags = BP_BLOCK_CHANGE_SPECIES +/obj/item/organ/internal/eyes/robotic/synth + name = "synth eyes" + +// Organ for synth head covers. + +/obj/item/organ/external/synth_head_cover + name = "Head Cover" + desc = "It is a cover that goes on a synth head." + + zone = BODY_ZONE_HEAD + slot = ORGAN_SLOT_EXTERNAL_SYNTH_HEAD_COVER + + preference = "feature_synth_head_cover" + + dna_block = DNA_SYNTH_HEAD_COVER_BLOCK + organ_flags = ORGAN_ROBOTIC + + bodypart_overlay = /datum/bodypart_overlay/mutant/synth_head_cover + + +/obj/item/organ/external/synth_head_cover/on_mob_insert(mob/living/carbon/organ_owner, special, movement_flags) + . = ..() + var/mob/living/carbon/human/robot_target = organ_owner + var/obj/item/bodypart/head/noggin = robot_target.get_bodypart(BODY_ZONE_HEAD) + + noggin.head_flags &= ~HEAD_EYESPRITES + + +/obj/item/organ/external/synth_head_cover/on_mob_remove(mob/living/carbon/organ_owner, special, movement_flags) + . = ..() + var/mob/living/carbon/human/robot_target = organ_owner + var/obj/item/bodypart/head/noggin = robot_target.get_bodypart(BODY_ZONE_HEAD) + + noggin.head_flags &= HEAD_EYESPRITES + + +//-- overlay -- +/datum/bodypart_overlay/mutant/synth_head_cover/get_global_feature_list() + return GLOB.synth_head_cover_list + +/datum/bodypart_overlay/mutant/synth_head_cover/can_draw_on_bodypart(mob/living/carbon/human/human) + if((human.head?.flags_inv & HIDEHAIR) || (human.wear_mask?.flags_inv & HIDEHAIR)) + return FALSE + return TRUE + +/datum/bodypart_overlay/mutant/synth_head_cover + feature_key = "synth_head_cover" + layers = ALL_EXTERNAL_OVERLAYS + +//-- accessories -- +//the path to the icon for the head covers +/datum/sprite_accessory/synth_head_cover + icon = 'maplestation_modules/icons/mob/synth_heads.dmi' + +//head covers +/datum/sprite_accessory/synth_head_cover/none // for those that don't want a cover. + name = "None" + icon_state = null + +//A kind of helmet looking thing with a big black screen/face cover thing. I dunno what else to call this. +/datum/sprite_accessory/synth_head_cover/helm + name = "Helm" + icon_state = "helm" + +//helm with white plastic on the sides. +/datum/sprite_accessory/synth_head_cover/helm_white + name = "White Helm" + icon_state = "helm_white" + +//just the IPC TV that is already in the code base +/datum/sprite_accessory/synth_head_cover/tv_blank + name = "Tv_blank" + icon_state = "tv_blank" + +//a cool design inspired from cloak pilots in titanfall 2, *sorta*. +/datum/sprite_accessory/synth_head_cover/cloakp + name = "Cloakp" + icon_state = "cloakp" + +// add more here!! + + #undef BODYPART_ID_SYNTH diff --git a/maplestation_modules/icons/mob/synth_heads.dmi b/maplestation_modules/icons/mob/synth_heads.dmi new file mode 100644 index 000000000000..4023357e4e19 Binary files /dev/null and b/maplestation_modules/icons/mob/synth_heads.dmi differ diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/_modular_species_features.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/_modular_species_features.tsx index a83b55e6a335..39f181308281 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/_modular_species_features.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/_modular_species_features.tsx @@ -14,6 +14,11 @@ export const feature_head_tentacles: FeatureChoiced = { component: FeatureDropdownInput, }; +export const feature_synth_head_cover: FeatureChoiced = { + name: 'Head Cover', + component: FeatureDropdownInput, +}; + export const hair_lizard: FeatureToggle = { name: 'Hair Lizard', description: 'Check to spawn as a Lizard with hair.',