diff --git a/SQL/migrate/V045__underwear_updates.sql b/SQL/migrate/V045__underwear_updates.sql new file mode 100644 index 00000000000..194879831f3 --- /dev/null +++ b/SQL/migrate/V045__underwear_updates.sql @@ -0,0 +1,10 @@ +-- +-- Adds support for underwear updates in PR #6973. +-- This collates all underwear data into one column, with an additional column for custom colours. +-- + +ALTER TABLE `ss13_characters` + CHANGE COLUMN `underwear` `all_underwear` JSON NULL DEFAULT NULL COLLATE 'utf8mb4_unicode_ci' AFTER `eyes_colour`, + DROP COLUMN `undershirt`, + DROP COLUMN `socks`, + ADD COLUMN `all_underwear_metadata` JSON NULL DEFAULT NULL COLLATE 'utf8mb4_unicode_ci' AFTER `all_underwear`; diff --git a/aurorastation.dme b/aurorastation.dme index 82fab7eeab7..e34455384ae 100644 --- a/aurorastation.dme +++ b/aurorastation.dme @@ -60,6 +60,7 @@ #include "code\__defines\vueui.dm" #include "code\__defines\webhook.dm" #include "code\__defines\ZAS.dm" +#include "code\_helpers\_global_objects.dm" #include "code\_helpers\_string_lists.dm" #include "code\_helpers\area_movement.dm" #include "code\_helpers\areas.dm" @@ -351,6 +352,11 @@ #include "code\datums\trading\unique.dm" #include "code\datums\trading\vox.dm" #include "code\datums\trading\weaponry.dm" +#include "code\datums\underwear\bottom.dm" +#include "code\datums\underwear\socks.dm" +#include "code\datums\underwear\top.dm" +#include "code\datums\underwear\undershirt.dm" +#include "code\datums\underwear\underwear.dm" #include "code\datums\uplink\ammunition.dm" #include "code\datums\uplink\announcements.dm" #include "code\datums\uplink\badassery.dm" diff --git a/code/_helpers/_global_objects.dm b/code/_helpers/_global_objects.dm new file mode 100644 index 00000000000..4a77edce5fb --- /dev/null +++ b/code/_helpers/_global_objects.dm @@ -0,0 +1,3 @@ +//Gear tweaks and underwear. +var/datum/gear_tweak/color/gear_tweak_free_color_choice = new() +var/datum/category_collection/underwear/global_underwear = new() diff --git a/code/_helpers/global_lists.dm b/code/_helpers/global_lists.dm index 78733de2979..b642bc8c198 100644 --- a/code/_helpers/global_lists.dm +++ b/code/_helpers/global_lists.dm @@ -46,7 +46,7 @@ var/global/list/poster_designs = list() var/list/obj/item/device/uplink/world_uplinks = list() //Preferences stuff - //Hairstyles +//Hairstyles var/global/list/hair_styles_list = list() //stores /datum/sprite_accessory/hair indexed by name var/global/list/hair_styles_male_list = list() var/global/list/hair_styles_female_list = list() @@ -58,34 +58,7 @@ var/global/list/body_marking_styles_list = list() var/global/list/chargen_disabilities_list = list() var/global/static/list/valid_player_genders = list(MALE, FEMALE, NEUTER) - //Underwear -var/global/list/underwear_m = list("White" = "m1", "Grey" = "m2", "Green" = "m3", "Blue" = "m4", "Black" = "m5", "Mankini" = "m6", "Boxers" = "boxers", "Green and blue boxers" = "boxers_green_and_blue","Loveheart boxers" = "boxers_loveheart","None") //Curse whoever made male/female underwear diffrent colours -var/global/list/underwear_f = list("Red" = "f1", "White" = "f2", "Yellow" = "f3", "Blue" = "f4", "Black" = "f5", "Thong" = "f6", "Black Sports" = "f7","White Sports" = "f8","None") - //undershirt -var/global/list/undershirt_t = list( - "White tank top" = "u1", "Black tank top" = "u2", "Black shirt" = "u3", "White shirt" = "u4", - "Polo" = "polo", "Blue polo" = "bluepolo_s", "Red polo" = "redpolo_s", "Yellow polo" = "grayyellowpolo_s", - "Striped shirt" = "shirt_stripes_s", "NanoTrasen shirt" = "shirt_nano_s", "Tiedye shirt" = "shirt_tiedye_s", - "Green sport shirt" = "greenshirtsport_s", "Red sport shirt" = "redshirtsport_s", "Blue sport shirt" = "blueshirtsport_s", - "Striped tank top " = "tank_stripes_s", "Rainbow tank top" = "tank_rainbow_s", "Longsleeve shirt" = "undershirt_long", - "Striped longsleve shirt" = "longstripe", "Blue striped longsleve shirt" = "longstripe_blue", "None") - - //socks -var/global/list/socks_f = list( - "White normal" = "white_norm", "White short" = "white_short", "White knee" = "white_knee", - "White thigh" = "white_thigh", "Black normal" = "black_norm", "Black short" = "black_short", - "Black knee" = "black_knee", "Black thigh" = "black_thigh", "Striped normal" = "striped_norm", - "Striped short" = "striped_short", "Striped knee" = "striped_knee", "Striped thigh" = "striped_thigh", - "Rainbow normal" = "rainbow_norm", "Rainbow short" = "rainbow_short", "Rainbow knee" = "rainbow_knee", - "Rainbow thigh" = "rainbow_thigh", "Pantyhose" = "pantyhose", "None") - -var/global/list/socks_m = list( - "White normal" = "white_norm", "White short" = "white_short", "White knee" = "white_knee", - "Black normal" = "black_norm", "Black short" = "black_short", "Black knee" = "black_knee", - "Striped normal" = "striped_norm", "Striped short" = "striped_short", "Striped knee" = "striped_knee", - "Rainbow normal" = "rainbow_norm", "Rainbow short" = "rainbow_short", "Rainbow knee" = "rainbow_knee", "None") - - //Backpacks +//Backpacks var/global/list/backbaglist = list("Nothing", "Backpack", "Satchel", "Satchel Alt", "Duffel Bag", "Messenger Bag") var/global/list/backbagstyles = list("Job-specific", "Grey") var/global/list/exclude_jobs = list(/datum/job/ai,/datum/job/cyborg, /datum/job/merchant) diff --git a/code/_helpers/lists.dm b/code/_helpers/lists.dm index 585d574cdb1..de0a9c6cb18 100644 --- a/code/_helpers/lists.dm +++ b/code/_helpers/lists.dm @@ -285,6 +285,122 @@ if(L[key] == value) return key +/proc/dd_sortedObjectList(var/list/L, var/cache=list()) + if(L.len < 2) + return L + var/middle = L.len / 2 + 1 // Copy is first,second-1 + return dd_mergeObjectList(dd_sortedObjectList(L.Copy(0,middle), cache), dd_sortedObjectList(L.Copy(middle), cache), cache) //second parameter null = to end of list + +/proc/dd_mergeObjectList(var/list/L, var/list/R, var/list/cache) + var/Li=1 + var/Ri=1 + var/list/result = new() + while(Li <= L.len && Ri <= R.len) + var/LLi = L[Li] + var/RRi = R[Ri] + var/LLiV = cache[LLi] + var/RRiV = cache[RRi] + if(!LLiV) + LLiV = LLi:dd_SortValue() + cache[LLi] = LLiV + if(!RRiV) + RRiV = RRi:dd_SortValue() + cache[RRi] = RRiV + if(LLiV < RRiV) + result += L[Li++] + else + result += R[Ri++] + + if(Li <= L.len) + return (result + L.Copy(Li, 0)) + return (result + R.Copy(Ri, 0)) + +// Insert an object into a sorted list, preserving sortedness +/proc/dd_insertObjectList(var/list/L, var/O) + var/min = 1 + var/max = L.len + var/Oval = O:dd_SortValue() + + while(1) + var/mid = min+round((max-min)/2) + + if(mid == max) + L.Insert(mid, O) + return + + var/Lmid = L[mid] + var/midval = Lmid:dd_SortValue() + if(Oval == midval) + L.Insert(mid, O) + return + else if(Oval < midval) + max = mid + else + min = mid+1 + +/proc/dd_sortedtextlist(list/incoming, case_sensitive = 0) + // Returns a new list with the text values sorted. + // Use binary search to order by sortValue. + // This works by going to the half-point of the list, seeing if the node in question is higher or lower cost, + // then going halfway up or down the list and checking again. + // This is a very fast way to sort an item into a list. + var/list/sorted_text = new() + var/low_index + var/high_index + var/insert_index + var/midway_calc + var/current_index + var/current_item + var/list/list_bottom + var/sort_result + + var/current_sort_text + for (current_sort_text in incoming) + low_index = 1 + high_index = sorted_text.len + while (low_index <= high_index) + // Figure out the midpoint, rounding up for fractions. (BYOND rounds down, so add 1 if necessary.) + midway_calc = (low_index + high_index) / 2 + current_index = round(midway_calc) + if (midway_calc > current_index) + current_index++ + current_item = sorted_text[current_index] + + if (case_sensitive) + sort_result = sorttextEx(current_sort_text, current_item) + else + sort_result = sorttext(current_sort_text, current_item) + + switch(sort_result) + if (1) + high_index = current_index - 1 // current_sort_text < current_item + if (-1) + low_index = current_index + 1 // current_sort_text > current_item + if (0) + low_index = current_index // current_sort_text == current_item + break + + // Insert before low_index. + insert_index = low_index + + // Special case adding to end of list. + if (insert_index > sorted_text.len) + sorted_text += current_sort_text + continue + + // Because BYOND lists don't support insert, have to do it by: + // 1) taking out bottom of list, 2) adding item, 3) putting back bottom of list. + list_bottom = sorted_text.Copy(insert_index) + sorted_text.Cut(insert_index) + sorted_text += current_sort_text + sorted_text += list_bottom + return sorted_text + + +/proc/dd_sortedTextList(list/incoming) + var/case_sensitive = 1 + return dd_sortedtextlist(incoming, case_sensitive) + /proc/count_by_type(var/list/L, type) var/i = 0 for(var/T in L) @@ -477,7 +593,7 @@ if (isnull(subject)) return - + var/final = keys[keys.len] if (isdatum(subject)) subject_d = subject @@ -522,7 +638,7 @@ if (isnull(subject)) return - + var/final = keys[keys.len] if (isdatum(subject)) subject_d = subject @@ -573,4 +689,4 @@ . = list() for(var/entry in L) if(istype(entry, type)) - . += entry \ No newline at end of file + . += entry diff --git a/code/_onclick/hud/human.dm b/code/_onclick/hud/human.dm index 406860083c0..8f768afe07c 100644 --- a/code/_onclick/hud/human.dm +++ b/code/_onclick/hud/human.dm @@ -291,7 +291,7 @@ mymob.nutrition_icon.name = "nutrition" mymob.nutrition_icon.screen_loc = ui_nutrition hud_elements |= mymob.nutrition_icon - + if(hud_data.has_hydration) mymob.hydration_icon = new /obj/screen() mymob.hydration_icon.icon = ui_style @@ -393,7 +393,5 @@ f_style = "Shaved" if(dna.species == "Human") //no more xenos losing ears/tentacles h_style = pick("Bedhead", "Bedhead 2", "Bedhead 3") - undershirt = null - underwear = null - socks = null + all_underwear.Cut() regenerate_icons() diff --git a/code/controllers/subsystems/garbage-debug.dm b/code/controllers/subsystems/garbage-debug.dm index 010c8ffb509..2d70f5223bb 100644 --- a/code/controllers/subsystems/garbage-debug.dm +++ b/code/controllers/subsystems/garbage-debug.dm @@ -312,11 +312,6 @@ SearchVar(facial_hair_styles_female_list) SearchVar(skin_styles_female_list) SearchVar(body_marking_styles_list) - SearchVar(underwear_m) - SearchVar(underwear_f) - SearchVar(undershirt_t) - SearchVar(socks_f) - SearchVar(socks_m) SearchVar(backbaglist) SearchVar(exclude_jobs) SearchVar(visual_nets) diff --git a/code/datums/category.dm b/code/datums/category.dm index 9542f6a3e94..b2a03a43327 100644 --- a/code/datums/category.dm +++ b/code/datums/category.dm @@ -4,16 +4,19 @@ /datum/category_collection var/category_group_type // The type of categories to initialize var/list/datum/category_group/categories // The list of initialized categories + var/list/datum/category_group/categories_by_name //Associative list of initialised categories, by name /datum/category_collection/New() ..() categories = new() + categories_by_name = new() for(var/category_type in typesof(category_group_type)) var/datum/category_group/category = category_type if(initial(category.name)) category = new category(src) categories += category - sortTim(categories, /proc/cmp_name_asc, FALSE) + categories_by_name[category.name] = category + categories = dd_sortedObjectList(categories) /datum/category_collection/Destroy() for(var/category in categories) @@ -28,21 +31,24 @@ var/name = "" var/category_item_type // The type of items to initialize var/list/datum/category_item/items // The list of initialized items + var/list/datum/category_item/items_by_name // Associative list of initialised items, by name var/datum/category_collection/collection // The collection this group belongs to /datum/category_group/New(var/datum/category_collection/cc) ..() collection = cc items = new() + items_by_name = new() for(var/item_type in typesof(category_item_type)) var/datum/category_item/item = item_type if(initial(item.name)) item = new item(src) items += item + items_by_name[item.name] = item // If you change this, confirm that character setup doesn't become completely unordered. - sortTim(items, /proc/cmp_player_setup_group) + items = dd_sortedObjectList(items) /datum/category_group/Destroy() for(var/item in items) @@ -51,6 +57,9 @@ collection = null return ..() +/datum/category_group/dd_SortValue() + return name + /***************** * Category Items * *****************/ @@ -65,3 +74,6 @@ /datum/category_item/Destroy() category = null return ..() + +/datum/category_item/dd_SortValue() + return name diff --git a/code/datums/underwear/bottom.dm b/code/datums/underwear/bottom.dm new file mode 100644 index 00000000000..5956b2436d4 --- /dev/null +++ b/code/datums/underwear/bottom.dm @@ -0,0 +1,113 @@ +/datum/category_item/underwear/bottom/none + name = "None" + always_last = TRUE + +/datum/category_item/underwear/bottom/briefs + name = "Briefs" + icon_state = "briefs" + has_color = TRUE + +/datum/category_item/underwear/bottom/briefs/is_default(var/gender) + return gender != FEMALE + +/datum/category_item/underwear/bottom/boxers + name = "Boxers" + icon_state = "boxers" + has_color = TRUE + +/datum/category_item/underwear/bottom/boxers_striped + name = "Boxers, Striped" + icon_state = "boxers_striped" + has_color = TRUE + +/datum/category_item/underwear/bottom/boxers_green_and_blue + name = "Boxers, Green & Blue Striped" + icon_state = "boxers_green_and_blue" + +/datum/category_item/underwear/bottom/boxers_loveheart + name = "Boxers, Loveheart" + icon_state = "boxers_loveheart" + has_color = TRUE + +/datum/category_item/underwear/bottom/panties + name = "Panties" + icon_state = "panties" + has_color = TRUE + +/datum/category_item/underwear/bottom/panties/is_default(var/gender) + return gender == FEMALE + +/datum/category_item/underwear/bottom/panties_striped + name = "Panties, Striped" + icon_state = "panties_striped" + has_color = TRUE + +/datum/category_item/underwear/bottom/panties_bikini + name = "Panties, Bikini" + icon_state = "panties_bikini" + has_color = TRUE + +/datum/category_item/underwear/bottom/panties_hipster + name = "Panties, Hipster" + icon_state = "panties_hipster" + has_color = TRUE + +/datum/category_item/underwear/bottom/compression_shorts + name = "Compression Shorts" + icon_state = "compression_shorts" + has_color = TRUE + +/datum/category_item/underwear/bottom/compression_shorts_alt + name = "Compression Shorts, Alt" + icon_state = "compression_shorts_alt" + has_color = TRUE + +/datum/category_item/underwear/bottom/shorts_army + name = "Shorts, Army" + icon_state = "shorts_army" + +/datum/category_item/underwear/bottom/shorts_expedition + name = "Shorts, Expedition" + icon_state = "shorts_expedition" + +/datum/category_item/underwear/bottom/shorts_fleet + name = "Shorts, Fleet" + icon_state = "shorts_fleet" + +/datum/category_item/underwear/bottom/shorts_necropolis + name = "Shorts, Necropolis Industries" + icon_state = "shorts_necropolis" + +/datum/category_item/underwear/bottom/shorts_epmc + name = "Shorts, EPMC" + icon_state = "shorts_epmc" + +/datum/category_item/underwear/bottom/midway + name = "Midway Briefs" + icon_state = "midway" + has_color = TRUE + +/datum/category_item/underwear/bottom/longjohnbottoms + name = "Long John Bottoms" + icon_state = "ljonb" + has_color = TRUE + +/datum/category_item/underwear/bottom/longjohnbottoms_alt + name = "Long John Bottoms, Alt" + icon_state = "ljonb_alt" + has_color = TRUE + +/datum/category_item/underwear/bottom/onepiece + name = "One Piece" + icon_state = "onepiece" + has_color = TRUE + +/datum/category_item/underwear/bottom/onepiece_striped + name = "One Piece, Striped" + icon_state = "onepiece_striped" + has_color = TRUE + +/datum/category_item/underwear/bottom/swimbottom + name = "Swimming Bottom" + icon_state = "swimbottom" + has_color = TRUE \ No newline at end of file diff --git a/code/datums/underwear/socks.dm b/code/datums/underwear/socks.dm new file mode 100644 index 00000000000..e17029a46c9 --- /dev/null +++ b/code/datums/underwear/socks.dm @@ -0,0 +1,185 @@ +/datum/category_item/underwear/socks/none + always_last = TRUE + name = "None" + +/datum/category_item/underwear/socks/short + name = "Short" + icon_state = "socks_short" + has_color = TRUE + +/datum/category_item/underwear/socks/striped_short + name = "Short, Striped" + icon_state = "striped_short" + has_color = TRUE + +/datum/category_item/underwear/socks/thin_short + name = "Short, Thin" + icon_state = "thin_short" + has_color = TRUE + +/datum/category_item/underwear/socks/bee_short + name = "Short, Bee" + icon_state = "bee_short" + +/datum/category_item/underwear/socks/woolblueorange_short + name = "Short, Wool Blue/Orange" + icon_state = "woolbo_short" + +/datum/category_item/underwear/socks/woolredblue_short + name = "Short, Wool Red/Blue" + icon_state = "woolrb_short" + +/datum/category_item/underwear/socks/spider_short + name = "Short, Spider" + icon_state = "spider_short" + +/datum/category_item/underwear/socks/rainbow_short + name = "Short, Rainbow" + icon_state = "rainbow_short" + +/datum/category_item/underwear/socks/normal + name = "Normal" + icon_state = "socks_norm" + has_color = TRUE + +/datum/category_item/underwear/socks/striped_normal + name = "Normal, Striped" + icon_state = "striped_norm" + has_color = TRUE + +/datum/category_item/underwear/socks/thin_normal + name = "Normal, Thin" + icon_state = "thin_normal" + has_color = TRUE + +/datum/category_item/underwear/socks/bee_normal + name = "Normal, Bee" + icon_state = "bee_normal" + +/datum/category_item/underwear/socks/woolblueorange_normal + name = "Normal, Wool Blue/Orange" + icon_state = "woolbo_normal" + +/datum/category_item/underwear/socks/woolredblue_normal + name = "Normal, Wool Red/Blue" + icon_state = "woolrb_normal" + +/datum/category_item/underwear/socks/spider_normal + name = "Normal, Spider" + icon_state = "spider_normal" + +/datum/category_item/underwear/socks/rainbow_normal + name = "Normal, Rainbow" + icon_state = "rainbow_normal" + +/datum/category_item/underwear/socks/knee + name = "Knee" + icon_state = "socks_knee" + has_color = TRUE + +/datum/category_item/underwear/socks/striped_knee + name = "Knee, Striped" + icon_state = "striped_knee" + has_color = TRUE + +/datum/category_item/underwear/socks/thin_knee + name = "Knee, Thin" + icon_state = "thin_knee" + has_color = TRUE + +/datum/category_item/underwear/socks/bee_knee + name = "Knee, Bee" + icon_state = "bee_knee" + +/datum/category_item/underwear/socks/woolblueorange_knee + name = "Knee, Wool Blue/Orange" + icon_state = "woolbo_knee" + +/datum/category_item/underwear/socks/woolredblue_knee + name = "Knee, Wool Red/Blue" + icon_state = "woolrb_knee" + +/datum/category_item/underwear/socks/spider_knee + name = "Knee, Spider" + icon_state = "spider_knee" + +/datum/category_item/underwear/socks/rainbow_knee + name = "Knee, Rainbow" + icon_state = "rainbow_knee" + +/datum/category_item/underwear/socks/thigh + name = "Thigh" + icon_state = "socks_thigh" + has_color = TRUE + +/datum/category_item/underwear/socks/striped_thigh + name = "Thigh, Striped" + icon_state = "striped_thigh" + has_color = TRUE + +/datum/category_item/underwear/socks/thin_thigh + name = "Thigh, Thin" + icon_state = "thin_thigh" + has_color = TRUE + +/datum/category_item/underwear/socks/bee_thigh + name = "Thigh, Bee" + icon_state = "bee_thigh" + +/datum/category_item/underwear/socks/woolblueorange_thigh + name = "Thigh, Wool Blue/Orange" + icon_state = "woolbo_thigh" + +/datum/category_item/underwear/socks/woolredblue_thigh + name = "Thigh, Wool Red/Blue" + icon_state = "woolrb_thigh" + +/datum/category_item/underwear/socks/spider_thigh + name = "Thigh, Spider" + icon_state = "spider_thigh" + +/datum/category_item/underwear/socks/rainbow_thigh + name = "Thigh, Rainbow" + icon_state = "rainbow_thigh" + +/datum/category_item/underwear/socks/leggings + name = "Leggings" + icon_state = "leggings" + has_color = TRUE + +/datum/category_item/underwear/socks/pantyhose + name = "Pantyhose" + icon_state = "pantyhose" + has_color = TRUE + +/datum/category_item/underwear/socks/stockings_blue + name = "Stockings, Blue" + icon_state = "stockings_blue" + +/datum/category_item/underwear/socks/stockings_cyan + name = "Stockings, Cyan" + icon_state = "stockings_cyan" + +/datum/category_item/underwear/socks/stockings_dpink + name = "Stockings, Dark Pink" + icon_state = "stockings_dpink" + +/datum/category_item/underwear/socks/stockings_green + name = "Stockings, Green" + icon_state = "stockings_green" + +/datum/category_item/underwear/socks/stockings_lpink + name = "Stockings, Light Pink" + icon_state = "stockings_lpink" + +/datum/category_item/underwear/socks/stockings_orange + name = "Stockings, Orange" + icon_state = "stockings_orange" + +/datum/category_item/underwear/socks/stockings_purple + name = "Stockings, Purple" + icon_state = "stockings_purple" + +/datum/category_item/underwear/socks/stockings_yellow + name = "Stockings, Yellow" + icon_state = "stockings_yellow" \ No newline at end of file diff --git a/code/datums/underwear/top.dm b/code/datums/underwear/top.dm new file mode 100644 index 00000000000..239cbe7ec7b --- /dev/null +++ b/code/datums/underwear/top.dm @@ -0,0 +1,53 @@ +/datum/category_item/underwear/top/none + name = "None" + always_last = TRUE + +/datum/category_item/underwear/top/none/is_default(var/gender) + return gender != FEMALE + +/datum/category_item/underwear/top/bra + is_default = TRUE + name = "Bra" + icon_state = "bra" + has_color = TRUE + +/datum/category_item/underwear/top/bra/is_default(var/gender) + return gender == FEMALE + +/datum/category_item/underwear/top/bra_bikini + name = "Bra, Bikini" + icon_state = "bra_bikini" + has_color = TRUE + +/datum/category_item/underwear/top/bra_bralette + name = "Bra, Bralette" + icon_state = "bra_bralette" + has_color = TRUE + +/datum/category_item/underwear/top/bra_striped + name = "Bra, Striped" + icon_state = "bra_striped" + has_color = TRUE + +/datum/category_item/underwear/top/sports_bra + name = "Sports Bra" + icon_state = "sports_bra" + has_color = TRUE + +/datum/category_item/underwear/top/binder + name = "Binder" + icon_state = "binder" + +/datum/category_item/underwear/top/binder_strapless + name = "Binder, Strapless" + icon_state = "binder_strapless" + +/datum/category_item/underwear/top/tubetop + name = "Tube Top" + icon_state = "tubetop" + has_color = TRUE + +/datum/category_item/underwear/top/swimtop + name = "Swimming Top" + icon_state = "swimtop" + has_color = TRUE diff --git a/code/datums/underwear/undershirt.dm b/code/datums/underwear/undershirt.dm new file mode 100644 index 00000000000..da045f99e41 --- /dev/null +++ b/code/datums/underwear/undershirt.dm @@ -0,0 +1,417 @@ +/datum/category_item/underwear/undershirt/none + is_default = TRUE + name = "None" + always_last = TRUE + +/datum/category_item/underwear/undershirt/tank_top + name = "Tank Top" + icon_state = "tanktop" + has_color = TRUE + +/datum/category_item/underwear/undershirt/tank_top_fem + name = "Tank Top, Feminine" + icon_state = "tanktop_fem" + has_color = TRUE + +/datum/category_item/underwear/undershirt/tank_top_alt + name = "Tank Top, Alt" + icon_state = "tanktop_alt" + has_color = TRUE + +/datum/category_item/underwear/undershirt/tank_top_alt_fem + name = "Tank Top, Alt Feminine" + icon_state = "tanktop_alt_fem" + has_color = TRUE + +/datum/category_item/underwear/undershirt/tank_top_alt_vneck + name = "Tank Top, Alt V-Neck" + icon_state = "tanktop_alt_vneck" + has_color = TRUE + +/datum/category_item/underwear/undershirt/tank_top_alt_vneck_fem + name = "Tank Top, Alt V-Neck Feminine" + icon_state = "tanktop_alt_vneck_fem" + has_color = TRUE + +/datum/category_item/underwear/undershirt/tank_top_midriff + name = "Tank Top, Midriff" + icon_state = "tank_midriff" + has_color = TRUE + +/datum/category_item/underwear/undershirt/tank_top_midriff_short + name = "Tank Top, Midriff Short" + icon_state = "tank_midriff_short" + has_color = TRUE + +/datum/category_item/underwear/undershirt/tank_top_expedition + name = "Tank Top, Expedition" + icon_state = "tank_expedition" + +/datum/category_item/underwear/undershirt/tank_top_expedition_fem + name = "Tank Top, Expedition Feminine" + icon_state = "tank_expedition_fem" + +/datum/category_item/underwear/undershirt/tank_top_fleet + name = "Tank Top, Fleet" + icon_state = "tank_fleet" + +/datum/category_item/underwear/undershirt/tank_top_fleet_fem + name = "Tank Top, Fleet Feminine" + icon_state = "tank_fleet_fem" + +/datum/category_item/underwear/undershirt/tank_top_fire + name = "Tank Top, Fire" + icon_state = "tank_fire" + +/datum/category_item/underwear/undershirt/tank_top_fire_fem + name = "Tank Top, Fire Feminine" + icon_state = "tank_fire_fem" + +/datum/category_item/underwear/undershirt/tank_top_stripes + name = "Tank Top, Stripes" + icon_state = "tank_stripes" + +/datum/category_item/underwear/undershirt/tank_top_stripes_fem + name = "Tank Top, Stripes Feminine" + icon_state = "tank_stripes_fem" + +/datum/category_item/underwear/undershirt/tank_top_stripes_alt + name = "Tank Top, Stripes Alt" + icon_state = "tank_stripes_alt" + +/datum/category_item/underwear/undershirt/tank_top_stripes_alt_fem + name = "Tank Top, Stripes Alt Feminine" + icon_state = "tank_stripes_alt_fem" + +/datum/category_item/underwear/undershirt/tank_top_sun + name = "Tank Top, Sun" + icon_state = "tank_sun" + +/datum/category_item/underwear/undershirt/tank_top_sun_fem + name = "Tank Top, Sun Feminine" + icon_state = "tank_sun_fem" + +/datum/category_item/underwear/undershirt/tank_top_sun_alt + name = "Tank Top, Sun Alt" + icon_state = "tank_sun_alt" + +/datum/category_item/underwear/undershirt/tank_top_sun_alt_fem + name = "Tank Top, Sun Alt Feminine" + icon_state = "tank_sun_alt_fem" + +/datum/category_item/underwear/undershirt/tank_top_tight + name = "Tank Top, Tight" + icon_state = "tank_tight" + +/datum/category_item/underwear/undershirt/tank_top_tight_fem + name = "Tank Top, Tight Feminine" + icon_state = "tank_tight_fem" + +/datum/category_item/underwear/undershirt/shortsleeve_undershirt + name = "Shortsleeve Undershirt" + icon_state = "shortsleeve" + has_color = TRUE + +/datum/category_item/underwear/undershirt/shortsleeve_undershirt_fem + name = "Shortsleeve Undershirt, Feminine" + icon_state = "shortsleeve_fem" + has_color = TRUE + +/datum/category_item/underwear/undershirt/shortsleeve_undershirt_vneck + name = "Shortsleeve Undershirt, V-Neck" + icon_state = "shortsleeve_vneck" + has_color = TRUE + +/datum/category_item/underwear/undershirt/shortsleeve_undershirt_vneck_fem + name = "Shortsleeve Undershirt, V-Neck Feminine" + icon_state = "shortsleeve_vneck_fem" + has_color = TRUE + +/datum/category_item/underwear/undershirt/undershirt + name = "Undershirt" + icon_state = "undershirt" + has_color = TRUE + +/datum/category_item/underwear/undershirt/undershirt_fem + name = "Undershirt, Feminine" + icon_state = "undershirt_fem" + has_color = TRUE + +/datum/category_item/underwear/undershirt/undershirt_heart + name = "Undershirt, Heart" + icon_state = "heart" + +/datum/category_item/underwear/undershirt/undershirt_heart_fem + name = "Undershirt, Heart Feminine" + icon_state = "heart_fem" + +/datum/category_item/underwear/undershirt/undershirt_heart_echelon + name = "Undershirt, Heart Echelon" + icon_state = "heart_echelon" + +/datum/category_item/underwear/undershirt/undershirt_heart_echelon_fem + name = "Undershirt, Heart Echelon Feminine" + icon_state = "heart_echelon_fem" + +/datum/category_item/underwear/undershirt/shirt_love_nt + name = "Undershirt, I<3NT" + icon_state = "ilovent" + +/datum/category_item/underwear/undershirt/shirt_love_nt_fem + name = "Undershirt, I<3NT Feminine" + icon_state = "ilovent_fem" + +/datum/category_item/underwear/undershirt/shirt + name = "Shirt" + icon_state = "shirt" + has_color = TRUE + +/datum/category_item/underwear/undershirt/shirt_alien + name = "Shirt, Alien" + icon_state = "shirt_alien" + +/datum/category_item/underwear/undershirt/shirt_band + name = "Shirt, Band" + icon_state = "shirt_band" + +/datum/category_item/underwear/undershirt/shirt_clown + name = "Shirt, Clown" + icon_state = "shirt_clown" + +/datum/category_item/underwear/undershirt/shirt_ian + name = "Shirt, Ian" + icon_state = "shirt_ian" + +/datum/category_item/underwear/undershirt/shirt_jersey + name = "Shirt, Blue Jersey" + icon_state = "shirt_jersey" + +/datum/category_item/underwear/undershirt/shirt_jersey_red + name = "Shirt, Red Jersey" + icon_state = "shirt_jersey_red" + +/datum/category_item/underwear/undershirt/shirt_meat + name = "Shirt, Meat" + icon_state = "shirt_meat" + +/datum/category_item/underwear/undershirt/shirt_nt + name = "Shirt, NT" + icon_state = "shirt_nano" + +/datum/category_item/underwear/undershirt/shirt_nt_red + name = "Shirt, NT Red" + icon_state = "shirt_nano_red" + +/datum/category_item/underwear/undershirt/shirt_peace + name = "Shirt, Peace" + icon_state = "shirt_peace" + +/datum/category_item/underwear/undershirt/shirt_question + name = "Shirt, Question" + icon_state = "shirt_question" + +/datum/category_item/underwear/undershirt/shirt_skull + name = "Shirt, Skull" + icon_state = "shirt_skull" + +/datum/category_item/underwear/undershirt/shirt_ss13 + name = "Shirt, SS13" + icon_state = "shirt_ss13" + +/datum/category_item/underwear/undershirt/shirt_blue_striped + name = "Shirt, Blue Stripes" + icon_state = "shirt_stripes" + +/datum/category_item/underwear/undershirt/shirt_blue_striped_alt + name = "Shirt, Blue Stripes Alt" + icon_state = "shirt_stripes_alt" + +/datum/category_item/underwear/undershirt/shirt_tiedye + name = "Shirt, Tiedye" + icon_state = "shirt_tiedye" + +/datum/category_item/underwear/undershirt/shirt_tight + name = "Shirt, Tight" + icon_state = "tight" + +/datum/category_item/underwear/undershirt/shirt_wing + name = "Shirt, Wing" + icon_state = "wing_shirt" + +/datum/category_item/underwear/undershirt/shirt_pinkblack + name = "Shirt, Pink-Black" + icon_state = "pinkblack_tshirt" + +/datum/category_item/underwear/undershirt/sport_shirt_blue + name = "Sport Shirt, Blue" + icon_state = "sportblue" + +/datum/category_item/underwear/undershirt/sport_shirt_green + name = "Sport Shirt, Green" + icon_state = "sportgreen" + +/datum/category_item/underwear/undershirt/sport_shirt_red + name = "Sport Shirt, Red" + icon_state = "sportred" + +/datum/category_item/underwear/undershirt/shirt_army + name = "Shirt, Army" + icon_state = "shirt_army" + +/datum/category_item/underwear/undershirt/shirt_army_fem + name = "Shirt, Army Feminine" + icon_state = "shirt_army_fem" + +/datum/category_item/underwear/undershirt/shirt_expedition + name = "Shirt, Expedition" + icon_state = "shirt_expedition" + +/datum/category_item/underwear/undershirt/shirt_expedition_fem + name = "Shirt, Expedition Feminine" + icon_state = "shirt_expedition_fem" + +/datum/category_item/underwear/undershirt/shirt_fleet + name = "Shirt, Fleet" + icon_state = "shirt_fleet" + +/datum/category_item/underwear/undershirt/shirt_fleet_fem + name = "Shirt, Fleet Feminine" + icon_state = "shirt_fleet_fem" + +/datum/category_item/underwear/undershirt/shirt_necropolis + name = "Shirt, Necropolis Industries" + icon_state = "shirt_necropolis" + +/datum/category_item/underwear/undershirt/shirt_necropolis_fem + name = "Shirt, Necropolis Industries Feminine" + icon_state = "shirt_necropolis_fem" + +/datum/category_item/underwear/undershirt/shirt_epmc + name = "Shirt, EPMC" + icon_state = "shirt_epmc" + +/datum/category_item/underwear/undershirt/shirt_epmc_fem + name = "Shirt, EPMC Feminine" + icon_state = "shirt_epmc_fem" + +/datum/category_item/underwear/undershirt/polo + name = "Polo" + icon_state = "polo" + has_color = TRUE + +/datum/category_item/underwear/undershirt/polo_fem + name = "Polo, Feminine" + icon_state = "polo_fem" + has_color = TRUE + +/datum/category_item/underwear/undershirt/polo_blue + name = "Polo, Blue" + icon_state = "polo_blue" + +/datum/category_item/underwear/undershirt/polo_blue_fem + name = "Polo, Blue Feminine" + icon_state = "polo_blue_fem" + +/datum/category_item/underwear/undershirt/polo_red + name = "Polo, Red" + icon_state = "polo_red" + +/datum/category_item/underwear/undershirt/polo_red_fem + name = "Polo, Red Feminine" + icon_state = "polo_red_fem" + +/datum/category_item/underwear/undershirt/polo_grayyellow + name = "Polo, Gray Yellow" + icon_state = "polo_grayyellow" + +/datum/category_item/underwear/undershirt/polo_grayyellow_fem + name = "Polo, Gray Yellow Feminine" + icon_state = "polo_grayyellow_fem" + +/datum/category_item/underwear/undershirt/polo_greenstrip + name = "Polo, Green Strip" + icon_state = "polo_corp" + +/datum/category_item/underwear/undershirt/polo_greenstrip_fem + name = "Polo, Green Strip Feminine" + icon_state = "polo_corp_fem" + +/datum/category_item/underwear/undershirt/polo_bluestrip + name = "Polo, Blue Strip" + icon_state = "polo_dais" + +/datum/category_item/underwear/undershirt/polo_bluestrip_fem + name = "Polo, Blue Strip Feminine" + icon_state = "polo_dais_fem" + +/datum/category_item/underwear/undershirt/polo_redstrip + name = "Polo, Red Strip" + icon_state = "polo_nt" + +/datum/category_item/underwear/undershirt/polo_redstrip_fem + name = "Polo, Red Strip Feminine" + icon_state = "polo_nt_fem" + +/datum/category_item/underwear/undershirt/bowlinga + name = "Bowling Shirt, Aqua" + icon_state = "bowlinga" + +/datum/category_item/underwear/undershirt/bowlingp + name = "Bowling Shirt, Pink" + icon_state = "bowlingp" + +/datum/category_item/underwear/undershirt/bowlingr + name = "Bowling Shirt, Red" + icon_state = "bowlingr" + +/datum/category_item/underwear/undershirt/bowlingw + name = "Bowling Shirt, White" + icon_state = "bowlingw" + +/datum/category_item/underwear/undershirt/longjon + name = "Long John Shirt" + icon_state = "ljont" + has_color = TRUE + +/datum/category_item/underwear/undershirt/blouse_fem + name = "Blouse Shirt" + icon_state = "blouse_fem" + has_color = TRUE + +/datum/category_item/underwear/undershirt/longsleeve_undershirt + name = "Longsleeve Undershirt" + icon_state = "undershirt_long" + has_color = TRUE + +/datum/category_item/underwear/undershirt/longsleeve_undershirt_fem + name = "Longsleeve Undershirt, Feminine" + icon_state = "undershirt_long_fem" + has_color = TRUE + +/datum/category_item/underwear/undershirt/longstripe_black + name = "Longsleeve Striped Shirt, Black" + icon_state = "longstripe" + has_color = TRUE + +/datum/category_item/underwear/undershirt/longstripe_blue + name = "Longsleeve Striped Shirt, Blue" + icon_state = "longstripe_blue" + +/datum/category_item/underwear/undershirt/longstripe_pink + name = "Longsleeve Striped Shirt, Pink" + icon_state = "longstripe_pink" + +/datum/category_item/underwear/undershirt/longsleeve_shirt + name = "Longsleeve Shirt" + icon_state = "shirt_long" + has_color = TRUE + +/datum/category_item/underwear/undershirt/longsleeve_shirt_fem + name = "Longsleeve Shirt, Feminine" + icon_state = "shirt_long_fem" + has_color = TRUE + +/datum/category_item/underwear/undershirt/turtleneck + name = "Turtleneck" + icon_state = "turtleneck" + has_color = TRUE \ No newline at end of file diff --git a/code/datums/underwear/underwear.dm b/code/datums/underwear/underwear.dm new file mode 100644 index 00000000000..0297690f822 --- /dev/null +++ b/code/datums/underwear/underwear.dm @@ -0,0 +1,73 @@ +/**************************** +* Category Collection Setup * +****************************/ +/datum/category_collection/underwear + category_group_type = /datum/category_group/underwear + +/************* +* Categories * +*************/ +/datum/category_group/underwear + var/sort_order = 5 // Lower sort order is applied as icons first + var/display_name + var/gender = NEUTER + +/datum/category_group/underwear/dd_SortValue() + return sort_order + +/datum/category_group/underwear/top + name = "Underwear, top" + sort_order = 1 + display_name = "top piece" + category_item_type = /datum/category_item/underwear/top + +/datum/category_group/underwear/bottom + name = "Underwear, bottom" + sort_order = 2 + display_name = "bottom piece" + category_item_type = /datum/category_item/underwear/bottom + +/datum/category_group/underwear/socks + name = "Socks" + sort_order = 3 + display_name = "socks" + gender = PLURAL + category_item_type = /datum/category_item/underwear/socks + +/datum/category_group/underwear/undershirt + name = "Undershirt" + sort_order = 4 // Undershirts currently have the lowest sort order because they may cover both underwear and socks. + display_name = "undershirt" + category_item_type = /datum/category_item/underwear/undershirt + +/******************* +* Category entries * +*******************/ +/datum/category_item/underwear + var/always_last = FALSE // Should this entry be sorte last? + var/is_default = FALSE // Should this entry be considered the default for its type? + var/icon = 'icons/mob/underwear.dmi' // Which icon to get the underwear from + var/icon_state // And the particular item state + var/list/tweaks = list() // Underwear customisation + var/has_color = FALSE + +/datum/category_item/underwear/New() + if(has_color) + tweaks += gear_tweak_free_color_choice + +/datum/category_item/underwear/dd_SortValue() + if(always_last) + return "~"+name + return name + +/datum/category_item/underwear/proc/is_default(var/gender) + return is_default + +/datum/category_item/underwear/proc/generate_image(var/list/metadata) + if(!icon_state) + return + + var/image/I = image(icon = 'icons/mob/underwear.dmi', icon_state = icon_state) + for(var/datum/gear_tweak/gt in tweaks) + gt.tweak_item(I, metadata && metadata["[gt]"] ? metadata["[gt]"] : gt.get_default()) + return I diff --git a/code/game/gamemodes/cult/runes/manifest_ghost.dm b/code/game/gamemodes/cult/runes/manifest_ghost.dm index 36b0cf562c3..66f3bdc552c 100644 --- a/code/game/gamemodes/cult/runes/manifest_ghost.dm +++ b/code/game/gamemodes/cult/runes/manifest_ghost.dm @@ -32,7 +32,7 @@ chose_name = TRUE break apparition.universal_speak = TRUE - apparition.underwear = null + apparition.all_underwear.Cut() apparition.key = ghost.key cult.add_antagonist(apparition.mind) playsound(loc, 'sound/magic/exit_blood.ogg', 100, 1) diff --git a/code/game/objects/structures/under_wardrobe.dm b/code/game/objects/structures/under_wardrobe.dm index c3e76950274..ede8b9a7cf7 100644 --- a/code/game/objects/structures/under_wardrobe.dm +++ b/code/game/objects/structures/under_wardrobe.dm @@ -11,55 +11,84 @@ icon_state = "cabinet_closed" density = 1 -/obj/structure/undies_wardrobe/attack_hand(mob/user as mob) - src.add_fingerprint(user) - var/mob/living/carbon/human/H = user - if(!ishuman(user) || (H.species && !(H.species.appearance_flags & HAS_UNDERWEAR)) && !(H.species.appearance_flags & HAS_SOCKS)) +/obj/structure/undies_wardrobe/attack_hand(var/mob/user) + if(!human_who_can_use_underwear(user)) to_chat(user, "Sadly there's nothing in here for you to wear.") - return 0 + return + interact(user) +/obj/structure/undies_wardrobe/interact(var/mob/living/carbon/human/H) + var/dat = list() + dat += "Underwear:
" + for(var/datum/category_group/underwear/UWC in global_underwear.categories) + var/datum/category_item/underwear/UWI = H.all_underwear[UWC.name] + var/item_name = UWI?.name || "None" + dat += "[UWC.name]: [item_name]" + if(UWI) + for(var/datum/gear_tweak/gt in UWI.tweaks) + dat += " [gt.get_contents(get_metadata(H, UWC.name, gt))]" + dat += " (Remove)
" - var/list/selection_types = list() - if (H.species.appearance_flags & HAS_UNDERWEAR) - selection_types += list(M_UNDER, F_UNDER, U_SHIRT) - if (H.species.appearance_flags & HAS_SOCKS) - selection_types += list(M_SOCKS, F_SOCKS) + dat = jointext(dat, null) + show_browser(H, dat, "window=wardrobe;size=400x200") - var/utype = input("Which section do you want to pick from?") as null|anything in selection_types - var/list/selection - switch(utype) - if(M_UNDER) - selection = underwear_m - if(F_UNDER) - selection = underwear_f - if(U_SHIRT) - selection = undershirt_t - if(M_SOCKS) - selection = socks_m - if(F_SOCKS) - selection = socks_f - var/pick = input("Select the style") as null|anything in selection - if(pick) - if(get_dist(src,user) > 1) +/obj/structure/undies_wardrobe/proc/get_metadata(var/mob/living/carbon/human/H, var/underwear_category, var/datum/gear_tweak/gt) + var/metadata = H.all_underwear_metadata[underwear_category] + if(!metadata) + metadata = list() + H.all_underwear_metadata[underwear_category] = metadata + + var/tweak_data = metadata["[gt]"] + if(!tweak_data) + tweak_data = gt.get_default() + metadata["[gt]"] = tweak_data + return tweak_data + +/obj/structure/undies_wardrobe/proc/set_metadata(var/mob/living/carbon/human/H, var/underwear_category, var/datum/gear_tweak/gt, var/new_metadata) + var/list/metadata = H.all_underwear_metadata[underwear_category] + metadata["[gt]"] = new_metadata + +/obj/structure/undies_wardrobe/proc/human_who_can_use_underwear(var/mob/living/carbon/human/H) + if(!istype(H) || !H.species || !(H.species.appearance_flags & HAS_UNDERWEAR)) + return FALSE + return TRUE + +/obj/structure/undies_wardrobe/CanUseTopic(var/user) + if(!human_who_can_use_underwear(user)) + return STATUS_CLOSE + + return ..() + +/obj/structure/undies_wardrobe/Topic(href, href_list, state) + if(..()) + return TRUE + + var/mob/living/carbon/human/H = usr + if(href_list["remove_underwear"]) + if(href_list["remove_underwear"] in H.all_underwear) + H.all_underwear -= href_list["remove_underwear"] + . = TRUE + else if(href_list["change_underwear"]) + var/datum/category_group/underwear/UWC = global_underwear.categories_by_name[href_list["change_underwear"]] + if(!UWC) return - switch (utype) - if(U_SHIRT) - H.undershirt = undershirt_t[pick] - if(F_SOCKS) - H.socks = selection[pick] - if(M_SOCKS) - H.socks = selection[pick] - if(M_UNDER) - H.underwear = selection[pick] - if(F_UNDER) - H.underwear = selection[pick] - + var/datum/category_item/underwear/selected_underwear = input(H, "Choose underwear:", "Choose underwear", H.all_underwear[UWC.name]) as null|anything in UWC.items + if(selected_underwear && CanUseTopic(H, default_state)) + H.all_underwear[UWC.name] = selected_underwear + H.hide_underwear[UWC.name] = FALSE + . = TRUE + else if(href_list["underwear"] && href_list["tweak"]) + var/underwear = href_list["underwear"] + if(!(underwear in H.all_underwear)) + return + var/datum/gear_tweak/gt = locate(href_list["tweak"]) + if(!gt) + return + var/new_metadata = gt.get_metadata(usr, get_metadata(H, underwear, gt), "Wardrobe Underwear Selection") + if(new_metadata) + set_metadata(H, underwear, gt, new_metadata) + H.hide_underwear[underwear] = FALSE + . = TRUE + if(.) H.update_underwear(TRUE) - - return 1 - -#undef M_UNDER -#undef F_UNDER -#undef M_SOCKS -#undef F_SOCKS -#undef U_SHIRT + interact(H) diff --git a/code/modules/client/preference_setup/general/03_body.dm b/code/modules/client/preference_setup/general/03_body.dm index 1b269bffd19..26181b9d014 100644 --- a/code/modules/client/preference_setup/general/03_body.dm +++ b/code/modules/client/preference_setup/general/03_body.dm @@ -753,3 +753,4 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O pref.rlimb_data[organ] = null while(null in pref.rlimb_data) pref.rlimb_data -= null*/ + diff --git a/code/modules/client/preference_setup/general/04_equipment.dm b/code/modules/client/preference_setup/general/04_equipment.dm index 8e9a102ce3e..cecd8e97f5c 100644 --- a/code/modules/client/preference_setup/general/04_equipment.dm +++ b/code/modules/client/preference_setup/general/04_equipment.dm @@ -1,18 +1,20 @@ +/datum/preferences + var/list/all_underwear + var/list/all_underwear_metadata + /datum/category_item/player_setup_item/general/equipment name = "Equipment" sort_order = 4 /datum/category_item/player_setup_item/general/equipment/load_character(var/savefile/S) - S["underwear"] >> pref.underwear - S["undershirt"] >> pref.undershirt - S["socks"] >> pref.socks + S["all_underwear"] >> pref.all_underwear + S["all_underwear_metadata"] >> pref.all_underwear_metadata S["backbag"] >> pref.backbag S["backbag_style"] >> pref.backbag_style /datum/category_item/player_setup_item/general/equipment/save_character(var/savefile/S) - S["underwear"] << pref.underwear - S["undershirt"] << pref.undershirt - S["socks"] << pref.socks + S["all_underwear"] << pref.all_underwear + S["all_underwear_metadata"] << pref.all_underwear_metadata S["backbag"] << pref.backbag S["backbag_style"] << pref.backbag_style @@ -20,9 +22,8 @@ return list( "ss13_characters" = list( "vars" = list( - "underwear", - "undershirt", - "socks", + "all_underwear", + "all_underwear_metadata", "backbag", "backbag_style" ), @@ -36,9 +37,8 @@ /datum/category_item/player_setup_item/general/equipment/gather_save_query() return list( "ss13_characters" = list( - "underwear", - "undershirt", - "socks", + "all_underwear", + "all_underwear_metadata", "backbag", "backbag_style", "id" = 1, @@ -48,9 +48,8 @@ /datum/category_item/player_setup_item/general/equipment/gather_save_parameters() return list( - "underwear" = pref.underwear, - "undershirt" = pref.undershirt, - "socks" = pref.socks, + "all_underwear" = json_encode(pref.all_underwear), + "all_underwear_metadata" = json_encode(pref.all_underwear_metadata), "backbag" = pref.backbag, "backbag_style" = pref.backbag_style, "id" = pref.current_character, @@ -60,58 +59,87 @@ /datum/category_item/player_setup_item/general/equipment/sanitize_character(var/sql_load = 0) if (sql_load) pref.backbag = text2num(pref.backbag) + pref.backbag_style = text2num(pref.backbag_style) + if(istext(pref.all_underwear)) + var/before = pref.all_underwear + try + pref.all_underwear = json_decode(pref.all_underwear) + catch(var/exception/e) + log_debug("UNDERWEAR: Caught [e]. Initial value: [before]") + pref.all_underwear = list() + if(istext(pref.all_underwear_metadata)) + var/before = pref.all_underwear_metadata + try + pref.all_underwear_metadata = json_decode(pref.all_underwear_metadata) + catch(var/exception/e) + log_debug("UNDERWEAR METADATA: Caught [e]. Initial value: [before]") + pref.all_underwear_metadata = list() + + if(!istype(pref.all_underwear)) + pref.all_underwear = list() + + for(var/datum/category_group/underwear/WRC in global_underwear.categories) + for(var/datum/category_item/underwear/WRI in WRC.items) + if(WRI.is_default(pref.gender ? pref.gender : MALE)) + pref.all_underwear[WRC.name] = WRI.name + break + + if(!istype(pref.all_underwear_metadata)) + pref.all_underwear_metadata = list() + + for(var/underwear_category in pref.all_underwear) + var/datum/category_group/underwear/UWC = global_underwear.categories_by_name[underwear_category] + if(!UWC) + pref.all_underwear -= underwear_category + else + var/datum/category_item/underwear/UWI = UWC.items_by_name[pref.all_underwear[underwear_category]] + if(!UWI) + pref.all_underwear -= underwear_category + + for(var/underwear_metadata in pref.all_underwear_metadata) + if(!(underwear_metadata in pref.all_underwear)) + pref.all_underwear_metadata -= underwear_metadata pref.backbag = sanitize_integer(pref.backbag, 1, backbaglist.len, initial(pref.backbag)) pref.backbag_style = sanitize_integer(pref.backbag_style, 1, backbagstyles.len, initial(pref.backbag_style)) - var/undies = get_undies() - var/gender_socks = get_gender_socks() - if(!get_key_by_value(undies, pref.underwear)) - pref.underwear = null - if(!get_key_by_value(undershirt_t, pref.undershirt)) - pref.undershirt = undershirt_t[undershirt_t[1]] - if(!get_key_by_value(gender_socks, pref.socks)) - pref.socks = null - /datum/category_item/player_setup_item/general/equipment/content() - var/list/dat = list() - dat += "Equipment:
" - dat += "Underwear: [get_key_by_value(get_undies(),pref.underwear)]
" - dat += "Undershirt: [get_key_by_value(undershirt_t,pref.undershirt)]
" - dat += "Socks: [get_key_by_value(get_gender_socks(),pref.socks)]
" - dat += "Backpack Type: [backbaglist[pref.backbag]]
" - dat += "Backpack Style: [backbagstyles[pref.backbag_style]]
" + . = list() + . += "Equipment:
" + for(var/datum/category_group/underwear/UWC in global_underwear.categories) + var/item_name = pref.all_underwear[UWC.name] ? pref.all_underwear[UWC.name] : "None" + . += "[UWC.name]: [item_name]" - . = dat.Join() + var/datum/category_item/underwear/UWI = UWC.items_by_name[item_name] + if(UWI) + for(var/datum/gear_tweak/gt in UWI.tweaks) + . += " [gt.get_contents(get_metadata(UWC.name, gt))]" -/datum/category_item/player_setup_item/general/equipment/proc/get_undies() - return pref.gender == MALE ? underwear_m : underwear_f + . += "
" -/datum/category_item/player_setup_item/general/equipment/proc/get_gender_socks() - return pref.gender == MALE ? socks_m : socks_f + . += "Backpack Type: [backbaglist[pref.backbag]]
" + . += "Backpack Style: [backbagstyles[pref.backbag_style]]
" + + return jointext(., null) + +/datum/category_item/player_setup_item/general/equipment/proc/get_metadata(var/underwear_category, var/datum/gear_tweak/gt) + var/metadata = pref.all_underwear_metadata[underwear_category] + if(!metadata) + metadata = list() + pref.all_underwear_metadata[underwear_category] = metadata + + var/tweak_data = metadata["[gt]"] + if(!tweak_data) + tweak_data = gt.get_default() + metadata["[gt]"] = tweak_data + return tweak_data + +/datum/category_item/player_setup_item/general/equipment/proc/set_metadata(var/underwear_category, var/datum/gear_tweak/gt, var/new_metadata) + var/list/metadata = pref.all_underwear_metadata[underwear_category] + metadata["[gt]"] = new_metadata /datum/category_item/player_setup_item/general/equipment/OnTopic(var/href,var/list/href_list, var/mob/user) - if(href_list["change_underwear"]) - var/underwear_options = get_undies() - var/new_underwear = input(user, "Choose your character's underwear:", "Character Preference", get_key_by_value(get_undies(),pref.underwear)) as null|anything in underwear_options - if(!isnull(new_underwear) && CanUseTopic(user)) - pref.underwear = underwear_options[new_underwear] - return TOPIC_REFRESH - - else if(href_list["change_undershirt"]) - var/new_undershirt = input(user, "Choose your character's undershirt:", "Character Preference", get_key_by_value(undershirt_t,pref.undershirt)) as null|anything in undershirt_t - if(!isnull(new_undershirt) && CanUseTopic(user)) - pref.undershirt = undershirt_t[new_undershirt] - return TOPIC_REFRESH - - else if(href_list["change_socks"]) - var/socks_options = get_gender_socks() - var/new_socks = input(user, "Choose your character's socks:", "Character Preference", get_key_by_value(get_gender_socks(),pref.socks)) as null|anything in socks_options - if(!isnull(new_socks) && CanUseTopic(user)) - pref.socks = socks_options[new_socks] - return TOPIC_REFRESH - - else if(href_list["change_backpack"]) + if(href_list["change_backpack"]) var/new_backbag = input(user, "Choose your character's bag type:", "Character Preference", backbaglist[pref.backbag]) as null|anything in backbaglist if(!isnull(new_backbag) && CanUseTopic(user)) pref.backbag = backbaglist.Find(new_backbag) @@ -123,4 +151,25 @@ pref.backbag_style = backbagstyles.Find(new_backbag) return TOPIC_REFRESH + else if(href_list["change_underwear"]) + var/datum/category_group/underwear/UWC = global_underwear.categories_by_name[href_list["change_underwear"]] + if(!UWC) + return TOPIC_NOACTION + var/datum/category_item/underwear/selected_underwear = input(user, "Choose underwear:", "Character Preference", pref.all_underwear[UWC.name]) as null|anything in UWC.items + if(selected_underwear && CanUseTopic(user)) + pref.all_underwear[UWC.name] = selected_underwear.name + return TOPIC_REFRESH + else if(href_list["underwear"] && href_list["tweak"]) + var/underwear = href_list["underwear"] + if(!(underwear in pref.all_underwear)) + return TOPIC_NOACTION + var/datum/gear_tweak/gt = locate(href_list["tweak"]) + if(!gt) + return TOPIC_NOACTION + var/new_metadata = gt.get_metadata(usr, get_metadata(underwear, gt)) + if(new_metadata) + set_metadata(underwear, gt, new_metadata) + return TOPIC_REFRESH + return ..() + diff --git a/code/modules/client/preference_setup/loadout/gear_tweaks.dm b/code/modules/client/preference_setup/loadout/gear_tweaks.dm index 09c56ad1585..8798e7c6c44 100644 --- a/code/modules/client/preference_setup/loadout/gear_tweaks.dm +++ b/code/modules/client/preference_setup/loadout/gear_tweaks.dm @@ -20,8 +20,6 @@ Color adjustment */ -var/datum/gear_tweak/color/gear_tweak_free_color_choice = new() - /datum/gear_tweak/color var/list/valid_colors @@ -38,16 +36,15 @@ var/datum/gear_tweak/color/gear_tweak_free_color_choice = new() /datum/gear_tweak/color/get_random() return valid_colors ? pick(valid_colors) : COLOR_GRAY -/datum/gear_tweak/color/get_metadata(var/user, var/metadata) +/datum/gear_tweak/color/get_metadata(var/user, var/metadata, var/title = "Character Preference") if(valid_colors) - return input(user, "Choose an item color.", "Character Preference", metadata) as null|anything in valid_colors - return input(user, "Choose an item color.", "Global Preference", metadata) as color|null + return input(user, "Choose a color.", title, metadata) as null|anything in valid_colors + return input(user, "Choose a color.", title, metadata) as color|null /datum/gear_tweak/color/tweak_item(var/obj/item/I, var/metadata) if(valid_colors && !(metadata in valid_colors)) return - I.color = metadata - I.update_icon() + I.color = sanitize_hexcolor(metadata, I.color) /* Path adjustment diff --git a/code/modules/client/preference_setup/preference_setup.dm b/code/modules/client/preference_setup/preference_setup.dm index 14e130ca1b4..30425b9c960 100644 --- a/code/modules/client/preference_setup/preference_setup.dm +++ b/code/modules/client/preference_setup/preference_setup.dm @@ -132,6 +132,9 @@ var/sql_role = SQL_CHARACTER var/modified = 0 +/datum/category_group/player_setup_category/dd_SortValue() + return sort_order + /datum/category_group/player_setup_category/proc/sanitize_setup(sql_load = FALSE) for(var/datum/category_item/player_setup_item/PI in items) PI.sanitize_preferences(sql_load) @@ -220,6 +223,9 @@ pref = null return ..() +/datum/category_item/player_setup_item/dd_SortValue() + return sort_order + /datum/category_item/player_setup_item/proc/to_client_chat(str) if (pref && pref.client) to_chat(pref.client, str) diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm index 742d164f589..fe5ffc2d875 100644 --- a/code/modules/client/preferences.dm +++ b/code/modules/client/preferences.dm @@ -38,9 +38,6 @@ datum/preferences var/age = 30 //age of character var/spawnpoint = "Arrivals Shuttle" //where this character will spawn (0-2). var/b_type = "A+" //blood type (not-chooseable) - var/underwear //underwear type - var/undershirt //undershirt type - var/socks //socks type var/backbag = 2 //backpack type var/backbag_style = 1 var/h_style = "Bald" //Hair type @@ -372,11 +369,17 @@ datum/preferences character.sync_trait_prefs_to_mob(src) - character.underwear = underwear - - character.undershirt = undershirt - - character.socks = socks + character.all_underwear.Cut() + character.all_underwear_metadata.Cut() + for(var/underwear_category_name in all_underwear) + var/datum/category_group/underwear/underwear_category = global_underwear.categories_by_name[underwear_category_name] + if(underwear_category) + var/underwear_item_name = all_underwear[underwear_category_name] + character.all_underwear[underwear_category_name] = underwear_category.items_by_name[underwear_item_name] + if(all_underwear_metadata[underwear_category_name]) + character.all_underwear_metadata[underwear_category_name] = all_underwear_metadata[underwear_category_name] + else + all_underwear -= underwear_category_name if(backbag > 6 || backbag < 1) backbag = 1 //Same as above diff --git a/code/modules/mob/abstract/new_player/preferences_setup.dm b/code/modules/mob/abstract/new_player/preferences_setup.dm index 3e4113b890e..07beb73e7d9 100644 --- a/code/modules/mob/abstract/new_player/preferences_setup.dm +++ b/code/modules/mob/abstract/new_player/preferences_setup.dm @@ -1,5 +1,6 @@ /datum/preferences //The mob should have a gender you want before running this proc. Will run fine without H + /datum/preferences/proc/randomize_appearance_for(var/mob/living/carbon/human/H,var/random_gender=TRUE) if(random_gender) gender = pick(MALE, FEMALE) @@ -14,17 +15,6 @@ randomize_eyes_color() if(current_species.appearance_flags & HAS_SKIN_COLOR) randomize_skin_color(current_species) - if(current_species.appearance_flags & HAS_UNDERWEAR) - if(gender == FEMALE) - underwear = underwear_f[pick(underwear_f)] - else - underwear = underwear_m[pick(underwear_m)] - undershirt = undershirt_t[pick(undershirt_t)] - if(current_species.appearance_flags & HAS_SOCKS) - if(gender == FEMALE) - socks = socks_f[pick(socks_f)] - else - socks = socks_m[pick(socks_m)] h_style = random_hair_style(gender, species) f_style = random_facial_hair_style(gender, species) diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index ae9a4ee33d3..f24914d69ab 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -73,6 +73,10 @@ . = ..() + hide_underwear.Cut() + for(var/category in global_underwear.categories_by_name) + hide_underwear[category] = FALSE + if(dna) dna.ready_dna(src) dna.real_name = real_name @@ -1757,6 +1761,22 @@ if (doClickAction) ..() +/mob/living/carbon/human/verb/toggle_underwear() + set name = "Toggle Underwear" + set desc = "Shows/hides selected parts of your underwear." + set category = "Object" + + if(stat) + return + var/datum/category_group/underwear/UWC = input(usr, "Choose underwear:", "Show/hide underwear") as null|anything in global_underwear.categories + var/datum/category_item/underwear/UWI = all_underwear[UWC.name] + if(!UWI || UWI.name == "None") + to_chat(src, "You do not have [UWC.gender==PLURAL ? "[UWC.display_name]" : "any [UWC.display_name]"].") + return + hide_underwear[UWC.name] = !hide_underwear[UWC.name] + update_underwear(1) + to_chat(src, "You [hide_underwear[UWC.name] ? "take off" : "put on"] your [UWC.display_name].") + /mob/living/carbon/human/verb/pull_punches() set name = "Pull Punches" set desc = "Try not to hurt them." diff --git a/code/modules/mob/living/carbon/human/human_defines.dm b/code/modules/mob/living/carbon/human/human_defines.dm index b4840529a02..8b26c8a0cd9 100644 --- a/code/modules/mob/living/carbon/human/human_defines.dm +++ b/code/modules/mob/living/carbon/human/human_defines.dm @@ -32,9 +32,9 @@ var/age = 30 //Player's age (pure fluff) var/b_type = "A+" //Player's bloodtype - var/underwear = 1 //Which underwear the player wants - var/undershirt = 0 //Which undershirt the player wants. - var/socks = 0 //Which socks the player wants. + var/list/all_underwear = list() + var/list/all_underwear_metadata = list() + var/list/hide_underwear = list() var/backbag = 2 //Which backpack type the player has chosen. Nothing, Satchel or Backpack. var/backbag_style = 1 diff --git a/code/modules/mob/living/carbon/human/update_icons.dm b/code/modules/mob/living/carbon/human/update_icons.dm index 21ce4582870..12940e5cd36 100644 --- a/code/modules/mob/living/carbon/human/update_icons.dm +++ b/code/modules/mob/living/carbon/human/update_icons.dm @@ -308,20 +308,18 @@ There are several things that need to be remembered: update_icons() /mob/living/carbon/human/proc/update_underwear(update_icons = TRUE) - var/list/ovr + overlays_raw[UNDERWEAR_LAYER] = list() - if(underwear && (species.appearance_flags & HAS_UNDERWEAR)) - LAZYADD(ovr, SSicon_cache.get_state('icons/mob/human.dmi', "[underwear]")) + if(species.appearance_flags & HAS_UNDERWEAR) + for(var/category in all_underwear) + if(hide_underwear[category]) + continue + if(category == "Underwear, top" && hide_underwear["Undershirt"] == FALSE && !istype(all_underwear["Undershirt"], /datum/category_item/underwear/undershirt/none)) + continue //This piece of "code" is here to prevent tops from showing up over undershirts. + var/datum/category_item/underwear/UWI = all_underwear[category] + overlays_raw[UNDERWEAR_LAYER] += UWI.generate_image(all_underwear_metadata[category]) - if(undershirt && (species.appearance_flags & HAS_UNDERWEAR)) - LAZYADD(ovr, SSicon_cache.get_state('icons/mob/human.dmi', "[undershirt]")) - - if(socks && (species.appearance_flags & HAS_SOCKS)) - LAZYADD(ovr, SSicon_cache.get_state('icons/mob/human.dmi', "[socks]")) - - overlays_raw[UNDERWEAR_LAYER] = ovr - - if (update_icons) + if(update_icons) update_icons() // This proc generates & returns an icon representing a human's hair, using a cached icon from SSicon_cache if possible. @@ -1424,3 +1422,4 @@ There are several things that need to be remembered: #undef UNDERSCORE_OR_NULL #undef GET_BODY_TYPE #undef GET_TAIL_LAYER + diff --git a/html/changelogs/hot_sexy_lingerie_update.yml b/html/changelogs/hot_sexy_lingerie_update.yml new file mode 100644 index 00000000000..58d74725a5b --- /dev/null +++ b/html/changelogs/hot_sexy_lingerie_update.yml @@ -0,0 +1,44 @@ +################################ +# Example Changelog File +# +# Note: This file, and files beginning with ".", and files that don't end in ".yml" will not be read. If you change this file, you will look really dumb. +# +# Your changelog will be merged with a master changelog. (New stuff added only, and only on the date entry for the day it was merged.) +# When it is, any changes listed below will disappear. +# +# Valid Prefixes: +# bugfix +# wip (For works in progress) +# tweak +# soundadd +# sounddel +# rscadd (general adding of nice things) +# rscdel (general deleting of nice things) +# imageadd +# imagedel +# maptweak +# spellcheck (typo fixes) +# experiment +# balance +# admin +# backend +# security +# refactor +################################# + +# Your name. +author: Mwahahahaha, The Stryker + +# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again. +delete-after: True + +# Any changes you've made. See valid prefix list above. +# INDENT WITH TWO SPACES. NOT TABS. SPACES. +# SCREW THIS UP AND IT WON'T WORK. +# Also, all entries are changed into a single [] after a master changelog generation. Just remove the brackets when you add new entries. +# Please surround your changes in double quotes ("), as certain characters otherwise screws up compiling. The quotes will not show up in the changelog. +changes: + - rscadd: "Splits the underwear into top and bottom pieces." + - rscadd: "Allows underwear to be removed." + - rscadd: "Ports some many more underwear, undershirt, socks styles from BS12, Polaris, tg, as well as some made by The Stryker, using this new system." + - bugfix: "Backpack styles (job-specific or grey) no longer keep changing back to job-specific." \ No newline at end of file diff --git a/icons/mob/human.dmi b/icons/mob/human.dmi index ffe2d44ae9e..7ad330f892e 100644 Binary files a/icons/mob/human.dmi and b/icons/mob/human.dmi differ diff --git a/icons/mob/underwear.dmi b/icons/mob/underwear.dmi new file mode 100644 index 00000000000..405b1282948 Binary files /dev/null and b/icons/mob/underwear.dmi differ