mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-01-06 06:52:39 +00:00
## About The Pull Request Added two new "layers" to hairstyles. The first draws on the normal hair layer but resists being affected by hair masks unless a piece of clothing really insists that it must mask it. The second draws on top of the headwear layer and will ignore all hair masking, but will disappear entirely if a piece of clothing covers the part of the head that hairpiece originates from. Each of these "Layers" (called "hair appendages" in the code) is associated with a part of the head that it comes off of (left side, rear, right side, etc.), which pieces of clothing can cover to prevent those parts from being shown. For example, a Beret will allow a ponytail to sprout off the back of a person's head and ignore the normal hair mask, but a winter coat hood covers every part of the head except the front, so it will hide the ponytail completely. ## Costs Hairstyles that use this system require some extra icon blending, but each hairstyle will cache the result of each blend whenever a new hair mask is applied, so the extra cost only happens once. The cache will also be used on hairstyles that don't utilize the additional layers, so we should end up with less total icon blending over the course of a round than we currently have. Adds a new sprite layer, OUTER_HAIR_LAYER, to humans. Changes hair masks from strings specifying an icon state to datums with an icon state and a bitfield storing which parts of the head the headware that uses them cover. The singletons for these datums are stored in the SSaccessories subsystem. Any hairstyle that uses this system will need 1-2 more icon states in the human_face.dmi file. I currently have 32 hairstyles marked that could reasonably use this system, about half of which use both additional icon states. ## Images Old system:  New system:   The new system is currently only implemented on the "Ponytail (High)" hairstyle for demonstration and testing. I have a branch with the same update for most similar hairstyles I can push if this is merged. ## Why It's Good For The Game Hair masks are okay but they look really bad with some hairstyles. This allows people who really care about their character's look to make their hairstyles work with their favorite hats. Potential for fixing #88886 ## Changelog 🆑 add: Added a system to create hairstyles with multiple layers to allow better interaction with hats and helmets image: Added additional sprite layers to the Ponytail (High) hairstyle /🆑 --------- Co-authored-by: SmArtKar <44720187+SmArtKar@users.noreply.github.com>
166 lines
8.5 KiB
Plaintext
166 lines
8.5 KiB
Plaintext
/// The non gender specific list that we get from init_sprite_accessory_subtypes()
|
|
#define DEFAULT_SPRITE_LIST "default_sprites"
|
|
/// The male specific list that we get from init_sprite_accessory_subtypes()
|
|
#define MALE_SPRITE_LIST "male_sprites"
|
|
/// The female specific list that we get from init_sprite_accessory_subtypes()
|
|
#define FEMALE_SPRITE_LIST "female_sprites"
|
|
|
|
/// subsystem that just holds lists of sprite accessories for accession in generating said sprites.
|
|
/// A sprite accessory is something that we add to a human sprite to make them look different. This is hair, facial hair, underwear, mutant bits, etc.
|
|
SUBSYSTEM_DEF(accessories) // just 'accessories' for brevity
|
|
name = "Sprite Accessories"
|
|
flags = SS_NO_FIRE | SS_NO_INIT
|
|
|
|
//Hairstyles
|
|
var/list/hairstyles_list //! stores /datum/sprite_accessory/hair indexed by name
|
|
var/list/hairstyles_male_list //! stores only hair names
|
|
var/list/hairstyles_female_list //! stores only hair names
|
|
var/list/facial_hairstyles_list //! stores /datum/sprite_accessory/facial_hair indexed by name
|
|
var/list/facial_hairstyles_male_list //! stores only hair names
|
|
var/list/facial_hairstyles_female_list //! stores only hair names
|
|
var/list/hair_gradients_list //! stores /datum/sprite_accessory/hair_gradient indexed by name
|
|
var/list/facial_hair_gradients_list //! stores /datum/sprite_accessory/facial_hair_gradient indexed by name
|
|
var/list/hair_masks_list //! stores /datum/hair_mask indexed by type
|
|
|
|
//Underwear
|
|
var/list/underwear_list //! stores /datum/sprite_accessory/underwear indexed by name
|
|
var/list/underwear_m //! stores only underwear name
|
|
var/list/underwear_f //! stores only underwear name
|
|
|
|
//Undershirts
|
|
var/list/undershirt_list //! stores /datum/sprite_accessory/undershirt indexed by name
|
|
var/list/undershirt_m //! stores only undershirt name
|
|
var/list/undershirt_f //! stores only undershirt name
|
|
|
|
//Socks
|
|
var/list/socks_list //! stores /datum/sprite_accessory/socks indexed by name
|
|
|
|
//Lizard Bits (all datum lists indexed by name)
|
|
var/list/lizard_markings_list
|
|
var/list/snouts_list
|
|
var/list/horns_list
|
|
var/list/frills_list
|
|
var/list/spines_list
|
|
var/list/tail_spines_list
|
|
|
|
//Mutant Human bits
|
|
var/list/tails_list_felinid
|
|
var/list/tails_list_lizard
|
|
var/list/tails_list_monkey
|
|
var/list/tails_list_xeno
|
|
var/list/tails_list_fish
|
|
var/list/ears_list
|
|
var/list/wings_list
|
|
var/list/wings_open_list
|
|
var/list/moth_wings_list
|
|
var/list/moth_antennae_list
|
|
var/list/moth_markings_list
|
|
var/list/caps_list
|
|
var/list/pod_hair_list
|
|
|
|
/datum/controller/subsystem/accessories/PreInit() // this stuff NEEDS to be set up before GLOB for preferences and stuff to work so this must go here. sorry
|
|
setup_lists()
|
|
init_hair_gradients()
|
|
init_hair_masks()
|
|
|
|
/// Sets up all of the lists for later utilization in the round and building sprites.
|
|
/// In an ideal world we could tack everything that just needed `DEFAULT_SPRITE_LIST` into static variables on the top, but due to the initialization order
|
|
/// where this subsystem will initialize BEFORE statics, it's just not feasible since this all needs to be ready for actual subsystems to use.
|
|
/// Sorry.
|
|
/datum/controller/subsystem/accessories/proc/setup_lists()
|
|
var/hair_lists = init_sprite_accessory_subtypes(/datum/sprite_accessory/hair)
|
|
hairstyles_list = hair_lists[DEFAULT_SPRITE_LIST]
|
|
hairstyles_male_list = hair_lists[MALE_SPRITE_LIST]
|
|
hairstyles_female_list = hair_lists[FEMALE_SPRITE_LIST]
|
|
|
|
var/facial_hair_lists = init_sprite_accessory_subtypes(/datum/sprite_accessory/facial_hair)
|
|
facial_hairstyles_list = facial_hair_lists[DEFAULT_SPRITE_LIST]
|
|
facial_hairstyles_male_list = facial_hair_lists[MALE_SPRITE_LIST]
|
|
facial_hairstyles_female_list = facial_hair_lists[FEMALE_SPRITE_LIST]
|
|
|
|
var/underwear_lists = init_sprite_accessory_subtypes(/datum/sprite_accessory/underwear)
|
|
underwear_list = underwear_lists[DEFAULT_SPRITE_LIST]
|
|
underwear_m = underwear_lists[MALE_SPRITE_LIST]
|
|
underwear_f = underwear_lists[FEMALE_SPRITE_LIST]
|
|
|
|
var/undershirt_lists = init_sprite_accessory_subtypes(/datum/sprite_accessory/undershirt)
|
|
undershirt_list = undershirt_lists[DEFAULT_SPRITE_LIST]
|
|
undershirt_m = undershirt_lists[MALE_SPRITE_LIST]
|
|
undershirt_f = undershirt_lists[FEMALE_SPRITE_LIST]
|
|
|
|
socks_list = init_sprite_accessory_subtypes(/datum/sprite_accessory/socks)[DEFAULT_SPRITE_LIST]
|
|
|
|
lizard_markings_list = init_sprite_accessory_subtypes(/datum/sprite_accessory/lizard_markings, add_blank = TRUE)[DEFAULT_SPRITE_LIST]
|
|
tails_list_felinid = init_sprite_accessory_subtypes(/datum/sprite_accessory/tails/felinid, add_blank = TRUE)[DEFAULT_SPRITE_LIST]
|
|
tails_list_lizard = init_sprite_accessory_subtypes(/datum/sprite_accessory/tails/lizard)[DEFAULT_SPRITE_LIST]
|
|
tails_list_monkey = init_sprite_accessory_subtypes(/datum/sprite_accessory/tails/monkey)[DEFAULT_SPRITE_LIST]
|
|
tails_list_xeno = init_sprite_accessory_subtypes(/datum/sprite_accessory/tails/xeno)[DEFAULT_SPRITE_LIST]
|
|
//tails fo fish organ infusions, not for prefs.
|
|
tails_list_fish = init_sprite_accessory_subtypes(/datum/sprite_accessory/tails/fish)[DEFAULT_SPRITE_LIST]
|
|
snouts_list = init_sprite_accessory_subtypes(/datum/sprite_accessory/snouts)[DEFAULT_SPRITE_LIST]
|
|
horns_list = init_sprite_accessory_subtypes(/datum/sprite_accessory/horns, add_blank = TRUE)[DEFAULT_SPRITE_LIST]
|
|
ears_list = init_sprite_accessory_subtypes(/datum/sprite_accessory/ears, add_blank = TRUE)[DEFAULT_SPRITE_LIST]
|
|
wings_list = init_sprite_accessory_subtypes(/datum/sprite_accessory/wings, add_blank = TRUE)[DEFAULT_SPRITE_LIST]
|
|
wings_open_list = init_sprite_accessory_subtypes(/datum/sprite_accessory/wings_open)[DEFAULT_SPRITE_LIST]
|
|
frills_list = init_sprite_accessory_subtypes(/datum/sprite_accessory/frills, add_blank = TRUE)[DEFAULT_SPRITE_LIST]
|
|
spines_list = init_sprite_accessory_subtypes(/datum/sprite_accessory/spines, add_blank = TRUE)[DEFAULT_SPRITE_LIST]
|
|
tail_spines_list = init_sprite_accessory_subtypes(/datum/sprite_accessory/tail_spines, add_blank = TRUE)[DEFAULT_SPRITE_LIST]
|
|
caps_list = init_sprite_accessory_subtypes(/datum/sprite_accessory/caps)[DEFAULT_SPRITE_LIST]
|
|
moth_wings_list = init_sprite_accessory_subtypes(/datum/sprite_accessory/moth_wings)[DEFAULT_SPRITE_LIST]
|
|
moth_antennae_list = init_sprite_accessory_subtypes(/datum/sprite_accessory/moth_antennae)[DEFAULT_SPRITE_LIST]
|
|
moth_markings_list = init_sprite_accessory_subtypes(/datum/sprite_accessory/moth_markings, add_blank = TRUE)[DEFAULT_SPRITE_LIST]
|
|
pod_hair_list = init_sprite_accessory_subtypes(/datum/sprite_accessory/pod_hair)[DEFAULT_SPRITE_LIST]
|
|
|
|
/// This proc just initializes all /datum/sprite_accessory/hair_gradient into an list indexed by gradient-style name
|
|
/datum/controller/subsystem/accessories/proc/init_hair_gradients()
|
|
hair_gradients_list = list()
|
|
facial_hair_gradients_list = list()
|
|
for(var/path in subtypesof(/datum/sprite_accessory/gradient))
|
|
var/datum/sprite_accessory/gradient/gradient = new path
|
|
if(gradient.gradient_category & GRADIENT_APPLIES_TO_HAIR)
|
|
hair_gradients_list[gradient.name] = gradient
|
|
if(gradient.gradient_category & GRADIENT_APPLIES_TO_FACIAL_HAIR)
|
|
facial_hair_gradients_list[gradient.name] = gradient
|
|
|
|
/datum/controller/subsystem/accessories/proc/init_hair_masks()
|
|
hair_masks_list = list()
|
|
for(var/path in subtypesof(/datum/hair_mask))
|
|
var/datum/hair_mask/mask = new path
|
|
hair_masks_list[path] = mask
|
|
|
|
/// This reads the applicable sprite accessory datum's subtypes and adds it to the subsystem's list of sprite accessories.
|
|
/// The boolean `add_blank` argument just adds a "None" option to the list of sprite accessories, like if a felinid doesn't want a tail or something, typically good for gated-off things.
|
|
/datum/controller/subsystem/accessories/proc/init_sprite_accessory_subtypes(prototype, add_blank = FALSE)
|
|
RETURN_TYPE(/list)
|
|
var/returnable_list = list(
|
|
DEFAULT_SPRITE_LIST = list(),
|
|
MALE_SPRITE_LIST = list(),
|
|
FEMALE_SPRITE_LIST = list(),
|
|
)
|
|
|
|
for(var/path in subtypesof(prototype))
|
|
var/datum/sprite_accessory/accessory = new path
|
|
|
|
if(accessory.icon_state)
|
|
returnable_list[DEFAULT_SPRITE_LIST][accessory.name] = accessory
|
|
else
|
|
returnable_list[DEFAULT_SPRITE_LIST] += accessory.name
|
|
|
|
switch(accessory.gender)
|
|
if(MALE)
|
|
returnable_list[MALE_SPRITE_LIST] += accessory.name
|
|
if(FEMALE)
|
|
returnable_list[FEMALE_SPRITE_LIST] += accessory.name
|
|
else
|
|
returnable_list[MALE_SPRITE_LIST] += accessory.name
|
|
returnable_list[FEMALE_SPRITE_LIST] += accessory.name
|
|
|
|
if(add_blank)
|
|
returnable_list[DEFAULT_SPRITE_LIST][SPRITE_ACCESSORY_NONE] = new /datum/sprite_accessory/blank
|
|
|
|
return returnable_list
|
|
|
|
#undef DEFAULT_SPRITE_LIST
|
|
#undef MALE_SPRITE_LIST
|
|
#undef FEMALE_SPRITE_LIST
|