mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-07-21 03:55:05 +01:00
Merge pull request #16172 from dearmochi/hair-gradients
[READY] Port hair gradient customization
This commit is contained in:
@@ -56,7 +56,11 @@
|
||||
body_accessory,
|
||||
gear,
|
||||
autohiss,
|
||||
slot
|
||||
slot,
|
||||
hair_gradient,
|
||||
hair_gradient_offset,
|
||||
hair_gradient_colour,
|
||||
hair_gradient_alpha
|
||||
FROM characters WHERE ckey=:ckey"}, list(
|
||||
"ckey" = C.ckey
|
||||
))
|
||||
|
||||
@@ -95,6 +95,13 @@
|
||||
/// Character slot number, used for saves and stuff.
|
||||
var/slot_number = 0
|
||||
|
||||
// Hair gradient
|
||||
var/h_grad_style = "None"
|
||||
var/h_grad_offset_x = 0
|
||||
var/h_grad_offset_y = 0
|
||||
var/h_grad_colour = "#000000"
|
||||
var/h_grad_alpha = 255
|
||||
|
||||
// Fuckery to prevent null characters
|
||||
/datum/character_save/New()
|
||||
randomise()
|
||||
@@ -178,7 +185,11 @@
|
||||
socks=:socks,
|
||||
body_accessory=:body_accessory,
|
||||
gear=:gearlist,
|
||||
autohiss=:autohiss_mode
|
||||
autohiss=:autohiss_mode,
|
||||
hair_gradient=:h_grad_style,
|
||||
hair_gradient_offset=:h_grad_offset,
|
||||
hair_gradient_colour=:h_grad_colour,
|
||||
hair_gradient_alpha=:h_grad_alpha
|
||||
WHERE ckey=:ckey
|
||||
AND slot=:slot"}, list(
|
||||
// OH GOD SO MANY PARAMETERS
|
||||
@@ -234,6 +245,10 @@
|
||||
"body_accessory" = (body_accessory ? body_accessory : ""),
|
||||
"gearlist" = (gearlist ? gearlist : ""),
|
||||
"autohiss_mode" = autohiss_mode,
|
||||
"h_grad_style" = h_grad_style,
|
||||
"h_grad_offset" = "[h_grad_offset_x],[h_grad_offset_y]",
|
||||
"h_grad_colour" = h_grad_colour,
|
||||
"h_grad_alpha" = h_grad_alpha,
|
||||
"ckey" = C.ckey,
|
||||
"slot" = slot_number
|
||||
))
|
||||
@@ -274,7 +289,8 @@
|
||||
gen_record,
|
||||
player_alt_titles,
|
||||
disabilities, organ_data, rlimb_data, nanotrasen_relation, speciesprefs,
|
||||
socks, body_accessory, gear, autohiss)
|
||||
socks, body_accessory, gear, autohiss,
|
||||
hair_gradient, hair_gradient_offset, hair_gradient_colour, hair_gradient_alpha)
|
||||
VALUES
|
||||
(:ckey, :slot, :metadata, :name, :be_random_name, :gender,
|
||||
:age, :species, :language,
|
||||
@@ -301,7 +317,8 @@
|
||||
:gen_record,
|
||||
:playertitlelist,
|
||||
:disabilities, :organlist, :rlimblist, :nanotrasen_relation, :speciesprefs,
|
||||
:socks, :body_accessory, :gearlist, :autohiss_mode)
|
||||
:socks, :body_accessory, :gearlist, :autohiss_mode,
|
||||
:h_grad_style, :h_grad_offset, :h_grad_colour, :h_grad_alpha)
|
||||
"}, list(
|
||||
// This has too many params for anyone to look at this without going insae
|
||||
"ckey" = C.ckey,
|
||||
@@ -357,7 +374,11 @@
|
||||
"socks" = socks,
|
||||
"body_accessory" = (body_accessory ? body_accessory : ""),
|
||||
"gearlist" = (gearlist ? gearlist : ""),
|
||||
"autohiss_mode" = autohiss_mode
|
||||
"autohiss_mode" = autohiss_mode,
|
||||
"h_grad_style" = h_grad_style,
|
||||
"h_grad_offset" = "[h_grad_offset_x],[h_grad_offset_y]",
|
||||
"h_grad_colour" = h_grad_colour,
|
||||
"h_grad_alpha" = h_grad_alpha
|
||||
))
|
||||
|
||||
if(!query.warn_execute())
|
||||
@@ -441,6 +462,11 @@
|
||||
loadout_gear = query.item[51]
|
||||
autohiss_mode = text2num(query.item[52])
|
||||
|
||||
h_grad_style = query.item[54]
|
||||
h_grad_offset_x = query.item[55] // parsed down below
|
||||
h_grad_colour = query.item[56]
|
||||
h_grad_alpha = query.item[57]
|
||||
|
||||
//Sanitize
|
||||
var/datum/species/SP = GLOB.all_species[species]
|
||||
metadata = sanitize_text(metadata, initial(metadata))
|
||||
@@ -507,6 +533,13 @@
|
||||
|
||||
socks = sanitize_text(socks, initial(socks))
|
||||
body_accessory = sanitize_text(body_accessory, initial(body_accessory))
|
||||
h_grad_style = sanitize_text(length(h_grad_style) ? h_grad_style : null, "None")
|
||||
var/list/expl = splittext(h_grad_offset_x, ",")
|
||||
if(length(expl) == 2)
|
||||
h_grad_offset_x = text2num(expl[1]) || 0
|
||||
h_grad_offset_y = text2num(expl[2]) || 0
|
||||
h_grad_colour = sanitize_hexcolor(h_grad_colour)
|
||||
h_grad_alpha = sanitize_integer(h_grad_alpha, 0, 255, initial(h_grad_alpha))
|
||||
loadout_gear = sanitize_json(loadout_gear)
|
||||
|
||||
if(!player_alt_titles)
|
||||
@@ -874,6 +907,18 @@
|
||||
else if(hair_style.do_colouration)
|
||||
hair_s.Blend(h_colour, ICON_ADD)
|
||||
|
||||
var/datum/sprite_accessory/hair_gradient/gradient = GLOB.hair_gradients_list[h_grad_style]
|
||||
if(gradient)
|
||||
var/icon/grad_s = new/icon("icon" = gradient.icon, "icon_state" = gradient.icon_state)
|
||||
if(h_grad_offset_x)
|
||||
grad_s.Shift(EAST, h_grad_offset_x)
|
||||
if(h_grad_offset_y)
|
||||
grad_s.Shift(NORTH, h_grad_offset_y)
|
||||
grad_s.Blend(hair_s, ICON_ADD)
|
||||
grad_s.MapColors(COLOR_BLACK, COLOR_BLACK, COLOR_BLACK, h_grad_colour)
|
||||
grad_s.ChangeOpacity(h_grad_alpha / 255)
|
||||
hair_s.Blend(grad_s, ICON_OVERLAY)
|
||||
|
||||
if(hair_style.secondary_theme)
|
||||
var/icon/hair_secondary_s = new/icon("icon" = hair_style.icon, "icon_state" = "[hair_style.icon_state]_[hair_style.secondary_theme]_s")
|
||||
if(!hair_style.no_sec_colour && hair_style.do_colouration )
|
||||
@@ -1781,6 +1826,12 @@
|
||||
H.f_style = f_style
|
||||
|
||||
H.alt_head = alt_head
|
||||
|
||||
H.h_grad_style = h_grad_style
|
||||
H.h_grad_offset_x = h_grad_offset_x
|
||||
H.h_grad_offset_y = h_grad_offset_y
|
||||
H.h_grad_colour = h_grad_colour
|
||||
H.h_grad_alpha = h_grad_alpha
|
||||
//End of head-specific.
|
||||
|
||||
character.skin_colour = s_colour
|
||||
|
||||
@@ -372,6 +372,29 @@
|
||||
var/new_h_style = input(user, "Choose your character's hair style:", "Character Preference") as null|anything in valid_hairstyles
|
||||
if(new_h_style)
|
||||
active_character.h_style = new_h_style
|
||||
|
||||
if("h_grad_style")
|
||||
var/result = input(user, "Choose your character's hair gradient style:", "Character Preference") as null|anything in GLOB.hair_gradients_list
|
||||
if(result)
|
||||
active_character.h_grad_style = result
|
||||
|
||||
if("h_grad_offset")
|
||||
var/result = input(user, "Enter your character's hair gradient offset as a comma-separated value (x,y). Example:\n0,0 (no offset)\n5,0 (5 pixels to the right)", "Character Preference") as null|text
|
||||
if(result)
|
||||
var/list/expl = splittext(result, ",")
|
||||
if(length(expl) == 2)
|
||||
active_character.h_grad_offset_x = clamp(text2num(expl[1]) || 0, -16, 16)
|
||||
active_character.h_grad_offset_y = clamp(text2num(expl[2]) || 0, -16, 16)
|
||||
|
||||
if("h_grad_colour")
|
||||
var/result = input(user, "Choose your character's hair gradient colour:", "Character Preference", active_character.h_grad_colour) as color|null
|
||||
if(result)
|
||||
active_character.h_grad_colour = result
|
||||
|
||||
if("h_grad_alpha")
|
||||
var/result = input(user, "Choose your character's hair gradient alpha (0-255):", "Character Preference", active_character.h_grad_alpha) as num|null
|
||||
if(!isnull(result))
|
||||
active_character.h_grad_alpha = clamp(result, 0, 255)
|
||||
|
||||
if("headaccessory")
|
||||
if(S.bodyflags & HAS_HEAD_ACCESSORY) //Species with head accessories.
|
||||
|
||||
@@ -233,6 +233,14 @@ GLOBAL_LIST_INIT(special_role_times, list( //minimum age (in days) for accounts
|
||||
var/datum/sprite_accessory/temp_hair_style = GLOB.hair_styles_public_list[active_character.h_style]
|
||||
if(temp_hair_style && temp_hair_style.secondary_theme && !temp_hair_style.no_sec_colour)
|
||||
dat += " <a href='?_src_=prefs;preference=secondary_hair;task=input'>Color #2</a> [color_square(active_character.h_sec_colour)]"
|
||||
// Hair gradient
|
||||
dat += "<br>"
|
||||
dat += "- <b>Gradient:</b>"
|
||||
dat += " <a href='?_src_=prefs;preference=h_grad_style;task=input'>[active_character.h_grad_style]</a>"
|
||||
dat += " <a href='?_src_=prefs;preference=h_grad_colour;task=input'>Color</a> [color_square(active_character.h_grad_colour)]"
|
||||
dat += " <a href='?_src_=prefs;preference=h_grad_alpha;task=input'>[active_character.h_grad_alpha]</a>"
|
||||
dat += "<br>"
|
||||
dat += "- <b>Gradient Offset:</b> <a href='?_src_=prefs;preference=h_grad_offset;task=input'>[active_character.h_grad_offset_x],[active_character.h_grad_offset_y]</a>"
|
||||
dat += "<br>"
|
||||
|
||||
dat += "<b>Facial Hair:</b> "
|
||||
|
||||
@@ -98,7 +98,6 @@
|
||||
qdel(query)
|
||||
return 1
|
||||
|
||||
|
||||
/datum/preferences/proc/load_random_character_slot(client/C)
|
||||
var/list/datum/character_save/valid_slots = list()
|
||||
for(var/datum/character_save/CS in character_saves)
|
||||
|
||||
@@ -153,6 +153,12 @@
|
||||
else
|
||||
//this shouldn't happen
|
||||
H.h_style = "Bald"
|
||||
// Gradient
|
||||
H.h_grad_style = "None"
|
||||
H.h_grad_offset_x = 0
|
||||
H.h_grad_offset_y = 0
|
||||
H.h_grad_colour = "#000000"
|
||||
H.h_grad_alpha = 255
|
||||
|
||||
update_hair()
|
||||
|
||||
@@ -310,6 +316,25 @@
|
||||
update_body()
|
||||
return 1
|
||||
|
||||
/mob/living/carbon/human/proc/change_hair_gradient(style, offset_raw, color, alpha)
|
||||
var/obj/item/organ/external/head/H = get_organ("head")
|
||||
if(!H)
|
||||
return
|
||||
|
||||
if(!isnull(style))
|
||||
H.h_grad_style = style
|
||||
if(!isnull(offset_raw))
|
||||
var/list/expl = splittext(offset_raw, ",")
|
||||
if(length(expl) == 2)
|
||||
H.h_grad_offset_x = clamp(text2num(expl[1]) || 0, -16, 16)
|
||||
H.h_grad_offset_y = clamp(text2num(expl[2]) || 0, -16, 16)
|
||||
if(!isnull(color))
|
||||
H.h_grad_colour = color
|
||||
if(!isnull(alpha))
|
||||
H.h_grad_alpha = clamp(alpha, 0, 255)
|
||||
|
||||
update_hair()
|
||||
|
||||
/mob/living/carbon/human/proc/update_dna()
|
||||
check_dna()
|
||||
dna.ready_dna(src)
|
||||
|
||||
@@ -354,49 +354,54 @@ GLOBAL_LIST_EMPTY(damage_icon_parts)
|
||||
else
|
||||
//warning("Invalid ha_style for [species.name]: [ha_style]")
|
||||
|
||||
|
||||
|
||||
//HAIR OVERLAY
|
||||
/**
|
||||
* Generates overlays for the hair layer.
|
||||
*/
|
||||
/mob/living/carbon/human/proc/update_hair()
|
||||
//Reset our hair
|
||||
remove_overlay(HAIR_LAYER)
|
||||
|
||||
var/obj/item/organ/external/head/head_organ = get_organ("head")
|
||||
if(!head_organ)
|
||||
var/obj/item/organ/external/head/O = get_organ("head")
|
||||
if(!O)
|
||||
return
|
||||
|
||||
//masks and helmets can obscure our hair, unless we're a synthetic
|
||||
if((head && (head.flags & BLOCKHAIR)) || (wear_mask && (wear_mask.flags & BLOCKHAIR)))
|
||||
if((head?.flags & BLOCKHAIR) || (wear_mask?.flags & BLOCKHAIR))
|
||||
return
|
||||
|
||||
//base icons
|
||||
var/icon/hair_standing = new /icon('icons/mob/human_face.dmi',"bald_s")
|
||||
if(head_organ.h_style && !(head && (head.flags & BLOCKHEADHAIR) && !(ismachineperson(src))))
|
||||
var/datum/sprite_accessory/hair/hair_style = GLOB.hair_styles_full_list[head_organ.h_style]
|
||||
if(hair_style && hair_style.species_allowed)
|
||||
if((head_organ.dna.species.name in hair_style.species_allowed) || (head_organ.dna.species.bodyflags & ALL_RPARTS)) //If the head's species is in the list of allowed species for the hairstyle, or the head's species is one flagged to have bodies comprised wholly of cybernetics...
|
||||
var/icon/hair_s = new/icon("icon" = hair_style.icon, "icon_state" = "[hair_style.icon_state]_s")
|
||||
if(istype(head_organ.dna.species, /datum/species/slime)) // I am el worstos
|
||||
hair_s.Blend("[skin_colour]A0", ICON_AND)
|
||||
else if(hair_style.do_colouration)
|
||||
hair_s.Blend(head_organ.hair_colour, ICON_ADD)
|
||||
var/mutable_appearance/MA = new()
|
||||
MA.appearance_flags = KEEP_TOGETHER
|
||||
MA.layer = -HAIR_LAYER
|
||||
if(O.h_style && !(head?.flags & BLOCKHEADHAIR) && !ismachineperson(src))
|
||||
var/datum/sprite_accessory/hair/hair = GLOB.hair_styles_full_list[O.h_style]
|
||||
if(hair?.species_allowed && ((O.dna.species.name in hair.species_allowed) || (O.dna.species.bodyflags & ALL_RPARTS)))
|
||||
// Base hair
|
||||
var/mutable_appearance/img_hair = mutable_appearance(hair.icon, "[hair.icon_state]_s")
|
||||
if(istype(O.dna.species, /datum/species/slime))
|
||||
img_hair.color = COLOR_MATRIX_OVERLAY("[skin_colour]A0")
|
||||
else if(hair.do_colouration)
|
||||
img_hair.color = COLOR_MATRIX_ADD(O.hair_colour)
|
||||
MA.overlays += img_hair
|
||||
|
||||
if(hair_style.secondary_theme)
|
||||
var/icon/hair_secondary_s = new/icon("icon" = hair_style.icon, "icon_state" = "[hair_style.icon_state]_[hair_style.secondary_theme]_s")
|
||||
if(!hair_style.no_sec_colour)
|
||||
hair_secondary_s.Blend(head_organ.sec_hair_colour, ICON_ADD)
|
||||
hair_s.Blend(hair_secondary_s, ICON_OVERLAY)
|
||||
// Gradient
|
||||
var/datum/sprite_accessory/hair_gradient/gradient = GLOB.hair_gradients_list[O.h_grad_style]
|
||||
if(gradient)
|
||||
var/mutable_appearance/img_gradient = mutable_appearance(gradient.icon, gradient.icon_state)
|
||||
img_gradient.alpha = O.h_grad_alpha
|
||||
img_gradient.color = COLOR_MATRIX_OVERLAY(O.h_grad_colour)
|
||||
img_gradient.pixel_x = O.h_grad_offset_x
|
||||
img_gradient.pixel_y = O.h_grad_offset_y
|
||||
img_gradient.blend_mode = BLEND_INSET_OVERLAY
|
||||
MA.overlays += img_gradient
|
||||
|
||||
hair_standing = hair_s //hair_standing.Blend(hair_s, ICON_OVERLAY)
|
||||
//Having it this way preserves animations. Useful for IPC screens.
|
||||
else
|
||||
//warning("Invalid h_style for [species.name]: [h_style]")
|
||||
//hair_standing.Blend(debrained_s, ICON_OVERLAY)//how does i overlay for fish?
|
||||
// Secondary style
|
||||
if(hair.secondary_theme)
|
||||
var/mutable_appearance/img_secondary = mutable_appearance(hair.icon, "[hair.icon_state]_[hair.secondary_theme]_s")
|
||||
if(!hair.no_sec_colour)
|
||||
img_secondary.color = COLOR_MATRIX_ADD(O.sec_hair_colour)
|
||||
MA.overlays += img_secondary
|
||||
|
||||
overlays_standing[HAIR_LAYER] = mutable_appearance(hair_standing, layer = -HAIR_LAYER)
|
||||
overlays_standing[HAIR_LAYER] = MA
|
||||
apply_overlay(HAIR_LAYER)
|
||||
|
||||
|
||||
//FACIAL HAIR OVERLAY
|
||||
/mob/living/carbon/human/proc/update_fhair()
|
||||
//Reset our facial hair
|
||||
|
||||
@@ -648,3 +648,48 @@
|
||||
/datum/sprite_accessory/socks/stockings_blue
|
||||
name = "Stockings (Blue)"
|
||||
icon_state = "stockings_blue"
|
||||
|
||||
/* HAIR GRADIENT */
|
||||
|
||||
/datum/sprite_accessory/hair_gradient
|
||||
icon = 'icons/mob/hair_gradients.dmi'
|
||||
|
||||
/datum/sprite_accessory/hair_gradient/none
|
||||
name = "None"
|
||||
icon_state = "none"
|
||||
|
||||
/datum/sprite_accessory/hair_gradient/fadeup
|
||||
name = "Fade Up"
|
||||
icon_state = "fadeup"
|
||||
|
||||
/datum/sprite_accessory/hair_gradient/fadedown
|
||||
name = "Fade Down"
|
||||
icon_state = "fadedown"
|
||||
|
||||
/datum/sprite_accessory/hair_gradient/vertical_split
|
||||
name = "Vertical Split"
|
||||
icon_state = "vsplit"
|
||||
|
||||
/datum/sprite_accessory/hair_gradient/_split
|
||||
name = "Horizontal Split"
|
||||
icon_state = "bottomflat"
|
||||
|
||||
/datum/sprite_accessory/hair_gradient/reflected
|
||||
name = "Reflected"
|
||||
icon_state = "reflected_high"
|
||||
|
||||
/datum/sprite_accessory/hair_gradient/reflected_inverse
|
||||
name = "Reflected Inverse"
|
||||
icon_state = "reflected_inverse_high"
|
||||
|
||||
/datum/sprite_accessory/hair_gradient/wavy
|
||||
name = "Wavy"
|
||||
icon_state = "wavy"
|
||||
|
||||
/datum/sprite_accessory/hair_gradient/long_fade_up
|
||||
name = "Long Fade Up"
|
||||
icon_state = "long_fade_up"
|
||||
|
||||
/datum/sprite_accessory/hair_gradient/long_fade_down
|
||||
name = "Long Fade Down"
|
||||
icon_state = "long_fade_down"
|
||||
|
||||
@@ -213,6 +213,11 @@
|
||||
var/hair_colour = "#000000"
|
||||
var/sec_hair_colour = "#000000"
|
||||
var/h_style = "Bald"
|
||||
var/h_grad_style = "None"
|
||||
var/h_grad_offset_x = 0
|
||||
var/h_grad_offset_y = 0
|
||||
var/h_grad_colour = "#000000"
|
||||
var/h_grad_alpha = 255
|
||||
|
||||
//Head accessory colour and style
|
||||
var/headacc_colour = "#000000"
|
||||
|
||||
@@ -93,6 +93,30 @@
|
||||
if(new_hair && (!..()) && owner.change_hair_color(new_hair, 1))
|
||||
update_dna()
|
||||
|
||||
if("hair_gradient")
|
||||
if(can_change(APPEARANCE_HAIR) && length(valid_hairstyles))
|
||||
var/new_style = input("Please select gradient style.", "Hair Gradient", head_organ.h_grad_style) as null|anything in GLOB.hair_gradients_list
|
||||
if(new_style)
|
||||
owner.change_hair_gradient(style = new_style)
|
||||
|
||||
if("hair_gradient_offset")
|
||||
if(can_change(APPEARANCE_HAIR) && length(valid_hairstyles))
|
||||
var/new_offset = input("Please enter gradient offset as a comma-separated value (x,y). Example:\n0,0 (no offset)\n5,0 (5 pixels to the right)", "Hair Gradient", "[head_organ.h_grad_offset_x],[head_organ.h_grad_offset_y]") as null|text
|
||||
if(new_offset)
|
||||
owner.change_hair_gradient(offset_raw = new_offset)
|
||||
|
||||
if("hair_gradient_colour")
|
||||
if(can_change(APPEARANCE_HAIR) && length(valid_hairstyles))
|
||||
var/new_color = input("Please select gradient color.", "Hair Gradient", head_organ.h_grad_colour) as null|color
|
||||
if(new_color)
|
||||
owner.change_hair_gradient(color = new_color)
|
||||
|
||||
if("hair_gradient_alpha")
|
||||
if(can_change(APPEARANCE_HAIR) && length(valid_hairstyles))
|
||||
var/new_alpha = input("Please enter gradient alpha (0-255).", "Hair Gradient", head_organ.h_grad_alpha) as null|num
|
||||
if(!isnull(new_alpha))
|
||||
owner.change_hair_gradient(alpha = new_alpha)
|
||||
|
||||
if("facial_hair")
|
||||
if(can_change(APPEARANCE_FACIAL_HAIR) && (params["facial_hair"] in valid_facial_hairstyles))
|
||||
if(owner.change_facial_hair(params["facial_hair"]))
|
||||
@@ -274,6 +298,7 @@
|
||||
data["change_head_marking_color"] = can_change_markings("head")
|
||||
data["change_body_marking_color"] = can_change_markings("body")
|
||||
data["change_tail_marking_color"] = can_change_markings("tail")
|
||||
data["change_hair_gradient"] = can_change(APPEARANCE_HAIR) && length(valid_hairstyles)
|
||||
|
||||
return data
|
||||
|
||||
|
||||
Reference in New Issue
Block a user