diff --git a/code/game/machinery/limbgrower.dm b/code/game/machinery/limbgrower.dm index 90408870a7..c3ce5732ab 100644 --- a/code/game/machinery/limbgrower.dm +++ b/code/game/machinery/limbgrower.dm @@ -330,7 +330,7 @@ var/obj/item/organ/genital/breasts/boobs = new(loc) if(features["has_breasts"]) boobs.color = sanitize_hexcolor(features["breasts_color"], 6, TRUE) - boobs.size = features["breasts_size"] + boobs.size = GLOB.breast_values[features["breasts_size"]] boobs.shape = features["breasts_shape"] if(!features["breasts_producing"]) boobs.genital_flags &= ~(GENITAL_FUID_PRODUCTION|CAN_CLIMAX_WITH|CAN_MASTURBATE_WITH) diff --git a/code/modules/arousal/genitals.dm b/code/modules/arousal/genitals.dm index ffe2e1ce42..c6776ddff3 100644 --- a/code/modules/arousal/genitals.dm +++ b/code/modules/arousal/genitals.dm @@ -190,7 +190,7 @@ aroused_state = FALSE /obj/item/organ/genital/proc/generate_fluid(datum/reagents/R) - var/amount = clamp((fluid_rate * ((world.time - last_orgasmed) / (10 SECONDS)) * fluid_mult),0,fluid_max_volume) + var/amount = get_fluid() R.clear_reagents() R.maximum_volume = fluid_max_volume if(fluid_id) @@ -325,7 +325,7 @@ var/obj/item/organ/genital/G = A var/datum/sprite_accessory/S - var/size = G.size + var/size = G.size_to_state() switch(G.type) if(/obj/item/organ/genital/penis) S = GLOB.cock_shapes_list[G.shape] diff --git a/code/modules/arousal/organs/breasts.dm b/code/modules/arousal/organs/breasts.dm index 53892b24d8..4e65cb3200 100644 --- a/code/modules/arousal/organs/breasts.dm +++ b/code/modules/arousal/organs/breasts.dm @@ -8,7 +8,7 @@ icon = 'icons/obj/genitals/breasts.dmi' zone = BODY_ZONE_CHEST slot = ORGAN_SLOT_BREASTS - size = BREASTS_SIZE_DEF // "c". Refer to the breast_values static list below for the cups associated number values + size = 3 fluid_id = /datum/reagent/consumable/milk fluid_rate = MILK_RATE shape = DEF_BREASTS_SHAPE @@ -19,19 +19,12 @@ orgasm_verb = "leaking" fluid_transfer_factor = 0.5 layer_index = BREASTS_LAYER_INDEX - var/static/list/breast_values = list("a" = 1, "b" = 2, "c" = 3, "d" = 4, "e" = 5, "f" = 6, "g" = 7, "h" = 8, "i" = 9, "j" = 10, "k" = 11, "l" = 12, "m" = 13, "n" = 14, "o" = 15, "huge" = 16, "massive" = 17, "giga" = 25, "impossible" = 30, "flat" = 0) - var/cached_size //these two vars pertain size modifications and so should be expressed in NUMBERS. var/prev_size //former cached_size value, to allow update_size() to early return should be there no significant changes. -/obj/item/organ/genital/breasts/Initialize(mapload, do_update = TRUE) - if(do_update) - cached_size = breast_values[size] - prev_size = cached_size - return ..() - /obj/item/organ/genital/breasts/update_appearance() . = ..() var/lowershape = lowertext(shape) + var/size_state = size_to_state() switch(lowershape) if("pair") desc = "You see a pair of breasts." @@ -41,13 +34,13 @@ desc = "You see three sets of breasts, running from their chest to their belly." else desc = "You see some breasts, they seem to be quite exotic." - if(size == "huge") - desc = "You see [pick("some serious honkers", "a real set of badonkers", "some dobonhonkeros", "massive dohoonkabhankoloos", "two big old tonhongerekoogers", "a couple of giant bonkhonagahoogs", "a pair of humongous hungolomghnonoloughongous")]. Their volume is way beyond cupsize now, measuring in about [round(cached_size*(owner ? get_size(owner) : 1))]cm in diameter." + if(size_state == "huge") + desc = "You see [pick("some serious honkers", "a real set of badonkers", "some dobonhonkeros", "massive dohoonkabhankoloos", "two big old tonhongerekoogers", "a couple of giant bonkhonagahoogs", "a pair of humongous hungolomghnonoloughongous")]. Their volume is way beyond cupsize now, measuring in about [round(size*(owner ? get_size(owner) : 1))]cm in diameter." else - if (size == "flat") + if (size_state == "flat") desc += " They're very small and flatchested, however." else - desc += " You estimate that they're [uppertext(size)]-cups." + desc += " You estimate that they're [uppertext(size_state)]-cups." if((genital_flags & GENITAL_FUID_PRODUCTION) && aroused_state) var/datum/reagent/R = GLOB.chemical_reagents_list[fluid_id] @@ -55,7 +48,7 @@ desc += " They're leaking [lowertext(R.name)]." var/datum/sprite_accessory/S = GLOB.breasts_shapes_list[shape] var/icon_shape = S ? S.icon_state : "pair" - var/icon_size = clamp(breast_values[size], BREASTS_ICON_MIN_SIZE, BREASTS_ICON_MAX_SIZE) + var/icon_size = clamp(GLOB.breast_values[size_state], BREASTS_ICON_MIN_SIZE, BREASTS_ICON_MAX_SIZE) icon_state = "breasts_[icon_shape]_[icon_size]" if(owner) if(owner.dna.species.use_skintones && owner.dna.features["genitals_use_skintone"]) @@ -74,45 +67,49 @@ //this is far too lewd wah /obj/item/organ/genital/breasts/modify_size(modifier, min = -INFINITY, max = INFINITY) - var/new_value = clamp(cached_size + modifier, min, max) - if(new_value == cached_size) + var/new_value = clamp(size + modifier, max(min, min_size ? min_size : -INFINITY), min(max_size ? max_size : INFINITY, max)) + if(new_value == size) return - prev_size = cached_size - cached_size = new_value + prev_size = size + size = new_value update() ..() +/obj/item/organ/genital/breasts/size_to_state() + var/str_size + switch(size) + if(0) //flatchested + str_size = "flat" + if(1 to 8) //modest + str_size = GLOB.breast_values[size] + if(9 to 15) //massive + str_size = GLOB.breast_values[size] + if(16 to 17) //ridiculous + str_size = GLOB.breast_values[size] + if(18 to 24) //AWOOOOGAAAAAAA + str_size = "massive" + if(25 to 29) //AWOOOOOOGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + str_size = "giga" + if(30 to INFINITY) //AWWWWWWWWWWWWWOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOGGGGGAAAAAAAAAAAAAAAAAAAAAA + str_size = "impossible" + return str_size + /obj/item/organ/genital/breasts/update_size()//wah - var/rounded_cached = round(cached_size) - if(cached_size < 0)//I don't actually know what round() does to negative numbers, so to be safe!!fixed + var/rounded_size = round(size) + var/size_state = size_to_state() + if(rounded_size < 0)//I don't actually know what round() does to negative numbers, so to be safe!!fixed if(owner) to_chat(owner, "You feel your breasts shrinking away from your body as your chest flattens out.") QDEL_IN(src, 1) return - switch(rounded_cached) - if(0) //flatchested - size = "flat" - if(1 to 8) //modest - size = breast_values[rounded_cached] - if(9 to 15) //massive - size = breast_values[rounded_cached] - if(16 to 17) //ridiculous - size = breast_values[rounded_cached] - if(18 to 24) //AWOOOOGAAAAAAA - size = "massive" - if(25 to 29) //AWOOOOOOGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - size = "giga" - if(30 to INFINITY) //AWWWWWWWWWWWWWOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOGGGGGAAAAAAAAAAAAAAAAAAAAAA - size = "impossible" - - if((rounded_cached < 18 || rounded_cached == 25 || rounded_cached == 30) && owner )//Because byond doesn't count from 0, I have to do this. + if((rounded_size < 18 || rounded_size == 25 || rounded_size == 30) && owner )//Because byond doesn't count from 0, I have to do this. var/mob/living/carbon/human/H = owner var/r_prev_size = round(prev_size) - if (rounded_cached > r_prev_size) - to_chat(H, "Your breasts [pick("swell up to", "flourish into", "expand into", "burst forth into", "grow eagerly into", "amplify into")] a [uppertext(size)]-cup.") - else if (rounded_cached < r_prev_size) - to_chat(H, "Your breasts [pick("shrink down to", "decrease into", "diminish into", "deflate into", "shrivel regretfully into", "contracts into")] a [uppertext(size)]-cup.") + if (rounded_size > r_prev_size) + to_chat(H, "Your breasts [pick("swell up to", "flourish into", "expand into", "burst forth into", "grow eagerly into", "amplify into")] a [uppertext(size_state)]-cup.") + else if (rounded_size < r_prev_size) + to_chat(H, "Your breasts [pick("shrink down to", "decrease into", "diminish into", "deflate into", "shrivel regretfully into", "contracts into")] a [uppertext(size_state)]-cup.") /obj/item/organ/genital/breasts/get_features(mob/living/carbon/human/H) var/datum/dna/D = H.dna @@ -120,16 +117,13 @@ color = SKINTONE2HEX(H.skin_tone) else color = "#[D.features["breasts_color"]]" - size = D.features["breasts_size"] + size = GLOB.breast_values[D.features["breasts_size"]] + max_size = D.features["breasts_max_size"] + min_size = D.features["breasts_min_size"] shape = D.features["breasts_shape"] if(!D.features["breasts_producing"]) genital_flags &= ~ (GENITAL_FUID_PRODUCTION|CAN_CLIMAX_WITH|CAN_MASTURBATE_WITH) - if(!isnum(size)) - cached_size = breast_values[size] - else - cached_size = size - size = breast_values[size] - prev_size = cached_size + prev_size = size toggle_visibility(D.features["breasts_visibility"], FALSE) if(D.features["breasts_stuffing"]) toggle_visibility(GEN_ALLOW_EGG_STUFFING, FALSE) diff --git a/code/modules/arousal/organs/butt.dm b/code/modules/arousal/organs/butt.dm index 526bc28ff1..bcad9af8fb 100644 --- a/code/modules/arousal/organs/butt.dm +++ b/code/modules/arousal/organs/butt.dm @@ -7,6 +7,7 @@ slot = ORGAN_SLOT_BUTT w_class = 3 size = 0 + max_size = BUTT_SIZE_MAX var/size_name = "nonexistent" shape = "Pair" //turn this into a default constant if for some inexplicable reason we get more than one butt type but I doubt it. genital_flags = UPDATE_OWNER_APPEARANCE|GENITAL_UNDIES_HIDDEN|CAN_CUM_INTO|HAS_EQUIPMENT @@ -15,8 +16,8 @@ var/prev_size //former size value, to allow update_size() to early return should be there no significant changes. layer_index = BUTT_LAYER_INDEX -/obj/item/organ/genital/butt/modify_size(modifier, min = -INFINITY, max = BUTT_SIZE_MAX) - var/new_value = clamp(size_cached + modifier, min, max) +/obj/item/organ/genital/butt/modify_size(modifier, min = -INFINITY, max = INFINITY) + var/new_value = clamp(size_cached + modifier, max(min, min_size ? min_size : -INFINITY), min(max_size ? max_size : INFINITY, max)) if(new_value == size_cached) return prev_size = size_cached @@ -88,6 +89,8 @@ else color = "#[D.features["butt_color"]]" size = D.features["butt_size"] + max_size = D.features["butt_max_size"] + min_size = D.features["butt_min_size"] prev_size = size size_cached = size toggle_visibility(D.features["butt_visibility"], FALSE) diff --git a/code/modules/arousal/organs/penis.dm b/code/modules/arousal/organs/penis.dm index 9e986d9bbb..46dc8bb19c 100644 --- a/code/modules/arousal/organs/penis.dm +++ b/code/modules/arousal/organs/penis.dm @@ -14,18 +14,20 @@ shape = DEF_COCK_SHAPE size = 2 //arbitrary value derived from length and diameter for sprites. layer_index = PENIS_LAYER_INDEX - var/length = 6 //inches + var/length = 6 //inches + var/max_length = 9 + var/min_length = 2 var/prev_length = 6 //really should be renamed to prev_length var/diameter = 4.38 var/diameter_ratio = COCK_DIAMETER_RATIO_DEF //0.25; check citadel_defines.dm /obj/item/organ/genital/penis/modify_size(modifier, min = -INFINITY, max = INFINITY) - var/new_value = clamp(length + modifier, min, max) + var/new_value = clamp(length + modifier, max(min, min_size ? min_size : -INFINITY), min(max_length ? max_length : INFINITY, max)) if(new_value == length) return prev_length = length - length = clamp(length + modifier, min, max) + length = new_value update() ..() @@ -95,6 +97,8 @@ else color = "#[D.features["cock_color"]]" length = D.features["cock_length"] + max_length = D.features["cock_max_length"] + min_length = D.features["cock_min_length"] diameter_ratio = D.features["cock_diameter_ratio"] shape = D.features["cock_shape"] prev_length = length diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm index c3dd22844b..e7b076f5bd 100644 --- a/code/modules/client/preferences.dm +++ b/code/modules/client/preferences.dm @@ -844,6 +844,8 @@ GLOBAL_LIST_EMPTY(preferences_datums) tauric_shape = TRUE dat += "Penis Shape: [features["cock_shape"]][tauric_shape ? " (Taur)" : ""]" dat += "Penis Length: [features["cock_length"]] inch(es)" + dat += "Max Length:[features["cock_max_length"] ? features["cock_max_length"] : "Disabled"]" + dat += "Min Length:[features["cock_min_length"] ? features["cock_min_length"] : "Disabled"]" dat += "Diameter Ratio: [features["cock_diameter_ratio"]]" //SPLURT Edit dat += "Penis Visibility:[features["cock_visibility"]]" dat += "Egg Stuffing:[features["cock_stuffing"] == TRUE ? "Yes" : "No"]" //SPLURT Edit @@ -859,6 +861,8 @@ GLOBAL_LIST_EMPTY(preferences_datums) dat += "Testicles Visibility:[features["balls_visibility"]]" //SPLURT Edit dat += "Egg Stuffing:[features["balls_stuffing"] == TRUE ? "Yes" : "No"]" + dat += "Max Size:[features["balls_max_size"] ? features["balls_max_size"] : "Disabled"]" + dat += "Min Size:[features["balls_min_size"] ? features["balls_min_size"] : "Disabled"]" dat += "Produces:" var/datum/reagent/balls_fluid = find_reagent_object_from_type(features["balls_fluid"]) if(balls_fluid && (balls_fluid in GLOB.genital_fluids_list)) @@ -907,6 +911,8 @@ GLOBAL_LIST_EMPTY(preferences_datums) dat += "Lactates:[features["breasts_producing"] == TRUE ? "Yes" : "No"]" //SPLURT Edit dat += "Egg Stuffing:[features["breasts_stuffing"] == TRUE ? "Yes" : "No"]" + dat += "Max Size:[features["breasts_max_size"] ? features["breasts_max_size"] : "Disabled"]" + dat += "Min Size:[features["breasts_min_size"] ? features["breasts_min_size"] : "Disabled"]" if(features["breasts_producing"] == TRUE) dat += "Produces:" var/datum/reagent/breasts_fluid = find_reagent_object_from_type(features["breasts_fluid"]) @@ -930,6 +936,8 @@ GLOBAL_LIST_EMPTY(preferences_datums) dat += "Butt Visibility:[features["butt_visibility"]]" //SPLURT Edit dat += "Egg Stuffing:[features["butt_stuffing"] == TRUE ? "Yes" : "No"]" + dat += "Max Size:[features["butt_max_size"] ? features["butt_max_size"] : "Disabled"]" + dat += "Min Size:[features["butt_min_size"] ? features["butt_min_size"] : "Disabled"]" dat += "Butthole Sprite:[features["has_anus"] == TRUE ? "Yes" : "No"]" if(features["has_anus"]) dat += "Butthole Color:
" @@ -953,6 +961,8 @@ GLOBAL_LIST_EMPTY(preferences_datums) dat += "Color:
" dat += "#[features["belly_color"]] Change
" dat += "Belly Size:[features["belly_size"]]" + dat += "Max Size:[features["belly_max_size"] ? features["belly_max_size"] : "Disabled" ]" + dat += "Min Size:[features["belly_min_size"] ? features["belly_min_size"] : "Disabled" ]" dat += "Belly Visibility:[features["belly_visibility"]]" dat += "Egg Stuffing:[features["belly_stuffing"] == TRUE ? "Yes" : "No"]" dat += "" @@ -2987,6 +2997,82 @@ GLOBAL_LIST_EMPTY(preferences_datums) if(n_vis) features["belly_visibility"] = n_vis + if("cock_max_length") + var/max_B = CONFIG_GET(number/penis_max_inches_prefs) + var/new_size = input(user, "Max size:\n([features["cock_length"]]-[max_B])(0 = disabled)", "Character Preference") as num|null + if(new_size) + features["cock_max_length"] = clamp(round(new_size), features["cock_length"], max_B) + else + features -= "cock_max_length" + + if("balls_max_size") + var/new_size = input(user, "Max size:\n([BALLS_SIZE_MIN]-[BALLS_SIZE_MAX])(0 = disabled)", "Character Preference") as num|null + if(new_size) + features["balls_max_size"] = clamp(round(new_size), BALLS_SIZE_MIN, BALLS_SIZE_MAX) + else + features -= "balls_max_size" + + if("breasts_max_size") + var/new_size = input(user, "Breast Max Size (cancel to disable)", "Character Preference") as null|anything in GLOB.breast_values + if(new_size) + features["breasts_max_size"] = new_size + else + features -= "breasts_max_size" + + if("belly_max_size") + var/max_B = CONFIG_GET(number/belly_max_size_prefs) + var/new_size = input(user, "Max size:\n([features["belly_size"]]-[max_B])(0 = disabled)", "Character Preference") as num|null + if(new_size) + features["belly_max_size"] = clamp(round(new_size), features["belly_size"], max_B) + else + features -= "belly_max_size" + + if("butt_max_size") + var/max_B = CONFIG_GET(number/butt_max_size_prefs) + var/new_size = input(user, "Max size:\n([features["butt_size"]]-[max_B])(0 = disabled)", "Character Preference") as num|null + if(new_size) + features["butt_max_size"] = clamp(round(new_size), features["butt_size"], max_B) + else + features -= "butt_max_size" + + if("cock_min_length") + var/min_B = CONFIG_GET(number/penis_min_inches_prefs) + var/new_size = input(user, "Min size:\n([min_B]-[features["cock_length"]])(0 = disabled)", "Character Preference") as num|null + if(new_size) + features["cock_min_length"] = clamp(round(new_size), min_B, features["cock_length"]) + else + features -= "cock_min_length" + + if("balls_min_size") + var/new_size = input(user, "Min size:\n([BALLS_SIZE_MIN]-[BALLS_SIZE_MAX])(0 = disabled)", "Character Preference") as num|null + if(new_size) + features["balls_min_size"] = clamp(round(new_size), BALLS_SIZE_MIN, BALLS_SIZE_MAX) + else + features -= "balls_min_size" + + if("breasts_min_size") + var/new_size = input(user, "Breast Min Size (cancel to disable)", "Character Preference") as null|anything in GLOB.breast_values + if(new_size) + features["breasts_min_size"] = new_size + else + features -= "breasts_min_size" + + if("belly_min_size") + var/min_B = CONFIG_GET(number/belly_min_size_prefs) + var/new_size = input(user, "Min size:\n([min_B]-[features["belly_size"]])(0 = disabled)", "Character Preference") as num|null + if(new_size) + features["belly_min_size"] = clamp(round(new_size), min_B, features["belly_size"]) + else + features -= "belly_min_size" + + if("butt_min_size") + var/min_B = CONFIG_GET(number/butt_min_size_prefs) + var/new_size = input(user, "Min size:\n([min_B]-[features["butt_size"]])(0 = disabled)", "Character Preference") as num|null + if(new_size) + features["butt_min_size"] = clamp(round(new_size), min_B, features["butt_size"]) + else + features -= "butt_min_size" + if("ooccolor") var/new_ooccolor = input(user, "Choose your OOC colour:", "Game Preference",ooccolor) as color|null if(new_ooccolor) @@ -4162,3 +4248,4 @@ GLOBAL_LIST_EMPTY(preferences_datums) #undef DEFAULT_SLOT_AMT #undef HANDS_SLOT_AMT #undef BACKPACK_SLOT_AMT + diff --git a/code/modules/client/preferences_savefile.dm b/code/modules/client/preferences_savefile.dm index 9811f7a2be..aad17eb424 100644 --- a/code/modules/client/preferences_savefile.dm +++ b/code/modules/client/preferences_savefile.dm @@ -1054,6 +1054,28 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car S["feature_inert_eggs"] >> features["inert_eggs"] + if(S["features_cock_max_length"]) + S["features_cock_max_length"] >> features["cock_max_length"] + if(S["features_balls_max_size"]) + S["features_balls_max_size"] >> features["balls_max_size"] + if(S["features_breasts_max_size"]) + S["features_breasts_max_size"] >> features["breasts_max_size"] + if(S["features_belly_max_size"]) + S["features_belly_max_size"] >> features["belly_max_size"] + if(S["features_butt_max_size"]) + S["features_butt_max_size"] >> features["butt_max_size"] + + if(S["features_cock_min_length"]) + S["features_cock_min_length"] >> features["cock_min_length"] + if(S["features_balls_min_size"]) + S["features_balls_min_size"] >> features["balls_min_size"] + if(S["features_breasts_min_size"]) + S["features_breasts_min_size"] >> features["breasts_min_size"] + if(S["features_belly_min_size"]) + S["features_belly_min_size"] >> features["belly_min_size"] + if(S["features_butt_min_size"]) + S["features_butt_min_size"] >> features["butt_min_size"] + var/char_vr_path = "[vr_path]/character_[default_slot]_v2.json" if(fexists(char_vr_path)) var/list/json_from_file = json_decode(file2text(char_vr_path)) @@ -1413,6 +1435,19 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car WRITE_FILE(S["feature_inert_eggs"], features["inert_eggs"]) + + WRITE_FILE(S["features_cock_max_length"], features["cock_max_length"]) + WRITE_FILE(S["features_balls_max_size"], features["balls_max_size"]) + WRITE_FILE(S["features_breasts_max_size"], features["breasts_max_size"]) + WRITE_FILE(S["features_belly_max_size"], features["belly_max_size"]) + WRITE_FILE(S["features_butt_max_size"], features["butt_max_size"]) + + WRITE_FILE(S["features_cock_min_length"], features["cock_min_length"]) + WRITE_FILE(S["features_balls_min_size"], features["balls_min_size"]) + WRITE_FILE(S["features_breasts_min_size"], features["breasts_min_size"]) + WRITE_FILE(S["features_belly_min_size"], features["belly_min_size"]) + WRITE_FILE(S["features_butt_min_size"], features["butt_min_size"]) + WRITE_FILE(S["feature_neckfire"], features["neckfire"]) WRITE_FILE(S["feature_neckfire_color"], features["neckfire_color"]) diff --git a/modular_citadel/code/modules/reagents/chemistry/reagents/enlargement.dm b/modular_citadel/code/modules/reagents/chemistry/reagents/enlargement.dm index 24b0fc0a76..8f0e3d00d7 100644 --- a/modular_citadel/code/modules/reagents/chemistry/reagents/enlargement.dm +++ b/modular_citadel/code/modules/reagents/chemistry/reagents/enlargement.dm @@ -68,8 +68,7 @@ B.color = "#[M.dna.features["breasts_color"]]" else B.color = SKINTONE2HEX(H.skin_tone) - B.size = "flat" - B.cached_size = 0 + B.size = 0 B.prev_size = 0 to_chat(H, "Your chest feels warm, tingling with newfound sensitivity.") H.reagents.remove_reagent(type, 5) @@ -145,12 +144,12 @@ var/obj/item/organ/genital/breasts/B = M.getorganslot(ORGAN_SLOT_BREASTS) if(!B) return..() - var/optimal_size = B.breast_values[M.dna.features["breasts_size"]] + var/optimal_size = GLOB.breast_values[M.dna.features["breasts_size"]] if(!optimal_size)//Fast fix for those who don't want it. B.modify_size(-0.1) - else if(B.cached_size > optimal_size) + else if(B.size > optimal_size) B.modify_size(-0.05, optimal_size) - else if(B.cached_size < optimal_size) + else if(B.size < optimal_size) B.modify_size(0.05, 0, optimal_size) return ..() @@ -238,7 +237,7 @@ if(B) B.modify_size(-0.05) - if(V && (!B || B.cached_size <= 0)) + if(V && (!B || B.size <= 0)) qdel(V) if(W && (!B || B.size <= 0)) qdel(W) diff --git a/modular_sand/code/datums/components/interaction_menu_granter.dm b/modular_sand/code/datums/components/interaction_menu_granter.dm index 89ea6ff046..ab9439cb2a 100644 --- a/modular_sand/code/datums/components/interaction_menu_granter.dm +++ b/modular_sand/code/datums/components/interaction_menu_granter.dm @@ -136,14 +136,8 @@ else visibility = "Hidden by clothes" - var/extras = "None" - if(CHECK_BITFIELD(genital.genital_flags, GENITAL_CAN_STUFF)) - extras = "Allows egg stuffing" - - genital_entry["extras"] = extras genital_entry["visibility"] = visibility genital_entry["possible_choices"] = GLOB.genitals_visibility_toggles - genital_entry["extra_choices"] = list(GEN_ALLOW_EGG_STUFFING) genital_entry["can_arouse"] = ( !!CHECK_BITFIELD(genital.genital_flags, GENITAL_CAN_AROUSE) \ && !(HAS_TRAIT(get_genitals, TRAIT_PERMABONER) \ @@ -169,37 +163,6 @@ genitals += list(simulated_ass) .["genitals"] = genitals - //Get their genitals - var/list/genital_fluids = list() - var/mob/living/carbon/target_genitals = target || self - if(istype(target_genitals)) - for(var/obj/item/organ/genital/genital in target_genitals.internal_organs) - if(!(CHECK_BITFIELD(genital.genital_flags, GENITAL_FUID_PRODUCTION))) - continue - var/fluids = (clamp(genital.fluid_rate * ((world.time - genital.last_orgasmed) / (10 SECONDS)) * genital.fluid_mult, 0, genital.fluid_max_volume) / genital.fluid_max_volume) - var/list/genital_entry = list() - genital_entry["name"] = "[genital.name]" - genital_entry["key"] = REF(genital) - genital_entry["fluid"] = fluids - genital_fluids += list(genital_entry) - .["genital_fluids"] = genital_fluids - - var/list/genital_interactibles = list() - if(istype(target_genitals)) - for(var/obj/item/organ/genital/genital in target_genitals.internal_organs) - if(!genital.is_exposed()) - continue - var/list/equipment_names = list() - for(var/obj/equipment in genital.contents) - equipment_names += equipment.name - var/list/genital_entry = list() - genital_entry["name"] = "[genital.name]" - genital_entry["key"] = REF(genital) - genital_entry["possible_choices"] = GLOB.genitals_interactions - genital_entry["equipments"] = equipment_names - genital_interactibles += list(genital_entry) - .["genital_interactibles"] = genital_interactibles - var/datum/preferences/prefs = self?.client.prefs if(prefs) //Getting char prefs @@ -294,28 +257,6 @@ return TRUE else return FALSE - if("genital_interaction") - var/mob/living/carbon/actual_target = target || usr - var/mob/user = usr - var/obj/item/organ/genital/genital = locate(params["genital"], actual_target.internal_organs) - if(!(genital && (genital in actual_target.internal_organs))) - return FALSE - switch(params["action"]) - if(GEN_INSERT_EQUIPMENT) - var/obj/item/stuff = user.get_active_held_item() - if(!istype(stuff)) - to_chat(user, span_warning("You need to hold an item to insert it!")) - return FALSE - stuff.insert_item_organ(user, actual_target, genital) - if(GEN_REMOVE_EQUIPMENT) - var/obj/item/selected_item = input(user, "Pick an item to remove", "Removing item") as null|anything in genital.contents - if(selected_item) - if(!do_mob(user, actual_target, 5 SECONDS)) - return FALSE - if(!user.put_in_hands(selected_item)) - user.transferItemToLoc(get_turf(user)) - return TRUE - return FALSE if("char_pref") var/datum/preferences/prefs = parent_mob.client.prefs var/value = num_to_pref(params["value"]) diff --git a/modular_sand/code/datums/interactions/interaction_datums/lewd/breasts.dm b/modular_sand/code/datums/interactions/interaction_datums/lewd/breasts.dm index fdd4e5bf82..961be135d9 100644 --- a/modular_sand/code/datums/interactions/interaction_datums/lewd/breasts.dm +++ b/modular_sand/code/datums/interactions/interaction_datums/lewd/breasts.dm @@ -41,8 +41,8 @@ if("f", "g", "h") modifier = 3 else - if(milkers.size in milkers.breast_values) - modifier = clamp(milkers.breast_values[milkers.size] - 5, 0, INFINITY) + if(milkers.size in GLOB.breast_values) + modifier = clamp(GLOB.breast_values[milkers.size] - 5, 0, INFINITY) else modifier = 1 target.reagents.add_reagent(milktype, rand(1,3 * modifier)) diff --git a/modular_sand/code/datums/interactions/interaction_datums/lewd/nipsuck.dm b/modular_sand/code/datums/interactions/interaction_datums/lewd/nipsuck.dm index e5a0b8911e..eb466e39f4 100644 --- a/modular_sand/code/datums/interactions/interaction_datums/lewd/nipsuck.dm +++ b/modular_sand/code/datums/interactions/interaction_datums/lewd/nipsuck.dm @@ -22,8 +22,8 @@ if("f", "g", "h") modifier = 3 else - if(B.size in B.breast_values) - modifier = clamp(B.breast_values[B.size] - 5, 0, INFINITY) + if(B.size in GLOB.breast_values) + modifier = clamp(GLOB.breast_values[B.size] - 5, 0, INFINITY) else modifier = 1 if(B.fluid_id) @@ -42,8 +42,8 @@ if("f", "g", "h") modifier = 3 else - if(B.size in B.breast_values) - modifier = clamp(B.breast_values[B.size] - 5, 0, INFINITY) + if(B.size in GLOB.breast_values) + modifier = clamp(GLOB.breast_values[B.size] - 5, 0, INFINITY) else modifier = 1 if(B.fluid_id) @@ -63,8 +63,8 @@ if("f", "g", "h") modifier = 3 else - if(B.size in B.breast_values) - modifier = clamp(B.breast_values[B.size] - 5, 0, INFINITY) + if(B.size in GLOB.breast_values) + modifier = clamp(GLOB.breast_values[B.size] - 5, 0, INFINITY) else modifier = 1 if(B.fluid_id) diff --git a/modular_sand/code/datums/interactions/interaction_datums/lewd/self/breasts.dm b/modular_sand/code/datums/interactions/interaction_datums/lewd/self/breasts.dm index 5c91e50a3c..36140d2cf0 100644 --- a/modular_sand/code/datums/interactions/interaction_datums/lewd/self/breasts.dm +++ b/modular_sand/code/datums/interactions/interaction_datums/lewd/self/breasts.dm @@ -79,8 +79,8 @@ if("f", "g", "h") modifier = 3 else - if(milkers.size in milkers.breast_values) - modifier = clamp(milkers.breast_values[milkers.size] - 5, 0, INFINITY) + if(milkers.size in GLOB.breast_values) + modifier = clamp(GLOB.breast_values[milkers.size] - 5, 0, INFINITY) else modifier = 1 user.reagents.add_reagent(milktype, rand(1,3 * modifier)) diff --git a/modular_splurt/code/_globalvars/lists/global_lewd.dm b/modular_splurt/code/_globalvars/lists/global_lewd.dm index 77b051c103..7883a8ecb4 100644 --- a/modular_splurt/code/_globalvars/lists/global_lewd.dm +++ b/modular_splurt/code/_globalvars/lists/global_lewd.dm @@ -15,3 +15,5 @@ GLOBAL_LIST_INIT(breast_nouns, list("breasts", "boobs", "honkers", "tatas", "tid GLOBAL_LIST_INIT(balls_nouns, list("balls", "nuts", "ballsack", "testicles", "sack", "cum orbs", "cum spheres", "cum tanks", "cum holders", "cum churners", "spunk orbs", "spunk spheres", "spunk tanks", "spunk holders", "spunk churners", "nut orbs", "nut spheres", "nut tanks", "nut holders", "nut churners", "jizz orbs", "jizz spheres", "jizz tanks", "jizz holders", "jizz churners", "seed orbs", "seed spheres", "seed tanks", "seed holders", "seed churners")) GLOBAL_LIST_INIT(butt_nouns, list("ass", "butt", "dumptruck", "tush", "badonk", "booty", "rump", "behind")) + +GLOBAL_LIST_INIT(breast_values, list("a" = 1, "b" = 2, "c" = 3, "d" = 4, "e" = 5, "f" = 6, "g" = 7, "h" = 8, "i" = 9, "j" = 10, "k" = 11, "l" = 12, "m" = 13, "n" = 14, "o" = 15, "huge" = 16, "massive" = 17, "giga" = 25, "impossible" = 30, "flat" = 0)) diff --git a/modular_splurt/code/datums/genitals/genitals_interface.dm b/modular_splurt/code/datums/genitals/genitals_interface.dm new file mode 100644 index 0000000000..86cced33e9 --- /dev/null +++ b/modular_splurt/code/datums/genitals/genitals_interface.dm @@ -0,0 +1,213 @@ +/// Attempts to open the tgui menu +/mob/living/verb/genital_menu() + set name = "Genitals Menu" + set desc = "Manage your genital, or someone else's." + set category = "IC" + set src in view(usr.client) + + if(!iscarbon(usr)) + return + if(!usr.mind) //Mindless boys, honestly just don't, it's better this way + return + if(!usr.mind.genitals_menu_holder) + usr.mind.genitals_menu_holder= new(usr.mind) + + usr.mind.genitals_menu_holder.target = src + usr.mind.genitals_menu_holder.ui_interact(usr) + +/datum/mind + var/datum/genitals_menu/genitals_menu_holder + +/datum/mind/New(key) + . = ..() + genitals_menu_holder = new(src) + +/datum/genitals_menu + var/mob/living/carbon/target + +/datum/genitals_menu/ui_state(mob/user) + return GLOB.conscious_state + +/datum/genitals_menu/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "GenitalConfig", "Genitals") + ui.open() + +/datum/genitals_menu/ui_data(mob/user) + . = ..() + var/mob/living/carbon/genital_holder = target || user + var/user_is_target = genital_holder == user + .["istargetself"] = user_is_target + if(!user_is_target) + .["target_name"] = genital_holder.name + var/list/genitals = list() + for(var/obj/item/organ/genital/genital in genital_holder.internal_organs) //Only get the genitals + if(CHECK_BITFIELD(genital.genital_flags, GENITAL_INTERNAL)) //Not those though + continue + + var/list/genital_entry = list() + genital_entry["img"] = icon2base64(getFlatIcon(genital, no_anim=TRUE)) + genital_entry["name"] = "[capitalize(genital.name)]" //Prevents code from adding a prefix + genital_entry["key"] = REF(genital) //The key is the reference to the object + + genital_entry["description"] = genital.desc + "\n [genital.linked_organ ? "Linked organ: [genital.linked_organ.name]" : ""]" + + if(user_is_target) + var/visibility = "Invalid" + if(CHECK_BITFIELD(genital.genital_flags, GENITAL_THROUGH_CLOTHES)) + visibility = "Always visible" + else if(CHECK_BITFIELD(genital.genital_flags, GENITAL_UNDIES_HIDDEN)) + visibility = "Hidden by underwear" + else if(CHECK_BITFIELD(genital.genital_flags, GENITAL_HIDDEN)) + visibility = "Always hidden" + else + visibility = "Hidden by clothes" + + var/extras = "None" + if(CHECK_BITFIELD(genital.genital_flags, GENITAL_CAN_STUFF)) + extras = "Allows egg stuffing" + + genital_entry["extras"] = extras + genital_entry["visibility"] = visibility + genital_entry["possible_choices"] = GLOB.genitals_visibility_toggles + genital_entry["extra_choices"] = list(GEN_ALLOW_EGG_STUFFING) + genital_entry["can_arouse"] = ( + !!CHECK_BITFIELD(genital.genital_flags, GENITAL_CAN_AROUSE) \ + && !(HAS_TRAIT(genital_holder, TRAIT_PERMABONER) \ + || HAS_TRAIT(genital_holder, TRAIT_NEVERBONER))) + genital_entry["arousal_state"] = genital.aroused_state + if(istype(genital, /obj/item/organ/genital/penis)) + var/obj/item/organ/genital/penis/peepee = genital + genital_entry["max_size"] = peepee.max_length ? peepee.max_length : 0 + genital_entry["min_size"] = peepee.min_length ? peepee.min_length : 0 + else + genital_entry["max_size"] = genital.max_size ? genital.max_size : 0 + genital_entry["min_size"] = genital.min_size ? genital.min_size : 0 + + //fluids + if(CHECK_BITFIELD(genital.genital_flags, GENITAL_FUID_PRODUCTION) || CHECK_BITFIELD(genital?.linked_organ?.genital_flags, GENITAL_FUID_PRODUCTION)) + var/fluids = genital.get_fluid_fraction() + genital_entry["fluid"] = fluids + + //equipments + if(genital.is_exposed()) + var/list/equipments = list() + for(var/obj/equipment in genital.contents) + var/list/equipment_entry = list() + equipment_entry["name"] = equipment.name + equipment_entry["key"] = REF(equipment) + equipments += list(equipment_entry) + genital_entry["possible_equipment_choices"] = GLOB.genitals_interactions + genital_entry["equipments"] = equipments + + genitals += list(genital_entry) + + if(!genital_holder.getorganslot(ORGAN_SLOT_ANUS) && user_is_target) + var/simulated_ass = list() + simulated_ass["name"] = "Anus" + simulated_ass["key"] = "anus" + var/visibility = "Invalid" + switch(genital_holder.anus_exposed) + if(1) + visibility = "Always visible" + if(0) + visibility = "Hidden by underwear" + else + visibility = "Always hidden" + simulated_ass["visibility"] = visibility + simulated_ass["possible_choices"] = GLOB.genitals_visibility_toggles - GEN_VISIBLE_NO_CLOTHES + genitals += list(simulated_ass) + .["genitals"] = genitals + +/datum/genitals_menu/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) + if(..()) + return + switch(action) + if("genital") + var/mob/living/carbon/self = usr + if(self != target) + return FALSE + if("visibility" in params) + if(params["genital"] == "anus") + self.anus_toggle_visibility(params["visibility"]) + return TRUE + var/obj/item/organ/genital/genital = locate(params["genital"], self.internal_organs) + if(genital && (genital in self.internal_organs)) + genital.toggle_visibility(params["visibility"]) + return TRUE + if("set_arousal" in params) + var/obj/item/organ/genital/genital = locate(params["genital"], self.internal_organs) + if(!genital || (genital \ + && (!CHECK_BITFIELD(genital.genital_flags, GENITAL_CAN_AROUSE) \ + || HAS_TRAIT(self, TRAIT_PERMABONER) \ + || HAS_TRAIT(self, TRAIT_NEVERBONER)))) + return FALSE + var/original_state = genital.aroused_state + genital.set_aroused_state(params["set_arousal"])// i'm not making it just `!aroused_state` because + if(original_state != genital.aroused_state) // someone just might port skyrat's new genitals + to_chat(self, "[genital.aroused_state ? genital.arousal_verb : genital.unarousal_verb].") + . = TRUE + else + to_chat(self, "You can't make that genital [genital.aroused_state ? "unaroused" : "aroused"]!") + . = FALSE + genital.update_appearance() + if(ishuman(self)) + var/mob/living/carbon/human/human = self + human.update_genitals() + return + if("max_size" in params) + var/obj/item/organ/genital/genital = locate(params["genital"], self.internal_organs) + if(!genital) + return FALSE + if(istype(genital, /obj/item/organ/genital/penis)) + var/obj/item/organ/genital/penis/peepee = genital + if(params["max_size"]) + var/new_max_size = clamp(params["max_size"], peepee.length, INFINITY) + peepee.max_length = new_max_size + else + peepee.max_length = 0 + else + if(params["max_size"]) + var/new_max_size = clamp(params["max_size"], genital.size, INFINITY) + genital.max_size = new_max_size + else + genital.max_size = 0 + if("min_size" in params) + var/obj/item/organ/genital/genital = locate(params["genital"], self.internal_organs) + if(!genital) + return FALSE + if(istype(genital, /obj/item/organ/genital/penis)) + var/obj/item/organ/genital/penis/peepee = genital + var/new_min_size = clamp(params["min_size"], 0, peepee.length) + peepee.min_length = new_min_size + else + var/new_min_size = clamp(params["min_size"], 0, genital.size) + genital.min_size = new_min_size + else + return FALSE + if("equipment") + var/mob/living/carbon/actual_target = target || usr + var/mob/living/carbon/self = usr + if(get_dist(actual_target, self) > 1) + to_chat(self, span_warning("You're too far away!")) + return FALSE + var/obj/item/organ/genital/genital = locate(params["genital"], actual_target.internal_organs) + if(!(genital && (genital in actual_target.internal_organs))) + return FALSE + switch(params["equipment_action"]) + if("remove") + var/obj/item/selected_item = locate(params["equipment"], genital.contents) + if(selected_item) + if(!do_mob(self, actual_target, 5 SECONDS)) + return FALSE + if(!self.put_in_hands(selected_item)) + self.transferItemToLoc(get_turf(self)) + return TRUE + return FALSE + if("insert") + var/obj/item/stuff = self.get_active_held_item() + if(!istype(stuff)) + to_chat(self, span_warning("You need to hold an item to insert it!")) + return FALSE + stuff.insert_item_organ(self, self, genital) diff --git a/modular_splurt/code/game/machinery/research_table.dm b/modular_splurt/code/game/machinery/research_table.dm index c984bec303..899910fac5 100644 --- a/modular_splurt/code/game/machinery/research_table.dm +++ b/modular_splurt/code/game/machinery/research_table.dm @@ -139,7 +139,7 @@ for(var/obj/item/organ/genital/genital in buckled_mob.internal_organs) if(istype(genital, /obj/item/organ/genital/breasts)) var/obj/item/organ/genital/breasts/breasts = genital - points_awarded += breasts.fluid_rate + breasts.breast_values[breasts.size] // Breasts use letters instead of numbers! + points_awarded += breasts.fluid_rate + GLOB.breast_values[breasts.size] continue points_awarded += genital.fluid_rate + genital.size points_awarded *= tier diff --git a/modular_splurt/code/game/objects/items.dm b/modular_splurt/code/game/objects/items.dm index c320da9586..a39406bb68 100644 --- a/modular_splurt/code/game/objects/items.dm +++ b/modular_splurt/code/game/objects/items.dm @@ -55,10 +55,17 @@ return if(locate(src.type) in target_organ.contents) - to_chat(user, span_notice("\The [target]'s [target_organ] already has a rod inside!")) + if(user == target) + to_chat(user, span_notice("You already have a rod inside your [target_organ]!")) + else + to_chat(user, span_notice("\The [target]'s [target_organ] already has a rod inside!")) return - target.visible_message(span_warning("\The [user] is trying to insert a rod inside \the [target]!"),\ + if(user == target) + target.visible_message(span_warning("\The [user] is trying to insert a rod inside themselves!"),\ + span_warning("You try to insert a rod inside yourself!")) + else + target.visible_message(span_warning("\The [user] is trying to insert a rod inside \the [target]!"),\ span_warning("\The [user] is trying to insert a rod inside you!")) if(!do_mob(user, target, 4 SECONDS)) @@ -81,15 +88,18 @@ return if(locate(src.type) in target_organ.contents) - to_chat(user, span_notice("\The [target]'s [target_organ] already has a vibrator inside!")) + if(user == target) + to_chat(user, span_notice("You already have a vibrator inside your [target_organ]!")) + else + to_chat(user, span_notice("\The [target]'s [target_organ] already has a vibrator inside!")) return - if(style == "long") - target.visible_message(span_warning("\The [user] is trying to insert a vibrator inside \the [target]!"),\ - span_warning("\The [user] is trying to insert a vibrator inside you!")) + if(user == target) + target.visible_message(span_warning("\The [user] is trying to [style == "long" ? "insert" : "attach"] a vibrator [style == "long" ? "inside" : "to"] themselves!"),\ + span_warning("You try to [style == "long" ? "insert" : "attach"] a vibrator [style == "long" ? "inside" : "to"] yourself!")) else - target.visible_message(span_userlove("\The [user] is trying to attach a vibrator to \the [target]!"),\ - span_warning("\The [user] is trying to attach a vibrator to you!")) + target.visible_message(span_warning("\The [user] is trying to [style == "long" ? "insert" : "attach"] a vibrator [style == "long" ? "inside" : "to"] \the [target]!"),\ + span_warning("\The [user] is trying to [style == "long" ? "insert" : "attach"] a vibrator [style == "long" ? "inside" : "to"] you!")) if(!do_mob(user, target, 5 SECONDS)) return @@ -115,7 +125,11 @@ to_chat(user, span_warning("This genital can't be stuffed!")) return - target.visible_message(span_warning("\The [user] is trying to insert an egg inside \the [target]!"),\ + if(user == target) + target.visible_message(span_warning("\The [user] is trying to insert an egg inside themselves!"),\ + span_warning("You try to insert an egg inside yourself!")) + else + target.visible_message(span_warning("\The [user] is trying to insert an egg inside \the [target]!"),\ span_warning("\The [user] is trying to insert an egg inside you!")) if(!do_mob(user, target, 5 SECONDS)) diff --git a/modular_splurt/code/modules/antagonists/qareen/qareen_abilities.dm b/modular_splurt/code/modules/antagonists/qareen/qareen_abilities.dm index 8963ea6379..4af34c922c 100644 --- a/modular_splurt/code/modules/antagonists/qareen/qareen_abilities.dm +++ b/modular_splurt/code/modules/antagonists/qareen/qareen_abilities.dm @@ -41,7 +41,7 @@ if(do_after(src, rand(10, 20), 0, target)) //did they get deleted in that second? // var/main_fluid = lowertext(fluid_source.get_master_reagent_name()) // doesn't work no more (should delete probably) var/main_fluid = G.get_fluid_name() - var/fluid_ammount = clamp((G.fluid_rate * ((world.time - G.last_orgasmed) / (10 SECONDS)) * G.fluid_mult),0,G.fluid_max_volume) + var/fluid_ammount = G.get_fluid() if (fluid_ammount <= 2) to_chat(src, span_revennotice("[target.p_their(TRUE)] [G.name] spasms pitifully, almost nothing will come out.")) else diff --git a/modular_splurt/code/modules/arousal/genitals.dm b/modular_splurt/code/modules/arousal/genitals.dm index b52a1aab76..6c935614fd 100644 --- a/modular_splurt/code/modules/arousal/genitals.dm +++ b/modular_splurt/code/modules/arousal/genitals.dm @@ -1,4 +1,6 @@ /obj/item/organ/genital + var/max_size = 6 + var/min_size = 1 var/datum/reagents/climax_fluids var/datum/reagent/original_fluid_id var/datum/reagent/default_fluid_id @@ -10,6 +12,15 @@ fluid_max_volume += (modifier*2.5)*(get_size(owner)-1) fluid_rate += (modifier/10)*(get_size(owner)-1) +/obj/item/organ/genital/proc/size_to_state() + return size + +/obj/item/organ/genital/proc/get_fluid() + return clamp(fluid_rate * ((world.time - last_orgasmed) / (10 SECONDS)) * fluid_mult, 0, fluid_max_volume) + +/obj/item/organ/genital/proc/get_fluid_fraction() + return get_fluid() / fluid_max_volume + /obj/item/organ/genital/proc/climax_modify_size(mob/living/partner, obj/item/organ/genital/source_gen) return diff --git a/modular_splurt/code/modules/arousal/organs/belly.dm b/modular_splurt/code/modules/arousal/organs/belly.dm index 44ae1ffafa..8f17da4a32 100644 --- a/modular_splurt/code/modules/arousal/organs/belly.dm +++ b/modular_splurt/code/modules/arousal/organs/belly.dm @@ -25,8 +25,8 @@ if(!owner) return -/obj/item/organ/genital/belly/modify_size(modifier, min = -INFINITY, max = BELLY_SIZE_MAX) - var/new_value = clamp(size_cached + modifier, min, max) +/obj/item/organ/genital/belly/modify_size(modifier, min = -INFINITY, max = INFINITY) + var/new_value = clamp(size_cached + modifier, max(min, min_size ? min_size : -INFINITY), min(max_size ? max_size : INFINITY, max)) if(new_value == size_cached) return prev_size = size_cached @@ -95,6 +95,8 @@ else color = "#[D.features["belly_color"]]" size = D.features["belly_size"] + max_size = D.features["belly_max_size"] + min_size = D.features["belly_min_size"] prev_size = size size_cached = size original_fluid_id = fluid_id diff --git a/modular_splurt/code/modules/arousal/organs/breasts.dm b/modular_splurt/code/modules/arousal/organs/breasts.dm index c815295e28..a4f3688d00 100644 --- a/modular_splurt/code/modules/arousal/organs/breasts.dm +++ b/modular_splurt/code/modules/arousal/organs/breasts.dm @@ -13,8 +13,8 @@ fluid_id = initial(fluid_id) original_fluid_id = fluid_id . = ..() - fluid_max_volume += ((cached_size - breast_values[initial(size)])*2.5)*(owner ? get_size(owner) : 1) - fluid_rate += ((cached_size - breast_values[initial(size)])/10)*(owner ? get_size(owner) : 1) + fluid_max_volume += ((size - initial(size))*2.5)*(owner ? get_size(owner) : 1) + fluid_rate += ((size - initial(size))/10)*(owner ? get_size(owner) : 1) /obj/item/organ/genital/breasts/climax_modify_size(mob/living/partner, obj/item/organ/genital/source_gen) if(!(owner.client?.prefs.cit_toggles & BREAST_ENLARGEMENT)) diff --git a/modular_splurt/code/modules/arousal/organs/testicles.dm b/modular_splurt/code/modules/arousal/organs/testicles.dm index 16a5f2b152..a8180ee4f4 100644 --- a/modular_splurt/code/modules/arousal/organs/testicles.dm +++ b/modular_splurt/code/modules/arousal/organs/testicles.dm @@ -1,6 +1,18 @@ /obj/item/organ/genital/testicles default_fluid_id = /datum/reagent/consumable/semen +/obj/item/organ/genital/testicles/get_fluid() + if(linked_organ) + return clamp(linked_organ.fluid_rate * ((world.time - linked_organ.last_orgasmed) / (10 SECONDS)) * linked_organ.fluid_mult, 0, linked_organ.fluid_max_volume) + else + return 0 + +/obj/item/organ/genital/testicles/get_fluid_fraction() + if(linked_organ) + return get_fluid() / linked_organ.fluid_max_volume + else + return 0 + /obj/item/organ/genital/testicles/get_features(mob/living/carbon/human/H) var/datum/dna/D = H.dna if(D.features["balls_fluid"]) diff --git a/modular_splurt/code/modules/arousal/organs/womb.dm b/modular_splurt/code/modules/arousal/organs/womb.dm index 7918365ea9..3a8bc4adf4 100644 --- a/modular_splurt/code/modules/arousal/organs/womb.dm +++ b/modular_splurt/code/modules/arousal/organs/womb.dm @@ -1,6 +1,18 @@ /obj/item/organ/genital/womb default_fluid_id = /datum/reagent/consumable/semen/femcum +/obj/item/organ/genital/womb/get_fluid() + if(linked_organ) + return clamp(linked_organ.fluid_rate * ((world.time - linked_organ.last_orgasmed) / (10 SECONDS)) * linked_organ.fluid_mult, 0, linked_organ.fluid_max_volume) + else + return 0 + +/obj/item/organ/genital/womb/get_fluid_fraction() + if(linked_organ) + return get_fluid() / linked_organ.fluid_max_volume + else + return 0 + /obj/item/organ/genital/womb/get_features(mob/living/carbon/human/H) var/datum/dna/D = H.dna if(D.features["womb_fluid"]) diff --git a/tgstation.dme b/tgstation.dme index fbe624f3a9..ca37a4862b 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -4350,6 +4350,7 @@ #include "modular_splurt\code\datums\elements\smalltalk.dm" #include "modular_splurt\code\datums\elements\spooky.dm" #include "modular_splurt\code\datums\elements\wuv.dm" +#include "modular_splurt\code\datums\genitals\genitals_interface.dm" #include "modular_splurt\code\datums\interactions\cuddling.dm" #include "modular_splurt\code\datums\interactions\rope.dm" #include "modular_splurt\code\datums\interactions\lewd\_lewd.dm" diff --git a/tgui/packages/tgui/index.js b/tgui/packages/tgui/index.js index 31251cc35b..bd6f3f5302 100644 --- a/tgui/packages/tgui/index.js +++ b/tgui/packages/tgui/index.js @@ -7,6 +7,7 @@ // Themes import './styles/main.scss'; import './styles/themes/abductor.scss'; +import './styles/themes/hotpink.scss'; import './styles/themes/cardtable.scss'; import './styles/themes/hackerman.scss'; import './styles/themes/malfunction.scss'; diff --git a/tgui/packages/tgui/interfaces/GenitalConfig.tsx b/tgui/packages/tgui/interfaces/GenitalConfig.tsx new file mode 100644 index 0000000000..e1b595bfce --- /dev/null +++ b/tgui/packages/tgui/interfaces/GenitalConfig.tsx @@ -0,0 +1,313 @@ + +import { filter } from 'common/collections'; +import { flow } from 'common/fp'; +import { createSearch } from 'common/string'; +import { useBackend, useLocalState } from '../backend'; +import { BlockQuote, Button, LabeledList, Icon, NumberInput, Input, Section, Table, Tabs, Stack, ProgressBar, Divider } from '../components'; +import { Window } from '../layouts'; + + +type GenitalInfo = { + istargetself: boolean, + target_name: String, + genitals: GenitalData[]; +} + +type GenitalData = { + img: string, + name: string, + key: string, + description: string, + visibility: string, + extras: string, + extra_choices: string[], + possible_choices: string[], + can_arouse: boolean, + arousal_state: boolean, + fluid: number, + possible_equipment_choices: string[], + min_size: number, + max_size: number, + equipments: Equipment[], +} + +type Equipment = { + name: string, + key: string, +} + +export const GenitalConfig = (props, context) => { + const { act, data } = useBackend(context); + const genitals = data.genitals || []; + const [tabIndex, setTabIndex] = useLocalState(context, 'tabIndex', 0); + return ( + + + {data.target_name ? ( +
+ Interacting with {data.target_name} +
+ ) : null} + {genitals.length ? ( + <> +
+ + + + {genitals.map((genital, index) => ( + setTabIndex(index)} + > + {genital.name} + + ))} + + + + {genitals[tabIndex].description} + + +
+
+ + + + +
+ Fluid level: + +
+
+ {data.istargetself + ? : null} +
+
+
+
+
act('equipment', { + genital: genitals[tabIndex].key, + equipment_action: "insert", + })} + /> + )} + > + +
+ + ) : ( +
+ {data.target_name ? "They" : "You"} don't seem to have any genitals... + Or any that you could interact with. +
+ )} +
+
+ ); +}; + +const SelfConfig = (props, context) => { + const [tabIndex] = useLocalState(context, 'tabIndex', 0); + const { act, data } = useBackend(context); + const genital = data.genitals[tabIndex]; + return ( + + + {genital.img ? ( + + + + ) : null} + {typeof genital.max_size === "number" ? ( + + + + ) : null} + + + + + + ); +}; + +const SizeButtons = (props, context) => { + const [tabIndex] = useLocalState(context, 'tabIndex', 0); + const { act, data } = useBackend(context); + const genital = data.genitals[tabIndex]; + return ( +
+ + + + Max growth: + act('genital', { + genital: genital.key, + max_size: value, + } + )} + /> + + + + + Min shrink: + act('genital', { + genital: genital.key, + min_size: value, + } + )} + /> + + + +
+ ); +}; + +const ModeToIcon = { + "Always visible": "eye", + "Hidden by clothes": "tshirt", + "Hidden by underwear": "low-vision", + "Always hidden": "eye-slash", + "Allows egg stuffing": "egg", +}; + +const ToggleSettings = (props, context) => { + const [tabIndex] = useLocalState(context, 'tabIndex', 0); + const { act, data } = useBackend(context); + const genital = data.genitals[tabIndex]; + return ( + + {genital.possible_choices.map(choice => ( + +