Body accessory system

This commit adds a modular system for selectable body accessories. These
accessories are currently split into two primary groups,
"/body_accessory/body" and "/body_accessory/tail", for "body" sprites and
"tail" sprites respectively. (also known as a subtype just for vorestation
taur sprites)

Basically, this allows for selectable tails. This commit doesn't include
any subtypes, which will cause the startup hook to fail. The only subtypes
this actually includes is a snake 'body'.

Admins can select any tail, regardless of species restriction. Admin-only
subtypes are simply defined by not adding any species to the whitelist.
Note, as this system uses the body color system, admins may also use the
body colors at any time regardless of race.
This commit is contained in:
Tigercat2000
2015-09-05 17:20:28 -07:00
parent 789794e0e1
commit 3ee80a3586
9 changed files with 157 additions and 27 deletions
@@ -0,0 +1,79 @@
var/global/list/body_accessory_by_name = list("None" = null)
/hook/startup/proc/initalize_body_accessories()
//each accessory subtype needs it's own loop
for(var/type in subtypesof(/datum/body_accessory/body))
var/datum/body_accessory/ac1 = new type
if(istype(ac1))
body_accessory_by_name["[ac1.name]"] = ac1
for(var/type in subtypesof(/datum/body_accessory/tail))
var/datum/body_accessory/ac2 = new type
if(istype(ac2))
body_accessory_by_name["[ac2.name]"] = ac2
if(body_accessory_by_name.len)
if(initialize_body_accessory_by_species())
return 1
return 0 //fail if no bodies are found
var/global/list/body_accessory_by_species = list("None" = null)
/proc/initialize_body_accessory_by_species()
for(var/B in body_accessory_by_name)
var/datum/body_accessory/accessory = body_accessory_by_name[B]
if(!istype(accessory)) continue
for(var/A in accessory.allowed_species)
body_accessory_by_species[A] += accessory
if(body_accessory_by_species.len)
return 1
return 0
/datum/body_accessory
var/name = "default"
var/icon = null
var/icon_state = ""
var/animated_icon = null
var/animated_icon_state = ""
var/blend_mode = null
var/list/pixel_offsets = list("x" = 0, "y" = 0)
var/list/allowed_species = list()
/datum/body_accessory/proc/try_restrictions(var/mob/living/carbon/human/H)
return 1
/datum/body_accessory/proc/get_pixel_x(var/mob/living/carbon/human/H)
return pixel_offsets["x"]
/datum/body_accessory/proc/get_pixel_y(var/mob/living/carbon/human/H)
return pixel_offsets["y"]
//Bodies
/datum/body_accessory/body
blend_mode = ICON_MULTIPLY
/datum/body_accessory/body/snake
name = "Snake"
icon = 'icons/mob/body_accessory_64.dmi'
icon_state = "naga"
pixel_offsets = list("x" = -16, "y" = 0)
//Tails
/datum/body_accessory/tail
blend_mode = ICON_ADD
/datum/body_accessory/tail/try_restrictions(var/mob/living/carbon/human/H)
if(!H.wear_suit || !(H.wear_suit.flags_inv & HIDETAIL) && !istype(H.wear_suit, /obj/item/clothing/suit/space))
return 1
return 0
@@ -81,4 +81,6 @@
var/lastFart = 0 // Toxic fart cooldown.
var/fire_dmi = 'icons/mob/OnFire.dmi'
var/fire_sprite = "Standing"
var/fire_sprite = "Standing"
var/datum/body_accessory/body_accessory = null
@@ -337,7 +337,7 @@ var/global/list/damage_icon_parts = list()
stand_icon.Blend(lips, ICON_OVERLAY)
//tail
update_tail_showing(0)
update_tail_layer(0)
//HAIR OVERLAY
@@ -756,12 +756,12 @@ var/global/list/damage_icon_parts = list()
overlays_standing[SUIT_LAYER] = standing
update_tail_showing(0)
update_tail_layer(0)
else
overlays_standing[SUIT_LAYER] = null
update_tail_showing(0)
update_tail_layer(0)
update_collar(0)
@@ -896,10 +896,20 @@ var/global/list/damage_icon_parts = list()
overlays_standing[L_HAND_LAYER] = null
if(update_icons) update_icons()
/mob/living/carbon/human/proc/update_tail_showing(var/update_icons=1)
/mob/living/carbon/human/proc/update_tail_layer(var/update_icons=1)
overlays_standing[TAIL_LAYER] = null
if(species.tail && species.bodyflags & HAS_TAIL)
if(body_accessory)
if(body_accessory.try_restrictions(src))
var/icon/accessory_s = new/icon("icon" = body_accessory.icon, "icon_state" = body_accessory.icon_state)
accessory_s.Blend(rgb(r_skin, g_skin, b_skin), body_accessory.blend_mode)
overlays_standing[TAIL_LAYER] = image(accessory_s, "pixel_x" = body_accessory.get_pixel_x(src), "pixel_y" = body_accessory.get_pixel_y(src))
else if(species.tail && species.bodyflags & HAS_TAIL) //no tailless tajaran
if(!wear_suit || !(wear_suit.flags_inv & HIDETAIL) && !istype(wear_suit, /obj/item/clothing/suit/space))
var/icon/tail_s = new/icon("icon" = 'icons/effects/species.dmi', "icon_state" = "[species.tail]_s")
tail_s.Blend(rgb(r_skin, g_skin, b_skin), ICON_ADD)
@@ -913,7 +923,14 @@ var/global/list/damage_icon_parts = list()
/mob/living/carbon/human/proc/start_tail_wagging(var/update_icons=1)
overlays_standing[TAIL_LAYER] = null
if(species.tail && species.bodyflags & HAS_TAIL)
if(body_accessory)
if(body_accessory.animated_icon && body_accessory.animated_icon_state)
var/icon/accessory_s = new/icon("icon" = body_accessory.animated_icon, "icon_state" = body_accessory.animated_icon_state)
accessory_s.Blend(rgb(r_skin, g_skin, b_skin), body_accessory.blend_mode)
overlays_standing[TAIL_LAYER] = image(accessory_s, "pixel_x" = body_accessory.get_pixel_x(src), "pixel_y" = body_accessory.get_pixel_y(src))
else if(species.tail && species.bodyflags & HAS_TAIL)
var/icon/tailw_s = new/icon("icon" = 'icons/effects/species.dmi', "icon_state" = "[species.tail]w_s")
tailw_s.Blend(rgb(r_skin, g_skin, b_skin), ICON_ADD)
@@ -925,14 +942,11 @@ var/global/list/damage_icon_parts = list()
/mob/living/carbon/human/proc/stop_tail_wagging(var/update_icons=1)
overlays_standing[TAIL_LAYER] = null
if(species.tail && species.bodyflags & HAS_TAIL)
var/icon/tail_s = new/icon("icon" = 'icons/effects/species.dmi', "icon_state" = "[species.tail]_s")
tail_s.Blend(rgb(r_skin, g_skin, b_skin), ICON_ADD)
update_tail_layer(update_icons) //just trigger a full update for normal stationary sprites
overlays_standing[TAIL_LAYER] = image(tail_s)
if(update_icons)
update_icons()
/mob/living/carbon/human/handle_transform_change()
..()
update_tail_layer()
//Adds a collar overlay above the helmet layer if the suit has one
// Suit needs an identically named sprite in icons/mob/collar.dmi
@@ -28,4 +28,8 @@
if(changed)
animate(src, transform = ntransform, time = 2, pixel_y = final_pixel_y, dir = final_dir, easing = EASE_IN|EASE_OUT)
floating = 0 // If we were without gravity, the bouncing animation got stopped, so we make sure we restart it in next life().
handle_transform_change()
floating = 0 // If we were without gravity, the bouncing animation got stopped, so we make sure we restart it in next life().
/mob/living/carbon/proc/handle_transform_change()
return