diff --git a/code/__defines/dna.dm b/code/__defines/dna.dm index ecf85abcd9..10fe4d729b 100644 --- a/code/__defines/dna.dm +++ b/code/__defines/dna.dm @@ -99,37 +99,53 @@ var/SMALLSIZEBLOCK = 0 #define DNA_UI_BEARD_STYLE 15 #define DNA_UI_HAIR_STYLE 16 #define DNA_UI_EAR_STYLE 17 // VOREStation snippet. -#define DNA_UI_TAIL_STYLE 18 -#define DNA_UI_PLAYERSCALE 19 -#define DNA_UI_TAIL_R 20 -#define DNA_UI_TAIL_G 21 -#define DNA_UI_TAIL_B 22 -#define DNA_UI_TAIL2_R 23 -#define DNA_UI_TAIL2_G 24 -#define DNA_UI_TAIL2_B 25 -#define DNA_UI_TAIL3_R 26 -#define DNA_UI_TAIL3_G 27 -#define DNA_UI_TAIL3_B 28 -#define DNA_UI_EARS_R 29 -#define DNA_UI_EARS_G 30 -#define DNA_UI_EARS_B 31 -#define DNA_UI_EARS2_R 32 -#define DNA_UI_EARS2_G 33 -#define DNA_UI_EARS2_B 34 -#define DNA_UI_EARS3_R 35 -#define DNA_UI_EARS3_G 36 -#define DNA_UI_EARS3_B 37 -#define DNA_UI_WING_STYLE 38 -#define DNA_UI_WING_R 39 -#define DNA_UI_WING_G 40 -#define DNA_UI_WING_B 41 -#define DNA_UI_WING2_R 42 -#define DNA_UI_WING2_G 43 -#define DNA_UI_WING2_B 44 -#define DNA_UI_WING3_R 45 -#define DNA_UI_WING3_G 46 -#define DNA_UI_WING3_B 47 // VOREStation snippet end. -#define DNA_UI_LENGTH 47 // VOREStation Edit - Needs to match the highest number above. +#define DNA_UI_EAR_SECONDARY_STYLE 18 // VOREStation snippet. +#define DNA_UI_TAIL_STYLE 19 +#define DNA_UI_PLAYERSCALE 20 +#define DNA_UI_TAIL_R 21 +#define DNA_UI_TAIL_G 22 +#define DNA_UI_TAIL_B 23 +#define DNA_UI_TAIL2_R 24 +#define DNA_UI_TAIL2_G 25 +#define DNA_UI_TAIL2_B 26 +#define DNA_UI_TAIL3_R 27 +#define DNA_UI_TAIL3_G 28 +#define DNA_UI_TAIL3_B 29 + +#define DNA_UI_EARS_R 30 +#define DNA_UI_EARS_G 31 +#define DNA_UI_EARS_B 32 +#define DNA_UI_EARS2_R 33 +#define DNA_UI_EARS2_G 34 +#define DNA_UI_EARS2_B 35 +#define DNA_UI_EARS3_R 36 +#define DNA_UI_EARS3_G 37 +#define DNA_UI_EARS3_B 38 + +#define DNA_UI_EARS_SECONDARY_START 39 +#define DNA_UI_EARS_SECONDARY_COLOR_CHANNEL_COUNT 3 + +#define DNA_UI_EARS_SECONDARY_R 39 +#define DNA_UI_EARS_SECONDARY_G 40 +#define DNA_UI_EARS_SECONDARY_B 41 +#define DNA_UI_EARS_SECONDARY2_R 42 +#define DNA_UI_EARS_SECONDARY2_G 43 +#define DNA_UI_EARS_SECONDARY2_B 44 +#define DNA_UI_EARS_SECONDARY3_R 45 +#define DNA_UI_EARS_SECONDARY3_G 46 +#define DNA_UI_EARS_SECONDARY3_B 47 + +#define DNA_UI_WING_STYLE 48 +#define DNA_UI_WING_R 49 +#define DNA_UI_WING_G 50 +#define DNA_UI_WING_B 51 +#define DNA_UI_WING2_R 52 +#define DNA_UI_WING2_G 53 +#define DNA_UI_WING2_B 54 +#define DNA_UI_WING3_R 55 +#define DNA_UI_WING3_G 56 +#define DNA_UI_WING3_B 57 // VOREStation snippet end. +#define DNA_UI_LENGTH 57 // VOREStation Edit - Needs to match the highest number above. #define DNA_SE_LENGTH 49 // VOREStation Edit (original was UI+11) diff --git a/code/game/dna/dna2.dm b/code/game/dna/dna2.dm index 5e78698f48..2a686e0a9a 100644 --- a/code/game/dna/dna2.dm +++ b/code/game/dna/dna2.dm @@ -139,6 +139,10 @@ var/global/list/datum/dna/gene/dna_genes[0] if(character.ear_style) ear_style = ear_styles_list.Find(character.ear_style.type) + var/ear_secondary_style = 0 + if(character.ear_secondary_style) + ear_secondary_style = ear_styles_list.Find(character.ear_secondary_style.type) + // Demi Tails var/tail_style = 0 if(character.tail_style) @@ -170,10 +174,11 @@ var/global/list/datum/dna/gene/dna_genes[0] src.digitigrade = character.digitigrade // +1 to account for the none-of-the-above possibility - SetUIValueRange(DNA_UI_EAR_STYLE, ear_style + 1, ear_styles_list.len + 1, 1) - SetUIValueRange(DNA_UI_TAIL_STYLE, tail_style + 1, tail_styles_list.len + 1, 1) - SetUIValueRange(DNA_UI_PLAYERSCALE, size_multiplier, player_sizes_list.len, 1) - SetUIValueRange(DNA_UI_WING_STYLE, wing_style + 1, wing_styles_list.len + 1, 1) + SetUIValueRange(DNA_UI_EAR_STYLE, ear_style + 1, ear_styles_list.len + 1, 1) + SetUIValueRange(DNA_UI_EAR_SECONDARY_STYLE, ear_secondary_style + 1, ear_styles_list.len + 1, 1) + SetUIValueRange(DNA_UI_TAIL_STYLE, tail_style + 1, tail_styles_list.len + 1, 1) + SetUIValueRange(DNA_UI_PLAYERSCALE, size_multiplier, player_sizes_list.len, 1) + SetUIValueRange(DNA_UI_WING_STYLE, wing_style + 1, wing_styles_list.len + 1, 1) SetUIValueRange(DNA_UI_TAIL_R, character.r_tail, 255, 1) SetUIValueRange(DNA_UI_TAIL_G, character.g_tail, 255, 1) @@ -211,6 +216,15 @@ var/global/list/datum/dna/gene/dna_genes[0] SetUIValueRange(DNA_UI_EARS3_G, character.g_ears3, 255, 1) SetUIValueRange(DNA_UI_EARS3_B, character.b_ears3, 255, 1) + for(var/channel in 1 to DNA_UI_EARS_SECONDARY_COLOR_CHANNEL_COUNT) + var/offset = DNA_UI_EARS_SECONDARY_START + (channel - 1) * 3 + var/list/read_rgb = ReadRGB(LAZYACCESS(character.ear_secondary_colors, channel) || "#ffffff") + var/red = read_rgb[1] + var/green = read_rgb[2] + var/blue = read_rgb[3] + SetUIValueRange(offset, red, 255, 1) + SetUIValueRange(offset + 1, green, 255, 1) + SetUIValueRange(offset + 2, blue, 255, 1) // VORE Station Edit End SetUIValueRange(DNA_UI_HAIR_R, character.r_hair, 255, 1) diff --git a/code/game/dna/dna2_helpers.dm b/code/game/dna/dna2_helpers.dm index 9b57cd87e1..e7b68fdfe5 100644 --- a/code/game/dna/dna2_helpers.dm +++ b/code/game/dna/dna2_helpers.dm @@ -183,6 +183,11 @@ H.ear_style = null else if((0 < ears) && (ears <= ear_styles_list.len)) H.ear_style = ear_styles_list[ear_styles_list[ears]] + var/ears_secondary = dna.GetUIValueRange(DNA_UI_EAR_SECONDARY_STYLE, ear_styles_list.len + 1) - 1 + if(ears_secondary < 1) + H.ear_secondary_style = null + else if((0 < ears_secondary) && (ears_secondary <= ear_styles_list.len)) + H.ear_secondary_style = ear_styles_list[ear_styles_list[ears_secondary]] // Ear Color H.r_ears = dna.GetUIValueRange(DNA_UI_EARS_R, 255) @@ -195,6 +200,15 @@ H.g_ears3 = dna.GetUIValueRange(DNA_UI_EARS3_G, 255) H.b_ears3 = dna.GetUIValueRange(DNA_UI_EARS3_B, 255) + LAZYINITLIST(H.ear_secondary_colors) + H.ear_secondary_colors.len = max(length(H.ear_secondary_colors), DNA_UI_EARS_SECONDARY_COLOR_CHANNEL_COUNT) + for(var/channel in 1 to DNA_UI_EARS_SECONDARY_COLOR_CHANNEL_COUNT) + var/offset = DNA_UI_EARS_SECONDARY_START + (channel - 1) * 3 + H.ear_secondary_colors[channel] = rgb( + dna.GetUIValueRange(offset, 255), + dna.GetUIValueRange(offset + 1, 255), + dna.GetUIValueRange(offset + 2, 255), + ) //Tail var/tail = dna.GetUIValueRange(DNA_UI_TAIL_STYLE, tail_styles_list.len + 1) - 1 diff --git a/code/game/machinery/embedded_controller/embedded_controller_base.dm b/code/game/machinery/embedded_controller/embedded_controller_base.dm index 268bde37ce..4aeb8ba70b 100644 --- a/code/game/machinery/embedded_controller/embedded_controller_base.dm +++ b/code/game/machinery/embedded_controller/embedded_controller_base.dm @@ -28,7 +28,7 @@ /obj/machinery/embedded_controller/Topic() . = ..() - stack_trace("WARNING: Embedded controller [src] ([type]) had Topic() called unexpectedly. Please report this.") + // stack_trace("WARNING: Embedded controller [src] ([type]) had Topic() called unexpectedly. Please report this.") // statpanel means that topic can always be called for clicking /obj/machinery/embedded_controller/tgui_act(action, params) if(..()) @@ -106,4 +106,4 @@ /obj/machinery/embedded_controller/radio/proc/set_frequency(new_frequency) radio_controller.remove_object(src, frequency) frequency = new_frequency - radio_connection = radio_controller.add_object(src, frequency, radio_filter) \ No newline at end of file + radio_connection = radio_controller.add_object(src, frequency, radio_filter) diff --git a/code/modules/client/preference_setup/general/03_body.dm b/code/modules/client/preference_setup/general/03_body.dm index 8a5c5b4bca..abdecba39f 100644 --- a/code/modules/client/preference_setup/general/03_body.dm +++ b/code/modules/client/preference_setup/general/03_body.dm @@ -17,6 +17,15 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O var/r_ears3 = 30 // Ear tertiary color. var/g_ears3 = 30 // Ear tertiary color var/b_ears3 = 30 // Ear tertiary color + + /// The typepath of the character's selected secondary ears. + var/ear_secondary_style + /// The color channels for the character's selected secondary ears + /// + /// * This is a lazy list. Its length, when populated, should but cannot be assumed + /// to be the number of color channels supported by the secondary ear style. + var/list/ear_secondary_colors = list() + var/tail_style // Type of selected tail style var/r_tail = 30 // Tail/Taur color var/g_tail = 30 // Tail/Taur color @@ -27,6 +36,7 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O var/r_tail3 = 30 // For tertiary overlay. var/g_tail3 = 30 // For tertiary overlay. var/b_tail3 = 30 // For tertiary overlay. + var/wing_style // Type of selected wing style var/r_wing = 30 // Wing color var/g_wing = 30 // Wing color @@ -37,6 +47,7 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O var/r_wing3 = 30 // Wing tertiary color var/g_wing3 = 30 // Wing tertiary color var/b_wing3 = 30 // Wing tertiary color + var/datum/browser/markings_subwindow = null // Sanitize ear/wing/tail styles @@ -59,6 +70,8 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O // Sanitize for non-existent keys. if(ear_style && !(ear_style in get_available_styles(global.ear_styles_list))) ear_style = null + if(ear_secondary_style && !(ear_secondary_style in get_available_styles(global.ear_styles_list))) + ear_secondary_style = null if(wing_style && !(wing_style in get_available_styles(global.wing_styles_list))) wing_style = null if(tail_style && !(tail_style in get_available_styles(global.tail_styles_list))) @@ -137,6 +150,8 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O pref.r_ears3 = save_data["r_ears3"] pref.g_ears3 = save_data["g_ears3"] pref.b_ears3 = save_data["b_ears3"] + pref.ear_secondary_style = save_data["ear_secondary_style"] + pref.ear_secondary_colors = save_data["ear_secondary_colors"] pref.tail_style = save_data["tail_style"] pref.r_tail = save_data["r_tail"] pref.g_tail = save_data["g_tail"] @@ -207,6 +222,8 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O save_data["r_ears3"] = pref.r_ears3 save_data["g_ears3"] = pref.g_ears3 save_data["b_ears3"] = pref.b_ears3 + save_data["ear_secondary_style"] = pref.ear_secondary_style + save_data["ear_secondary_colors"] = pref.ear_secondary_colors save_data["tail_style"] = pref.tail_style save_data["r_tail"] = pref.r_tail save_data["g_tail"] = pref.g_tail @@ -274,6 +291,14 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O pref.r_ears3 = sanitize_integer(pref.r_ears3, 0, 255, initial(pref.r_ears3)) pref.g_ears3 = sanitize_integer(pref.g_ears3, 0, 255, initial(pref.g_ears3)) pref.b_ears3 = sanitize_integer(pref.b_ears3, 0, 255, initial(pref.b_ears3)) + + // sanitize secondary ears + pref.ear_secondary_colors = SANITIZE_LIST(pref.ear_secondary_colors) + if(length(pref.ear_secondary_colors) > length(GLOB.fancy_sprite_accessory_color_channel_names)) + pref.ear_secondary_colors.len = length(GLOB.fancy_sprite_accessory_color_channel_names) + for(var/i in 1 to length(pref.ear_secondary_colors)) + pref.ear_secondary_colors[i] = sanitize_hexcolor(pref.ear_secondary_colors[i], "#ffffff") + pref.r_tail = sanitize_integer(pref.r_tail, 0, 255, initial(pref.r_tail)) pref.g_tail = sanitize_integer(pref.g_tail, 0, 255, initial(pref.g_tail)) pref.b_tail = sanitize_integer(pref.b_tail, 0, 255, initial(pref.b_tail)) @@ -348,6 +373,10 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O character.b_ears3 = pref.b_ears3 character.g_ears3 = pref.g_ears3 + // apply secondary ears; sanitize again to prevent runtimes in rendering + character.ear_secondary_style = ear_styles[pref.ear_secondary_style] + character.ear_secondary_colors = SANITIZE_LIST(pref.ear_secondary_colors) + var/list/tail_styles = pref.get_available_styles(global.tail_styles_list) character.tail_style = tail_styles[pref.tail_style] character.r_tail = pref.r_tail @@ -623,6 +652,15 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O else . += " Style: Select
" + var/datum/sprite_accessory/ears/ears_secondary = ear_styles[pref.ear_secondary_style] + . += span_bold("Horns") + "
" + if(istype(ears_secondary)) + . += " Style: [ears_secondary.name]
" + for(var/channel in 1 to min(ears_secondary.get_color_channel_count(), length(GLOB.fancy_sprite_accessory_color_channel_names))) + . += "Change [GLOB.fancy_sprite_accessory_color_channel_names[channel]] Color [color_square(hex = LAZYACCESS(pref.ear_secondary_colors, channel) || "#ffffff")]
" + else + . += " Style: Select
" + var/list/tail_styles = pref.get_available_styles(global.tail_styles_list) var/datum/sprite_accessory/tail/tail = tail_styles[pref.tail_style] . += span_bold("Tail") + "
" @@ -1264,6 +1302,32 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O pref.b_ears3 = hex2num(copytext(new_earc3, 6, 8)) return TOPIC_REFRESH_UPDATE_PREVIEW + else if(href_list["ear_secondary_style"]) + var/new_style = tgui_input_list(user, "Select an ear style for this character:", "Character Preference", pref.get_available_styles(global.ear_styles_list), pref.ear_secondary_style) + if(!new_style) + return TOPIC_NOACTION + pref.ear_secondary_style = new_style + return TOPIC_REFRESH_UPDATE_PREVIEW + else if(href_list["ear_secondary_color"]) + var/channel = text2num(href_list["ear_secondary_color"]) + // very important sanity check; this makes sure someone can't crash the server by setting channel to some insanely high value + if(channel > GLOB.fancy_sprite_accessory_color_channel_names.len) + return TOPIC_NOACTION + // this would say 'secondary ears' but you'd get 'choose your character's primary secondary ear colour' which sounds silly + var/new_color = input( + user, + "Choose your character's [lowertext(GLOB.fancy_sprite_accessory_color_channel_names[channel])] ear colour:", + "Secondary Ear Coloration", + LAZYACCESS(pref.ear_secondary_colors, channel) || "#ffffff", + ) as color | null + if(!new_color) + return TOPIC_NOACTION + // ensures color channel list is at least that long + // the upper bound is to have a secondary safety check because list index set is a dangerous call + pref.ear_secondary_colors.len = clamp(length(pref.ear_secondary_colors), channel, length(GLOB.fancy_sprite_accessory_color_channel_names)) + pref.ear_secondary_colors[channel] = new_color + return TOPIC_REFRESH_UPDATE_PREVIEW + else if(href_list["tail_style"]) var/new_tail_style = tgui_input_list(user, "Select a tail style for this character:", "Character Preference", pref.get_available_styles(global.tail_styles_list), pref.tail_style) if(new_tail_style) diff --git a/code/modules/client/preference_setup/loadout/loadout_accessories.dm b/code/modules/client/preference_setup/loadout/loadout_accessories.dm index 18cd673d5f..d22bdcc20e 100644 --- a/code/modules/client/preference_setup/loadout/loadout_accessories.dm +++ b/code/modules/client/preference_setup/loadout/loadout_accessories.dm @@ -568,4 +568,12 @@ Talon pin "Studded Belt" = /obj/item/clothing/accessory/belt/studded ) gear_tweaks += new/datum/gear_tweak/path(wristband_lists) - gear_tweaks += gear_tweak_free_color_choice \ No newline at end of file + gear_tweaks += gear_tweak_free_color_choice + +/datum/gear/accessory/bunny_tail + display_name = "bunny tail, colorable" + path = /obj/item/clothing/accessory/bunny_tail + +/datum/gear/accessory/bunny_tail/New() + ..() + gear_tweaks += gear_tweak_free_color_choice diff --git a/code/modules/client/preference_setup/loadout/loadout_head.dm b/code/modules/client/preference_setup/loadout/loadout_head.dm index 070502d772..c5a80a9e67 100644 --- a/code/modules/client/preference_setup/loadout/loadout_head.dm +++ b/code/modules/client/preference_setup/loadout/loadout_head.dm @@ -239,6 +239,10 @@ display_name = "rabbit ears" path = /obj/item/clothing/head/rabbitears +/datum/gear/head/rabbit/New() + ..() + gear_tweaks += gear_tweak_free_color_choice + /datum/gear/head/beanie display_name = "beanie" path = /obj/item/clothing/head/beanie diff --git a/code/modules/client/preference_setup/loadout/loadout_uniform.dm b/code/modules/client/preference_setup/loadout/loadout_uniform.dm index 32157af5eb..c7803fc0e9 100644 --- a/code/modules/client/preference_setup/loadout/loadout_uniform.dm +++ b/code/modules/client/preference_setup/loadout/loadout_uniform.dm @@ -635,3 +635,22 @@ "black tabard-dress"=/obj/item/clothing/under/dress/tabard/black ) gear_tweaks += list(new/datum/gear_tweak/path(tabarddress)) + +//bunny suits + +/datum/gear/uniform/bunnysuit + display_name = "bunny suit selection, colorable" + path = /obj/item/clothing/under/bunnysuit + +/datum/gear/uniform/bunnysuit/New() + ..() + var/list/bunnysuit = list( + "bunnysuit"=/obj/item/clothing/under/bunnysuit, + "maid bunnysuit"=/obj/item/clothing/under/bunnysuit_maid, + "reverse bunnysuit"=/obj/item/clothing/under/reverse_bunnysuit, + "maid reverse bunnysuit"=/obj/item/clothing/under/reverse_bunnysuit_maid, + "reverse bunnysuit, no legs"=/obj/item/clothing/under/reverse_bunnytop, + "maid reverse bunnysuit, no legs"=/obj/item/clothing/under/reverse_bunnytop_maid + ) + gear_tweaks += list(new/datum/gear_tweak/path(bunnysuit)) + gear_tweaks += gear_tweak_free_color_choice diff --git a/code/modules/clothing/accessories/accessory_vr.dm b/code/modules/clothing/accessories/accessory_vr.dm index 7b68ced88a..4c8e2c6143 100644 --- a/code/modules/clothing/accessories/accessory_vr.dm +++ b/code/modules/clothing/accessories/accessory_vr.dm @@ -1033,3 +1033,13 @@ desc = "A studded belt for holding your pants up and looking cool." icon_state = "belt_studded" item_state = "belt_studded" + +/obj/item/clothing/accessory/bunny_tail + name = "Bunny Tail" + desc = "A little fluffy bunny tail to spice up your outfit." + icon = 'icons/inventory/accessory/item.dmi' + icon_override = 'icons/inventory/accessory/mob.dmi' + icon_state = "bunny_tail" + item_state = "bunny_tail" + slot_flags = SLOT_TIE | SLOT_BELT + slot = ACCESSORY_SLOT_DECOR diff --git a/code/modules/clothing/clothing.dm b/code/modules/clothing/clothing.dm index c416698a64..125b70ac82 100644 --- a/code/modules/clothing/clothing.dm +++ b/code/modules/clothing/clothing.dm @@ -465,6 +465,7 @@ var/light_overlay = "helmet_light" var/image/helmet_light + var/overhead = 0 //Used by spacesuit helmets sprite_sheets = list( SPECIES_TESHARI = 'icons/inventory/head/mob_teshari.dmi', diff --git a/code/modules/clothing/head/helmet.dm b/code/modules/clothing/head/helmet.dm index 4106d577af..7af3597928 100644 --- a/code/modules/clothing/head/helmet.dm +++ b/code/modules/clothing/head/helmet.dm @@ -16,6 +16,7 @@ ear_protection = 1 drop_sound = 'sound/items/drop/helm.ogg' pickup_sound = 'sound/items/pickup/helm.ogg' + overhead = TRUE /obj/item/clothing/head/helmet/solgov name = "\improper Solar Confederate Government helmet" diff --git a/code/modules/clothing/spacesuits/spacesuits.dm b/code/modules/clothing/spacesuits/spacesuits.dm index b70ddc6a57..0a434e3b65 100644 --- a/code/modules/clothing/spacesuits/spacesuits.dm +++ b/code/modules/clothing/spacesuits/spacesuits.dm @@ -31,6 +31,44 @@ light_overlay = "helmet_light" light_range = 4 + overhead = TRUE // prevents stacking helmets indefinitely + var/obj/item/clothing/head/stored_under_head = null // under head + var/mob/living/carbon/human/wearer = null // Used to restore our under when we're dropped + +/obj/item/clothing/head/helmet/space/mob_can_equip(mob/user, slot, disable_warning = FALSE) + var/mob/living/carbon/human/H = user + if(H.head) + stored_under_head = H.head + if(!istype(stored_under_head)) + to_chat(user, "You are unable to wear \the [src] as \the [H.head] is in the way.") + stored_under_head = null + return 0 + if(stored_under_head.overhead) + to_chat(user, "You are unable to wear \the [src] as \the [H.head] is in the way.") + stored_under_head = null + return 0 + H.drop_from_inventory(stored_under_head) + stored_under_head.forceMove(src) + + if(!..()) + if(stored_under_head) + if(H.equip_to_slot_if_possible(stored_under_head, slot_head)) + stored_under_head = null + return 0 + if(stored_under_head) + to_chat(user, "You slip \the [src] on over \the [stored_under_head].") + wearer = H + return 1 + +/obj/item/clothing/head/helmet/space/dropped() + ..() + var/mob/living/carbon/human/H = wearer + if(stored_under_head) + if(!H.equip_to_slot_if_possible(stored_under_head, slot_head)) + stored_under_head.forceMove(get_turf(src)) + src.stored_under_head = null + wearer = null + /obj/item/clothing/head/helmet/space/Initialize() . = ..() if(camera_networks) diff --git a/code/modules/clothing/spacesuits/void/void.dm b/code/modules/clothing/spacesuits/void/void.dm index a8c4c0f53d..ce32a5cddb 100644 --- a/code/modules/clothing/spacesuits/void/void.dm +++ b/code/modules/clothing/spacesuits/void/void.dm @@ -91,11 +91,11 @@ boots.canremove = FALSE if(helmet) - if(H.head) - to_chat(M, "You are unable to deploy your suit's helmet as \the [H.head] is in the way.") - else if (H.equip_to_slot_if_possible(helmet, slot_head)) + if(H.equip_to_slot_if_possible(helmet, slot_head)) to_chat(M, "Your suit's helmet deploys with a hiss.") helmet.canremove = FALSE + else + to_chat(M, "You are unable to deploy your suit's helmet[H.head ? " because [H.head] is in the way." : ""].") if(tank) if(H.s_store) //In case someone finds a way. @@ -190,13 +190,12 @@ helmet.forceMove(src) playsound(src.loc, 'sound/machines/click2.ogg', 75, 1) else - if(H.head) - to_chat(H, span_danger("You cannot deploy your helmet while wearing \the [H.head].")) - return if(H.equip_to_slot_if_possible(helmet, slot_head)) helmet.canremove = FALSE to_chat(H, span_info("You deploy your suit helmet, sealing you off from the world.")) playsound(src.loc, 'sound/machines/click2.ogg', 75, 1) + else + to_chat(H, span_danger("You cannot deploy your helmet[H.head ? " while wearing \the [H.head]." : ""]")) /obj/item/clothing/suit/space/void/AltClick(mob/living/user) eject_tank() diff --git a/code/modules/clothing/under/miscellaneous.dm b/code/modules/clothing/under/miscellaneous.dm index 152b107ecf..83063a48b6 100644 --- a/code/modules/clothing/under/miscellaneous.dm +++ b/code/modules/clothing/under/miscellaneous.dm @@ -1723,3 +1723,36 @@ name = "fiendish dress" desc = "A red and black dress befitting someone from the dark pits themselves… Or someone way too edgy." icon_state = "fienddress" + +//bunny suits + +/obj/item/clothing/under/bunnysuit_maid + name = "bunny suit" + desc = "A black and white bunny suit, extremely skimpy. Tails and ears sold seperately." + icon_state = "bunnysuit_maid" + +/obj/item/clothing/under/bunnysuit + name = "bunny suit" + desc = "A bunny suit, extremely skimpy. Tails and ears sold seperately." + icon_state = "bunnysuit_colour" + + +/obj/item/clothing/under/reverse_bunnysuit + name = "reverse bunny suit" + desc = "A reverse bunny suit, literally just covers everything except the bits you're supposed to. Tails and ears sold seperately." + icon_state = "reverse_bunnysuit_colour" + +/obj/item/clothing/under/reverse_bunnysuit_maid + name = "reverse bunny suit" + desc = "A maid themed reverse bunny suit, literally just covers everything except the bits you're supposed to. Tails and ears sold seperately." + icon_state = "reverse_bunnysuit_maid" + +/obj/item/clothing/under/reverse_bunnytop + name = "reverse bunny suit" + desc = "A reverse bunny suit, literally just covers everything except the bits you're supposed to. Tails and ears sold seperately." + icon_state = "reverse_bunnytop_colour" + +/obj/item/clothing/under/reverse_bunnytop_maid + name = "reverse bunny suit" + desc = "A maid themed reverse bunny suit, literally just covers everything except the bits you're supposed to. Tails and ears sold seperately." + icon_state = "reverse_bunnytop_maid" diff --git a/code/modules/economy/vending_machines_vr.dm b/code/modules/economy/vending_machines_vr.dm index f8d5a98032..d6a58e7166 100644 --- a/code/modules/economy/vending_machines_vr.dm +++ b/code/modules/economy/vending_machines_vr.dm @@ -1540,6 +1540,14 @@ /obj/item/clothing/accessory/maid_arms = 3, /obj/item/clothing/head/headband/maid/modern = 3, /obj/item/clothing/accessory/maidcorset = 3, + /obj/item/clothing/under/bunnysuit = 3, + /obj/item/clothing/under/bunnysuit_maid = 3, + /obj/item/clothing/under/reverse_bunnysuit = 3, + /obj/item/clothing/under/reverse_bunnysuit_maid = 3, + /obj/item/clothing/under/reverse_bunnytop = 3, + /obj/item/clothing/under/reverse_bunnytop_maid = 3, + /obj/item/clothing/head/rabbitears = 3, + /obj/item/clothing/accessory/bunny_tail = 3, /obj/item/clothing/suit/shrine_maiden = 3) prices = list(/obj/item/clothing/suit/storage/hooded/costume/carp = 200, /obj/item/clothing/suit/storage/hooded/costume/carp = 200, @@ -1617,6 +1625,14 @@ /obj/item/clothing/accessory/maid_arms = 25, /obj/item/clothing/head/headband/maid/modern = 25, /obj/item/clothing/accessory/maidcorset = 25, + /obj/item/clothing/under/bunnysuit = 50, + /obj/item/clothing/under/bunnysuit_maid = 50, + /obj/item/clothing/under/reverse_bunnysuit = 50, + /obj/item/clothing/under/reverse_bunnysuit_maid = 50, + /obj/item/clothing/under/reverse_bunnytop = 50, + /obj/item/clothing/under/reverse_bunnytop_maid = 50, + /obj/item/clothing/head/rabbitears = 25, + /obj/item/clothing/accessory/bunny_tail = 25, /obj/item/clothing/suit/shrine_maiden = 200) premium = list(/obj/item/clothing/suit/imperium_monk = 3, /obj/item/clothing/suit/barding/agatha = 2, diff --git a/code/modules/mob/dead/corpse.dm b/code/modules/mob/dead/corpse.dm index 7b6856137a..cab2a71147 100644 --- a/code/modules/mob/dead/corpse.dm +++ b/code/modules/mob/dead/corpse.dm @@ -31,6 +31,9 @@ var/list/random_species_list = list(SPECIES_HUMAN,SPECIES_TAJ,SPECIES_UNATHI,SPECIES_SKRELL) var/list/tail_type = null var/list/ear_type = null + /// list(name of ear, color of ear, color of ear, ...). + /// Color is optional, each position after the name is a color channel from 1 to n. + var/list/ear_secondary_type var/list/wing_type = null var/corpsesynthtype = 0 // 0 for organic, 1 for drone, 2 for posibrain var/corpsesynthbrand = "Unbranded" @@ -85,6 +88,12 @@ M.g_ears3 = color_rgb_list[2] M.b_ears3 = color_rgb_list[3] M.update_hair() + // handle secondary ears + if(length(ear_secondary_type) && (ear_secondary_type[1] in global.ear_styles_list)) + M.ear_secondary_style = global.ear_styles_list[ear_secondary_type[1]] + if(length(ear_secondary_type) > 1) + M.ear_secondary_colors = ear_secondary_type.Copy(2, min(length(GLOB.fancy_sprite_accessory_color_channel_names), length(ear_secondary_type)) + 1) + if(wing_type && wing_type.len) if(wing_type[1] in wing_styles_list) M.wing_style = wing_styles_list[wing_type[1]] diff --git a/code/modules/mob/living/carbon/human/human_defines.dm b/code/modules/mob/living/carbon/human/human_defines.dm index 5b816be294..d182593d1f 100644 --- a/code/modules/mob/living/carbon/human/human_defines.dm +++ b/code/modules/mob/living/carbon/human/human_defines.dm @@ -135,6 +135,12 @@ var/r_ears3 = 30 //Trust me, we could always use more colour. No japes. var/g_ears3 = 30 var/b_ears3 = 30 + + /// secondary ears sprite accessory reference + var/datum/sprite_accessory/ears/ear_secondary_style + /// secondary ears color channels; can be null, or a list of #aabbcc hexcolors + var/list/ear_secondary_colors + var/datum/sprite_accessory/tail/tail_style = null var/r_tail = 30 var/g_tail = 30 @@ -164,4 +170,4 @@ var/block_hud - var/phobias //For holding a list of phobias \ No newline at end of file + var/phobias //For holding a list of phobias diff --git a/code/modules/mob/living/carbon/human/species/lleill/hanner.dm b/code/modules/mob/living/carbon/human/species/lleill/hanner.dm index 8b7e2b98f8..39fb9f749a 100644 --- a/code/modules/mob/living/carbon/human/species/lleill/hanner.dm +++ b/code/modules/mob/living/carbon/human/species/lleill/hanner.dm @@ -87,6 +87,7 @@ /mob/living/carbon/human/proc/shapeshifter_select_wings, /mob/living/carbon/human/proc/shapeshifter_select_tail, /mob/living/carbon/human/proc/shapeshifter_select_ears, + /mob/living/carbon/human/proc/shapeshifter_select_secondary_ears, /mob/living/carbon/human/proc/shapeshifter_select_eye_colour, /mob/living/proc/set_size, // /mob/living/carbon/human/proc/lleill_contact, diff --git a/code/modules/mob/living/carbon/human/species/lleill/lleill.dm b/code/modules/mob/living/carbon/human/species/lleill/lleill.dm index 8c6e206555..444139ce21 100644 --- a/code/modules/mob/living/carbon/human/species/lleill/lleill.dm +++ b/code/modules/mob/living/carbon/human/species/lleill/lleill.dm @@ -82,6 +82,7 @@ /mob/living/carbon/human/proc/shapeshifter_select_wings, /mob/living/carbon/human/proc/shapeshifter_select_tail, /mob/living/carbon/human/proc/shapeshifter_select_ears, + /mob/living/carbon/human/proc/shapeshifter_select_secondary_ears, /mob/living/proc/set_size, // /mob/living/carbon/human/proc/lleill_invisibility, // /mob/living/carbon/human/proc/lleill_transmute, diff --git a/code/modules/mob/living/carbon/human/species/species_shapeshift_vr.dm b/code/modules/mob/living/carbon/human/species/species_shapeshift_vr.dm index 88074be3d4..58b4a6d045 100644 --- a/code/modules/mob/living/carbon/human/species/species_shapeshift_vr.dm +++ b/code/modules/mob/living/carbon/human/species/species_shapeshift_vr.dm @@ -56,6 +56,37 @@ update_hair() //Includes Virgo ears +/mob/living/carbon/human/proc/shapeshifter_select_secondary_ears() + set name = "Select Secondary Ears" + set category = "Abilities" + + if(stat || world.time < last_special) + return + last_special = world.time + 1 SECONDS + + // Construct the list of names allowed for this user. + var/list/pretty_ear_styles = list("Normal" = null) + for(var/path in ear_styles_list) + var/datum/sprite_accessory/ears/instance = ear_styles_list[path] + if((!instance.ckeys_allowed) || (ckey in instance.ckeys_allowed)) + pretty_ear_styles[instance.name] = path + + // Handle style pick + var/new_ear_style = tgui_input_list(src, "Pick some ears!", "Character Preference", pretty_ear_styles) + if(!new_ear_style) + return + ear_secondary_style = ear_styles_list[pretty_ear_styles[new_ear_style]] + + // Handle color picks + var/list/new_colors = list() + for(var/channel in 1 to ear_secondary_style.get_color_channel_count()) + var/channel_name = GLOB.fancy_sprite_accessory_color_channel_names[channel] + var/default = LAZYACCESS(ear_secondary_colors, channel) || "#ffffff" + var/new_color = input(usr, "Pick [channel_name]", "Ear Color ([channel_name])", default) as color | null + new_colors += new_color || default + + update_hair() + /mob/living/carbon/human/proc/shapeshifter_select_tail() set name = "Select Tail" set category = "Abilities" diff --git a/code/modules/mob/living/carbon/human/species/station/prometheans_vr.dm b/code/modules/mob/living/carbon/human/species/station/prometheans_vr.dm index eb6fe5fd7b..113c3c73ed 100644 --- a/code/modules/mob/living/carbon/human/species/station/prometheans_vr.dm +++ b/code/modules/mob/living/carbon/human/species/station/prometheans_vr.dm @@ -31,6 +31,7 @@ /mob/living/carbon/human/proc/shapeshifter_select_wings, /mob/living/carbon/human/proc/shapeshifter_select_tail, /mob/living/carbon/human/proc/shapeshifter_select_ears, + /mob/living/carbon/human/proc/shapeshifter_select_secondary_ears, /mob/living/carbon/human/proc/prommie_blobform, /mob/living/proc/set_size, /mob/living/carbon/human/proc/promethean_select_opaqueness, diff --git a/code/modules/mob/living/carbon/human/species/station/protean_vr/protean_species.dm b/code/modules/mob/living/carbon/human/species/station/protean_vr/protean_species.dm index e582d2b4d7..2825cdf802 100755 --- a/code/modules/mob/living/carbon/human/species/station/protean_vr/protean_species.dm +++ b/code/modules/mob/living/carbon/human/species/station/protean_vr/protean_species.dm @@ -103,7 +103,8 @@ /mob/living/carbon/human/proc/shapeshifter_select_gender, /mob/living/carbon/human/proc/shapeshifter_select_wings, /mob/living/carbon/human/proc/shapeshifter_select_tail, - /mob/living/carbon/human/proc/shapeshifter_select_ears + /mob/living/carbon/human/proc/shapeshifter_select_ears, + /mob/living/carbon/human/proc/shapeshifter_select_secondary_ears, ) var/global/list/abilities = list() diff --git a/code/modules/mob/living/carbon/human/species/station/replicant_crew.dm b/code/modules/mob/living/carbon/human/species/station/replicant_crew.dm index d5d3ed3c04..c8e7b769c3 100644 --- a/code/modules/mob/living/carbon/human/species/station/replicant_crew.dm +++ b/code/modules/mob/living/carbon/human/species/station/replicant_crew.dm @@ -45,6 +45,7 @@ /mob/living/carbon/human/proc/shapeshifter_select_wings, /mob/living/carbon/human/proc/shapeshifter_select_tail, /mob/living/carbon/human/proc/shapeshifter_select_ears, + /mob/living/carbon/human/proc/shapeshifter_select_secondary_ears, /mob/living/carbon/human/proc/shapeshifter_select_eye_colour, /mob/living/proc/set_size ) diff --git a/code/modules/mob/living/carbon/human/species/virtual_reality/avatar.dm b/code/modules/mob/living/carbon/human/species/virtual_reality/avatar.dm index 3d549233c4..9f72a2621c 100644 --- a/code/modules/mob/living/carbon/human/species/virtual_reality/avatar.dm +++ b/code/modules/mob/living/carbon/human/species/virtual_reality/avatar.dm @@ -37,6 +37,7 @@ /mob/living/carbon/human/proc/shapeshifter_select_wings, /mob/living/carbon/human/proc/shapeshifter_select_tail, /mob/living/carbon/human/proc/shapeshifter_select_ears, + /mob/living/carbon/human/proc/shapeshifter_select_secondary_ears, /mob/living/proc/set_size, /mob/living/carbon/human/proc/regenerate, /mob/living/carbon/human/proc/promethean_select_opaqueness, diff --git a/code/modules/mob/living/carbon/human/update_icons.dm b/code/modules/mob/living/carbon/human/update_icons.dm index a592afd1c2..e90d7771ed 100644 --- a/code/modules/mob/living/carbon/human/update_icons.dm +++ b/code/modules/mob/living/carbon/human/update_icons.dm @@ -555,7 +555,8 @@ var/global/list/damage_icon_parts = list() //see UpdateDamageIcon() if(ears_s.Height() > face_standing.Height()) // Tol ears face_standing.Crop(1, 1, face_standing.Width(), ears_s.Height()) face_standing.Blend(ears_s, ICON_OVERLAY) - if(ear_style?.em_block) + // todo: these should be considered separately, but it'd take a slight refactor to how sprite acc's are rendered (or atleast ears) + if(ear_style?.em_block || ear_secondary_style?.em_block) em_block_ears = em_block_image_generic(image(ears_s)) var/image/semifinal = image(face_standing, layer = BODY_LAYER+HAIR_LAYER, "pixel_y" = head_organ.head_offset) @@ -1315,11 +1316,13 @@ var/global/list/damage_icon_parts = list() //see UpdateDamageIcon() /mob/living/carbon/human/proc/get_ears_overlay() //If you are FBP with ear style and didn't set a custom one var/datum/robolimb/model = isSynthetic() - if(istype(model) && model.includes_ears && !ear_style) + if(istype(model) && model.includes_ears && !ear_style && !ear_secondary_style) var/icon/ears_s = new/icon("icon" = synthetic.icon, "icon_state" = "ears") ears_s.Blend(rgb(src.r_ears, src.g_ears, src.b_ears), species.color_mult ? ICON_MULTIPLY : ICON_ADD) return ears_s + var/icon/rendered + if(ear_style && !(head && (head.flags_inv & BLOCKHEADHAIR))) var/icon/ears_s = new/icon("icon" = ear_style.icon, "icon_state" = ear_style.icon_state) if(ear_style.do_colouration) @@ -1334,9 +1337,29 @@ var/global/list/damage_icon_parts = list() //see UpdateDamageIcon() overlay.Blend(rgb(src.r_ears3, src.g_ears3, src.b_ears3), ear_style.color_blend_mode) ears_s.Blend(overlay, ICON_OVERLAY) qdel(overlay) - return ears_s - return null + rendered = ears_s + // todo: this is utterly horrible but i don't think i should be violently refactoring sprite acc rendering in a feature PR ~silicons + if(ear_secondary_style && !(head && (head.flags_inv & BLOCKHEADHAIR))) + var/icon/ears_s = new/icon("icon" = ear_secondary_style.icon, "icon_state" = ear_secondary_style.icon_state) + if(ear_secondary_style.do_colouration) + ears_s.Blend(LAZYACCESS(ear_secondary_colors, 1), ear_secondary_style.color_blend_mode) + if(ear_secondary_style.extra_overlay) + var/icon/overlay = new/icon("icon" = ear_secondary_style.icon, "icon_state" = ear_secondary_style.extra_overlay) + overlay.Blend(LAZYACCESS(ear_secondary_colors, 2), ear_secondary_style.color_blend_mode) + ears_s.Blend(overlay, ICON_OVERLAY) + qdel(overlay) + if(ear_secondary_style.extra_overlay2) //MORE COLOURS IS BETTERER + var/icon/overlay = new/icon("icon" = ear_secondary_style.icon, "icon_state" = ear_secondary_style.extra_overlay2) + overlay.Blend(LAZYACCESS(ear_secondary_colors, 3), ear_secondary_style.color_blend_mode) + ears_s.Blend(overlay, ICON_OVERLAY) + qdel(overlay) + if(!rendered) + rendered = ears_s + else + rendered.Blend(ears_s, ICON_OVERLAY) + + return rendered /mob/living/carbon/human/proc/get_tail_image() //If you are FBP with tail style and didn't set a custom one diff --git a/code/modules/mob/living/silicon/robot/life.dm b/code/modules/mob/living/silicon/robot/life.dm index 3f7a39f07e..fdc3060a44 100644 --- a/code/modules/mob/living/silicon/robot/life.dm +++ b/code/modules/mob/living/silicon/robot/life.dm @@ -375,7 +375,7 @@ /mob/living/silicon/robot/handle_light() if(lights_on) - set_light(integrated_light_power, 1, "#FFFFFF") + set_light(integrated_light_power, 1, robot_light_col) return TRUE else . = ..() diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm index 1e31fc297a..1610036f16 100644 --- a/code/modules/mob/living/silicon/robot/robot.dm +++ b/code/modules/mob/living/silicon/robot/robot.dm @@ -15,6 +15,7 @@ blocks_emissive = EMISSIVE_BLOCK_UNIQUE var/lights_on = 0 // Is our integrated light on? + var/robot_light_col = "#FFFFFF" var/used_power_this_tick = 0 var/sight_mode = 0 var/custom_name = "" diff --git a/code/modules/mob/living/silicon/robot/robot_ui.dm b/code/modules/mob/living/silicon/robot/robot_ui.dm index f7c0e31079..7262f45364 100644 --- a/code/modules/mob/living/silicon/robot/robot_ui.dm +++ b/code/modules/mob/living/silicon/robot/robot_ui.dm @@ -62,6 +62,7 @@ data["max_charge"] = R.cell?.maxcharge data["health"] = R.health data["max_health"] = R.getMaxHealth() + data["light_color"] = R.robot_light_col data["weapon_lock"] = R.weapon_lock @@ -111,6 +112,11 @@ var/mob/living/silicon/robot/R = host switch(action) + if("set_light_col") + var/new_color = params["value"] + if(findtext(new_color, GLOB.is_color)) + R.robot_light_col = new_color + . = TRUE if("select_module") R.pick_module() . = TRUE diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index d772f6d487..88247bdd07 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -534,8 +534,7 @@ onclose(usr, "[name]") if(href_list["flavor_change"]) update_flavor_text() -// ..() - return + return ..() /mob/proc/pull_damage() diff --git a/code/modules/mob/new_player/sprite_accessories.dm b/code/modules/mob/new_player/sprite_accessories.dm index e008f953aa..ffc6dcd1e0 100644 --- a/code/modules/mob/new_player/sprite_accessories.dm +++ b/code/modules/mob/new_player/sprite_accessories.dm @@ -17,6 +17,14 @@ conversion in savefile.dm */ +/** + * Color channel names; this is used in things like character setup, editors, etc. + * + * * The length of this is also used to sanitize color channel list lengths. This should never be longer than the + * maximum number of color channels possible across all sprite accessories. + */ +GLOBAL_LIST_INIT(fancy_sprite_accessory_color_channel_names, list("Primary", "Secondary", "Tertiary", "Quaternary")) + /datum/sprite_accessory var/icon // the icon file the accessory is located in @@ -44,6 +52,12 @@ var/list/hide_body_parts = list() //Uses organ tag defines. Bodyparts in this list do not have their icons rendered, allowing for more spriter freedom when doing taur/digitigrade stuff. +/** + * Gets the number of color channels we have. + */ +/datum/sprite_accessory/proc/get_color_channel_count() + return do_colouration ? 1 : 0 + /* //////////////////////////// / =--------------------= / diff --git a/code/modules/mob/new_player/sprite_accessories_ear.dm b/code/modules/mob/new_player/sprite_accessories_ear.dm index 2f27663571..6f7c326378 100644 --- a/code/modules/mob/new_player/sprite_accessories_ear.dm +++ b/code/modules/mob/new_player/sprite_accessories_ear.dm @@ -18,6 +18,18 @@ //species_allowed = list(SPECIES_EVENT1, SPECIES_EVENT2, SPECIES_EVENT3) //Removing Polaris whitelits, ones we need are defined in our files +/** + * Gets the number of color channels we have. + */ +/datum/sprite_accessory/ears/get_color_channel_count() + if(!do_colouration) + return 0 + . = 1 + if(extra_overlay) + . += 1 + if(extra_overlay2) + . += 1 + /datum/sprite_accessory/ears/shadekin name = "Shadekin Ears, colorable" desc = "" @@ -527,4 +539,4 @@ do_colouration = 1 color_blend_mode = ICON_MULTIPLY extra_overlay = "zorgoia_inner" - extra_overlay2 = "zorgoia_tips" \ No newline at end of file + extra_overlay2 = "zorgoia_tips" diff --git a/code/modules/reagents/reagents/vore_vr.dm b/code/modules/reagents/reagents/vore_vr.dm index 5277adf962..936f555cbc 100644 --- a/code/modules/reagents/reagents/vore_vr.dm +++ b/code/modules/reagents/reagents/vore_vr.dm @@ -203,7 +203,7 @@ var/drug_strength = 20 M.druggy = max(M.druggy, drug_strength) -/datum/reagent/drugs/bliss/overdose(var/mob/living/M as mob) +/datum/reagent/drugs/rainbow_toxin/overdose(var/mob/living/M as mob) if(prob_proc == TRUE && prob(20)) M.hallucination = max(M.hallucination, 5) prob_proc = FALSE diff --git a/code/modules/resleeving/designer.dm b/code/modules/resleeving/designer.dm index c3a220790b..72a7778e1d 100644 --- a/code/modules/resleeving/designer.dm +++ b/code/modules/resleeving/designer.dm @@ -148,6 +148,17 @@ temp["colorHref2"] = "ear_color2" styles["Ears"] = temp + temp = list("styleHref" = "ear_style", "style" = "Normal") + if(mannequin.ear_secondary_style) + temp["style"] = mannequin.ear_secondary_style.name + if(length(mannequin.ear_secondary_colors) >= 1) + temp["color"] = mannequin.ear_secondary_colors[1] + temp["colorHref"] = list("act" = "ear_secondary_color", "channel" = 1) + if(length(mannequin.ear_secondary_colors) >= 2) + temp["color"] = mannequin.ear_secondary_colors[2] + temp["colorHref"] = list("act" = "ear_secondary_color", "channel" = 2) + styles["Horns"] = temp + temp = list("styleHref" = "tail_style", "style" = "Normal") if(mannequin.tail_style) temp["style"] = mannequin.tail_style.name @@ -419,7 +430,15 @@ var/href_list = list() href_list["src"] = "\ref[src]" - href_list["[params["target_href"]]"] = params["target_value"] + var/list/target_href_maybe = params["target_href"] + // convert list-form inputs as needed + if(islist(target_href_maybe)) + href_list[target_href_maybe["act"]] = TRUE + for(var/key in target_href_maybe["params"]) + var/val = target_href_maybe["params"][key] + href_list[key] = "[val]" + else + href_list[target_href_maybe] = params["target_value"] var/datum/category_item/player_setup_item/to_use = (params["target_href"] in use_different_category) ? use_different_category[params["target_href"]] : B var/action = 0 diff --git a/code/modules/tgui/modules/appearance_changer.dm b/code/modules/tgui/modules/appearance_changer.dm index 9eeb4de664..eee72f9b38 100644 --- a/code/modules/tgui/modules/appearance_changer.dm +++ b/code/modules/tgui/modules/appearance_changer.dm @@ -191,6 +191,22 @@ update_dna() changed_hook(APPEARANCECHANGER_CHANGED_HAIRSTYLE) return TRUE + if("ear_secondary") + if(can_change(APPEARANCE_ALL_HAIR)) + var/datum/sprite_accessory/ears/instance = locate(params["ref"]) + if(params["clear"]) + instance = null + if(!istype(instance) && !params["clear"]) + return FALSE + target.ear_secondary_style = instance + if(!islist(target.ear_secondary_colors)) + target.ear_secondary_colors = list() + if(length(target.ear_secondary_colors) < instance.get_color_channel_count()) + target.ear_secondary_colors.len = instance.get_color_channel_count() + target.update_hair() + update_dna() + changed_hook(APPEARANCECHANGER_CHANGED_HAIRSTYLE) + return TRUE if("ears_color") if(can_change(APPEARANCE_HAIR_COLOR)) var/new_hair = input(usr, "Please select ear color.", "Ear Color", rgb(target.r_ears, target.g_ears, target.b_ears)) as color|null @@ -213,6 +229,19 @@ target.update_hair() changed_hook(APPEARANCECHANGER_CHANGED_HAIRCOLOR) return 1 + if("ears_secondary_color") + if(can_change(APPEARANCE_HAIR_COLOR)) + var/channel = params["channel"] + if(channel > length(target.ear_secondary_colors)) + return TRUE + var/existing = LAZYACCESS(target.ear_secondary_colors, channel) || "#ffffff" + var/new_color = input(usr, "Please select ear color.", "2nd Ear Color", existing) as color|null + if(new_color && can_still_topic(usr, state)) + target.ear_secondary_colors[channel] = new_color + update_dna() + target.update_hair() + changed_hook(APPEARANCECHANGER_CHANGED_HAIRCOLOR) + return TRUE if("tail") if(can_change(APPEARANCE_ALL_HAIR)) var/datum/sprite_accessory/tail/instance = locate(params["ref"]) @@ -406,6 +435,7 @@ // VOREStation Add - Ears/Tails/Wings data["ear_style"] = target.ear_style + data["ear_secondary_style"] = target.ear_secondary_style?.name data["tail_style"] = target.tail_style data["wing_style"] = target.wing_style var/list/markings_data[0] @@ -434,6 +464,12 @@ // VOREStation Add - Ears/Tails/Wings data["ears_color"] = rgb(target.r_ears, target.g_ears, target.b_ears) data["ears2_color"] = rgb(target.r_ears2, target.g_ears2, target.b_ears2) + + // secondary ear colors + var/list/ear_secondary_color_channels = target.ear_secondary_colors || list() + ear_secondary_color_channels.len = target.ear_secondary_style?.get_color_channel_count() || 0 + data["ear_secondary_colors"] = ear_secondary_color_channels + data["tail_color"] = rgb(target.r_tail, target.g_tail, target.b_tail) data["tail2_color"] = rgb(target.r_tail2, target.g_tail2, target.b_tail2) data["wing_color"] = rgb(target.r_wing, target.g_wing, target.b_wing) diff --git a/code/modules/vore/eating/belly_import.dm b/code/modules/vore/eating/belly_import.dm new file mode 100644 index 0000000000..18e750863f --- /dev/null +++ b/code/modules/vore/eating/belly_import.dm @@ -0,0 +1,1186 @@ +/datum/vore_look/proc/import_belly(mob/host) + var/panel_choice = tgui_input_list(usr, "Belly Import", "Pick an option", list("Import all bellies from VRDB","Import one belly from VRDB")) + if(!panel_choice) return + var/pickOne = FALSE + if(panel_choice == "Import one belly from VRDB") + pickOne = TRUE + var/input_file = input(usr,"Please choose a valid VRDB file to import from.","Belly Import") as file + var/input_data + try + input_data = json_decode(file2text(input_file)) + catch(var/exception/e) + tgui_alert_async(usr, "The supplied file contains errors: [e]", "Error!") + return FALSE + + if(!islist(input_data)) + tgui_alert_async(usr, "The supplied file was not a valid VRDB file.", "Error!") + return FALSE + + var/list/valid_names = list() + var/list/valid_lists = list() + var/list/updated = list() + + for(var/list/raw_list in input_data) + if(length(valid_names) >= BELLIES_MAX) break + if(!islist(raw_list)) continue + if(!istext(raw_list["name"])) continue + if(length(raw_list["name"]) > BELLIES_NAME_MAX || length(raw_list["name"]) < BELLIES_NAME_MIN) continue + if(raw_list["name"] in valid_names) continue + for(var/obj/belly/B in host.vore_organs) + if(lowertext(B.name) == lowertext(raw_list["name"])) + updated += raw_list["name"] + break + if(!pickOne && length(host.vore_organs)+length(valid_names)-length(updated) >= BELLIES_MAX) continue + valid_names += raw_list["name"] + valid_lists += list(raw_list) + + if(length(valid_names) == 0) + tgui_alert_async(usr, "The supplied VRDB file does not contain any valid bellies.", "Error!") + return FALSE + + if(pickOne) + var/picked = tgui_input_list(usr, "Belly Import", "Which belly?", valid_names) + if(!picked) return + for(var/B in valid_lists) + if(lowertext(picked) == lowertext(B["name"])) + valid_names = list(picked) + valid_lists = list(B) + break + if(picked in updated) + updated = list(picked) + else + updated = list() + + var/list/alert_msg = list() + if(length(valid_names)-length(updated) > 0) + alert_msg += "add [length(valid_names)-length(updated)] new bell[length(valid_names)-length(updated) == 1 ? "y" : "ies"]" + if(length(updated) > 0) + alert_msg += "update [length(updated)] existing bell[length(updated) == 1 ? "y" : "ies"]. Please make sure you have saved a copy of your existing bellies" + + var/confirm = tgui_alert(host, "WARNING: This will [jointext(alert_msg," and ")]. You can revert the import by using the Reload Prefs button under Preferences as long as you don't Save Prefs. Are you sure?","Import bellies?",list("Yes","Cancel")) + if(confirm != "Yes") return FALSE + + for(var/list/belly_data in valid_lists) + var/obj/belly/new_belly + for(var/obj/belly/existing_belly in host.vore_organs) + if(lowertext(existing_belly.name) == lowertext(belly_data["name"])) + new_belly = existing_belly + break + if(!new_belly && length(host.vore_organs) < BELLIES_MAX) + new_belly = new(host) + new_belly.name = belly_data["name"] + if(!new_belly) continue + + // Controls + if(istext(belly_data["mode"])) + var/new_mode = html_encode(belly_data["mode"]) + if(new_mode in new_belly.digest_modes) + new_belly.digest_mode = new_mode + + if(istext(belly_data["item_mode"])) + var/new_item_mode = html_encode(belly_data["item_mode"]) + if(new_item_mode in new_belly.item_digest_modes) + new_belly.item_digest_mode = new_item_mode + + if(isnum(belly_data["message_mode"])) + var/new_message_mode = belly_data["message_mode"] + if(new_message_mode == 0) + new_belly.message_mode = FALSE + if(new_message_mode == 1) + new_belly.message_mode = TRUE + + if(islist(belly_data["addons"])) + new_belly.mode_flags = 0 + //new_belly.slow_digestion = FALSE // Not implemented on virgo + //new_belly.speedy_mob_processing = FALSE // Not implemented on virgo + STOP_PROCESSING(SSbellies, new_belly) + // STOP_PROCESSING(SSobj, new_belly) // Not implemented on virgo + START_PROCESSING(SSbellies, new_belly) + for(var/addon in belly_data["addons"]) + new_belly.mode_flags += new_belly.mode_flag_list[addon] + /* Not implemented on virgo + switch(addon) + if("Slow Body Digestion") + new_belly.slow_digestion = TRUE + if("TURBO MODE") + new_belly.speedy_mob_processing = TRUE + STOP_PROCESSING(SSbellies, new_belly) + START_PROCESSING(SSobj, new_belly) + */ + + // Descriptions + if(istext(belly_data["desc"])) + var/new_desc = html_encode(belly_data["desc"]) + if(new_desc) + new_desc = readd_quotes(new_desc) + if(length(new_desc) > 0 && length(new_desc) <= BELLIES_DESC_MAX) + new_belly.desc = new_desc + + if(istext(belly_data["absorbed_desc"])) + var/new_absorbed_desc = html_encode(belly_data["absorbed_desc"]) + if(new_absorbed_desc) + new_absorbed_desc = readd_quotes(new_absorbed_desc) + if(length(new_absorbed_desc) > 0 && length(new_absorbed_desc) <= BELLIES_DESC_MAX) + new_belly.absorbed_desc = new_absorbed_desc + + if(istext(belly_data["vore_verb"])) + var/new_vore_verb = html_encode(belly_data["vore_verb"]) + if(new_vore_verb) + new_vore_verb = readd_quotes(new_vore_verb) + if(length(new_vore_verb) >= BELLIES_NAME_MIN && length(new_vore_verb) <= BELLIES_NAME_MAX) + new_belly.vore_verb = new_vore_verb + + if(istext(belly_data["release_verb"])) + var/new_release_verb = html_encode(belly_data["release_verb"]) + if(new_release_verb) + new_release_verb = readd_quotes(new_release_verb) + if(length(new_release_verb) >= BELLIES_NAME_MIN && length(new_release_verb) <= BELLIES_NAME_MAX) + new_belly.release_verb = new_release_verb + + if(islist(belly_data["digest_messages_prey"])) + var/new_digest_messages_prey = sanitize(jointext(belly_data["digest_messages_prey"],"\n\n"),MAX_MESSAGE_LEN * 1.5,0,0,0) + if(new_digest_messages_prey) + new_belly.set_messages(new_digest_messages_prey,"dmp", limit = MAX_MESSAGE_LEN / 4) + + if(islist(belly_data["digest_messages_owner"])) + var/new_digest_messages_owner = sanitize(jointext(belly_data["digest_messages_owner"],"\n\n"),MAX_MESSAGE_LEN * 1.5,0,0,0) + if(new_digest_messages_owner) + new_belly.set_messages(new_digest_messages_owner,"dmo", limit = MAX_MESSAGE_LEN / 4) + + if(islist(belly_data["absorb_messages_prey"])) + var/new_absorb_messages_prey = sanitize(jointext(belly_data["absorb_messages_prey"],"\n\n"),MAX_MESSAGE_LEN * 1.5,0,0,0) + if(new_absorb_messages_prey) + new_belly.set_messages(new_absorb_messages_prey,"amp", limit = MAX_MESSAGE_LEN / 4) + + if(islist(belly_data["absorb_messages_owner"])) + var/new_absorb_messages_owner = sanitize(jointext(belly_data["absorb_messages_owner"],"\n\n"),MAX_MESSAGE_LEN * 1.5,0,0,0) + if(new_absorb_messages_owner) + new_belly.set_messages(new_absorb_messages_owner,"amo", limit = MAX_MESSAGE_LEN / 4) + + if(islist(belly_data["unabsorb_messages_prey"])) + var/new_unabsorb_messages_prey = sanitize(jointext(belly_data["unabsorb_messages_prey"],"\n\n"),MAX_MESSAGE_LEN * 1.5,0,0,0) + if(new_unabsorb_messages_prey) + new_belly.set_messages(new_unabsorb_messages_prey,"uamp", limit = MAX_MESSAGE_LEN / 4) + + if(islist(belly_data["unabsorb_messages_owner"])) + var/new_unabsorb_messages_owner = sanitize(jointext(belly_data["unabsorb_messages_owner"],"\n\n"),MAX_MESSAGE_LEN * 1.5,0,0,0) + if(new_unabsorb_messages_owner) + new_belly.set_messages(new_unabsorb_messages_owner,"uamo", limit = MAX_MESSAGE_LEN / 4) + + if(islist(belly_data["struggle_messages_outside"])) + var/new_struggle_messages_outside = sanitize(jointext(belly_data["struggle_messages_outside"],"\n\n"),MAX_MESSAGE_LEN * 1.5,0,0,0) + if(new_struggle_messages_outside) + new_belly.set_messages(new_struggle_messages_outside,"smo", limit = MAX_MESSAGE_LEN / 4) + + if(islist(belly_data["struggle_messages_inside"])) + var/new_struggle_messages_inside = sanitize(jointext(belly_data["struggle_messages_inside"],"\n\n"),MAX_MESSAGE_LEN * 1.5,0,0,0) + if(new_struggle_messages_inside) + new_belly.set_messages(new_struggle_messages_inside,"smi", limit = MAX_MESSAGE_LEN / 4) + + if(islist(belly_data["absorbed_struggle_messages_outside"])) + var/new_absorbed_struggle_messages_outside = sanitize(jointext(belly_data["absorbed_struggle_messages_outside"],"\n\n"),MAX_MESSAGE_LEN * 1.5,0,0,0) + if(new_absorbed_struggle_messages_outside) + new_belly.set_messages(new_absorbed_struggle_messages_outside,"asmo", limit = MAX_MESSAGE_LEN / 4) + + if(islist(belly_data["absorbed_struggle_messages_inside"])) + var/new_absorbed_struggle_messages_inside = sanitize(jointext(belly_data["absorbed_struggle_messages_inside"],"\n\n"),MAX_MESSAGE_LEN * 1.5,0,0,0) + if(new_absorbed_struggle_messages_inside) + new_belly.set_messages(new_absorbed_struggle_messages_inside,"asmi", limit = MAX_MESSAGE_LEN / 4) + + if(islist(belly_data["escape_attempt_messages_prey"])) + var/new_escape_attempt_messages_prey = sanitize(jointext(belly_data["escape_attempt_messages_prey"],"\n\n"),MAX_MESSAGE_LEN * 1.5,0,0,0) + if(new_escape_attempt_messages_prey) + new_belly.set_messages(new_escape_attempt_messages_prey,"escap", limit = MAX_MESSAGE_LEN / 4) + + if(islist(belly_data["escape_attempt_messages_owner"])) + var/new_escape_attempt_messages_owner = sanitize(jointext(belly_data["escape_attempt_messages_owner"],"\n\n"),MAX_MESSAGE_LEN * 1.5,0,0,0) + if(new_escape_attempt_messages_owner) + new_belly.set_messages(new_escape_attempt_messages_owner,"escao", limit = MAX_MESSAGE_LEN / 4) + + if(islist(belly_data["escape_messages_prey"])) + var/new_escape_messages_prey = sanitize(jointext(belly_data["escape_messages_prey"],"\n\n"),MAX_MESSAGE_LEN * 1.5,0,0,0) + if(new_escape_messages_prey) + new_belly.set_messages(new_escape_messages_prey,"escp", limit = MAX_MESSAGE_LEN / 4) + + if(islist(belly_data["escape_messages_owner"])) + var/new_escape_messages_owner = sanitize(jointext(belly_data["escape_messages_owner"],"\n\n"),MAX_MESSAGE_LEN * 1.5,0,0,0) + if(new_escape_messages_owner) + new_belly.set_messages(new_escape_messages_owner,"esco", limit = MAX_MESSAGE_LEN / 4) + + if(islist(belly_data["escape_messages_outside"])) + var/new_escape_messages_outside = sanitize(jointext(belly_data["escape_messages_outside"],"\n\n"),MAX_MESSAGE_LEN * 1.5,0,0,0) + if(new_escape_messages_outside) + new_belly.set_messages(new_escape_messages_outside,"escout", limit = MAX_MESSAGE_LEN / 4) + + if(islist(belly_data["escape_item_messages_prey"])) + var/new_escape_item_messages_prey = sanitize(jointext(belly_data["escape_item_messages_prey"],"\n\n"),MAX_MESSAGE_LEN * 1.5,0,0,0) + if(new_escape_item_messages_prey) + new_belly.set_messages(new_escape_item_messages_prey,"escip", limit = MAX_MESSAGE_LEN / 4) + + if(islist(belly_data["escape_item_messages_owner"])) + var/new_escape_item_messages_owner = sanitize(jointext(belly_data["escape_item_messages_owner"],"\n\n"),MAX_MESSAGE_LEN * 1.5,0,0,0) + if(new_escape_item_messages_owner) + new_belly.set_messages(new_escape_item_messages_owner,"escio", limit = MAX_MESSAGE_LEN / 4) + + if(islist(belly_data["escape_item_messages_outside"])) + var/new_escape_item_messages_outside = sanitize(jointext(belly_data["escape_item_messages_outside"],"\n\n"),MAX_MESSAGE_LEN * 1.5,0,0,0) + if(new_escape_item_messages_outside) + new_belly.set_messages(new_escape_item_messages_outside,"esciout", limit = MAX_MESSAGE_LEN / 4) + + if(islist(belly_data["escape_fail_messages_prey"])) + var/new_escape_fail_messages_prey = sanitize(jointext(belly_data["escape_fail_messages_prey"],"\n\n"),MAX_MESSAGE_LEN * 1.5,0,0,0) + if(new_escape_fail_messages_prey) + new_belly.set_messages(new_escape_fail_messages_prey,"escfp", limit = MAX_MESSAGE_LEN / 4) + + if(islist(belly_data["escape_fail_messages_owner"])) + var/new_escape_fail_messages_owner = sanitize(jointext(belly_data["escape_fail_messages_owner"],"\n\n"),MAX_MESSAGE_LEN * 1.5,0,0,0) + if(new_escape_fail_messages_owner) + new_belly.set_messages(new_escape_fail_messages_owner,"escfo", limit = MAX_MESSAGE_LEN / 4) + + if(islist(belly_data["escape_attempt_absorbed_messages_prey"])) + var/new_escape_attempt_absorbed_messages_prey = sanitize(jointext(belly_data["escape_attempt_absorbed_messages_prey"],"\n\n"),MAX_MESSAGE_LEN * 1.5,0,0,0) + if(new_escape_attempt_absorbed_messages_prey) + new_belly.set_messages(new_escape_attempt_absorbed_messages_prey,"aescap", limit = MAX_MESSAGE_LEN / 4) + + if(islist(belly_data["escape_attempt_absorbed_messages_owner"])) + var/new_escape_attempt_absorbed_messages_owner = sanitize(jointext(belly_data["escape_attempt_absorbed_messages_owner"],"\n\n"),MAX_MESSAGE_LEN * 1.5,0,0,0) + if(new_escape_attempt_absorbed_messages_owner) + new_belly.set_messages(new_escape_attempt_absorbed_messages_owner,"aescao", limit = MAX_MESSAGE_LEN / 4) + + if(islist(belly_data["escape_absorbed_messages_prey"])) + var/new_escape_absorbed_messages_prey = sanitize(jointext(belly_data["escape_absorbed_messages_prey"],"\n\n"),MAX_MESSAGE_LEN * 1.5,0,0,0) + if(new_escape_absorbed_messages_prey) + new_belly.set_messages(new_escape_absorbed_messages_prey,"aescp", limit = MAX_MESSAGE_LEN / 4) + + if(islist(belly_data["escape_absorbed_messages_owner"])) + var/new_escape_absorbed_messages_owner = sanitize(jointext(belly_data["escape_absorbed_messages_owner"],"\n\n"),MAX_MESSAGE_LEN * 1.5,0,0,0) + if(new_escape_absorbed_messages_owner) + new_belly.set_messages(new_escape_absorbed_messages_owner,"aesco", limit = MAX_MESSAGE_LEN / 4) + + if(islist(belly_data["escape_absorbed_messages_outside"])) + var/new_escape_absorbed_messages_outside = sanitize(jointext(belly_data["escape_absorbed_messages_outside"],"\n\n"),MAX_MESSAGE_LEN * 1.5,0,0,0) + if(new_escape_absorbed_messages_outside) + new_belly.set_messages(new_escape_absorbed_messages_outside,"aescout", limit = MAX_MESSAGE_LEN / 4) + + if(islist(belly_data["escape_fail_absorbed_messages_prey"])) + var/new_escape_fail_absorbed_messages_prey = sanitize(jointext(belly_data["escape_fail_absorbed_messages_prey"],"\n\n"),MAX_MESSAGE_LEN * 1.5,0,0,0) + if(new_escape_fail_absorbed_messages_prey) + new_belly.set_messages(new_escape_fail_absorbed_messages_prey,"aescfp", limit = MAX_MESSAGE_LEN / 4) + + if(islist(belly_data["escape_fail_absorbed_messages_owner"])) + var/new_escape_fail_absorbed_messages_owner = sanitize(jointext(belly_data["escape_fail_absorbed_messages_owner"],"\n\n"),MAX_MESSAGE_LEN * 1.5,0,0,0) + if(new_escape_fail_absorbed_messages_owner) + new_belly.set_messages(new_escape_fail_absorbed_messages_owner,"aescfo", limit = MAX_MESSAGE_LEN / 4) + + if(islist(belly_data["primary_transfer_messages_prey"])) + var/new_primary_transfer_messages_prey = sanitize(jointext(belly_data["primary_transfer_messages_prey"],"\n\n"),MAX_MESSAGE_LEN * 1.5,0,0,0) + if(new_primary_transfer_messages_prey) + new_belly.set_messages(new_primary_transfer_messages_prey,"trnspp", limit = MAX_MESSAGE_LEN / 4) + + if(islist(belly_data["primary_transfer_messages_owner"])) + var/new_primary_transfer_messages_owner = sanitize(jointext(belly_data["primary_transfer_messages_owner"],"\n\n"),MAX_MESSAGE_LEN * 1.5,0,0,0) + if(new_primary_transfer_messages_owner) + new_belly.set_messages(new_primary_transfer_messages_owner,"trnspo", limit = MAX_MESSAGE_LEN / 4) + + if(islist(belly_data["secondary_transfer_messages_prey"])) + var/new_secondary_transfer_messages_prey = sanitize(jointext(belly_data["secondary_transfer_messages_prey"],"\n\n"),MAX_MESSAGE_LEN * 1.5,0,0,0) + if(new_secondary_transfer_messages_prey) + new_belly.set_messages(new_secondary_transfer_messages_prey,"trnssp", limit = MAX_MESSAGE_LEN / 4) + + if(islist(belly_data["secondary_transfer_messages_owner"])) + var/new_secondary_transfer_messages_owner = sanitize(jointext(belly_data["secondary_transfer_messages_owner"],"\n\n"),MAX_MESSAGE_LEN * 1.5,0,0,0) + if(new_secondary_transfer_messages_owner) + new_belly.set_messages(new_secondary_transfer_messages_owner,"trnsso", limit = MAX_MESSAGE_LEN / 4) + + if(islist(belly_data["primary_autotransfer_messages_prey"])) + var/new_primary_autotransfer_messages_prey = sanitize(jointext(belly_data["primary_autotransfer_messages_prey"],"\n\n"),MAX_MESSAGE_LEN * 1.5,0,0,0) + if(new_primary_autotransfer_messages_prey) + new_belly.set_messages(new_primary_autotransfer_messages_prey,"atrnspp", limit = MAX_MESSAGE_LEN / 4) + + if(islist(belly_data["primary_autotransfer_messages_owner"])) + var/new_primary_autotransfer_messages_owner = sanitize(jointext(belly_data["primary_autotransfer_messages_owner"],"\n\n"),MAX_MESSAGE_LEN * 1.5,0,0,0) + if(new_primary_autotransfer_messages_owner) + new_belly.set_messages(new_primary_autotransfer_messages_owner,"atrnspo", limit = MAX_MESSAGE_LEN / 4) + + if(islist(belly_data["secondary_autotransfer_messages_prey"])) + var/new_secondary_autotransfer_messages_prey = sanitize(jointext(belly_data["secondary_autotransfer_messages_prey"],"\n\n"),MAX_MESSAGE_LEN * 1.5,0,0,0) + if(new_secondary_autotransfer_messages_prey) + new_belly.set_messages(new_secondary_autotransfer_messages_prey,"atrnssp", limit = MAX_MESSAGE_LEN / 4) + + if(islist(belly_data["secondary_autotransfer_messages_owner"])) + var/new_secondary_autotransfer_messages_owner = sanitize(jointext(belly_data["secondary_autotransfer_messages_owner"],"\n\n"),MAX_MESSAGE_LEN * 1.5,0,0,0) + if(new_secondary_autotransfer_messages_owner) + new_belly.set_messages(new_secondary_autotransfer_messages_owner,"atrnsso", limit = MAX_MESSAGE_LEN / 4) + + if(islist(belly_data["digest_chance_messages_prey"])) + var/new_digest_chance_messages_prey = sanitize(jointext(belly_data["digest_chance_messages_prey"],"\n\n"),MAX_MESSAGE_LEN * 1.5,0,0,0) + if(new_digest_chance_messages_prey) + new_belly.set_messages(new_digest_chance_messages_prey,"stmodp", limit = MAX_MESSAGE_LEN / 4) + + if(islist(belly_data["digest_chance_messages_owner"])) + var/new_digest_chance_messages_owner = sanitize(jointext(belly_data["digest_chance_messages_owner"],"\n\n"),MAX_MESSAGE_LEN * 1.5,0,0,0) + if(new_digest_chance_messages_owner) + new_belly.set_messages(new_digest_chance_messages_owner,"stmodo", limit = MAX_MESSAGE_LEN / 4) + + if(islist(belly_data["absorb_chance_messages_prey"])) + var/new_absorb_chance_messages_prey = sanitize(jointext(belly_data["absorb_chance_messages_prey"],"\n\n"),MAX_MESSAGE_LEN * 1.5,0,0,0) + if(new_absorb_chance_messages_prey) + new_belly.set_messages(new_absorb_chance_messages_prey,"stmoap", limit = MAX_MESSAGE_LEN / 4) + + if(islist(belly_data["absorb_chance_messages_owner"])) + var/new_absorb_chance_messages_owner = sanitize(jointext(belly_data["absorb_chance_messages_owner"],"\n\n"),MAX_MESSAGE_LEN * 1.5,0,0,0) + if(new_absorb_chance_messages_owner) + new_belly.set_messages(new_absorb_chance_messages_owner,"stmoao", limit = MAX_MESSAGE_LEN / 4) + + if(islist(belly_data["examine_messages"])) + var/new_examine_messages = sanitize(jointext(belly_data["examine_messages"],"\n\n"),MAX_MESSAGE_LEN * 1.5,0,0,0) + if(new_examine_messages) + new_belly.set_messages(new_examine_messages,"em", limit = MAX_MESSAGE_LEN / 2) + + if(islist(belly_data["examine_messages_absorbed"])) + var/new_examine_messages_absorbed = sanitize(jointext(belly_data["examine_messages_absorbed"],"\n\n"),MAX_MESSAGE_LEN * 1.5,0,0,0) + if(new_examine_messages_absorbed) + new_belly.set_messages(new_examine_messages_absorbed,"ema", limit = MAX_MESSAGE_LEN / 2) + + if(islist(belly_data["emotes_digest"])) + var/new_emotes_digest = sanitize(jointext(belly_data["emotes_digest"],"\n\n"),MAX_MESSAGE_LEN * 1.5,0,0,0) + if(new_emotes_digest) + new_belly.set_messages(new_emotes_digest,"im_digest", limit = MAX_MESSAGE_LEN / 4) + + if(islist(belly_data["emotes_hold"])) + var/new_emotes_hold = sanitize(jointext(belly_data["emotes_hold"],"\n\n"),MAX_MESSAGE_LEN * 1.5,0,0,0) + if(new_emotes_hold) + new_belly.set_messages(new_emotes_hold,"im_hold", limit = MAX_MESSAGE_LEN / 4) + + if(islist(belly_data["emotes_holdabsorbed"])) + var/new_emotes_holdabsorbed = sanitize(jointext(belly_data["emotes_holdabsorbed"],"\n\n"),MAX_MESSAGE_LEN * 1.5,0,0,0) + if(new_emotes_holdabsorbed) + new_belly.set_messages(new_emotes_holdabsorbed,"im_holdabsorbed", limit = MAX_MESSAGE_LEN / 4) + + if(islist(belly_data["emotes_absorb"])) + var/new_emotes_absorb = sanitize(jointext(belly_data["emotes_absorb"],"\n\n"),MAX_MESSAGE_LEN * 1.5,0,0,0) + if(new_emotes_absorb) + new_belly.set_messages(new_emotes_absorb,"im_absorb", limit = MAX_MESSAGE_LEN / 4) + + if(islist(belly_data["emotes_heal"])) + var/new_emotes_heal = sanitize(jointext(belly_data["emotes_heal"],"\n\n"),MAX_MESSAGE_LEN * 1.5,0,0,0) + if(new_emotes_heal) + new_belly.set_messages(new_emotes_heal,"im_heal", limit = MAX_MESSAGE_LEN / 4) + + if(islist(belly_data["emotes_drain"])) + var/new_emotes_drain = sanitize(jointext(belly_data["emotes_drain"],"\n\n"),MAX_MESSAGE_LEN * 1.5,0,0,0) + if(new_emotes_drain) + new_belly.set_messages(new_emotes_drain,"im_drain", limit = MAX_MESSAGE_LEN / 4) + + if(islist(belly_data["emotes_steal"])) + var/new_emotes_steal = sanitize(jointext(belly_data["emotes_steal"],"\n\n"),MAX_MESSAGE_LEN * 1.5,0,0,0) + if(new_emotes_steal) + new_belly.set_messages(new_emotes_steal,"im_steal", limit = MAX_MESSAGE_LEN / 4) + + if(islist(belly_data["emotes_egg"])) + var/new_emotes_egg = sanitize(jointext(belly_data["emotes_egg"],"\n\n"),MAX_MESSAGE_LEN * 1.5,0,0,0) + if(new_emotes_egg) + new_belly.set_messages(new_emotes_egg,"im_egg", limit = MAX_MESSAGE_LEN / 4) + + if(islist(belly_data["emotes_shrink"])) + var/new_emotes_shrink = sanitize(jointext(belly_data["emotes_shrink"],"\n\n"),MAX_MESSAGE_LEN * 1.5,0,0,0) + if(new_emotes_shrink) + new_belly.set_messages(new_emotes_shrink,"im_shrink", limit = MAX_MESSAGE_LEN / 4) + + if(islist(belly_data["emotes_grow"])) + var/new_emotes_grow = sanitize(jointext(belly_data["emotes_grow"],"\n\n"),MAX_MESSAGE_LEN * 1.5,0,0,0) + if(new_emotes_grow) + new_belly.set_messages(new_emotes_grow,"im_grow", limit = MAX_MESSAGE_LEN / 4) + + if(islist(belly_data["emotes_unabsorb"])) + var/new_emotes_unabsorb = sanitize(jointext(belly_data["emotes_unabsorb"],"\n\n"),MAX_MESSAGE_LEN * 1.5,0,0,0) + if(new_emotes_unabsorb) + new_belly.set_messages(new_emotes_unabsorb,"im_unabsorb", limit = MAX_MESSAGE_LEN / 4) + + // Options + if(isnum(belly_data["can_taste"])) + var/new_can_taste = belly_data["can_taste"] + if(new_can_taste == 0) + new_belly.can_taste = FALSE + if(new_can_taste == 1) + new_belly.can_taste = TRUE + + /* Not implemented on virgo + if(isnum(belly_data["is_feedable"])) + var/new_is_feedable = belly_data["is_feedable"] + if(new_is_feedable == 0) + new_belly.is_feedable = FALSE + if(new_is_feedable == 1) + new_belly.is_feedable = TRUE + */ + + if(isnum(belly_data["contaminates"])) + var/new_contaminates = belly_data["contaminates"] + if(new_contaminates == 0) + new_belly.contaminates = FALSE + if(new_contaminates == 1) + new_belly.contaminates = TRUE + + if(istext(belly_data["contamination_flavor"])) + var/new_contamination_flavor = sanitize(belly_data["contamination_flavor"],MAX_MESSAGE_LEN,0,0,0) + if(new_contamination_flavor) + if(new_contamination_flavor in contamination_flavors) + new_belly.contamination_flavor = new_contamination_flavor + + if(istext(belly_data["contamination_color"])) + var/new_contamination_color = sanitize(belly_data["contamination_color"],MAX_MESSAGE_LEN,0,0,0) + if(new_contamination_color) + if(new_contamination_color in contamination_colors) + new_belly.contamination_color = new_contamination_color + + if(isnum(belly_data["nutrition_percent"])) + var/new_nutrition_percent = belly_data["nutrition_percent"] + new_belly.nutrition_percent = CLAMP(new_nutrition_percent,0.01,100) + + if(isnum(belly_data["bulge_size"])) + var/new_bulge_size = belly_data["bulge_size"] + if(new_bulge_size == 0) + new_belly.bulge_size = 0 + else + new_belly.bulge_size = CLAMP(new_bulge_size,0.25,2) + + if(isnum(belly_data["display_absorbed_examine"])) + var/new_display_absorbed_examine = belly_data["display_absorbed_examine"] + if(new_display_absorbed_examine == 0) + new_belly.display_absorbed_examine = FALSE + if(new_display_absorbed_examine == 1) + new_belly.display_absorbed_examine = TRUE + + if(isnum(belly_data["save_digest_mode"])) + var/new_save_digest_mode = belly_data["save_digest_mode"] + if(new_save_digest_mode == 0) + new_belly.save_digest_mode = FALSE + if(new_save_digest_mode == 1) + new_belly.save_digest_mode = TRUE + + if(isnum(belly_data["emote_active"])) + var/new_emote_active = belly_data["emote_active"] + if(new_emote_active == 0) + new_belly.emote_active = FALSE + if(new_emote_active == 1) + new_belly.emote_active = TRUE + + if(isnum(belly_data["emote_time"])) + var/new_emote_time = belly_data["emote_time"] + new_belly.emote_time = CLAMP(new_emote_time, 60, 600) + + // new_belly.set_zero_digestion_damage() // Not implemented on virgo; needed for importing a belly to overwrite an existing belly; otherwise pre-existing values throw off the unused digestion damage. + + if(isnum(belly_data["digest_brute"])) + var/new_digest_brute = belly_data["digest_brute"] + new_belly.digest_brute = CLAMP(new_digest_brute, 0, 6) + + if(isnum(belly_data["digest_burn"])) + var/new_digest_burn = belly_data["digest_burn"] + new_belly.digest_burn = CLAMP(new_digest_burn, 0, 6) + + if(isnum(belly_data["digest_oxy"])) + var/new_digest_oxy = belly_data["digest_oxy"] + new_belly.digest_oxy = CLAMP(new_digest_oxy, 0, 12) + + if(isnum(belly_data["digest_tox"])) + var/new_digest_tox = belly_data["digest_tox"] + new_belly.digest_tox = CLAMP(new_digest_tox, 0, 6) + + if(isnum(belly_data["digest_clone"])) + var/new_digest_clone = belly_data["digest_clone"] + new_belly.digest_clone = CLAMP(new_digest_clone, 0, 6) + + if(isnum(belly_data["shrink_grow_size"])) + var/new_shrink_grow_size = belly_data["shrink_grow_size"] + new_belly.shrink_grow_size = CLAMP(new_shrink_grow_size, 0.25, 2) + + /* Not implemented on virgo + if(isnum(belly_data["vorespawn_blacklist"])) + var/new_vorespawn_blacklist = belly_data["vorespawn_blacklist"] + if(new_vorespawn_blacklist == 0) + new_belly.vorespawn_blacklist = FALSE + if(new_vorespawn_blacklist == 1) + new_belly.vorespawn_blacklist = TRUE + + if(islist(belly_data["vorespawn_whitelist"])) + var/new_vorespawn_whitelist = splittext(sanitize(lowertext(jointext(belly_data["vorespawn_whitelist"],"\n")),MAX_MESSAGE_LEN,0,0,0),"\n") + new_belly.vorespawn_whitelist = new_vorespawn_whitelist + + if(isnum(belly_data["vorespawn_absorbed"])) + var/new_vorespawn_absorbed = 0 + var/updated_vorespawn_absorbed = belly_data["vorespawn_absorbed"] + if(updated_vorespawn_absorbed & VS_FLAG_ABSORB_YES) + new_vorespawn_absorbed |= VS_FLAG_ABSORB_YES + if(updated_vorespawn_absorbed & VS_FLAG_ABSORB_PREY) + new_vorespawn_absorbed |= VS_FLAG_ABSORB_YES + new_vorespawn_absorbed |= VS_FLAG_ABSORB_PREY + new_belly.vorespawn_absorbed = new_vorespawn_absorbed + */ + + if(istext(belly_data["egg_type"])) + var/new_egg_type = sanitize(belly_data["egg_type"],MAX_MESSAGE_LEN,0,0,0) + if(new_egg_type) + if(new_egg_type in global_vore_egg_types) + new_belly.egg_type = new_egg_type + + /* Not implemented on virgo + if(istext(belly_data["egg_name"])) //CHOMPAdd Start + var/new_egg_name = html_encode(belly_data["egg_name"]) + if(new_egg_name) + new_egg_name = readd_quotes(new_egg_name) + if(length(new_egg_name) >= BELLIES_NAME_MIN && length(new_egg_name) <= BELLIES_NAME_MAX) + new_belly.egg_name = new_egg_name + + if(istext(belly_data["egg_size"])) + var/new_egg_size = belly_data["egg_size"] + if(new_egg_size == 0) + new_belly.egg_size = 0 + else + new_belly.egg_size = CLAMP(new_egg_size,0.25,2) + + if(isnum(belly_data["recycling"])) + var/new_recycling = belly_data["recycling"] + if(new_recycling == 0) + new_belly.recycling = FALSE + if(new_recycling == 1) + new_belly.recycling = TRUE + + if(isnum(belly_data["storing_nutrition"])) + var/new_storing_nutrition = belly_data["storing_nutrition"] + if(new_storing_nutrition == 0) + new_belly.storing_nutrition = FALSE + if(new_storing_nutrition == 1) + new_belly.storing_nutrition = TRUE + + if(isnum(belly_data["entrance_logs"])) + var/new_entrance_logs = belly_data["entrance_logs"] + if(new_entrance_logs == 0) + new_belly.entrance_logs = FALSE + if(new_entrance_logs == 1) + new_belly.entrance_logs = TRUE + + if(isnum(belly_data["item_digest_logs"])) + var/new_item_digest_logs = belly_data["item_digest_logs"] + if(new_item_digest_logs == 0) + new_belly.item_digest_logs = FALSE + if(new_item_digest_logs == 1) + new_belly.item_digest_logs = TRUE + */ + + if(istext(belly_data["selective_preference"])) + var/new_selective_preference = belly_data["selective_preference"] + if(new_selective_preference == "Digest") + new_belly.selective_preference = DM_DIGEST + if(new_selective_preference == "Absorb") + new_belly.selective_preference = DM_ABSORB + + /* Not implemented on virgo + if(isnum(belly_data["private_struggle"])) + var/new_private_struggle = belly_data["private_struggle"] + if(new_private_struggle == 0) + new_belly.private_struggle = FALSE + if(new_private_struggle == 1) + new_belly.private_struggle = TRUE + */ + + if(istext(belly_data["eating_privacy_local"])) + var/new_eating_privacy_local = html_encode(belly_data["eating_privacy_local"]) + if(new_eating_privacy_local && (new_eating_privacy_local in list("default","subtle","loud"))) + new_belly.eating_privacy_local = new_eating_privacy_local + + // Sounds + if(isnum(belly_data["is_wet"])) + var/new_is_wet = belly_data["is_wet"] + if(new_is_wet == 0) + new_belly.is_wet = FALSE + if(new_is_wet == 1) + new_belly.is_wet = TRUE + + if(isnum(belly_data["wet_loop"])) + var/new_wet_loop = belly_data["wet_loop"] + if(new_wet_loop == 0) + new_belly.wet_loop = FALSE + if(new_wet_loop == 1) + new_belly.wet_loop = TRUE + + if(isnum(belly_data["fancy_vore"])) + var/new_fancy_vore = belly_data["fancy_vore"] + if(new_fancy_vore == 0) + new_belly.fancy_vore = FALSE + if(new_fancy_vore == 1) + new_belly.fancy_vore = TRUE + + if(new_belly.fancy_vore) + if(!(new_belly.vore_sound in fancy_vore_sounds)) + new_belly.vore_sound = "Gulp" + if(!(new_belly.release_sound in fancy_vore_sounds)) + new_belly.release_sound = "Splatter" + else + if(!(new_belly.vore_sound in classic_vore_sounds)) + new_belly.vore_sound = "Gulp" + if(!(new_belly.release_sound in classic_vore_sounds)) + new_belly.release_sound = "Splatter" + + if(istext(belly_data["vore_sound"])) + var/new_vore_sound = sanitize(belly_data["vore_sound"],MAX_MESSAGE_LEN,0,0,0) + if(new_vore_sound) + if (new_belly.fancy_vore && (new_vore_sound in fancy_vore_sounds)) + new_belly.vore_sound = new_vore_sound + if (!new_belly.fancy_vore && (new_vore_sound in classic_vore_sounds)) + new_belly.vore_sound = new_vore_sound + + if(istext(belly_data["release_sound"])) + var/new_release_sound = sanitize(belly_data["release_sound"],MAX_MESSAGE_LEN,0,0,0) + if(new_release_sound) + if (new_belly.fancy_vore && (new_release_sound in fancy_release_sounds)) + new_belly.release_sound = new_release_sound + if (!new_belly.fancy_vore && (new_release_sound in classic_release_sounds)) + new_belly.release_sound = new_release_sound + + /* Not implemented on virgo + if(isnum(belly_data["sound_volume"])) + var/new_sound_volume = belly_data["sound_volume"] + new_belly.sound_volume = sanitize_integer(new_sound_volume, 0, 100, initial(new_belly.sound_volume)) + + if(isnum(belly_data["noise_freq"])) //CHOMPAdd Start + var/new_noise_freq = belly_data["noise_freq"] + new_belly.noise_freq = sanitize_integer(new_noise_freq, MIN_VOICE_FREQ, MAX_VOICE_FREQ, initial(new_belly.noise_freq)) + */ + + // Visuals + if(isnum(belly_data["affects_vore_sprites"])) + var/new_affects_vore_sprites = belly_data["affects_vore_sprites"] + if(new_affects_vore_sprites == 0) + new_belly.affects_vore_sprites = FALSE + if(new_affects_vore_sprites == 1) + new_belly.affects_vore_sprites = TRUE + + if(islist(belly_data["vore_sprite_flags"])) + new_belly.vore_sprite_flags = 0 + for(var/sprite_flag in belly_data["vore_sprite_flags"]) + new_belly.vore_sprite_flags += new_belly.vore_sprite_flag_list[sprite_flag] + + if(isnum(belly_data["count_absorbed_prey_for_sprite"])) + var/new_count_absorbed_prey_for_sprite = belly_data["count_absorbed_prey_for_sprite"] + if(new_count_absorbed_prey_for_sprite == 0) + new_belly.count_absorbed_prey_for_sprite = FALSE + if(new_count_absorbed_prey_for_sprite == 1) + new_belly.count_absorbed_prey_for_sprite = TRUE + + if(isnum(belly_data["absorbed_multiplier"])) + var/new_absorbed_multiplier = belly_data["absorbed_multiplier"] + new_belly.absorbed_multiplier = CLAMP(new_absorbed_multiplier, 0.1, 3) + + if(isnum(belly_data["count_liquid_for_sprite"])) + var/new_count_liquid_for_sprite = belly_data["count_liquid_for_sprite"] + if(new_count_liquid_for_sprite == 0) + new_belly.count_liquid_for_sprite = FALSE + if(new_count_liquid_for_sprite == 1) + new_belly.count_liquid_for_sprite = TRUE + + if(isnum(belly_data["liquid_multiplier"])) + var/new_liquid_multiplier = belly_data["liquid_multiplier"] + new_belly.liquid_multiplier = CLAMP(new_liquid_multiplier, 0.1, 10) + + if(isnum(belly_data["count_items_for_sprite"])) + var/new_count_items_for_sprite = belly_data["count_items_for_sprite"] + if(new_count_items_for_sprite == 0) + new_belly.count_items_for_sprite = FALSE + if(new_count_items_for_sprite == 1) + new_belly.count_items_for_sprite = TRUE + + if(isnum(belly_data["item_multiplier"])) + var/new_item_multiplier = belly_data["item_multiplier"] + new_belly.item_multiplier = CLAMP(new_item_multiplier, 0.1, 10) + + if(isnum(belly_data["health_impacts_size"])) + var/new_health_impacts_size = belly_data["health_impacts_size"] + if(new_health_impacts_size == 0) + new_belly.health_impacts_size = FALSE + if(new_health_impacts_size == 1) + new_belly.health_impacts_size = TRUE + + if(isnum(belly_data["resist_triggers_animation"])) + var/new_resist_triggers_animation = belly_data["resist_triggers_animation"] + if(new_resist_triggers_animation == 0) + new_belly.resist_triggers_animation = FALSE + if(new_resist_triggers_animation == 1) + new_belly.resist_triggers_animation = TRUE + + if(isnum(belly_data["size_factor_for_sprite"])) + var/new_size_factor_for_sprite = belly_data["size_factor_for_sprite"] + new_belly.size_factor_for_sprite = CLAMP(new_size_factor_for_sprite, 0.1, 3) + + if(istext(belly_data["belly_sprite_to_affect"])) + var/new_belly_sprite_to_affect = sanitize(belly_data["belly_sprite_to_affect"],MAX_MESSAGE_LEN,0,0,0) + if(new_belly_sprite_to_affect) + if(ishuman(host)) + var/mob/living/carbon/human/H = host + if (new_belly_sprite_to_affect in H.vore_icon_bellies) + new_belly.belly_sprite_to_affect = new_belly_sprite_to_affect + + if(istext(belly_data["undergarment_chosen"])) + var/new_undergarment_chosen = sanitize(belly_data["undergarment_chosen"],MAX_MESSAGE_LEN,0,0,0) + if(new_undergarment_chosen) + for(var/datum/category_group/underwear/U in global_underwear.categories) + if(lowertext(U.name) == lowertext(new_undergarment_chosen)) + new_belly.undergarment_chosen = U.name + break + + /* Not implemented on virgo + var/datum/category_group/underwear/UWC = global_underwear.categories_by_name[new_belly.undergarment_chosen] + var/invalid_if_none = TRUE + for(var/datum/category_item/underwear/U in UWC.items) + if(lowertext(U.name) == lowertext(new_belly.undergarment_if_none)) + invalid_if_none = FALSE + break + if(invalid_if_none) + new_belly.undergarment_if_none = null + + if(istext(belly_data["undergarment_if_none"])) + var/new_undergarment_if_none = sanitize(belly_data["undergarment_if_none"],MAX_MESSAGE_LEN,0,0,0) + if(new_undergarment_if_none) + for(var/datum/category_item/underwear/U in UWC.items) + if(lowertext(U.name) == lowertext(new_undergarment_if_none)) + new_belly.undergarment_if_none = U.name + break + + if(istext(belly_data["undergarment_color"])) + var/new_undergarment_color = sanitize_hexcolor(belly_data["undergarment_color"],new_belly.undergarment_color) + new_belly.undergarment_color = new_undergarment_color + */ + /* These don't seem to actually be available yet + if(istext(belly_data["tail_to_change_to"])) + var/new_tail_to_change_to = sanitize(belly_data["tail_to_change_to"],MAX_MESSAGE_LEN,0,0,0) + if(new_tail_to_change_to) + if (new_tail_to_change_to in tail_styles_list) + new_belly.tail_to_change_to = new_tail_to_change_to + + if(istext(belly_data["tail_colouration"])) + var/new_tail_colouration = sanitize_hexcolor(belly_data["tail_colouration"],new_belly.tail_colouration) + new_belly.tail_colouration = new_tail_colouration + + if(istext(belly_data["tail_extra_overlay"])) + var/new_tail_extra_overlay = sanitize_hexcolor(belly_data["tail_extra_overlay"],new_belly.tail_extra_overlay) + new_belly.tail_extra_overlay = new_tail_extra_overlay + + if(istext(belly_data["tail_extra_overlay2"])) + var/new_tail_extra_overlay2 = sanitize_hexcolor(belly_data["tail_extra_overlay2"],new_belly.tail_extra_overlay2) + new_belly.tail_extra_overlay2 = new_tail_extra_overlay2 + */ + if(istext(belly_data["belly_fullscreen_color"])) + var/new_belly_fullscreen_color = sanitize_hexcolor(belly_data["belly_fullscreen_color"],new_belly.belly_fullscreen_color) + new_belly.belly_fullscreen_color = new_belly_fullscreen_color + + if(istext(belly_data["belly_fullscreen_color_secondary"])) + var/new_belly_fullscreen_color_secondary = sanitize_hexcolor(belly_data["belly_fullscreen_color_secondary"],new_belly.belly_fullscreen_color_secondary) + new_belly.belly_fullscreen_color_secondary = new_belly_fullscreen_color_secondary + else if (istext(belly_data["belly_fullscreen_color2"])) // Inter server support between virgo and chomp! + var/new_belly_fullscreen_color_secondary = sanitize_hexcolor(belly_data["belly_fullscreen_color2"],new_belly.belly_fullscreen_color_secondary) + new_belly.belly_fullscreen_color_secondary = new_belly_fullscreen_color_secondary + + if(istext(belly_data["belly_fullscreen_color_trinary"]))// Inter server support between virgo and chomp! + var/new_belly_fullscreen_color_trinary = sanitize_hexcolor(belly_data["belly_fullscreen_color_trinary"],new_belly.belly_fullscreen_color_trinary) + new_belly.belly_fullscreen_color_trinary = new_belly_fullscreen_color_trinary + else if(istext(belly_data["belly_fullscreen_color3"])) + var/new_belly_fullscreen_color_trinary = sanitize_hexcolor(belly_data["belly_fullscreen_color3"],new_belly.belly_fullscreen_color_trinary) + new_belly.belly_fullscreen_color_trinary = new_belly_fullscreen_color_trinary + + /* Not implemented on virgo + if(istext(belly_data["belly_fullscreen_color4"])) + var/new_belly_fullscreen_color4 = sanitize_hexcolor(belly_data["belly_fullscreen_color4"],new_belly.belly_fullscreen_color4) + new_belly.belly_fullscreen_color4 = new_belly_fullscreen_color4 + + if(istext(belly_data["belly_fullscreen_alpha"])) + var/new_belly_fullscreen_alpha = sanitize_integer(belly_data["belly_fullscreen_alpha"],0,255,initial(new_belly.belly_fullscreen_alpha)) + new_belly.belly_fullscreen_alpha = new_belly_fullscreen_alpha + */ + + if(isnum(belly_data["colorization_enabled"])) + var/new_colorization_enabled = belly_data["colorization_enabled"] + if(new_colorization_enabled == 0) + new_belly.colorization_enabled = FALSE + if(new_colorization_enabled == 1) + new_belly.colorization_enabled = TRUE + + if(isnum(belly_data["disable_hud"])) + var/new_disable_hud = belly_data["disable_hud"] + if(new_disable_hud == 0) + new_belly.disable_hud = FALSE + if(new_disable_hud == 1) + new_belly.disable_hud = TRUE + + var/possible_fullscreens = icon_states('icons/mob/screen_full_colorized_vore.dmi') + if(!new_belly.colorization_enabled) + possible_fullscreens = icon_states('icons/mob/screen_full_vore.dmi') + possible_fullscreens -= "a_synth_flesh_mono" + possible_fullscreens -= "a_synth_flesh_mono_hole" + possible_fullscreens -= "a_anim_belly" + if(!(new_belly.belly_fullscreen in possible_fullscreens)) + new_belly.belly_fullscreen = "" + + if(istext(belly_data["belly_fullscreen"])) + var/new_belly_fullscreen = sanitize(belly_data["belly_fullscreen"],MAX_MESSAGE_LEN,0,0,0) + if(new_belly_fullscreen) + if(new_belly_fullscreen in possible_fullscreens) + new_belly.belly_fullscreen = new_belly_fullscreen + + // Interactions + if(isnum(belly_data["escapable"])) + var/new_escapable = belly_data["escapable"] + if(new_escapable == 0) + new_belly.escapable = FALSE + if(new_escapable == 1) + new_belly.escapable = TRUE + + if(isnum(belly_data["escapechance"])) + var/new_escapechance = belly_data["escapechance"] + new_belly.escapechance = sanitize_integer(new_escapechance, 0, 100, initial(new_belly.escapechance)) + + if(isnum(belly_data["escapechance_absorbed"])) + var/new_escapechance_absorbed = belly_data["escapechance_absorbed"] + new_belly.escapechance_absorbed = sanitize_integer(new_escapechance_absorbed, 0, 100, initial(new_belly.escapechance_absorbed)) + + + if(isnum(belly_data["escapetime"])) + var/new_escapetime = belly_data["escapetime"] + new_belly.escapetime = sanitize_integer(new_escapetime*10, 10, 600, initial(new_belly.escapetime)) + + if(isnum(belly_data["transferchance"])) + var/new_transferchance = belly_data["transferchance"] + new_belly.transferchance = sanitize_integer(new_transferchance, 0, 100, initial(new_belly.transferchance)) + + if(istext(belly_data["transferlocation"])) + var/new_transferlocation = sanitize(belly_data["transferlocation"],MAX_MESSAGE_LEN,0,0,0) + if(new_transferlocation) + for(var/obj/belly/existing_belly in host.vore_organs) + if(existing_belly.name == new_transferlocation) + new_belly.transferlocation = new_transferlocation + break + if(new_transferlocation in valid_names) + new_belly.transferlocation = new_transferlocation + if(new_transferlocation == new_belly.name) + new_belly.transferlocation = null + + if(isnum(belly_data["transferchance_secondary"])) + var/new_transferchance_secondary = belly_data["transferchance_secondary"] + new_belly.transferchance_secondary = sanitize_integer(new_transferchance_secondary, 0, 100, initial(new_belly.transferchance_secondary)) + + if(istext(belly_data["transferlocation_secondary"])) + var/new_transferlocation_secondary = sanitize(belly_data["transferlocation_secondary"],MAX_MESSAGE_LEN,0,0,0) + if(new_transferlocation_secondary) + for(var/obj/belly/existing_belly in host.vore_organs) + if(existing_belly.name == new_transferlocation_secondary) + new_belly.transferlocation_secondary = new_transferlocation_secondary + break + if(new_transferlocation_secondary in valid_names) + new_belly.transferlocation_secondary = new_transferlocation_secondary + if(new_transferlocation_secondary == new_belly.name) + new_belly.transferlocation_secondary = null + + /* Not implemented on virgo + if(islist(belly_data["autotransfer_whitelist"])) + new_belly.autotransfer_whitelist = 0 + for(var/at_flag in belly_data["autotransfer_whitelist"]) + new_belly.autotransfer_whitelist += new_belly.autotransfer_flags_list[at_flag] + + if(islist(belly_data["autotransfer_blacklist"])) + new_belly.autotransfer_blacklist = 0 + for(var/at_flag in belly_data["autotransfer_blacklist"]) + new_belly.autotransfer_blacklist += new_belly.autotransfer_flags_list[at_flag] + + if(islist(belly_data["autotransfer_secondary_whitelist"])) + new_belly.autotransfer_secondary_whitelist = 0 + for(var/at_flag in belly_data["autotransfer_secondary_whitelist"]) + new_belly.autotransfer_secondary_whitelist += new_belly.autotransfer_flags_list[at_flag] + + if(islist(belly_data["autotransfer_secondary_blacklist"])) + new_belly.autotransfer_secondary_blacklist = 0 + for(var/at_flag in belly_data["autotransfer_secondary_blacklist"]) + new_belly.autotransfer_secondary_blacklist += new_belly.autotransfer_flags_list[at_flag] + */ + + if(isnum(belly_data["absorbchance"])) + var/new_absorbchance = belly_data["absorbchance"] + new_belly.absorbchance = sanitize_integer(new_absorbchance, 0, 100, initial(new_belly.absorbchance)) + + if(isnum(belly_data["digestchance"])) + var/new_digestchance = belly_data["digestchance"] + new_belly.digestchance = sanitize_integer(new_digestchance, 0, 100, initial(new_belly.digestchance)) + + /* Not implemented on virgo + if(isnum(belly_data["autotransfer_enabled"])) + var/new_autotransfer_enabled = belly_data["autotransfer_enabled"] + if(new_autotransfer_enabled == 0) + new_belly.autotransfer_enabled = FALSE + if(new_autotransfer_enabled == 1) + new_belly.autotransfer_enabled = TRUE + */ + + if(isnum(belly_data["autotransferwait"])) + var/new_autotransferwait = belly_data["autotransferwait"] + new_belly.autotransferwait = sanitize_integer(new_autotransferwait*10, 10, 18000, initial(new_belly.autotransferwait)) + + if(isnum(belly_data["autotransferchance"])) + var/new_autotransferchance = belly_data["autotransferchance"] + new_belly.autotransferchance = sanitize_integer(new_autotransferchance, 0, 100, initial(new_belly.autotransferchance)) + + if(istext(belly_data["autotransferlocation"])) + var/new_autotransferlocation = sanitize(belly_data["autotransferlocation"],MAX_MESSAGE_LEN,0,0,0) + if(new_autotransferlocation) + for(var/obj/belly/existing_belly in host.vore_organs) + if(existing_belly.name == new_autotransferlocation) + new_belly.autotransferlocation = new_autotransferlocation + break + if(new_autotransferlocation in valid_names) + new_belly.autotransferlocation = new_autotransferlocation + if(new_autotransferlocation == new_belly.name) + new_belly.autotransferlocation = null + + /* Not implemented on virgo + if(islist(belly_data["autotransferextralocation"])) + var/new_autotransferextralocation = belly_data["autotransferextralocation"] + if(new_autotransferextralocation) + new_belly.autotransferextralocation = list() + for(var/extra_belly in new_autotransferextralocation) + if(extra_belly in valid_names) + new_belly.autotransferextralocation += extra_belly + + if(isnum(belly_data["autotransferchance_secondary"])) + var/new_autotransferchance_secondary = belly_data["autotransferchance_secondary"] + new_belly.autotransferchance_secondary = sanitize_integer(new_autotransferchance_secondary, 0, 100, initial(new_belly.autotransferchance_secondary)) + + if(istext(belly_data["autotransferlocation_secondary"])) + var/new_autotransferlocation_secondary = sanitize(belly_data["autotransferlocation_secondary"],MAX_MESSAGE_LEN,0,0,0) + if(new_autotransferlocation_secondary) + for(var/obj/belly/existing_belly in host.vore_organs) + if(existing_belly.name == new_autotransferlocation_secondary) + new_belly.autotransferlocation_secondary = new_autotransferlocation_secondary + break + if(new_autotransferlocation_secondary in valid_names) + new_belly.autotransferlocation_secondary = new_autotransferlocation_secondary + if(new_autotransferlocation_secondary == new_belly.name) + new_belly.autotransferlocation_secondary = null + + if(islist(belly_data["autotransferextralocation_secondary"])) + var/new_autotransferextralocation_secondary = belly_data["autotransferextralocation_secondary"] + if(new_autotransferextralocation_secondary) + new_belly.autotransferextralocation_secondary = list() + for(var/extra_belly in new_autotransferextralocation_secondary) + if(extra_belly in valid_names) + new_belly.autotransferextralocation_secondary += extra_belly + + + if(isnum(belly_data["autotransfer_min_amount"])) + var/new_autotransfer_min_amount = belly_data["autotransfer_min_amount"] + new_belly.autotransfer_min_amount = sanitize_integer(new_autotransfer_min_amount, 0, 100, initial(new_belly.autotransfer_min_amount)) + + if(isnum(belly_data["autotransfer_max_amount"])) + var/new_autotransfer_max_amount = belly_data["autotransfer_max_amount"] + new_belly.autotransfer_max_amount = sanitize_integer(new_autotransfer_max_amount, 0, 100, initial(new_belly.autotransfer_max_amount)) + + if(isnum(belly_data["belchchance"])) + var/new_belchchance = belly_data["belchchance"] + new_belly.belchchance = sanitize_integer(new_belchchance, 0, 100, initial(new_belly.belchchance)) + + // Liquid Options + if(isnum(belly_data["show_liquids"])) + var/new_show_liquids = belly_data["show_liquids"] + if(new_show_liquids == 0) + new_belly.show_liquids = FALSE + if(new_show_liquids == 1) + new_belly.show_liquids = TRUE + + if(isnum(belly_data["reagentbellymode"])) + var/new_reagentbellymode = belly_data["reagentbellymode"] + if(new_reagentbellymode == 0) + new_belly.reagentbellymode = FALSE + if(new_reagentbellymode == 1) + new_belly.reagentbellymode = TRUE + + if(istext(belly_data["reagent_chosen"])) + var/new_reagent_chosen = sanitize(belly_data["reagent_chosen"],MAX_MESSAGE_LEN,0,0,0) + if(new_reagent_chosen) + if(new_reagent_chosen in new_belly.reagent_choices) + new_belly.reagent_chosen = new_reagent_chosen + new_belly.ReagentSwitch() + + if(istext(belly_data["reagent_name"])) + var/new_reagent_name = html_encode(belly_data["reagent_name"]) + if(new_reagent_name) + new_reagent_name = readd_quotes(new_reagent_name) + if(length(new_reagent_name) >= BELLIES_NAME_MIN && length(new_reagent_name) <= BELLIES_NAME_MAX) + new_belly.reagent_name = new_reagent_name + + if(istext(belly_data["reagent_transfer_verb"])) + var/new_reagent_transfer_verb = html_encode(belly_data["reagent_transfer_verb"]) + if(new_reagent_transfer_verb) + new_reagent_transfer_verb = readd_quotes(new_reagent_transfer_verb) + if(length(new_reagent_transfer_verb) >= BELLIES_NAME_MIN && length(new_reagent_transfer_verb) <= BELLIES_NAME_MAX) + new_belly.reagent_transfer_verb = new_reagent_transfer_verb + + if(istext(belly_data["gen_time_display"])) + var/new_gen_time_display = sanitize(belly_data["gen_time_display"],MAX_MESSAGE_LEN,0,0,0) + if(new_gen_time_display) + if(new_gen_time_display in list("10 minutes","30 minutes","1 hour","3 hours","6 hours","12 hours","24 hours")) + new_belly.gen_time_display = new_gen_time_display + switch(new_gen_time_display) + if("10 minutes") + new_belly.gen_time = 0 + if("30 minutes") + new_belly.gen_time = 2 + if("1 hour") + new_belly.gen_time = 5 + if("3 hours") + new_belly.gen_time = 17 + if("6 hours") + new_belly.gen_time = 35 + if("12 hours") + new_belly.gen_time = 71 + if("24 hours") + new_belly.gen_time = 143 + + if(isnum(belly_data["custom_max_volume"])) + var/new_custom_max_volume = belly_data["custom_max_volume"] + new_belly.custom_max_volume = CLAMP(new_custom_max_volume, 10, 300) + + if(isnum(belly_data["vorefootsteps_sounds"])) + var/new_vorefootsteps_sounds = belly_data["vorefootsteps_sounds"] + if(new_vorefootsteps_sounds == 0) + new_belly.vorefootsteps_sounds = FALSE + if(new_vorefootsteps_sounds == 1) + new_belly.vorefootsteps_sounds = TRUE + + if(islist(belly_data["reagent_mode_flag_list"])) + new_belly.reagent_mode_flags = 0 + for(var/reagent_flag in belly_data["reagent_mode_flag_list"]) + new_belly.reagent_mode_flags += new_belly.reagent_mode_flag_list[reagent_flag] + + if(istext(belly_data["custom_reagentcolor"])) + var/custom_reagentcolor = sanitize_hexcolor(belly_data["custom_reagentcolor"],new_belly.custom_reagentcolor) + new_belly.custom_reagentcolor = custom_reagentcolor + + if(istext(belly_data["mush_color"])) + var/mush_color = sanitize_hexcolor(belly_data["mush_color"],new_belly.mush_color) + new_belly.mush_color = mush_color + + if(istext(belly_data["mush_alpha"])) + var/new_mush_alpha = sanitize_integer(belly_data["mush_alpha"],0,255,initial(new_belly.mush_alpha)) + new_belly.mush_alpha = new_mush_alpha + + if(isnum(belly_data["max_mush"])) + var/max_mush = belly_data["max_mush"] + new_belly.max_mush = CLAMP(max_mush, 0, 6000) + + if(isnum(belly_data["min_mush"])) + var/min_mush = belly_data["min_mush"] + new_belly.min_mush = CLAMP(min_mush, 0, 100) + + if(isnum(belly_data["item_mush_val"])) + var/item_mush_val = belly_data["item_mush_val"] + new_belly.item_mush_val = CLAMP(item_mush_val, 0, 1000) + + if(isnum(belly_data["liquid_overlay"])) + var/new_liquid_overlay = belly_data["liquid_overlay"] + if(new_liquid_overlay == 0) + new_belly.liquid_overlay = FALSE + if(new_liquid_overlay == 1) + new_belly.liquid_overlay = TRUE + + if(isnum(belly_data["max_liquid_level"])) + var/max_liquid_level = belly_data["max_liquid_level"] + new_belly.max_liquid_level = CLAMP(max_liquid_level, 0, 100) + + if(isnum(belly_data["reagent_touches"])) + var/new_reagent_touches = belly_data["reagent_touches"] + if(new_reagent_touches == 0) + new_belly.reagent_touches = FALSE + if(new_reagent_touches == 1) + new_belly.reagent_touches = TRUE + + if(isnum(belly_data["mush_overlay"])) + var/new_mush_overlay = belly_data["mush_overlay"] + if(new_mush_overlay == 0) + new_belly.mush_overlay = FALSE + if(new_mush_overlay == 1) + new_belly.mush_overlay = TRUE + + // Liquid Messages + if(isnum(belly_data["show_fullness_messages"])) + var/new_show_fullness_messages = belly_data["show_fullness_messages"] + if(new_show_fullness_messages == 0) + new_belly.show_fullness_messages = FALSE + if(new_show_fullness_messages == 1) + new_belly.show_fullness_messages = TRUE + + if(isnum(belly_data["liquid_fullness1_messages"])) + var/new_liquid_fullness1_messages = belly_data["liquid_fullness1_messages"] + if(new_liquid_fullness1_messages == 0) + new_belly.liquid_fullness1_messages = FALSE + if(new_liquid_fullness1_messages == 1) + new_belly.liquid_fullness1_messages = TRUE + + if(isnum(belly_data["liquid_fullness2_messages"])) + var/new_liquid_fullness2_messages = belly_data["liquid_fullness2_messages"] + if(new_liquid_fullness2_messages == 0) + new_belly.liquid_fullness2_messages = FALSE + if(new_liquid_fullness2_messages == 1) + new_belly.liquid_fullness2_messages = TRUE + + if(isnum(belly_data["liquid_fullness3_messages"])) + var/new_liquid_fullness3_messages = belly_data["liquid_fullness3_messages"] + if(new_liquid_fullness3_messages == 0) + new_belly.liquid_fullness3_messages = FALSE + if(new_liquid_fullness3_messages == 1) + new_belly.liquid_fullness3_messages = TRUE + + if(isnum(belly_data["liquid_fullness4_messages"])) + var/new_liquid_fullness4_messages = belly_data["liquid_fullness4_messages"] + if(new_liquid_fullness4_messages == 0) + new_belly.liquid_fullness4_messages = FALSE + if(new_liquid_fullness4_messages == 1) + new_belly.liquid_fullness4_messages = TRUE + + if(isnum(belly_data["liquid_fullness5_messages"])) + var/new_liquid_fullness5_messages = belly_data["liquid_fullness5_messages"] + if(new_liquid_fullness5_messages == 0) + new_belly.liquid_fullness5_messages = FALSE + if(new_liquid_fullness5_messages == 1) + new_belly.liquid_fullness5_messages = TRUE + + if(islist(belly_data["fullness1_messages"])) + var/new_fullness1_messages = sanitize(jointext(belly_data["fullness1_messages"],"\n\n"),MAX_MESSAGE_LEN,0,0,0) + if(new_fullness1_messages) + new_belly.set_reagent_messages(new_fullness1_messages,"full1") + + if(islist(belly_data["fullness2_messages"])) + var/new_fullness2_messages = sanitize(jointext(belly_data["fullness2_messages"],"\n\n"),MAX_MESSAGE_LEN,0,0,0) + if(new_fullness2_messages) + new_belly.set_reagent_messages(new_fullness2_messages,"full2") + + if(islist(belly_data["fullness3_messages"])) + var/new_fullness3_messages = sanitize(jointext(belly_data["fullness3_messages"],"\n\n"),MAX_MESSAGE_LEN,0,0,0) + if(new_fullness3_messages) + new_belly.set_reagent_messages(new_fullness3_messages,"full3") + + if(islist(belly_data["fullness4_messages"])) + var/new_fullness4_messages = sanitize(jointext(belly_data["fullness4_messages"],"\n\n"),MAX_MESSAGE_LEN,0,0,0) + if(new_fullness4_messages) + new_belly.set_reagent_messages(new_fullness4_messages,"full4") + + if(islist(belly_data["fullness5_messages"])) + var/new_fullness5_messages = sanitize(jointext(belly_data["fullness5_messages"],"\n\n"),MAX_MESSAGE_LEN,0,0,0) + if(new_fullness5_messages) + new_belly.set_reagent_messages(new_fullness5_messages,"full5") + */ + + // After import updates + new_belly.items_preserved.Cut() + // new_belly.update_internal_overlay() // Signal not implemented! + + if(ishuman(host)) + var/mob/living/carbon/human/H = host + H.update_fullness() + host.updateVRPanel() + unsaved_changes = TRUE diff --git a/code/modules/vore/eating/vorepanel_vr.dm b/code/modules/vore/eating/vorepanel_vr.dm index 8da9844d4e..88266f1b84 100644 --- a/code/modules/vore/eating/vorepanel_vr.dm +++ b/code/modules/vore/eating/vorepanel_vr.dm @@ -415,7 +415,9 @@ var/global/list/belly_colorable_only_fullscreens = list("a_synth_flesh_mono", host.vore_selected = NB unsaved_changes = TRUE return TRUE - + if("importpanel") + import_belly(host) + return TRUE if("bellypick") host.vore_selected = locate(params["bellypick"]) return TRUE diff --git a/code/modules/vore/fluffstuff/custom_clothes_vr.dm b/code/modules/vore/fluffstuff/custom_clothes_vr.dm index 6361637d45..dcab0fdc8a 100644 --- a/code/modules/vore/fluffstuff/custom_clothes_vr.dm +++ b/code/modules/vore/fluffstuff/custom_clothes_vr.dm @@ -668,7 +668,9 @@ /obj/item/clothing/head/fluff/avida/mob_can_equip(var/mob/living/carbon/human/H, slot, disable_warning = 0) if(..()) - if(H.ear_style && (H.ear_style.name == "Bnnuy Ears" || H.ear_style.name == "Bnnuy Ears 2")) //check if wearer's ear sprite is compatible with trimmed icon + var/static/list/allowed_ear_names = list("Bnnuy Ears", "Bnnuy Ears 2") + //check if wearer's ear sprite is compatible with trimmed icon + if((H.ear_style?.name in allowed_ear_names) || (H.ear_secondary_style?.name in allowed_ear_names)) item_state = initial(src.item_state) else //if not, just use a generic icon item_state = "avidahatnoears" diff --git a/code/modules/vore/persist/persist_vr.dm b/code/modules/vore/persist/persist_vr.dm index 9bb2771e55..bc96b1d82a 100644 --- a/code/modules/vore/persist/persist_vr.dm +++ b/code/modules/vore/persist/persist_vr.dm @@ -146,6 +146,11 @@ prefs.r_ears3 = character.r_ears3 prefs.g_ears3 = character.g_ears3 prefs.b_ears3 = character.b_ears3 + + // secondary ears + prefs.ear_secondary_style = character.ear_secondary_style?.name + prefs.ear_secondary_colors = character.ear_secondary_colors + prefs.r_tail = character.r_tail prefs.b_tail = character.b_tail prefs.g_tail = character.g_tail diff --git a/html/statbrowser.css b/html/statbrowser.css index 0e20233b47..1f5aec0558 100644 --- a/html/statbrowser.css +++ b/html/statbrowser.css @@ -1,150 +1,147 @@ body { font-family: Verdana, Geneva, Tahoma, sans-serif; - font-size: 12px !important; + font-size: 12px; margin: 0 !important; padding: 0 !important; - overflow-x: hidden; - overflow-y: scroll; -} - -body.dark { - background-color: #131313; - color: #b2c4dd; - scrollbar-base-color: #1c1c1c; - scrollbar-face-color: #3b3b3b; - scrollbar-3dlight-color: #252525; - scrollbar-highlight-color: #252525; - scrollbar-track-color: #1c1c1c; - scrollbar-arrow-color: #929292; - scrollbar-shadow-color: #3b3b3b; -} - -#menu { - background-color: #F0F0F0; - position: fixed; - width: 100%; - z-index: 100; -} - -.dark #menu { - background-color: #202020; -} - -#statcontent { - padding: 7px 7px 7px 7px; + overflow: hidden; } a { - color: black; - text-decoration: none -} - -.dark a { - color: #b2c4dd; -} - -a:hover, -.dark a:hover { - text-decoration: underline; -} - -ul { - list-style-type: none; - margin: 0; - padding: 0; - background-color: #333; -} - -li { - float: left; -} - -li a { - display: block; - color: white; - text-align: center; - padding: 14px 16px; + color: #003399; text-decoration: none; } -li a:hover:not(.active) { - background-color: #111; +a:hover { + color: #007fff; } -.button-container { - display: inline-flex; +h3 { + margin: 0 -0.5em 0.5em; + padding: 1em 0.66em 0.5em; + border-bottom: 0.1667em solid; +} + + +img { + -ms-interpolation-mode: nearest-neighbor; + image-rendering: pixelated; +} + +.stat-container { + display: flex; + flex-direction: column; + height: 100vh; +} + +#menu { + display: flex; + overflow-x: auto; + overflow-y: hidden; + padding: 0.25em 0.25em 0; + background-color: #ffffff; +} + +.menu-wrap { flex-wrap: wrap-reverse; - flex-direction: row; - align-items: flex-start; - overflow-x: hidden; - white-space: pre-wrap; - padding: 0 4px; +} + +#menu.tabs-classic { + padding: 0.15em; +} + +#menu.tabs-classic .button { + min-width: 2em; + margin: 0.1em; + padding: 0.25em 0.4em; + border: 0; + border-radius: 0.25em; +} + +#menu.tabs-classic .button.active { + background-color: #0668b8; + color: white; } .button { - background-color: #dfdfdf; - border: 1px solid #cecece; - border-bottom-width: 2px; - color: rgba(0, 0, 0, 0.7); - padding: 6px 4px 4px; - text-align: center; - text-decoration: none; - font-size: 12px; - margin: 0; + display: inline-table; cursor: pointer; - transition-duration: 100ms; - order: 3; - min-width: 40px; -} - -.dark button { - background-color: #222222; - border-color: #343434; - color: rgba(255, 255, 255, 0.5); + user-select: none; + -ms-user-select: none; /* Remove after Byond 516 */ + text-align: center; + font-size: 1em; + min-width: 2.9em; + padding: 0.5em 0.5em 0.4em; + background-color: transparent; + color: rgba(0, 0, 0, 0.5); + border: 0; + border-bottom: 0.1667em solid transparent; + border-radius: 0.25em 0.25em 0 0; } .button:hover { background-color: #ececec; - transition-duration: 0; } -.dark button:hover { - background-color: #2e2e2e; -} - -.button:active, .button.active { - background-color: #ffffff; + cursor: default; + background-color: #dfdfdf; color: black; - border-top-color: #cecece; - border-left-color: #cecece; - border-right-color: #cecece; - border-bottom-color: #ffffff; + border-bottom-color: #000000; } -.dark .button:active, -.dark .button.active { - background-color: #444444; - color: white; - border-top-color: #343434; - border-left-color: #343434; - border-right-color: #343434; - border-bottom-color: #ffffff; +#under-menu { + height: 0.5em; + background-color: #eeeeee; +} + +#statcontent { + flex: 1; + padding: 0.75em 0.5em; + overflow-y: scroll; + overflow-x: hidden; } .grid-container { - margin: -2px; - margin-right: -15px; + margin: -0.25em; } .grid-item { + display: inline-flex; position: relative; - display: inline-block; + user-select: none; + -ms-user-select: none; /* Remove after Byond 516 */ width: 100%; - box-sizing: border-box; - overflow: visible; - padding: 3px 2px; + max-height: 1.85em; text-decoration: none; + background-color: transparent; + color: black; +} + +.grid-item:hover, +.grid-item:active { + color: #003399; + z-index: 1; +} + +.grid-item-text { + display: inline-block; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + pointer-events: none; + width: 100%; + padding: 0.33em 0.5em; + border-radius: 0.25em; +} + +.grid-item:hover .grid-item-text { + overflow: visible; + white-space: normal; + background-color: #ececec; +} + +.grid-item:active .grid-item-text { + background-color: #dfdfdf; } @media only screen and (min-width: 300px) { @@ -171,31 +168,77 @@ li a:hover:not(.active) { } } -.grid-item:hover { - z-index: 1; +.status-info { + margin: 0 0.33em 0.25em; } -.grid-item:hover .grid-item-text { - width: auto; - text-decoration: underline; +.interview_panel_stats, +.interview_panel_controls { + margin-bottom: 1em; } -.grid-item-text { - display: inline-block; - width: 100%; - background-color: #ffffff; - margin: 0 -6px; - padding: 0 6px; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - pointer-events: none; +/* Dark theme colors */ +body.dark { + background-color: #131313; + color: #b2c4dd; + scrollbar-base-color: #1c1c1c; + scrollbar-face-color: #3b3b3b; + scrollbar-3dlight-color: #252525; + scrollbar-highlight-color: #252525; + scrollbar-track-color: #1c1c1c; + scrollbar-arrow-color: #929292; + scrollbar-shadow-color: #3b3b3b; } -.dark .grid-item-text { +.dark a { + color: #6699ff; +} + +.dark a:hover, +.dark .grid-item:hover, +.dark .grid-item:active { + color: #80bfff; +} + +.dark #menu { background-color: #131313; } +.dark #menu.tabs-classic .button.active { + background-color: #20b142; +} + +.dark .button { + color: rgba(255, 255, 255, 0.5); +} + +.dark .button:hover { + background-color: #252525; +} + +.dark .button.active { + background-color: #313131; + color: #d4dfec; + border-bottom-color: #d4dfec; +} + +.dark #under-menu { + background-color: #202020; +} + +.dark .grid-item{ + color: #b2c4dd; +} + +.dark .grid-item:hover .grid-item-text { + background-color: #252525; +} + +.dark .grid-item:active .grid-item-text { + background-color: #313131; +} + +/* required for alt click menu */ .link { display: inline; background: none; @@ -220,20 +263,6 @@ li a:hover:not(.active) { margin: 2px 2px; } -.elemcontainer { - border-collapse: separate; - border-spacing: 0 5px; - display: flex; -} - -.elem { - background: none; - border: none; - padding: 0px 14px; - font-size: 13px; - margin: 2px 2px; -} - .dark .link { color: #abc6ec; } @@ -249,13 +278,3 @@ li a:hover:not(.active) { .linkelem:hover { text-decoration: underline; } - -img { - -ms-interpolation-mode: nearest-neighbor; - image-rendering: pixelated; -} - -.interview_panel_controls, -.interview_panel_stats { - margin-bottom: 10px; -} diff --git a/html/statbrowser.html b/html/statbrowser.html index 1aea8811d5..ffd7425bd2 100644 --- a/html/statbrowser.html +++ b/html/statbrowser.html @@ -1,3 +1,5 @@ - -
-
+
+ +
+
+
diff --git a/html/statbrowser.js b/html/statbrowser.js index 2572d121ef..032d5c1610 100644 --- a/html/statbrowser.js +++ b/html/statbrowser.js @@ -33,7 +33,6 @@ var turfname = ""; var imageRetryDelay = 500; var imageRetryLimit = 50; var menu = document.getElementById('menu'); -var under_menu = document.getElementById('under_menu'); var statcontentdiv = document.getElementById('statcontent'); var storedimages = []; var split_admin_tabs = false; @@ -59,26 +58,26 @@ function createStatusTab(name) { if (!verb_tabs.includes(name) && !permanent_tabs.includes(name)) { return; } - var B = document.createElement("BUTTON"); - B.onclick = function () { + var button = document.createElement("DIV"); + button.onclick = function () { tab_change(name); this.blur(); + statcontentdiv.focus(); }; - B.id = name; - B.textContent = name; - B.className = "button"; + button.id = name; + button.textContent = name; + button.className = "button"; //ORDERING ALPHABETICALLY - B.style.order = name.charCodeAt(0); + button.style.order = name.charCodeAt(0); if (name == "Status" || name == "MC") { - B.style.order = name == "Status" ? 1 : 2; + button.style.order = name == "Status" ? 1 : 2; } if (name == "Tickets") { - B.style.order = 3; + button.style.order = 3; } //END ORDERING - menu.appendChild(B); + menu.appendChild(button); SendTabToByond(name); - under_menu.style.height = menu.clientHeight + 'px'; } function removeStatusTab(name) { @@ -92,7 +91,6 @@ function removeStatusTab(name) { } menu.removeChild(document.getElementById(name)); TakeTabFromByond(name); - under_menu.style.height = menu.clientHeight + 'px'; } function sortVerbs() { @@ -108,10 +106,6 @@ function sortVerbs() { }) } -window.onresize = function () { - under_menu.style.height = menu.clientHeight + 'px'; -} - function addPermanentTab(name) { if (!permanent_tabs.includes(name)) { permanent_tabs.push(name); @@ -383,6 +377,7 @@ function draw_status() { } else { var div = document.createElement("div"); div.textContent = status_tab_parts[i]; + div.className = "status-info"; document.getElementById("statcontent").appendChild(div); } } @@ -506,7 +501,7 @@ function draw_listedturf() { table.appendChild(b); table.appendChild(document.createElement("br")); } - document.getElementById("statcontent").appendChild(table); + statcontentdiv.appendChild(table); } function remove_listedturf() { @@ -777,6 +772,23 @@ function set_theme(which) { } } +function set_font_size(size) { + document.body.style.setProperty('font-size', size); +} + +function set_tabs_style(style) { + if (style == "default") { + menu.classList.add('menu-wrap'); + menu.classList.remove('tabs-classic'); + } else if (style == "classic") { + menu.classList.add('menu-wrap'); + menu.classList.add('tabs-classic'); + } else if (style == "scrollable") { + menu.classList.remove('menu-wrap'); + menu.classList.remove('tabs-classic'); + } +} + function set_style_sheet(sheet) { if (document.getElementById("goonStyle")) { var currentSheet = document.getElementById("goonStyle"); diff --git a/icons/inventory/accessory/item.dmi b/icons/inventory/accessory/item.dmi index 2782922a7a..2e2f0fa9e6 100644 Binary files a/icons/inventory/accessory/item.dmi and b/icons/inventory/accessory/item.dmi differ diff --git a/icons/inventory/accessory/mob.dmi b/icons/inventory/accessory/mob.dmi index 9ec056adc9..8b67d7d7de 100644 Binary files a/icons/inventory/accessory/mob.dmi and b/icons/inventory/accessory/mob.dmi differ diff --git a/icons/inventory/uniform/item.dmi b/icons/inventory/uniform/item.dmi index 16b3b53f64..a08ddf8ed3 100644 Binary files a/icons/inventory/uniform/item.dmi and b/icons/inventory/uniform/item.dmi differ diff --git a/icons/inventory/uniform/mob.dmi b/icons/inventory/uniform/mob.dmi index f6ec8e9285..ab3112edf9 100644 Binary files a/icons/inventory/uniform/mob.dmi and b/icons/inventory/uniform/mob.dmi differ diff --git a/maps/~map_system/_map_selection.dm b/maps/~map_system/_map_selection.dm index 47ff0d984d..879f058f54 100644 --- a/maps/~map_system/_map_selection.dm +++ b/maps/~map_system/_map_selection.dm @@ -5,8 +5,8 @@ /* FOR LIVE SERVER */ /*********************/ -//#define USE_MAP_TETHER -#define USE_MAP_STELLARDELIGHT +#define USE_MAP_TETHER +//#define USE_MAP_STELLARDELIGHT //#define USE_MAP_GROUNDBASE // Debug diff --git a/tgui/packages/tgui-panel/settings/SettingsPanel.tsx b/tgui/packages/tgui-panel/settings/SettingsPanel.tsx index e017d83c12..a141b09e93 100644 --- a/tgui/packages/tgui-panel/settings/SettingsPanel.tsx +++ b/tgui/packages/tgui-panel/settings/SettingsPanel.tsx @@ -11,6 +11,7 @@ import { ChatPageSettings } from '../chat'; import { changeSettingsTab } from './actions'; import { SETTINGS_TABS } from './constants'; import { selectActiveTab } from './selectors'; +import { SettingsStatPanel } from './SettingsStatPanel'; import { AdminSettings } from './SettingTabs/AdminSettings'; import { ExportTab } from './SettingTabs/ExportTab'; import { MessageLimits } from './SettingTabs/MessageLimits'; @@ -49,6 +50,7 @@ export const SettingsPanel = (props) => { {activeTab === 'export' && } {activeTab === 'chatPage' && } {activeTab === 'textHighlight' && } + {activeTab === 'statPanel' && } {activeTab === 'adminSettings' && } diff --git a/tgui/packages/tgui-panel/settings/SettingsStatPanel.tsx b/tgui/packages/tgui-panel/settings/SettingsStatPanel.tsx new file mode 100644 index 0000000000..68ca14131c --- /dev/null +++ b/tgui/packages/tgui-panel/settings/SettingsStatPanel.tsx @@ -0,0 +1,84 @@ +import { toFixed } from 'common/math'; +import { capitalize } from 'common/string'; +import { useDispatch, useSelector } from 'tgui/backend'; +import { + Button, + LabeledList, + NoticeBox, + Section, + Slider, + Stack, +} from 'tgui/components'; + +import { updateSettings } from './actions'; +import { selectSettings } from './selectors'; + +const TabsViews = ['default', 'classic', 'scrollable']; +const LinkedToChat = () => ( + Unlink Stat Panel from chat! +); + +export function SettingsStatPanel(props) { + const { statLinked, statFontSize, statTabsStyle } = + useSelector(selectSettings); + const dispatch = useDispatch(); + + return ( +
+ + + + + {TabsViews.map((view) => ( + + ))} + + + + {statLinked ? ( + + ) : ( + toFixed(value)} + onChange={(e, value) => + dispatch(updateSettings({ statFontSize: value })) + } + /> + )} + + + + + + + + + +
+ ); +} diff --git a/tgui/packages/tgui-panel/settings/constants.ts b/tgui/packages/tgui-panel/settings/constants.ts index 8be68f3d2c..8bb3222a1b 100644 --- a/tgui/packages/tgui-panel/settings/constants.ts +++ b/tgui/packages/tgui-panel/settings/constants.ts @@ -29,6 +29,10 @@ export const SETTINGS_TABS = [ id: 'chatPage', name: 'Chat Tabs', }, + { + id: 'statPanel', + name: 'Stat Panel', + }, ]; export const FONTS_DISABLED = 'Default'; diff --git a/tgui/packages/tgui-panel/settings/middleware.ts b/tgui/packages/tgui-panel/settings/middleware.ts index fc09fe5d2c..078b9a7874 100644 --- a/tgui/packages/tgui-panel/settings/middleware.ts +++ b/tgui/packages/tgui-panel/settings/middleware.ts @@ -13,11 +13,12 @@ import { removeHighlightSetting, updateHighlightSetting, updateSettings, - updateToggle, } from './actions'; import { FONTS_DISABLED } from './constants'; import { selectSettings } from './selectors'; +let statFontTimer: NodeJS.Timeout; +let statTabsTimer: NodeJS.Timeout; let overrideRule: HTMLStyleElement; let overrideFontFamily: string | undefined; let overrideFontSize: string; @@ -45,14 +46,37 @@ function updateGlobalOverrideRule() { document.body.style.setProperty('font-size', overrideFontSize); } -function setGlobalFontSize(fontSize: string) { +function setGlobalFontSize( + fontSize: string, + statFontSize: string, + statLinked: boolean, +) { overrideFontSize = `${fontSize}px`; + + // Used solution from theme.ts + clearInterval(statFontTimer); + Byond.command( + `.output statbrowser:set_font_size ${statLinked ? fontSize : statFontSize}px`, + ); + statFontTimer = setTimeout(() => { + Byond.command( + `.output statbrowser:set_font_size ${statLinked ? fontSize : statFontSize}px`, + ); + }, 1500); } function setGlobalFontFamily(fontFamily: string) { overrideFontFamily = fontFamily === FONTS_DISABLED ? undefined : fontFamily; } +function setStatTabsStyle(style: string) { + clearInterval(statTabsTimer); + Byond.command(`.output statbrowser:set_tabs_style ${style}`); + statTabsTimer = setTimeout(() => { + Byond.command(`.output statbrowser:set_tabs_style ${style}`); + }, 1500); +} + export function settingsMiddleware(store) { let initialized = false; @@ -66,7 +90,6 @@ export function settingsMiddleware(store) { }); } if ( - type !== updateToggle.type && type !== updateSettings.type && type !== loadSettings.type && type !== addHighlightSetting.type && @@ -87,8 +110,15 @@ export function settingsMiddleware(store) { const settings = selectSettings(store.getState()); + // Update stat panel settings + setStatTabsStyle(settings.statTabsStyle); + // Update global UI font size - setGlobalFontSize(settings.fontSize); + setGlobalFontSize( + settings.fontSize, + settings.statFontSize, + settings.statLinked, + ); setGlobalFontFamily(settings.fontFamily); updateGlobalOverrideRule(); diff --git a/tgui/packages/tgui-panel/settings/reducer.ts b/tgui/packages/tgui-panel/settings/reducer.ts index a4f6d3c56a..2fd2e0b94d 100644 --- a/tgui/packages/tgui-panel/settings/reducer.ts +++ b/tgui/packages/tgui-panel/settings/reducer.ts @@ -62,6 +62,9 @@ const initialState = { hideImportantInAdminTab: false, interleave: false, interleaveColor: '#909090', + statLinked: true, + statFontSize: 12, + statTabsStyle: 'default', } as const; export function settingsReducer( diff --git a/tgui/packages/tgui/components/ColorBox.tsx b/tgui/packages/tgui/components/ColorBox.tsx index b04cdd9241..fe55366952 100644 --- a/tgui/packages/tgui/components/ColorBox.tsx +++ b/tgui/packages/tgui/components/ColorBox.tsx @@ -24,7 +24,7 @@ export function ColorBox(props: Props) { className={classes(['ColorBox', className, computeBoxClassName(rest)])} {...computeBoxProps(rest)} > - {content || '.'} + {content} ); } diff --git a/tgui/packages/tgui/interfaces/AppearanceChanger/AppearanceChangerBody.tsx b/tgui/packages/tgui/interfaces/AppearanceChanger/AppearanceChangerBody.tsx index 1991030820..68bb73dfcc 100644 --- a/tgui/packages/tgui/interfaces/AppearanceChanger/AppearanceChangerBody.tsx +++ b/tgui/packages/tgui/interfaces/AppearanceChanger/AppearanceChangerBody.tsx @@ -1,7 +1,7 @@ import { sortBy } from 'common/collections'; import { useBackend } from '../../backend'; -import { Button, LabeledList, Section } from '../../components'; +import { Button, LabeledList, Section, Stack } from '../../components'; import { Data, species, styles } from './types'; export const AppearanceChangerSpecies = (props) => { @@ -66,23 +66,50 @@ export const AppearanceChangerEars = (props) => { const { ear_style, ear_styles } = data; return ( -
- - {sortBy(ear_styles, (e: styles) => e.name.toLowerCase()).map((ear) => ( - - ))} -
+ + +
+ + {sortBy(ear_styles, (e: styles) => e.name.toLowerCase()).map( + (ear) => ( + + ), + )} +
+
+ +
+ + {sortBy(ear_styles, (e: styles) => e.name.toLowerCase()).map( + (ear) => ( + + ), + )} +
+
+
); }; diff --git a/tgui/packages/tgui/interfaces/AppearanceChanger/AppearanceChangerDetails.tsx b/tgui/packages/tgui/interfaces/AppearanceChanger/AppearanceChangerDetails.tsx index c5d2f403b7..e9e3472a18 100644 --- a/tgui/packages/tgui/interfaces/AppearanceChanger/AppearanceChangerDetails.tsx +++ b/tgui/packages/tgui/interfaces/AppearanceChanger/AppearanceChangerDetails.tsx @@ -1,6 +1,6 @@ import { useBackend } from '../../backend'; import { Box, Button, ColorBox, LabeledList, Section } from '../../components'; -import { Data } from './types'; +import { Data, SPRITE_ACCESSORY_COLOR_CHANNEL_NAMES } from './types'; export const AppearanceChangerColors = (props) => { const { act, data } = useBackend(); @@ -56,14 +56,25 @@ export const AppearanceChangerColors = (props) => { - + + {data.ear_secondary_colors.map((color, index) => ( + + ))} diff --git a/tgui/packages/tgui/interfaces/AppearanceChanger/types.ts b/tgui/packages/tgui/interfaces/AppearanceChanger/types.ts index 4d62e13177..aae93386f1 100644 --- a/tgui/packages/tgui/interfaces/AppearanceChanger/types.ts +++ b/tgui/packages/tgui/interfaces/AppearanceChanger/types.ts @@ -1,5 +1,12 @@ import { BooleanLike } from 'common/react'; +export const SPRITE_ACCESSORY_COLOR_CHANNEL_NAMES = [ + 'Primary', + 'Secondary', + 'Tertiary', + 'Quaternary', +]; + export type Data = { name: string; specimen: string; @@ -39,6 +46,8 @@ export type Data = { wing2_color: string; facial_hair_styles: { facialhairstyle: string }[]; hair_styles: { hairstyle: string }[]; + ear_secondary_style: string; + ear_secondary_colors: string[]; }; type genders = { gender_name: string; gender_key: string }[]; diff --git a/tgui/packages/tgui/interfaces/BodyDesigner/types.ts b/tgui/packages/tgui/interfaces/BodyDesigner/types.ts index 42be826e55..56f1eae39d 100644 --- a/tgui/packages/tgui/interfaces/BodyDesigner/types.ts +++ b/tgui/packages/tgui/interfaces/BodyDesigner/types.ts @@ -10,9 +10,9 @@ export type Data = { styleHref: string; style: string; color: string | undefined; - colorHref: string | undefined; + colorHref: string | undefined | { act: string; params: Object }; color2?: string | undefined; - colorHref2?: string | undefined; + colorHref2?: string | undefined | { act: string; params: Object }; }; disk: BooleanLike; diskStored: BooleanLike; @@ -31,6 +31,7 @@ export type activeBodyRecord = { digitigrade: BooleanLike; styles: { Ears: colourableStyle; + Horns: colourableStyle; Tail: colourableStyle; Wing: colourableStyle; Hair: simpleStyle; diff --git a/tgui/packages/tgui/interfaces/Robotact/StatusScreen.tsx b/tgui/packages/tgui/interfaces/Robotact/StatusScreen.tsx index 08ab33efc2..f07c1c4315 100644 --- a/tgui/packages/tgui/interfaces/Robotact/StatusScreen.tsx +++ b/tgui/packages/tgui/interfaces/Robotact/StatusScreen.tsx @@ -1,7 +1,9 @@ import { useBackend } from 'tgui/backend'; import { Box, + ColorBox, ImageButton, + Input, LabeledList, NoticeBox, ProgressBar, @@ -164,9 +166,9 @@ const Configuration = (props) => { }; const Status = (props) => { - const { data } = useBackend(); + const { act, data } = useBackend(); - const { charge, max_charge, health, max_health } = data; + const { charge, max_charge, health, max_health, light_color } = data; return (
@@ -199,6 +201,17 @@ const Status = (props) => { }} /> + + + + act('set_light_col', { value })} + /> + +
); diff --git a/tgui/packages/tgui/interfaces/Robotact/types.ts b/tgui/packages/tgui/interfaces/Robotact/types.ts index 9fd62f6280..bd33676d99 100644 --- a/tgui/packages/tgui/interfaces/Robotact/types.ts +++ b/tgui/packages/tgui/interfaces/Robotact/types.ts @@ -30,6 +30,8 @@ export type Data = { health: number; max_health: number; + light_color: string; + // Modules modules_static: Module[]; emag_modules_static: Module[]; diff --git a/tgui/packages/tgui/interfaces/VorePanel/VoreBellySelectionAndCustomization.tsx b/tgui/packages/tgui/interfaces/VorePanel/VoreBellySelectionAndCustomization.tsx index e96c0b6428..3e30618ae8 100644 --- a/tgui/packages/tgui/interfaces/VorePanel/VoreBellySelectionAndCustomization.tsx +++ b/tgui/packages/tgui/interfaces/VorePanel/VoreBellySelectionAndCustomization.tsx @@ -29,6 +29,10 @@ export const VoreBellySelectionAndCustomization = (props: { Export + act('importpanel')}> + Import + + {our_bellies.map((belly) => ( { const { db_version, db_repo, mob_name, bellies } = data; + if (!bellies) { + return; + } + let datesegment = getCurrentTimestamp(); let filename = mob_name + datesegment + extension; diff --git a/tgui/packages/tgui/interfaces/VorePanelExport/types.ts b/tgui/packages/tgui/interfaces/VorePanelExport/types.ts index 720a3a7287..38575ccfe6 100644 --- a/tgui/packages/tgui/interfaces/VorePanelExport/types.ts +++ b/tgui/packages/tgui/interfaces/VorePanelExport/types.ts @@ -4,7 +4,7 @@ export type Data = { db_version: string; db_repo: string; mob_name: string; - bellies: Belly[]; + bellies?: Belly[]; }; export type Belly = { diff --git a/vorestation.dme b/vorestation.dme index 7a400ffa06..6817963a1a 100644 --- a/vorestation.dme +++ b/vorestation.dme @@ -4221,6 +4221,7 @@ #include "code\modules\vore\appearance\preferences_vr.dm" #include "code\modules\vore\appearance\update_icons_vr.dm" #include "code\modules\vore\eating\belly_dat_vr.dm" +#include "code\modules\vore\eating\belly_import.dm" #include "code\modules\vore\eating\belly_messages.dm" #include "code\modules\vore\eating\belly_obj_vr.dm" #include "code\modules\vore\eating\bellymodes_datum_vr.dm"