diff --git a/SQL/paradise_schema.sql b/SQL/paradise_schema.sql index d8f8edfe7d7..a801eb17898 100644 --- a/SQL/paradise_schema.sql +++ b/SQL/paradise_schema.sql @@ -48,6 +48,7 @@ CREATE TABLE `characters` ( `facial_style_name` varchar(45) NOT NULL, `marking_styles` mediumtext NOT NULL, `head_accessory_style_name` varchar(45) NOT NULL, + `alt_head_name` varchar(45) NOT NULL, `eyes_red` smallint(4) NOT NULL, `eyes_green` smallint(4) NOT NULL, `eyes_blue` smallint(4) NOT NULL, diff --git a/SQL/paradise_schema_prefixed.sql b/SQL/paradise_schema_prefixed.sql index a75af823a5b..e4b7e375786 100644 --- a/SQL/paradise_schema_prefixed.sql +++ b/SQL/paradise_schema_prefixed.sql @@ -48,6 +48,7 @@ CREATE TABLE `SS13_characters` ( `facial_style_name` varchar(45) NOT NULL, `marking_styles` mediumtext NOT NULL, `head_accessory_style_name` varchar(45) NOT NULL, + `alt_head_name` varchar(45) NOT NULL, `eyes_red` smallint(4) NOT NULL, `eyes_green` smallint(4) NOT NULL, `eyes_blue` smallint(4) NOT NULL, diff --git a/code/__HELPERS/global_lists.dm b/code/__HELPERS/global_lists.dm index 8a44c1b7cab..ea8411ef30b 100644 --- a/code/__HELPERS/global_lists.dm +++ b/code/__HELPERS/global_lists.dm @@ -18,6 +18,8 @@ init_sprite_accessory_subtypes(/datum/sprite_accessory/undershirt, undershirt_list, undershirt_m, undershirt_f) //socks init_sprite_accessory_subtypes(/datum/sprite_accessory/socks, socks_list, socks_m, socks_f) + //alt heads + init_sprite_accessory_subtypes(/datum/sprite_accessory/alt_heads, alt_heads_list) init_subtypes(/datum/surgery_step, surgery_steps) diff --git a/code/_globalvars/lists/flavor_misc.dm b/code/_globalvars/lists/flavor_misc.dm index b6e851ec452..92eefcd54a9 100644 --- a/code/_globalvars/lists/flavor_misc.dm +++ b/code/_globalvars/lists/flavor_misc.dm @@ -26,6 +26,8 @@ var/global/list/undershirt_f = list() //stores only undershirt name var/global/list/socks_list = list() //stores /datum/sprite_accessory/socks indexed by name var/global/list/socks_m = list() //stores only socks name var/global/list/socks_f = list() //stores only socks name + //Alt Heads +var/global/list/alt_heads_list = list() //stores /datum/sprite_accessory/alt_heads indexed by name //Backpacks var/global/list/backbaglist = list("Nothing", "Backpack", "Satchel", "Satchel Alt") diff --git a/code/datums/datacore.dm b/code/datums/datacore.dm index 0f71fa429ea..de485d12056 100644 --- a/code/datums/datacore.dm +++ b/code/datums/datacore.dm @@ -140,7 +140,12 @@ proc/get_id_photo(var/mob/living/carbon/human/H) var/icon/temp temp = new /icon(icobase, "groin_[g]") preview_icon.Blend(temp, ICON_OVERLAY) - temp = new /icon(icobase, "head_[g]") + var/head = "head" + if(head_organ.alt_head) + var/datum/sprite_accessory/alt_heads/alternate_head = alt_heads_list[head_organ.alt_head] + if(alternate_head.icon_state) + head = alternate_head.icon_state + temp = new /icon(icobase, "[head]_[g]") preview_icon.Blend(temp, ICON_OVERLAY) //Tail diff --git a/code/modules/client/preference/preferences.dm b/code/modules/client/preference/preferences.dm index 0d796197f6a..8802d937904 100644 --- a/code/modules/client/preference/preferences.dm +++ b/code/modules/client/preference/preferences.dm @@ -131,6 +131,7 @@ var/global/list/special_role_times = list( //minimum age (in days) for accounts var/r_eyes = 0 //Eye color var/g_eyes = 0 //Eye color var/b_eyes = 0 //Eye color + var/alt_head = null //Alt head style. var/species = "Human" var/language = "None" //Secondary language @@ -339,6 +340,9 @@ var/global/list/special_role_times = list( //minimum age (in days) for accounts dat += "Character Records
" dat += "

Limbs

" + if(species in list("Unathi")) //Species with alt heads. + dat += "Alternate Head: " + dat += "[alt_head]
" dat += "Limbs and Parts: Adjust
" if(species != "Slime People" && species != "Machine") dat += "Internal Organs: Adjust
" @@ -1372,16 +1376,46 @@ var/global/list/special_role_times = list( //minimum age (in days) for accounts if(new_head_accessory_style) ha_style = new_head_accessory_style + if("alt_head") + if(organ_data["head"] == "cyborg") + return + if(species in list("Unathi")) //Species with head accessories. + var/list/valid_alt_heads = list() + valid_alt_heads["None"] = alt_heads_list["None"] //The only null entry should be the "None" option + for(var/alternate_head in alt_heads_list) + var/datum/sprite_accessory/alt_heads/head = alt_heads_list[alternate_head] + if(!(species in head.species_allowed)) + continue + + valid_alt_heads[alternate_head] = alt_heads_list[alternate_head] + + var/new_alt_head = input(user, "Choose your character's alternate head style:", "Character Preference") as null|anything in valid_alt_heads + if(new_alt_head) + alt_head = new_alt_head + var/list/marking_styles = params2list(m_styles) + if(marking_styles["head"]) + var/head_marking = marking_styles["head"] + var/datum/sprite_accessory/body_markings/head/head_marking_style = marking_styles_list[head_marking] + if(!head_marking_style.heads_allowed || !(alt_head in head_marking_style.heads_allowed)) + marking_styles["head"] = "None" + m_styles = list2params(marking_styles) + if("m_style_head") if(species in list("Machine", "Tajaran", "Unathi")) //Species with head markings. var/list/valid_markings = list() valid_markings["None"] = marking_styles_list["None"] for(var/markingstyle in marking_styles_list) - var/datum/sprite_accessory/M = marking_styles_list[markingstyle] + var/datum/sprite_accessory/body_markings/head/M = marking_styles_list[markingstyle] if(!(species in M.species_allowed)) continue if(M.marking_location != "head") continue + if(alt_head && alt_head != "None") + if(!(alt_head in M.heads_allowed)) + continue + else + if(M.heads_allowed) + continue if(species == "Machine") //Species that can use prosthetic heads. var/obj/item/organ/external/head/H = new() @@ -1738,11 +1772,15 @@ var/global/list/special_role_times = list( //minimum age (in days) for accounts subchoice = input(user, "Which model of [choice] [limb_name] do you wish to use?") as null|anything in robolimb_models if(subchoice) choice = subchoice - if(limb == "head") - ha_style = "None" - h_style = hair_styles_list["Bald"] - f_style = facial_hair_styles_list["Shaved"] - marking_styles["head"] = "None" + if(limb in list("head", "chest", "groin")) + if(species != "Machine") + return + if(limb == "head") + ha_style = "None" + alt_head = null + h_style = hair_styles_list["Bald"] + f_style = facial_hair_styles_list["Shaved"] + marking_styles["head"] = "None" rlimb_data[limb] = choice organ_data[limb] = "cyborg" if(second_limb) @@ -1964,6 +2002,8 @@ var/global/list/special_role_times = list( //minimum age (in days) for accounts H.h_style = h_style H.f_style = f_style + + H.alt_head = alt_head //End of head-specific. character.r_skin = r_skin diff --git a/code/modules/client/preference/preferences_mysql.dm b/code/modules/client/preference/preferences_mysql.dm index 0dcfade53af..3a06395ba77 100644 --- a/code/modules/client/preference/preferences_mysql.dm +++ b/code/modules/client/preference/preferences_mysql.dm @@ -125,6 +125,7 @@ facial_style_name, marking_styles, head_accessory_style_name, + alt_head_name, eyes_red, eyes_green, eyes_blue, @@ -194,46 +195,47 @@ f_style = query.item[23] m_styles = query.item[24] ha_style = query.item[25] - r_eyes = text2num(query.item[26]) - g_eyes = text2num(query.item[27]) - b_eyes = text2num(query.item[28]) - underwear = query.item[29] - undershirt = query.item[30] - backbag = text2num(query.item[31]) - b_type = query.item[32] + alt_head = query.item[26] + r_eyes = text2num(query.item[27]) + g_eyes = text2num(query.item[28]) + b_eyes = text2num(query.item[29]) + underwear = query.item[30] + undershirt = query.item[31] + backbag = text2num(query.item[32]) + b_type = query.item[33] //Jobs - alternate_option = text2num(query.item[33]) - job_support_high = text2num(query.item[34]) - job_support_med = text2num(query.item[35]) - job_support_low = text2num(query.item[36]) - job_medsci_high = text2num(query.item[37]) - job_medsci_med = text2num(query.item[38]) - job_medsci_low = text2num(query.item[39]) - job_engsec_high = text2num(query.item[40]) - job_engsec_med = text2num(query.item[41]) - job_engsec_low = text2num(query.item[42]) - job_karma_high = text2num(query.item[43]) - job_karma_med = text2num(query.item[44]) - job_karma_low = text2num(query.item[44]) + alternate_option = text2num(query.item[34]) + job_support_high = text2num(query.item[35]) + job_support_med = text2num(query.item[36]) + job_support_low = text2num(query.item[37]) + job_medsci_high = text2num(query.item[38]) + job_medsci_med = text2num(query.item[39]) + job_medsci_low = text2num(query.item[40]) + job_engsec_high = text2num(query.item[41]) + job_engsec_med = text2num(query.item[42]) + job_engsec_low = text2num(query.item[43]) + job_karma_high = text2num(query.item[44]) + job_karma_med = text2num(query.item[45]) + job_karma_low = text2num(query.item[46]) //Miscellaneous - flavor_text = query.item[46] - med_record = query.item[47] - sec_record = query.item[48] - gen_record = query.item[49] - disabilities = text2num(query.item[50]) - player_alt_titles = params2list(query.item[51]) - organ_data = params2list(query.item[52]) - rlimb_data = params2list(query.item[53]) - nanotrasen_relation = query.item[54] - speciesprefs = text2num(query.item[55]) + flavor_text = query.item[47] + med_record = query.item[48] + sec_record = query.item[49] + gen_record = query.item[50] + disabilities = text2num(query.item[51]) + player_alt_titles = params2list(query.item[52]) + organ_data = params2list(query.item[53]) + rlimb_data = params2list(query.item[54]) + nanotrasen_relation = query.item[55] + speciesprefs = text2num(query.item[56]) //socks - socks = query.item[56] - body_accessory = query.item[57] - gear = params2list(query.item[58]) + socks = query.item[57] + body_accessory = query.item[58] + gear = params2list(query.item[59]) //Sanitize metadata = sanitize_text(metadata, initial(metadata)) @@ -262,6 +264,7 @@ h_style = sanitize_inlist(h_style, hair_styles_list, initial(h_style)) f_style = sanitize_inlist(f_style, facial_hair_styles_list, initial(f_style)) ha_style = sanitize_inlist(ha_style, head_accessory_styles_list, initial(ha_style)) + alt_head = sanitize_inlist(alt_head, alt_heads_list, initial(alt_head)) r_eyes = sanitize_integer(r_eyes, 0, 255, initial(r_eyes)) g_eyes = sanitize_integer(g_eyes, 0, 255, initial(g_eyes)) b_eyes = sanitize_integer(b_eyes, 0, 255, initial(b_eyes)) @@ -341,6 +344,7 @@ facial_style_name='[sql_sanitize_text(f_style)]', marking_styles='[m_styles]', head_accessory_style_name='[sql_sanitize_text(ha_style)]', + alt_head_name='[sql_sanitize_text(alt_head)]', eyes_red='[r_eyes]', eyes_green='[g_eyes]', eyes_blue='[b_eyes]', @@ -393,7 +397,7 @@ skin_tone, skin_red, skin_green, skin_blue, marking_colours, head_accessory_red, head_accessory_green, head_accessory_blue, - hair_style_name, facial_style_name, marking_styles, head_accessory_style_name, + hair_style_name, facial_style_name, marking_styles, head_accessory_style_name, alt_head_name, eyes_red, eyes_green, eyes_blue, underwear, undershirt, backbag, b_type, alternate_option, @@ -414,7 +418,7 @@ '[s_tone]', '[r_skin]', '[g_skin]', '[b_skin]', '[m_colours]', '[r_headacc]', '[g_headacc]', '[b_headacc]', - '[sql_sanitize_text(h_style)]', '[sql_sanitize_text(f_style)]', '[m_styles]', '[sql_sanitize_text(ha_style)]', + '[sql_sanitize_text(h_style)]', '[sql_sanitize_text(f_style)]', '[m_styles]', '[sql_sanitize_text(ha_style)]', '[sql_sanitize_text(alt_head)]', '[r_eyes]', '[g_eyes]', '[b_eyes]', '[underwear]', '[undershirt]', '[backbag]', '[b_type]', '[alternate_option]', diff --git a/code/modules/mob/living/carbon/human/appearance.dm b/code/modules/mob/living/carbon/human/appearance.dm index 535c5676a9b..e01211a0f94 100644 --- a/code/modules/mob/living/carbon/human/appearance.dm +++ b/code/modules/mob/living/carbon/human/appearance.dm @@ -96,10 +96,16 @@ if(!(marking_style in marking_styles_list)) return - var/datum/sprite_accessory/marking = marking_styles_list[marking_style] + var/datum/sprite_accessory/body_markings/marking = marking_styles_list[marking_style] if(marking.name != "None" && marking.marking_location != location) return + var/obj/item/organ/external/head/head_organ = get_organ("head") + if(location == "head" && head_organ.alt_head) + var/datum/sprite_accessory/body_markings/head/H + if(!H.heads_allowed || !(head_organ.alt_head in H.heads_allowed)) + return + marking_styles[location] = marking_style m_styles = list2params(marking_styles) @@ -403,10 +409,18 @@ else if(!S.tails_allowed || !(body_accessory in S.tails_allowed)) continue - if(location == "head" && H.species.flags & ALL_RPARTS) //If the user is a species that can have a robotic head... - var/datum/robolimb/robohead = all_robolimbs[H.model] - if(!(S.models_allowed && (robohead.company in S.models_allowed))) //Make sure they don't get markings incompatible with their head. - continue + if(location == "head") + var/datum/sprite_accessory/body_markings/head/M = marking_styles_list[S.name] + if(H.species.flags & ALL_RPARTS)//If the user is a species that can have a robotic head... + var/datum/robolimb/robohead = all_robolimbs[H.model] + if(!(S.models_allowed && (robohead.company in S.models_allowed))) //Make sure they don't get markings incompatible with their head. + continue + else if(H.alt_head && H.alt_head != "None") //If the user's got an alt head, validate markings for that head. + if(!(H.alt_head in M.heads_allowed)) + continue + else + if(M.heads_allowed) + continue valid_markings += marking return valid_markings diff --git a/code/modules/mob/living/carbon/human/update_icons.dm b/code/modules/mob/living/carbon/human/update_icons.dm index dfe570e8a98..04e602fab0d 100644 --- a/code/modules/mob/living/carbon/human/update_icons.dm +++ b/code/modules/mob/living/carbon/human/update_icons.dm @@ -365,7 +365,7 @@ var/global/list/damage_icon_parts = list() if(chest_organ && !chest_organ.is_stump() && !(chest_organ.status & ORGAN_DESTROYED) && marking_styles["body"]) var/body_marking = marking_styles["body"] var/datum/sprite_accessory/body_marking_style = marking_styles_list[body_marking] - if(body_marking_style) + if(body_marking_style && body_marking_style.species_allowed && (species.name in body_marking_style.species_allowed)) var/icon/b_marking_s = new/icon("icon" = body_marking_style.icon, "icon_state" = "[body_marking_style.icon_state]_s") if(body_marking_style.do_colouration) marking_colours["body"] = sanitize_hexcolor(marking_colours["body"]) @@ -376,7 +376,7 @@ var/global/list/damage_icon_parts = list() if(head_organ && !head_organ.is_stump() && !(head_organ.status & ORGAN_DESTROYED) && marking_styles["head"]) //If the head is destroyed, forget the head markings. This prevents floating optical markings on decapitated IPCs, for example. var/head_marking = marking_styles["head"] var/datum/sprite_accessory/head_marking_style = marking_styles_list[head_marking] - if(head_marking_style) + if(head_marking_style && head_marking_style.species_allowed && (head_organ.species.name in head_marking_style.species_allowed)) var/icon/h_marking_s = new/icon("icon" = head_marking_style.icon, "icon_state" = "[head_marking_style.icon_state]_s") if(head_marking_style.do_colouration) marking_colours["head"] = sanitize_hexcolor(marking_colours["head"]) diff --git a/code/modules/mob/new_player/preferences_setup.dm b/code/modules/mob/new_player/preferences_setup.dm index b7ca2de44a1..7c6426ed93d 100644 --- a/code/modules/mob/new_player/preferences_setup.dm +++ b/code/modules/mob/new_player/preferences_setup.dm @@ -221,7 +221,12 @@ fat="_fat" preview_icon = new /icon(icobase, "torso_[g][fat]") preview_icon.Blend(new /icon(icobase, "groin_[g]"), ICON_OVERLAY) - preview_icon.Blend(new /icon(icobase, "head_[g]"), ICON_OVERLAY) + var/head = "head" + if(alt_head) + var/datum/sprite_accessory/alt_heads/H = alt_heads_list[alt_head] + if(H.icon_state) + head = H.icon_state + preview_icon.Blend(new /icon(icobase, "[head]_[g]"), ICON_OVERLAY) for(var/name in list("chest", "groin", "head", "r_arm", "r_hand", "r_leg", "r_foot", "l_leg", "l_foot", "l_arm", "l_hand")) if(organ_data[name] == "amputated") continue diff --git a/code/modules/mob/new_player/sprite_accessories.dm b/code/modules/mob/new_player/sprite_accessories.dm index 952bf0453fc..19768d19430 100644 --- a/code/modules/mob/new_player/sprite_accessories.dm +++ b/code/modules/mob/new_player/sprite_accessories.dm @@ -44,6 +44,7 @@ // Restrict some styles to specific species var/list/species_allowed = list("Human", "Slime People") var/list/models_allowed = list() //Specifies which, if any, hairstyles or markings can be accessed by which prosthetics. Should equal the manufacturing company name in robolimbs.dm. + var/list/heads_allowed = null //Specifies which, if any, alt heads a head marking, hairstyle or facial hair style is compatible with. var/list/tails_allowed = null //Specifies which, if any, tails a tail marking is compatible with. var/marking_location //Specifies which bodypart a body marking is located on. @@ -1962,10 +1963,22 @@ species_allowed = list("Unathi") icon_state = "markings_face_snout_round_una" +/datum/sprite_accessory/body_markings/head/snout_round_lower_una + name = "Unathi Round Snout - Lower" + species_allowed = list("Unathi") + icon_state = "markings_face_snout_round_lower_una" + /datum/sprite_accessory/body_markings/head/snout_sharp_una name = "Unathi Sharp Snout" species_allowed = list("Unathi") icon_state = "markings_face_snout_sharp_una" + heads_allowed = list("Unathi Sharp Snout") + +/datum/sprite_accessory/body_markings/head/snout_sharp_lower_una + name = "Unathi Sharp Snout - Lower" + species_allowed = list("Unathi") + icon_state = "markings_face_snout_sharp_lower_una" + heads_allowed = list("Unathi Sharp Snout") /datum/sprite_accessory/body_markings/head/optics name = "Humanoid Optics" @@ -2043,4 +2056,23 @@ name = "Vulpkanin Short Tail Tip" species_allowed = list("Vulpkanin") tails_allowed = list("Vulpkanin Alt 4 (Short)") - icon_state = "markings_vulptail5_tip" \ No newline at end of file + icon_state = "markings_vulptail5_tip" + +/* ALT HEADS */ + +/datum/sprite_accessory/alt_heads + name = "Alternate Head" + icon = null + icon_state = null + species_allowed = null + +/datum/sprite_accessory/alt_heads/none + name = "None" + icon = null + icon_state = null + species_allowed = null + +/datum/sprite_accessory/alt_heads/una_sharp_snout + name = "Unathi Sharp Snout" + species_allowed = list("Unathi") + icon_state = "head_sharp" diff --git a/code/modules/surgery/organs/organ_icon.dm b/code/modules/surgery/organs/organ_icon.dm index 431c4484040..e7702426c7f 100644 --- a/code/modules/surgery/organs/organ_icon.dm +++ b/code/modules/surgery/organs/organ_icon.dm @@ -139,6 +139,13 @@ var/global/list/limb_icon_cache = list() else if(status & ORGAN_ROBOT) mob_icon = new /icon('icons/mob/human_races/robotic.dmi', "[icon_name][gender ? "_[gender]" : ""]") else + if(limb_name == "head") + var/obj/item/organ/external/head/head_organ = src + if(head_organ.alt_head) + var/datum/sprite_accessory/alt_heads/alternate_head = alt_heads_list[head_organ.alt_head] + if(alternate_head.icon_state) + icon_name = alternate_head.icon_state + if(status & ORGAN_MUTATED) mob_icon = new /icon(species.deform, "[icon_name][gender ? "_[gender]" : ""]") else diff --git a/code/modules/surgery/organs/subtypes/standard.dm b/code/modules/surgery/organs/subtypes/standard.dm index 1c6240318fe..182f0875417 100644 --- a/code/modules/surgery/organs/subtypes/standard.dm +++ b/code/modules/surgery/organs/subtypes/standard.dm @@ -140,6 +140,7 @@ gendered_icon = 1 encased = "skull" var/can_intake_reagents = 1 + var/alt_head = null //Hair colour and style var/r_hair = 0 diff --git a/icons/mob/body_accessory.dmi b/icons/mob/body_accessory.dmi index a53460c1d24..ee52b20206c 100644 Binary files a/icons/mob/body_accessory.dmi and b/icons/mob/body_accessory.dmi differ diff --git a/icons/mob/human_races/r_def_lizard.dmi b/icons/mob/human_races/r_def_lizard.dmi index 3926ca17092..e1c40712b23 100644 Binary files a/icons/mob/human_races/r_def_lizard.dmi and b/icons/mob/human_races/r_def_lizard.dmi differ diff --git a/icons/mob/human_races/r_lizard.dmi b/icons/mob/human_races/r_lizard.dmi index 457e50b204e..d60ae4979df 100644 Binary files a/icons/mob/human_races/r_lizard.dmi and b/icons/mob/human_races/r_lizard.dmi differ