From 3bd0ba02754753b4b93fbcc403bd198cca4bb44a Mon Sep 17 00:00:00 2001 From: Ghommie Date: Tue, 23 Jul 2019 06:39:53 +0200 Subject: [PATCH 01/17] Cleaning up Arousal code & co. --- code/__DEFINES/DNA.dm | 5 + code/__DEFINES/citadel_defines.dm | 9 + code/__DEFINES/traits.dm | 11 +- code/__HELPERS/_cit_helpers.dm | 41 +- code/__HELPERS/global_lists.dm | 4 + code/__HELPERS/mobs.dm | 1 - code/datums/traits/neutral.dm | 35 ++ code/modules/admin/create_mob.dm | 3 + code/modules/client/preferences.dm | 4 - code/modules/client/preferences_savefile.dm | 7 +- modular_citadel/code/datums/traits/neutral.dm | 33 -- .../code/modules/arousal/arousal.dm | 559 ++++++------------ .../organs/{genitals.dm => _genitals.dm} | 213 +++---- .../code/modules/arousal/organs/breasts.dm | 60 +- .../code/modules/arousal/organs/eggsack.dm | 16 +- .../organs/genitals_sprite_accessories.dm | 21 +- .../code/modules/arousal/organs/ovipositor.dm | 7 +- .../code/modules/arousal/organs/penis.dm | 56 +- .../code/modules/arousal/organs/testicles.dm | 105 ++-- .../code/modules/arousal/organs/vagina.dm | 47 +- .../code/modules/arousal/organs/womb.dm | 50 +- .../modules/client/preferences_savefile.dm | 1 - .../modules/mob/living/carbon/human/life.dm | 4 +- .../carbon/human/species_types/jellypeople.dm | 50 +- .../icons/obj/genitals/testicles_onmob.dmi | Bin 759 -> 562 bytes tgstation.dme | 3 +- 26 files changed, 525 insertions(+), 820 deletions(-) delete mode 100644 modular_citadel/code/datums/traits/neutral.dm rename modular_citadel/code/modules/arousal/organs/{genitals.dm => _genitals.dm} (60%) diff --git a/code/__DEFINES/DNA.dm b/code/__DEFINES/DNA.dm index 4ed099d9e2..95c2c70801 100644 --- a/code/__DEFINES/DNA.dm +++ b/code/__DEFINES/DNA.dm @@ -122,3 +122,8 @@ #define ORGAN_SLOT_BRAIN_ANTISTUN "brain_antistun" #define ORGAN_SLOT_TAIL "tail" #define ORGAN_SLOT_PENIS "penis" +#define ORGAN_SLOT_WOMB "womb" +#define ORGAN_SLOT_VAGINA "vagina" +#define ORGAN_SLOT_TESTICLES "testicles" +#define ORGAN_SLOT_BREASTS "breasts" + diff --git a/code/__DEFINES/citadel_defines.dm b/code/__DEFINES/citadel_defines.dm index 2abe0db04e..8b75784ab2 100644 --- a/code/__DEFINES/citadel_defines.dm +++ b/code/__DEFINES/citadel_defines.dm @@ -18,6 +18,15 @@ #define CIT_FILTER_STAMINACRIT filter(type="drop_shadow", x=0, y=0, size=-3, border=0, color="#04080F") //organ defines +#define VAGINA_LAYER_INDEX 1 +#define TESTICLES_LAYER_INDEX 2 +#define GENITAL_LAYER_INDEX 3 +#define PENIS_LAYER_INDEX 4 + +#define GENITAL_LAYER_INDEX_LENGTH 4 //keep it updated with each new index added, thanks. + +#define MASTURBATE_LINKED_ORGAN 2 //special value used to pass our mission to the linked organ + #define COCK_SIZE_MIN 1 #define COCK_SIZE_MAX 20 diff --git a/code/__DEFINES/traits.dm b/code/__DEFINES/traits.dm index 7bcb4881f0..1546717c7a 100644 --- a/code/__DEFINES/traits.dm +++ b/code/__DEFINES/traits.dm @@ -136,13 +136,14 @@ #define TRAIT_SKITTISH "skittish" #define TRAIT_POOR_AIM "poor_aim" #define TRAIT_PROSOPAGNOSIA "prosopagnosia" -#define TRAIT_DRUNK_HEALING "drunk_healing" -#define TRAIT_TAGGER "tagger" -#define TRAIT_PHOTOGRAPHER "photographer" -#define TRAIT_MUSICIAN "musician" -#define TRAIT_CROCRIN_IMMUNE "crocin_immune" +#define TRAIT_DRUNK_HEALING "drunk_healing" +#define TRAIT_TAGGER "tagger" +#define TRAIT_PHOTOGRAPHER "photographer" +#define TRAIT_MUSICIAN "musician" +#define TRAIT_CROCRIN_IMMUNE "crocin_immune" #define TRAIT_NYMPHO "nymphomania" #define TRAIT_MASO "masochism" +#define TRAIT_EXHIBITIONIST "exhibitionist" #define TRAIT_PARA "paraplegic" #define TRAIT_EMPATH "empath" #define TRAIT_FRIENDLY "friendly" diff --git a/code/__HELPERS/_cit_helpers.dm b/code/__HELPERS/_cit_helpers.dm index 668b151b6e..d75dd31b46 100644 --- a/code/__HELPERS/_cit_helpers.dm +++ b/code/__HELPERS/_cit_helpers.dm @@ -56,6 +56,7 @@ GLOBAL_LIST_EMPTY(ipc_screens_list) GLOBAL_LIST_EMPTY(ipc_antennas_list) //Genitals and Arousal Lists +GLOBAL_LIST_EMPTY(genitals_list) GLOBAL_LIST_EMPTY(cock_shapes_list)//global_lists.dm for the list initializations //Now also _DATASTRUCTURES globals.dm GLOBAL_LIST_EMPTY(cock_shapes_icons) //Associated list for names->icon_states for cockshapes. GLOBAL_LIST_EMPTY(balls_shapes_list) @@ -124,41 +125,39 @@ GLOBAL_VAR_INIT(miscreants_allowed, FALSE) SSblackbox.record_feedback("tally", "admin_verb", 1, "TLOOC") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! /mob/living/carbon/proc/has_penis() - if(getorganslot("penis"))//slot shared with ovipositor - if(istype(getorganslot("penis"), /obj/item/organ/genital/penis)) - return TRUE + var/obj/item/organ/genital/G = getorganslot(ORGAN_SLOT_PENIS) + if(G && istype(G, /obj/item/organ/genital/penis)) + return TRUE return FALSE /mob/living/carbon/proc/has_balls() - if(getorganslot("balls")) - if(istype(getorganslot("balls"), /obj/item/organ/genital/testicles)) - return TRUE + var/obj/item/organ/genital/G = getorganslot(ORGAN_SLOT_TESTICLES) + if(G && istype(G, /obj/item/organ/genital/testicles)) + return TRUE return FALSE /mob/living/carbon/proc/has_vagina() - if(getorganslot("vagina")) + if(getorganslot(ORGAN_SLOT_VAGINA)) return TRUE return FALSE /mob/living/carbon/proc/has_breasts() - if(getorganslot("breasts")) + if(getorganslot(ORGAN_SLOT_BREASTS)) return TRUE return FALSE /mob/living/carbon/proc/has_ovipositor() - if(getorganslot("penis"))//shared slot - if(istype(getorganslot("penis"), /obj/item/organ/genital/ovipositor)) - return TRUE + var/obj/item/organ/genital/G = getorganslot(ORGAN_SLOT_PENIS) + if(G && istype(G, /obj/item/organ/genital/ovipositor)) + return TRUE return FALSE /mob/living/carbon/human/proc/has_eggsack() - if(getorganslot("balls")) - if(istype(getorganslot("balls"), /obj/item/organ/genital/eggsack)) - return TRUE + var/obj/item/organ/genital/G = getorganslot(ORGAN_SLOT_TESTICLES) + if(G && istype(G, /obj/item/organ/genital/eggsack)) + return TRUE return FALSE -/mob/living/carbon/human/proc/is_bodypart_exposed(bodypart) - /mob/living/carbon/proc/is_groin_exposed(var/list/L) if(!L) L = get_equipped_items() @@ -188,9 +187,9 @@ GLOBAL_VAR_INIT(miscreants_allowed, FALSE) message_admins("[src] gave everyone genitals.") for(var/mob/living/carbon/human/H in GLOB.mob_list) if(H.gender == MALE) - H.give_penis() - H.give_balls() + H.give_genital(/obj/item/organ/genital/penis) + H.give_genital(/obj/item/organ/genital/testicles) else - H.give_vagina() - H.give_womb() - H.give_breasts() + H.give_genital(/obj/item/organ/genital/vagina) + H.give_genital(/obj/item/organ/genital/womb) + H.give_genital(/obj/item/organ/genital/breasts) diff --git a/code/__HELPERS/global_lists.dm b/code/__HELPERS/global_lists.dm index c8a33959ed..b0b0f32345 100644 --- a/code/__HELPERS/global_lists.dm +++ b/code/__HELPERS/global_lists.dm @@ -61,6 +61,10 @@ for(var/K in GLOB.balls_shapes_list) var/datum/sprite_accessory/testicles/value = GLOB.balls_shapes_list[K] GLOB.balls_shapes_icons[K] = value.icon_state + + for(var/gpath in subtypesof(/obj/item/organ/genital)) + var/obj/item/organ/genital/G = gpath + GLOB.genitals_list[initial(G.name)] = gpath //END OF CIT CHANGES //Species diff --git a/code/__HELPERS/mobs.dm b/code/__HELPERS/mobs.dm index 5ec839130a..81801cd6a2 100644 --- a/code/__HELPERS/mobs.dm +++ b/code/__HELPERS/mobs.dm @@ -154,7 +154,6 @@ "xenodorsal" = "Standard", "xenohead" = "Standard", "xenotail" = "Xenomorph Tail", - "exhibitionist" = FALSE, "genitals_use_skintone" = FALSE, "has_cock" = FALSE, "cock_shape" = pick(GLOB.cock_shapes_list), diff --git a/code/datums/traits/neutral.dm b/code/datums/traits/neutral.dm index f70e3a3c68..156ee00d75 100644 --- a/code/datums/traits/neutral.dm +++ b/code/datums/traits/neutral.dm @@ -94,6 +94,41 @@ lose_text = "You don't feel as prudish as before." medical_record_text = "Patient exhibits a special gene that makes them immune to Crocin and Hexacrocin." +/datum/quirk/libido + name = "Nymphomania" + desc = "You're always feeling a bit in heat. Also, you get aroused faster than usual." + value = 0 + mob_trait = TRAIT_NYMPHO + gain_text = "You are feeling extra wild." + lose_text = "You don't feel that burning sensation anymore." + +/datum/quirk/libido/add() + var/mob/living/M = quirk_holder + M.min_arousal = 16 + M.arousal_rate = 3 + +/datum/quirk/libido/remove() + var/mob/living/M = quirk_holder + M.min_arousal = initial(M.min_arousal) + M.arousal_rate = initial(M.arousal_rate) + +/datum/quirk/maso + name = "Masochism" + desc = "You are aroused by pain." + value = 0 + mob_trait = TRAIT_MASO + gain_text = "You desire to be hurt." + lose_text = "Pain has become less exciting for you." + +/datum/quirk/exhibitionism + name = "Exhibitionism" + desc = "You don't mind showing off your bare body to strangers, in fact you find it quite satistying. Not the best excuse to break Space Law anyway." //as if they'd care anyway. + value = 0 + medical_record_text = "Patient has been diagnosed with exhibitionistic disorder." + mob_trait = TRAIT_EXHIBITIONIST + gain_text = "You feel like exposing yourself to the world." + lose_text = "Indecent exposure doesn't sound as charming to you anymore." + /datum/quirk/assblastusa name = "Buns of Steel" desc = "You've never skipped ass day. With this trait, you are completely immune to all forms of ass slapping and anyone who tries to slap your rock hard ass usually gets a broken hand." diff --git a/code/modules/admin/create_mob.dm b/code/modules/admin/create_mob.dm index fad7410a6a..eb856237bf 100644 --- a/code/modules/admin/create_mob.dm +++ b/code/modules/admin/create_mob.dm @@ -25,6 +25,9 @@ H.facial_hair_color = H.hair_color H.eye_color = random_eye_color() H.dna.blood_type = random_blood_type() + H.saved_underwear = H.underwear + H.saved_undershirt = H.undershirt + H.saved_socks = H.socks // Mutant randomizing, doesn't affect the mob appearance unless it's the specific mutant. H.dna.features["mcolor"] = random_short_color() diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm index 54d75e8437..bac9ed0c89 100644 --- a/code/modules/client/preferences.dm +++ b/code/modules/client/preferences.dm @@ -108,7 +108,6 @@ GLOBAL_LIST_EMPTY(preferences_datums) "xenohead" = "Standard", "xenotail" = "Xenomorph Tail", "taur" = "None", - "exhibitionist" = FALSE, "genitals_use_skintone" = FALSE, "has_cock" = FALSE, "cock_shape" = "Human", @@ -790,7 +789,6 @@ GLOBAL_LIST_EMPTY(preferences_datums) dat +="" dat += "

Citadel Preferences

" //Because fuck me if preferences can't be fucking modularized and expected to update in a reasonable timeframe. dat += "Arousal:[arousable == TRUE ? "Enabled" : "Disabled"]
" - dat += "Exhibitionist:[features["exhibitionist"] == TRUE ? "Yes" : "No"]
" dat += "Voracious MediHound sleepers: [(cit_toggles & MEDIHOUND_SLEEPER) ? "Yes" : "No"]
" dat += "Hear Vore Sounds: [(cit_toggles & EATING_NOISES) ? "Yes" : "No"]
" dat += "Hear Vore Digestion Sounds: [(cit_toggles & DIGESTION_NOISES) ? "Yes" : "No"]
" @@ -2048,8 +2046,6 @@ GLOBAL_LIST_EMPTY(preferences_datums) features["has_womb"] = FALSE if("has_womb") features["has_womb"] = !features["has_womb"] - if("exhibitionist") - features["exhibitionist"] = !features["exhibitionist"] if("widescreenpref") widescreenpref = !widescreenpref user.client.change_view(CONFIG_GET(string/default_view)) diff --git a/code/modules/client/preferences_savefile.dm b/code/modules/client/preferences_savefile.dm index b9c5cb7ef9..175cd9613a 100644 --- a/code/modules/client/preferences_savefile.dm +++ b/code/modules/client/preferences_savefile.dm @@ -5,7 +5,7 @@ // You do not need to raise this if you are adding new values that have sane defaults. // Only raise this value when changing the meaning/format/name/layout of an existing value // where you would want the updater procs below to run -#define SAVEFILE_VERSION_MAX 20 +#define SAVEFILE_VERSION_MAX 21 /* SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Carn @@ -49,6 +49,11 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car pda_style = "mono" if(current_version < 20) pda_color = "#808000" + if(current_version < 21 && S["feature_exhibitionist"]) + var/datum/quirk/exhibitionism/E + var/quirk_name = initial(E.name) + neutral_quirks += quirk_name + all_quirks += quirk_name /datum/preferences/proc/load_path(ckey,filename="preferences.sav") if(!ckey) diff --git a/modular_citadel/code/datums/traits/neutral.dm b/modular_citadel/code/datums/traits/neutral.dm deleted file mode 100644 index 05aeb27361..0000000000 --- a/modular_citadel/code/datums/traits/neutral.dm +++ /dev/null @@ -1,33 +0,0 @@ -// Citadel-specific Neutral Traits - -/datum/quirk/libido - name = "Nymphomania" - desc = "You're always feeling a bit in heat. Also, you get aroused faster than usual." - value = 0 - mob_trait = TRAIT_NYMPHO - gain_text = "You are feeling extra wild." - lose_text = "You don't feel that burning sensation anymore." - -/datum/quirk/libido/add() - var/mob/living/M = quirk_holder - M.min_arousal = 16 - M.arousal_rate = 3 - -/datum/quirk/libido/remove() - var/mob/living/M = quirk_holder - M.min_arousal = initial(M.min_arousal) - M.arousal_rate = initial(M.arousal_rate) - -/datum/quirk/libido/on_process() - var/mob/living/M = quirk_holder - if(M.canbearoused == FALSE) - to_chat(quirk_holder, "Having high libido is useless when you can't feel arousal at all!") - qdel(src) - -/datum/quirk/maso - name = "Masochism" - desc = "You are aroused by pain." - value = 0 - mob_trait = TRAIT_MASO - gain_text = "You desire to be hurt." - lose_text = "Pain has become less exciting for you." diff --git a/modular_citadel/code/modules/arousal/arousal.dm b/modular_citadel/code/modules/arousal/arousal.dm index 27f7576e7f..8826cb0774 100644 --- a/modular_citadel/code/modules/arousal/arousal.dm +++ b/modular_citadel/code/modules/arousal/arousal.dm @@ -19,11 +19,6 @@ var/hidden_undershirt = FALSE var/hidden_socks = FALSE -/mob/living/carbon/human/New() - ..() - saved_underwear = underwear - saved_undershirt = undershirt - //Species vars /datum/species var/arousal_gain_rate = AROUSAL_START_VALUE //Rate at which this species becomes aroused @@ -35,60 +30,53 @@ //Mob procs /mob/living/carbon/human/proc/underwear_toggle() set name = "Toggle undergarments" - set category = "Object" - if(ishuman(src)) - var/mob/living/carbon/human/humz = src - var/confirm = input(src, "Select what part of your form to alter", "Undergarment Toggling", "Cancel") in list("Top", "Bottom", "Socks", "All", "Cancel") - if(confirm == "Top") - humz.hidden_undershirt = !humz.hidden_undershirt + set category = "IC" - if(confirm == "Bottom") - humz.hidden_underwear = !humz.hidden_underwear + var/confirm = input(src, "Select what part of your form to alter", "Undergarment Toggling") as null|anything in list("Top", "Bottom", "Socks", "All") + if(!confirm) + return + if(confirm == "Top") + hidden_undershirt = !hidden_undershirt - if(confirm == "Socks") - humz.hidden_socks = !humz.hidden_socks + if(confirm == "Bottom") + hidden_underwear = !hidden_underwear - if(confirm == "All") - humz.hidden_undershirt = !humz.hidden_undershirt - humz.hidden_underwear = !humz.hidden_underwear - humz.hidden_socks = !humz.hidden_socks + if(confirm == "Socks") + hidden_socks = !hidden_socks - if(confirm == "Cancel") - return - src.update_body() + if(confirm == "All") + var/on_off = (hidden_undershirt || hidden_underwear || hidden_socks) ? FALSE : TRUE + hidden_undershirt = on_off + hidden_underwear = on_off + hidden_socks = on_off - else - to_chat(src, "Humans only. How the fuck did you get this verb anyway.") + update_body() -/mob/living/proc/handle_arousal() - - -/mob/living/carbon/handle_arousal() - if(canbearoused && dna) - var/datum/species/S - S = dna.species - if(S && !(SSmobs.times_fired % 36) && getArousalLoss() < max_arousal)//Totally stolen from breathing code. Do this every 36 ticks. - adjustArousalLoss(arousal_rate * S.arousal_gain_rate) - if(dna.features["exhibitionist"] && client) - var/amt_nude = 0 - if(is_chest_exposed() && (getorganslot("breasts"))) - amt_nude++ - if(is_groin_exposed()) - if(getorganslot("penis")) - amt_nude++ - if(getorganslot("vagina")) - amt_nude++ - if(amt_nude) - var/watchers = 0 - for(var/mob/_M in view(world.view, src)) - var/mob/living/M = _M - if(!istype(M)) - continue - if(M.client && !M.stat && !M.eye_blind && (locate(src) in viewers(world.view,M))) - watchers++ - if(watchers) - adjustArousalLoss((amt_nude * watchers) + S.arousal_gain_rate) +/mob/living/proc/handle_arousal(times_fired) + return +/mob/living/carbon/handle_arousal(times_fired) + if(!canbearoused || !dna) + return + var/datum/species/S = dna.species + if(!S || (times_fired % 36) || !getArousalLoss() >= max_arousal)//Totally stolen from breathing code. Do this every 36 ticks. + return + var/our_loss = arousal_rate * S.arousal_gain_rate + if(HAS_TRAIT(src, TRAIT_EXHIBITIONIST) && client) + var/amt_nude = 0 + for(var/obj/item/organ/genital/G in internal_organs) + if(G.is_exposed()) + amt_nude++ + if(amt_nude) + var/watchers = 0 + for(var/mob/living/L in view(world.view, src)) + if(!istype(L)) + continue + if(L.client && !L.stat && !L.eye_blind && (locate(src) in viewers(world.view, L))) + watchers++ + if(watchers) + our_loss += (amt_nude * watchers) + S.arousal_gain_rate + adjustArousalLoss(our_loss) /mob/living/proc/getArousalLoss() return arousalloss @@ -138,8 +126,6 @@ S = GLOB.breasts_shapes_list[G.shape] if(S?.alt_aroused) G.aroused_state = isPercentAroused(G.aroused_amount) - if(getArousalLoss() >= ((max_arousal / 100) * 33)) - G.aroused_state = TRUE else G.aroused_state = FALSE G.update_appearance() @@ -147,54 +133,18 @@ /mob/living/proc/update_arousal_hud() return FALSE -/datum/species/proc/update_arousal_hud(mob/living/carbon/human/H) - return FALSE - /mob/living/carbon/human/update_arousal_hud() - if(!client || !hud_used) - return FALSE - if(dna.species.update_arousal_hud()) + if(!client || !(hud_used?.arousal)) return FALSE if(!canbearoused) hud_used.arousal.icon_state = "" return FALSE + if(stat == DEAD) + hud_used.arousal.icon_state = "arousal0" else - if(hud_used.arousal) - if(stat == DEAD) - hud_used.arousal.icon_state = "arousal0" - return TRUE - if(getArousalLoss() == max_arousal) - hud_used.arousal.icon_state = "arousal100" - return TRUE - if(getArousalLoss() >= (max_arousal / 100) * 90)//M O D U L A R , W O W - hud_used.arousal.icon_state = "arousal90" - return TRUE - if(getArousalLoss() >= (max_arousal / 100) * 80)//M O D U L A R , W O W - hud_used.arousal.icon_state = "arousal80" - return TRUE - if(getArousalLoss() >= (max_arousal / 100) * 70)//M O D U L A R , W O W - hud_used.arousal.icon_state = "arousal70" - return TRUE - if(getArousalLoss() >= (max_arousal / 100) * 60)//M O D U L A R , W O W - hud_used.arousal.icon_state = "arousal60" - return TRUE - if(getArousalLoss() >= (max_arousal / 100) * 50)//M O D U L A R , W O W - hud_used.arousal.icon_state = "arousal50" - return TRUE - if(getArousalLoss() >= (max_arousal / 100) * 40)//M O D U L A R , W O W - hud_used.arousal.icon_state = "arousal40" - return TRUE - if(getArousalLoss() >= (max_arousal / 100) * 30)//M O D U L A R , W O W - hud_used.arousal.icon_state = "arousal30" - return TRUE - if(getArousalLoss() >= (max_arousal / 100) * 20)//M O D U L A R , W O W - hud_used.arousal.icon_state = "arousal10" - return TRUE - if(getArousalLoss() >= (max_arousal / 100) * 10)//M O D U L A R , W O W - hud_used.arousal.icon_state = "arousal10" - return TRUE - else - hud_used.arousal.icon_state = "arousal0" + var/value = FLOOR(getPercentAroused(), 10) + hud_used.arousal.icon_state = "arousal[value]" + return TRUE /obj/screen/arousal name = "arousal" @@ -213,7 +163,6 @@ to_chat(M, "Arousal is disabled. Feature is unavailable.") - /mob/living/proc/mob_climax()//This is just so I can test this shit without being forced to add actual content to get rid of arousal. Will be a very basic proc for a while. set name = "Masturbate" set category = "IC" @@ -221,212 +170,150 @@ if(mb_cd_timer <= world.time) //start the cooldown even if it fails mb_cd_timer = world.time + mb_cd_length - if(getArousalLoss() >= ((max_arousal / 100) * 33))//33% arousal or greater required - src.visible_message("[src] starts masturbating!", \ + if(getArousalLoss() >= 33)//one third of average max_arousal or greater required + visible_message("[src] starts masturbating!", \ "You start masturbating.") if(do_after(src, 30, target = src)) - src.visible_message("[src] relieves [p_them()]self!", \ + visible_message("[src] relieves [p_them()]self!", \ "You have relieved yourself.") SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "orgasm", /datum/mood_event/orgasm) setArousalLoss(min_arousal) else to_chat(src, "You aren't aroused enough for that.") +/obj/item/organ/genital/proc/climaxable(mob/living/carbon/human/H, silent = FALSE) //returns the fluid source (ergo reagents holder) if found. + if(producing) + . = reagents + else + if(linked_organ) + . = linked_organ.reagents + else if(!silent) + to_chat(H, "Your [name] is unable to produce it's own fluids, it's missing the organs for it.") + +/mob/living/carbon/human/proc/do_climax(datum/reagents/R, atom/target, obj/item/organ/genital/G, spill = TRUE) + if(!G) + return + SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "orgasm", /datum/mood_event/orgasm) + if(!target || !R) + return + var/turfing = isturf(target) + if(spill & R.total_volume >= 5) + R.reaction(turfing ? target : target.loc, TOUCH, 1, 0) + if(!turfing) + R.trans_to(target, R.total_volume * (spill ? G.fluid_transfer_factor : 1)) + R.clear_reagents() //These are various procs that we'll use later, split up for readability instead of having one, huge proc. //For all of these, we assume the arguments given are proper and have been checked beforehand. /mob/living/carbon/human/proc/mob_masturbate(obj/item/organ/genital/G, mb_time = 30) //Masturbation, keep it gender-neutral - var/total_fluids = 0 - var/datum/reagents/fluid_source = null - - if(G.producing) //Can it produce its own fluids, such as breasts? - fluid_source = G.reagents - else - if(!G.linked_organ) - to_chat(src, "Your [G.name] is unable to produce it's own fluids, it's missing the organs for it.") - return - fluid_source = G.linked_organ.reagents - total_fluids = fluid_source.total_volume + var/datum/reagents/fluid_source = G.climaxable(src) + if(!fluid_source) + return + var/obj/item/organ/genital/PP = G.can_masturbate_with == MASTURBATE_LINKED_ORGAN ? G.linked_organ : G + if(!PP) + to_chat(src, "You shudder, unable to cum with your [name].") if(mb_time) - src.visible_message("[src] starts to [G.masturbation_verb] [p_their()] [G.name].", \ - "You start to [G.masturbation_verb] your [G.name].", \ + visible_message("[src] starts to [G.masturbation_verb] [p_their()] [G.name].", \ "You start to [G.masturbation_verb] your [G.name].") - - if(do_after(src, mb_time, target = src)) - if(total_fluids > 5) - fluid_source.reaction(src.loc, TOUCH, 1, 0) - fluid_source.clear_reagents() - src.visible_message("[src] orgasms, cumming[istype(src.loc, /turf/open/floor) ? " onto [src.loc]" : ""]!", \ - "You cum[istype(src.loc, /turf/open/floor) ? " onto [src.loc]" : ""].", \ - "You have relieved yourself.") - SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "orgasm", /datum/mood_event/orgasm) - if(G.can_climax) - setArousalLoss(min_arousal) - + if(!do_after(src, mb_time, target = src) || !G.climaxable(src, TRUE)) + return + visible_message("[src] orgasms, [PP.orgasm_verb][isturf(loc) ? " onto [loc]" : ""]!", \ + "You orgasm, [PP.orgasm_verb][isturf(loc) ? " onto [loc]" : ""].") + do_climax(fluid_source, loc, G) /mob/living/carbon/human/proc/mob_climax_outside(obj/item/organ/genital/G, mb_time = 30) //This is used for forced orgasms and other hands-free climaxes - var/total_fluids = 0 - var/datum/reagents/fluid_source = null - var/unable_to_come = FALSE - - if(G.producing) //Can it produce its own fluids, such as breasts? - fluid_source = G.reagents - total_fluids = fluid_source.total_volume - else - if(!G.linked_organ) - unable_to_come = TRUE - else - fluid_source = G.linked_organ.reagents - total_fluids = fluid_source.total_volume - - if(unable_to_come) - src.visible_message("[src] shudders, their [G.name] unable to cum.", \ - "Your [G.name] cannot cum, giving no relief.", \ + var/datum/reagents/fluid_source = G.climaxable(src, TRUE) + if(!fluid_source) + visible_message("[src] shudders, their [G.name] unable to cum.", \ "Your [G.name] cannot cum, giving no relief.") - else - total_fluids = fluid_source.total_volume - if(mb_time) //as long as it's not instant, give a warning - src.visible_message("[src] looks like they're about to cum.", \ - "You feel yourself about to orgasm.", \ - "You feel yourself about to orgasm.") - if(do_after(src, mb_time, target = src)) - if(total_fluids > 5) - fluid_source.reaction(src.loc, TOUCH, 1, 0) - fluid_source.clear_reagents() - src.visible_message("[src] orgasms[istype(src.loc, /turf/open/floor) ? ", spilling onto [src.loc]" : ""], using [p_their()] [G.name]!", \ - "You climax[istype(src.loc, /turf/open/floor) ? ", spilling onto [src.loc]" : ""] with your [G.name].", \ - "You climax using your [G.name].") - SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "orgasm", /datum/mood_event/orgasm) - if(G.can_climax) - setArousalLoss(min_arousal) - + return + if(mb_time) //as long as it's not instant, give a warning + visible_message("[src] looks like they're about to cum.", \ + "You feel yourself about to orgasm.") + if(!do_after(src, mb_time, target = src) || !G.climaxable(src, TRUE)) + return + visible_message("[src] orgasms[isturf(loc) ? " onto [loc]" : ""], using [p_their()] [G.name]!", \ + "You climax[isturf(loc) ? " onto [loc]" : ""] with your [G.name].") + do_climax(fluid_source, loc, G) /mob/living/carbon/human/proc/mob_climax_partner(obj/item/organ/genital/G, mob/living/L, spillage = TRUE, mb_time = 30) //Used for climaxing with any living thing - var/total_fluids = 0 - var/datum/reagents/fluid_source = null - - if(G.producing) //Can it produce its own fluids, such as breasts? - fluid_source = G.reagents - else - if(!G.linked_organ) - to_chat(src, "Your [G.name] is unable to produce it's own fluids, it's missing the organs for it.") - return - fluid_source = G.linked_organ.reagents - total_fluids = fluid_source.total_volume + var/datum/reagents/fluid_source = G.climaxable(src) + if(!fluid_source) + return if(mb_time) //Skip warning if this is an instant climax. - src.visible_message("[src] is about to climax with [L]!", \ - "You're about to climax with [L]!", \ - "You're preparing to climax with someone!") + visible_message("[src] is about to climax with [L]!", \ + "You're about to climax with [L]!") + if(!do_after(src, mb_time, target = src) || !in_range(src, L) || !G.climaxable(src, TRUE)) + return if(spillage) - if(do_after(src, mb_time, target = src) && in_range(src, L)) - fluid_source.trans_to(L, total_fluids*G.fluid_transfer_factor) - total_fluids -= total_fluids*G.fluid_transfer_factor - if(total_fluids > 5) - fluid_source.reaction(L.loc, TOUCH, 1, 0) - fluid_source.clear_reagents() - src.visible_message("[src] climaxes with [L][spillage ? ", overflowing and spilling":""], using [p_their()] [G.name]!", \ - "You orgasm with [L][spillage ? ", spilling out of them":""], using your [G.name].", \ - "You have climaxed with someone[spillage ? ", spilling out of them":""], using your [G.name].") - SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "orgasm", /datum/mood_event/orgasm) - SEND_SIGNAL(L, COMSIG_ADD_MOOD_EVENT, "orgasm", /datum/mood_event/orgasm) - if(G.can_climax) - setArousalLoss(min_arousal) + visible_message("[src] climaxes with [L], overflowing and spilling, using [p_their()] [G.name]!", \ + "You orgasm with [L], spilling out of them, using your [G.name].") else //knots and other non-spilling orgasms - if(do_after(src, mb_time, target = src) && in_range(src, L)) - fluid_source.trans_to(L, total_fluids) - total_fluids = 0 - src.visible_message("[src] climaxes with [L], [p_their()] [G.name] spilling nothing!", \ - "You ejaculate with [L], your [G.name] spilling nothing.", \ - "You have climaxed inside someone, your [G.name] spilling nothing.") - SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "orgasm", /datum/mood_event/orgasm) - SEND_SIGNAL(L, COMSIG_ADD_MOOD_EVENT, "orgasm", /datum/mood_event/orgasm) - if(G.can_climax) - setArousalLoss(min_arousal) + visible_message("[src] climaxes with [L], [p_their()] [G.name] spilling nothing!", \ + "You ejaculate with [L], your [G.name] spilling nothing.") + SEND_SIGNAL(L, COMSIG_ADD_MOOD_EVENT, "orgasm", /datum/mood_event/orgasm) + do_climax(fluid_source, spillage ? loc : L, G, spillage) /mob/living/carbon/human/proc/mob_fill_container(obj/item/organ/genital/G, obj/item/reagent_containers/container, mb_time = 30) //For beaker-filling, beware the bartender - var/total_fluids = 0 - var/datum/reagents/fluid_source = null - - if(G.producing) //Can it produce its own fluids, such as breasts? - fluid_source = G.reagents - else - if(!G.linked_organ) - to_chat(src, "Your [G.name] is unable to produce it's own fluids, it's missing the organs for it.") + var/datum/reagents/fluid_source = G.climaxable(src) + if(!fluid_source) + return + if(mb_time) + visible_message("[src] starts to [G.masturbation_verb] their [G.name] over [container].", \ + "You start to [G.masturbation_verb] your [G.name] over [container].") + if(!do_after(src, mb_time, target = src) || !in_range(src, container) || !G.climaxable(src, TRUE)) return - fluid_source = G.linked_organ.reagents - total_fluids = fluid_source.total_volume - - //if(!container) //Something weird happened - // to_chat(src, "You need a container to do this!") - // return - - src.visible_message("[src] starts to [G.masturbation_verb] their [G.name] over [container].", \ - "You start to [G.masturbation_verb] your [G.name] over [container].", \ - "You start to [G.masturbation_verb] your [G.name] over something.") - if(do_after(src, mb_time, target = src) && in_range(src, container)) - fluid_source.trans_to(container, total_fluids) - src.visible_message("[src] uses [p_their()] [G.name] to fill [container]!", \ - "You used your [G.name] to fill [container].", \ - "You have relieved some pressure.") - SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "orgasm", /datum/mood_event/orgasm) - if(G.can_climax) - setArousalLoss(min_arousal) + visible_message("[src] uses [p_their()] [G.name] to fill [container]!", \ + "You used your [G.name] to fill [container].") + do_climax(fluid_source, container, G, FALSE) /mob/living/carbon/human/proc/pick_masturbate_genitals() - var/obj/item/organ/genital/ret_organ var/list/genitals_list = list() var/list/worn_stuff = get_equipped_items() for(var/obj/item/organ/genital/G in internal_organs) - if(G.can_masturbate_with) //filter out what you can't masturbate with - if(G.is_exposed(worn_stuff)) //Nude or through_clothing - genitals_list += G + if(G.can_masturbate_with && G.is_exposed(worn_stuff)) //filter out what you can't masturbate with + if(G.can_masturbate_with == MASTURBATE_LINKED_ORGAN && !G.linked_organ) + continue + genitals_list += G if(genitals_list.len) - ret_organ = input(src, "with what?", "Masturbate", null) as null|obj in genitals_list + var/obj/item/organ/genital/ret_organ = input(src, "with what?", "Masturbate", null) as null|obj in genitals_list return ret_organ - return null //error stuff /mob/living/carbon/human/proc/pick_climax_genitals() - var/obj/item/organ/genital/ret_organ var/list/genitals_list = list() var/list/worn_stuff = get_equipped_items() for(var/obj/item/organ/genital/G in internal_organs) - if(G.can_climax) //filter out what you can't masturbate with - if(G.is_exposed(worn_stuff)) //Nude or through_clothing - genitals_list += G + if(G.can_climax && G.is_exposed(worn_stuff)) //filter out what you can't masturbate with + genitals_list += G if(genitals_list.len) - ret_organ = input(src, "with what?", "Climax", null) as null|obj in genitals_list + var/obj/item/organ/genital/ret_organ = input(src, "with what?", "Climax", null) as null|obj in genitals_list return ret_organ - return null //error stuff /mob/living/carbon/human/proc/pick_partner() var/list/partners = list() - if(src.pulling) - partners += src.pulling //Yes, even objects for now - if(src.pulledby) - partners += src.pulledby + if(pulling) + partners += pulling + if(pulledby) + partners += pulledby //Now we got both of them, let's check if they're proper - for(var/I in partners) - if(isliving(I)) - if(iscarbon(I)) - var/mob/living/carbon/C = I - if(!C.exposed_genitals.len) //Nothing through_clothing - if(!C.is_groin_exposed()) //No pants undone - if(!C.is_chest_exposed()) //No chest exposed - partners -= I //Then not proper, remove them - else - partners -= I //No fucking objects + for(var/mob/living/L in partners) + if(iscarbon(L)) + var/mob/living/carbon/C = L + if(!C.exposed_genitals.len && !C.is_groin_exposed() && !C.is_chest_exposed()) //Nothing through_clothing, no proper partner. + partners -= C //NOW the list should only contain correct partners if(!partners.len) - return null //No one left. - return input(src, "With whom?", "Sexual partner", null) in partners //pick one, default to null + return //No one left. + var/mob/living/target = input(src, "With whom?", "Sexual partner", null) as null|anything in partners //pick one, default to null + if(target && in_range(src, target)) + return target /mob/living/carbon/human/proc/pick_climax_container() - var/obj/item/reagent_containers/SC = null var/list/containers_list = list() for(var/obj/item/reagent_containers/container in held_items) @@ -434,12 +321,21 @@ containers_list += container if(containers_list.len) - SC = input(src, "Into or onto what?(Cancel for nowhere)", null) as null|obj in containers_list - if(SC) - if(in_range(src, SC)) - return SC + var/obj/item/reagent_containers/SC = input(src, "Into or onto what?(Cancel for nowhere)", null) as null|obj in containers_list + if(SC && in_range(src, SC)) + return SC return null //If nothing correct, give null. +/mob/living/carbon/human/proc/available_rosie_palms(silent = FALSE) + if(restrained(TRUE)) //TRUE ignores grabs + if(!silent) + to_chat(src, "You can't do that while restrained!") + return FALSE + if(!get_num_arms() || !get_empty_held_indexes()) + if(!silent) + to_chat(src, "You need at least one free arm.") + return FALSE + return TRUE //Here's the main proc itself /mob/living/carbon/human/mob_climax(forced_climax=FALSE) //Forced is instead of the other proc, makes you cum if you have the tools for it, ignoring restraints @@ -447,49 +343,47 @@ if(!forced_climax) //Don't spam the message to the victim if forced to come too fast to_chat(src, "You need to wait [DisplayTimeText((mb_cd_timer - world.time), TRUE)] before you can do that again!") return - mb_cd_timer = (world.time + mb_cd_length) - + mb_cd_timer = world.time + mb_cd_length if(canbearoused && has_dna()) - if(stat==2) - to_chat(src, "You can't do that while dead!") + if(stat == DEAD) + if(!forced_climax) + to_chat(src, "You can't do that while dead!") return if(forced_climax) //Something forced us to cum, this is not a masturbation thing and does not progress to the other checks - for(var/obj/item/organ/O in internal_organs) - if(istype(O, /obj/item/organ/genital)) - var/obj/item/organ/genital/G = O - if(!G.can_climax) //Skip things like wombs and testicles - continue - var/mob/living/partner - var/check_target - var/list/worn_stuff = get_equipped_items() + for(var/obj/item/organ/genital/G in internal_organs) + if(!G.can_climax) //Skip things like wombs and testicles + continue + var/mob/living/partner + var/check_target + var/list/worn_stuff = get_equipped_items() - if(G.is_exposed(worn_stuff)) - if(src.pulling) //Are we pulling someone? Priority target, we can't be making option menus for this, has to be quick - if(isliving(src.pulling)) //Don't fuck objects - check_target = src.pulling - if(src.pulledby && !check_target) //prioritise pulled over pulledby - if(isliving(src.pulledby)) - check_target = src.pulledby - //Now we should have a partner, or else we have to come alone - if(check_target) - if(iscarbon(check_target)) //carbons can have clothes - var/mob/living/carbon/C = check_target - if(C.exposed_genitals.len || C.is_groin_exposed() || C.is_chest_exposed()) //Are they naked enough? - partner = C - else //A cat is fine too - partner = check_target - if(partner) //Did they pass the clothing checks? - mob_climax_partner(G, partner, mb_time = 0) //Instant climax due to forced - continue //You've climaxed once with this organ, continue on - //not exposed OR if no partner was found while exposed, climax alone - mob_climax_outside(G, mb_time = 0) //removed climax timer for sudden, forced orgasms + if(G.is_exposed(worn_stuff)) + if(pulling) //Are we pulling someone? Priority target, we can't be making option menus for this, has to be quick + if(isliving(pulling)) //Don't fuck objects + check_target = pulling + if(pulledby && !check_target) //prioritise pulled over pulledby + if(isliving(pulledby)) + check_target = pulledby + //Now we should have a partner, or else we have to come alone + if(check_target) + if(iscarbon(check_target)) //carbons can have clothes + var/mob/living/carbon/C = check_target + if(C.exposed_genitals.len || C.is_groin_exposed() || C.is_chest_exposed()) //Are they naked enough? + partner = C + else //A cat is fine too + partner = check_target + if(partner) //Did they pass the clothing checks? + mob_climax_partner(G, partner, mb_time = 0) //Instant climax due to forced + continue //You've climaxed once with this organ, continue on + //not exposed OR if no partner was found while exposed, climax alone + mob_climax_outside(G, mb_time = 0) //removed climax timer for sudden, forced orgasms //Now all genitals that could climax, have. //Since this was a forced climax, we do not need to continue with the other stuff return //If we get here, then this is not a forced climax and we gotta check a few things. - if(stat==1) //No sleep-masturbation, you're unconscious. + if(stat == UNCONSCIOUS) //No sleep-masturbation, you're unconscious. to_chat(src, "You must be conscious to do that!") return if(getArousalLoss() < 33) //flat number instead of percentage @@ -497,91 +391,38 @@ return //Ok, now we check what they want to do. - var/choice = input(src, "Select sexual activity", "Sexual activity:") in list("Masturbate", "Climax alone", "Climax with partner", "Fill container") + var/choice = input(src, "Select sexual activity", "Sexual activity:") as null|anything in list("Masturbate", "Climax alone", "Climax with partner", "Fill container") switch(choice) if("Masturbate") - if(restrained(TRUE)) //TRUE ignores grabs - to_chat(src, "You can't do that while restrained!") - return - var/free_hands = get_num_arms() - if(!free_hands) - to_chat(src, "You need at least one free arm.") - return - for(var/helditem in held_items)//how many hands are free - if(isobj(helditem)) - free_hands-- - if(free_hands <= 0) - to_chat(src, "You're holding too many things.") + if(!available_rosie_palms()) return //We got hands, let's pick an organ - var/obj/item/organ/genital/picked_organ - picked_organ = pick_masturbate_genitals() - if(picked_organ) + var/obj/item/organ/genital/picked_organ = pick_masturbate_genitals() + if(picked_organ && available_rosie_palms(TRUE)) mob_masturbate(picked_organ) return - else //They either lack organs that can masturbate, or they didn't pick one. - to_chat(src, "You cannot masturbate without choosing genitals.") - return if("Climax alone") - if(restrained(TRUE)) //TRUE ignores grabs - to_chat(src, "You can't do that while restrained!") + if(!available_rosie_palms()) return - var/free_hands = get_num_arms() - if(!free_hands) - to_chat(src, "You need at least one free arm.") - return - for(var/helditem in held_items)//how many hands are free - if(isobj(helditem)) - free_hands-- - if(free_hands <= 0) - to_chat(src, "You're holding too many things.") - return - //We got hands, let's pick an organ - var/obj/item/organ/genital/picked_organ - picked_organ = pick_climax_genitals() - if(picked_organ) + var/obj/item/organ/genital/picked_organ = pick_climax_genitals() + if(picked_organ && available_rosie_palms(TRUE)) mob_climax_outside(picked_organ) - return - else //They either lack organs that can masturbate, or they didn't pick one. - to_chat(src, "You cannot climax without choosing genitals.") - return if("Climax with partner") //We need no hands, we can be restrained and so on, so let's pick an organ - var/obj/item/organ/genital/picked_organ - picked_organ = pick_climax_genitals() + var/obj/item/organ/genital/picked_organ = pick_climax_genitals() if(picked_organ) var/mob/living/partner = pick_partner() //Get someone if(partner) - var/spillage = input(src, "Would your fluids spill outside?", "Choose overflowing option", "Yes") as anything in list("Yes", "No") - if(spillage == "Yes") - mob_climax_partner(picked_organ, partner, TRUE) - else - mob_climax_partner(picked_organ, partner, FALSE) - return - else - to_chat(src, "You cannot do this alone.") - return - else //They either lack organs that can masturbate, or they didn't pick one. - to_chat(src, "You cannot climax without choosing genitals.") - return + var/spillage = input(src, "Would your fluids spill outside?", "Choose overflowing option", "Yes") as null|anything in list("Yes", "No") + if(spillage && in_range(src, partner)) + mob_climax_partner(picked_organ, partner, spillage == "Yes" ? TRUE : FALSE) if("Fill container") //We'll need hands and no restraints. - if(restrained(TRUE)) //TRUE ignores grabs - to_chat(src, "You can't do that while restrained!") - return - var/free_hands = get_num_arms() - if(!free_hands) - to_chat(src, "You need at least one free arm.") - return - for(var/helditem in held_items)//how many hands are free - if(isobj(helditem)) - free_hands-- - if(free_hands <= 0) - to_chat(src, "You're holding too many things.") + if(!available_rosie_palms()) return //We got hands, let's pick an organ var/obj/item/organ/genital/picked_organ @@ -589,14 +430,6 @@ if(picked_organ) //Good, got an organ, time to pick a container var/obj/item/reagent_containers/fluid_container = pick_climax_container() - if(fluid_container) + if(fluid_container && available_rosie_palms(TRUE)) mob_fill_container(picked_organ, fluid_container) - return - else - to_chat(src, "You cannot do this without anything to fill.") - return - else //They either lack organs that can climax, or they didn't pick one. - to_chat(src, "You cannot fill anything without choosing genitals.") - return - else //Somehow another option was taken, maybe something interrupted the selection or it was cancelled - return //Just end it in that case. + return \ No newline at end of file diff --git a/modular_citadel/code/modules/arousal/organs/genitals.dm b/modular_citadel/code/modules/arousal/organs/_genitals.dm similarity index 60% rename from modular_citadel/code/modules/arousal/organs/genitals.dm rename to modular_citadel/code/modules/arousal/organs/_genitals.dm index 63d6834409..2222624050 100644 --- a/modular_citadel/code/modules/arousal/organs/genitals.dm +++ b/modular_citadel/code/modules/arousal/organs/_genitals.dm @@ -6,8 +6,9 @@ var/list/genital_flags = list() var/can_masturbate_with = FALSE var/masturbation_verb = "masturbate" + var/orgasm_verb = "cumming" //present continous var/can_climax = FALSE - var/fluid_transfer_factor = 0.0 //How much would a partner get in them if they climax using this? + var/fluid_transfer_factor = 0 //How much would a partner get in them if they climax using this? var/size = 2 //can vary between num or text, just used in icon_state strings var/fluid_id = null var/fluid_max_volume = 50 @@ -18,48 +19,49 @@ var/aroused_state = FALSE //Boolean used in icon_state strings var/aroused_amount = 50 //This is a num from 0 to 100 for arousal percentage for when to use arousal state icons. var/obj/item/organ/genital/linked_organ + var/linked_organ_slot //only one of the two organs needs this to be set up. update_link() will handle linking the rest. var/through_clothes = FALSE var/internal = FALSE var/hidden = FALSE + var/layer_index = GENITAL_LAYER_INDEX //Order should be very important. FIRST vagina, THEN testicles, THEN penis, as this affects the order they are rendered in. /obj/item/organ/genital/Initialize() . = ..() - if(!reagents) + if(fluid_id) create_reagents(fluid_max_volume) + if(producing) + reagents.add_reagent(fluid_id, fluid_max_volume) update() /obj/item/organ/genital/Destroy() - remove_ref() + if(linked_organ) + update_link(TRUE)//this should remove any other links it has if(owner) - Remove(owner, 1)//this should remove references to it, so it can be GCd correctly - update_link()//this should remove any other links it has + Remove(owner, TRUE)//this should remove references to it, so it can be GCd correctly return ..() -/obj/item/organ/genital/proc/update() +/obj/item/organ/genital/proc/update(removing = FALSE) if(QDELETED(src)) return update_size() update_appearance() - update_link() + if(linked_organ_slot || (linked_organ && removing)) + update_link(removing) //exposure and through-clothing code /mob/living/carbon var/list/exposed_genitals = list() //Keeping track of them so we don't have to iterate through every genitalia and see if exposed /obj/item/organ/genital/proc/is_exposed() - if(!owner) - return FALSE - if(hidden) - return FALSE - if(internal) + if(!owner || hidden || internal) return FALSE if(through_clothes) return TRUE switch(zone) //update as more genitals are added - if("chest") + if(BODY_ZONE_CHEST) return owner.is_chest_exposed() - if("groin") + if(BODY_ZONE_PRECISE_GROIN) return owner.is_groin_exposed() return FALSE @@ -107,22 +109,37 @@ picked_organ.toggle_visibility(picked_visibility) return - - - /obj/item/organ/genital/proc/update_size() return /obj/item/organ/genital/proc/update_appearance() return -/obj/item/organ/genital/proc/update_link() - return +/obj/item/organ/genital/on_life() + if(!reagents || !owner) + return + reagents.maximum_volume = fluid_max_volume + if(fluid_id && producing) + generate_fluid() -/obj/item/organ/genital/proc/remove_ref() - if(linked_organ) - linked_organ.linked_organ = null +/obj/item/organ/genital/proc/generate_fluid() + if(owner.stat != DEAD && reagents.total_volume < reagents.maximum_volume) + reagents.isolate_reagent(fluid_id)//remove old reagents if it changed and just clean up generally + reagents.add_reagent(fluid_id, (fluid_mult * fluid_rate))//generate the cum + return TRUE + return FALSE + +/obj/item/organ/genital/proc/update_link(removing = FALSE) + if(!removing && owner) + linked_organ = owner.getorganslot(linked_organ_slot) + if(linked_organ) + linked_organ.linked_organ = src + return TRUE + else + if(linked_organ) + linked_organ.linked_organ = null linked_organ = null + return FALSE /obj/item/organ/genital/Insert(mob/living/carbon/M, special = 0) ..() @@ -130,127 +147,42 @@ /obj/item/organ/genital/Remove(mob/living/carbon/M, special = 0) ..() - update() + update(TRUE) //proc to give a player their genitals and stuff when they log in -/mob/living/carbon/human/proc/give_genitals(clean=0)//clean will remove all pre-existing genitals. proc will then give them any genitals that are enabled in their DNA +/mob/living/carbon/human/proc/give_genitals(clean = FALSE)//clean will remove all pre-existing genitals. proc will then give them any genitals that are enabled in their DNA if(clean) - var/obj/item/organ/genital/GtoClean - for(GtoClean in internal_organs) - qdel(GtoClean) + for(var/obj/item/organ/genital/G in internal_organs) + qdel(G) if (NOGENITALS in dna.species.species_traits) return - //Order should be very important. FIRST vagina, THEN testicles, THEN penis, as this affects the order they are rendered in. if(dna.features["has_vag"]) - give_vagina() + give_genital(/obj/item/organ/genital/vagina) if(dna.features["has_womb"]) - give_womb() + give_genital(/obj/item/organ/genital/womb) if(dna.features["has_balls"]) - give_balls() + give_genital(/obj/item/organ/genital/testicles) if(dna.features["has_breasts"]) // since we have multi-boobs as a thing, we'll want to at least draw over these. but not over the pingas. - give_breasts() + give_genital(/obj/item/organ/genital/breasts) if(dna.features["has_cock"]) - give_penis() + give_genital(/obj/item/organ/genital/penis) + /* if(dna.features["has_ovi"]) - give_ovipositor() + give_genital(/obj/item/organ/genital/ovipositor) if(dna.features["has_eggsack"]) - give_eggsack() + give_genital(/obj/item/organ/genital/eggsack) + */ -/mob/living/carbon/human/proc/give_penis() - if(!dna) +/mob/living/carbon/human/proc/give_genital(obj/item/organ/genital/G) + if(!dna || (NOGENITALS in dna.species.species_traits) || getorganslot(initial(G.slot))) return FALSE - if(NOGENITALS in dna.species.species_traits) - return FALSE - if(!getorganslot("penis")) - var/obj/item/organ/genital/penis/P = new - P.Insert(src) - if(P) - if(dna.species.use_skintones && dna.features["genitals_use_skintone"]) - P.color = "#[skintone2hex(skin_tone)]" - else - P.color = "#[dna.features["cock_color"]]" - P.length = dna.features["cock_length"] - P.girth_ratio = dna.features["cock_girth_ratio"] - P.shape = dna.features["cock_shape"] - P.update() + G = new + if(istype(G, /obj/item/organ/genital)) //badminnery-proofing. + G.get_features(src) + G.Insert(src) -/mob/living/carbon/human/proc/give_balls() - if(!dna) - return FALSE - if(NOGENITALS in dna.species.species_traits) - return FALSE - if(!getorganslot("testicles")) - var/obj/item/organ/genital/testicles/T = new - T.Insert(src) - if(T) - if(dna.species.use_skintones && dna.features["genitals_use_skintone"]) - T.color = "#[skintone2hex(skin_tone)]" - else - T.color = "#[dna.features["balls_color"]]" - T.size = dna.features["balls_size"] - T.sack_size = dna.features["balls_sack_size"] - T.shape = dna.features["balls_shape"] - if(dna.features["balls_shape"] == "Hidden") - T.internal = TRUE - else - T.internal = FALSE - T.fluid_id = dna.features["balls_fluid"] - T.fluid_rate = dna.features["balls_cum_rate"] - T.fluid_mult = dna.features["balls_cum_mult"] - T.fluid_efficiency = dna.features["balls_efficiency"] - T.update() - -/mob/living/carbon/human/proc/give_breasts() - if(!dna) - return FALSE - if(NOGENITALS in dna.species.species_traits) - return FALSE - if(!getorganslot("breasts")) - var/obj/item/organ/genital/breasts/B = new - B.Insert(src) - if(B) - if(dna.species.use_skintones && dna.features["genitals_use_skintone"]) - B.color = "#[skintone2hex(skin_tone)]" - else - B.color = "#[dna.features["breasts_color"]]" - B.size = dna.features["breasts_size"] - B.shape = dna.features["breasts_shape"] - B.fluid_id = dna.features["breasts_fluid"] - B.update() - - -/mob/living/carbon/human/proc/give_ovipositor() +/obj/item/organ/genital/proc/get_features(datum/dna/D) return -/mob/living/carbon/human/proc/give_eggsack() - return - -/mob/living/carbon/human/proc/give_vagina() - if(!dna) - return FALSE - if(NOGENITALS in dna.species.species_traits) - return FALSE - if(!getorganslot("vagina")) - var/obj/item/organ/genital/vagina/V = new - V.Insert(src) - if(V) - if(dna.species.use_skintones && dna.features["genitals_use_skintone"]) - V.color = "#[skintone2hex(skin_tone)]" - else - V.color = "[dna.features["vag_color"]]" - V.shape = "[dna.features["vag_shape"]]" - V.update() - -/mob/living/carbon/human/proc/give_womb() - if(!dna) - return FALSE - if(NOGENITALS in dna.species.species_traits) - return FALSE - if(!getorganslot("womb")) - var/obj/item/organ/genital/womb/W = new - W.Insert(src) - if(W) - W.update() - /datum/species/proc/genitals_layertext(layer) switch(layer) @@ -267,7 +199,7 @@ if(ishuman(user)) var/mob/living/carbon/human/H = user H.update_genitals() - ..() + . = ..() /mob/living/carbon/human/doUnEquip(obj/item/I, force) . = ..() @@ -276,20 +208,16 @@ update_genitals() /mob/living/carbon/human/proc/update_genitals() - if(src && !QDELETED(src)) + if(!QDELETED(src)) dna.species.handle_genitals(src) /datum/species/proc/handle_genitals(mob/living/carbon/human/H) if(!H)//no args CRASH("H = null") - if(!LAZYLEN(H.internal_organs))//if they have no organs, we're done - return - if(NOGENITALS in species_traits)//golems and such - return - if(HAS_TRAIT(H, TRAIT_HUSK)) + if(!LAZYLEN(H.internal_organs) || (NOGENITALS in species_traits) || HAS_TRAIT(H, TRAIT_HUSK)) return - var/list/genitals_to_add = list() + var/list/genitals_to_add[GENITAL_LAYER_INDEX_LENGTH] var/list/relevant_layers = list(GENITALS_BEHIND_LAYER, GENITALS_ADJ_LAYER, GENITALS_FRONT_LAYER) var/list/standing = list() var/size @@ -300,18 +228,16 @@ //start scanning for genitals //var/list/worn_stuff = H.get_equipped_items()//cache this list so it's not built again - for(var/obj/item/organ/O in H.internal_organs) - if(isgenital(O)) - var/obj/item/organ/genital/G = O - if(G.hidden) - return //we're gunna just hijack this for updates. - if(G.is_exposed()) //Checks appropriate clothing slot and if it's through_clothes - genitals_to_add += H.getorganslot(G.slot) + for(var/obj/item/organ/genital/G in H.internal_organs) + if(G.hidden) + return //we're gunna just hijack this for updates. + if(G.is_exposed()) //Checks appropriate clothing slot and if it's through_clothes + LAZYADD(genitals_to_add[G.layer_index], G) //Now we added all genitals that aren't internal and should be rendered //start applying overlays for(var/layer in relevant_layers) - var/layertext = genitals_layertext(layer) + var/layertext = flatten_list(genitals_layertext(layer)) for(var/obj/item/organ/genital/G in genitals_to_add) var/datum/sprite_accessory/S size = G.size @@ -357,3 +283,4 @@ for(var/L in relevant_layers) H.apply_overlay(L) + diff --git a/modular_citadel/code/modules/arousal/organs/breasts.dm b/modular_citadel/code/modules/arousal/organs/breasts.dm index 1223f0b616..f6d5673a53 100644 --- a/modular_citadel/code/modules/arousal/organs/breasts.dm +++ b/modular_citadel/code/modules/arousal/organs/breasts.dm @@ -1,38 +1,20 @@ /obj/item/organ/genital/breasts - name = "breasts" - desc = "Female milk producing organs." - icon_state = "breasts" - icon = 'modular_citadel/icons/obj/genitals/breasts.dmi' - zone = "chest" - slot = "breasts" - size = BREASTS_SIZE_DEF - fluid_id = "milk" - var/amount = 2 - producing = TRUE - shape = "pair" - can_masturbate_with = TRUE - masturbation_verb = "massage" - can_climax = TRUE - fluid_transfer_factor = 0.5 - -/obj/item/organ/genital/breasts/Initialize() - . = ..() - reagents.add_reagent(fluid_id, fluid_max_volume) - -/obj/item/organ/genital/breasts/on_life() - if(QDELETED(src)) - return - if(!reagents || !owner) - return - reagents.maximum_volume = fluid_max_volume - if(fluid_id && producing) - generate_milk() - -/obj/item/organ/genital/breasts/proc/generate_milk() - if(owner.stat == DEAD) - return FALSE - reagents.isolate_reagent(fluid_id) - reagents.add_reagent(fluid_id, (fluid_mult * fluid_rate)) + name = "breasts" + desc = "Female milk producing organs." + icon_state = "breasts" + icon = 'modular_citadel/icons/obj/genitals/breasts.dmi' + zone = BODY_ZONE_CHEST + slot = ORGAN_SLOT_BREASTS + size = BREASTS_SIZE_DEF + fluid_id = "milk" + var/amount = 2 + producing = TRUE + shape = "pair" + can_masturbate_with = TRUE + masturbation_verb = "massage" + orgasm_verb = "leaking" + can_climax = TRUE + fluid_transfer_factor = 0.5 /obj/item/organ/genital/breasts/update_appearance() var/lowershape = lowertext(shape) @@ -65,3 +47,13 @@ var/mob/living/carbon/human/H = owner icon_state = sanitize_text(string) H.update_genitals() + +/obj/item/organ/genital/breasts/get_features(mob/living/carbon/human/H) + var/datum/dna/D = H.dna + if(D.species.use_skintones && D.features["genitals_use_skintone"]) + color = "#[skintone2hex(H.skin_tone)]" + else + color = "#[D.features["breasts_color"]]" + size = D.features["breasts_size"] + shape = D.features["breasts_shape"] + fluid_id = D.features["breasts_fluid"] diff --git a/modular_citadel/code/modules/arousal/organs/eggsack.dm b/modular_citadel/code/modules/arousal/organs/eggsack.dm index 402d246e40..3282bad5f9 100644 --- a/modular_citadel/code/modules/arousal/organs/eggsack.dm +++ b/modular_citadel/code/modules/arousal/organs/eggsack.dm @@ -1,14 +1,14 @@ /obj/item/organ/genital/eggsack - name = "Egg sack" - desc = "An egg producing reproductive organ." - icon_state = "egg_sack" - icon = 'modular_citadel/icons/obj/genitals/ovipositor.dmi' - zone = "groin" - slot = "testicles" - color = null //don't use the /genital color since it already is colored + name = "Egg sack" + desc = "An egg producing reproductive organ." + icon_state = "egg_sack" + icon = 'modular_citadel/icons/obj/genitals/ovipositor.dmi' + zone = BODY_ZONE_PRECISE_GROIN + slot = ORGAN_SLOT_TESTICLES + linked_organ_slot = ORGAN_SLOT_PENIS + color = null //don't use the /genital color since it already is colored internal = TRUE var/egg_girth = EGG_GIRTH_DEF var/cum_mult = CUM_RATE_MULT var/cum_rate = CUM_RATE var/cum_efficiency = CUM_EFFICIENCY - var/obj/item/organ/ovipositor/linked_ovi diff --git a/modular_citadel/code/modules/arousal/organs/genitals_sprite_accessories.dm b/modular_citadel/code/modules/arousal/organs/genitals_sprite_accessories.dm index b913a90fb6..4ba2e373a2 100644 --- a/modular_citadel/code/modules/arousal/organs/genitals_sprite_accessories.dm +++ b/modular_citadel/code/modules/arousal/organs/genitals_sprite_accessories.dm @@ -5,11 +5,9 @@ //DICKS,COCKS,PENISES,WHATEVER YOU WANT TO CALL THEM /datum/sprite_accessory/penis icon = 'modular_citadel/icons/obj/genitals/penis_onmob.dmi' - icon_state = null name = "penis" //the preview name of the accessory - gender_specific = 0 //Might be needed somewhere down the list. color_src = "cock_color" - locked = 0 + alt_aroused = TRUE /datum/sprite_accessory/penis/human icon_state = "human" @@ -62,27 +60,21 @@ icon_state = "testicle" name = "testicle" //the preview name of the accessory color_src = "balls_color" - locked = 0 /datum/sprite_accessory/testicles/hidden - icon_state = "hidden" + icon_state = "none" name = "Hidden" - alt_aroused = TRUE /datum/sprite_accessory/testicles/single icon_state = "single" name = "Single" - alt_aroused = TRUE //Vaginas /datum/sprite_accessory/vagina icon = 'modular_citadel/icons/obj/genitals/vagina_onmob.dmi' icon_state = null name = "vagina" - gender_specific = 0 color_src = "vag_color" - locked = 0 - alt_aroused = FALSE //if this is TRUE, then the genitals will use an alternate sprite for aroused states /datum/sprite_accessory/vagina/human icon_state = "human" @@ -114,35 +106,28 @@ //BREASTS BE HERE /datum/sprite_accessory/breasts icon = 'modular_citadel/icons/obj/genitals/breasts_onmob.dmi' - icon_state = null name = "breasts" - gender_specific = 0 color_src = "breasts_color" - locked = 0 + alt_aroused = TRUE /datum/sprite_accessory/breasts/pair icon_state = "pair" name = "Pair" - alt_aroused = TRUE /datum/sprite_accessory/breasts/quad icon_state = "quad" name = "Quad" - alt_aroused = TRUE /datum/sprite_accessory/breasts/sextuple icon_state = "sextuple" name = "Sextuple" - alt_aroused = TRUE //OVIPOSITORS BE HERE /datum/sprite_accessory/ovipositor icon = 'modular_citadel/icons/obj/genitals/penis_onmob.dmi' icon_state = null name = "Ovipositor" //the preview name of the accessory - gender_specific = 0 //Might be needed somewhere down the list. color_src = "cock_color" - locked = 0 /datum/sprite_accessory/ovipositor/knotted icon_state = "knotted" diff --git a/modular_citadel/code/modules/arousal/organs/ovipositor.dm b/modular_citadel/code/modules/arousal/organs/ovipositor.dm index 76bf60d93c..92b608f905 100644 --- a/modular_citadel/code/modules/arousal/organs/ovipositor.dm +++ b/modular_citadel/code/modules/arousal/organs/ovipositor.dm @@ -3,14 +3,13 @@ desc = "An egg laying reproductive organ." icon_state = "ovi_knotted_2" icon = 'modular_citadel/icons/obj/genitals/ovipositor.dmi' - zone = "groin" - slot = "penis" - w_class = 3 + zone = BODY_ZONE_PRECISE_GROIN + slot = ORGAN_SLOT_PENIS shape = "knotted" size = 3 + layer_index = PENIS_LAYER_INDEX var/length = 6 //inches var/girth = 0 var/girth_ratio = COCK_GIRTH_RATIO_DEF //citadel_defines.dm for these defines var/knot_girth_ratio = KNOT_GIRTH_RATIO_DEF var/list/oviflags = list() - var/obj/item/organ/eggsack/linked_eggsack diff --git a/modular_citadel/code/modules/arousal/organs/penis.dm b/modular_citadel/code/modules/arousal/organs/penis.dm index b6cb8fa4b2..2593460a32 100644 --- a/modular_citadel/code/modules/arousal/organs/penis.dm +++ b/modular_citadel/code/modules/arousal/organs/penis.dm @@ -1,22 +1,23 @@ /obj/item/organ/genital/penis - name = "penis" - desc = "A male reproductive organ." - icon_state = "penis" - icon = 'modular_citadel/icons/obj/genitals/penis.dmi' - zone = "groin" - slot = ORGAN_SLOT_PENIS - can_masturbate_with = TRUE - masturbation_verb = "stroke" - can_climax = TRUE - fluid_transfer_factor = 0.5 - size = 2 //arbitrary value derived from length and girth for sprites. - var/length = 6 //inches - var/cached_length //used to detect a change in length - var/girth = 0 - var/girth_ratio = COCK_GIRTH_RATIO_DEF //0.73; check citadel_defines.dm - var/knot_girth_ratio = KNOT_GIRTH_RATIO_DEF - var/list/dickflags = list() - var/list/knotted_types = list("knotted", "barbed, knotted") + name = "penis" + desc = "A male reproductive organ." + icon_state = "penis" + icon = 'modular_citadel/icons/obj/genitals/penis.dmi' + zone = BODY_ZONE_PRECISE_GROIN + slot = ORGAN_SLOT_PENIS + can_masturbate_with = TRUE + masturbation_verb = "stroke" + can_climax = TRUE + fluid_transfer_factor = 0.5 + size = 2 //arbitrary value derived from length and girth for sprites. + layer_index = PENIS_LAYER_INDEX + var/length = 6 //inches + var/cached_length //used to detect a change in length + var/girth = 0 + var/girth_ratio = COCK_GIRTH_RATIO_DEF //0.73; check citadel_defines.dm + var/knot_girth_ratio = KNOT_GIRTH_RATIO_DEF + var/list/dickflags = list() + var/list/knotted_types = list("knotted", "barbed, knotted") /obj/item/organ/genital/penis/update_size() if(length == cached_length) @@ -38,7 +39,7 @@ /obj/item/organ/genital/penis/update_appearance() var/string var/lowershape = lowertext(shape) - desc = "You see [aroused_state ? "an erect" : "a flaccid"] [lowershape] penis. You estimate it's about [round(length, 0.25)] inch[round(length, 0.25) != 1 ? "es" : ""] long and [round(girth, 0.25)] inch[round(girth, 0.25) != 1 ? "es" : ""] in girth." + desc = "You see [aroused_state ? "an erect" : "a flaccid"] [lowershape] [name]. You estimate it's about [round(length, 0.25)] inch[round(length, 0.25) != 1 ? "es" : ""] long and [round(girth, 0.25)] inch[round(girth, 0.25) != 1 ? "es" : ""] in girth." if(owner) if(owner.dna.species.use_skintones && owner.dna.features["genitals_use_skintone"]) @@ -54,13 +55,12 @@ icon_state = sanitize_text(string) H.update_genitals() -/obj/item/organ/genital/penis/update_link() - if(owner) - linked_organ = (owner.getorganslot("testicles")) - if(linked_organ) - linked_organ.linked_organ = src - linked_organ.size = size +/obj/item/organ/genital/penis/get_features(mob/living/carbon/human/H) + var/datum/dna/D = H.dna + if(D.species.use_skintones && D.features["genitals_use_skintone"]) + color = "#[skintone2hex(H.skin_tone)]" else - if(linked_organ) - linked_organ.linked_organ = null - linked_organ = null + color = "#[D.features["cock_color"]]" + length = D.features["cock_length"] + girth_ratio = D.features["cock_girth_ratio"] + shape = D.features["cock_shape"] diff --git a/modular_citadel/code/modules/arousal/organs/testicles.dm b/modular_citadel/code/modules/arousal/organs/testicles.dm index 1e6b4d62d4..de7b6d6f70 100644 --- a/modular_citadel/code/modules/arousal/organs/testicles.dm +++ b/modular_citadel/code/modules/arousal/organs/testicles.dm @@ -1,56 +1,34 @@ /obj/item/organ/genital/testicles - name = "testicles" - desc = "A male reproductive organ." - icon_state = "testicles" - icon = 'modular_citadel/icons/obj/genitals/testicles.dmi' - zone = "groin" - slot = "testicles" - size = BALLS_SIZE_MIN - var/size_name = "average" - shape = "single" - var/sack_size = BALLS_SACK_SIZE_DEF - fluid_id = "semen" - producing = TRUE - can_masturbate_with = FALSE - masturbation_verb = "massage" - can_climax = TRUE - var/sent_full_message = TRUE //defaults to 1 since they're full to start + name = "testicles" + desc = "A male reproductive organ." + icon_state = "testicles" + icon = 'modular_citadel/icons/obj/genitals/testicles.dmi' + zone = BODY_ZONE_PRECISE_GROIN + slot = ORGAN_SLOT_TESTICLES + size = BALLS_SIZE_MIN + linked_organ_slot = ORGAN_SLOT_PENIS + var/size_name = "average" + shape = "single" + var/sack_size = BALLS_SACK_SIZE_DEF + fluid_id = "semen" + producing = TRUE + can_masturbate_with = MASTURBATE_LINKED_ORGAN + masturbation_verb = "massage" + layer_index = TESTICLES_LAYER_INDEX + var/size_linked = FALSE -/obj/item/organ/genital/testicles/Initialize() +/obj/item/organ/genital/testicles/generate_fluid() + if(!linked_organ && !update_link()) + return FALSE . = ..() - reagents.add_reagent(fluid_id, fluid_max_volume) + if(.) + send_full_message() -/obj/item/organ/genital/testicles/on_life() - if(QDELETED(src)) - return - if(reagents && producing) - generate_cum() - -/obj/item/organ/genital/testicles/proc/generate_cum() - reagents.maximum_volume = fluid_max_volume - if(reagents.total_volume >= reagents.maximum_volume) - if(!sent_full_message) - send_full_message() - sent_full_message = TRUE - return FALSE - sent_full_message = FALSE - update_link() - if(!linked_organ) - return FALSE - reagents.isolate_reagent(fluid_id)//remove old reagents if it changed and just clean up generally - reagents.add_reagent(fluid_id, (fluid_mult * fluid_rate))//generate the cum - -/obj/item/organ/genital/testicles/update_link() - if(owner && !QDELETED(src)) - linked_organ = (owner.getorganslot("penis")) - if(linked_organ) - linked_organ.linked_organ = src - size = linked_organ.size - - else - if(linked_organ) - linked_organ.linked_organ = null - linked_organ = null +/obj/item/organ/genital/testicles/update_link(removing = FALSE) + . = ..() + if(. && !size_linked) + size = linked_organ.size + size_linked = TRUE /obj/item/organ/genital/testicles/proc/send_full_message(msg = "Your balls finally feel full, again.") if(owner && istext(msg)) @@ -59,19 +37,16 @@ /obj/item/organ/genital/testicles/update_appearance() switch(size) - if(0.1 to 1) + if(BALLS_SIZE_MIN) size_name = "average" - if(1.1 to 2) + if(BALLS_SIZE_DEF) size_name = "enlarged" - if(2.1 to INFINITY) + if(BALLS_SIZE_MAX) size_name = "engorged" else size_name = "nonexistant" - if(!internal) - desc = "You see an [size_name] pair of testicles." - else - desc = "They don't have any testicles you can see." + desc = "You see an [size_name] pair of testicles." if(owner) var/string @@ -87,3 +62,21 @@ var/mob/living/carbon/human/H = owner icon_state = sanitize_text(string) H.update_genitals() + +/obj/item/organ/genital/testicles/get_features(mob/living/carbon/human/H) + var/datum/dna/D = H.dna + if(D.species.use_skintones && D.features["genitals_use_skintone"]) + color = "#[skintone2hex(H.skin_tone)]" + else + color = "#[D.features["balls_color"]]" + size = D.features["balls_size"] + sack_size = D.features["balls_sack_size"] + shape = D.features["balls_shape"] + if(D.features["balls_shape"] == "Hidden") + internal = TRUE + else + internal = FALSE + fluid_id = D.features["balls_fluid"] + fluid_rate = D.features["balls_cum_rate"] + fluid_mult = D.features["balls_cum_mult"] + fluid_efficiency = D.features["balls_efficiency"] diff --git a/modular_citadel/code/modules/arousal/organs/vagina.dm b/modular_citadel/code/modules/arousal/organs/vagina.dm index 8c15aa5437..af2beb5f79 100644 --- a/modular_citadel/code/modules/arousal/organs/vagina.dm +++ b/modular_citadel/code/modules/arousal/organs/vagina.dm @@ -1,25 +1,24 @@ /obj/item/organ/genital/vagina - name = "vagina" - desc = "A female reproductive organ." - icon = 'modular_citadel/icons/obj/genitals/vagina.dmi' - icon_state = "vagina" - zone = "groin" - slot = "vagina" - size = 1 //There is only 1 size right now - can_masturbate_with = TRUE - masturbation_verb = "finger" - can_climax = TRUE + name = "vagina" + desc = "A female reproductive organ." + icon = 'modular_citadel/icons/obj/genitals/vagina.dmi' + icon_state = ORGAN_SLOT_VAGINA + zone = BODY_ZONE_PRECISE_GROIN + slot = "vagina" + size = 1 //There is only 1 size right now + can_masturbate_with = TRUE + masturbation_verb = "finger" + can_climax = TRUE fluid_transfer_factor = 0.1 //Yes, some amount is exposed to you, go get your AIDS - w_class = 3 - var/cap_length = 8//D E P T H (cap = capacity) - var/cap_girth = 12 + layer_index = VAGINA_LAYER_INDEX + var/cap_length = 8//D E P T H (cap = capacity) + var/cap_girth = 12 var/cap_girth_ratio = 1.5 - var/clits = 1 - var/clit_diam = 0.25 - var/clit_len = 0.25 + var/clits = 1 + var/clit_diam = 0.25 + var/clit_len = 0.25 var/list/vag_types = list("tentacle", "dentata", "hairy", "spade", "furred") - /obj/item/organ/genital/vagina/update_appearance() var/string //Keeping this code here, so making multiple sprites for the different kinds is easier. var/lowershape = lowertext(shape) @@ -63,12 +62,10 @@ icon_state = sanitize_text(string) H.update_genitals() -/obj/item/organ/genital/vagina/update_link() - if(owner) - linked_organ = (owner.getorganslot("womb")) - if(linked_organ) - linked_organ.linked_organ = src +/obj/item/organ/genital/vagina/get_features(mob/living/carbon/human/H) + var/datum/dna/D = H.dna + if(D.species.use_skintones && D.features["genitals_use_skintone"]) + color = "#[skintone2hex(H.skin_tone)]" else - if(linked_organ) - linked_organ.linked_organ = null - linked_organ = null + color = "[D.features["vag_color"]]" + shape = "[D.features["vag_shape"]]" diff --git a/modular_citadel/code/modules/arousal/organs/womb.dm b/modular_citadel/code/modules/arousal/organs/womb.dm index 686d9059a0..d99206d0f1 100644 --- a/modular_citadel/code/modules/arousal/organs/womb.dm +++ b/modular_citadel/code/modules/arousal/organs/womb.dm @@ -1,41 +1,11 @@ /obj/item/organ/genital/womb - name = "womb" - desc = "A female reproductive organ." - icon = 'modular_citadel/icons/obj/genitals/vagina.dmi' - icon_state = "womb" - zone = "groin" - slot = "womb" - internal = TRUE - fluid_id = "femcum" - producing = TRUE - -/obj/item/organ/genital/womb/Initialize() - . = ..() - reagents.add_reagent(fluid_id, fluid_max_volume) - -/obj/item/organ/genital/womb/on_life() - if(QDELETED(src)) - return - if(reagents && producing) - generate_femcum() - -/obj/item/organ/genital/womb/proc/generate_femcum() - reagents.maximum_volume = fluid_max_volume - update_link() - if(!linked_organ) - return FALSE - reagents.isolate_reagent(fluid_id)//remove old reagents if it changed and just clean up generally - reagents.add_reagent(fluid_id, (fluid_mult * fluid_rate))//generate the cum - -/obj/item/organ/genital/womb/update_link() - if(owner) - linked_organ = (owner.getorganslot("vagina")) - if(linked_organ) - linked_organ.linked_organ = src - else - if(linked_organ) - linked_organ.linked_organ = null - linked_organ = null - -/obj/item/organ/genital/womb/Destroy() - return ..() + name = "womb" + desc = "A female reproductive organ." + icon = 'modular_citadel/icons/obj/genitals/vagina.dmi' + icon_state = "womb" + zone = BODY_ZONE_PRECISE_GROIN + slot = ORGAN_SLOT_WOMB + internal = TRUE + fluid_id = "femcum" + producing = TRUE + linked_organ_slot = ORGAN_SLOT_VAGINA \ No newline at end of file diff --git a/modular_citadel/code/modules/client/preferences_savefile.dm b/modular_citadel/code/modules/client/preferences_savefile.dm index 2921f70684..be9e92d4c3 100644 --- a/modular_citadel/code/modules/client/preferences_savefile.dm +++ b/modular_citadel/code/modules/client/preferences_savefile.dm @@ -32,7 +32,6 @@ WRITE_FILE(S["feature_ipc_antenna"], features["ipc_antenna"]) //Citadel WRITE_FILE(S["feature_genitals_use_skintone"], features["genitals_use_skintone"]) - WRITE_FILE(S["feature_exhibitionist"], features["exhibitionist"]) WRITE_FILE(S["feature_mcolor2"], features["mcolor2"]) WRITE_FILE(S["feature_mcolor3"], features["mcolor3"]) WRITE_FILE(S["feature_mam_body_markings"], features["mam_body_markings"]) diff --git a/modular_citadel/code/modules/mob/living/carbon/human/life.dm b/modular_citadel/code/modules/mob/living/carbon/human/life.dm index e728d70c97..fbaa1b4b58 100644 --- a/modular_citadel/code/modules/mob/living/carbon/human/life.dm +++ b/modular_citadel/code/modules/mob/living/carbon/human/life.dm @@ -1,7 +1,7 @@ -/mob/living/carbon/human/Life() +/mob/living/carbon/human/Life(seconds, times_fired) //citadel code if(stat != DEAD) - handle_arousal() + handle_arousal(times_fired) . = ..() /mob/living/carbon/human/calculate_affecting_pressure(pressure) diff --git a/modular_citadel/code/modules/mob/living/carbon/human/species_types/jellypeople.dm b/modular_citadel/code/modules/mob/living/carbon/human/species_types/jellypeople.dm index fa6ded8065..0e6c12053a 100644 --- a/modular_citadel/code/modules/mob/living/carbon/human/species_types/jellypeople.dm +++ b/modular_citadel/code/modules/mob/living/carbon/human/species_types/jellypeople.dm @@ -78,42 +78,30 @@ else H.facial_hair_style = "Shaved" //handle normal hair - var/new_style = input(owner, "Select a hair style", "Hair Alterations") as null|anything in GLOB.hair_styles_list + var/new_style = input(owner, "Select a hair style", "Hair Alterations") as null|anything in GLOB.hair_styles_list if(new_style) H.hair_style = new_style H.update_hair() else if (select_alteration == "Genitals") - var/list/organs = list() var/operation = input("Select organ operation.", "Organ Manipulation", "cancel") in list("add sexual organ", "remove sexual organ", "cancel") switch(operation) if("add sexual organ") - var/new_organ = input("Select sexual organ:", "Organ Manipulation") in list("Penis", "Testicles", "Breasts", "Vagina", "Womb", "Cancel") - if(new_organ == "Penis") - H.give_penis() - else if(new_organ == "Testicles") - H.give_balls() - else if(new_organ == "Breasts") - H.give_breasts() - else if(new_organ == "Vagina") - H.give_vagina() - else if(new_organ == "Womb") - H.give_womb() - else + var/new_organ = input("Select sexual organ:", "Organ Manipulation") as null|anything in GLOB.genitals_list + if(!new_organ) return + H.give_genital(GLOB.genitals_list[new_organ]) + if("remove sexual organ") + var/list/organs = list() for(var/obj/item/organ/genital/X in H.internal_organs) var/obj/item/organ/I = X organs["[I.name] ([I.type])"] = I - var/obj/item/organ = input("Select sexual organ:", "Organ Manipulation", null) in organs - organ = organs[organ] - if(!organ) + var/obj/item/O = input("Select sexual organ:", "Organ Manipulation", null) as null|anything in organs + var/obj/item/organ/genital/G = organs[O] + if(!G) return - var/obj/item/organ/genital/O - if(isorgan(organ)) - O = organ - O.Remove(H) - organ.forceMove(get_turf(H)) - qdel(organ) + G.forceMove(get_turf(H)) + qdel(G) H.update_genitals() else if (select_alteration == "Ears") @@ -203,8 +191,8 @@ if(new_shape) H.dna.features["cock_shape"] = new_shape H.update_genitals() - H.give_balls() - H.give_penis() + H.give_genital(/obj/item/organ/genital/testicles) + H.give_genital(/obj/item/organ/genital/penis) H.apply_overlay() @@ -216,8 +204,8 @@ if(new_shape) H.dna.features["vag_shape"] = new_shape H.update_genitals() - H.give_womb() - H.give_vagina() + H.give_genital(/obj/item/organ/genital/womb) + H.give_genital(/obj/item/organ/genital/vagina) H.apply_overlay() else if (select_alteration == "Penis Length") @@ -229,8 +217,8 @@ H.dna.features["cock_length"] = max(min( round(text2num(new_length)), COCK_SIZE_MAX),COCK_SIZE_MIN) H.update_genitals() H.apply_overlay() - H.give_balls() - H.give_penis() + H.give_genital(/obj/item/organ/genital/testicles) + H.give_genital(/obj/item/organ/genital/penis) else if (select_alteration == "Breast Size") for(var/obj/item/organ/genital/breasts/X in H.internal_organs) @@ -241,7 +229,7 @@ H.dna.features["breasts_size"] = new_size H.update_genitals() H.apply_overlay() - H.give_breasts() + H.give_genital(/obj/item/organ/genital/breasts) else if (select_alteration == "Breast Shape") for(var/obj/item/organ/genital/breasts/X in H.internal_organs) @@ -252,7 +240,7 @@ H.dna.features["breasts_shape"] = new_shape H.update_genitals() H.apply_overlay() - H.give_breasts() + H.give_genital(/obj/item/organ/genital/breasts) else return diff --git a/modular_citadel/icons/obj/genitals/testicles_onmob.dmi b/modular_citadel/icons/obj/genitals/testicles_onmob.dmi index 33659cf13cb42239e1fc3a2e8ccf3c02ff42ea26..7d4d2610c5337d0877fd9d741c38998893444576 100644 GIT binary patch delta 554 zcmV+_0@eNZ1+oNFiBL{Q4GJ0x0000DNk~Le0002s0002s1Oos70O$jE(f|Me6;Mo6 zMZmzo)YR1W-sjr1vg+B~<;Kgvz`!ul@9_Wt00DGTPE!Ct=GbNc0069!P!xZXK@Ng2 z5JlJRDH>R7D0S;X(nf0{S7?ZgbP~jbY4rMn96%j*|1aLWWNscbK#O z0#@$iYx_T2a;4=8so_e^3aNkI5PRSW)%=P1;ss^T%om#<#JO^{{k;Ag^Y-h|ENe+x z0003KNklWH z0{{ScN7EDnhj1SI-)!9Z91`bg`8@W&Qv3Ol7Ooo@9n-wF?mhqjfL~KOPl3|@=eOt( z>Rs-CrOOx!W*g?^{#Q;qT`!@(rFs|pU#UH=dqDsIfK9~y_m>fcVL2W9Usev-kIU)Y s|Dvz*52)AWbcOymyHKorp9v561}X^=h=s}*u>b%707*qoM6N<$f}&*w)Bpeg literal 759 zcmeAS@N?(olHy`uVBq!ia0y~yU~B+k7G|JG*vl0?KuRdUC&cx@fdf~rT={nI`K>LR zUfsO&^w{Z}CW78TS;mqezhDN3XE)M-oG(=&5hX6E#mPmP1tppJc?=8{bCynXw_}%}Keknxc>Bd#9`$GO? z9)BR;e53oW+2c1)Z@*a9J86#PYin`)*#fgOmZu8kcKo|_JE2K_*S%SHQl2e1&zZhf z{%{Rn`u2@GZ&%L!&r&RM#wT#zs;Fewz_3NjgiNQh1bZ5Uu2|{hD|#?Q(C4#n!)NP- z8BO9-%F->wcWgY;tNQa?i^=0-T;^da$*q#s_qUZDPEaktG3V{ggSm$s1Xu&4 zgB$KLE@E<-WX-PC@UPl)$(%h6ZCCpa3cY`tlKC$s{Lz=~uYtkFkYUh!(81pBpVx`- z`OB>~eB%ZQGJI$}wqdT`v&o;$wO+rio3%>p+tG?_yIK5e-!p9u`!37`QuD(l@#d`A z?@xc)78+Cj{MmBNSD&?Szx*1z;9Kp3tM&^&-sP9+{(OKDr1Z(@ch950hd$r@`)5Ub zk=^e3^*>oR0onIA{jAo0KL1xGNKu36jrUEBXWxAcciQ*MX6a)^s{=U+8sE1+TYVms zBp4X(z7*lf>HhiTPw%O^x@tRi;paE^-w}Jf_Gk3ezkfdb6_ri+XBQx|!1Vq*f!GQS zpyR>1O8mck-TCwE{rFWo)}KEc|LtP4OX0zUU!D8x%Z=nDH diff --git a/tgstation.dme b/tgstation.dme index 722ebae9be..7c9fa1e899 100755 --- a/tgstation.dme +++ b/tgstation.dme @@ -2844,7 +2844,6 @@ #include "modular_citadel\code\datums\mood_events\moodular.dm" #include "modular_citadel\code\datums\mutations\hulk.dm" #include "modular_citadel\code\datums\status_effects\debuffs.dm" -#include "modular_citadel\code\datums\traits\neutral.dm" #include "modular_citadel\code\datums\wires\airlock.dm" #include "modular_citadel\code\datums\wires\autoylathe.dm" #include "modular_citadel\code\game\area\cit_areas.dm" @@ -2912,9 +2911,9 @@ #include "modular_citadel\code\modules\admin\secrets.dm" #include "modular_citadel\code\modules\admin\topic.dm" #include "modular_citadel\code\modules\arousal\arousal.dm" +#include "modular_citadel\code\modules\arousal\organs\_genitals.dm" #include "modular_citadel\code\modules\arousal\organs\breasts.dm" #include "modular_citadel\code\modules\arousal\organs\eggsack.dm" -#include "modular_citadel\code\modules\arousal\organs\genitals.dm" #include "modular_citadel\code\modules\arousal\organs\genitals_sprite_accessories.dm" #include "modular_citadel\code\modules\arousal\organs\ovipositor.dm" #include "modular_citadel\code\modules\arousal\organs\penis.dm" From fd2f2ae1af2b6192cf705a7aa21760401ab9ea4d Mon Sep 17 00:00:00 2001 From: Ghommie Date: Tue, 23 Jul 2019 07:21:03 +0200 Subject: [PATCH 02/17] update, bitflags. --- code/__DEFINES/citadel_defines.dm | 4 +- code/__HELPERS/global_lists.dm | 3 +- .../code/modules/arousal/arousal.dm | 4 +- .../code/modules/arousal/organs/_genitals.dm | 42 +++++++++---------- .../code/modules/arousal/organs/eggsack.dm | 1 + .../code/modules/arousal/organs/ovipositor.dm | 1 + .../code/modules/arousal/organs/testicles.dm | 3 +- 7 files changed, 32 insertions(+), 26 deletions(-) diff --git a/code/__DEFINES/citadel_defines.dm b/code/__DEFINES/citadel_defines.dm index 8b75784ab2..b366a792e5 100644 --- a/code/__DEFINES/citadel_defines.dm +++ b/code/__DEFINES/citadel_defines.dm @@ -25,7 +25,9 @@ #define GENITAL_LAYER_INDEX_LENGTH 4 //keep it updated with each new index added, thanks. -#define MASTURBATE_LINKED_ORGAN 2 //special value used to pass our mission to the linked organ +//genital flags +#define GENITAL_BLACKLISTED (1 << 0) //for genitals that shouldn't be added to GLOB.genitals_list. +#define MASTURBATE_LINKED_ORGAN (1<<1) //used to pass our mission to the linked organ #define COCK_SIZE_MIN 1 #define COCK_SIZE_MAX 20 diff --git a/code/__HELPERS/global_lists.dm b/code/__HELPERS/global_lists.dm index b0b0f32345..96f2d404f8 100644 --- a/code/__HELPERS/global_lists.dm +++ b/code/__HELPERS/global_lists.dm @@ -64,7 +64,8 @@ for(var/gpath in subtypesof(/obj/item/organ/genital)) var/obj/item/organ/genital/G = gpath - GLOB.genitals_list[initial(G.name)] = gpath + if(!CHECK_BITFIELD(initial(G.genital_flags), GENITAL_BLACKLISTED)) + GLOB.genitals_list[initial(G.name)] = gpath //END OF CIT CHANGES //Species diff --git a/modular_citadel/code/modules/arousal/arousal.dm b/modular_citadel/code/modules/arousal/arousal.dm index 8826cb0774..924c507e7d 100644 --- a/modular_citadel/code/modules/arousal/arousal.dm +++ b/modular_citadel/code/modules/arousal/arousal.dm @@ -209,7 +209,7 @@ var/datum/reagents/fluid_source = G.climaxable(src) if(!fluid_source) return - var/obj/item/organ/genital/PP = G.can_masturbate_with == MASTURBATE_LINKED_ORGAN ? G.linked_organ : G + var/obj/item/organ/genital/PP = CHECK_BITFIELD(G.genital_flags, MASTURBATE_LINKED_ORGAN) ? G.linked_organ : G if(!PP) to_chat(src, "You shudder, unable to cum with your [name].") if(mb_time) @@ -274,7 +274,7 @@ for(var/obj/item/organ/genital/G in internal_organs) if(G.can_masturbate_with && G.is_exposed(worn_stuff)) //filter out what you can't masturbate with - if(G.can_masturbate_with == MASTURBATE_LINKED_ORGAN && !G.linked_organ) + if(CHECK_BITFIELD(G.genital_flags, MASTURBATE_LINKED_ORGAN) && !G.linked_organ) continue genitals_list += G if(genitals_list.len) diff --git a/modular_citadel/code/modules/arousal/organs/_genitals.dm b/modular_citadel/code/modules/arousal/organs/_genitals.dm index 2222624050..c4c3eaa9f1 100644 --- a/modular_citadel/code/modules/arousal/organs/_genitals.dm +++ b/modular_citadel/code/modules/arousal/organs/_genitals.dm @@ -1,28 +1,28 @@ /obj/item/organ/genital color = "#fcccb3" - w_class = WEIGHT_CLASS_NORMAL - var/shape = "human" - var/sensitivity = AROUSAL_START_VALUE - var/list/genital_flags = list() - var/can_masturbate_with = FALSE - var/masturbation_verb = "masturbate" - var/orgasm_verb = "cumming" //present continous - var/can_climax = FALSE - var/fluid_transfer_factor = 0 //How much would a partner get in them if they climax using this? - var/size = 2 //can vary between num or text, just used in icon_state strings - var/fluid_id = null - var/fluid_max_volume = 50 - var/fluid_efficiency = 1 - var/fluid_rate = 1 - var/fluid_mult = 1 - var/producing = FALSE - var/aroused_state = FALSE //Boolean used in icon_state strings - var/aroused_amount = 50 //This is a num from 0 to 100 for arousal percentage for when to use arousal state icons. + w_class = WEIGHT_CLASS_NORMAL + var/shape = "human" + var/sensitivity = AROUSAL_START_VALUE + var/genital_flags + var/can_masturbate_with = FALSE + var/masturbation_verb = "masturbate" + var/orgasm_verb = "cumming" //present continous + var/can_climax = FALSE + var/fluid_transfer_factor = 0 //How much would a partner get in them if they climax using this? + var/size = 2 //can vary between num or text, just used in icon_state strings + var/fluid_id = null + var/fluid_max_volume = 50 + var/fluid_efficiency = 1 + var/fluid_rate = 1 + var/fluid_mult = 1 + var/producing = FALSE + var/aroused_state = FALSE //Boolean used in icon_state strings + var/aroused_amount = 50 //This is a num from 0 to 100 for arousal percentage for when to use arousal state icons. var/obj/item/organ/genital/linked_organ var/linked_organ_slot //only one of the two organs needs this to be set up. update_link() will handle linking the rest. - var/through_clothes = FALSE - var/internal = FALSE - var/hidden = FALSE + var/through_clothes = FALSE + var/internal = FALSE + var/hidden = FALSE var/layer_index = GENITAL_LAYER_INDEX //Order should be very important. FIRST vagina, THEN testicles, THEN penis, as this affects the order they are rendered in. /obj/item/organ/genital/Initialize() diff --git a/modular_citadel/code/modules/arousal/organs/eggsack.dm b/modular_citadel/code/modules/arousal/organs/eggsack.dm index 3282bad5f9..624b2c24cd 100644 --- a/modular_citadel/code/modules/arousal/organs/eggsack.dm +++ b/modular_citadel/code/modules/arousal/organs/eggsack.dm @@ -5,6 +5,7 @@ icon = 'modular_citadel/icons/obj/genitals/ovipositor.dmi' zone = BODY_ZONE_PRECISE_GROIN slot = ORGAN_SLOT_TESTICLES + genital_flags = GENITAL_BLACKLISTED //unimplemented linked_organ_slot = ORGAN_SLOT_PENIS color = null //don't use the /genital color since it already is colored internal = TRUE diff --git a/modular_citadel/code/modules/arousal/organs/ovipositor.dm b/modular_citadel/code/modules/arousal/organs/ovipositor.dm index 92b608f905..c26424d296 100644 --- a/modular_citadel/code/modules/arousal/organs/ovipositor.dm +++ b/modular_citadel/code/modules/arousal/organs/ovipositor.dm @@ -5,6 +5,7 @@ icon = 'modular_citadel/icons/obj/genitals/ovipositor.dmi' zone = BODY_ZONE_PRECISE_GROIN slot = ORGAN_SLOT_PENIS + genital_flags = GENITAL_BLACKLISTED //unimplemented shape = "knotted" size = 3 layer_index = PENIS_LAYER_INDEX diff --git a/modular_citadel/code/modules/arousal/organs/testicles.dm b/modular_citadel/code/modules/arousal/organs/testicles.dm index de7b6d6f70..c67d6a49a4 100644 --- a/modular_citadel/code/modules/arousal/organs/testicles.dm +++ b/modular_citadel/code/modules/arousal/organs/testicles.dm @@ -7,12 +7,13 @@ slot = ORGAN_SLOT_TESTICLES size = BALLS_SIZE_MIN linked_organ_slot = ORGAN_SLOT_PENIS + genital_flags = MASTURBATE_LINKED_ORGAN var/size_name = "average" shape = "single" var/sack_size = BALLS_SACK_SIZE_DEF fluid_id = "semen" producing = TRUE - can_masturbate_with = MASTURBATE_LINKED_ORGAN + can_masturbate_with = TRUE masturbation_verb = "massage" layer_index = TESTICLES_LAYER_INDEX var/size_linked = FALSE From 376f6e8b4adfe74516942577a3b86de12501cb02 Mon Sep 17 00:00:00 2001 From: Ghommie Date: Tue, 23 Jul 2019 23:54:11 +0200 Subject: [PATCH 03/17] arousal states won't persist after death anymore. --- code/modules/surgery/organs/organ_internal.dm | 4 +++- .../code/modules/arousal/organs/_genitals.dm | 14 ++++++++++---- .../code/modules/arousal/organs/breasts.dm | 1 + .../code/modules/arousal/organs/penis.dm | 16 ++++++++-------- .../code/modules/arousal/organs/testicles.dm | 7 +++++-- .../code/modules/arousal/organs/vagina.dm | 1 + .../icons/obj/genitals/testicles_onmob.dmi | Bin 562 -> 561 bytes 7 files changed, 28 insertions(+), 15 deletions(-) diff --git a/code/modules/surgery/organs/organ_internal.dm b/code/modules/surgery/organs/organ_internal.dm index b16967b6b0..a17b983689 100644 --- a/code/modules/surgery/organs/organ_internal.dm +++ b/code/modules/surgery/organs/organ_internal.dm @@ -16,7 +16,7 @@ /obj/item/organ/proc/Insert(mob/living/carbon/M, special = 0, drop_if_replaced = TRUE) if(!iscarbon(M) || owner == M) - return + return FALSE var/obj/item/organ/replaced = M.getorganslot(slot) if(replaced) @@ -33,6 +33,7 @@ for(var/X in actions) var/datum/action/A = X A.Grant(M) + return TRUE //Special is for instant replacement like autosurgeons /obj/item/organ/proc/Remove(mob/living/carbon/M, special = 0) @@ -46,6 +47,7 @@ for(var/X in actions) var/datum/action/A = X A.Remove(M) + return TRUE /obj/item/organ/proc/on_find(mob/living/finder) diff --git a/modular_citadel/code/modules/arousal/organs/_genitals.dm b/modular_citadel/code/modules/arousal/organs/_genitals.dm index c4c3eaa9f1..292cc5f4ee 100644 --- a/modular_citadel/code/modules/arousal/organs/_genitals.dm +++ b/modular_citadel/code/modules/arousal/organs/_genitals.dm @@ -113,6 +113,8 @@ return /obj/item/organ/genital/proc/update_appearance() + if(!owner || owner.stat == DEAD) + aroused_state = FALSE return /obj/item/organ/genital/on_life() @@ -142,12 +144,16 @@ return FALSE /obj/item/organ/genital/Insert(mob/living/carbon/M, special = 0) - ..() - update() + . = ..() + if(.) + update() + RegisterSignal(owner, COMSIG_MOB_DEATH, .proc/update_appearance) /obj/item/organ/genital/Remove(mob/living/carbon/M, special = 0) - ..() - update(TRUE) + . = ..() + if(.) + update(TRUE) + UnregisterSignal(M, COMSIG_MOB_DEATH) //proc to give a player their genitals and stuff when they log in /mob/living/carbon/human/proc/give_genitals(clean = FALSE)//clean will remove all pre-existing genitals. proc will then give them any genitals that are enabled in their DNA diff --git a/modular_citadel/code/modules/arousal/organs/breasts.dm b/modular_citadel/code/modules/arousal/organs/breasts.dm index f6d5673a53..3fec45006b 100644 --- a/modular_citadel/code/modules/arousal/organs/breasts.dm +++ b/modular_citadel/code/modules/arousal/organs/breasts.dm @@ -17,6 +17,7 @@ fluid_transfer_factor = 0.5 /obj/item/organ/genital/breasts/update_appearance() + . = ..() var/lowershape = lowertext(shape) switch(lowershape) if("pair") diff --git a/modular_citadel/code/modules/arousal/organs/penis.dm b/modular_citadel/code/modules/arousal/organs/penis.dm index 2593460a32..5ab9868895 100644 --- a/modular_citadel/code/modules/arousal/organs/penis.dm +++ b/modular_citadel/code/modules/arousal/organs/penis.dm @@ -16,27 +16,27 @@ var/girth = 0 var/girth_ratio = COCK_GIRTH_RATIO_DEF //0.73; check citadel_defines.dm var/knot_girth_ratio = KNOT_GIRTH_RATIO_DEF - var/list/dickflags = list() var/list/knotted_types = list("knotted", "barbed, knotted") /obj/item/organ/genital/penis/update_size() if(length == cached_length) return + var/new_size switch(length) if(-INFINITY to 5) - size = 1 + new_size = 1 if(5 to 9) - size = 2 + new_size = 2 if(15 to INFINITY) - size = 3//no new sprites for anything larger yet -/* if(9 to 15) - size = 3 - if(15 to INFINITY) - size = 3*/ + new_size = 3 //no new sprites for anything larger yet. girth = (length * girth_ratio) cached_length = length + if(linked_organ) + linked_organ.update_size(new_size - size) + size = new_size /obj/item/organ/genital/penis/update_appearance() + . = ..() var/string var/lowershape = lowertext(shape) desc = "You see [aroused_state ? "an erect" : "a flaccid"] [lowershape] [name]. You estimate it's about [round(length, 0.25)] inch[round(length, 0.25) != 1 ? "es" : ""] long and [round(girth, 0.25)] inch[round(girth, 0.25) != 1 ? "es" : ""] in girth." diff --git a/modular_citadel/code/modules/arousal/organs/testicles.dm b/modular_citadel/code/modules/arousal/organs/testicles.dm index c67d6a49a4..2e1b330095 100644 --- a/modular_citadel/code/modules/arousal/organs/testicles.dm +++ b/modular_citadel/code/modules/arousal/organs/testicles.dm @@ -36,7 +36,9 @@ to_chat(owner, msg) return TRUE -/obj/item/organ/genital/testicles/update_appearance() +/obj/item/organ/genital/testicles/update_size(new_size) + if(new_size) + size = CLAMP(size + new_size, BALLS_SIZE_MIN, BALLS_SIZE_MAX) switch(size) if(BALLS_SIZE_MIN) size_name = "average" @@ -47,8 +49,9 @@ else size_name = "nonexistant" +/obj/item/organ/genital/testicles/update_appearance() + . = ..() desc = "You see an [size_name] pair of testicles." - if(owner) var/string if(owner.dna.species.use_skintones && owner.dna.features["genitals_use_skintone"]) diff --git a/modular_citadel/code/modules/arousal/organs/vagina.dm b/modular_citadel/code/modules/arousal/organs/vagina.dm index af2beb5f79..1b4b088015 100644 --- a/modular_citadel/code/modules/arousal/organs/vagina.dm +++ b/modular_citadel/code/modules/arousal/organs/vagina.dm @@ -20,6 +20,7 @@ var/list/vag_types = list("tentacle", "dentata", "hairy", "spade", "furred") /obj/item/organ/genital/vagina/update_appearance() + . = ..() var/string //Keeping this code here, so making multiple sprites for the different kinds is easier. var/lowershape = lowertext(shape) var/details diff --git a/modular_citadel/icons/obj/genitals/testicles_onmob.dmi b/modular_citadel/icons/obj/genitals/testicles_onmob.dmi index 7d4d2610c5337d0877fd9d741c38998893444576..65eb24268f99929355d5d90054cf8d6a1c2b3a97 100644 GIT binary patch delta 193 zcmV;y06zb+1hE8=Qh%#@R9JLGWpiV4X>fFDZ*Bkpc$}ruK@P$o5CzaRoPxA#O#!zq zY#@q>T!A!pEF`ri4AJY`)&r=po4@$;lF8Jp)kkBQx)}O|h~Y7@J=<*?N?xH)ehyMl z;voz^eFCN~!8}$8Foo*~=rByf2#&kP9n`s^qz@67J(S#HcQuD)=3k1fJ{hb2?}}Vh v6reH}l?5o@VD^F6YW9iqVNnFjd|3Vf*GyZrzWy8X+Uw7#l4CKm2LUSq=#E*> delta 194 zcmV;z06qV)1hNE>Qh%&^R9JLGWpiV4X>fFDZ*Bkpc$}q@K@Ng25JlJRDH>R7D0S;X z(nf0{S7?ZgbP~jbY4rMn96%j*|1aLWWNscQ%-_{sLC+Hq)$ From 6000f96dbc4de60f1088f06a3e7586aff7d307ca Mon Sep 17 00:00:00 2001 From: Ghommie Date: Wed, 24 Jul 2019 02:00:30 +0200 Subject: [PATCH 04/17] deleted some boolean variables in favor of bitflags. --- code/__DEFINES/citadel_defines.dm | 8 ++++- code/_globalvars/bitfields.dm | 10 ++++++ .../code/modules/arousal/arousal.dm | 12 +++---- .../code/modules/arousal/organs/_genitals.dm | 32 +++++++------------ .../code/modules/arousal/organs/breasts.dm | 7 ++-- .../code/modules/arousal/organs/eggsack.dm | 3 +- .../code/modules/arousal/organs/penis.dm | 3 +- .../code/modules/arousal/organs/testicles.dm | 8 ++--- .../code/modules/arousal/organs/vagina.dm | 3 +- .../code/modules/arousal/organs/womb.dm | 3 +- 10 files changed, 43 insertions(+), 46 deletions(-) diff --git a/code/__DEFINES/citadel_defines.dm b/code/__DEFINES/citadel_defines.dm index b366a792e5..035e660176 100644 --- a/code/__DEFINES/citadel_defines.dm +++ b/code/__DEFINES/citadel_defines.dm @@ -27,7 +27,13 @@ //genital flags #define GENITAL_BLACKLISTED (1 << 0) //for genitals that shouldn't be added to GLOB.genitals_list. -#define MASTURBATE_LINKED_ORGAN (1<<1) //used to pass our mission to the linked organ +#define GENITAL_INTERNAL (1<<1) +#define GENITAL_HIDDEN (1<<2) +#define GENITAL_THROUGH_CLOTHES (1<<3) +#define GENITAL_FUID_PRODUCTION (1<<4) +#define CAN_MASTURBATE_WITH (1<<5) +#define MASTURBATE_LINKED_ORGAN (1<<6) //used to pass our mission to the linked organ +#define CAN_CLIMAX_WITH (1<<7) #define COCK_SIZE_MIN 1 #define COCK_SIZE_MAX 20 diff --git a/code/_globalvars/bitfields.dm b/code/_globalvars/bitfields.dm index bb9fc98b8e..3c7af9af7e 100644 --- a/code/_globalvars/bitfields.dm +++ b/code/_globalvars/bitfields.dm @@ -177,4 +177,14 @@ GLOBAL_LIST_INIT(bitfields, list( "CAN_CARRY" = CAN_CARRY, "CAN_RESIST" = CAN_RESIST ), + "genital_flags" = list( + "GENITAL_BLACKLISTED" = GENITAL_BLACKLISTED, + "GENITAL_INTERNAL" = GENITAL_INTERNAL, + "GENITAL_HIDDEN" = GENITAL_HIDDEN, + "GENITAL_THROUGH_CLOTHES" = GENITAL_THROUGH_CLOTHES, + "GENITAL_FUID_PRODUCTION" = GENITAL_FUID_PRODUCTION, + "CAN_MASTURBATE_WITH" = CAN_MASTURBATE_WITH, + "MASTURBATE_LINKED_ORGAN" = MASTURBATE_LINKED_ORGAN, + "CAN_CLIMAX_WITH" = CAN_CLIMAX_WITH + ) )) \ No newline at end of file diff --git a/modular_citadel/code/modules/arousal/arousal.dm b/modular_citadel/code/modules/arousal/arousal.dm index 924c507e7d..f5b27b2c15 100644 --- a/modular_citadel/code/modules/arousal/arousal.dm +++ b/modular_citadel/code/modules/arousal/arousal.dm @@ -182,13 +182,13 @@ to_chat(src, "You aren't aroused enough for that.") /obj/item/organ/genital/proc/climaxable(mob/living/carbon/human/H, silent = FALSE) //returns the fluid source (ergo reagents holder) if found. - if(producing) + if(CHECK_BITFIELD(genital_flags, GENITAL_FUID_PRODUCTION)) . = reagents else if(linked_organ) . = linked_organ.reagents - else if(!silent) - to_chat(H, "Your [name] is unable to produce it's own fluids, it's missing the organs for it.") + if(!. && !silent) + to_chat(H, "Your [name] is unable to produce it's own fluids, it's missing the organs for it.") /mob/living/carbon/human/proc/do_climax(datum/reagents/R, atom/target, obj/item/organ/genital/G, spill = TRUE) if(!G) @@ -273,7 +273,7 @@ var/list/worn_stuff = get_equipped_items() for(var/obj/item/organ/genital/G in internal_organs) - if(G.can_masturbate_with && G.is_exposed(worn_stuff)) //filter out what you can't masturbate with + if(CHECK_BITFIELD(G.genital_flags, CAN_MASTURBATE_WITH) && G.is_exposed(worn_stuff)) //filter out what you can't masturbate with if(CHECK_BITFIELD(G.genital_flags, MASTURBATE_LINKED_ORGAN) && !G.linked_organ) continue genitals_list += G @@ -287,7 +287,7 @@ var/list/worn_stuff = get_equipped_items() for(var/obj/item/organ/genital/G in internal_organs) - if(G.can_climax && G.is_exposed(worn_stuff)) //filter out what you can't masturbate with + if(CHECK_BITFIELD(G.genital_flags, CAN_CLIMAX_WITH) && G.is_exposed(worn_stuff)) //filter out what you can't masturbate with genitals_list += G if(genitals_list.len) var/obj/item/organ/genital/ret_organ = input(src, "with what?", "Climax", null) as null|obj in genitals_list @@ -352,7 +352,7 @@ return if(forced_climax) //Something forced us to cum, this is not a masturbation thing and does not progress to the other checks for(var/obj/item/organ/genital/G in internal_organs) - if(!G.can_climax) //Skip things like wombs and testicles + if(!CHECK_BITFIELD(G.genital_flags, CAN_CLIMAX_WITH)) //Skip things like wombs and testicles continue var/mob/living/partner var/check_target diff --git a/modular_citadel/code/modules/arousal/organs/_genitals.dm b/modular_citadel/code/modules/arousal/organs/_genitals.dm index 292cc5f4ee..38c39d4756 100644 --- a/modular_citadel/code/modules/arousal/organs/_genitals.dm +++ b/modular_citadel/code/modules/arousal/organs/_genitals.dm @@ -3,11 +3,9 @@ w_class = WEIGHT_CLASS_NORMAL var/shape = "human" var/sensitivity = AROUSAL_START_VALUE - var/genital_flags - var/can_masturbate_with = FALSE + var/genital_flags //see citadel_defines.dm var/masturbation_verb = "masturbate" var/orgasm_verb = "cumming" //present continous - var/can_climax = FALSE var/fluid_transfer_factor = 0 //How much would a partner get in them if they climax using this? var/size = 2 //can vary between num or text, just used in icon_state strings var/fluid_id = null @@ -15,21 +13,17 @@ var/fluid_efficiency = 1 var/fluid_rate = 1 var/fluid_mult = 1 - var/producing = FALSE var/aroused_state = FALSE //Boolean used in icon_state strings var/aroused_amount = 50 //This is a num from 0 to 100 for arousal percentage for when to use arousal state icons. var/obj/item/organ/genital/linked_organ var/linked_organ_slot //only one of the two organs needs this to be set up. update_link() will handle linking the rest. - var/through_clothes = FALSE - var/internal = FALSE - var/hidden = FALSE var/layer_index = GENITAL_LAYER_INDEX //Order should be very important. FIRST vagina, THEN testicles, THEN penis, as this affects the order they are rendered in. /obj/item/organ/genital/Initialize() . = ..() if(fluid_id) create_reagents(fluid_max_volume) - if(producing) + if(CHECK_BITFIELD(genital_flags, GENITAL_FUID_PRODUCTION)) reagents.add_reagent(fluid_id, fluid_max_volume) update() @@ -53,9 +47,9 @@ var/list/exposed_genitals = list() //Keeping track of them so we don't have to iterate through every genitalia and see if exposed /obj/item/organ/genital/proc/is_exposed() - if(!owner || hidden || internal) + if(!owner || CHECK_BITFIELD(genital_flags, GENITAL_INTERNAL|GENITAL_HIDDEN)) return FALSE - if(through_clothes) + if(CHECK_BITFIELD(genital_flags, GENITAL_THROUGH_CLOTHES)) return TRUE switch(zone) //update as more genitals are added @@ -69,18 +63,18 @@ /obj/item/organ/genital/proc/toggle_visibility(visibility) switch(visibility) if("Always visible") - through_clothes = TRUE - hidden = FALSE + ENABLE_BITFIELD(genital_flags, GENITAL_THROUGH_CLOTHES) + DISABLE_BITFIELD(genital_flags, GENITAL_HIDDEN) if(!(src in owner.exposed_genitals)) owner.exposed_genitals += src if("Hidden by clothes") - through_clothes = FALSE - hidden = TRUE + DISABLE_BITFIELD(genital_flags, GENITAL_THROUGH_CLOTHES) + DISABLE_BITFIELD(genital_flags, GENITAL_HIDDEN) if(src in owner.exposed_genitals) owner.exposed_genitals -= src if("Always hidden") - through_clothes = FALSE - hidden = TRUE + DISABLE_BITFIELD(genital_flags, GENITAL_THROUGH_CLOTHES) + ENABLE_BITFIELD(genital_flags, GENITAL_HIDDEN) if(src in owner.exposed_genitals) owner.exposed_genitals -= src @@ -97,7 +91,7 @@ for(var/obj/item/organ/O in internal_organs) if(isgenital(O)) var/obj/item/organ/genital/G = O - if(!G.internal) + if(!CHECK_BITFIELD(G.genital_flags, GENITAL_INTERNAL)) genital_list += G if(!genital_list.len) //There is nothing to expose return @@ -121,7 +115,7 @@ if(!reagents || !owner) return reagents.maximum_volume = fluid_max_volume - if(fluid_id && producing) + if(fluid_id && CHECK_BITFIELD(genital_flags, GENITAL_FUID_PRODUCTION)) generate_fluid() /obj/item/organ/genital/proc/generate_fluid() @@ -235,8 +229,6 @@ //start scanning for genitals //var/list/worn_stuff = H.get_equipped_items()//cache this list so it's not built again for(var/obj/item/organ/genital/G in H.internal_organs) - if(G.hidden) - return //we're gunna just hijack this for updates. if(G.is_exposed()) //Checks appropriate clothing slot and if it's through_clothes LAZYADD(genitals_to_add[G.layer_index], G) //Now we added all genitals that aren't internal and should be rendered diff --git a/modular_citadel/code/modules/arousal/organs/breasts.dm b/modular_citadel/code/modules/arousal/organs/breasts.dm index 3fec45006b..6079c9364f 100644 --- a/modular_citadel/code/modules/arousal/organs/breasts.dm +++ b/modular_citadel/code/modules/arousal/organs/breasts.dm @@ -7,13 +7,10 @@ slot = ORGAN_SLOT_BREASTS size = BREASTS_SIZE_DEF fluid_id = "milk" - var/amount = 2 - producing = TRUE shape = "pair" - can_masturbate_with = TRUE + genital_flags = CAN_MASTURBATE_WITH|CAN_CLIMAX_WITH|GENITAL_FUID_PRODUCTION masturbation_verb = "massage" orgasm_verb = "leaking" - can_climax = TRUE fluid_transfer_factor = 0.5 /obj/item/organ/genital/breasts/update_appearance() @@ -32,7 +29,7 @@ desc += " You estimate that they're [uppertext(size)]-cups." else desc += " You wouldn't measure them in cup sizes." - if(producing && aroused_state) + if(CHECK_BITFIELD(genital_flags, GENITAL_FUID_PRODUCTION) && aroused_state) desc += " They're leaking [fluid_id]." var/string if(owner) diff --git a/modular_citadel/code/modules/arousal/organs/eggsack.dm b/modular_citadel/code/modules/arousal/organs/eggsack.dm index 624b2c24cd..ebdefd2371 100644 --- a/modular_citadel/code/modules/arousal/organs/eggsack.dm +++ b/modular_citadel/code/modules/arousal/organs/eggsack.dm @@ -5,10 +5,9 @@ icon = 'modular_citadel/icons/obj/genitals/ovipositor.dmi' zone = BODY_ZONE_PRECISE_GROIN slot = ORGAN_SLOT_TESTICLES - genital_flags = GENITAL_BLACKLISTED //unimplemented + genital_flags = GENITAL_INTERNAL|GENITAL_BLACKLISTED //unimplemented linked_organ_slot = ORGAN_SLOT_PENIS color = null //don't use the /genital color since it already is colored - internal = TRUE var/egg_girth = EGG_GIRTH_DEF var/cum_mult = CUM_RATE_MULT var/cum_rate = CUM_RATE diff --git a/modular_citadel/code/modules/arousal/organs/penis.dm b/modular_citadel/code/modules/arousal/organs/penis.dm index 5ab9868895..0441f78774 100644 --- a/modular_citadel/code/modules/arousal/organs/penis.dm +++ b/modular_citadel/code/modules/arousal/organs/penis.dm @@ -5,9 +5,8 @@ icon = 'modular_citadel/icons/obj/genitals/penis.dmi' zone = BODY_ZONE_PRECISE_GROIN slot = ORGAN_SLOT_PENIS - can_masturbate_with = TRUE masturbation_verb = "stroke" - can_climax = TRUE + genital_flags = CAN_MASTURBATE_WITH|CAN_CLIMAX_WITH fluid_transfer_factor = 0.5 size = 2 //arbitrary value derived from length and girth for sprites. layer_index = PENIS_LAYER_INDEX diff --git a/modular_citadel/code/modules/arousal/organs/testicles.dm b/modular_citadel/code/modules/arousal/organs/testicles.dm index 2e1b330095..e06a10b9fc 100644 --- a/modular_citadel/code/modules/arousal/organs/testicles.dm +++ b/modular_citadel/code/modules/arousal/organs/testicles.dm @@ -7,13 +7,11 @@ slot = ORGAN_SLOT_TESTICLES size = BALLS_SIZE_MIN linked_organ_slot = ORGAN_SLOT_PENIS - genital_flags = MASTURBATE_LINKED_ORGAN + genital_flags = CAN_MASTURBATE_WITH|MASTURBATE_LINKED_ORGAN|GENITAL_FUID_PRODUCTION var/size_name = "average" shape = "single" var/sack_size = BALLS_SACK_SIZE_DEF fluid_id = "semen" - producing = TRUE - can_masturbate_with = TRUE masturbation_verb = "massage" layer_index = TESTICLES_LAYER_INDEX var/size_linked = FALSE @@ -77,9 +75,7 @@ sack_size = D.features["balls_sack_size"] shape = D.features["balls_shape"] if(D.features["balls_shape"] == "Hidden") - internal = TRUE - else - internal = FALSE + ENABLE_BITFIELD(genital_flags, GENITAL_INTERNAL) fluid_id = D.features["balls_fluid"] fluid_rate = D.features["balls_cum_rate"] fluid_mult = D.features["balls_cum_mult"] diff --git a/modular_citadel/code/modules/arousal/organs/vagina.dm b/modular_citadel/code/modules/arousal/organs/vagina.dm index 1b4b088015..0df954fd79 100644 --- a/modular_citadel/code/modules/arousal/organs/vagina.dm +++ b/modular_citadel/code/modules/arousal/organs/vagina.dm @@ -6,9 +6,8 @@ zone = BODY_ZONE_PRECISE_GROIN slot = "vagina" size = 1 //There is only 1 size right now - can_masturbate_with = TRUE + genital_flags = CAN_MASTURBATE_WITH|CAN_CLIMAX_WITH masturbation_verb = "finger" - can_climax = TRUE fluid_transfer_factor = 0.1 //Yes, some amount is exposed to you, go get your AIDS layer_index = VAGINA_LAYER_INDEX var/cap_length = 8//D E P T H (cap = capacity) diff --git a/modular_citadel/code/modules/arousal/organs/womb.dm b/modular_citadel/code/modules/arousal/organs/womb.dm index d99206d0f1..3c4ce225f4 100644 --- a/modular_citadel/code/modules/arousal/organs/womb.dm +++ b/modular_citadel/code/modules/arousal/organs/womb.dm @@ -5,7 +5,6 @@ icon_state = "womb" zone = BODY_ZONE_PRECISE_GROIN slot = ORGAN_SLOT_WOMB - internal = TRUE + genital_flags = GENITAL_INTERNAL|GENITAL_FUID_PRODUCTION fluid_id = "femcum" - producing = TRUE linked_organ_slot = ORGAN_SLOT_VAGINA \ No newline at end of file From 6623dd48968b19858155d28799cce5a39c402900 Mon Sep 17 00:00:00 2001 From: Ghommie Date: Wed, 24 Jul 2019 02:03:52 +0200 Subject: [PATCH 05/17] As if they'd care anyway. --- code/datums/traits/neutral.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/datums/traits/neutral.dm b/code/datums/traits/neutral.dm index 156ee00d75..3c7894f250 100644 --- a/code/datums/traits/neutral.dm +++ b/code/datums/traits/neutral.dm @@ -122,7 +122,7 @@ /datum/quirk/exhibitionism name = "Exhibitionism" - desc = "You don't mind showing off your bare body to strangers, in fact you find it quite satistying. Not the best excuse to break Space Law anyway." //as if they'd care anyway. + desc = "You don't mind showing off your bare body to strangers, in fact you find it quite satistying." value = 0 medical_record_text = "Patient has been diagnosed with exhibitionistic disorder." mob_trait = TRAIT_EXHIBITIONIST From 30292c385b77ad5d2e52feb100a7ea89106ff6cb Mon Sep 17 00:00:00 2001 From: Ghommie Date: Wed, 24 Jul 2019 02:07:59 +0200 Subject: [PATCH 06/17] moving files. --- .../code/modules/arousal/{organs/_genitals.dm => genitals.dm} | 0 .../arousal/{organs => }/genitals_sprite_accessories.dm | 0 tgstation.dme | 4 ++-- 3 files changed, 2 insertions(+), 2 deletions(-) rename modular_citadel/code/modules/arousal/{organs/_genitals.dm => genitals.dm} (100%) rename modular_citadel/code/modules/arousal/{organs => }/genitals_sprite_accessories.dm (100%) diff --git a/modular_citadel/code/modules/arousal/organs/_genitals.dm b/modular_citadel/code/modules/arousal/genitals.dm similarity index 100% rename from modular_citadel/code/modules/arousal/organs/_genitals.dm rename to modular_citadel/code/modules/arousal/genitals.dm diff --git a/modular_citadel/code/modules/arousal/organs/genitals_sprite_accessories.dm b/modular_citadel/code/modules/arousal/genitals_sprite_accessories.dm similarity index 100% rename from modular_citadel/code/modules/arousal/organs/genitals_sprite_accessories.dm rename to modular_citadel/code/modules/arousal/genitals_sprite_accessories.dm diff --git a/tgstation.dme b/tgstation.dme index 7c9fa1e899..c872760203 100755 --- a/tgstation.dme +++ b/tgstation.dme @@ -2911,10 +2911,10 @@ #include "modular_citadel\code\modules\admin\secrets.dm" #include "modular_citadel\code\modules\admin\topic.dm" #include "modular_citadel\code\modules\arousal\arousal.dm" -#include "modular_citadel\code\modules\arousal\organs\_genitals.dm" +#include "modular_citadel\code\modules\arousal\genitals.dm" +#include "modular_citadel\code\modules\arousal\genitals_sprite_accessories.dm" #include "modular_citadel\code\modules\arousal\organs\breasts.dm" #include "modular_citadel\code\modules\arousal\organs\eggsack.dm" -#include "modular_citadel\code\modules\arousal\organs\genitals_sprite_accessories.dm" #include "modular_citadel\code\modules\arousal\organs\ovipositor.dm" #include "modular_citadel\code\modules\arousal\organs\penis.dm" #include "modular_citadel\code\modules\arousal\organs\testicles.dm" From 56f2a8f8846093f681d6d744230b31ca5aafdf11 Mon Sep 17 00:00:00 2001 From: Ghommie Date: Thu, 25 Jul 2019 04:29:21 +0200 Subject: [PATCH 07/17] Fixes oversized tennis balls, testing and fixing. --- code/__DEFINES/citadel_defines.dm | 16 +- code/__HELPERS/_cit_helpers.dm | 10 +- .../code/modules/arousal/arousal.dm | 229 ++++++++++-------- .../code/modules/arousal/genitals.dm | 33 +-- .../code/modules/arousal/organs/penis.dm | 6 +- .../code/modules/arousal/organs/testicles.dm | 13 +- 6 files changed, 162 insertions(+), 145 deletions(-) diff --git a/code/__DEFINES/citadel_defines.dm b/code/__DEFINES/citadel_defines.dm index 035e660176..04e9c52527 100644 --- a/code/__DEFINES/citadel_defines.dm +++ b/code/__DEFINES/citadel_defines.dm @@ -26,14 +26,14 @@ #define GENITAL_LAYER_INDEX_LENGTH 4 //keep it updated with each new index added, thanks. //genital flags -#define GENITAL_BLACKLISTED (1 << 0) //for genitals that shouldn't be added to GLOB.genitals_list. -#define GENITAL_INTERNAL (1<<1) -#define GENITAL_HIDDEN (1<<2) -#define GENITAL_THROUGH_CLOTHES (1<<3) -#define GENITAL_FUID_PRODUCTION (1<<4) -#define CAN_MASTURBATE_WITH (1<<5) -#define MASTURBATE_LINKED_ORGAN (1<<6) //used to pass our mission to the linked organ -#define CAN_CLIMAX_WITH (1<<7) +#define GENITAL_BLACKLISTED (1<<0) //for genitals that shouldn't be added to GLOB.genitals_list. +#define GENITAL_INTERNAL (1<<1) +#define GENITAL_HIDDEN (1<<2) +#define GENITAL_THROUGH_CLOTHES (1<<3) +#define GENITAL_FUID_PRODUCTION (1<<4) +#define CAN_MASTURBATE_WITH (1<<5) +#define MASTURBATE_LINKED_ORGAN (1<<6) //used to pass our mission to the linked organ +#define CAN_CLIMAX_WITH (1<<7) #define COCK_SIZE_MIN 1 #define COCK_SIZE_MAX 20 diff --git a/code/__HELPERS/_cit_helpers.dm b/code/__HELPERS/_cit_helpers.dm index d75dd31b46..1c7b4aeb99 100644 --- a/code/__HELPERS/_cit_helpers.dm +++ b/code/__HELPERS/_cit_helpers.dm @@ -158,18 +158,20 @@ GLOBAL_VAR_INIT(miscreants_allowed, FALSE) return TRUE return FALSE -/mob/living/carbon/proc/is_groin_exposed(var/list/L) +/mob/living/carbon/proc/is_groin_exposed(list/L) if(!L) L = get_equipped_items() - for(var/obj/item/I in L) + for(var/A in L) + var/obj/item/I = A if(I.body_parts_covered & GROIN) return FALSE return TRUE -/mob/living/carbon/proc/is_chest_exposed(var/list/L) +/mob/living/carbon/proc/is_chest_exposed(list/L) if(!L) L = get_equipped_items() - for(var/obj/item/I in L) + for(var/A in L) + var/obj/item/I = A if(I.body_parts_covered & CHEST) return FALSE return TRUE diff --git a/modular_citadel/code/modules/arousal/arousal.dm b/modular_citadel/code/modules/arousal/arousal.dm index f5b27b2c15..83a5622f49 100644 --- a/modular_citadel/code/modules/arousal/arousal.dm +++ b/modular_citadel/code/modules/arousal/arousal.dm @@ -139,8 +139,6 @@ if(!canbearoused) hud_used.arousal.icon_state = "" return FALSE - if(stat == DEAD) - hud_used.arousal.icon_state = "arousal0" else var/value = FLOOR(getPercentAroused(), 10) hud_used.arousal.icon_state = "arousal[value]" @@ -194,6 +192,7 @@ if(!G) return SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "orgasm", /datum/mood_event/orgasm) + setArousalLoss(min_arousal) if(!target || !R) return var/turfing = isturf(target) @@ -217,8 +216,8 @@ "You start to [G.masturbation_verb] your [G.name].") if(!do_after(src, mb_time, target = src) || !G.climaxable(src, TRUE)) return - visible_message("[src] orgasms, [PP.orgasm_verb][isturf(loc) ? " onto [loc]" : ""]!", \ - "You orgasm, [PP.orgasm_verb][isturf(loc) ? " onto [loc]" : ""].") + visible_message("[src] orgasms, [PP.orgasm_verb][isturf(loc) ? " onto [loc]" : ""] with [p_their()] [PP.name]!", \ + "You orgasm, [PP.orgasm_verb][isturf(loc) ? " onto [loc]" : ""] with your [PP.name].") do_climax(fluid_source, loc, G) /mob/living/carbon/human/proc/mob_climax_outside(obj/item/organ/genital/G, mb_time = 30) //This is used for forced orgasms and other hands-free climaxes @@ -268,33 +267,35 @@ "You used your [G.name] to fill [container].") do_climax(fluid_source, container, G, FALSE) -/mob/living/carbon/human/proc/pick_masturbate_genitals() - var/list/genitals_list = list() +/mob/living/carbon/human/proc/pick_masturbate_genitals(silent = FALSE) + var/list/genitals_list var/list/worn_stuff = get_equipped_items() for(var/obj/item/organ/genital/G in internal_organs) if(CHECK_BITFIELD(G.genital_flags, CAN_MASTURBATE_WITH) && G.is_exposed(worn_stuff)) //filter out what you can't masturbate with if(CHECK_BITFIELD(G.genital_flags, MASTURBATE_LINKED_ORGAN) && !G.linked_organ) continue - genitals_list += G - if(genitals_list.len) - var/obj/item/organ/genital/ret_organ = input(src, "with what?", "Masturbate", null) as null|obj in genitals_list + LAZYADD(genitals_list, G) + if(LAZYLEN(genitals_list)) + var/obj/item/organ/genital/ret_organ = input(src, "with what?", "Masturbate", null) as null|obj in genitals_list return ret_organ + else if(!silent) + to_chat(src, "You cannot masturbate without available genitals.") - -/mob/living/carbon/human/proc/pick_climax_genitals() - var/list/genitals_list = list() +/mob/living/carbon/human/proc/pick_climax_genitals(silent = FALSE) + var/list/genitals_list var/list/worn_stuff = get_equipped_items() for(var/obj/item/organ/genital/G in internal_organs) if(CHECK_BITFIELD(G.genital_flags, CAN_CLIMAX_WITH) && G.is_exposed(worn_stuff)) //filter out what you can't masturbate with - genitals_list += G - if(genitals_list.len) - var/obj/item/organ/genital/ret_organ = input(src, "with what?", "Climax", null) as null|obj in genitals_list + LAZYADD(genitals_list, G) + if(LAZYLEN(genitals_list)) + var/obj/item/organ/genital/ret_organ = input(src, "with what?", "Climax", null) as null|obj in genitals_list return ret_organ + else if(!silent) + to_chat(src, "You cannot climax without available genitals.") - -/mob/living/carbon/human/proc/pick_partner() +/mob/living/carbon/human/proc/pick_partner(silent = FALSE) var/list/partners = list() if(pulling) partners += pulling @@ -308,30 +309,42 @@ partners -= C //NOW the list should only contain correct partners if(!partners.len) + if(!silent) + to_chat(src, "You cannot do this alone.") return //No one left. var/mob/living/target = input(src, "With whom?", "Sexual partner", null) as null|anything in partners //pick one, default to null if(target && in_range(src, target)) return target -/mob/living/carbon/human/proc/pick_climax_container() +/mob/living/carbon/human/proc/pick_climax_container(silent = FALSE) var/list/containers_list = list() - for(var/obj/item/reagent_containers/container in held_items) - if(container.is_open_container() || istype(container, /obj/item/reagent_containers/food/snacks)) - containers_list += container + for(var/obj/item/reagent_containers/C in held_items) + if(C.is_open_container() || istype(C, /obj/item/reagent_containers/food/snacks)) + containers_list += C + for(var/obj/item/reagent_containers/C in range(1, src)) + if((C.is_open_container() || istype(C, /obj/item/reagent_containers/food/snacks)) && CanReach(C)) + containers_list += C if(containers_list.len) var/obj/item/reagent_containers/SC = input(src, "Into or onto what?(Cancel for nowhere)", null) as null|obj in containers_list - if(SC && in_range(src, SC)) + if(SC && CanReach(SC)) return SC - return null //If nothing correct, give null. + else if(!silent) + to_chat(src, "You cannot do this without an appropriate container.") -/mob/living/carbon/human/proc/available_rosie_palms(silent = FALSE) +/mob/living/carbon/human/proc/available_rosie_palms(silent = FALSE, list/whitelist_typepaths = list(/obj/item/dildo)) if(restrained(TRUE)) //TRUE ignores grabs if(!silent) to_chat(src, "You can't do that while restrained!") return FALSE if(!get_num_arms() || !get_empty_held_indexes()) + if(whitelist_typepaths) + if(!islist(whitelist_typepaths)) + whitelist_typepaths = list(whitelist_typepaths) + for(var/path in whitelist_typepaths) + if(is_holding_item_of_type(path)) + return TRUE if(!silent) to_chat(src, "You need at least one free arm.") return FALSE @@ -343,93 +356,97 @@ if(!forced_climax) //Don't spam the message to the victim if forced to come too fast to_chat(src, "You need to wait [DisplayTimeText((mb_cd_timer - world.time), TRUE)] before you can do that again!") return - mb_cd_timer = world.time + mb_cd_length - if(canbearoused && has_dna()) - if(stat == DEAD) - if(!forced_climax) - to_chat(src, "You can't do that while dead!") - return - if(forced_climax) //Something forced us to cum, this is not a masturbation thing and does not progress to the other checks - for(var/obj/item/organ/genital/G in internal_organs) - if(!CHECK_BITFIELD(G.genital_flags, CAN_CLIMAX_WITH)) //Skip things like wombs and testicles - continue - var/mob/living/partner - var/check_target - var/list/worn_stuff = get_equipped_items() + if(!canbearoused || !has_dna()) + return + if(stat == DEAD) + if(!forced_climax) + to_chat(src, "You can't do that while dead!") + return + if(forced_climax) //Something forced us to cum, this is not a masturbation thing and does not progress to the other checks + for(var/obj/item/organ/genital/G in internal_organs) + if(!CHECK_BITFIELD(G.genital_flags, CAN_CLIMAX_WITH)) //Skip things like wombs and testicles + continue + var/mob/living/partner + var/check_target + var/list/worn_stuff = get_equipped_items() - if(G.is_exposed(worn_stuff)) - if(pulling) //Are we pulling someone? Priority target, we can't be making option menus for this, has to be quick - if(isliving(pulling)) //Don't fuck objects - check_target = pulling - if(pulledby && !check_target) //prioritise pulled over pulledby - if(isliving(pulledby)) - check_target = pulledby - //Now we should have a partner, or else we have to come alone - if(check_target) - if(iscarbon(check_target)) //carbons can have clothes - var/mob/living/carbon/C = check_target - if(C.exposed_genitals.len || C.is_groin_exposed() || C.is_chest_exposed()) //Are they naked enough? - partner = C - else //A cat is fine too - partner = check_target - if(partner) //Did they pass the clothing checks? - mob_climax_partner(G, partner, mb_time = 0) //Instant climax due to forced - continue //You've climaxed once with this organ, continue on - //not exposed OR if no partner was found while exposed, climax alone - mob_climax_outside(G, mb_time = 0) //removed climax timer for sudden, forced orgasms - //Now all genitals that could climax, have. - //Since this was a forced climax, we do not need to continue with the other stuff - return - //If we get here, then this is not a forced climax and we gotta check a few things. + if(G.is_exposed(worn_stuff)) + if(pulling) //Are we pulling someone? Priority target, we can't be making option menus for this, has to be quick + if(isliving(pulling)) //Don't fuck objects + check_target = pulling + if(pulledby && !check_target) //prioritise pulled over pulledby + if(isliving(pulledby)) + check_target = pulledby + //Now we should have a partner, or else we have to come alone + if(check_target) + if(iscarbon(check_target)) //carbons can have clothes + var/mob/living/carbon/C = check_target + if(C.exposed_genitals.len || C.is_groin_exposed() || C.is_chest_exposed()) //Are they naked enough? + partner = C + else //A cat is fine too + partner = check_target + if(partner) //Did they pass the clothing checks? + mob_climax_partner(G, partner, mb_time = 0) //Instant climax due to forced + continue //You've climaxed once with this organ, continue on + //not exposed OR if no partner was found while exposed, climax alone + mob_climax_outside(G, mb_time = 0) //removed climax timer for sudden, forced orgasms + //Now all genitals that could climax, have. + //Since this was a forced climax, we do not need to continue with the other stuff + mb_cd_timer = world.time + mb_cd_length + return + //If we get here, then this is not a forced climax and we gotta check a few things. - if(stat == UNCONSCIOUS) //No sleep-masturbation, you're unconscious. - to_chat(src, "You must be conscious to do that!") - return - if(getArousalLoss() < 33) //flat number instead of percentage - to_chat(src, "You aren't aroused enough for that!") - return + if(stat == UNCONSCIOUS) //No sleep-masturbation, you're unconscious. + to_chat(src, "You must be conscious to do that!") + return + if(getArousalLoss() < 33) //flat number instead of percentage + to_chat(src, "You aren't aroused enough for that!") + return - //Ok, now we check what they want to do. - var/choice = input(src, "Select sexual activity", "Sexual activity:") as null|anything in list("Masturbate", "Climax alone", "Climax with partner", "Fill container") + //Ok, now we check what they want to do. + var/choice = input(src, "Select sexual activity", "Sexual activity:") as null|anything in list("Masturbate", "Climax alone", "Climax with partner", "Fill container") + if(!choice) + return - switch(choice) - if("Masturbate") - if(!available_rosie_palms()) - return - //We got hands, let's pick an organ - var/obj/item/organ/genital/picked_organ = pick_masturbate_genitals() - if(picked_organ && available_rosie_palms(TRUE)) - mob_masturbate(picked_organ) - return + switch(choice) + if("Masturbate") + if(!available_rosie_palms()) + return + //We got hands, let's pick an organ + var/obj/item/organ/genital/picked_organ = pick_masturbate_genitals() + if(picked_organ && available_rosie_palms(TRUE)) + mob_masturbate(picked_organ) + return - if("Climax alone") - if(!available_rosie_palms()) - return - var/obj/item/organ/genital/picked_organ = pick_climax_genitals() - if(picked_organ && available_rosie_palms(TRUE)) - mob_climax_outside(picked_organ) + if("Climax alone") + if(!available_rosie_palms()) + return + var/obj/item/organ/genital/picked_organ = pick_climax_genitals() + if(picked_organ && available_rosie_palms(TRUE)) + mob_climax_outside(picked_organ) - if("Climax with partner") - //We need no hands, we can be restrained and so on, so let's pick an organ - var/obj/item/organ/genital/picked_organ = pick_climax_genitals() - if(picked_organ) - var/mob/living/partner = pick_partner() //Get someone - if(partner) - var/spillage = input(src, "Would your fluids spill outside?", "Choose overflowing option", "Yes") as null|anything in list("Yes", "No") - if(spillage && in_range(src, partner)) - mob_climax_partner(picked_organ, partner, spillage == "Yes" ? TRUE : FALSE) + if("Climax with partner") + //We need no hands, we can be restrained and so on, so let's pick an organ + var/obj/item/organ/genital/picked_organ = pick_climax_genitals() + if(picked_organ) + var/mob/living/partner = pick_partner() //Get someone + if(partner) + var/spillage = input(src, "Would your fluids spill outside?", "Choose overflowing option", "Yes") as null|anything in list("Yes", "No") + if(spillage && in_range(src, partner)) + mob_climax_partner(picked_organ, partner, spillage == "Yes" ? TRUE : FALSE) - if("Fill container") - //We'll need hands and no restraints. - if(!available_rosie_palms()) - return - //We got hands, let's pick an organ - var/obj/item/organ/genital/picked_organ - picked_organ = pick_climax_genitals() //Gotta be climaxable, not just masturbation, to fill with fluids. - if(picked_organ) - //Good, got an organ, time to pick a container - var/obj/item/reagent_containers/fluid_container = pick_climax_container() - if(fluid_container && available_rosie_palms(TRUE)) - mob_fill_container(picked_organ, fluid_container) - return \ No newline at end of file + if("Fill container") + //We'll need hands and no restraints. + if(!available_rosie_palms(FALSE, /obj/item/reagent_containers)) + return + //We got hands, let's pick an organ + var/obj/item/organ/genital/picked_organ + picked_organ = pick_climax_genitals() //Gotta be climaxable, not just masturbation, to fill with fluids. + if(picked_organ) + //Good, got an organ, time to pick a container + var/obj/item/reagent_containers/fluid_container = pick_climax_container() + if(fluid_container && available_rosie_palms(TRUE, /obj/item/reagent_containers)) + mob_fill_container(picked_organ, fluid_container) + + mb_cd_timer = world.time + mb_cd_length \ No newline at end of file diff --git a/modular_citadel/code/modules/arousal/genitals.dm b/modular_citadel/code/modules/arousal/genitals.dm index 38c39d4756..3545c96a50 100644 --- a/modular_citadel/code/modules/arousal/genitals.dm +++ b/modular_citadel/code/modules/arousal/genitals.dm @@ -47,7 +47,7 @@ var/list/exposed_genitals = list() //Keeping track of them so we don't have to iterate through every genitalia and see if exposed /obj/item/organ/genital/proc/is_exposed() - if(!owner || CHECK_BITFIELD(genital_flags, GENITAL_INTERNAL|GENITAL_HIDDEN)) + if(!owner || CHECK_BITFIELD(genital_flags, GENITAL_INTERNAL) || CHECK_BITFIELD(genital_flags, GENITAL_HIDDEN)) return FALSE if(CHECK_BITFIELD(genital_flags, GENITAL_THROUGH_CLOTHES)) return TRUE @@ -58,8 +58,6 @@ if(BODY_ZONE_PRECISE_GROIN) return owner.is_groin_exposed() - return FALSE - /obj/item/organ/genital/proc/toggle_visibility(visibility) switch(visibility) if("Always visible") @@ -119,7 +117,7 @@ generate_fluid() /obj/item/organ/genital/proc/generate_fluid() - if(owner.stat != DEAD && reagents.total_volume < reagents.maximum_volume) + if(reagents.total_volume < reagents.maximum_volume) reagents.isolate_reagent(fluid_id)//remove old reagents if it changed and just clean up generally reagents.add_reagent(fluid_id, (fluid_mult * fluid_rate))//generate the cum return TRUE @@ -137,13 +135,13 @@ linked_organ = null return FALSE -/obj/item/organ/genital/Insert(mob/living/carbon/M, special = 0) +/obj/item/organ/genital/Insert(mob/living/carbon/M, special = FALSE, drop_if_replaced = TRUE) . = ..() if(.) update() - RegisterSignal(owner, COMSIG_MOB_DEATH, .proc/update_appearance) + RegisterSignal(owner, COMSIG_MOB_DEATH, .proc/update) -/obj/item/organ/genital/Remove(mob/living/carbon/M, special = 0) +/obj/item/organ/genital/Remove(mob/living/carbon/M, special = FALSE, drop_if_replaced = TRUE) . = ..() if(.) update(TRUE) @@ -176,12 +174,11 @@ /mob/living/carbon/human/proc/give_genital(obj/item/organ/genital/G) if(!dna || (NOGENITALS in dna.species.species_traits) || getorganslot(initial(G.slot))) return FALSE - G = new - if(istype(G, /obj/item/organ/genital)) //badminnery-proofing. - G.get_features(src) + G = new G + G.get_features(src) G.Insert(src) -/obj/item/organ/genital/proc/get_features(datum/dna/D) +/obj/item/organ/genital/proc/get_features(mob/living/carbon/human/H) return /datum/species/proc/genitals_layertext(layer) @@ -217,7 +214,6 @@ if(!LAZYLEN(H.internal_organs) || (NOGENITALS in species_traits) || HAS_TRAIT(H, TRAIT_HUSK)) return - var/list/genitals_to_add[GENITAL_LAYER_INDEX_LENGTH] var/list/relevant_layers = list(GENITALS_BEHIND_LAYER, GENITALS_ADJ_LAYER, GENITALS_FRONT_LAYER) var/list/standing = list() var/size @@ -228,15 +224,22 @@ //start scanning for genitals //var/list/worn_stuff = H.get_equipped_items()//cache this list so it's not built again + + var/list/gen_index[GENITAL_LAYER_INDEX_LENGTH] + var/list/genitals_to_add for(var/obj/item/organ/genital/G in H.internal_organs) if(G.is_exposed()) //Checks appropriate clothing slot and if it's through_clothes - LAZYADD(genitals_to_add[G.layer_index], G) + LAZYADD(gen_index[G.layer_index], G) + for(var/L in gen_index) + if(L) //skip nulls + LAZYADD(genitals_to_add, L) //Now we added all genitals that aren't internal and should be rendered //start applying overlays for(var/layer in relevant_layers) - var/layertext = flatten_list(genitals_layertext(layer)) - for(var/obj/item/organ/genital/G in genitals_to_add) + var/layertext = genitals_layertext(layer) + for(var/A in genitals_to_add) + var/obj/item/organ/genital/G = A var/datum/sprite_accessory/S size = G.size aroused_state = G.aroused_state diff --git a/modular_citadel/code/modules/arousal/organs/penis.dm b/modular_citadel/code/modules/arousal/organs/penis.dm index 0441f78774..b387fa96f5 100644 --- a/modular_citadel/code/modules/arousal/organs/penis.dm +++ b/modular_citadel/code/modules/arousal/organs/penis.dm @@ -22,11 +22,11 @@ return var/new_size switch(length) - if(-INFINITY to 5) + if(-INFINITY to 6) new_size = 1 - if(5 to 9) + if(6 to 12) new_size = 2 - if(15 to INFINITY) + if(12 to INFINITY) new_size = 3 //no new sprites for anything larger yet. girth = (length * girth_ratio) cached_length = length diff --git a/modular_citadel/code/modules/arousal/organs/testicles.dm b/modular_citadel/code/modules/arousal/organs/testicles.dm index e06a10b9fc..06f40b5b51 100644 --- a/modular_citadel/code/modules/arousal/organs/testicles.dm +++ b/modular_citadel/code/modules/arousal/organs/testicles.dm @@ -9,7 +9,7 @@ linked_organ_slot = ORGAN_SLOT_PENIS genital_flags = CAN_MASTURBATE_WITH|MASTURBATE_LINKED_ORGAN|GENITAL_FUID_PRODUCTION var/size_name = "average" - shape = "single" + shape = "Single" var/sack_size = BALLS_SACK_SIZE_DEF fluid_id = "semen" masturbation_verb = "massage" @@ -20,20 +20,16 @@ if(!linked_organ && !update_link()) return FALSE . = ..() - if(.) - send_full_message() + if(. && reagents.holder_full()) + to_chat(owner, "Your balls finally feel full, again.") /obj/item/organ/genital/testicles/update_link(removing = FALSE) . = ..() if(. && !size_linked) size = linked_organ.size + update() size_linked = TRUE -/obj/item/organ/genital/testicles/proc/send_full_message(msg = "Your balls finally feel full, again.") - if(owner && istext(msg)) - to_chat(owner, msg) - return TRUE - /obj/item/organ/genital/testicles/update_size(new_size) if(new_size) size = CLAMP(size + new_size, BALLS_SIZE_MIN, BALLS_SIZE_MAX) @@ -71,7 +67,6 @@ color = "#[skintone2hex(H.skin_tone)]" else color = "#[D.features["balls_color"]]" - size = D.features["balls_size"] sack_size = D.features["balls_sack_size"] shape = D.features["balls_shape"] if(D.features["balls_shape"] == "Hidden") From 44a28066a16607219a1caa478509fe77b06f3e47 Mon Sep 17 00:00:00 2001 From: Ghommie Date: Thu, 25 Jul 2019 04:44:34 +0200 Subject: [PATCH 08/17] coding exasperation. --- modular_citadel/code/modules/arousal/arousal.dm | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/modular_citadel/code/modules/arousal/arousal.dm b/modular_citadel/code/modules/arousal/arousal.dm index 83a5622f49..6c9da17289 100644 --- a/modular_citadel/code/modules/arousal/arousal.dm +++ b/modular_citadel/code/modules/arousal/arousal.dm @@ -69,10 +69,8 @@ amt_nude++ if(amt_nude) var/watchers = 0 - for(var/mob/living/L in view(world.view, src)) - if(!istype(L)) - continue - if(L.client && !L.stat && !L.eye_blind && (locate(src) in viewers(world.view, L))) + for(var/mob/living/L in view(src)) + if(L.client && !L.stat && !L.eye_blind && (src in view(L))) watchers++ if(watchers) our_loss += (amt_nude * watchers) + S.arousal_gain_rate From 36ffd3d6a8d69d3ac75145080d0ada2f06f53874 Mon Sep 17 00:00:00 2001 From: Ghommie <42542238+Ghommie@users.noreply.github.com> Date: Sun, 1 Sep 2019 03:35:36 +0200 Subject: [PATCH 09/17] More lines. --- code/__DEFINES/misc.dm | 27 ++++---- .../code/modules/arousal/genitals.dm | 40 ++++++------ .../chemistry/reagents/enlargement.dm | 61 +++++++++---------- 3 files changed, 62 insertions(+), 66 deletions(-) diff --git a/code/__DEFINES/misc.dm b/code/__DEFINES/misc.dm index c71780e7e9..8a0db9ad9c 100644 --- a/code/__DEFINES/misc.dm +++ b/code/__DEFINES/misc.dm @@ -51,24 +51,25 @@ Will print: "/mob/living/carbon/human/death" (you can optionally embed it in a s //Human Overlays Indexes///////// //LOTS OF CIT CHANGES HERE. BE CAREFUL WHEN UPSTREAM ADDS MORE LAYERS -#define MUTATIONS_LAYER 31 //mutations. Tk headglows, cold resistance glow, etc -#define GENITALS_BEHIND_LAYER 30 //Some genitalia needs to be behind everything, such as with taurs (Taurs use body_behind_layer -#define BODY_BEHIND_LAYER 29 //certain mutantrace features (tail when looking south) that must appear behind the body parts -#define BODYPARTS_LAYER 28 //Initially "AUGMENTS", this was repurposed to be a catch-all bodyparts flag -#define MARKING_LAYER 27 //Matrixed body markings because clashing with snouts? -#define BODY_ADJ_LAYER 26 //certain mutantrace features (snout, body markings) that must appear above the body parts -#define GENITALS_FRONT_LAYER 25 //Draws some genitalia above clothes and the TAUR body if need be. -#define BODY_LAYER 24 //underwear, undershirts, socks, eyes, lips(makeup) -#define FRONT_MUTATIONS_LAYER 23 //mutations that should appear above body, body_adj and bodyparts layer (e.g. laser eyes) -#define DAMAGE_LAYER 22 //damage indicators (cuts and burns) -#define UNIFORM_LAYER 21 -#define ID_LAYER 20 +#define MUTATIONS_LAYER 32 //mutations. Tk headglows, cold resistance glow, etc +#define GENITALS_BEHIND_LAYER 31 //Some genitalia needs to be behind everything, such as with taurs (Taurs use body_behind_layer +#define BODY_BEHIND_LAYER 30 //certain mutantrace features (tail when looking south) that must appear behind the body parts +#define BODYPARTS_LAYER 29 //Initially "AUGMENTS", this was repurposed to be a catch-all bodyparts flag +#define MARKING_LAYER 28 //Matrixed body markings because clashing with snouts? +#define BODY_ADJ_LAYER 27 //certain mutantrace features (snout, body markings) that must appear above the body parts +#define GENITALS_FRONT_LAYER 26 //Draws some genitalia above clothes and the TAUR body if need be. +#define BODY_LAYER 25 //underwear, undershirts, socks, eyes, lips(makeup) +#define FRONT_MUTATIONS_LAYER 24 //mutations that should appear above body, body_adj and bodyparts layer (e.g. laser eyes) +#define DAMAGE_LAYER 23 //damage indicators (cuts and burns) +#define UNIFORM_LAYER 22 +#define ID_LAYER 21 #define HANDS_PART_LAYER 20 #define SHOES_LAYER 19 #define GLOVES_LAYER 18 #define EARS_LAYER 17 #define BODY_TAUR_LAYER 16 #define SUIT_LAYER 15 +#define GENITALS_EXPOSED_LAYER 14 #define GLASSES_LAYER 13 #define BELT_LAYER 12 //Possible make this an overlay of somethign required to wear a belt? #define SUIT_STORE_LAYER 11 @@ -82,7 +83,7 @@ Will print: "/mob/living/carbon/human/death" (you can optionally embed it in a s #define HANDS_LAYER 3 #define BODY_FRONT_LAYER 2 #define FIRE_LAYER 1 //If you're on fire -#define TOTAL_LAYERS 30 //KEEP THIS UP-TO-DATE OR SHIT WILL BREAK ;_; +#define TOTAL_LAYERS 32 //KEEP THIS UP-TO-DATE OR SHIT WILL BREAK ;_; //Human Overlay Index Shortcuts for alternate_worn_layer, layers //Because I *KNOW* somebody will think layer+1 means "above" diff --git a/modular_citadel/code/modules/arousal/genitals.dm b/modular_citadel/code/modules/arousal/genitals.dm index 5632aa7eef..f8e404713d 100644 --- a/modular_citadel/code/modules/arousal/genitals.dm +++ b/modular_citadel/code/modules/arousal/genitals.dm @@ -166,7 +166,7 @@ give_genital(/obj/item/organ/genital/womb) if(dna.features["has_balls"]) give_genital(/obj/item/organ/genital/testicles) - if(dna.features["has_breasts"]) // since we have multi-boobs as a thing, we'll want to at least draw over these. but not over the pingas. + if(dna.features["has_breasts"]) give_genital(/obj/item/organ/genital/breasts) if(dna.features["has_cock"]) give_genital(/obj/item/organ/genital/penis) @@ -183,6 +183,7 @@ G = new G G.get_features(src) G.Insert(src) + return G /obj/item/organ/genital/proc/get_features(mob/living/carbon/human/H) return @@ -191,8 +192,6 @@ switch(layer) if(GENITALS_BEHIND_LAYER) return "BEHIND" - /*if(GENITALS_ADJ_LAYER) - return "ADJ"*/ if(GENITALS_FRONT_LAYER) return "FRONT" @@ -227,14 +226,12 @@ if(!canbearoused) ADD_TRAIT(src, TRAIT_PHARMA, "pharma")//Prefs prevent unwanted organs. return - for(var/obj/item/organ/O in internal_organs) + for(var/O in internal_organs) if(istype(O, /obj/item/organ/genital)) organCheck = TRUE - if(/obj/item/organ/genital/penis) - //dna.features["has_cock"] = TRUE + if(istype(O, /obj/item/organ/genital/penis)) willyCheck = TRUE - if(/obj/item/organ/genital/breasts) - //dna.features["has_breasts"] = TRUE//Goddamnit get in there. + if(istype(O, /obj/item/organ/genital/breasts)) breastCheck = TRUE if(organCheck == FALSE) if(ishuman(src) && dna.species.id == "human") @@ -260,10 +257,7 @@ CRASH("H = null") if(!LAZYLEN(H.internal_organs) || ((NOGENITALS in species_traits) && !H.genital_override) || HAS_TRAIT(H, TRAIT_HUSK)) return - var/list/relevant_layers = list(GENITALS_BEHIND_LAYER, GENITALS_FRONT_LAYER) //GENITALS_ADJ_LAYER removed - var/list/standing = list() - var/size - var/aroused_state + var/list/relevant_layers = list(GENITALS_BEHIND_LAYER, GENITALS_FRONT_LAYER) for(var/L in relevant_layers) //Less hardcode H.remove_overlay(L) @@ -271,21 +265,25 @@ var/list/gen_index[GENITAL_LAYER_INDEX_LENGTH] var/list/genitals_to_add + var/list/fully_exposed for(var/obj/item/organ/genital/G in H.internal_organs) if(G.is_exposed()) //Checks appropriate clothing slot and if it's through_clothes LAZYADD(gen_index[G.layer_index], G) for(var/L in gen_index) if(L) //skip nulls LAZYADD(genitals_to_add, L) + if(!genitals_to_add) + return //Now we added all genitals that aren't internal and should be rendered //start applying overlays for(var/layer in relevant_layers) + var/list/standing = list() var/layertext = genitals_layertext(layer) for(var/A in genitals_to_add) var/obj/item/organ/genital/G = A var/datum/sprite_accessory/S - size = G.size - aroused_state = G.aroused_state + var/size = G.size + var/aroused_state = G.aroused_state switch(G.type) if(/obj/item/organ/genital/penis) S = GLOB.cock_shapes_list[G.shape] @@ -296,9 +294,6 @@ if(/obj/item/organ/genital/breasts) S = GLOB.breasts_shapes_list[G.shape] - - - if(!S || S.icon_state == "none") continue @@ -322,11 +317,16 @@ if("vag_color") genital_overlay.color = "#[H.dna.features["vag_color"]]" - standing += genital_overlay + if(layer == GENITALS_FRONT_LAYER && CHECK_BITFIELD(G.genital_flags, GENITAL_THROUGH_CLOTHES)) + LAZYADD(fully_exposed, genital_overlay) // to be added to a layer with higher priority than clothes, hence the name of the bitflag. + else + standing += genital_overlay if(LAZYLEN(standing)) - H.overlays_standing[layer] = standing.Copy() - standing = list() + H.overlays_standing[layer] = standing + + if(LAZYLEN(fully_exposed)) + H.overlays_standing[GENITALS_EXPOSED_LAYER] = fully_exposed for(var/L in relevant_layers) H.apply_overlay(L) diff --git a/modular_citadel/code/modules/reagents/chemistry/reagents/enlargement.dm b/modular_citadel/code/modules/reagents/chemistry/reagents/enlargement.dm index 01a0e75710..a4c4e352ac 100644 --- a/modular_citadel/code/modules/reagents/chemistry/reagents/enlargement.dm +++ b/modular_citadel/code/modules/reagents/chemistry/reagents/enlargement.dm @@ -31,16 +31,13 @@ InverseChem = "BEsmaller" //At really impure vols, it just becomes 100% inverse can_synth = FALSE -/datum/reagent/fermi/breast_enlarger/on_mob_add(mob/living/carbon/M) +/datum/reagent/fermi/breast_enlarger/on_mob_metabolize(mob/living/M) . = ..() if(!ishuman(M)) //The monkey clause if(volume >= 15) //To prevent monkey breast farms var/turf/T = get_turf(M) var/obj/item/organ/genital/breasts/B = new /obj/item/organ/genital/breasts(T) - var/list/seen = viewers(8, T) - for(var/mob/S in seen) - to_chat(S, "A pair of breasts suddenly fly out of the [M]!") - //var/turf/T2 = pick(turf in view(5, M)) + M.visible_message("A pair of breasts suddenly fly out of the [M]!") var/T2 = get_random_station_turf() M.adjustBruteLoss(25) M.Knockdown(50) @@ -51,7 +48,7 @@ log_game("FERMICHEM: [M] ckey: [M.key] has ingested Sucubus milk") var/mob/living/carbon/human/H = M H.genital_override = TRUE - var/obj/item/organ/genital/breasts/B = H.getorganslot("breasts") + var/obj/item/organ/genital/breasts/B = H.getorganslot(ORGAN_SLOT_BREASTS) if(!B) H.emergent_genital_call() return @@ -103,7 +100,7 @@ M.adjustOxyLoss(5, 0) M.apply_damage(1, BRUTE, target) B.update() - ..() + return ..() /datum/reagent/fermi/breast_enlarger/overdose_process(mob/living/carbon/M) //Turns you into a female if male and ODing, doesn't touch nonbinary and object genders. @@ -135,7 +132,7 @@ var/obj/item/organ/genital/womb/nW = new nW.Insert(M) W = nW - ..() + return ..() /datum/reagent/fermi/BEsmaller name = "Modesty milk" @@ -159,7 +156,7 @@ return..() B.cached_size = B.cached_size - 0.05 B.update() - ..() + return ..() /datum/reagent/fermi/BEsmaller_hypo name = "Rectify milk" //Rectify @@ -171,19 +168,18 @@ var/sizeConv = list("a" = 1, "b" = 2, "c" = 3, "d" = 4, "e" = 5) can_synth = TRUE -/datum/reagent/fermi/BEsmaller_hypo/on_mob_add(mob/living/carbon/M) +/datum/reagent/fermi/BEsmaller_hypo/on_mob_metabolize(mob/living/M) . = ..() - if(!M.getorganslot("vagina")) - if(M.dna.features["has_vag"]) - var/obj/item/organ/genital/vagina/nV = new - nV.Insert(M) - if(!M.getorganslot("womb")) - if(M.dna.features["has_womb"]) - var/obj/item/organ/genital/womb/nW = new - nW.Insert(M) + if(!ishuman(M)) + return + var/mob/living/carbon/human/H = M + if(!H.getorganslot(ORGAN_SLOT_VAGINA) && H.dna.features["has_vag"]) + H.give_genital(/obj/item/organ/genital/vagina) + if(!H.getorganslot(ORGAN_SLOT_WOMB) && H.dna.features["has_womb"]) + H.give_genital(/obj/item/organ/genital/womb) /datum/reagent/fermi/BEsmaller_hypo/on_mob_life(mob/living/carbon/M) - var/obj/item/organ/genital/breasts/B = M.getorganslot("breasts") + var/obj/item/organ/genital/breasts/B = M.getorganslot(ORGAN_SLOT_BREASTS) if(!B) return..() if(!M.dna.features["has_breasts"])//Fast fix for those who don't want it. @@ -195,7 +191,7 @@ else if(B.cached_size < (sizeConv[M.dna.features["breasts_size"]])+0.1) B.cached_size = B.cached_size + 0.05 B.update() - ..() + return ..() //////////////////////////////////////////////////////////////////////////////////////////////////// // PENIS ENLARGE @@ -216,15 +212,13 @@ InverseChem = "PEsmaller" //At really impure vols, it just becomes 100% inverse and shrinks instead. can_synth = FALSE -/datum/reagent/fermi/penis_enlarger/on_mob_add(mob/living/carbon/M) +/datum/reagent/fermi/penis_enlarger/on_mob_metabolize(mob/living/M) . = ..() if(!ishuman(M)) //Just monkeying around. if(volume >= 15) //to prevent monkey penis farms var/turf/T = get_turf(M) var/obj/item/organ/genital/penis/P = new /obj/item/organ/genital/penis(T) - var/list/seen = viewers(8, T) - for(var/mob/S in seen) - to_chat(S, "A penis suddenly flies out of the [M]!") + M.visible_message("A penis suddenly flies out of the [M]!") var/T2 = get_random_station_turf() M.adjustBruteLoss(25) M.Knockdown(50) @@ -234,7 +228,7 @@ return var/mob/living/carbon/human/H = M H.genital_override = TRUE - var/obj/item/organ/genital/penis/P = M.getorganslot("penis") + var/obj/item/organ/genital/penis/P = M.getorganslot(ORGAN_SLOT_PENIS) if(!P) H.emergent_genital_call() return @@ -277,7 +271,7 @@ M.apply_damage(2.5, BRUTE, target) P.update() - ..() + return ..() /datum/reagent/fermi/penis_enlarger/overdose_process(mob/living/carbon/M) //Turns you into a male if female and ODing, doesn't touch nonbinary and object genders. //Acute hepatic pharmacokinesis. @@ -306,7 +300,7 @@ var/obj/item/organ/genital/testicles/nT = new nT.Insert(M) T = nT - ..() + return ..() /datum/reagent/fermi/PEsmaller // Due to cozmo's request...! name = "Chastity draft" @@ -342,12 +336,13 @@ metabolization_rate = 0.5 can_synth = TRUE -/datum/reagent/fermi/PEsmaller_hypo/on_mob_add(mob/living/carbon/M) +/datum/reagent/fermi/PEsmaller_hypo/on_mob_metabolize(mob/living/M) . = ..() - if(!M.getorganslot("testicles")) - if(M.dna.features["has_balls"]) - var/obj/item/organ/genital/testicles/nT = new - nT.Insert(M) + if(!ishuman(M)) + return + var/mob/living/carbon/human/H = M + if(!H.getorganslot(ORGAN_SLOT_TESTICLES) && H.dna.features["has_balls"]) + H.give_genital(/obj/item/organ/genital/testicles) /datum/reagent/fermi/PEsmaller_hypo/on_mob_life(mob/living/carbon/M) var/obj/item/organ/genital/penis/P = M.getorganslot(ORGAN_SLOT_PENIS) @@ -362,4 +357,4 @@ else if(P.cached_length < (M.dna.features["cock_length"]+0.1)) P.cached_length = P.cached_length + 0.1 P.update() - ..() + return ..() From e66b95b9c9dd5da1d214b10112244d88438e71f8 Mon Sep 17 00:00:00 2001 From: Ghommie <42542238+Ghommie@users.noreply.github.com> Date: Sun, 1 Sep 2019 05:58:57 +0200 Subject: [PATCH 10/17] More lines of code rewriting fermis' mess. --- .../code/modules/arousal/genitals.dm | 12 +++-- .../code/modules/arousal/organs/breasts.dm | 54 +++++++++++-------- .../code/modules/arousal/organs/penis.dm | 10 ++-- .../chemistry/reagents/enlargement.dm | 35 +++++------- 4 files changed, 56 insertions(+), 55 deletions(-) diff --git a/modular_citadel/code/modules/arousal/genitals.dm b/modular_citadel/code/modules/arousal/genitals.dm index f8e404713d..7b3b637e26 100644 --- a/modular_citadel/code/modules/arousal/genitals.dm +++ b/modular_citadel/code/modules/arousal/genitals.dm @@ -19,13 +19,17 @@ var/linked_organ_slot //only one of the two organs needs this to be set up. update_link() will handle linking the rest. var/layer_index = GENITAL_LAYER_INDEX //Order should be very important. FIRST vagina, THEN testicles, THEN penis, as this affects the order they are rendered in. -/obj/item/organ/genital/Initialize() +/obj/item/organ/genital/Initialize(mapload, mob/living/carbon/human/H) . = ..() if(fluid_id) create_reagents(fluid_max_volume) if(CHECK_BITFIELD(genital_flags, GENITAL_FUID_PRODUCTION)) reagents.add_reagent(fluid_id, fluid_max_volume) - update() + if(H) + get_features(H) + Insert(H) + else + update() /obj/item/organ/genital/Destroy() if(linked_organ) @@ -180,9 +184,7 @@ /mob/living/carbon/human/proc/give_genital(obj/item/organ/genital/G) if(!dna || (NOGENITALS in dna.species.species_traits) || getorganslot(initial(G.slot))) return FALSE - G = new G - G.get_features(src) - G.Insert(src) + G = new G(null, src) return G /obj/item/organ/genital/proc/get_features(mob/living/carbon/human/H) diff --git a/modular_citadel/code/modules/arousal/organs/breasts.dm b/modular_citadel/code/modules/arousal/organs/breasts.dm index c862e21bc5..08b99eabfa 100644 --- a/modular_citadel/code/modules/arousal/organs/breasts.dm +++ b/modular_citadel/code/modules/arousal/organs/breasts.dm @@ -12,10 +12,17 @@ masturbation_verb = "massage" orgasm_verb = "leaking" fluid_transfer_factor = 0.5 - var/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, "flat" = 0) + var/list/static/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, "flat" = 0) var/cached_size //for enlargement SHOULD BE A NUMBER var/prev_size //For flavour texts SHOULD BE A LETTER +/obj/item/organ/genital/breasts/Initialize(mapload, mob/living/carbon/human/H) + if(!H) + cached_size = size + size = breast_values[size] + prev_size = size + return ..() + /obj/item/organ/genital/breasts/update_appearance() . = ..() var/lowershape = lowertext(shape) @@ -28,14 +35,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(cached_size > 16) + 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)]cm in diameter." - else if (!isnum(size)) + else if (size == "flat") desc += " They're very small and flatchested, however." else desc += " You estimate that they're [uppertext(size)]-cups." - //string = "breasts_[lowertext(shape)]_[size]-s" if(CHECK_BITFIELD(genital_flags, GENITAL_FUID_PRODUCTION) && aroused_state) desc += " They're leaking [fluid_id]." @@ -62,38 +68,40 @@ //this is far too lewd wah /obj/item/organ/genital/breasts/update_size()//wah - if(cached_size == size) - return if(cached_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.") + to_chat(owner, "You feel your breasts shrinking away from your body as your chest flattens out.") QDEL_IN(src, 1) + return var/enlargement = FALSE - switch(cached_size) - if(0 to 0.99) //If flatchested + switch(round(cached_size)) + if(0) //flatchested size = "flat" - if(16 to INFINITY) //if Rediculous + if(1 to 8) //modest + size = breast_values[round(cached_size)] + if(9 to 15) //massive + size = breast_values[round(cached_size)] + enlargement = TRUE + if(16 to INFINITY) //rediculous size = "huge" enlargement = TRUE - if(owner && !enlargement) - if(!owner.has_status_effect(/datum/status_effect/chem/breast_enlarger)) + if(owner) + var/status_effect = owner.has_status_effect(/datum/status_effect/chem/breast_enlarger) + if(enlargement && !status_effect) owner.apply_status_effect(/datum/status_effect/chem/breast_enlarger) - size = breast_values[round(cached_size)] + else if(status_effect) + owner.remove_status_effect(/datum/status_effect/chem/breast_enlarger) if(round(cached_size) < 16)//Because byond doesn't count from 0, I have to do this. - if(isnum(prev_size)) - prev_size = breast_values[prev_size] if(owner) var/mob/living/carbon/human/H = owner if (breast_values[size] > breast_values[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.") + 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.") H.dna.species.handle_genitals(src) else if (breast_values[size] > 0.5) - to_chat(H, "Your breasts [pick("shrink down to", "decrease into", "diminish into", "deflate into", "shrivel regretfully into", "contracts into")] a [uppertext(size)]-cup.") + to_chat(H, "Your breasts [pick("shrink down to", "decrease into", "diminish into", "deflate into", "shrivel regretfully into", "contracts into")] a [uppertext(size)]-cup.") H.dna.species.handle_genitals(src) prev_size = size - else - size = "huge" /obj/item/organ/genital/breasts/get_features(mob/living/carbon/human/H) var/datum/dna/D = H.dna @@ -107,12 +115,12 @@ if(!isnum(size)) if(size == "flat") cached_size = 0 - prev_size = 0 - else if (cached_size == "huge") - prev_size = "huge" + else if (size == "huge") + cached_size = 16 else cached_size = breast_values[size] - prev_size = size + prev_size = size else cached_size = size + size = breast_values[size] prev_size = size diff --git a/modular_citadel/code/modules/arousal/organs/penis.dm b/modular_citadel/code/modules/arousal/organs/penis.dm index ff5f216f2f..c79a522405 100644 --- a/modular_citadel/code/modules/arousal/organs/penis.dm +++ b/modular_citadel/code/modules/arousal/organs/penis.dm @@ -19,8 +19,6 @@ var/list/knotted_types = list("knotted", "barbed, knotted") /obj/item/organ/genital/penis/update_size() - if(cached_length == length) - return if(cached_length < 0)//I don't actually know what round() does to negative numbers, so to be safe!! if(owner) to_chat(owner, "You feel your tallywacker shrinking away from your body as your groin flattens out!") @@ -31,13 +29,13 @@ var/new_size var/enlargement = FALSE switch(round(cached_length)) - if(0 to 6.99) //If modest size + if(0 to 6) //If modest size new_size = 1 - if(7 to 10.99) //If large + if(7 to 10) //If large size = 2 - if(11 to 19.99) //If massive + if(11 to 19) //If massive size = 3 - if(20 to 34.99) //If massive and due for large effects + if(20 to 34) //If massive and due for large effects size = 3 enlargement = TRUE if(35 to INFINITY) //If comical diff --git a/modular_citadel/code/modules/reagents/chemistry/reagents/enlargement.dm b/modular_citadel/code/modules/reagents/chemistry/reagents/enlargement.dm index a4c4e352ac..87e1567eda 100644 --- a/modular_citadel/code/modules/reagents/chemistry/reagents/enlargement.dm +++ b/modular_citadel/code/modules/reagents/chemistry/reagents/enlargement.dm @@ -52,10 +52,6 @@ if(!B) H.emergent_genital_call() return - if(!B.size == "huge") - var/sizeConv = list("a" = 1, "b" = 2, "c" = 3, "d" = 4, "e" = 5) - B.prev_size = B.size - B.cached_size = sizeConv[B.size] /datum/reagent/fermi/breast_enlarger/on_mob_life(mob/living/carbon/M) //Increases breast size if(!ishuman(M))//Just in case @@ -87,7 +83,7 @@ nB.color = skintone2hex(H.skin_tone) nB.size = "flat" nB.cached_size = 0 - nB.prev_size = 0 + nB.prev_size = "flat" to_chat(M, "Your chest feels warm, tingling with newfound sensitivity.") M.reagents.remove_reagent(id, 5) B = nB @@ -123,15 +119,13 @@ P.cached_length = P.cached_length - 0.05 P.update() if(T) - T.Remove(M) + qdel(T) if(!V) - var/obj/item/organ/genital/vagina/nV = new - nV.Insert(M) - V = nV + V = new + V.Insert(M) if(!W) - var/obj/item/organ/genital/womb/nW = new - nW.Insert(M) - W = nW + W = new + W.Insert(M) return ..() /datum/reagent/fermi/BEsmaller @@ -232,8 +226,6 @@ if(!P) H.emergent_genital_call() return - P.prev_length = P.length - P.cached_length = P.length /datum/reagent/fermi/penis_enlarger/on_mob_life(mob/living/carbon/M) //Increases penis size, 5u = +1 inch. if(!ishuman(M)) @@ -273,7 +265,9 @@ P.update() return ..() -/datum/reagent/fermi/penis_enlarger/overdose_process(mob/living/carbon/M) //Turns you into a male if female and ODing, doesn't touch nonbinary and object genders. +/datum/reagent/fermi/penis_enlarger/overdose_process(mob/living/carbon/human/M) //Turns you into a male if female and ODing, doesn't touch nonbinary and object genders. + if(!istype(M)) + return ..() //Acute hepatic pharmacokinesis. if(HAS_TRAIT(M, TRAIT_PHARMA)) var/obj/item/organ/liver/L = M.getorganslot(ORGAN_SLOT_LIVER) @@ -292,14 +286,13 @@ if(B) B.cached_size = B.cached_size - 0.05 B.update() - if(V) - V.Remove(M) + if(M.getorganslot(ORGAN_SLOT_VAGINA)) + qdel(V) if(W) - W.Remove(M) + qdel(W) if(!T) - var/obj/item/organ/genital/testicles/nT = new - nT.Insert(M) - T = nT + T = new + T.Insert(M) return ..() /datum/reagent/fermi/PEsmaller // Due to cozmo's request...! From 6dbac16c74065a6a0c486cc8bb4b33ac33d8491b Mon Sep 17 00:00:00 2001 From: Ghommie <42542238+Ghommie@users.noreply.github.com> Date: Thu, 3 Oct 2019 04:31:11 +0200 Subject: [PATCH 11/17] Sanitizing the fermis code biohazard. --- code/__DEFINES/citadel_defines.dm | 21 --- code/__DEFINES/status_effects.dm | 3 + .../objects/items/devices/compressionkit.dm | 41 ++-- .../chemistry/reagents/other_reagents.dm | 18 -- .../code/datums/status_effects/chems.dm | 170 ++++++++--------- .../code/modules/arousal/genitals.dm | 34 ++-- .../code/modules/arousal/organs/breasts.dm | 63 ++++--- .../code/modules/arousal/organs/penis.dm | 33 ++-- .../chemistry/reagents/enlargement.dm | 176 ++++++++---------- 9 files changed, 251 insertions(+), 308 deletions(-) diff --git a/code/__DEFINES/citadel_defines.dm b/code/__DEFINES/citadel_defines.dm index 785dd15417..53e3723912 100644 --- a/code/__DEFINES/citadel_defines.dm +++ b/code/__DEFINES/citadel_defines.dm @@ -67,27 +67,6 @@ #define BREASTS_VOLUME_BASE 50 //base volume for the reagents in the breasts, multiplied by the size then multiplier. 50u for A cups, 850u for HH cups. #define BREASTS_VOLUME_MULT 1 //global multiplier for breast volume. -#define BREASTS_SIZE_FLAT 0 -#define BREASTS_SIZE_A 1 -#define BREASTS_SIZE_AA 1.5 -#define BREASTS_SIZE_B 2 -#define BREASTS_SIZE_BB 2.5 -#define BREASTS_SIZE_C 3 -#define BREASTS_SIZE_CC 3.5 -#define BREASTS_SIZE_D 4 -#define BREASTS_SIZE_DD 4.5 -#define BREASTS_SIZE_E 5 -#define BREASTS_SIZE_EE 5.5 -#define BREASTS_SIZE_F 6 -#define BREASTS_SIZE_FF 6.5 -#define BREASTS_SIZE_G 7 -#define BREASTS_SIZE_GG 7.5//Are these even real sizes? The world may never know because cup sizes make no fucking sense. -#define BREASTS_SIZE_H 8 -#define BREASTS_SIZE_HH 8.5//Largest size, ever. For now. - -#define BREASTS_SIZE_MIN BREASTS_SIZE_A -#define BREASTS_SIZE_DEF BREASTS_SIZE_C -#define BREASTS_SIZE_MAX BREASTS_SIZE_HH #define MILK_RATE 5 #define MILK_RATE_MULT 1 diff --git a/code/__DEFINES/status_effects.dm b/code/__DEFINES/status_effects.dm index 3cd64af8c7..05309333af 100644 --- a/code/__DEFINES/status_effects.dm +++ b/code/__DEFINES/status_effects.dm @@ -72,6 +72,9 @@ #define STATUS_EFFECT_ICHORIAL_STAIN /datum/status_effect/ichorial_stain //Prevents a servant from being revived by vitality matrices for one minute. +#define STATUS_EFFECT_BREASTS_ENLARGEMENT /datum/status_effect/chem/breast_enlarger //Applied slowdown due to the ominous bulk. + +#define STATUS_EFFECT_PENIS_ENLARGEMENT //More applied slowdown, just like the above. ///////////// // NEUTRAL // ///////////// diff --git a/code/game/objects/items/devices/compressionkit.dm b/code/game/objects/items/devices/compressionkit.dm index 5ac958328d..a5a9377690 100644 --- a/code/game/objects/items/devices/compressionkit.dm +++ b/code/game/objects/items/devices/compressionkit.dm @@ -89,30 +89,23 @@ else to_chat(user, "Anomalous error. Summon a coder.") - if(istype(target, /mob/living)) - var/mob/living/victim = target - if(istype(victim, /mob/living/carbon/human)) - if(user.zone_selected == "groin") // pp smol. There's probably a smarter way to do this but im retarded. If you have a simpler method let me know. - var/list/organs = victim.getorganszone("groin") - for(var/internal_organ in organs) - if(istype(internal_organ, /obj/item/organ/genital/penis)) - var/obj/item/organ/genital/penis/O = internal_organ - playsound(get_turf(src), 'sound/weapons/flash.ogg', 50, 1) - victim.visible_message("[user] is preparing to shrink [victim]\'s [O.name] with their bluespace compression kit!") - if(do_mob(user, victim, 40) && charges > 0 && O.length > 0) - victim.visible_message("[user] has shrunk [victim]\'s [O.name]!") - playsound(get_turf(src), 'sound/weapons/emitter2.ogg', 50, 1) - sparks() - flash_lighting_fx(3, 3, LIGHT_COLOR_CYAN) - charges -= 1 - O.length -= 5 - if(O.length < 1) - victim.visible_message("[user]\'s [O.name] vanishes!") - qdel(O) // no pp for you - else - O.update_size() - O.update_appearance() - + else if(ishuman(target) && user.zone_selected == BODY_ZONE_PRECISE_GROIN) + var/mob/living/carbon/human/H = target + var/obj/item/organ/genital/penis/P = H.getorganslot(ORGAN_SLOT_PENIS) + if(!P) + return + playsound(get_turf(src), 'sound/weapons/flash.ogg', 50, 1) + H.visible_message("[user] is preparing to shrink [H]\'s [P.name] with their bluespace compression kit!") + if(do_mob(user, H, 40) && charges > 0 && P.length > 0) + H.visible_message("[user] has shrunk [H]\'s [P.name]!") + playsound(get_turf(src), 'sound/weapons/emitter2.ogg', 50, 1) + sparks() + flash_lighting_fx(3, 3, LIGHT_COLOR_CYAN) + charges -= 1 + var/p_name = P.name + P.modify_size(-5) + if(QDELETED(P)) + H.visible_message("[H]\'s [p_name] vanishes!") /obj/item/compressionkit/attackby(obj/item/I, mob/user, params) diff --git a/code/modules/reagents/chemistry/reagents/other_reagents.dm b/code/modules/reagents/chemistry/reagents/other_reagents.dm index 2f7a8652ba..669ac602dc 100644 --- a/code/modules/reagents/chemistry/reagents/other_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/other_reagents.dm @@ -1965,24 +1965,6 @@ M.emote("nya") ..() -//Kept for legacy, I think it will break everything if you enable it. -/datum/reagent/penis_enlargement - name = "Penis Enlargement" - id = "penis_enlargement" - description = "A patented chemical forumula by Doctor Ronald Hyatt that is guaranteed to bring maximum GROWTH and LENGTH to your penis, today!" - color = "#888888" - taste_description = "chinese dragon powder" - metabolization_rate = INFINITY //So it instantly removes all of itself. Don't want to put strain on the system. - -/datum/reagent/penis_enlargement/on_mob_life(mob/living/carbon/C) - var/obj/item/organ/genital/penis/P = C.getorganslot(ORGAN_SLOT_PENIS) - if(P) - var/added_length = round(volume/30,0.01) //Every 30u gives an extra inch. Rounded to the nearest 0.01 so float fuckery doesn't occur with the division by 30. - if(added_length >= 0.20) //Only add the length if it's greater than or equal to 0.2. This is to prevent people from smoking the reagents and causing the penis to update constantly. - P.length += added_length - P.update() - ..() - /datum/reagent/changeling_string name = "UNKNOWN" id = "changeling_sting_real" diff --git a/modular_citadel/code/datums/status_effects/chems.dm b/modular_citadel/code/datums/status_effects/chems.dm index 4bc83d2af6..a14c490999 100644 --- a/modular_citadel/code/datums/status_effects/chems.dm +++ b/modular_citadel/code/datums/status_effects/chems.dm @@ -37,64 +37,62 @@ alert_type = null var/moveCalc = 1 var/cachedmoveCalc = 1 + var/last_checked_size //used to prevent potential cpu waste from happening every tick. -/datum/status_effect/chem/breast_enlarger/on_apply(mob/living/carbon/human/H)//Removes clothes, they're too small to contain you. You belong to space now. +/datum/status_effect/chem/breast_enlarger/on_apply()//Removes clothes, they're too small to contain you. You belong to space now. log_game("FERMICHEM: [owner]'s breasts has reached comical sizes. ID: [owner.key]") - var/mob/living/carbon/human/o = owner - var/items = o.get_contents() - for(var/obj/item/W in items) - if(W == o.w_uniform || W == o.wear_suit) - o.dropItemToGround(W, TRUE) - playsound(o.loc, 'sound/items/poster_ripped.ogg', 50, 1) - to_chat(o, "Your clothes give, ripping into peices under the strain of your swelling breasts! Unless you manage to reduce the size of your breasts, there's no way you're going to be able to put anything on over these melons..!") - o.visible_message("[o]'s chest suddenly bursts forth, ripping their clothes off!'") - else - to_chat(o, "Your bountiful bosom is so rich with mass, you seriously doubt you'll be able to fit any clothes over it.") - return ..() + var/mob/living/carbon/human/H = owner + var/message = FALSE + if(H.w_uniform) + H.dropItemToGround(H.w_uniform, TRUE) + message = TRUE + if(H.wear_suit) + H.dropItemToGround(H.wear_suit, TRUE) + message = TRUE + if(message) + playsound(H.loc, 'sound/items/poster_ripped.ogg', 50, 1) + H.visible_message("[H]'s chest suddenly bursts forth, ripping their clothes off!'", \ + "Your clothes give, ripping into peices under the strain of your swelling breasts! Unless you manage to reduce the size of your breasts, there's no way you're going to be able to put anything on over these melons..!") + else + to_chat(H, "Your bountiful bosom is so rich with mass, you seriously doubt you'll be able to fit any clothes over it.") + return ..() -/datum/status_effect/chem/breast_enlarger/tick(mob/living/carbon/human/H)//If you try to wear clothes, you fail. Slows you down if you're comically huge - var/mob/living/carbon/human/o = owner - var/obj/item/organ/genital/breasts/B = o.getorganslot("breasts") - moveCalc = 1+((round(B.cached_size) - 9)/3) //Afffects how fast you move, and how often you can click. +/datum/status_effect/chem/breast_enlarger/tick()//If you try to wear clothes, you fail. Slows you down if you're comically huge + var/mob/living/carbon/human/H = owner + var/obj/item/organ/genital/breasts/B = H.getorganslot(ORGAN_SLOT_BREASTS) if(!B) - o.remove_movespeed_modifier(BREAST_MOVEMENT_SPEED) - sizeMoveMod(1) - owner.remove_status_effect(src) - var/items = o.get_contents() - for(var/obj/item/W in items) - if(W == o.w_uniform || W == o.wear_suit) - o.dropItemToGround(W, TRUE) - playsound(o.loc, 'sound/items/poster_ripped.ogg', 50, 1) - to_chat(owner, "Your enormous breasts are way too large to fit anything over them!") + H.remove_status_effect(src) + return + moveCalc = 1+((round(B.cached_size) - 9)/3) //Afffects how fast you move, and how often you can click. + var/message = FALSE + if(H.w_uniform) + H.dropItemToGround(H.w_uniform, TRUE) + message = TRUE + if(H.wear_suit) + H.dropItemToGround(H.wear_suit, TRUE) + message = TRUE + if(message) + playsound(H.loc, 'sound/items/poster_ripped.ogg', 50, 1) + to_chat(H, "Your enormous breasts are way too large to fit anything over them!") + + if(last_checked_size != B.cached_size) + H.add_movespeed_modifier(BREAST_MOVEMENT_SPEED, TRUE, 100, NONE, override = TRUE, multiplicative_slowdown = moveCalc) + sizeMoveMod(moveCalc) + if (B.size == "huge") if(prob(1)) to_chat(owner, "Your back is feeling sore.") - var/target = o.get_bodypart(BODY_ZONE_CHEST) - o.apply_damage(0.1, BRUTE, target) - if(!B.cached_size == B.breast_values[B.prev_size]) - o.add_movespeed_modifier(BREAST_MOVEMENT_SPEED, TRUE, 100, NONE, override = TRUE, multiplicative_slowdown = moveCalc) - sizeMoveMod(moveCalc) - return ..() - else if (B.breast_values[B.size] > B.breast_values[B.prev_size]) - o.add_movespeed_modifier(BREAST_MOVEMENT_SPEED, TRUE, 100, NONE, override = TRUE, multiplicative_slowdown = moveCalc) - sizeMoveMod(moveCalc) - else if (B.breast_values[B.size] < B.breast_values[B.prev_size]) - o.add_movespeed_modifier(BREAST_MOVEMENT_SPEED, TRUE, 100, NONE, override = TRUE, multiplicative_slowdown = moveCalc) - sizeMoveMod(moveCalc) - if((B.cached_size) < 16) - switch(round(B.cached_size)) - if(9) - if (B.breast_values[B.prev_size] != B.breast_values[B.size]) - to_chat(o, "Your expansive chest has become a more managable size, liberating your movements.") - if(10 to INFINITY) - if (B.breast_values[B.prev_size] != B.breast_values[B.size]) - to_chat(H, "Your indulgent busom is so substantial, it's affecting your movements!") + var/target = H.get_bodypart(BODY_ZONE_CHEST) + H.apply_damage(0.1, BRUTE, target) + else if(prob(1)) - to_chat(owner, "Your back is feeling a little sore.") - ..() + to_chat(H, "Your back is feeling a little sore.") + last_checked_size = B.cached_size + ..() -/datum/status_effect/chem/breast_enlarger/on_remove(mob/living/carbon/M) +/datum/status_effect/chem/breast_enlarger/on_remove() log_game("FERMICHEM: [owner]'s breasts has reduced to an acceptable size. ID: [owner.key]") + to_chat(owner, "Your expansive chest has become a more managable size, liberating your movements.") owner.remove_movespeed_modifier(BREAST_MOVEMENT_SPEED) sizeMoveMod(1) @@ -112,51 +110,57 @@ alert_type = null var/bloodCalc var/moveCalc + var/last_checked_size //used to prevent potential cpu waste, just like the above. -/datum/status_effect/chem/penis_enlarger/on_apply(mob/living/carbon/human/H)//Removes clothes, they're too small to contain you. You belong to space now. +/datum/status_effect/chem/penis_enlarger/on_apply()//Removes clothes, they're too small to contain you. You belong to space now. log_game("FERMICHEM: [owner]'s dick has reached comical sizes. ID: [owner.key]") - var/mob/living/carbon/human/o = owner - var/items = o.get_contents() - if(o.w_uniform || o.wear_suit) - to_chat(o, "Your clothes give, ripping into peices under the strain of your swelling pecker! Unless you manage to reduce the size of your emancipated trouser snake, there's no way you're going to be able to put anything on over this girth..!") - owner.visible_message("[o]'s schlong suddenly bursts forth, ripping their clothes off!'") + var/mob/living/carbon/human/H = owner + var/message = FALSE + if(H.w_uniform) + H.dropItemToGround(H.w_uniform, TRUE) + message = TRUE + if(H.wear_suit) + H.dropItemToGround(H.wear_suit, TRUE) + message = TRUE + if(message) + playsound(H.loc, 'sound/items/poster_ripped.ogg', 50, 1) + H.visible_message("[H]'s schlong suddenly bursts forth, ripping their clothes off!'", \ + "Your clothes give, ripping into peices under the strain of your swelling pecker! Unless you manage to reduce the size of your emancipated trouser snake, there's no way you're going to be able to put anything on over this girth..!") else - to_chat(o, "Your emancipated trouser snake is so ripe with girth, you seriously doubt you'll be able to fit any clothes over it.") - for(var/obj/item/W in items) - if(W == o.w_uniform || W == o.wear_suit) - o.dropItemToGround(W, TRUE) - playsound(o.loc, 'sound/items/poster_ripped.ogg', 50, 1) + to_chat(H, "Your emancipated trouser snake is so ripe with girth, you seriously doubt you'll be able to fit any clothes over it.") return ..() -/datum/status_effect/chem/penis_enlarger/tick(mob/living/carbon/M) - var/mob/living/carbon/human/o = owner - var/obj/item/organ/genital/penis/P = o.getorganslot("penis") +/datum/status_effect/chem/penis_enlarger/tick() + var/mob/living/carbon/human/H = owner + var/obj/item/organ/genital/penis/P = H.getorganslot(ORGAN_SLOT_PENIS) + if(!P) + owner.remove_status_effect(src) + return moveCalc = 1+((round(P.length) - 21)/3) //effects how fast you can move bloodCalc = 1+((round(P.length) - 21)/15) //effects how much blood you need (I didn' bother adding an arousal check because I'm spending too much time on this organ already.) - if(!P) - o.remove_movespeed_modifier(DICK_MOVEMENT_SPEED) - o.ResetBloodVol() - owner.remove_status_effect(src) - var/items = o.get_contents() - for(var/obj/item/W in items) - if(W == o.w_uniform || W == o.wear_suit) - o.dropItemToGround(W, TRUE) - playsound(o.loc, 'sound/items/poster_ripped.ogg', 50, 1) - to_chat(owner, "Your enormous package is way to large to fit anything over!") - switch(round(P.cached_length)) - if(21) - to_chat(o, "Your rascally willy has become a more managable size, liberating your movements.") - o.remove_movespeed_modifier(DICK_MOVEMENT_SPEED) - o.AdjustBloodVol(bloodCalc) - if(22 to INFINITY) - if(prob(2)) - to_chat(o, "Your indulgent johnson is so substantial, it's taking all your blood and affecting your movements!") - o.add_movespeed_modifier(DICK_MOVEMENT_SPEED, TRUE, 100, NONE, override = TRUE, multiplicative_slowdown = moveCalc) - o.AdjustBloodVol(bloodCalc) + + var/message = FALSE + if(H.w_uniform) + H.dropItemToGround(H.w_uniform, TRUE) + message = TRUE + if(H.wear_suit) + H.dropItemToGround(H.wear_suit, TRUE) + message = TRUE + if(message) + playsound(H.loc, 'sound/items/poster_ripped.ogg', 50, 1) + to_chat(H, "Your enormous package is way to large to fit anything over!") + + if(P.length < 22 && H.has_movespeed_modifier(DICK_MOVEMENT_SPEED)) + to_chat(owner, "Your rascally willy has become a more managable size, liberating your movements.") + H.remove_movespeed_modifier(DICK_MOVEMENT_SPEED) + else if(P.length >= 22 && !H.has_movespeed_modifier(DICK_MOVEMENT_SPEED)) + to_chat(H, "Your indulgent johnson is so substantial, it's taking all your blood and affecting your movements!") + H.add_movespeed_modifier(DICK_MOVEMENT_SPEED, TRUE, 100, NONE, override = TRUE, multiplicative_slowdown = moveCalc) + H.AdjustBloodVol(bloodCalc) ..() -/datum/status_effect/chem/penis_enlarger/on_remove(mob/living/carbon/human/o) +/datum/status_effect/chem/penis_enlarger/on_remove() log_game("FERMICHEM: [owner]'s dick has reduced to an acceptable size. ID: [owner.key]") owner.remove_movespeed_modifier(DICK_MOVEMENT_SPEED) owner.ResetBloodVol() diff --git a/modular_citadel/code/modules/arousal/genitals.dm b/modular_citadel/code/modules/arousal/genitals.dm index 7b3b637e26..593874496a 100644 --- a/modular_citadel/code/modules/arousal/genitals.dm +++ b/modular_citadel/code/modules/arousal/genitals.dm @@ -105,6 +105,9 @@ picked_organ.toggle_visibility(picked_visibility) return +/obj/item/organ/genital/proc/modify_size(modifier, min = -INFINITY, max = INFINITY) + return + /obj/item/organ/genital/proc/update_size() return @@ -215,34 +218,23 @@ if(!QDELETED(src)) dna.species.handle_genitals(src) -//fermichem procs -/mob/living/carbon/human/proc/Force_update_genitals(mob/living/carbon/human/H) //called in fermiChem - dna.species.handle_genitals(src)//should work. - //dna.species.handle_breasts(src) - //Checks to see if organs are new on the mob, and changes their colours so that they don't get crazy colours. /mob/living/carbon/human/proc/emergent_genital_call() - var/organCheck = FALSE - var/breastCheck = FALSE - var/willyCheck = FALSE if(!canbearoused) - ADD_TRAIT(src, TRAIT_PHARMA, "pharma")//Prefs prevent unwanted organs. - return - for(var/O in internal_organs) - if(istype(O, /obj/item/organ/genital)) - organCheck = TRUE - if(istype(O, /obj/item/organ/genital/penis)) - willyCheck = TRUE - if(istype(O, /obj/item/organ/genital/breasts)) - breastCheck = TRUE + return FALSE + + var/organCheck = locate(/obj/item/organ/genital) in internal_organs + var/breastCheck = getorganslot(ORGAN_SLOT_BREASTS) + var/willyCheck = getorganslot(ORGAN_SLOT_PENIS) + if(organCheck == FALSE) if(ishuman(src) && dna.species.id == "human") dna.features["genitals_use_skintone"] = TRUE dna.species.use_skintones = TRUE if(MUTCOLORS) if(src.dna.species.fixed_mut_color) - dna.features["cock_color"] = "[src.dna.species.fixed_mut_color]" - dna.features["breasts_color"] = "[src.dna.species.fixed_mut_color]" + dna.features["cock_color"] = "[dna.species.fixed_mut_color]" + dna.features["breasts_color"] = "[dna.species.fixed_mut_color]" return //So people who haven't set stuff up don't get rainbow surprises. dna.features["cock_color"] = "[dna.features["mcolor"]]" @@ -252,7 +244,7 @@ dna.features["breasts_color"] = dna.features["cock_color"] else if (willyCheck == FALSE) dna.features["cock_color"] = dna.features["breasts_color"] - return + return TRUE /datum/species/proc/handle_genitals(mob/living/carbon/human/H)//more like handle sadness if(!H)//no args @@ -263,6 +255,7 @@ for(var/L in relevant_layers) //Less hardcode H.remove_overlay(L) + H.remove_overlay(GENITALS_EXPOSED_LAYER) //start scanning for genitals var/list/gen_index[GENITAL_LAYER_INDEX_LENGTH] @@ -329,6 +322,7 @@ if(LAZYLEN(fully_exposed)) H.overlays_standing[GENITALS_EXPOSED_LAYER] = fully_exposed + H.apply_overlay(GENITALS_EXPOSED_LAYER) for(var/L in relevant_layers) H.apply_overlay(L) diff --git a/modular_citadel/code/modules/arousal/organs/breasts.dm b/modular_citadel/code/modules/arousal/organs/breasts.dm index 08b99eabfa..fe502ab66e 100644 --- a/modular_citadel/code/modules/arousal/organs/breasts.dm +++ b/modular_citadel/code/modules/arousal/organs/breasts.dm @@ -5,22 +5,21 @@ icon = 'modular_citadel/icons/obj/genitals/breasts.dmi' zone = BODY_ZONE_CHEST slot = ORGAN_SLOT_BREASTS - size = BREASTS_SIZE_DEF + size = "c" //refer to the breast_values static list below for the cups associated number values fluid_id = "milk" shape = "pair" genital_flags = CAN_MASTURBATE_WITH|CAN_CLIMAX_WITH|GENITAL_FUID_PRODUCTION masturbation_verb = "massage" orgasm_verb = "leaking" fluid_transfer_factor = 0.5 - var/list/static/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, "flat" = 0) - var/cached_size //for enlargement SHOULD BE A NUMBER - var/prev_size //For flavour texts SHOULD BE A LETTER + 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, "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, mob/living/carbon/human/H) if(!H) - cached_size = size - size = breast_values[size] - prev_size = size + cached_size = breast_values[size] + prev_size = cached_size return ..() /obj/item/organ/genital/breasts/update_appearance() @@ -67,41 +66,47 @@ //Rediculous sizes makes you more cumbersome. //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 == prev_size) + return + prev_size = cached_size + cached_size = new_value + update() + /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 if(owner) to_chat(owner, "You feel your breasts shrinking away from your body as your chest flattens out.") QDEL_IN(src, 1) return var/enlargement = FALSE - switch(round(cached_size)) + switch(rounded_cached) if(0) //flatchested size = "flat" if(1 to 8) //modest - size = breast_values[round(cached_size)] + size = breast_values[rounded_cached] if(9 to 15) //massive - size = breast_values[round(cached_size)] + size = breast_values[rounded_cached] enlargement = TRUE if(16 to INFINITY) //rediculous size = "huge" enlargement = TRUE if(owner) - var/status_effect = owner.has_status_effect(/datum/status_effect/chem/breast_enlarger) + var/status_effect = owner.has_status_effect(STATUS_EFFECT_BREASTS_ENLARGEMENT) if(enlargement && !status_effect) - owner.apply_status_effect(/datum/status_effect/chem/breast_enlarger) + owner.apply_status_effect(STATUS_EFFECT_BREASTS_ENLARGEMENT) else if(status_effect) - owner.remove_status_effect(/datum/status_effect/chem/breast_enlarger) + owner.remove_status_effect(STATUS_EFFECT_BREASTS_ENLARGEMENT) - if(round(cached_size) < 16)//Because byond doesn't count from 0, I have to do this. - if(owner) - var/mob/living/carbon/human/H = owner - if (breast_values[size] > breast_values[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.") - H.dna.species.handle_genitals(src) - else if (breast_values[size] > 0.5) - to_chat(H, "Your breasts [pick("shrink down to", "decrease into", "diminish into", "deflate into", "shrivel regretfully into", "contracts into")] a [uppertext(size)]-cup.") - H.dna.species.handle_genitals(src) - prev_size = size + if(rounded_cached < 16 && 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.") /obj/item/organ/genital/breasts/get_features(mob/living/carbon/human/H) var/datum/dna/D = H.dna @@ -112,15 +117,11 @@ size = D.features["breasts_size"] shape = D.features["breasts_shape"] fluid_id = D.features["breasts_fluid"] + if(!D.features["breasts_producing"]) + DISABLE_BITFIELD(genital_flags, GENITAL_FUID_PRODUCTION) if(!isnum(size)) - if(size == "flat") - cached_size = 0 - else if (size == "huge") - cached_size = 16 - else - cached_size = breast_values[size] - prev_size = size + cached_size = breast_values[size] else cached_size = size size = breast_values[size] - prev_size = size + prev_size = cached_size diff --git a/modular_citadel/code/modules/arousal/organs/penis.dm b/modular_citadel/code/modules/arousal/organs/penis.dm index c79a522405..5df9f30fdd 100644 --- a/modular_citadel/code/modules/arousal/organs/penis.dm +++ b/modular_citadel/code/modules/arousal/organs/penis.dm @@ -12,42 +12,47 @@ layer_index = PENIS_LAYER_INDEX var/length = 6 //inches var/prev_length = 6 //really should be renamed to prev_length - var/cached_length //used to detect a change in length var/girth = 4.38 var/girth_ratio = COCK_GIRTH_RATIO_DEF //0.73; check citadel_defines.dm - var/knot_girth_ratio = KNOT_GIRTH_RATIO_DEF - var/list/knotted_types = list("knotted", "barbed, knotted") + +/obj/item/organ/genital/penis/modify_size(modifier, min = -INFINITY, max = INFINITY) + var/new_value = CLAMP(length + modifier, min, max) + if(new_value == prev_length) + return + prev_length = length + length = CLAMP(length + modifier, min, max) + update() /obj/item/organ/genital/penis/update_size() - if(cached_length < 0)//I don't actually know what round() does to negative numbers, so to be safe!! + if(length < 0)//I don't actually know what round() does to negative numbers, so to be safe!! if(owner) to_chat(owner, "You feel your tallywacker shrinking away from your body as your groin flattens out!") QDEL_IN(src, 1) if(linked_organ) QDEL_IN(linked_organ, 1) return + var/rounded_length = round(length) var/new_size var/enlargement = FALSE - switch(round(cached_length)) + switch(rounded_length) if(0 to 6) //If modest size new_size = 1 if(7 to 10) //If large - size = 2 + new_size = 2 if(11 to 19) //If massive - size = 3 + new_size = 3 if(20 to 34) //If massive and due for large effects - size = 3 + new_size = 3 enlargement = TRUE if(35 to INFINITY) //If comical - size = 4 //no new sprites for anything larger yet + new_size = 4 //no new sprites for anything larger yet enlargement = TRUE - length = cached_length if(owner) - var/status_effect = owner.has_status_effect(/datum/status_effect/chem/penis_enlarger) + var/status_effect = owner.has_status_effect(STATUS_EFFECT_PENIS_ENLARGEMENT) if(enlargement && !status_effect) - owner.apply_status_effect(/datum/status_effect/chem/penis_enlarger) + owner.apply_status_effect(STATUS_EFFECT_PENIS_ENLARGEMENT) else if(status_effect) - owner.remove_status_effect(/datum/status_effect/chem/penis_enlarger) + owner.remove_status_effect(STATUS_EFFECT_PENIS_ENLARGEMENT) if(linked_organ) linked_organ.update_size(new_size - size) size = new_size @@ -57,7 +62,6 @@ to_chat(owner, "Your [pick(GLOB.gentlemans_organ_names)] [pick("swells up to", "flourishes into", "expands into", "bursts forth into", "grows eagerly into", "amplifys into")] a [uppertext(round(length))] inch penis.") else if ((round(length) < round(prev_length)) && (length > 0.5)) to_chat(owner, "Your [pick(GLOB.gentlemans_organ_names)] [pick("shrinks down to", "decreases into", "diminishes into", "deflates into", "shrivels regretfully into", "contracts into")] a [uppertext(round(length))] inch penis.") - prev_length = length icon_state = sanitize_text("penis_[shape]_[size]") girth = (length * girth_ratio)//Is it just me or is this ludicous, why not make it exponentially decay? @@ -92,4 +96,3 @@ girth_ratio = D.features["cock_girth_ratio"] shape = D.features["cock_shape"] prev_length = length - cached_length = length diff --git a/modular_citadel/code/modules/reagents/chemistry/reagents/enlargement.dm b/modular_citadel/code/modules/reagents/chemistry/reagents/enlargement.dm index 87e1567eda..d6e0297581 100644 --- a/modular_citadel/code/modules/reagents/chemistry/reagents/enlargement.dm +++ b/modular_citadel/code/modules/reagents/chemistry/reagents/enlargement.dm @@ -30,6 +30,7 @@ InverseChemVal = 0.35 InverseChem = "BEsmaller" //At really impure vols, it just becomes 100% inverse can_synth = FALSE + var/message_spam = FALSE /datum/reagent/fermi/breast_enlarger/on_mob_metabolize(mob/living/M) . = ..() @@ -45,13 +46,9 @@ B.throw_at(T2, 8, 1) M.reagents.remove_reagent(id, volume) return - log_game("FERMICHEM: [M] ckey: [M.key] has ingested Sucubus milk") var/mob/living/carbon/human/H = M - H.genital_override = TRUE - var/obj/item/organ/genital/breasts/B = H.getorganslot(ORGAN_SLOT_BREASTS) - if(!B) - H.emergent_genital_call() - return + if(!H.getorganslot(ORGAN_SLOT_BREASTS) && H.emergent_genital_call()) + H.genital_override = TRUE /datum/reagent/fermi/breast_enlarger/on_mob_life(mob/living/carbon/M) //Increases breast size if(!ishuman(M))//Just in case @@ -62,46 +59,45 @@ if(!B) //If they don't have breasts, give them breasts. //If they have Acute hepatic pharmacokinesis, then route processing though liver. - if(HAS_TRAIT(M, TRAIT_PHARMA)) - var/obj/item/organ/liver/L = M.getorganslot(ORGAN_SLOT_LIVER) + if(HAS_TRAIT(H, TRAIT_PHARMA) || !H.canbearoused) + var/obj/item/organ/liver/L = H.getorganslot(ORGAN_SLOT_LIVER) if(L) - L.swelling+= 0.05 - return..() + L.swelling += 0.05 else - M.adjustToxLoss(1) - return..() + H.adjustToxLoss(1) + return..() //otherwise proceed as normal - var/obj/item/organ/genital/breasts/nB = new - nB.Insert(M) - if(nB) - if(M.dna.species.use_skintones && M.dna.features["genitals_use_skintone"]) - nB.color = skintone2hex(H.skin_tone) - else if(M.dna.features["breasts_color"]) - nB.color = "#[M.dna.features["breasts_color"]]" - else - nB.color = skintone2hex(H.skin_tone) - nB.size = "flat" - nB.cached_size = 0 - nB.prev_size = "flat" - to_chat(M, "Your chest feels warm, tingling with newfound sensitivity.") - M.reagents.remove_reagent(id, 5) - B = nB + B = new + if(H.dna.species.use_skintones && H.dna.features["genitals_use_skintone"]) + B.color = skintone2hex(H.skin_tone) + else if(M.dna.features["breasts_color"]) + B.color = "#[M.dna.features["breasts_color"]]" + else + B.color = skintone2hex(H.skin_tone) + B.size = "flat" + B.cached_size = 0 + B.prev_size = 0 + to_chat(H, "Your chest feels warm, tingling with newfound sensitivity.") + H.reagents.remove_reagent(id, 5) + B.Insert(H) + //If they have them, increase size. If size is comically big, limit movement and rip clothes. - B.cached_size = B.cached_size + 0.05 - if (B.cached_size >= 8.5 && B.cached_size < 9) - if(H.w_uniform || H.wear_suit) - var/target = M.get_bodypart(BODY_ZONE_CHEST) - to_chat(M, "Your breasts begin to strain against your clothes tightly!") - M.adjustOxyLoss(5, 0) - M.apply_damage(1, BRUTE, target) - B.update() + B.modify_size(0.05) + + if (ISINRANGE_EX(B.cached_size, 8.5, 9) && (H.w_uniform || H.wear_suit)) + var/target = H.get_bodypart(BODY_ZONE_CHEST) + if(!message_spam) + to_chat(H, "Your breasts begin to strain against your clothes tightly!") + message_spam = TRUE + H.adjustOxyLoss(5, 0) + H.apply_damage(1, BRUTE, target) return ..() /datum/reagent/fermi/breast_enlarger/overdose_process(mob/living/carbon/M) //Turns you into a female if male and ODing, doesn't touch nonbinary and object genders. //Acute hepatic pharmacokinesis. - if(HAS_TRAIT(M, TRAIT_PHARMA)) + if(HAS_TRAIT(M, TRAIT_PHARMA) || !M.canbearoused) var/obj/item/organ/liver/L = M.getorganslot(ORGAN_SLOT_LIVER) L.swelling+= 0.05 return ..() @@ -116,8 +112,7 @@ M.visible_message("[M] suddenly looks more feminine!", "You suddenly feel more feminine!") if(P) - P.cached_length = P.cached_length - 0.05 - P.update() + P.modify_size(-0.05) if(T) qdel(T) if(!V) @@ -141,15 +136,14 @@ var/obj/item/organ/genital/breasts/B = M.getorganslot(ORGAN_SLOT_BREASTS) if(!B) //Acute hepatic pharmacokinesis. - if(HAS_TRAIT(M, TRAIT_PHARMA)) + if(HAS_TRAIT(M, TRAIT_PHARMA) || !M.canbearoused) var/obj/item/organ/liver/L = M.getorganslot(ORGAN_SLOT_LIVER) L.swelling-= 0.05 return ..() //otherwise proceed as normal return..() - B.cached_size = B.cached_size - 0.05 - B.update() + B.modify_size(-0.05) return ..() /datum/reagent/fermi/BEsmaller_hypo @@ -176,15 +170,13 @@ var/obj/item/organ/genital/breasts/B = M.getorganslot(ORGAN_SLOT_BREASTS) if(!B) return..() - if(!M.dna.features["has_breasts"])//Fast fix for those who don't want it. - B.cached_size = B.cached_size - 0.1 - B.update() - else if(B.cached_size > (sizeConv[M.dna.features["breasts_size"]]+0.1)) - B.cached_size = B.cached_size - 0.05 - B.update() - else if(B.cached_size < (sizeConv[M.dna.features["breasts_size"]])+0.1) - B.cached_size = B.cached_size + 0.05 - B.update() + var/optimal_size = B.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) + B.modify_size(-0.05, optimal_size) + else if(B.cached_size < optimal_size) + B.modify_size(0.05, 0, optimal_size) return ..() //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -205,6 +197,7 @@ InverseChemVal = 0.35 InverseChem = "PEsmaller" //At really impure vols, it just becomes 100% inverse and shrinks instead. can_synth = FALSE + var/message_spam = FALSE /datum/reagent/fermi/penis_enlarger/on_mob_metabolize(mob/living/M) . = ..() @@ -221,55 +214,48 @@ M.reagents.remove_reagent(id, volume) return var/mob/living/carbon/human/H = M - H.genital_override = TRUE - var/obj/item/organ/genital/penis/P = M.getorganslot(ORGAN_SLOT_PENIS) - if(!P) - H.emergent_genital_call() - return + if(!H.getorganslot(ORGAN_SLOT_PENIS) && H.emergent_genital_call()) + H.genital_override = TRUE /datum/reagent/fermi/penis_enlarger/on_mob_life(mob/living/carbon/M) //Increases penis size, 5u = +1 inch. if(!ishuman(M)) - return + return ..() var/mob/living/carbon/human/H = M - var/obj/item/organ/genital/penis/P = M.getorganslot(ORGAN_SLOT_PENIS) + var/obj/item/organ/genital/penis/P = H.getorganslot(ORGAN_SLOT_PENIS) if(!P)//They do have a preponderance for escapism, or so I've heard. //If they have Acute hepatic pharmacokinesis, then route processing though liver. - if(HAS_TRAIT(M, TRAIT_PHARMA)) - var/obj/item/organ/liver/L = M.getorganslot(ORGAN_SLOT_LIVER) + if(HAS_TRAIT(H, TRAIT_PHARMA) || !H.canbearoused) + var/obj/item/organ/liver/L = H.getorganslot(ORGAN_SLOT_LIVER) if(L) - L.swelling+= 0.05 - return..() + L.swelling += 0.05 else - M.adjustToxLoss(1) - return..() + H.adjustToxLoss(1) + return ..() //otherwise proceed as normal - var/obj/item/organ/genital/penis/nP = new - nP.Insert(M) - if(nP) - nP.length = 1 - to_chat(M, "Your groin feels warm, as you feel a newly forming bulge down below.") - nP.cached_length = 1 - nP.prev_length = 1 - M.reagents.remove_reagent(id, 5) - P = nP + P = new + P.length = 1 + to_chat(H, "Your groin feels warm, as you feel a newly forming bulge down below.") + P.prev_length = 1 + H.reagents.remove_reagent(id, 5) + P.Insert(H) - P.cached_length = P.cached_length + 0.1 - if (P.cached_length >= 20.5 && P.cached_length < 21) - if(H.w_uniform || H.wear_suit) - var/target = M.get_bodypart(BODY_ZONE_CHEST) - to_chat(M, "Your cock begin to strain against your clothes tightly!") - M.apply_damage(2.5, BRUTE, target) + P.modify_size(0.1) + if (ISINRANGE_EX(P.length, 20.5, 21) && (H.w_uniform || H.wear_suit)) + var/target = H.get_bodypart(BODY_ZONE_CHEST) + if(!message_spam) + to_chat(H, "Your cock begin to strain against your clothes tightly!") + message_spam = TRUE + H.apply_damage(2.5, BRUTE, target) - P.update() return ..() /datum/reagent/fermi/penis_enlarger/overdose_process(mob/living/carbon/human/M) //Turns you into a male if female and ODing, doesn't touch nonbinary and object genders. if(!istype(M)) return ..() //Acute hepatic pharmacokinesis. - if(HAS_TRAIT(M, TRAIT_PHARMA)) + if(HAS_TRAIT(M, TRAIT_PHARMA) || !M.canbearoused) var/obj/item/organ/liver/L = M.getorganslot(ORGAN_SLOT_LIVER) L.swelling+= 0.05 return..() @@ -284,8 +270,7 @@ M.visible_message("[M] suddenly looks more masculine!", "You suddenly feel more masculine!") if(B) - B.cached_size = B.cached_size - 0.05 - B.update() + B.modify_size(-0.05) if(M.getorganslot(ORGAN_SLOT_VAGINA)) qdel(V) if(W) @@ -305,6 +290,8 @@ can_synth = FALSE /datum/reagent/fermi/PEsmaller/on_mob_life(mob/living/carbon/M) + if(!ishuman(M)) + return ..() var/mob/living/carbon/human/H = M var/obj/item/organ/genital/penis/P = H.getorganslot(ORGAN_SLOT_PENIS) if(!P) @@ -312,12 +299,9 @@ if(HAS_TRAIT(M, TRAIT_PHARMA)) var/obj/item/organ/liver/L = M.getorganslot(ORGAN_SLOT_LIVER) L.swelling-= 0.05 - return..() - - //otherwise proceed as normal return..() - P.cached_length = P.cached_length - 0.1 - P.update() + + P.modify_size(-0.1) ..() /datum/reagent/fermi/PEsmaller_hypo @@ -334,6 +318,8 @@ if(!ishuman(M)) return var/mob/living/carbon/human/H = M + if(!H.getorganslot(ORGAN_SLOT_PENIS) && H.dna.features["has_cock"]) + H.give_genital(/obj/item/organ/genital/penis) if(!H.getorganslot(ORGAN_SLOT_TESTICLES) && H.dna.features["has_balls"]) H.give_genital(/obj/item/organ/genital/testicles) @@ -341,13 +327,11 @@ var/obj/item/organ/genital/penis/P = M.getorganslot(ORGAN_SLOT_PENIS) if(!P) return ..() - if(!M.dna.features["has_cock"])//Fast fix for those who don't want it. - P.cached_length = P.cached_length - 0.2 - P.update() - else if(P.cached_length > (M.dna.features["cock_length"]+0.1)) - P.cached_length = P.cached_length - 0.1 - P.update() - else if(P.cached_length < (M.dna.features["cock_length"]+0.1)) - P.cached_length = P.cached_length + 0.1 - P.update() + var/optimal_size = M.dna.features["cock_length"] + if(!optimal_size)//Fast fix for those who don't want it. + P.modify_size(-0.2) + else if(P.length > optimal_size) + P.modify_size(-0.1, optimal_size) + else if(P.length < optimal_size) + P.modify_size(0.1, 0, optimal_size) return ..() From 8a36c007cd3384f14b1e6f3a6d347044d82250db Mon Sep 17 00:00:00 2001 From: Ghommie <42542238+Ghommie@users.noreply.github.com> Date: Thu, 3 Oct 2019 04:38:36 +0200 Subject: [PATCH 12/17] unatomized sin. --- code/modules/mob/living/carbon/human/species.dm | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm index d2e8cab240..9e3b40c9d3 100644 --- a/code/modules/mob/living/carbon/human/species.dm +++ b/code/modules/mob/living/carbon/human/species.dm @@ -507,7 +507,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) if(H.hidden_underwear) H.underwear = "Nude" else - H.saved_underwear = H.underwear + H.underwear = H.saved_underwear var/datum/sprite_accessory/underwear/bottom/B = GLOB.underwear_list[H.underwear] if(B) var/mutable_appearance/MA = mutable_appearance(B.icon, B.icon_state, -BODY_LAYER) @@ -519,7 +519,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) if(H.hidden_undershirt) H.undershirt = "Nude" else - H.saved_undershirt = H.undershirt + H.undershirt = H.saved_undershirt var/datum/sprite_accessory/underwear/top/T = GLOB.undershirt_list[H.undershirt] if(T) var/mutable_appearance/MA @@ -535,7 +535,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) if(H.hidden_socks) H.socks = "Nude" else - H.saved_socks = H.socks + H.socks = H.saved_socks var/datum/sprite_accessory/underwear/socks/S = GLOB.socks_list[H.socks] if(S) var/digilegs = (DIGITIGRADE in species_traits) ? "_d" : "" From 7c77f2d2e3b7c90c8f1a54f6b4bf5b2a0835b233 Mon Sep 17 00:00:00 2001 From: Ghommie <42542238+Ghommie@users.noreply.github.com> Date: Thu, 3 Oct 2019 08:57:35 +0200 Subject: [PATCH 13/17] testing... --- code/__DEFINES/status_effects.dm | 2 +- .../code/modules/arousal/genitals.dm | 14 +++++++++++--- .../code/modules/arousal/organs/breasts.dm | 4 ++-- .../code/modules/arousal/organs/penis.dm | 10 ++++++---- .../code/modules/arousal/organs/testicles.dm | 15 +++++---------- modular_citadel/icons/obj/genitals/hud.dmi | Bin 2019 -> 1992 bytes 6 files changed, 25 insertions(+), 20 deletions(-) diff --git a/code/__DEFINES/status_effects.dm b/code/__DEFINES/status_effects.dm index 05309333af..135a8eb679 100644 --- a/code/__DEFINES/status_effects.dm +++ b/code/__DEFINES/status_effects.dm @@ -74,7 +74,7 @@ #define STATUS_EFFECT_BREASTS_ENLARGEMENT /datum/status_effect/chem/breast_enlarger //Applied slowdown due to the ominous bulk. -#define STATUS_EFFECT_PENIS_ENLARGEMENT //More applied slowdown, just like the above. +#define STATUS_EFFECT_PENIS_ENLARGEMENT /datum/status_effect/chem/penis_enlarger //More applied slowdown, just like the above. ///////////// // NEUTRAL // ///////////// diff --git a/modular_citadel/code/modules/arousal/genitals.dm b/modular_citadel/code/modules/arousal/genitals.dm index 593874496a..d94f70ecef 100644 --- a/modular_citadel/code/modules/arousal/genitals.dm +++ b/modular_citadel/code/modules/arousal/genitals.dm @@ -16,7 +16,7 @@ var/aroused_state = FALSE //Boolean used in icon_state strings var/aroused_amount = 50 //This is a num from 0 to 100 for arousal percentage for when to use arousal state icons. var/obj/item/organ/genital/linked_organ - var/linked_organ_slot //only one of the two organs needs this to be set up. update_link() will handle linking the rest. + var/linked_organ_slot //used for linking an apparatus' organ to its other half on update_link(). var/layer_index = GENITAL_LAYER_INDEX //Order should be very important. FIRST vagina, THEN testicles, THEN penis, as this affects the order they are rendered in. /obj/item/organ/genital/Initialize(mapload, mob/living/carbon/human/H) @@ -114,7 +114,6 @@ /obj/item/organ/genital/proc/update_appearance() if(!owner || owner.stat == DEAD) aroused_state = FALSE - return /obj/item/organ/genital/on_life() if(!reagents || !owner) @@ -138,9 +137,13 @@ /obj/item/organ/genital/proc/update_link(removing = FALSE) if(!removing && owner) + if(linked_organ) + return linked_organ = owner.getorganslot(linked_organ_slot) if(linked_organ) linked_organ.linked_organ = src + linked_organ.upon_link() + upon_link() return TRUE else if(linked_organ) @@ -148,11 +151,15 @@ linked_organ = null return FALSE +//post organ duo making arrangements. +/obj/item/organ/genital/proc/upon_link() + return + /obj/item/organ/genital/Insert(mob/living/carbon/M, special = FALSE, drop_if_replaced = TRUE) . = ..() if(.) update() - RegisterSignal(owner, COMSIG_MOB_DEATH, .proc/update) + RegisterSignal(owner, COMSIG_MOB_DEATH, .proc/update_appearance) /obj/item/organ/genital/Remove(mob/living/carbon/M, special = FALSE, drop_if_replaced = TRUE) . = ..() @@ -313,6 +320,7 @@ genital_overlay.color = "#[H.dna.features["vag_color"]]" if(layer == GENITALS_FRONT_LAYER && CHECK_BITFIELD(G.genital_flags, GENITAL_THROUGH_CLOTHES)) + genital_overlay.layer = -GENITALS_EXPOSED_LAYER LAZYADD(fully_exposed, genital_overlay) // to be added to a layer with higher priority than clothes, hence the name of the bitflag. else standing += genital_overlay diff --git a/modular_citadel/code/modules/arousal/organs/breasts.dm b/modular_citadel/code/modules/arousal/organs/breasts.dm index fe502ab66e..6299f68b6c 100644 --- a/modular_citadel/code/modules/arousal/organs/breasts.dm +++ b/modular_citadel/code/modules/arousal/organs/breasts.dm @@ -68,7 +68,7 @@ /obj/item/organ/genital/breasts/modify_size(modifier, min = -INFINITY, max = INFINITY) var/new_value = CLAMP(cached_size + modifier, min, max) - if(new_value == prev_size) + if(new_value == cached_size) return prev_size = cached_size cached_size = new_value @@ -97,7 +97,7 @@ var/status_effect = owner.has_status_effect(STATUS_EFFECT_BREASTS_ENLARGEMENT) if(enlargement && !status_effect) owner.apply_status_effect(STATUS_EFFECT_BREASTS_ENLARGEMENT) - else if(status_effect) + else if(!enlargement && status_effect) owner.remove_status_effect(STATUS_EFFECT_BREASTS_ENLARGEMENT) if(rounded_cached < 16 && owner)//Because byond doesn't count from 0, I have to do this. diff --git a/modular_citadel/code/modules/arousal/organs/penis.dm b/modular_citadel/code/modules/arousal/organs/penis.dm index 5df9f30fdd..6b9e5024df 100644 --- a/modular_citadel/code/modules/arousal/organs/penis.dm +++ b/modular_citadel/code/modules/arousal/organs/penis.dm @@ -7,6 +7,7 @@ slot = ORGAN_SLOT_PENIS masturbation_verb = "stroke" genital_flags = CAN_MASTURBATE_WITH|CAN_CLIMAX_WITH + linked_organ_slot = ORGAN_SLOT_TESTICLES fluid_transfer_factor = 0.5 size = 2 //arbitrary value derived from length and girth for sprites. layer_index = PENIS_LAYER_INDEX @@ -17,13 +18,13 @@ /obj/item/organ/genital/penis/modify_size(modifier, min = -INFINITY, max = INFINITY) var/new_value = CLAMP(length + modifier, min, max) - if(new_value == prev_length) + if(new_value == length) return prev_length = length length = CLAMP(length + modifier, min, max) update() -/obj/item/organ/genital/penis/update_size() +/obj/item/organ/genital/penis/update_size(modified = FALSE) if(length < 0)//I don't actually know what round() does to negative numbers, so to be safe!! if(owner) to_chat(owner, "You feel your tallywacker shrinking away from your body as your groin flattens out!") @@ -51,10 +52,11 @@ var/status_effect = owner.has_status_effect(STATUS_EFFECT_PENIS_ENLARGEMENT) if(enlargement && !status_effect) owner.apply_status_effect(STATUS_EFFECT_PENIS_ENLARGEMENT) - else if(status_effect) + else if(!enlargement && status_effect) owner.remove_status_effect(STATUS_EFFECT_PENIS_ENLARGEMENT) if(linked_organ) - linked_organ.update_size(new_size - size) + linked_organ.size = CLAMP(size + new_size, BALLS_SIZE_MIN, BALLS_SIZE_MAX) + linked_organ.update() size = new_size if(owner) diff --git a/modular_citadel/code/modules/arousal/organs/testicles.dm b/modular_citadel/code/modules/arousal/organs/testicles.dm index 06f40b5b51..547674a5f1 100644 --- a/modular_citadel/code/modules/arousal/organs/testicles.dm +++ b/modular_citadel/code/modules/arousal/organs/testicles.dm @@ -14,7 +14,6 @@ fluid_id = "semen" masturbation_verb = "massage" layer_index = TESTICLES_LAYER_INDEX - var/size_linked = FALSE /obj/item/organ/genital/testicles/generate_fluid() if(!linked_organ && !update_link()) @@ -23,16 +22,12 @@ if(. && reagents.holder_full()) to_chat(owner, "Your balls finally feel full, again.") -/obj/item/organ/genital/testicles/update_link(removing = FALSE) - . = ..() - if(. && !size_linked) - size = linked_organ.size - update() - size_linked = TRUE +/obj/item/organ/genital/testicles/upon_link() + size = linked_organ.size + update_size() + update_appearance() -/obj/item/organ/genital/testicles/update_size(new_size) - if(new_size) - size = CLAMP(size + new_size, BALLS_SIZE_MIN, BALLS_SIZE_MAX) +/obj/item/organ/genital/testicles/update_size(modified = FALSE) switch(size) if(BALLS_SIZE_MIN) size_name = "average" diff --git a/modular_citadel/icons/obj/genitals/hud.dmi b/modular_citadel/icons/obj/genitals/hud.dmi index bf2adcb1fcdb9c7ca35d186f72e62ced787db730..f8c8643fe0c9a7fc80760f703b441094123a338e 100644 GIT binary patch delta 1163 zcmV;61a$l356BOYBmu{YCy699jBp11#Esqz2-1Q1C? zK~!jg?U?6VQehZ}A2X76S#Sd|E;(z}bamFdHE8JG$h|R-Z=HNzV{$fZ;O4Av(zID~ z504g}UM;=N)4QdYXA2LH=FOTman1``wHAs*K5g3iip^8(+qR95NF;3CO5mLLYv&)( zzC*`Oox61H)*YZnx2|0}e|PHGp?!dVJHP+oB|V8=z5Dd(9VqP^M7{_7puW;T^X^6T zlvrLszy1RT4jMdo(2(GvA;X4`7#T7&c!+rq9MHet|L}xNAeSo?a=B6w8pf4KLlsKv z7RU&*A2oW+*l`xdPnZ}oX>!QK3FEDM?3mG`&^>30QlYY-mWPKyoOP4KQzHDjfTD)lC0{k8#B3G=m zvx=l_t%!`k?_u?tsI?SCtyzuVLv+l#^%Sg&iN^0CcEiR^6l~lOi{Arm-m;Z~Et{F} zuxv^XGwuOy+)TT5+rq81J8{f=fV=nZKX^#;;QqZwf0f|@9zS{d?D_L&PoF%l z91rm5MS4a?`U{HJhu@RDeD&((A2fCk@cMP-dX}mSV&9{B)V@dcsC|#>>G~bFr|oy# zp03|g=opNzuK6%ZOfm3r*`&*2%r z2!G>?k@w5LB7^ zFV^|WNlYX%U!C}0JbK?3XP0FC_>onTUHoqzfB%aEWhEuDK#HH=0`C6j5(M{89)JHA dQ@;IGmY>1YmMPi=>Q(>%002ovPDHLkV1j69TRs2) delta 1190 zcmV;X1X=sY591GzBmv5?C9ncB0RI4yk&%v$j*^m+m6es3mzR{3lxS#Zo}QkXnwpN0 zG{yh`00DGTPE!Ct=GbNc005Aa1p|VABw8g-g~|%9elFn12LL#klEB&BPI&+T1S?5I zK~!jg?U?6Rl3^H!?=q97Eoj)Xz>@Zk-b%7vHW=DoV0-VKrK#;{d+)vX-n*>S5JNHQ zl#=#8^fJUu-fr^YdHo>Qx8J!q@WA05xE=rxR*Dt(DqbRYmSAVG|MA`>eM$;{a;Jcu z-v8mfN|i2CwoJM5zP9OGz8pJCm-2Ge`&6h{sdA+%LXmBXgjLvCv4W4QzG}7VHT?W) z)~a2nu4UG(Q@d78KffB)t5tQ)``4>4mPi5`Gz^qlrZli&g8+#{T)&>bYrawACQX|) zZ_%<<>o#rM0km)1rgf{9Et)rfYuco7BX@XN2c~1E&Ye32$-4xzpMfa2i#*7(J2D+) z)&q3y*1bp1UcGwu?$bA$DX(pb?d!$ZdkLc^7RTH98s$5_6J zzILXH3DO0CSpE_l-eNLP(ejI%dGiJ`3J;%=6dGqJbo13#{&zd=dzJ~=17cF+M zge7+^TDX9|ho#FRmU9rXY$<&YD zrOQ{Y+PQN18t)$9`i+~nZdPh>a)MNcl+oSzX z+hhGs+k^C-HeP5$qkRA2<9nsXKI66Tr1U+A65trHcUiJNoCAHbjNFs=y*fqDL5kWHPu%yP z4Tcn_7!03X@#KB4O-*x3s@646z5k7A>8VagPc!EH9MbOpFDCKVe27h7ay<3^_ZFJI ziT~o8N%+TK63_jB=YGI~=YGI*KVZdkKj5M0Li>IIfp-6YW6K)e4j==VPcY2Ty$k3rh^c>iON_C4DF7+AlPdK|3ZNj(bI z@1!0_r~hvHkq6UviOzi<$C#eMEwhoc_ Date: Thu, 3 Oct 2019 19:08:11 +0200 Subject: [PATCH 14/17] hopefully a performance improvement to stop genitalia from having to update everytime. --- code/__DEFINES/inventory.dm | 3 +++ code/modules/mob/living/carbon/human/inventory.dm | 4 +++- modular_citadel/code/modules/arousal/genitals.dm | 7 +++---- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/code/__DEFINES/inventory.dm b/code/__DEFINES/inventory.dm index 24d381d1a8..7f1360d3ac 100644 --- a/code/__DEFINES/inventory.dm +++ b/code/__DEFINES/inventory.dm @@ -237,3 +237,6 @@ GLOBAL_LIST_INIT(security_wintercoat_allowed, typecacheof(list( //Internals checker #define GET_INTERNAL_SLOTS(C) list(C.head, C.wear_mask) + +//Slots that won't trigger humans' update_genitals() on equip(). +GLOBAL_LIST_INIT(no_genitals_update_slots, list(SLOT_L_STORE, SLOT_R_STORE, SLOT_S_STORE, SLOT_IN_BACKPACK, SLOT_LEGCUFFED, SLOT_HANDCUFFED, SLOT_HANDS, SLOT_GENERC_DEXTROUS_STORAGE)) diff --git a/code/modules/mob/living/carbon/human/inventory.dm b/code/modules/mob/living/carbon/human/inventory.dm index d35df6b789..084dbd83ef 100644 --- a/code/modules/mob/living/carbon/human/inventory.dm +++ b/code/modules/mob/living/carbon/human/inventory.dm @@ -79,7 +79,8 @@ //This is an UNSAFE proc. Use mob_can_equip() before calling this one! Or rather use equip_to_slot_if_possible() or advanced_equip_to_slot_if_possible() /mob/living/carbon/human/equip_to_slot(obj/item/I, slot) - if(!..()) //a check failed or the item has already found its slot + . = ..() + if(!.) //a check failed or the item has already found its slot return var/not_handled = FALSE //Added in case we make this type path deeper one day @@ -136,6 +137,7 @@ update_inv_s_store() else to_chat(src, "You are trying to equip this item to an unsupported inventory slot. Report this to a coder!") + not_handled = TRUE //Item is handled and in slot, valid to call callback, for this proc should always be true if(!not_handled) diff --git a/modular_citadel/code/modules/arousal/genitals.dm b/modular_citadel/code/modules/arousal/genitals.dm index d94f70ecef..68759218c7 100644 --- a/modular_citadel/code/modules/arousal/genitals.dm +++ b/modular_citadel/code/modules/arousal/genitals.dm @@ -209,11 +209,10 @@ //procs to handle sprite overlays being applied to humans -/obj/item/equipped(mob/user, slot) - if(ishuman(user)) - var/mob/living/carbon/human/H = user - H.update_genitals() +/mob/living/carbon/human/equip_to_slot(obj/item/I, slot) . = ..() + if(!. && !(slot in GLOB.no_genitals_update_slots)) //the item was successfully equipped, and the chosen slot wasn't merely storage or hands. + update_genitals() /mob/living/carbon/human/doUnEquip(obj/item/I, force) . = ..() From 59e6ed701479c9fc883970ae2a6d21a7c80e8680 Mon Sep 17 00:00:00 2001 From: Ghommie <42542238+Ghommie@users.noreply.github.com> Date: Thu, 3 Oct 2019 19:09:47 +0200 Subject: [PATCH 15/17] inventory.dm is a mess too. --- modular_citadel/code/modules/arousal/genitals.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modular_citadel/code/modules/arousal/genitals.dm b/modular_citadel/code/modules/arousal/genitals.dm index 68759218c7..34c52fe51d 100644 --- a/modular_citadel/code/modules/arousal/genitals.dm +++ b/modular_citadel/code/modules/arousal/genitals.dm @@ -211,7 +211,7 @@ /mob/living/carbon/human/equip_to_slot(obj/item/I, slot) . = ..() - if(!. && !(slot in GLOB.no_genitals_update_slots)) //the item was successfully equipped, and the chosen slot wasn't merely storage or hands. + if(!. && I && slot && !(slot in GLOB.no_genitals_update_slots)) //the item was successfully equipped, and the chosen slot wasn't merely storage or hands. update_genitals() /mob/living/carbon/human/doUnEquip(obj/item/I, force) From 6bd0b85e54bc18efe5f3cd40e1b396e825c07f76 Mon Sep 17 00:00:00 2001 From: Ghommie <42542238+Ghommie@users.noreply.github.com> Date: Thu, 3 Oct 2019 19:32:11 +0200 Subject: [PATCH 16/17] I'd rather add a redundant get_held_index_of_item(I) than allow it to render privates over and over again. --- modular_citadel/code/modules/arousal/genitals.dm | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/modular_citadel/code/modules/arousal/genitals.dm b/modular_citadel/code/modules/arousal/genitals.dm index 34c52fe51d..9ecf67e4b0 100644 --- a/modular_citadel/code/modules/arousal/genitals.dm +++ b/modular_citadel/code/modules/arousal/genitals.dm @@ -211,12 +211,15 @@ /mob/living/carbon/human/equip_to_slot(obj/item/I, slot) . = ..() - if(!. && I && slot && !(slot in GLOB.no_genitals_update_slots)) //the item was successfully equipped, and the chosen slot wasn't merely storage or hands. + if(!. && I && slot && !(slot in GLOB.no_genitals_update_slots)) //the item was successfully equipped, and the chosen slot wasn't merely storage, hands or cuffs. update_genitals() -/mob/living/carbon/human/doUnEquip(obj/item/I, force) +/mob/living/carbon/human/doUnEquip(obj/item/I, force, newloc, no_move, invdrop = TRUE) + var/no_update = FALSE + if(!I || I == l_store || I == r_store || I == s_store || I == handcuffed || I == legcuffed || get_held_index_of_item(I)) //stops storages, cuffs and held items from triggering it. + no_update = TRUE . = ..() - if(!.) + if(!. || no_update) return update_genitals() From ce0ba51b61b31fa4430b9519fecfd18b0b5ceb11 Mon Sep 17 00:00:00 2001 From: Ghommie <42542238+Ghommie@users.noreply.github.com> Date: Fri, 25 Oct 2019 12:52:32 +0200 Subject: [PATCH 17/17] Fixing schlongs and death. --- modular_citadel/code/modules/arousal/organs/penis.dm | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/modular_citadel/code/modules/arousal/organs/penis.dm b/modular_citadel/code/modules/arousal/organs/penis.dm index 6b9e5024df..17cd35c144 100644 --- a/modular_citadel/code/modules/arousal/organs/penis.dm +++ b/modular_citadel/code/modules/arousal/organs/penis.dm @@ -38,11 +38,11 @@ switch(rounded_length) if(0 to 6) //If modest size new_size = 1 - if(7 to 10) //If large + if(7 to 11) //If large new_size = 2 - if(11 to 19) //If massive + if(12 to 20) //If massive new_size = 3 - if(20 to 34) //If massive and due for large effects + if(21 to 34) //If massive and due for large effects new_size = 3 enlargement = TRUE if(35 to INFINITY) //If comical