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