Merge pull request #15755 from timothyteakettle/dullahan-2-electric-boogaloo

dullahans 2: electric boogaloo
This commit is contained in:
Lin
2022-12-14 19:07:59 -07:00
committed by GitHub
33 changed files with 330 additions and 241 deletions

View File

@@ -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

View File

@@ -48,6 +48,7 @@
icon = 'modular_citadel/icons/mob/xeno_parts_greyscale.dmi'
mutant_part_string = "xhead"
relevant_layers = list(BODY_ADJ_LAYER)
mutable_category = "HEAD"
/datum/sprite_accessory/xeno_head/is_not_visible(var/mob/living/carbon/human/H, var/tauric)
var/obj/item/bodypart/head/HD = H.get_bodypart(BODY_ZONE_HEAD)

View File

@@ -49,6 +49,7 @@
relevant_layers = list(BODY_ADJ_LAYER, BODY_FRONT_LAYER)
mutant_part_string = "mandibles"
color_src = 0
mutable_category = "HEAD"
/datum/sprite_accessory/arachnid_mandibles/none
name = "None"

View File

@@ -2,6 +2,7 @@
icon = 'icons/mob/mutant_bodyparts.dmi'
color_src = HAIR
relevant_layers = list(BODY_ADJ_LAYER)
mutable_category = "HEAD"
/datum/sprite_accessory/caps/round
name = "Round"

View File

@@ -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)

View File

@@ -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

View File

@@ -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~

View File

@@ -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)

View File

@@ -6,6 +6,11 @@
icon = 'modular_citadel/icons/mob/ipc_screens.dmi'
color_src = null
relevant_layers = list(BODY_ADJ_LAYER)
mutable_category = "HEAD"
/datum/sprite_accessory/screen/is_not_visible(var/mob/living/carbon/human/H, var/tauric)
var/obj/item/bodypart/head/HD = H.get_bodypart(BODY_ZONE_HEAD)
return (HD == null) // it's not visible if head is null
/datum/sprite_accessory/screen/blank
name = "Blank"
@@ -133,6 +138,7 @@
relevant_layers = list(BODY_ADJ_LAYER)
recommended_species = list("ipc")
mutant_part_string = "ipc_antenna"
mutable_category = "HEAD"
/datum/sprite_accessory/antenna/none
name = "None"

View File

@@ -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)

View File

@@ -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'

View File

@@ -954,9 +954,6 @@
/mob/living/carbon/human/species/corporate
race = /datum/species/corporate
/mob/living/carbon/human/species/dullahan
race = /datum/species/dullahan
/mob/living/carbon/human/species/felinid
race = /datum/species/human/felinid

View File

@@ -345,11 +345,11 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
var/obj/item/organ/stomach/stomach = C.getorganslot(ORGAN_SLOT_STOMACH)
var/obj/item/organ/tail/tail = C.getorganslot(ORGAN_SLOT_TAIL)
var/should_have_brain = TRUE
var/should_have_brain = !(HAS_TRAIT(C, TRAIT_DULLAHAN)) // do not mess with a dullahans brain
var/should_have_heart = !(NOBLOOD in species_traits)
var/should_have_lungs = ((TRAIT_AUXILIARY_LUNGS in inherent_traits) || !(TRAIT_NOBREATH in inherent_traits))
var/should_have_appendix = !(TRAIT_NOHUNGER in inherent_traits)
var/should_have_eyes = TRUE
var/should_have_eyes = !(HAS_TRAIT(C, TRAIT_DULLAHAN)) // .. or their eyes
var/should_have_ears = TRUE
var/should_have_tongue = TRUE
var/should_have_liver = !(NOLIVER in species_traits)
@@ -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"
@@ -800,7 +803,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
H.apply_overlay(HAIR_LAYER)
/datum/species/proc/handle_body(mob/living/carbon/human/H)
/datum/species/proc/handle_body(mob/living/carbon/human/H, block_recursive_calls = FALSE)
H.remove_overlay(BODY_LAYER)
var/list/standing = list()
@@ -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)
@@ -821,7 +825,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
// eyes
if(!(NOEYES in species_traits))
var/has_eyes = H.getorganslot(ORGAN_SLOT_EYES)
var/has_eyes = H.getorganslot(ORGAN_SLOT_EYES) || HAS_TRAIT(H, TRAIT_DULLAHAN) // if they are a dullahan just assume eyes exist
if(!has_eyes)
standing += mutable_appearance('icons/mob/eyes.dmi', "eyes_missing", -BODY_LAYER)
else
@@ -832,6 +836,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]"
@@ -892,9 +898,9 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
H.overlays_standing[BODY_LAYER] = standing
H.apply_overlay(BODY_LAYER)
handle_mutant_bodyparts(H)
handle_mutant_bodyparts(H, null, block_recursive_calls)
/datum/species/proc/handle_mutant_bodyparts(mob/living/carbon/human/H, forced_colour)
/datum/species/proc/handle_mutant_bodyparts(mob/living/carbon/human/H, forced_colour, block_recursive_calls = FALSE)
var/list/bodyparts_to_add = mutant_bodyparts.Copy()
H.remove_overlay(BODY_BEHIND_LAYER)
@@ -1009,6 +1015,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 +1120,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 +1167,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
@@ -1206,6 +1215,11 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
H.apply_overlay(BODY_FRONT_LAYER)
H.apply_overlay(HORNS_LAYER)
if(!block_recursive_calls)
var/datum/component/dullahan/D = H.GetComponent(/datum/component/dullahan)
if(D && D.dullahan_head)
D.dullahan_head.update_appearance()
/*
* Equip the outfit required for life. Replaces items currently worn.
*/

View File

@@ -1,165 +0,0 @@
/datum/species/dullahan
name = "Dullahan"
id = SPECIES_DULLAHAN
default_color = "FFFFFF"
species_traits = list(EYECOLOR,HAIR,FACEHAIR,LIPS,HAS_FLESH,HAS_BONE)
inherent_traits = list(TRAIT_NOHUNGER,TRAIT_NOBREATH)
mutant_bodyparts = list("tail_human" = "None", "ears" = "None", "deco_wings" = "None")
use_skintones = USE_SKINTONES_GRAYSCALE_CUSTOM
mutant_brain = /obj/item/organ/brain/dullahan
mutanteyes = /obj/item/organ/eyes/dullahan
mutanttongue = /obj/item/organ/tongue/dullahan
mutantears = /obj/item/organ/ears/dullahan
blacklisted = TRUE
limbs_id = SPECIES_HUMAN
skinned_type = /obj/item/stack/sheet/animalhide/human
has_field_of_vision = FALSE //Too much of a trouble, their vision is already bound to their severed head.
species_category = SPECIES_CATEGORY_UNDEAD
var/pumpkin = FALSE
wings_icons = SPECIES_WINGS_SKELETAL //seems suitable for an undead.
var/obj/item/dullahan_relay/myhead
/datum/species/dullahan/pumpkin
name = "Pumpkin Head Dullahan"
id = "pumpkindullahan"
pumpkin = TRUE
/datum/species/dullahan/check_roundstart_eligible()
if(SSevents.holidays && SSevents.holidays[HALLOWEEN])
return TRUE
return ..()
/datum/species/dullahan/on_species_gain(mob/living/carbon/human/H, datum/species/old_species)
. = ..()
H.flags_1 &= ~(HEAR_1)
var/obj/item/bodypart/head/head = H.get_bodypart(BODY_ZONE_HEAD)
if(head)
if(pumpkin)//Pumpkinhead!
head.animal_origin = 100
head.icon = 'icons/obj/clothing/hats.dmi'
head.icon_state = "hardhat1_pumpkin_j"
head.custom_head = TRUE
head.drop_limb()
if(!QDELETED(head)) //drop_limb() deletes the limb if it's no drop location and dummy humans used for rendering icons are located in nullspace. Do the math.
head.throwforce = 25
myhead = new /obj/item/dullahan_relay (head, H)
H.put_in_hands(head)
var/obj/item/organ/eyes/E = H.getorganslot(ORGAN_SLOT_EYES)
for(var/datum/action/item_action/organ_action/OA in E.actions)
OA.Trigger()
/datum/species/dullahan/on_species_loss(mob/living/carbon/human/H)
H.flags_1 |= HEAR_1
H.reset_perspective(H)
if(myhead)
var/obj/item/dullahan_relay/DR = myhead
myhead = null
DR.owner = null
qdel(DR)
H.regenerate_limb(BODY_ZONE_HEAD,FALSE)
..()
/datum/species/dullahan/spec_life(mob/living/carbon/human/H)
if(QDELETED(myhead))
myhead = null
H.gib()
var/obj/item/bodypart/head/head2 = H.get_bodypart(BODY_ZONE_HEAD)
if(head2)
myhead = null
H.gib()
/datum/species/dullahan/proc/update_vision_perspective(mob/living/carbon/human/H)
var/obj/item/organ/eyes/eyes = H.getorganslot(ORGAN_SLOT_EYES)
if(eyes)
H.update_tint()
if(eyes.tint)
H.reset_perspective(H)
else
H.reset_perspective(myhead)
/obj/item/organ/brain/dullahan
decoy_override = TRUE
organ_flags = ORGAN_NO_SPOIL//Do not decay
/obj/item/organ/tongue/dullahan
zone = "abstract"
accents = list(/datum/accent/dullahan)
/obj/item/organ/ears/dullahan
zone = "abstract"
/obj/item/organ/eyes/dullahan
name = "head vision"
desc = "An abstraction."
actions_types = list(/datum/action/item_action/organ_action/dullahan)
zone = "abstract"
tint = INFINITY // used to switch the vision perspective to the head on species_gain().
/datum/action/item_action/organ_action/dullahan
name = "Toggle Perspective"
desc = "Switch between seeing normally from your head, or blindly from your body."
/datum/action/item_action/organ_action/dullahan/Trigger()
. = ..()
var/obj/item/organ/eyes/dullahan/DE = target
if(DE.tint)
DE.tint = 0
else
DE.tint = INFINITY
if(ishuman(owner))
var/mob/living/carbon/human/H = owner
if(isdullahan(H))
var/datum/species/dullahan/D = H.dna.species
D.update_vision_perspective(H)
/obj/item/dullahan_relay
name = "dullahan relay"
var/mob/living/owner
flags_1 = HEAR_1
/obj/item/dullahan_relay/Initialize(mapload, mob/living/carbon/human/new_owner)
. = ..()
if(!new_owner)
return INITIALIZE_HINT_QDEL
owner = new_owner
START_PROCESSING(SSobj, src)
RegisterSignal(owner, COMSIG_MOB_CLICKED_SHIFT_ON, .proc/examinate_check)
RegisterSignal(src, COMSIG_ATOM_HEARER_IN_VIEW, .proc/include_owner)
RegisterSignal(owner, COMSIG_LIVING_REGENERATE_LIMBS, .proc/unlist_head)
RegisterSignal(owner, COMSIG_LIVING_REVIVE, .proc/retrieve_head)
/obj/item/dullahan_relay/proc/examinate_check(mob/source, atom/target)
if(source.client.eye == src)
return COMPONENT_ALLOW_EXAMINATE
/obj/item/dullahan_relay/proc/include_owner(datum/source, list/processing_list, list/hearers)
if(!QDELETED(owner))
hearers += owner
/obj/item/dullahan_relay/proc/unlist_head(datum/source, noheal = FALSE, list/excluded_limbs)
excluded_limbs |= BODY_ZONE_HEAD // So we don't gib when regenerating limbs.
//Retrieving the owner's head for better ahealing.
/obj/item/dullahan_relay/proc/retrieve_head(datum/source, full_heal, admin_revive)
if(admin_revive)
var/obj/item/bodypart/head/H = loc
var/turf/T = get_turf(owner)
if(H && istype(H) && T && !(H in owner.GetAllContents()))
H.forceMove(T)
/obj/item/dullahan_relay/process()
if(!istype(loc, /obj/item/bodypart/head) || QDELETED(owner))
. = PROCESS_KILL
qdel(src)
/obj/item/dullahan_relay/Destroy()
if(!QDELETED(owner))
var/mob/living/carbon/human/H = owner
if(isdullahan(H))
var/datum/species/dullahan/D = H.dna.species
D.myhead = null
owner.gib()
owner = null
..()

View File

@@ -58,14 +58,14 @@ There are several things that need to be remembered:
dna.species.handle_hair(src)
//used when putting/removing clothes that hide certain mutant body parts to just update those and not update the whole body.
/mob/living/carbon/human/proc/update_mutant_bodyparts()
/mob/living/carbon/human/proc/update_mutant_bodyparts(block_recursive_calls = FALSE)
if(!HAS_TRAIT(src, TRAIT_HUMAN_NO_RENDER))
dna.species.handle_mutant_bodyparts(src)
dna.species.handle_mutant_bodyparts(src, null, block_recursive_calls)
/mob/living/carbon/human/update_body(update_genitals = FALSE)
/mob/living/carbon/human/update_body(update_genitals = FALSE, block_recursive_calls = FALSE)
if(!HAS_TRAIT(src, TRAIT_HUMAN_NO_RENDER))
remove_overlay(BODY_LAYER)
dna.species.handle_body(src)
dna.species.handle_body(src, block_recursive_calls)
..()
if(update_genitals)
update_genitals()
@@ -75,24 +75,24 @@ There are several things that need to be remembered:
/* --------------------------------------- */
//For legacy support.
/mob/living/carbon/human/regenerate_icons()
/mob/living/carbon/human/regenerate_icons(block_recursive_calls = FALSE)
if(!HAS_TRAIT(src, TRAIT_HUMAN_NO_RENDER))
if(!..())
icon_render_key = null //invalidate bodyparts cache
update_body(TRUE)
update_body(TRUE, block_recursive_calls)
update_hair()
update_inv_w_uniform()
update_inv_w_uniform(block_recursive_calls)
update_inv_wear_id()
update_inv_gloves()
update_inv_glasses()
update_inv_ears()
update_inv_shoes()
update_inv_s_store()
update_inv_wear_mask()
update_inv_head()
update_inv_wear_mask(block_recursive_calls)
update_inv_head(block_recursive_calls)
update_inv_belt()
update_inv_back()
update_inv_wear_suit()
update_inv_wear_suit(block_recursive_calls)
update_inv_pockets()
update_inv_neck()
update_transform()
@@ -123,7 +123,7 @@ There are several things that need to be remembered:
apply_overlay(ANTAG_LAYER)
/mob/living/carbon/human/update_inv_w_uniform()
/mob/living/carbon/human/update_inv_w_uniform(block_recursive_calls = FALSE)
if(!HAS_TRAIT(src, TRAIT_HUMAN_NO_RENDER))
remove_overlay(UNIFORM_LAYER)
@@ -173,7 +173,7 @@ There are several things that need to be remembered:
overlays_standing[UNIFORM_LAYER] = uniform_overlay
apply_overlay(UNIFORM_LAYER)
update_mutant_bodyparts()
update_mutant_bodyparts(block_recursive_calls)
/mob/living/carbon/human/update_inv_wear_id()
if(!HAS_TRAIT(src, TRAIT_HUMAN_NO_RENDER))
@@ -349,7 +349,7 @@ There are several things that need to be remembered:
overlays_standing[SUIT_STORE_LAYER] = s_store_overlay
apply_overlay(SUIT_STORE_LAYER)
/mob/living/carbon/human/update_inv_head()
/mob/living/carbon/human/update_inv_head(block_recursive_calls = FALSE)
if(!HAS_TRAIT(src, TRAIT_HUMAN_NO_RENDER))
remove_overlay(HEAD_LAYER)
@@ -387,7 +387,7 @@ There are several things that need to be remembered:
head_overlay.pixel_y += dna.species.offset_features[OFFSET_HEAD][2]
overlays_standing[HEAD_LAYER] = head_overlay
apply_overlay(HEAD_LAYER)
update_mutant_bodyparts()
update_mutant_bodyparts(block_recursive_calls)
/mob/living/carbon/human/update_inv_belt()
if(!HAS_TRAIT(src, TRAIT_HUMAN_NO_RENDER))
@@ -411,7 +411,7 @@ There are several things that need to be remembered:
overlays_standing[BELT_LAYER] = belt_overlay
apply_overlay(BELT_LAYER)
/mob/living/carbon/human/update_inv_wear_suit()
/mob/living/carbon/human/update_inv_wear_suit(block_recursive_calls = FALSE)
if(!HAS_TRAIT(src, TRAIT_HUMAN_NO_RENDER))
remove_overlay(SUIT_LAYER)
@@ -471,7 +471,7 @@ There are several things that need to be remembered:
suit_overlay = center_image(suit_overlay, dimension_x, dimension_y)
overlays_standing[SUIT_LAYER] = suit_overlay
update_hair()
update_mutant_bodyparts()
update_mutant_bodyparts(block_recursive_calls)
apply_overlay(SUIT_LAYER)
@@ -498,7 +498,7 @@ There are several things that need to be remembered:
update_observer_view(r_store)
/mob/living/carbon/human/update_inv_wear_mask()
/mob/living/carbon/human/update_inv_wear_mask(block_recursive_calls = FALSE)
if(!HAS_TRAIT(src, TRAIT_HUMAN_NO_RENDER))
remove_overlay(FACEMASK_LAYER)
@@ -537,7 +537,7 @@ There are several things that need to be remembered:
mask_overlay.pixel_y += dna.species.offset_features[OFFSET_FACEMASK][2]
overlays_standing[FACEMASK_LAYER] = mask_overlay
apply_overlay(FACEMASK_LAYER)
update_mutant_bodyparts() //e.g. upgate needed because mask now hides lizard snout
update_mutant_bodyparts(block_recursive_calls) //e.g. upgate needed because mask now hides lizard snout
/mob/living/carbon/human/update_inv_back()
if(!HAS_TRAIT(src, TRAIT_HUMAN_NO_RENDER))
@@ -791,7 +791,7 @@ 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 && !HAS_TRAIT(src, TRAIT_DULLAHAN))
add_overlay(mutable_appearance('icons/mob/eyes.dmi', "eyes_missing", -BODY_LAYER))
else
var/left_state = DEFAULT_LEFT_EYE_STATE
@@ -803,6 +803,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