diff --git a/SQL/paradise_schema.sql b/SQL/paradise_schema.sql index 22369d5470d..ba319ac8491 100644 --- a/SQL/paradise_schema.sql +++ b/SQL/paradise_schema.sql @@ -79,6 +79,7 @@ CREATE TABLE `characters` ( `nanotrasen_relation` varchar(45) NOT NULL, `speciesprefs` int(1) NOT NULL, `socks` mediumtext NOT NULL, + `body_accessory` mediumtext NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=18747 DEFAULT CHARSET=utf8; /*!40101 SET character_set_client = @saved_cs_client */; diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm index 37e2f588fc3..bb8065b845e 100644 --- a/code/modules/client/preferences.dm +++ b/code/modules/client/preferences.dm @@ -128,6 +128,7 @@ datum/preferences var/species = "Human" var/language = "None" //Secondary language + var/body_accessory = null var/speciesprefs = 0//I hate having to do this, I really do (Using this for oldvox code, making names universal I guess @@ -366,10 +367,14 @@ datum/preferences dat += "
Eyes
" dat += "Change Color
__

" - if(species == "Unathi" || species == "Tajaran" || species == "Skrell" || species == "Slime People" || species == "Vulpkanin") + if(species == "Unathi" || species == "Tajaran" || species == "Skrell" || species == "Slime People" || species == "Vulpkanin" || body_accessory_by_species[species] || check_rights(R_ADMIN, 1, user)) //admins can always fuck with this, because they are admins dat += "
Body Color
" dat += "Change Color
__
" + if(body_accessory_by_species[species] || check_rights(R_ADMIN, 1, user)) + dat += "
Body Accessory
" + dat += "Accessory: [body_accessory ? "[body_accessory]" : "None"]
" + dat += "
" if (1) // General Preferences @@ -1165,10 +1170,27 @@ datum/preferences valid_hairstyles[hairstyle] = hair_styles_list[hairstyle] - var/new_h_style = input(user, "Choose your character's hair style:", "Character Preference") as null|anything in valid_hairstyles + var/new_h_style = input(user, "Choose your character's hair style:", "Character Preference") as null|anything in valid_hairstyles if(new_h_style) h_style = new_h_style + if("body_accessory") + var/list/possible_body_accessories = list() + if(check_rights(R_ADMIN, 1, user)) + possible_body_accessories = body_accessory_by_name.Copy() + else + for(var/B in body_accessory_by_name) + var/datum/body_accessory/accessory = body_accessory_by_name[B] + if(!istype(accessory)) + possible_body_accessories += "None" //the only null entry should be the "None" option + continue + if(species in accessory.allowed_species) + possible_body_accessories += B + + var/new_body_accessory = input(user, "Choose your body accessory:", "Character Preference") as null|anything in possible_body_accessories + if(new_body_accessory) + body_accessory = new_body_accessory + if("facial") var/new_facial = input(user, "Choose your character's facial-hair colour:", "Character Preference") as color|null if(new_facial) @@ -1246,7 +1268,7 @@ datum/preferences s_tone = 35 - max(min( round(new_s_tone), 220),1) if("skin") - if(species == "Unathi" || species == "Tajaran" || species == "Skrell" || species == "Slime People"|| species == "Vulpkanin") + if(species == "Unathi" || species == "Tajaran" || species == "Skrell" || species == "Slime People"|| species == "Vulpkanin" || body_accessory_by_species[species] || check_rights(R_ADMIN, 1, user)) var/new_skin = input(user, "Choose your character's skin colour: ", "Character Preference") as color|null if(new_skin) r_skin = hex2num(copytext(new_skin, 2, 4)) @@ -1571,6 +1593,9 @@ datum/preferences character.undershirt = undershirt character.socks = socks + if(body_accessory) + character.body_accessory = body_accessory_by_name["[body_accessory]"] + if(backbag > 4 || backbag < 1) backbag = 1 //Same as above character.backbag = backbag diff --git a/code/modules/client/preferences_mysql.dm b/code/modules/client/preferences_mysql.dm index 8470ece80a9..f60b315d912 100644 --- a/code/modules/client/preferences_mysql.dm +++ b/code/modules/client/preferences_mysql.dm @@ -151,7 +151,8 @@ //socks socks = query.item[54] - + body_accessory = query.item[55] + //Sanitize metadata = sanitize_text(metadata, initial(metadata)) real_name = reject_bad_name(real_name) @@ -200,7 +201,7 @@ be_special = sanitize_integer(be_special, 0, 65535, initial(be_special)) socks = sanitize_text(socks, initial(socks)) - + body_accessory = sanitize_text(body_accessory, initial(body_accessory)) // if(isnull(disabilities)) disabilities = 0 if(!player_alt_titles) player_alt_titles = new() @@ -274,7 +275,8 @@ rlimb_data='[rlimblist]', nanotrasen_relation='[nanotrasen_relation]', speciesprefs='[speciesprefs]', - socks='[socks]' + socks='[socks]', + body_accessory='[body_accessory]' WHERE ckey='[C.ckey]' AND slot='[default_slot]'"} ) @@ -302,7 +304,9 @@ job_karma_high, job_karma_med, job_karma_low, flavor_text, med_record, sec_record, gen_record, player_alt_titles, be_special, - disabilities, organ_data, rlimb_data, nanotrasen_relation, speciesprefs, socks) + disabilities, organ_data, rlimb_data, nanotrasen_relation, speciesprefs, + socks, body_accessory) + VALUES ('[C.ckey]', '[default_slot]', '[sql_sanitize_text(metadata)]', '[sql_sanitize_text(real_name)]', '[be_random_name]','[gender]', '[age]', '[sql_sanitize_text(species)]', '[sql_sanitize_text(language)]', @@ -319,7 +323,9 @@ '[job_karma_high]', '[job_karma_med]', '[job_karma_low]', '[sql_sanitize_text(flavor_text)]', '[sql_sanitize_text(med_record)]', '[sql_sanitize_text(sec_record)]', '[sql_sanitize_text(gen_record)]', '[playertitlelist]', '[be_special]', - '[disabilities]', '[organlist]', '[rlimblist]', '[nanotrasen_relation]', '[speciesprefs]','[socks]') + '[disabilities]', '[organlist]', '[rlimblist]', '[nanotrasen_relation]', '[speciesprefs]', + '[socks]', '[body_accessory]') + "} ) diff --git a/code/modules/mob/living/carbon/human/body_accessories.dm b/code/modules/mob/living/carbon/human/body_accessories.dm new file mode 100644 index 00000000000..2a8dfa4e458 --- /dev/null +++ b/code/modules/mob/living/carbon/human/body_accessories.dm @@ -0,0 +1,128 @@ + +var/global/list/body_accessory_by_name = list("None" = null) + +/hook/startup/proc/initalize_body_accessories() + +// __init_body_accessory(/datum/body_accessory/body) + __init_body_accessory(/datum/body_accessory/tail) + + 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/species in accessory.allowed_species) + if(!body_accessory_by_species["[species]"]) body_accessory_by_species["[species]"] = list() + body_accessory_by_species["[species]"] += accessory + + if(body_accessory_by_species.len) + return 1 + return 0 + +/proc/__init_body_accessory(var/ba_path) + if(ispath(ba_path)) + var/_added_counter = 0 + + for(var/A in subtypesof(ba_path)) + var/datum/body_accessory/B = new A + if(istype(B)) + body_accessory_by_name[B.name] += B + ++_added_counter + + if(_added_counter) + 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/pixel_x_offset = 0 + var/pixel_y_offset = 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_animated_icon() //return animated if it has it, return static if it does not. + if(animated_icon) + return animated_icon + + else return icon + +/datum/body_accessory/proc/get_animated_icon_state() + if(animated_icon_state) + return animated_icon_state + + else return icon_state + +/* +//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_x_offset = -16*/ + +//Tails +/datum/body_accessory/tail + icon = 'icons/mob/body_accessory.dmi' + animated_icon = 'icons/mob/body_accessory.dmi' + 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 + + +//vulpakin +/datum/body_accessory/tail/vulpkanin_2 + name = "Vulpkanin Alt 1 (Bushy)" + + icon_state = "vulptail2" + animated_icon_state = "vulptail2_a" + allowed_species = list("Vulpkanin") + +/datum/body_accessory/tail/vulpkanin_3 + name = "Vulpkanin Alt 2 (Straight)" + + icon_state = "vulptail3" + animated_icon_state = "vulptail3_a" + allowed_species = list("Vulpkanin") + +/datum/body_accessory/tail/vulpkanin_4 + name = "Vulpkanin Alt 3 (Tiny)" + + icon_state = "vulptail4" + animated_icon_state = "vulptail4_a" + allowed_species = list("Vulpkanin") + +/datum/body_accessory/tail/vulpkanin_5 + name = "Vulpkanin Alt 4 (Short)" + + icon_state = "vulptail5" + animated_icon_state = "vulptail5_a" + allowed_species = list("Vulpkanin") \ No newline at end of file diff --git a/code/modules/mob/living/carbon/human/emote.dm b/code/modules/mob/living/carbon/human/emote.dm index 1054a639819..abbe2d2cf3d 100644 --- a/code/modules/mob/living/carbon/human/emote.dm +++ b/code/modules/mob/living/carbon/human/emote.dm @@ -116,7 +116,12 @@ m_type = 1 if("wag") - if(species.bodyflags & TAIL_WAGGING) + if(body_accessory) + if(body_accessory.try_restrictions(src)) + message = "[src] starts wagging \his tail." + start_tail_wagging(1) + + else if(species.bodyflags & TAIL_WAGGING) if(!wear_suit || !(wear_suit.flags_inv & HIDETAIL) && !istype(wear_suit, /obj/item/clothing/suit/space)) message = "[src] starts wagging \his tail." src.start_tail_wagging(1) @@ -126,7 +131,7 @@ return if("swag") - if(species.bodyflags & TAIL_WAGGING) + if(species.bodyflags & TAIL_WAGGING || body_accessory) message = "[src] stops wagging \his tail." src.stop_tail_wagging(1) else diff --git a/code/modules/mob/living/carbon/human/human_defines.dm b/code/modules/mob/living/carbon/human/human_defines.dm index 7d7d400c9c3..eead644cc58 100644 --- a/code/modules/mob/living/carbon/human/human_defines.dm +++ b/code/modules/mob/living/carbon/human/human_defines.dm @@ -82,4 +82,6 @@ var/lastFart = 0 // Toxic fart cooldown. var/fire_dmi = 'icons/mob/OnFire.dmi' - var/fire_sprite = "Standing" \ No newline at end of file + var/fire_sprite = "Standing" + + var/datum/body_accessory/body_accessory = null diff --git a/code/modules/mob/living/carbon/human/update_icons.dm b/code/modules/mob/living/carbon/human/update_icons.dm index 1590db1c214..e55ee2d1149 100644 --- a/code/modules/mob/living/carbon/human/update_icons.dm +++ b/code/modules/mob/living/carbon/human/update_icons.dm @@ -344,7 +344,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 @@ -763,12 +763,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) @@ -893,10 +893,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.pixel_x_offset, "pixel_y" = body_accessory.pixel_y_offset) + + + 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) @@ -910,7 +920,13 @@ 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) + var/icon/accessory_s = new/icon("icon" = body_accessory.get_animated_icon(), "icon_state" = body_accessory.get_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.pixel_x_offset, "pixel_y" = body_accessory.pixel_y_offset) + + 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) @@ -922,14 +938,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 diff --git a/code/modules/mob/living/carbon/update_icons.dm b/code/modules/mob/living/carbon/update_icons.dm index 02fe01c39a1..e22ad5e66dc 100644 --- a/code/modules/mob/living/carbon/update_icons.dm +++ b/code/modules/mob/living/carbon/update_icons.dm @@ -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(). \ No newline at end of file + 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 \ No newline at end of file diff --git a/icons/mob/body_accessory.dmi b/icons/mob/body_accessory.dmi new file mode 100644 index 00000000000..fac217e71fa Binary files /dev/null and b/icons/mob/body_accessory.dmi differ diff --git a/paradise.dme b/paradise.dme index 083fa7a3c81..c56fea4d065 100644 --- a/paradise.dme +++ b/paradise.dme @@ -1328,6 +1328,7 @@ #include "code\modules\mob\living\carbon\brain\posibrain.dm" #include "code\modules\mob\living\carbon\brain\say.dm" #include "code\modules\mob\living\carbon\human\appearance.dm" +#include "code\modules\mob\living\carbon\human\body_accessories.dm" #include "code\modules\mob\living\carbon\human\death.dm" #include "code\modules\mob\living\carbon\human\emote.dm" #include "code\modules\mob\living\carbon\human\examine.dm"