From d9c1c0248a79ce50f1098af7ba7e37af27966b30 Mon Sep 17 00:00:00 2001 From: sarcoph <83266791+sarcoph@users.noreply.github.com> Date: Tue, 3 May 2022 23:45:30 -0800 Subject: [PATCH 01/28] cleanup and typos --- .../code/modules/arousal/arousalhud.dm | 83 +++++-------- hyperstation/code/obj/farming/farming.dm | 4 +- hyperstation/code/obj/fleshlight.dm | 22 ++-- hyperstation/code/obj/pregnancytester.dm | 3 +- .../code/modules/arousal/arousal.dm | 110 +++++++----------- 5 files changed, 81 insertions(+), 141 deletions(-) diff --git a/hyperstation/code/modules/arousal/arousalhud.dm b/hyperstation/code/modules/arousal/arousalhud.dm index 509438813..2058307e9 100644 --- a/hyperstation/code/modules/arousal/arousalhud.dm +++ b/hyperstation/code/modules/arousal/arousalhud.dm @@ -11,7 +11,7 @@ for(var/obj/item/organ/genital/G in U.internal_organs) if(!G.nochange) if(!G.dontlist) - dat += "[G.mode == "hidden" ? "[G.name] (Hidden)" : (G.mode == "clothes" ? "[G.name] (Hidden by Clothes)" : (G.mode == "visable" ? "[G.name] (Visable)" : "[G.name] (Visable)"))]
" + dat += "[G.mode == "hidden" ? "[G.name] (Hidden)" : (G.mode == "clothes" ? "[G.name] (Hidden by Clothes)" : (G.mode == "visable" ? "[G.name] (Visible)" : "[G.name] (Visible)"))]
" dat += {"
Contexual Options

"} var/obj/item/organ/genital/penis/P = user.getorganslot("penis") @@ -366,33 +366,20 @@ obj/screen/arousal/proc/kiss() return /mob/living/carbon/human/proc/climaxwith(mob/living/T) - - var/mob/living/carbon/human/L = pick_partner() var/obj/item/organ/genital/picked_organ picked_organ = pick_climax_genitals() - if(picked_organ) - var/mob/living/partner = L - if(partner) - src << browse(null, "window=arousal") //alls fine, we can close the window now. - var/obj/item/organ/genital/penis/P = picked_organ - var/spillage = "No" //default to no, just incase player has items on to prevent climax - if(!P.condom == 1&&!P.sounding == 1) //you cant climax with a condom on or sounding in. - 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, FALSE, FALSE) - else - mob_climax_partner(picked_organ, partner, FALSE, FALSE, FALSE) - else - to_chat(src, "You cannot do this alone.") - return - else //They either lack organs that can masturbate, or they didn't pick one. + if(!picked_organ) to_chat(src, "You cannot climax without choosing genitals.") return - + var/mob/living/carbon/human/partner = pick_partner() + if(!partner) + to_chat(src, "You cannot do this alone.") + return + src << browse(null, "window=arousal") // close arousal window + mob_climax_partner_spillage(picked_organ, partner, FALSE) /mob/living/carbon/human/proc/climaxover(mob/living/T) - var/mob/living/carbon/human/L = T var/obj/item/organ/genital/picked_organ picked_organ = pick_climax_genitals() @@ -428,39 +415,29 @@ obj/screen/arousal/proc/kiss() H.visible_message("[H] explodes out of their clothes!'") - -/mob/living/carbon/human/proc/impregwith(mob/living/T) - - var/mob/living/carbon/human/L = pick_partner() - var/obj/item/organ/genital/picked_organ - picked_organ = src.getorganslot("penis") //Impregnation must be done with a penis. - if(picked_organ) - var/mob/living/partner = L - if(partner) - if(!partner.breedable)//check if impregable. - to_chat(src, "Your partner cannot be impregnated.")//some fuckary happening, you shouldnt even get to this point tbh. - return - var/obj/item/organ/genital/penis/P = picked_organ - //you cant impreg with a condom on or sounding in. - if(P.condom == 1) - to_chat(src, "You cannot do this action with a condom on.") - return - if(P.sounding == 1) - to_chat(src, "You cannot do this action with a sounding in.") - return - src << browse(null, "window=arousal") //alls fine, we can close the window now. - //Keeping this for messy fun - 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, TRUE, FALSE) - else - mob_climax_partner(picked_organ, partner, FALSE, TRUE, FALSE) - else - to_chat(src, "You cannot do this alone.") - return - else //no penis :( - to_chat(src, "You cannot impregnate without a penis.") +/mob/living/carbon/human/proc/impregwith(mob/living/carbon/T) + var/mob/living/carbon/human/partner = pick_partner() + var/obj/item/organ/genital/penis/picked_organ = src.getorganslot("penis") + // wow that is a lot of conditionals huh + if(!picked_organ) // no penis :( + to_chat(src, "You cannot impregnate someone without a penis.") return + if(!partner) + to_chat(src, "You cannot do this alone.") + return + if(!partner.breedable) //check if impregable. + to_chat(src, "Your partner cannot be impregnated.") + //some fuckery happening, you shouldnt even get to this point tbh. + return + if(picked_organ.condom) + to_chat(src, "You cannot impregnate someone with a condom on.") + return + if(picked_organ.sounding) + to_chat(src, "You cannot impregnate someone with a sounding rod in.") + return + src << browse(null, "window=arousal") //alls fine, we can close the window now. + mob_climax_partner_spillage(picked_organ, partner, TRUE) + /mob/living/carbon/human/proc/cumcontainer(mob/living/T) //We'll need hands and no restraints. diff --git a/hyperstation/code/obj/farming/farming.dm b/hyperstation/code/obj/farming/farming.dm index 8c203d78d..ad4671774 100644 --- a/hyperstation/code/obj/farming/farming.dm +++ b/hyperstation/code/obj/farming/farming.dm @@ -1,5 +1,5 @@ -/obj/item/reagent_containers/food/snacks/grown/wheat/ - var stacktype = /obj/item/stack/tile/hay +/obj/item/reagent_containers/food/snacks/grown/wheat + var/stacktype = /obj/item/stack/tile/hay var/tile_coefficient = 0.02 // same as grass /obj/item/reagent_containers/food/snacks/grown/wheat/attack_self(mob/user) diff --git a/hyperstation/code/obj/fleshlight.dm b/hyperstation/code/obj/fleshlight.dm index 125c7ec34..30659b3cf 100644 --- a/hyperstation/code/obj/fleshlight.dm +++ b/hyperstation/code/obj/fleshlight.dm @@ -165,22 +165,14 @@ M.adjustArousalLoss(20) M.do_jitter_animation() //make your partner shake too! - if (M.getArousalLoss() >= 100 && ishuman(M) && prob(5))//Why not have a probability to cum when someone's getting nailed with max arousal?~ - if(G.is_exposed()) //Oh yea, if vagina is not exposed, the climax will not cause a spill - M.mob_climax_outside(G, spillage = TRUE) - else - M.mob_climax_outside(G, spillage = FALSE) - - if (C.getArousalLoss() >= 100 && ishuman(C) && C.has_dna()) + // Why not have a probability to cum when someone's getting nailed with max arousal?~ + if (M.can_climax() && prob(5)) + // if vagina is not exposed, the climax will not cause a spill + M.mob_climax_outside(G, G.is_exposed()) + if (C.can_climax()) var/mob/living/carbon/human/O = C - - if( (P.condom == 1) || (P.sounding == 1)) //If coundomed and/or sounded, do not fire impreg chance - O.mob_climax_partner(P, M, FALSE, FALSE, FALSE, TRUE) - else //Else, fire impreg chance - if(G.name == "vagina") //no more spontaneous impregnations through the butt! - O.mob_climax_partner(P, M, FALSE, TRUE, FALSE, TRUE) - else - O.mob_climax_partner(P, M, FALSE, FALSE, FALSE, TRUE) + var/impreg_chance = G.name == "vagina" && !P.condom && !P.sounding + O.mob_climax_partner(P, M, FALSE, impreg_chance, FALSE, TRUE) if(option == "Lick") to_chat(M, "You feel a tongue lick you through the portal against your [G.name].") diff --git a/hyperstation/code/obj/pregnancytester.dm b/hyperstation/code/obj/pregnancytester.dm index 974fda3ab..7fd8c0b5b 100644 --- a/hyperstation/code/obj/pregnancytester.dm +++ b/hyperstation/code/obj/pregnancytester.dm @@ -31,8 +31,9 @@ /obj/item/pregnancytest/proc/test(mob/living/user) - var/obj/item/organ/genital/womb/W = user.getorganslot("womb") + if(!W) + return if(W.pregnant == 1) results = "positive" icon_state = "positive" diff --git a/modular_citadel/code/modules/arousal/arousal.dm b/modular_citadel/code/modules/arousal/arousal.dm index 5e37cbbe7..fa6b735b5 100644 --- a/modular_citadel/code/modules/arousal/arousal.dm +++ b/modular_citadel/code/modules/arousal/arousal.dm @@ -217,6 +217,9 @@ if(M.canbearoused) ui_interact(usr) +/mob/living/proc/can_climax(_arousal = 100) + return src.getArousalLoss() >= _arousal && ishuman(src) && src.has_dna() + /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" @@ -475,7 +478,7 @@ if(prob(L.impregchance)) var/obj/item/organ/genital/womb/W = L.getorganslot("womb") if(W) //check if they have a womb. - if (L.breedable == 1 && W.pregnant == 0) //Dont get pregnant again, if you are pregnant. + if (L.breedable && !W.pregnant) //Dont get pregnant again, if you are pregnant. log_game("Debug: [L] has been impregnated by [src]") to_chat(L, "You feel your hormones change, and a motherly instinct take over.") //leting them know magic has happened. W.pregnant = 1 @@ -488,12 +491,19 @@ if (B.fluid_mult < 0.5 && B) B.fluid_mult = 0.5 +/mob/living/carbon/human/proc/mob_climax_partner_spillage(obj/item/organ/genital/picked_organ, mob/living/carbon/partner, impreg = FALSE) + var/obj/item/organ/genital/penis/_penis = picked_organ + if(picked_organ.name != "penis" || _penis.sounding || _penis.condom) + mob_climax_partner(picked_organ, partner, FALSE, FALSE, FALSE) + return + var/_question = "Would your fluids spill outside?" + var/_title = "Choose overflowing option" + var/spillage = input(src, _question, _title, "Yes") as anything in list("Yes", "No") + mob_climax_partner(picked_organ, partner, spillage == "Yes", impreg, FALSE) /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.name == "penis")//if the select organ is a penis var/obj/item/organ/genital/penis/P = src.getorganslot("penis") if(P.condom) //if the penis is condomed @@ -573,43 +583,22 @@ return ret_organ return null //error stuff -/mob/living/carbon/human/proc/pick_partner_overide() //used for cumming on people without genitals exposed - var/list/partners = list() - if(src.pulling) - partners += src.pulling //Yes, even objects for now - if(src.pulledby) - partners += src.pulledby - //Now we got both of them, let's check if they're proper - for(var/I in partners) - if(isliving(I)) - else - partners -= I //No fucking objects - //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 -/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 - //Now we got both of them, let's check if they're proper +/mob/living/carbon/human/proc/pick_partner(needs_exposed = TRUE) + var/list/partners = list(src.pulling, src.pulledby) 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 - //NOW the list should only contain correct partners + if(!iscarbon(I)) + partners -= I + continue + if(!needs_exposed) + continue + var/mob/living/carbon/C = I + if(!C.exposed_genitals.len && !C.is_groin_exposed() && !C.is_chest_exposed()) + partners -= I if(!partners.len) - return null //No one left. - return input(src, "With whom?", "Sexual partner", null) in partners //pick one, default to null + return null + return input(src, "With whom?", "Sexual partner", null) as null|anything in partners + /mob/living/carbon/human/proc/pick_climax_container() var/obj/item/reagent_containers/SC = null @@ -774,45 +763,26 @@ //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() - if(picked_organ) - var/mob/living/partner = pick_partner() //Get someone - if(partner) - var/obj/item/organ/genital/penis/P = picked_organ - if(partner.breedable == 1 && picked_organ.name == "penis"&&!P.condom == 1&&!P.sounding == 1) - var/impreg = input(src, "Would this action carry the risk of pregnancy?", "Choose a option", "Yes") as anything in list("Yes", "No") - if(impreg == "Yes") //If we are impregging - 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, TRUE, FALSE) - else - mob_climax_partner(picked_organ, partner, FALSE, TRUE, FALSE) - else - 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, FALSE, FALSE) - else - mob_climax_partner(picked_organ, partner, FALSE, FALSE, FALSE) //Wow, im trash at coding, I need to find a better way of coding this, ill rewrite it later.-quote - return - - else //If we arent impregging - 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, FALSE, FALSE) - else - mob_climax_partner(picked_organ, partner, FALSE, FALSE, 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. + if(!picked_organ) to_chat(src, "You cannot climax without choosing genitals.") return + var/mob/living/carbon/partner = pick_partner() //Get someone + if(!partner) + to_chat(src, "You cannot do this alone.") + return + var/obj/item/organ/genital/penis/P = picked_organ + var/impreg = "No" + if(partner.breedable && picked_organ.name == "penis" && !P.condom && !P.sounding) + var/impreg_question = "Would this action carry the risk of pregnancy?" + var/impreg_title = "Choose a option" + impreg = input(src, impreg_question, impreg_title, "Yes") as anything in list("Yes", "No") + mob_climax_partner_spillage(picked_organ, partner, impreg == "Yes") + if("Climax over partner") var/obj/item/organ/genital/picked_organ picked_organ = pick_climax_genitals() if(picked_organ) - var/mob/living/partner = pick_partner_overide() //Get your partner, clothed or not. + var/mob/living/partner = pick_partner(FALSE) //Get your partner, clothed or not. if(partner) mob_climax_partner(picked_organ, partner, FALSE, FALSE, TRUE) else From d84debe29e3a0f01f3cf6ecafa07a7456ae42db1 Mon Sep 17 00:00:00 2001 From: sarcoph <83266791+sarcoph@users.noreply.github.com> Date: Wed, 4 May 2022 12:40:29 -0800 Subject: [PATCH 02/28] pregnancy test cleanup + condensing climax stat checks --- .../mob/living/carbon/human/species.dm | 4 +- code/modules/mob/living/carbon/life.dm | 2 +- .../ruins/objects_and_mobs/sin_ruins.dm | 4 +- hyperstation/code/obj/fleshlight.dm | 2 +- hyperstation/code/obj/pregnancytester.dm | 41 ++++++++----------- hyperstation/code/obj/vibrator.dm | 4 +- .../subtypes/manipulation.dm | 2 +- .../modules/reagents/reagents/cit_reagents.dm | 2 +- 8 files changed, 28 insertions(+), 33 deletions(-) diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm index a036dbb7f..4764523ed 100644 --- a/code/modules/mob/living/carbon/human/species.dm +++ b/code/modules/mob/living/carbon/human/species.dm @@ -1647,7 +1647,7 @@ GLOBAL_LIST_EMPTY(roundstart_races) ) if (target.canbearoused) target.adjustArousalLoss(5) - if (target.getArousalLoss() >= 100 && ishuman(target) && HAS_TRAIT(target, TRAIT_MASO) && target.has_dna()) + if (target.can_climax() && HAS_TRAIT(target, TRAIT_MASO)) target.mob_climax(forced_climax=TRUE) if (!HAS_TRAIT(target, TRAIT_NYMPHO)) stop_wagging_tail(target) @@ -2005,7 +2005,7 @@ GLOBAL_LIST_EMPTY(roundstart_races) H.update_damage_overlays() if(HAS_TRAIT(H, TRAIT_MASO)) H.adjustArousalLoss(damage * brutemod * H.physiology.brute_mod) - if (H.getArousalLoss() >= 100 && ishuman(H) && H.has_dna()) + if (H.can_climax()) H.mob_climax(forced_climax=TRUE) else//no bodypart, we deal damage with a more general method. diff --git a/code/modules/mob/living/carbon/life.dm b/code/modules/mob/living/carbon/life.dm index ca11c14d0..45160b35f 100644 --- a/code/modules/mob/living/carbon/life.dm +++ b/code/modules/mob/living/carbon/life.dm @@ -77,7 +77,7 @@ var/mob/living/carbon/human/B = src if(HAS_TRAIT(B, TRAIT_CHOKE_SLUT)) B.adjustArousalLoss(7) - if (B.getArousalLoss() >= 100 && ishuman(B) && B.has_dna()) + if (B.can_climax()) B.mob_climax(forced_climax=TRUE) else SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "suffocation", /datum/mood_event/suffocation) diff --git a/code/modules/ruins/objects_and_mobs/sin_ruins.dm b/code/modules/ruins/objects_and_mobs/sin_ruins.dm index 18e90b3a6..2e7f1c55c 100644 --- a/code/modules/ruins/objects_and_mobs/sin_ruins.dm +++ b/code/modules/ruins/objects_and_mobs/sin_ruins.dm @@ -282,13 +282,13 @@ . = ..() if(.) return - if(chalice_taken == 1) + if(chalice_taken) to_chat(user, "You hear a voice in your head... \"My chalice has already been taken, dear. I cannot give you another...\"") return if(user.getArousalLoss() < 100) to_chat(user, "You hear a voice in your head... \"You are not horny enough to receive my blessing, dear~\"") return - if (ishuman(user) && user.has_dna()) + if (user.can_climax(0)) user.mob_climax(forced_climax=TRUE) to_chat(user, "You hear a voice in your head... \"You are worth of my blessing dear~\"") to_chat(user, "You feel overpowering pleasure surge through your entire body.") diff --git a/hyperstation/code/obj/fleshlight.dm b/hyperstation/code/obj/fleshlight.dm index 30659b3cf..7af123ce5 100644 --- a/hyperstation/code/obj/fleshlight.dm +++ b/hyperstation/code/obj/fleshlight.dm @@ -63,7 +63,7 @@ C.do_jitter_animation() C.adjustArousalLoss(20) //make the target more aroused. - if (C.getArousalLoss() >= 100 && ishuman(C) && C.has_dna()) + if (C.can_climax()) C.mob_climax(forced_climax=TRUE) //make them cum if they are over the edge. return diff --git a/hyperstation/code/obj/pregnancytester.dm b/hyperstation/code/obj/pregnancytester.dm index 7fd8c0b5b..51e4786c4 100644 --- a/hyperstation/code/obj/pregnancytester.dm +++ b/hyperstation/code/obj/pregnancytester.dm @@ -8,7 +8,6 @@ var/results = "null" w_class = WEIGHT_CLASS_TINY - /obj/item/pregnancytest/attack_self(mob/user) if(QDELETED(src)) return @@ -16,29 +15,25 @@ return if(isAI(user)) return - if(user.stat > 0)//unconscious or dead + if(user.stat > CONSCIOUS)//unconscious or dead return - if(status == 1) - return //Already been used once, pregnancy tests only work once. - test(user) + Test(user) -/obj/item/pregnancytest/proc/force(mob/living/user) - //Force it negative - icon_state = "negative" - name = "[results] pregnancy test" - status = 1 - to_chat(user, "You use the pregnancy test, the display reads negative!") - - -/obj/item/pregnancytest/proc/test(mob/living/user) +/obj/item/pregnancytest/proc/Test(mob/living/user) + if(status) + return + var/_result = FALSE var/obj/item/organ/genital/womb/W = user.getorganslot("womb") if(!W) - return - if(W.pregnant == 1) - results = "positive" - icon_state = "positive" - name = "[results] pregnancy test" - status = 1 - to_chat(user, "You use the pregnancy test, the display reads positive!") - else - force(user) \ No newline at end of file + return // no reason to waste the single-use on them + if(W.pregnant) + _result = TRUE + UpdateResult(user, _result) + +/obj/item/pregnancytest/proc/UpdateResult(mob/living/user, _result) + var/result_text = _result ? "positive" : "negative" + results = result_text + icon_state = result_text + name = "[results] preganancy test" + status = TRUE + to_chat(user, "You use the pregnancy test, the display reads [results]!") \ No newline at end of file diff --git a/hyperstation/code/obj/vibrator.dm b/hyperstation/code/obj/vibrator.dm index 51f495945..e7433a927 100644 --- a/hyperstation/code/obj/vibrator.dm +++ b/hyperstation/code/obj/vibrator.dm @@ -132,13 +132,13 @@ Code: if(2) //med, can make you cum to_chat(U, "You feel intense pleasure surge through your [G.name]") U.do_jitter_animation() - if (U.getArousalLoss() >= 100 && ishuman(U) && U.has_dna()) + if (U.can_climax()) U.mob_climax(forced_climax=TRUE) if(3) //high, makes you stun to_chat(U, "You feel overpowering pleasure surge through your [G.name]") U.Jitter(3) U.Stun(30) - if (U.getArousalLoss() >= 100 && ishuman(U) && U.has_dna()) + if (U.can_climax()) U.mob_climax(forced_climax=TRUE) if(prob(50)) U.emote("moan") diff --git a/modular_citadel/code/modules/integrated_electronics/subtypes/manipulation.dm b/modular_citadel/code/modules/integrated_electronics/subtypes/manipulation.dm index 547c1a576..5302e1b99 100644 --- a/modular_citadel/code/modules/integrated_electronics/subtypes/manipulation.dm +++ b/modular_citadel/code/modules/integrated_electronics/subtypes/manipulation.dm @@ -25,7 +25,7 @@ if(ismob(M) && M.canbearoused && arousal_gain != 0) var/orgasm = FALSE if(arousal_gain > 0) - if(M.getArousalLoss() >= 100 && ishuman(M) && M.has_dna()) + if(M.can_climax()) var/mob/living/carbon/human/H = M var/orgasm_message = pick("A sharp pulse of electricity pushes you to orgasm!", "You feel a jolt of electricity force you into orgasm!") H.visible_message("\The [assembly] electrodes shock [H]!", "[orgasm_message]") diff --git a/modular_citadel/code/modules/reagents/reagents/cit_reagents.dm b/modular_citadel/code/modules/reagents/reagents/cit_reagents.dm index 324b44db3..6ddb87619 100644 --- a/modular_citadel/code/modules/reagents/reagents/cit_reagents.dm +++ b/modular_citadel/code/modules/reagents/reagents/cit_reagents.dm @@ -197,7 +197,7 @@ /datum/reagent/drug/aphrodisiacplus/overdose_process(mob/living/M) if(M && M.canbearoused && !(M.client?.prefs.cit_toggles & NO_APHRO) && prob(33)) - if(prob(5) && M.getArousalLoss() >= 100 && ishuman(M) && M.has_dna()) + if(prob(5) && M.can_climax()) if(prob(5)) //Less spam to_chat(M, "Your libido is going haywire!") if(M.min_arousal < 50) From 49f8b5caace62e1f4633ccf843c1710982246403 Mon Sep 17 00:00:00 2001 From: sarcoph <83266791+sarcoph@users.noreply.github.com> Date: Wed, 4 May 2022 13:55:30 -0800 Subject: [PATCH 03/28] tweak realized you need it to be 100 to work --- code/modules/ruins/objects_and_mobs/sin_ruins.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/ruins/objects_and_mobs/sin_ruins.dm b/code/modules/ruins/objects_and_mobs/sin_ruins.dm index 2e7f1c55c..47d489d3f 100644 --- a/code/modules/ruins/objects_and_mobs/sin_ruins.dm +++ b/code/modules/ruins/objects_and_mobs/sin_ruins.dm @@ -288,7 +288,7 @@ if(user.getArousalLoss() < 100) to_chat(user, "You hear a voice in your head... \"You are not horny enough to receive my blessing, dear~\"") return - if (user.can_climax(0)) + if(user.can_climax()) user.mob_climax(forced_climax=TRUE) to_chat(user, "You hear a voice in your head... \"You are worth of my blessing dear~\"") to_chat(user, "You feel overpowering pleasure surge through your entire body.") From d7c8a05eb0988f982c245a234be164c2ec18734a Mon Sep 17 00:00:00 2001 From: sarcoph <83266791+sarcoph@users.noreply.github.com> Date: Wed, 4 May 2022 14:03:47 -0800 Subject: [PATCH 04/28] check if there is a user for pregnancy test for admin command calls --- hyperstation/code/obj/pregnancytester.dm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hyperstation/code/obj/pregnancytester.dm b/hyperstation/code/obj/pregnancytester.dm index 51e4786c4..f8c12ab55 100644 --- a/hyperstation/code/obj/pregnancytester.dm +++ b/hyperstation/code/obj/pregnancytester.dm @@ -36,4 +36,5 @@ icon_state = result_text name = "[results] preganancy test" status = TRUE - to_chat(user, "You use the pregnancy test, the display reads [results]!") \ No newline at end of file + if(user) + to_chat(user, "You use the pregnancy test, the display reads [results]!") \ No newline at end of file From 227a298150b4cd4ad7fef9a96bb0cf1ea3600e13 Mon Sep 17 00:00:00 2001 From: sarcoph <83266791+sarcoph@users.noreply.github.com> Date: Wed, 4 May 2022 14:21:20 -0800 Subject: [PATCH 05/28] slightly more descriptive variables for portal fleshlights --- .../code/modules/arousal/arousalhud.dm | 3 +- hyperstation/code/obj/fleshlight.dm | 91 +++++++------------ 2 files changed, 33 insertions(+), 61 deletions(-) diff --git a/hyperstation/code/modules/arousal/arousalhud.dm b/hyperstation/code/modules/arousal/arousalhud.dm index 2058307e9..802f43c90 100644 --- a/hyperstation/code/modules/arousal/arousalhud.dm +++ b/hyperstation/code/modules/arousal/arousalhud.dm @@ -380,12 +380,11 @@ obj/screen/arousal/proc/kiss() /mob/living/carbon/human/proc/climaxover(mob/living/T) - var/mob/living/carbon/human/L = T + var/mob/living/carbon/human/partner = T var/obj/item/organ/genital/picked_organ picked_organ = pick_climax_genitals() if(picked_organ) src << browse(null, "window=arousal") //alls fine, we can close the window now. - var/mob/living/partner = L if(partner) var/obj/item/organ/genital/penis/P = picked_organ if(P.condom == 1) diff --git a/hyperstation/code/obj/fleshlight.dm b/hyperstation/code/obj/fleshlight.dm index 7af123ce5..bc7e4d0df 100644 --- a/hyperstation/code/obj/fleshlight.dm +++ b/hyperstation/code/obj/fleshlight.dm @@ -77,7 +77,6 @@ //Hyperstation 13 portal fleshlight //kinky! - /obj/item/portallight name = "portal fleshlight" desc = "A silver love(TM) fleshlight, used to stimulate someones penis, with bluespace tech that allows lovers to hump at a distance." @@ -104,45 +103,39 @@ else . += "The device is paired, and awaiting input. " -/obj/item/portallight/attack(mob/living/carbon/C, mob/living/user) //use portallight! nearly the same as the fleshlight apart from you have a buddy! - var/obj/item/organ/genital/penis/P = C.getorganslot("penis") - +/obj/item/portallight/attack(mob/living/carbon/holder, mob/living/user) +//use portallight! nearly the same as the fleshlight apart from you have a buddy! + var/obj/item/organ/genital/penis/P = holder.getorganslot("penis") if(inuse) //just to stop stacking and causing people to cum instantly return if(!useable) to_chat(user, "It seems the device has failed or your partner is not wearing their device.") - - if(C == user)//if your using it on yourself, more options! otherwise, just fuck. + if(holder == user)//if your using it on yourself, more options! otherwise, just fuck. option = input(usr, "Choose action", "Portal Fleshlight", "Fuck") in list("Fuck", "Lick", "Touch") else option = "Fuck" - - var/obj/item/organ/genital/G + var/obj/item/organ/genital/target_genital if(istype(portalunderwear.loc, /obj/item/organ/genital)) //Sanity check. Without this it will runtime error. - G = portalunderwear.loc - if(!G) + target_genital = portalunderwear.loc + if(!target_genital) return - var/mob/living/carbon/human/M = G.owner - + var/mob/living/carbon/human/target = target_genital.owner if(option == "Fuck"&&!P.is_exposed()) //we are trying to fuck with no penis! to_chat(user, "You don't see anywhere to use this on.") return else //other options dont need checks inuse = 1 - if(!(C == user)) //if we are targeting someone else. - C.visible_message("[user] is trying to use [src] on [C]'s penis.", "[user] is trying to use [src] on your penis.") - - if(!do_mob(user, C, 3 SECONDS)) //3 second delay + if(!(holder == user)) //if we are targeting someone else. + holder.visible_message("[user] is trying to use [src] on [holder]'s penis.", "[user] is trying to use [src] on your penis.") + if(!do_mob(user, holder, 3 SECONDS)) //3 second delay inuse = 0 return - //checked if not used on yourself, if not, carry on. if(option == "Fuck") playsound(src, 'sound/lewd/slaps.ogg', 30, 1, -1) //slapping sound for fuck. - inuse = 0 - if(!(C == user)) - C.visible_message("[user] pumps [src] on [C]'s penis.", "[user] pumps [src] up and down on your penis.") + if(!(holder == user)) + holder.visible_message("[user] pumps [src] on [holder]'s penis.", "[user] pumps [src] up and down on your penis.") else if(option == "Fuck") user.visible_message("[user] pumps [src] on their penis.", "You pump the fleshlight on your penis.") @@ -150,82 +143,68 @@ user.visible_message("[user] licks into [src].", "You lick into [src].") if(option == "Touch") user.visible_message("[user] touches softly against [src].", "You touch softly on [src].") - - if(prob(30)) //30% chance to make your partner moan. - M.emote("moan") - + target.emote("moan") if(option == "Fuck")// normal fuck - to_chat(M, "You feel a [P.length] inch, [P.shape] shaped penis pumping through the portal into your [G.name].")//message your partner, and kinky! + to_chat(target, "You feel a [P.length] inch, [P.shape] shaped penis pumping through the portal into your [target_genital.name].")//message your partner, and kinky! if(prob(30)) //30% chance to make them moan. - C.emote("moan") + holder.emote("moan") if(prob(30)) //30% chance to make your partner moan. - M.emote("moan") - C.adjustArousalLoss(20) - M.adjustArousalLoss(20) - M.do_jitter_animation() //make your partner shake too! - + target.emote("moan") + holder.adjustArousalLoss(20) + target.adjustArousalLoss(20) + target.do_jitter_animation() //make your partner shake too! // Why not have a probability to cum when someone's getting nailed with max arousal?~ - if (M.can_climax() && prob(5)) + if (target.can_climax() && prob(5)) // if vagina is not exposed, the climax will not cause a spill - M.mob_climax_outside(G, G.is_exposed()) - if (C.can_climax()) - var/mob/living/carbon/human/O = C - var/impreg_chance = G.name == "vagina" && !P.condom && !P.sounding - O.mob_climax_partner(P, M, FALSE, impreg_chance, FALSE, TRUE) - + target.mob_climax_outside(target_genital, target_genital.is_exposed()) + if (holder.can_climax()) + var/mob/living/carbon/human/O = holder + var/impreg_chance = target_genital.name == "vagina" && !P.condom && !P.sounding + O.mob_climax_partner(P, target, FALSE, impreg_chance, FALSE, TRUE) if(option == "Lick") - to_chat(M, "You feel a tongue lick you through the portal against your [G.name].") - M.adjustArousalLoss(10) + to_chat(target, "You feel a tongue lick you through the portal against your [target_genital.name].") + target.adjustArousalLoss(10) if(option == "Touch") - to_chat(M, "You feel someone touching your [G.name] through the portal.") - M.adjustArousalLoss(5) - + to_chat(target, "You feel someone touching your [target_genital.name] through the portal.") + target.adjustArousalLoss(5) return ..() /obj/item/portallight/proc/updatesleeve() //get their looks and vagina colour! cut_overlays()//remove current overlays - var/obj/item/organ/genital/G if(istype(portalunderwear.loc, /obj/item/organ/genital)) //Sanity check. Without this it will runtime. G = portalunderwear.loc if(!G) useable = FALSE return - var/mob/living/carbon/human/H = G.owner - if(H) //if the portal panties are on someone. sleeve = mutable_appearance('hyperstation/icons/obj/fleshlight.dmi', "portal_sleeve_normal") if(H.dna.species.name == "Lizardperson") // lizard nerd sleeve = mutable_appearance('hyperstation/icons/obj/fleshlight.dmi', "portal_sleeve_lizard") - if(H.dna.species.name == "Slimeperson") // slime nerd sleeve = mutable_appearance('hyperstation/icons/obj/fleshlight.dmi', "portal_sleeve_slime") - if(H.dna.species.name == "Avian") // bird nerd sleeve = mutable_appearance('hyperstation/icons/obj/fleshlight.dmi', "portal_sleeve_avian") - sleeve.color = "#" + H.dna.features["mcolor"] add_overlay(sleeve) - if(G.name == "vagina") organ = mutable_appearance('hyperstation/icons/obj/fleshlight.dmi', "portal_vag") organ.color = portalunderwear.loc.color if(G.name == "anus") organ = mutable_appearance('hyperstation/icons/obj/fleshlight.dmi', "portal_anus") organ.color = "#" + H.dna.features["mcolor"] - useable = TRUE add_overlay(organ) else useable = FALSE + //Hyperstation 13 portal underwear //can be attached to vagina or anus, just like the vibrator, still requires pairing with the portallight - /obj/item/portalpanties name = "portal panties" desc = "A silver love(TM) pair of portal underwear, with bluespace tech allows lovers to hump at a distance. Needs to be paired with a portal fleshlight before use." @@ -244,7 +223,6 @@ else . += "The device is paired, and awaiting attachment. " - /obj/item/portalpanties/attackby(obj/item/I, mob/living/user) //pairing if(istype(I, /obj/item/portallight)) var/obj/item/portallight/P = I @@ -260,11 +238,9 @@ ..() //just allows people to hit it with other objects, if they so wished. /obj/item/portalpanties/attack(mob/living/carbon/C, mob/living/user) - if(!portallight) //we arent paired yet! noobie trap, let them know. to_chat(user, "[src] can only be attached once paired with a portal fleshlight.") return - var/obj/item/organ/genital/picked_organ var/mob/living/carbon/human/S = user var/mob/living/carbon/human/T = C @@ -274,21 +250,17 @@ "[user] is trying to put [src] on you!") if(!do_mob(user, C, 3 SECONDS))//warn them and have a delay of 5 seconds to apply. return - if((picked_organ.name == "vagina")||(picked_organ.name == "anus")) //only fits on a vagina or anus - src.shapetype = picked_organ.name if(!picked_organ.equipment) to_chat(user, "You wrap [src] around [T]'s [picked_organ.name].") else to_chat(user, "They already have [picked_organ.equipment.name] there.") return - if(!user.transferItemToLoc(src, picked_organ)) //check if you can put it in return src.attached = TRUE picked_organ.equipment = src - var/obj/item/portallight/P = portallight //now we need to send what they look like, but saddly if the person changes colour for what ever reason, it wont update. but dont tell people shh. if(P) //just to make sure @@ -304,6 +276,7 @@ var/obj/item/portallight/P = portallight P.updatesleeve() + /obj/item/storage/box/portallight name = "Portal Fleshlight and Underwear" icon = 'hyperstation/icons/obj/fleshlight.dmi' From e91606bc60ba22a11450cda6bfaaaaa9382d27ee Mon Sep 17 00:00:00 2001 From: sarcoph <83266791+sarcoph@users.noreply.github.com> Date: Wed, 4 May 2022 14:43:22 -0800 Subject: [PATCH 06/28] can_climax() -> can_orgasm() makes the separation between body climax and genital climax clearer, as genitals have a can_climax variable --- code/modules/mob/living/carbon/human/species.dm | 4 ++-- code/modules/mob/living/carbon/life.dm | 2 +- code/modules/ruins/objects_and_mobs/sin_ruins.dm | 2 +- hyperstation/code/obj/fleshlight.dm | 6 +++--- hyperstation/code/obj/pregnancytester.dm | 12 ++++++------ hyperstation/code/obj/vibrator.dm | 4 ++-- modular_citadel/code/modules/arousal/arousal.dm | 4 ++-- .../integrated_electronics/subtypes/manipulation.dm | 2 +- .../code/modules/reagents/reagents/cit_reagents.dm | 2 +- 9 files changed, 19 insertions(+), 19 deletions(-) diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm index 4764523ed..344615093 100644 --- a/code/modules/mob/living/carbon/human/species.dm +++ b/code/modules/mob/living/carbon/human/species.dm @@ -1647,7 +1647,7 @@ GLOBAL_LIST_EMPTY(roundstart_races) ) if (target.canbearoused) target.adjustArousalLoss(5) - if (target.can_climax() && HAS_TRAIT(target, TRAIT_MASO)) + if (target.can_orgasm() && HAS_TRAIT(target, TRAIT_MASO)) target.mob_climax(forced_climax=TRUE) if (!HAS_TRAIT(target, TRAIT_NYMPHO)) stop_wagging_tail(target) @@ -2005,7 +2005,7 @@ GLOBAL_LIST_EMPTY(roundstart_races) H.update_damage_overlays() if(HAS_TRAIT(H, TRAIT_MASO)) H.adjustArousalLoss(damage * brutemod * H.physiology.brute_mod) - if (H.can_climax()) + if (H.can_orgasm()) H.mob_climax(forced_climax=TRUE) else//no bodypart, we deal damage with a more general method. diff --git a/code/modules/mob/living/carbon/life.dm b/code/modules/mob/living/carbon/life.dm index 45160b35f..471109572 100644 --- a/code/modules/mob/living/carbon/life.dm +++ b/code/modules/mob/living/carbon/life.dm @@ -77,7 +77,7 @@ var/mob/living/carbon/human/B = src if(HAS_TRAIT(B, TRAIT_CHOKE_SLUT)) B.adjustArousalLoss(7) - if (B.can_climax()) + if (B.can_orgasm()) B.mob_climax(forced_climax=TRUE) else SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "suffocation", /datum/mood_event/suffocation) diff --git a/code/modules/ruins/objects_and_mobs/sin_ruins.dm b/code/modules/ruins/objects_and_mobs/sin_ruins.dm index 47d489d3f..31fbecea0 100644 --- a/code/modules/ruins/objects_and_mobs/sin_ruins.dm +++ b/code/modules/ruins/objects_and_mobs/sin_ruins.dm @@ -288,7 +288,7 @@ if(user.getArousalLoss() < 100) to_chat(user, "You hear a voice in your head... \"You are not horny enough to receive my blessing, dear~\"") return - if(user.can_climax()) + if(user.can_orgasm()) user.mob_climax(forced_climax=TRUE) to_chat(user, "You hear a voice in your head... \"You are worth of my blessing dear~\"") to_chat(user, "You feel overpowering pleasure surge through your entire body.") diff --git a/hyperstation/code/obj/fleshlight.dm b/hyperstation/code/obj/fleshlight.dm index bc7e4d0df..ce98c62e6 100644 --- a/hyperstation/code/obj/fleshlight.dm +++ b/hyperstation/code/obj/fleshlight.dm @@ -63,7 +63,7 @@ C.do_jitter_animation() C.adjustArousalLoss(20) //make the target more aroused. - if (C.can_climax()) + if (C.can_orgasm()) C.mob_climax(forced_climax=TRUE) //make them cum if they are over the edge. return @@ -155,10 +155,10 @@ target.adjustArousalLoss(20) target.do_jitter_animation() //make your partner shake too! // Why not have a probability to cum when someone's getting nailed with max arousal?~ - if (target.can_climax() && prob(5)) + if (target.can_orgasm() && prob(5)) // if vagina is not exposed, the climax will not cause a spill target.mob_climax_outside(target_genital, target_genital.is_exposed()) - if (holder.can_climax()) + if (holder.can_orgasm()) var/mob/living/carbon/human/O = holder var/impreg_chance = target_genital.name == "vagina" && !P.condom && !P.sounding O.mob_climax_partner(P, target, FALSE, impreg_chance, FALSE, TRUE) diff --git a/hyperstation/code/obj/pregnancytester.dm b/hyperstation/code/obj/pregnancytester.dm index f8c12ab55..d08610271 100644 --- a/hyperstation/code/obj/pregnancytester.dm +++ b/hyperstation/code/obj/pregnancytester.dm @@ -22,17 +22,17 @@ /obj/item/pregnancytest/proc/Test(mob/living/user) if(status) return - var/_result = FALSE + var/_results = FALSE var/obj/item/organ/genital/womb/W = user.getorganslot("womb") if(!W) return // no reason to waste the single-use on them if(W.pregnant) - _result = TRUE - UpdateResult(user, _result) + _results = TRUE + UpdateResult(user, _results) -/obj/item/pregnancytest/proc/UpdateResult(mob/living/user, _result) - var/result_text = _result ? "positive" : "negative" - results = result_text +/obj/item/pregnancytest/proc/UpdateResult(mob/living/user, results) + var/result_text = results ? "positive" : "negative" + src.results = result_text icon_state = result_text name = "[results] preganancy test" status = TRUE diff --git a/hyperstation/code/obj/vibrator.dm b/hyperstation/code/obj/vibrator.dm index e7433a927..8eedff37e 100644 --- a/hyperstation/code/obj/vibrator.dm +++ b/hyperstation/code/obj/vibrator.dm @@ -132,13 +132,13 @@ Code: if(2) //med, can make you cum to_chat(U, "You feel intense pleasure surge through your [G.name]") U.do_jitter_animation() - if (U.can_climax()) + if (U.can_orgasm()) U.mob_climax(forced_climax=TRUE) if(3) //high, makes you stun to_chat(U, "You feel overpowering pleasure surge through your [G.name]") U.Jitter(3) U.Stun(30) - if (U.can_climax()) + if (U.can_orgasm()) U.mob_climax(forced_climax=TRUE) if(prob(50)) U.emote("moan") diff --git a/modular_citadel/code/modules/arousal/arousal.dm b/modular_citadel/code/modules/arousal/arousal.dm index fa6b735b5..34e2dbbe9 100644 --- a/modular_citadel/code/modules/arousal/arousal.dm +++ b/modular_citadel/code/modules/arousal/arousal.dm @@ -217,8 +217,8 @@ if(M.canbearoused) ui_interact(usr) -/mob/living/proc/can_climax(_arousal = 100) - return src.getArousalLoss() >= _arousal && ishuman(src) && src.has_dna() +/mob/living/proc/can_orgasm(arousal = 100) + return src.getArousalLoss() >= arousal && ishuman(src) && src.has_dna() /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" diff --git a/modular_citadel/code/modules/integrated_electronics/subtypes/manipulation.dm b/modular_citadel/code/modules/integrated_electronics/subtypes/manipulation.dm index 5302e1b99..5ce3ae234 100644 --- a/modular_citadel/code/modules/integrated_electronics/subtypes/manipulation.dm +++ b/modular_citadel/code/modules/integrated_electronics/subtypes/manipulation.dm @@ -25,7 +25,7 @@ if(ismob(M) && M.canbearoused && arousal_gain != 0) var/orgasm = FALSE if(arousal_gain > 0) - if(M.can_climax()) + if(M.can_orgasm()) var/mob/living/carbon/human/H = M var/orgasm_message = pick("A sharp pulse of electricity pushes you to orgasm!", "You feel a jolt of electricity force you into orgasm!") H.visible_message("\The [assembly] electrodes shock [H]!", "[orgasm_message]") diff --git a/modular_citadel/code/modules/reagents/reagents/cit_reagents.dm b/modular_citadel/code/modules/reagents/reagents/cit_reagents.dm index 6ddb87619..30c528cc0 100644 --- a/modular_citadel/code/modules/reagents/reagents/cit_reagents.dm +++ b/modular_citadel/code/modules/reagents/reagents/cit_reagents.dm @@ -197,7 +197,7 @@ /datum/reagent/drug/aphrodisiacplus/overdose_process(mob/living/M) if(M && M.canbearoused && !(M.client?.prefs.cit_toggles & NO_APHRO) && prob(33)) - if(prob(5) && M.can_climax()) + if(prob(5) && M.can_orgasm()) if(prob(5)) //Less spam to_chat(M, "Your libido is going haywire!") if(M.min_arousal < 50) From f8d9eecec5cff0b7687ba79349ff15ebf774a383 Mon Sep 17 00:00:00 2001 From: sarcoph <83266791+sarcoph@users.noreply.github.com> Date: Wed, 4 May 2022 15:38:46 -0800 Subject: [PATCH 07/28] fixing arousal% redundancy + butt sprite --- .../code/modules/arousal/arousalhud.dm | 16 ++--- hyperstation/icons/obj/genitals/butt.dmi | Bin 2723 -> 2632 bytes .../code/modules/arousal/arousal.dm | 55 +++++------------- 3 files changed, 22 insertions(+), 49 deletions(-) diff --git a/hyperstation/code/modules/arousal/arousalhud.dm b/hyperstation/code/modules/arousal/arousalhud.dm index 802f43c90..264735710 100644 --- a/hyperstation/code/modules/arousal/arousalhud.dm +++ b/hyperstation/code/modules/arousal/arousalhud.dm @@ -140,7 +140,7 @@ T.toggle_visibility(picked_visibility) if(href_list["masturbate"]) - if (H.arousalloss >= (H.max_arousal / 100) * 33) //requires 33% arousal. + if (H.arousalloss >= H.isPercentAroused(33)) //requires 33% arousal. H.solomasturbate() return else @@ -148,7 +148,7 @@ return if(href_list["container"]) - if (H.arousalloss >= (H.max_arousal / 100) * 33) //requires 33% arousal. + if (H.arousalloss >= H.isPercentAroused(33)) //requires 33% arousal. H.cumcontainer() return else @@ -156,7 +156,7 @@ return if(href_list["clothesplosion"]) - if (H.arousalloss >= (H.max_arousal / 100) * 33) //Requires 33% arousal. + if (H.arousalloss >= H.isPercentAroused(33)) //Requires 33% arousal. H.clothesplosion() return else @@ -164,7 +164,7 @@ return if(href_list["climaxself"]) - if (H.arousalloss >= (H.max_arousal / 100) * 33) //requires 33% arousal. + if (H.arousalloss >= H.isPercentAroused(33)) //requires 33% arousal. H.climaxself() return else @@ -172,7 +172,7 @@ return if(href_list["climax"]) - if (H.arousalloss >= (H.max_arousal / 100) * 33) //requires 33% arousal. + if (H.arousalloss >= H.isPercentAroused(33)) //requires 33% arousal. H.climaxalone(FALSE) return else @@ -180,7 +180,7 @@ return if(href_list["climaxover"]) - if (H.arousalloss >= (H.max_arousal / 100) * 33) //requires 33% arousal. + if (H.arousalloss >= H.isPercentAroused(33)) //requires 33% arousal. H.climaxover(usr.pulling) return else @@ -188,7 +188,7 @@ return if(href_list["climaxwith"]) - if (H.arousalloss >= (H.max_arousal / 100) * 33) //requires 33% arousal. + if (H.arousalloss >= H.isPercentAroused(33)) //requires 33% arousal. H.climaxwith(usr.pulling) return else @@ -196,7 +196,7 @@ return if(href_list["impreg"]) - if (H.arousalloss >= (H.max_arousal / 100) * 33) //requires 33% arousal. + if (H.arousalloss >= H.isPercentAroused(33)) //requires 33% arousal. H.impregwith(usr.pulling) return else diff --git a/hyperstation/icons/obj/genitals/butt.dmi b/hyperstation/icons/obj/genitals/butt.dmi index 55f746287107b430642fff05e2deb7ac3e4c76b4..186dfffbdb6901e95ddf5a6bf07b4a189f64db8c 100644 GIT binary patch delta 2502 zcmY*Yc{tRG8=od2!=f#Nv`VyT6*Ej$j&W9w9I>^|nay2})-{e9Uo)=O8Rcp)w3#U( zq1UPK6 zM5AQ)#{(hPt?faE%yF;%r86T-9q_TV+S>j_Y<2XTKPxUL(eUIc-NoSS>bcCJcXdMs z!eJg9DLeSoD5gj0SCxX7-2T9xh2w$Qu<%Qoj+!D5YerLh%&p$_A(|(cHW*w4>Po0x zNyAPj$2%YDnYEVeZki^YcN%`h1OFDBp`v7IdgET1lul{X!ZR*wS!J8401WGpAy&}b z3ozGP4R1oWY$WsgA8ZXo9MqREw=Q9-Y=A(bgXX424&nK$1*u`gI+@Gm1h{)V0WpO5 zb4S3A7?7^|*?$<6=(F-9ih{5BP3k>!eV7MX2?MQ%-tC`mfRN<5t5e$IlYgd)`f2!- zY)JyUyJN9|fzufSNm1iKBDGC`KT`Ag&1{=HjdTLK&8wcpL5&xhsG(O3RIOJK*G}6f z4HE35=$i)Q)}jMrA${>_QLS5bj0Unl0gFjH;*xqto;@f37|0Ji+xn`mlWkh$W_qdi zi>OO7B)TDG&hj2h)-4(0zd;dp7HYxseFd|~QY36V35mEz15kI1cjo(+g6aho^c|P2 zo9(uRd(4Xy^Re1mUxCvuCNpSjvm2D(xD1pDm^Uao1Kg4sjxUcwB-iUFrDW@@)9i-Scuz4-K9=B+Q zR_DTGwHSaVoib6bdvMuwS|09IE73O+1P9P=pXJPP$|k2zie z7MU{2Z=(=}UMDAb&BWaxbsk-IK>q+3HYg|~3J>9Yw8hF&e%WZS_;dzy%x5|ViXUxT zrqU1v;+2!^Jl~|5tY^~n@fY_|F?n&S|GxVFPJ@>zw(!G5IU_eB(J|^nWOO>^ymNs4 zx1teB?S%aLAF>UD5+(&Ka^2lN?nITGfAvXvP8YQmt*hSwyss)%d~{j-hfB}Vw!5xh zaA#us2w0RHRp01|gzS%*7a$>y==jZd${H(gWboBrTi^nJu=CWZg*nlmjPoApu3LY3 z!NHLw-VW&y*~Ct&%E6~UgJusbBn*bOEE}hSckab_O!c$)Av>$&&781GmDUH= z43y|B))(9*KtR+FyDA<=Z!C5aTzHs#wLl#4UvwX3Yv!9+zLix$0kMFpV)N*N@M!q(87#ugTWgbNqzXBZV8Qww%9B&Lk_m-ur6kH^-HJQUfw|zxdwHlGJDlV^x99)8!Dj3>6Yz4+SRu_12y$2CU zV2(d3vSZN{m|JkkxvH#{i@qvrW*FTsuL=jh&tpZbCV ziw#W-Y}#T!U)xuZip1;WhwU2+oH;X~NYruliXfoUxLH_|4&&xA?m0Rpz1H_DL&7t1 zxxeYJMkar42=!H8GH_4-AAG=f7{}j!qUe;(O7)-~k1&w1_Igi`3?QYCU3g1SRpCZ7 z$-k`F2Zr*T>jsH>9k_5Yej_6Msu>y%NwE~V;JC1g;PQ8kTFRHlnCnL$^j^nSDZa7H zhAX~t!ikg{&wd-xQC^*VP!GCunw3l0)1Mg70Q3@plU<#kR8LBM_s0InkWsKNEcyEt zUSI;{$G=Qp)ai)Usz8om&&}F&N~Da1WWB^2v_JG(*;MU7Yo6Urri3Ih1>SkEp#ynU1r0LL`-`kin8NJ}`OmsH5jk?I)zF;|8pT4o>9 zxOgr|&E6fdp*(C~aAM~GaIf`2$P1@Ea?kqwE%E=dfJ&KVO2+ZyC3?-qquY4A-1os2 z>FJ^1=&n0@ec68Iut}4{NoQjBU8tq#;UhTv?Y()6=^v?nt+05d!EAr?4IQ$NT3Xeo zO0_~6Lh)#c!M2gaQjKwgXK;%RM8hCaqU+CYpyQQck*fZ64#qyREZY#4OUd4zA764G zSF&~fJ)2$qp`Kj$!6na8_p2MfG(ZcY;Q71n1DY$HTisFO{ca|t@Yn8%{ZyCOr^d{g zUr}FuesEa$vRrfuv7&vpZcYjAbTBhgTF&OTr9kb~qW3MKBB_`{zv1Fl>k$s-ifX_y zAiUI$0SI+vYIG=mkDf+h-HBeWRhp?akMZl`t&m`e-XYgj=v+=vAGf)w426q)I=VyS z@U-=Ip4z}fK8?Q6VM=f#oLU(@h_Sy_i?@VB9UvTB#LmS7IsLvVgOx43DUn4~VRTb# z&K;7S44l+B|Bmb08Q9OVlD0^Wfsu5F zb1BD!$mWcQBe^#qz1|BGSi0xV_HbPqwYJQFiS|G;r*9gea}I^EE4 zU9wBjCa6ckcS;4{Qvw1l1qIk=2Ii5svCI8fV~g9A^KymG7}jvc?qBtUhDzip>mXzNQ81wopEAOWdT6{SdxlJFU6QU#<(DWWL7!-AA3 zy(_S^EF|=$83Z(h1oC|E>^Zw<-~Dyx&%HBqX8K@7@Dv0m($d`K8VCepcqymKSiw*J zG==;^Ou@HqScCLdr@elG-qbXCU^+8vZ8 zO5}hVy5QP1`**ZOfmC_uz!JmUIzQ{m??876O>d$Msv4eXi+Ub$cC4aTlB zk6$P@Ge>4uHtwgaYuW3(gBH42ZT&1h76yUXB}@$UZBVbaUt`_gsKc%)8jLx)NcH7L z-(fH`DQ$>bgwiN)<+0b{Ef<_P6*Um}KV@xkXQTsggm}?_OpB1tufs0S@Wm~1>zm|6 z#dm`HW@u;pDV&cS#}k0_c?9XNjjnGJ(%NSN7$b2|XU8jiZz)G<&qRYV`eZ62u}l#nQOnX2&oW^0Rxu+IA2%fRu&;akx_Y$w z&_dkM%jaS^dYnEdmM=gHxZ zMAqrll6)M5jQn`{hEGK6v zzQZbizGu_I)P{u=skv(3TExlC(%J%2A1}1h)qOs_ICt_xf=Uc zFf#&g8^;oY>hlUos<*Z?%I|^=CgORXs)$`L71qC~;@bwqc-(5Ow4?z;h=2;_Z_!~2 zVb#+oGhuBeW(9Y*m3jVV`qzdp>gTGsS0_6X+U3&tg&XV`ubQfw=cR0Y6S?;|&>!Et z{37FH(>m9cjh2|)%1c2+n1OYRdDd`sh##Yh{dv>-R{O}Lu$qbb(U6c~R!u1m0T^K2 zeiQJl9w9T}Obe^=dvHmBDlpvOnRv~TRR>)u#!_ikAFjq{#Lz{LM41)WRmZw|`Z`2Y z9K4$xe2~EJ6)-@73t}ngh#GN@Cw^6Mh|jGFxlp=|jK7O#t`rfuxa34;(B1eUBNcFn z^r1X0w(p9dX-HSSYdcv`rz1PImu@>wR+i4cstAYVW>S!$fLQ_aRqtz-{;*CjL|!#H(xEhS_O$tj7(*YH=h+Y|sQot)eKt9gHCktkj%K&kN$7g>_BGC<~X!%lBBEsBWQC+nju+M^%HY2=I5O2Boa<6 zWAQo|bX-4Ai!ckHt(+u{NMN01t4B{|*Nv^nHW9XyI~oXCUQJ|e{&wQ#`+$)<8&Wbw z{t`u&&6r1_&bf_9D1K~5(ThQL2BN4-Gp9zA=JG`USuWr&UMNT;G+Lw{UQcY9=6!HRZM5u<`O)e7ZDbSg6vC7Uy%5<{rBEcnu`VqaEW1^*=IcLuzd6(s z?~le{JR>oq-O}7Aj}X;U7H;PRHJIDvNNTOToI=m^e&`n?z@xH$XTrBKj6Z#C(qML& z13+s(zn?QTyG=9g)Kp{J`du^o#cohh0`f~9BxYXZx9TLAWok4T6wYm1 zuKl#1EY+Bso8S zFsdx3gwYZ<{}`ZIv$UK=oJoI4eu++bbBO&x1p_sod1sz|vfj`wIn+I~Y zkp)6`yBwuq+qepsi6kHF*FOTJRqA~;HGf-{oGHC=9t?;axwVgqa0r2$pL|oFl0Oc< zsSu^D`9}@VtGI?x@&Ts>@}7ZS>v4gHS(dtdj9lEY5-yD39BbIHEXRPMey329ig*TF zj0$++-wk@&ptRh+aL7O}$$z9xLHd#~N)tPKlH?=hn4LtK_+{Gsd@%}`ClGdrmn<5T zXn@sIvP(E|)L8kjdU5x3@O**37v@MKb|K18-?r!+r$V=tC+ zv+q^noRS^ z7%jm!on>-Y4?R?r0XW(Atw@R-`w1*D;=!Q|`ExzJjj!`x)f$y)a3+cg%p~8XzX57k&Pc_42#$_h=ksL= ((max_arousal / 100) * 33)) + if(getArousalLoss() >= isPercentAroused(33)) G.aroused_state = TRUE else G.aroused_state = FALSE @@ -166,41 +167,13 @@ return FALSE 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/arousal_state = "arousal0" + if(!stat == DEAD) + var/arousal_percent = getPercentAroused() + var/arousal_rounded = FLOOR(arousal_percent, 10) + arousal_state = "arousal[arousal_rounded]" + hud_used.arousal.icon_state = arousal_state + return TRUE /obj/screen/arousal name = "arousal" @@ -227,12 +200,12 @@ 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 + if(getArousalLoss() >= isPercentAroused(33))//33% arousal or greater required src.visible_message("[src] starts masturbating!", \ - "You start masturbating.") + "You start masturbating.") if(do_after(src, 30, target = src)) src.visible_message("[src] relieves [p_them()]self!", \ - "You have relieved yourself.") + "You have relieved yourself.") SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "orgasm", /datum/mood_event/orgasm) setArousalLoss(min_arousal) else From 0efa252c00871a40ee1ef296e8a2f6d7ef551cde Mon Sep 17 00:00:00 2001 From: sarcoph <83266791+sarcoph@users.noreply.github.com> Date: Wed, 4 May 2022 15:45:35 -0800 Subject: [PATCH 08/28] typo --- modular_citadel/code/modules/arousal/arousal.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modular_citadel/code/modules/arousal/arousal.dm b/modular_citadel/code/modules/arousal/arousal.dm index 7bd960a09..aab2e5012 100644 --- a/modular_citadel/code/modules/arousal/arousal.dm +++ b/modular_citadel/code/modules/arousal/arousal.dm @@ -168,7 +168,7 @@ else if(hud_used.arousal) var/arousal_state = "arousal0" - if(!stat == DEAD) + if(stat != DEAD) var/arousal_percent = getPercentAroused() var/arousal_rounded = FLOOR(arousal_percent, 10) arousal_state = "arousal[arousal_rounded]" From e2b6765b98976f72d473792bbad66dd61646021c Mon Sep 17 00:00:00 2001 From: sarcoph <83266791+sarcoph@users.noreply.github.com> Date: Wed, 4 May 2022 15:57:41 -0800 Subject: [PATCH 09/28] add arousal20 without this the hud is invisible between 20 and 30 arousal --- modular_citadel/icons/obj/genitals/hud.dmi | Bin 2019 -> 2005 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/modular_citadel/icons/obj/genitals/hud.dmi b/modular_citadel/icons/obj/genitals/hud.dmi index bf2adcb1fcdb9c7ca35d186f72e62ced787db730..e090dbd84e70cf084d2e1f5d9acad0c72cf2e062 100644 GIT binary patch delta 1176 zcmV;J1ZVr>57iHlBmvE_C9ncEk&%&(j*gO&l9iQ}mzS56l$5eRF|$81XlQ7jo}QYT znuZ%wKL7v#0d!JMQvg8b*k%9#0F#pl1A>1dTBRY;Dsd`QR&e!m0Vfjxe|Vm^|6-}~ z000CRNklA!SlXh8PX3GLg%Ca(xP9@nc8w_pP0<&SZ_p-frwjJ%g z_ckqUYNduKiqTLi?QiHXM9p(L*xP&j;JLs3t{bikQ7*h601h)%sybAyRy?bbvr2z? zykm8z>b&B~Bd23IyhDwewQAR@Q@5UF)~j2GoHc7W*z29@H*jv~+=wr*OaZ?UIUCe> zve&ybc5UM3*0fpk7A;M)WsBy`n!33)ac%5kpLcK7S|}2Ev}x-pHchc-+cq8|k+5|u zcl&(1_Ff%2dUxvF#iy%pH-PTGU44JLbnfKcv4dCpcK^dmdJsK(_3quvPuj!XTWWdlNgH3xt|9*Y{hbLt2a=Ahwmn#*4 zK|F~xP@%MJcNt;wqehPzJI+k-_z3|MCk0FxA8grU$BZ6@?j0v96)H1oc}RcY6kcG6 zTy5D3zqDqYAAjWbLP&Qzrf1EMT-|NT3EE^&zn03 zzlSADmo2xkf~0sYTe<|lhn1@$R?`r%Y9)RTYu2t?Ps6&kYw&y6uyNC78a8d*fZqdb z*}9E}ty|deuzknQU6kzHv7LVn53qaB-hCA8-Lsn=50U#19HijD{z!H_z@fuOj+Wub z;X`bBh>DJhJ@yB&G0{A_uJxApQvF}kmYTu)J)V@dc zO#P1AGxj@f&(!a@J&2RlDSQhm`MdWY-pN(gnW9b>>Nt6)%JPp{jbl-&88qXM_=@Hh`awk8HAt9AT)d` z^4R;|k#G1S{DUtBeu;lcxcdNiA27k)2e|uy8SXy7QF-C+1KfXofV&TH_koJM58&>9 z#`^&7{%5=o;O>9s`v7X+Bi{#5`yTy1fZF%S_W`DU$L*Q>9k*xfcii6eS^aAGRtm#c zk%m1_{+e?0h*IR`>e=+)F`1@b%Co3$J`O*CR qW^ngEk05w|^Z5I}fcEXLwEPDAAeC_rJM{qo00000GBw8g-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: Wed, 4 May 2022 16:25:00 -0800 Subject: [PATCH 10/28] force partners to be carbon before it allowed you to interact w animals --- .../code/modules/arousal/arousalhud.dm | 40 +++-- .../code/modules/arousal/arousal.dm | 150 ++++++++---------- 2 files changed, 80 insertions(+), 110 deletions(-) diff --git a/hyperstation/code/modules/arousal/arousalhud.dm b/hyperstation/code/modules/arousal/arousalhud.dm index 264735710..ae9b814e4 100644 --- a/hyperstation/code/modules/arousal/arousalhud.dm +++ b/hyperstation/code/modules/arousal/arousalhud.dm @@ -365,41 +365,37 @@ obj/screen/arousal/proc/kiss() to_chat(src, "You cannot climax without choosing genitals.") return -/mob/living/carbon/human/proc/climaxwith(mob/living/T) +/mob/living/carbon/human/proc/climaxwith(mob/living/carbon/human/partner) + if(!partner) + to_chat(src, "You cannot do this alone.") + return var/obj/item/organ/genital/picked_organ picked_organ = pick_climax_genitals() if(!picked_organ) to_chat(src, "You cannot climax without choosing genitals.") return - var/mob/living/carbon/human/partner = pick_partner() - if(!partner) - to_chat(src, "You cannot do this alone.") - return src << browse(null, "window=arousal") // close arousal window mob_climax_partner_spillage(picked_organ, partner, FALSE) -/mob/living/carbon/human/proc/climaxover(mob/living/T) - var/mob/living/carbon/human/partner = T +/mob/living/carbon/human/proc/climaxover(mob/living/carbon/human/partner) var/obj/item/organ/genital/picked_organ picked_organ = pick_climax_genitals() - if(picked_organ) - src << browse(null, "window=arousal") //alls fine, we can close the window now. - if(partner) - var/obj/item/organ/genital/penis/P = picked_organ - if(P.condom == 1) - to_chat(src, "You cannot do this action with a condom on.") - return - if(P.sounding == 1) - to_chat(src, "You cannot do this action with a sounding in.") - return - mob_climax_partner(picked_organ, partner, FALSE, FALSE, TRUE) - else - to_chat(src, "You cannot do this alone.") - return - else //They either lack organs that can masturbate, or they didn't pick one. + if(!picked_organ) to_chat(src, "You cannot climax without choosing genitals.") return + src << browse(null, "window=arousal") //alls fine, we can close the window now. + if(!partner) + to_chat(src, "You cannot do this alone.") + return + var/obj/item/organ/genital/penis/P = picked_organ + if(P.condom) + to_chat(src, "You cannot do this action with a condom on.") + return + if(P.sounding) + to_chat(src, "You cannot do this action with a sounding in.") + return + mob_climax_partner(picked_organ, partner, FALSE, FALSE, TRUE) /mob/living/carbon/human/proc/clothesplosion() if(usr.restrained(TRUE)) diff --git a/modular_citadel/code/modules/arousal/arousal.dm b/modular_citadel/code/modules/arousal/arousal.dm index aab2e5012..3f11f90de 100644 --- a/modular_citadel/code/modules/arousal/arousal.dm +++ b/modular_citadel/code/modules/arousal/arousal.dm @@ -214,12 +214,12 @@ //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, cover = FALSE, mb_time = 30) //Masturbation, keep it gender-neutral +/mob/living/carbon/human/proc/mob_masturbate(obj/item/organ/genital/G, cover = FALSE, mb_time = 30) +//Masturbation, keep it gender-neutral var/total_fluids = 0 var/datum/reagents/fluid_source = null var/condomed = 0 var/sounded = 0 - if(G.name == "penis")//if the select organ is a penis var/obj/item/organ/genital/penis/P = src.getorganslot("penis") if(P.condom) //if the penis is condomed @@ -236,8 +236,8 @@ total_fluids = fluid_source.total_volume 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].", \ - "You start to [G.masturbation_verb] your [G.name].") + "You start to [G.masturbation_verb] your [G.name].", \ + "You start to [G.masturbation_verb] your [G.name].") if(do_after(src, mb_time, target = src)) if(total_fluids > 5 &&!condomed &&!sounded) @@ -245,17 +245,16 @@ fluid_source.clear_reagents() if(!condomed && !sounded && !cover) 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.") + "You cum[istype(src.loc, /turf/open/floor) ? " onto [src.loc]" : ""].", \ + "You have relieved yourself.") if(!condomed &&!sounded && cover)//For when you want to make a mess of yourself. fluid_source.trans_to(src, total_fluids*G.fluid_transfer_factor) total_fluids -= total_fluids*G.fluid_transfer_factor if(total_fluids > 80) // now thats a big cum! - if(isliving(src)) - var/mutable_appearance/cumoverlaylarge = mutable_appearance('hyperstation/icons/effects/cumoverlay.dmi') - cumoverlaylarge.icon_state = "cum_large" - src.add_overlay(cumoverlaylarge) + var/mutable_appearance/cumoverlaylarge = mutable_appearance('hyperstation/icons/effects/cumoverlay.dmi') + cumoverlaylarge.icon_state = "cum_large" + src.add_overlay(cumoverlaylarge) if(total_fluids > 5) fluid_source.reaction(src.loc, TOUCH, 1, 0) @@ -264,14 +263,11 @@ H.cumdrip_rate += rand(5,10) fluid_source.clear_reagents() src.visible_message("[src] climaxes over [p_their()] self, using [p_their()] [G.name]!", \ - "You orgasm over yourself, using your [G.name].", \ - "You have climaxed over something, using your [G.name].") - if(isliving(src)) - var/mutable_appearance/cumoverlay = mutable_appearance('hyperstation/icons/effects/cumoverlay.dmi') - cumoverlay.icon_state = "cum_normal" - src.add_overlay(cumoverlay) - else - src.add_cum_overlay() + "You orgasm over yourself, using your [G.name].", \ + "You have climaxed over something, using your [G.name].") + var/mutable_appearance/cumoverlay = mutable_appearance('hyperstation/icons/effects/cumoverlay.dmi') + cumoverlay.icon_state = "cum_normal" + src.add_overlay(cumoverlay) if(condomed) //condomed src.visible_message("[src] orgasms, climaxing into [p_their()] condom ", \ @@ -333,10 +329,9 @@ setArousalLoss(min_arousal) -/mob/living/carbon/human/proc/mob_climax_partner(obj/item/organ/genital/G, mob/living/L, spillage = TRUE, impreg = FALSE,cover = FALSE,remote = FALSE, mb_time = 30) //Used for climaxing with any living thing +/mob/living/carbon/human/proc/mob_climax_partner(obj/item/organ/genital/G, mob/living/carbon/partner, spillage = TRUE, impreg = FALSE,cover = FALSE,remote = FALSE, mb_time = 30) //Used for climaxing with any person 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 @@ -345,122 +340,107 @@ return fluid_source = G.linked_organ.reagents total_fluids = fluid_source.total_volume - if(mb_time && !remote) //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]!", \ + src.visible_message("[src] is about to climax with [partner]!", \ + "You're about to climax with [partner]!", \ "You're preparing to climax with something!") if(remote) src.visible_message("[src] is about to climax with someone!", \ "You're about to climax with someone!", \ "You're preparing to climax with something!") - if(cover)//covering the partner in cum, this overrides other options. - if(do_after(src, mb_time, target = src) && in_range(src, L)) - fluid_source.trans_to(L, total_fluids*G.fluid_transfer_factor) + if(do_after(src, mb_time, target = src) && in_range(src, partner)) + fluid_source.trans_to(partner, total_fluids*G.fluid_transfer_factor) total_fluids -= total_fluids*G.fluid_transfer_factor if(total_fluids > 80) // now thats a big cum! - if(isliving(L)) - var/mutable_appearance/cumoverlaylarge = mutable_appearance('hyperstation/icons/effects/cumoverlay.dmi') - cumoverlaylarge.icon_state = "cum_large" - L.add_overlay(cumoverlaylarge) - + var/mutable_appearance/cumoverlaylarge = mutable_appearance('hyperstation/icons/effects/cumoverlay.dmi') + cumoverlaylarge.icon_state = "cum_large" + partner.add_overlay(cumoverlaylarge) if(total_fluids > 5) - fluid_source.reaction(L.loc, TOUCH, 1, 0) - var/mob/living/carbon/human/H = L + fluid_source.reaction(partner.loc, TOUCH, 1, 0) + var/mob/living/carbon/human/H = partner if(H) H.cumdrip_rate += rand(5,10) fluid_source.clear_reagents() - src.visible_message("[src] climaxes over [L], using [p_their()] [G.name]!", \ - "You orgasm over [L], using your [G.name].", \ + src.visible_message("[src] climaxes over [partner], using [p_their()] [G.name]!", \ + "You orgasm over [partner], using your [G.name].", \ "You have climaxed over something, using your [G.name].") SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "orgasm", /datum/mood_event/orgasm) - - if(isliving(L)) - var/mutable_appearance/cumoverlay = mutable_appearance('hyperstation/icons/effects/cumoverlay.dmi') - cumoverlay.icon_state = "cum_normal" - L.add_overlay(cumoverlay) - else - L.add_cum_overlay() - + var/mutable_appearance/cumoverlay = mutable_appearance('hyperstation/icons/effects/cumoverlay.dmi') + cumoverlay.icon_state = "cum_normal" + partner.add_overlay(cumoverlay) setArousalLoss(min_arousal) if(G.can_climax) setArousalLoss(min_arousal) - if(spillage && !cover) if(do_after(src, mb_time, target = src)) - if(!in_range(src, L) && !remote) + if(!in_range(src, partner) && !remote) return - fluid_source.trans_to(L, total_fluids*G.fluid_transfer_factor) + fluid_source.trans_to(partner, 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) - var/mob/living/carbon/human/H = L + fluid_source.reaction(partner.loc, TOUCH, 1, 0) + var/mob/living/carbon/human/H = partner if(H) H.cumdrip_rate += rand(5,10) 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].", \ + src.visible_message("[src] climaxes with [partner][spillage ? ", overflowing and spilling":""], using [p_their()] [G.name]!", \ + "You orgasm with [partner][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) - + SEND_SIGNAL(partner, COMSIG_ADD_MOOD_EVENT, "orgasm", /datum/mood_event/orgasm) if(G.can_climax) setArousalLoss(min_arousal) - else //knots, portal fleshlights, and other non-spilling orgasms if(!cover) - if(!remote && !in_range(src, L)) + if(!remote && !in_range(src, partner)) return if(do_after(src, mb_time, target = src)) - var/mob/living/carbon/H = L + var/mob/living/carbon/H = partner if(!spillage && total_fluids > 80) //hyper inflation; requires a big cumshot to expand H.expand_belly(1) var/obj/item/organ/genital/penis/P = G if (P.condom)//condomed. src.condomclimax() else - fluid_source.trans_to(L, total_fluids) + fluid_source.trans_to(partner, total_fluids) total_fluids = 0 if(!remote) - src.visible_message("[src] climaxes with [L], [p_their()] [G.name] spilling nothing!", \ - "You ejaculate with [L], your [G.name] spilling nothing.", \ + src.visible_message("[src] climaxes with [partner], [p_their()] [G.name] spilling nothing!", \ + "You ejaculate with [partner], your [G.name] spilling nothing.", \ "You have climaxed inside someone, your [G.name] spilling nothing.") else src.visible_message("[src] climaxes with someone, using [p_their()] [G.name]!", \ "You ejaculate with someone, using your [G.name].", \ "You have climaxed inside someone, using your [G.name].") - to_chat(L, "You feel someone ejaculate inside you.") + to_chat(partner, "You feel someone ejaculate inside you.") SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "orgasm", /datum/mood_event/orgasm) - SEND_SIGNAL(L, COMSIG_ADD_MOOD_EVENT, "orgasm", /datum/mood_event/orgasm) + SEND_SIGNAL(partner, COMSIG_ADD_MOOD_EVENT, "orgasm", /datum/mood_event/orgasm) if(G.can_climax) setArousalLoss(min_arousal) - //Hyper - antag code if(src.mind.special_role == ROLE_LEWD_TRAITOR) for(var/datum/objective/obj in src.mind.objectives) - if (L.mind == obj.target) - L.mind.sexed = TRUE //sexed + if (partner.mind == obj.target) + partner.mind.sexed = TRUE //sexed to_chat(src, "You feel deep satisfaction with yourself.") - //Hyper - impreg if(impreg) //Role them odds, only people with the dicks can send the chance to the person with the settings enabled at the momment. - if(prob(L.impregchance)) - var/obj/item/organ/genital/womb/W = L.getorganslot("womb") + if(prob(partner.impregchance)) + var/obj/item/organ/genital/womb/W = partner.getorganslot("womb") if(W) //check if they have a womb. - if (L.breedable && !W.pregnant) //Dont get pregnant again, if you are pregnant. - log_game("Debug: [L] has been impregnated by [src]") - to_chat(L, "You feel your hormones change, and a motherly instinct take over.") //leting them know magic has happened. + if (partner.breedable && !W.pregnant) //Dont get pregnant again, if you are pregnant. + log_game("Debug: [partner] has been impregnated by [src]") + to_chat(partner, "You feel your hormones change, and a motherly instinct take over.") //leting them know magic has happened. W.pregnant = 1 - if (HAS_TRAIT(L, TRAIT_HEAT)) - SEND_SIGNAL(L, COMSIG_ADD_MOOD_EVENT, "heat", /datum/mood_event/heat) //well done you perv. - REMOVE_TRAIT(L, TRAIT_HEAT, ROUNDSTART_TRAIT) //take the heat away, you satisfied it! - + if (HAS_TRAIT(partner, TRAIT_HEAT)) + SEND_SIGNAL(partner, COMSIG_ADD_MOOD_EVENT, "heat", /datum/mood_event/heat) //well done you perv. + REMOVE_TRAIT(partner, TRAIT_HEAT, ROUNDSTART_TRAIT) //take the heat away, you satisfied it! //Make breasts produce quicker. - var/obj/item/organ/genital/breasts/B = L.getorganslot("breasts") + var/obj/item/organ/genital/breasts/B = partner.getorganslot("breasts") if (B.fluid_mult < 0.5 && B) B.fluid_mult = 0.5 @@ -598,8 +578,6 @@ 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==2) to_chat(src, "You can't do that while dead!") @@ -610,23 +588,22 @@ var/obj/item/organ/genital/G = O if(!G.can_climax) //Skip things like wombs and testicles continue - var/mob/living/partner + var/mob/living/carbon/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 + if(iscarbon(src.pulling)) //Don't fuck objects check_target = src.pulling - if(src.pulledby && !check_target) //prioritise pulled over pulledby - if(isliving(src.pulledby)) + else if(src.pulledby) //prioritise pulled over pulledby + if(iscarbon(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 + 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 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 @@ -636,17 +613,14 @@ //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. 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:") in list("Masturbate", "Climax alone", "Climax with partner","Climax over partner", "Fill container", "Remove condom", "Remove sounding rod") - switch(choice) if("Remove sounding rod") if(restrained(TRUE)) //TRUE ignores grabs @@ -755,7 +729,7 @@ var/obj/item/organ/genital/picked_organ picked_organ = pick_climax_genitals() if(picked_organ) - var/mob/living/partner = pick_partner(FALSE) //Get your partner, clothed or not. + var/mob/living/carbon/partner = pick_partner(FALSE) //Get your partner, clothed or not. if(partner) mob_climax_partner(picked_organ, partner, FALSE, FALSE, TRUE) else From 058d368a6f1722135be05e8a55e981e08e32d8e6 Mon Sep 17 00:00:00 2001 From: sarcoph <83266791+sarcoph@users.noreply.github.com> Date: Wed, 4 May 2022 16:57:37 -0800 Subject: [PATCH 11/28] plus ratio --- .../code/modules/arousal/arousalhud.dm | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/hyperstation/code/modules/arousal/arousalhud.dm b/hyperstation/code/modules/arousal/arousalhud.dm index ae9b814e4..c51887b1a 100644 --- a/hyperstation/code/modules/arousal/arousalhud.dm +++ b/hyperstation/code/modules/arousal/arousalhud.dm @@ -48,15 +48,14 @@ if(user.pulling) - dat += "Climax over [user.pulling]" //you can cum on objects if you really want... - dat += "(Orgasm over a person or object.)
" - if(isliving(user.pulling)) + if(!(isliving(user.pulling) && !iscarbon(user.pulling))) // do not fuck animals + dat += "Climax over [user.pulling]" //you can cum on objects if you really want... + dat += "(Orgasm over a person or object.)
" if(iscarbon(user.pulling)) dat += "Climax with [user.pulling]" dat += {"(Orgasm with another person.)
"} - var/mob/living/carbon/human/H = user.pulling - if(H.breedable && P && H) + if(H && H.breedable && P) dat += "Impregnate [U.pulling] ([clamp(U.impregchance,0,100)]%)" dat += "(Climax inside another person, and attempt to knock them up.)
" else @@ -140,7 +139,7 @@ T.toggle_visibility(picked_visibility) if(href_list["masturbate"]) - if (H.arousalloss >= H.isPercentAroused(33)) //requires 33% arousal. + if (H.isPercentAroused(33)) //requires 33% arousal. H.solomasturbate() return else @@ -148,7 +147,7 @@ return if(href_list["container"]) - if (H.arousalloss >= H.isPercentAroused(33)) //requires 33% arousal. + if (H.isPercentAroused(33)) //requires 33% arousal. H.cumcontainer() return else @@ -156,7 +155,7 @@ return if(href_list["clothesplosion"]) - if (H.arousalloss >= H.isPercentAroused(33)) //Requires 33% arousal. + if (H.isPercentAroused(33)) //Requires 33% arousal. H.clothesplosion() return else @@ -164,7 +163,7 @@ return if(href_list["climaxself"]) - if (H.arousalloss >= H.isPercentAroused(33)) //requires 33% arousal. + if (H.isPercentAroused(33)) //requires 33% arousal. H.climaxself() return else @@ -172,7 +171,7 @@ return if(href_list["climax"]) - if (H.arousalloss >= H.isPercentAroused(33)) //requires 33% arousal. + if (H.isPercentAroused(33)) //requires 33% arousal. H.climaxalone(FALSE) return else @@ -180,7 +179,7 @@ return if(href_list["climaxover"]) - if (H.arousalloss >= H.isPercentAroused(33)) //requires 33% arousal. + if (H.isPercentAroused(33)) //requires 33% arousal. H.climaxover(usr.pulling) return else @@ -188,7 +187,7 @@ return if(href_list["climaxwith"]) - if (H.arousalloss >= H.isPercentAroused(33)) //requires 33% arousal. + if (H.isPercentAroused(33)) //requires 33% arousal. H.climaxwith(usr.pulling) return else @@ -196,7 +195,7 @@ return if(href_list["impreg"]) - if (H.arousalloss >= H.isPercentAroused(33)) //requires 33% arousal. + if (H.isPercentAroused(33)) //requires 33% arousal. H.impregwith(usr.pulling) return else @@ -385,7 +384,7 @@ obj/screen/arousal/proc/kiss() to_chat(src, "You cannot climax without choosing genitals.") return src << browse(null, "window=arousal") //alls fine, we can close the window now. - if(!partner) + if(!partner || !iscarbon(partner)) to_chat(src, "You cannot do this alone.") return var/obj/item/organ/genital/penis/P = picked_organ @@ -397,6 +396,7 @@ obj/screen/arousal/proc/kiss() return mob_climax_partner(picked_organ, partner, FALSE, FALSE, TRUE) + /mob/living/carbon/human/proc/clothesplosion() if(usr.restrained(TRUE)) to_chat(usr, "You can't do that while restrained!") From 1e7e2949b3532df8751d2a2179b8c9e90f09e82a Mon Sep 17 00:00:00 2001 From: sarcoph <83266791+sarcoph@users.noreply.github.com> Date: Wed, 4 May 2022 17:42:52 -0800 Subject: [PATCH 12/28] Update arousalhud.dm --- hyperstation/code/modules/arousal/arousalhud.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hyperstation/code/modules/arousal/arousalhud.dm b/hyperstation/code/modules/arousal/arousalhud.dm index c51887b1a..931930113 100644 --- a/hyperstation/code/modules/arousal/arousalhud.dm +++ b/hyperstation/code/modules/arousal/arousalhud.dm @@ -384,7 +384,7 @@ obj/screen/arousal/proc/kiss() to_chat(src, "You cannot climax without choosing genitals.") return src << browse(null, "window=arousal") //alls fine, we can close the window now. - if(!partner || !iscarbon(partner)) + if(!partner || (isliving(partner) !iscarbon(partner))) to_chat(src, "You cannot do this alone.") return var/obj/item/organ/genital/penis/P = picked_organ From e1a6c16dd0971d98ccc9fc42f1c60663a572ef5b Mon Sep 17 00:00:00 2001 From: sarcoph <83266791+sarcoph@users.noreply.github.com> Date: Wed, 4 May 2022 23:54:21 -0800 Subject: [PATCH 13/28] allow objects for certain interactions no animals still --- code/__DEFINES/is_helpers.dm | 2 + .../code/modules/arousal/arousalhud.dm | 28 +++++------ .../code/modules/arousal/arousal.dm | 48 +++++++++++-------- 3 files changed, 41 insertions(+), 37 deletions(-) diff --git a/code/__DEFINES/is_helpers.dm b/code/__DEFINES/is_helpers.dm index c91c0fda4..363d4c38b 100644 --- a/code/__DEFINES/is_helpers.dm +++ b/code/__DEFINES/is_helpers.dm @@ -60,6 +60,8 @@ GLOBAL_LIST_INIT(turfs_without_ground, typecacheof(list( #define isbrain(A) (istype(A, /mob/living/brain)) +#define isnoncarbon(A) (isliving(A) && !iscarbon(A)) + //Carbon mobs #define iscarbon(A) (istype(A, /mob/living/carbon)) diff --git a/hyperstation/code/modules/arousal/arousalhud.dm b/hyperstation/code/modules/arousal/arousalhud.dm index 931930113..375728cf5 100644 --- a/hyperstation/code/modules/arousal/arousalhud.dm +++ b/hyperstation/code/modules/arousal/arousalhud.dm @@ -45,19 +45,17 @@ if(Belly.inflatable) dat += "Deflate belly" dat += "(Shrink your belly down a size)
" - - - if(user.pulling) - if(!(isliving(user.pulling) && !iscarbon(user.pulling))) // do not fuck animals - dat += "Climax over [user.pulling]" //you can cum on objects if you really want... - dat += "(Orgasm over a person or object.)
" - if(iscarbon(user.pulling)) - dat += "Climax with [user.pulling]" - dat += {"(Orgasm with another person.)
"} - var/mob/living/carbon/human/H = user.pulling - if(H && H.breedable && P) - dat += "Impregnate [U.pulling] ([clamp(U.impregchance,0,100)]%)" - dat += "(Climax inside another person, and attempt to knock them up.)
" + + if(user.pulling && !isnoncarbon(user.pulling)) // do not fuck animals + dat += "Climax over [user.pulling]" //you can cum on objects if you really want... + dat += "(Orgasm over a person or object.)
" + if(iscarbon(user.pulling)) + dat += "Climax with [user.pulling]" + dat += {"(Orgasm with another person.)
"} + var/mob/living/carbon/human/H = user.pulling + if(H && H.breedable && P) + dat += "Impregnate [U.pulling] ([clamp(U.impregchance,0,100)]%)" + dat += "(Climax inside another person, and attempt to knock them up.)
" else dat += "Climax over" dat += "(Requires a partner)
" @@ -80,11 +78,9 @@ dat += "Old Menu" dat += "Toggle Undergarments " dat += "
" - var/datum/browser/popup = new(user, "arousal", "Arousal Panel") popup.set_content(dat) popup.set_title_image(user.browse_rsc_icon(icon, icon_state), 500,600) - popup.open() @@ -384,7 +380,7 @@ obj/screen/arousal/proc/kiss() to_chat(src, "You cannot climax without choosing genitals.") return src << browse(null, "window=arousal") //alls fine, we can close the window now. - if(!partner || (isliving(partner) !iscarbon(partner))) + if(!partner || isnoncarbon(partner)) to_chat(src, "You cannot do this alone.") return var/obj/item/organ/genital/penis/P = picked_organ diff --git a/modular_citadel/code/modules/arousal/arousal.dm b/modular_citadel/code/modules/arousal/arousal.dm index 3f11f90de..42521dcf1 100644 --- a/modular_citadel/code/modules/arousal/arousal.dm +++ b/modular_citadel/code/modules/arousal/arousal.dm @@ -329,7 +329,9 @@ setArousalLoss(min_arousal) -/mob/living/carbon/human/proc/mob_climax_partner(obj/item/organ/genital/G, mob/living/carbon/partner, spillage = TRUE, impreg = FALSE,cover = FALSE,remote = FALSE, mb_time = 30) //Used for climaxing with any person +/mob/living/carbon/human/proc/mob_climax_partner(obj/item/organ/genital/G, atom/partner, spillage = TRUE, impreg = FALSE,cover = FALSE,remote = FALSE, mb_time = 30) //Used for climaxing with any person + if(isnoncarbon(partner)) // deny animals + return var/total_fluids = 0 var/datum/reagents/fluid_source = null if(G.producing) //Can it produce its own fluids, such as breasts? @@ -342,17 +344,17 @@ total_fluids = fluid_source.total_volume if(mb_time && !remote) //Skip warning if this is an instant climax. src.visible_message("[src] is about to climax with [partner]!", \ - "You're about to climax with [partner]!", \ - "You're preparing to climax with something!") + "You're about to climax with [partner]!", \ + "You're preparing to climax with something!") if(remote) src.visible_message("[src] is about to climax with someone!", \ - "You're about to climax with someone!", \ - "You're preparing to climax with something!") + "You're about to climax with someone!", \ + "You're preparing to climax with something!") if(cover)//covering the partner in cum, this overrides other options. if(do_after(src, mb_time, target = src) && in_range(src, partner)) fluid_source.trans_to(partner, total_fluids*G.fluid_transfer_factor) total_fluids -= total_fluids*G.fluid_transfer_factor - if(total_fluids > 80) // now thats a big cum! + if(total_fluids > 80 && iscarbon(partner)) // now thats a big cum! var/mutable_appearance/cumoverlaylarge = mutable_appearance('hyperstation/icons/effects/cumoverlay.dmi') cumoverlaylarge.icon_state = "cum_large" partner.add_overlay(cumoverlaylarge) @@ -363,12 +365,15 @@ H.cumdrip_rate += rand(5,10) fluid_source.clear_reagents() src.visible_message("[src] climaxes over [partner], using [p_their()] [G.name]!", \ - "You orgasm over [partner], using your [G.name].", \ - "You have climaxed over something, using your [G.name].") + "You orgasm over [partner], using your [G.name].", \ + "You have climaxed over something, using your [G.name].") SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "orgasm", /datum/mood_event/orgasm) - var/mutable_appearance/cumoverlay = mutable_appearance('hyperstation/icons/effects/cumoverlay.dmi') - cumoverlay.icon_state = "cum_normal" - partner.add_overlay(cumoverlay) + if(iscarbon(partner)) + var/mutable_appearance/cumoverlay = mutable_appearance('hyperstation/icons/effects/cumoverlay.dmi') + cumoverlay.icon_state = "cum_normal" + partner.add_overlay(cumoverlay) + else + partner.add_cum_overlay() setArousalLoss(min_arousal) if(G.can_climax) setArousalLoss(min_arousal) @@ -407,12 +412,12 @@ total_fluids = 0 if(!remote) src.visible_message("[src] climaxes with [partner], [p_their()] [G.name] spilling nothing!", \ - "You ejaculate with [partner], your [G.name] spilling nothing.", \ - "You have climaxed inside someone, your [G.name] spilling nothing.") + "You ejaculate with [partner], your [G.name] spilling nothing.", \ + "You have climaxed inside someone, your [G.name] spilling nothing.") else src.visible_message("[src] climaxes with someone, using [p_their()] [G.name]!", \ - "You ejaculate with someone, using your [G.name].", \ - "You have climaxed inside someone, using your [G.name].") + "You ejaculate with someone, using your [G.name].", \ + "You have climaxed inside someone, using your [G.name].") to_chat(partner, "You feel someone ejaculate inside you.") SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "orgasm", /datum/mood_event/orgasm) @@ -421,18 +426,19 @@ if(G.can_climax) setArousalLoss(min_arousal) //Hyper - antag code + var/mob/living/carbon/partner_carbon = partner if(src.mind.special_role == ROLE_LEWD_TRAITOR) for(var/datum/objective/obj in src.mind.objectives) - if (partner.mind == obj.target) - partner.mind.sexed = TRUE //sexed + if (partner_carbon.mind == obj.target) + partner_carbon.mind.sexed = TRUE //sexed to_chat(src, "You feel deep satisfaction with yourself.") //Hyper - impreg if(impreg) //Role them odds, only people with the dicks can send the chance to the person with the settings enabled at the momment. - if(prob(partner.impregchance)) - var/obj/item/organ/genital/womb/W = partner.getorganslot("womb") + if(prob(partner_carbon.impregchance)) + var/obj/item/organ/genital/womb/W = partner_carbon.getorganslot("womb") if(W) //check if they have a womb. - if (partner.breedable && !W.pregnant) //Dont get pregnant again, if you are pregnant. + if (partner_carbon.breedable && !W.pregnant) //Dont get pregnant again, if you are pregnant. log_game("Debug: [partner] has been impregnated by [src]") to_chat(partner, "You feel your hormones change, and a motherly instinct take over.") //leting them know magic has happened. W.pregnant = 1 @@ -440,7 +446,7 @@ SEND_SIGNAL(partner, COMSIG_ADD_MOOD_EVENT, "heat", /datum/mood_event/heat) //well done you perv. REMOVE_TRAIT(partner, TRAIT_HEAT, ROUNDSTART_TRAIT) //take the heat away, you satisfied it! //Make breasts produce quicker. - var/obj/item/organ/genital/breasts/B = partner.getorganslot("breasts") + var/obj/item/organ/genital/breasts/B = partner_carbon.getorganslot("breasts") if (B.fluid_mult < 0.5 && B) B.fluid_mult = 0.5 From 6bfd8b666ad2b728852e74ae0d1d8e9b8bf183d6 Mon Sep 17 00:00:00 2001 From: sarcoph <83266791+sarcoph@users.noreply.github.com> Date: Thu, 5 May 2022 01:48:08 -0800 Subject: [PATCH 14/28] move forced_climax to its own proc --- .../mob/living/carbon/human/species.dm | 4 +- code/modules/mob/living/carbon/life.dm | 2 +- .../ruins/objects_and_mobs/sin_ruins.dm | 2 +- code/modules/surgery/organs/vocal_cords.dm | 4 +- hyperstation/code/obj/fleshlight.dm | 2 +- hyperstation/code/obj/vibrator.dm | 4 +- .../code/datums/status_effects/chems.dm | 2 +- .../code/modules/arousal/arousal.dm | 79 +++++++++---------- .../subtypes/manipulation.dm | 2 +- 9 files changed, 49 insertions(+), 52 deletions(-) diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm index 344615093..57ce2307c 100644 --- a/code/modules/mob/living/carbon/human/species.dm +++ b/code/modules/mob/living/carbon/human/species.dm @@ -1648,7 +1648,7 @@ GLOBAL_LIST_EMPTY(roundstart_races) if (target.canbearoused) target.adjustArousalLoss(5) if (target.can_orgasm() && HAS_TRAIT(target, TRAIT_MASO)) - target.mob_climax(forced_climax=TRUE) + target.mob_climax_forced() if (!HAS_TRAIT(target, TRAIT_NYMPHO)) stop_wagging_tail(target) @@ -2006,7 +2006,7 @@ GLOBAL_LIST_EMPTY(roundstart_races) if(HAS_TRAIT(H, TRAIT_MASO)) H.adjustArousalLoss(damage * brutemod * H.physiology.brute_mod) if (H.can_orgasm()) - H.mob_climax(forced_climax=TRUE) + H.mob_climax_forced() else//no bodypart, we deal damage with a more general method. H.adjustBruteLoss(damage * hit_percent * brutemod * H.physiology.brute_mod) diff --git a/code/modules/mob/living/carbon/life.dm b/code/modules/mob/living/carbon/life.dm index 471109572..7484bdbd6 100644 --- a/code/modules/mob/living/carbon/life.dm +++ b/code/modules/mob/living/carbon/life.dm @@ -78,7 +78,7 @@ if(HAS_TRAIT(B, TRAIT_CHOKE_SLUT)) B.adjustArousalLoss(7) if (B.can_orgasm()) - B.mob_climax(forced_climax=TRUE) + B.mob_climax_forced() else SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "suffocation", /datum/mood_event/suffocation) else diff --git a/code/modules/ruins/objects_and_mobs/sin_ruins.dm b/code/modules/ruins/objects_and_mobs/sin_ruins.dm index 31fbecea0..e8b79c5f6 100644 --- a/code/modules/ruins/objects_and_mobs/sin_ruins.dm +++ b/code/modules/ruins/objects_and_mobs/sin_ruins.dm @@ -289,7 +289,7 @@ to_chat(user, "You hear a voice in your head... \"You are not horny enough to receive my blessing, dear~\"") return if(user.can_orgasm()) - user.mob_climax(forced_climax=TRUE) + user.mob_climax_forced() to_chat(user, "You hear a voice in your head... \"You are worth of my blessing dear~\"") to_chat(user, "You feel overpowering pleasure surge through your entire body.") var/A = new /obj/item/reagent_containers/chalice/lust diff --git a/code/modules/surgery/organs/vocal_cords.dm b/code/modules/surgery/organs/vocal_cords.dm index b2d19c586..3d9b5d637 100644 --- a/code/modules/surgery/organs/vocal_cords.dm +++ b/code/modules/surgery/organs/vocal_cords.dm @@ -581,7 +581,7 @@ for(var/V in listeners) var/mob/living/carbon/human/H = V if(H.canbearoused && H.has_dna() && HAS_TRAIT(H, TRAIT_NYMPHO)) // probably a redundant check but for good measure - H.mob_climax(forced_climax=TRUE) + H.mob_climax_forced() */ else if((findtext(message, family_friendly_words))) cooldown = COOLDOWN_MEME @@ -1123,7 +1123,7 @@ if(E.phase > 1) if(HAS_TRAIT(H, TRAIT_NYMPHO) && H.canbearoused && E.lewd) // probably a redundant check but for good measure addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, H, "Your [E.enthrallGender] pushes you over the limit, overwhelming your body with pleasure."), 5) - H.mob_climax(forced_climax=TRUE) + H.mob_climax_forced() H.SetStun(20) H.setArousalLoss(H.min_arousal) E.resistanceTally = 0 //makes resistance 0, but resets arousal, resistance buildup is faster unaroused (massively so). diff --git a/hyperstation/code/obj/fleshlight.dm b/hyperstation/code/obj/fleshlight.dm index ce98c62e6..a7410a204 100644 --- a/hyperstation/code/obj/fleshlight.dm +++ b/hyperstation/code/obj/fleshlight.dm @@ -64,7 +64,7 @@ C.do_jitter_animation() C.adjustArousalLoss(20) //make the target more aroused. if (C.can_orgasm()) - C.mob_climax(forced_climax=TRUE) //make them cum if they are over the edge. + C.mob_climax_forced() //make them cum if they are over the edge. return diff --git a/hyperstation/code/obj/vibrator.dm b/hyperstation/code/obj/vibrator.dm index 8eedff37e..f0911b4f3 100644 --- a/hyperstation/code/obj/vibrator.dm +++ b/hyperstation/code/obj/vibrator.dm @@ -133,13 +133,13 @@ Code: to_chat(U, "You feel intense pleasure surge through your [G.name]") U.do_jitter_animation() if (U.can_orgasm()) - U.mob_climax(forced_climax=TRUE) + U.mob_climax_forced() if(3) //high, makes you stun to_chat(U, "You feel overpowering pleasure surge through your [G.name]") U.Jitter(3) U.Stun(30) if (U.can_orgasm()) - U.mob_climax(forced_climax=TRUE) + U.mob_climax_forced() if(prob(50)) U.emote("moan") diff --git a/modular_citadel/code/datums/status_effects/chems.dm b/modular_citadel/code/datums/status_effects/chems.dm index 92aa3b21b..2720bc97c 100644 --- a/modular_citadel/code/datums/status_effects/chems.dm +++ b/modular_citadel/code/datums/status_effects/chems.dm @@ -620,7 +620,7 @@ else if (lowertext(customTriggers[trigger]) == "cum")//aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa if (HAS_TRAIT(C, TRAIT_NYMPHO) && lewd) if (C.getArousalLoss() > 80) - C.mob_climax(forced_climax=TRUE) + C.mob_climax_forced() C.SetStun(10)//We got your stun effects in somewhere, Kev. else C.adjustArousalLoss(10) diff --git a/modular_citadel/code/modules/arousal/arousal.dm b/modular_citadel/code/modules/arousal/arousal.dm index 42521dcf1..365f9a0f1 100644 --- a/modular_citadel/code/modules/arousal/arousal.dm +++ b/modular_citadel/code/modules/arousal/arousal.dm @@ -11,7 +11,6 @@ /mob/living/carbon/human canbearoused = TRUE - var/saved_underwear = ""//saves their underwear so it can be toggled later var/saved_undershirt = "" var/saved_socks = "" @@ -193,7 +192,9 @@ /mob/living/proc/can_orgasm(arousal = 100) return src.getArousalLoss() >= arousal && ishuman(src) && src.has_dna() -/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. +/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" if(canbearoused && !restrained() && !stat) @@ -575,57 +576,23 @@ return null //If nothing correct, give null. -//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 +/mob/living/carbon/human/mob_climax() if(stat == DEAD) //corpses can't cum return if(mb_cd_timer > world.time) - 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!") + 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==2) + if(stat == DEAD) 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/carbon/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(iscarbon(src.pulling)) //Don't fuck objects - check_target = src.pulling - else if(src.pulledby) //prioritise pulled over pulledby - if(iscarbon(src.pulledby)) - check_target = src.pulledby - //Now we should have a partner, or else we have to come alone - if(check_target) - 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 - 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) to_chat(src, "You must be conscious to do that!") return - if(getArousalLoss() < 33) //flat number instead of percentage + if(getArousalLoss() < 33) 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:") in list("Masturbate", "Climax alone", "Climax with partner","Climax over partner", "Fill container", "Remove condom", "Remove sounding rod") switch(choice) if("Remove sounding rod") @@ -774,3 +741,33 @@ else //Somehow another option was taken, maybe something interrupted the selection or it was cancelled return //Just end it in that case. + +/mob/living/carbon/human/proc/mob_climax_forced() + 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/carbon/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(iscarbon(src.pulling)) //Don't fuck objects + check_target = src.pulling + else if(src.pulledby) //prioritise pulled over pulledby + if(iscarbon(src.pulledby)) + check_target = src.pulledby + //Now we should have a partner, or else we have to come alone + if(check_target) + 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 + 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 \ No newline at end of file diff --git a/modular_citadel/code/modules/integrated_electronics/subtypes/manipulation.dm b/modular_citadel/code/modules/integrated_electronics/subtypes/manipulation.dm index 5ce3ae234..6ec3687b4 100644 --- a/modular_citadel/code/modules/integrated_electronics/subtypes/manipulation.dm +++ b/modular_citadel/code/modules/integrated_electronics/subtypes/manipulation.dm @@ -30,7 +30,7 @@ var/orgasm_message = pick("A sharp pulse of electricity pushes you to orgasm!", "You feel a jolt of electricity force you into orgasm!") H.visible_message("\The [assembly] electrodes shock [H]!", "[orgasm_message]") playsound(src, "sound/effects/light_flicker.ogg", 30, 1) - H.mob_climax(forced_climax=TRUE) + H.mob_climax_forced() orgasm = TRUE else M.adjustArousalLoss(arousal_gain) From 2671e4ab0f48049995acddf53024c21357a6a38c Mon Sep 17 00:00:00 2001 From: sarcoph <83266791+sarcoph@users.noreply.github.com> Date: Thu, 5 May 2022 01:57:11 -0800 Subject: [PATCH 15/28] mob_forced_climax() cleanup --- .../ruins/objects_and_mobs/sin_ruins.dm | 7 +- .../code/modules/arousal/arousal.dm | 350 +++++++++--------- 2 files changed, 181 insertions(+), 176 deletions(-) diff --git a/code/modules/ruins/objects_and_mobs/sin_ruins.dm b/code/modules/ruins/objects_and_mobs/sin_ruins.dm index e8b79c5f6..c4ca810ba 100644 --- a/code/modules/ruins/objects_and_mobs/sin_ruins.dm +++ b/code/modules/ruins/objects_and_mobs/sin_ruins.dm @@ -289,9 +289,10 @@ to_chat(user, "You hear a voice in your head... \"You are not horny enough to receive my blessing, dear~\"") return if(user.can_orgasm()) - user.mob_climax_forced() - to_chat(user, "You hear a voice in your head... \"You are worth of my blessing dear~\"") + var/mob/living/carbon/user_carbon = user + user_carbon.mob_climax_forced() + to_chat(user, "You hear a voice in your head... \"You are worthy of my blessing, dear~\"") to_chat(user, "You feel overpowering pleasure surge through your entire body.") var/A = new /obj/item/reagent_containers/chalice/lust user.put_in_hands(A) - chalice_taken = 1 \ No newline at end of file + chalice_taken = TRUE \ 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 365f9a0f1..a26348e2c 100644 --- a/modular_citadel/code/modules/arousal/arousal.dm +++ b/modular_citadel/code/modules/arousal/arousal.dm @@ -190,7 +190,7 @@ ui_interact(usr) /mob/living/proc/can_orgasm(arousal = 100) - return src.getArousalLoss() >= arousal && ishuman(src) && src.has_dna() + return src.canbearoused && src.getArousalLoss() >= arousal && ishuman(src) && src.has_dna() /mob/living/proc/mob_climax() // This is just so I can test this shit without being forced to add actual content @@ -579,195 +579,199 @@ /mob/living/carbon/human/mob_climax() if(stat == DEAD) //corpses can't cum return + if(!canbearoused || !has_dna()) + return if(mb_cd_timer > world.time) 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) - to_chat(src, "You can't do that while dead!") + if(stat == DEAD) + to_chat(src, "You can't do that while dead!") + return + if(stat == UNCONSCIOUS) + to_chat(src, "You must be conscious to do that!") + return + if(getArousalLoss() < 33) + to_chat(src, "You aren't aroused enough for that!") + return + var/choice = input(src, "Select sexual activity", "Sexual activity:") in list("Masturbate", "Climax alone", "Climax with partner","Climax over partner", "Fill container", "Remove condom", "Remove sounding rod") + switch(choice) + if("Remove sounding rod") + 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 + var/obj/item/organ/genital/penis/P = src.getorganslot("penis") + if(!P.sounding) + to_chat(src, "You don't have a rod inside!") + return + if(P.sounding) + to_chat(src, "You pull the rod off from the tip of your penis!") + src.removesounding() + return return - if(stat == UNCONSCIOUS) - to_chat(src, "You must be conscious to do that!") + + if("Remove condom") + 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 + var/obj/item/organ/genital/penis/P = src.getorganslot("penis") + if(!P.condom) + to_chat(src, "You don't have a condom on!") + return + if(P.condom) + to_chat(src, "You tug the condom off the end of your penis!") + src.removecondom() + return return - if(getArousalLoss() < 33) - to_chat(src, "You aren't aroused enough for that!") - return - var/choice = input(src, "Select sexual activity", "Sexual activity:") in list("Masturbate", "Climax alone", "Climax with partner","Climax over partner", "Fill container", "Remove condom", "Remove sounding rod") - switch(choice) - if("Remove sounding rod") - 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 - var/obj/item/organ/genital/penis/P = src.getorganslot("penis") - if(!P.sounding) - to_chat(src, "You don't have a rod inside!") - return - if(P.sounding) - to_chat(src, "You pull the rod off from the tip of your penis!") - src.removesounding() - return + + 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.") + return + //We got hands, let's pick an organ + var/obj/item/organ/genital/picked_organ + picked_organ = pick_masturbate_genitals() + if(picked_organ) + 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("Remove condom") - 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 - var/obj/item/organ/genital/penis/P = src.getorganslot("penis") - if(!P.condom) - to_chat(src, "You don't have a condom on!") - return - if(P.condom) - to_chat(src, "You tug the condom off the end of your penis!") - src.removecondom() - return + if("Climax alone") + 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.") + return + //We got hands, let's pick an organ + var/obj/item/organ/genital/picked_organ + picked_organ = pick_climax_genitals() + if(picked_organ) + 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("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.") - return - //We got hands, let's pick an organ - var/obj/item/organ/genital/picked_organ - picked_organ = pick_masturbate_genitals() - if(picked_organ) - 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 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() + if(!picked_organ) + to_chat(src, "You cannot climax without choosing genitals.") + return + var/mob/living/carbon/partner = pick_partner() //Get someone + if(!partner) + to_chat(src, "You cannot do this alone.") + return + var/obj/item/organ/genital/penis/P = picked_organ + var/impreg = "No" + if(partner.breedable && picked_organ.name == "penis" && !P.condom && !P.sounding) + var/impreg_question = "Would this action carry the risk of pregnancy?" + var/impreg_title = "Choose a option" + impreg = input(src, impreg_question, impreg_title, "Yes") as anything in list("Yes", "No") + mob_climax_partner_spillage(picked_organ, partner, impreg == "Yes") - if("Climax alone") - 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.") - return - //We got hands, let's pick an organ - var/obj/item/organ/genital/picked_organ - picked_organ = pick_climax_genitals() - if(picked_organ) - 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() - if(!picked_organ) - to_chat(src, "You cannot climax without choosing genitals.") - return - var/mob/living/carbon/partner = pick_partner() //Get someone - if(!partner) + if("Climax over partner") + var/obj/item/organ/genital/picked_organ + picked_organ = pick_climax_genitals() + if(picked_organ) + var/mob/living/carbon/partner = pick_partner(FALSE) //Get your partner, clothed or not. + if(partner) + mob_climax_partner(picked_organ, partner, FALSE, FALSE, TRUE) + else to_chat(src, "You cannot do this alone.") - return - var/obj/item/organ/genital/penis/P = picked_organ - var/impreg = "No" - if(partner.breedable && picked_organ.name == "penis" && !P.condom && !P.sounding) - var/impreg_question = "Would this action carry the risk of pregnancy?" - var/impreg_title = "Choose a option" - impreg = input(src, impreg_question, impreg_title, "Yes") as anything in list("Yes", "No") - mob_climax_partner_spillage(picked_organ, partner, impreg == "Yes") - if("Climax over partner") - var/obj/item/organ/genital/picked_organ - picked_organ = pick_climax_genitals() - if(picked_organ) - var/mob/living/carbon/partner = pick_partner(FALSE) //Get your partner, clothed or not. - if(partner) - mob_climax_partner(picked_organ, partner, FALSE, FALSE, TRUE) - else - to_chat(src, "You cannot do this alone.") - - 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!") + 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.") + 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) + mob_fill_container(picked_organ, fluid_container) return - var/free_hands = get_num_arms() - if(!free_hands) - to_chat(src, "You need at least one free arm.") + else + to_chat(src, "You cannot do this without anything to fill.") 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() //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) - 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. + 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. -/mob/living/carbon/human/proc/mob_climax_forced() +/mob/living/carbon/proc/mob_climax_forced() + if(stat == DEAD) //corpses can't cum + to_chat(src, "You can't do that while dead!") + return + if(!canbearoused || !has_dna()) + return + var/mob/living/carbon/human/user_human = src 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 + if(!istype(O, /obj/item/organ/genital)) + return + var/obj/item/organ/genital/current_genital = O + if(!current_genital.can_climax) + continue // no wombs or testicles + var/mob/living/carbon/partner + var/check_target + var/list/worn_stuff = get_equipped_items() + if(current_genital.is_exposed(worn_stuff)) + if(src.pulling) + if(iscarbon(src.pulling)) + check_target = src.pulling + else if(src.pulledby) + if(iscarbon(src.pulledby)) + check_target = src.pulledby + if(check_target) + var/mob/living/carbon/C = check_target + if(C.exposed_genitals.len || C.is_groin_exposed() || C.is_chest_exposed()) + partner = C + if(partner) + user_human.mob_climax_partner(current_genital, partner, mb_time = 0) continue - var/mob/living/carbon/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(iscarbon(src.pulling)) //Don't fuck objects - check_target = src.pulling - else if(src.pulledby) //prioritise pulled over pulledby - if(iscarbon(src.pulledby)) - check_target = src.pulledby - //Now we should have a partner, or else we have to come alone - if(check_target) - 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 - 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 + user_human.mob_climax_outside(current_genital, mb_time = 0) return \ No newline at end of file From 30220e0baad4e24aab1f4075df41b6ba1cd69aef Mon Sep 17 00:00:00 2001 From: sarcoph <83266791+sarcoph@users.noreply.github.com> Date: Thu, 5 May 2022 02:55:07 -0800 Subject: [PATCH 16/28] more cleanup --- hyperstation/code/obj/condom.dm | 1 - .../code/modules/arousal/arousal.dm | 111 +++++++++--------- 2 files changed, 57 insertions(+), 55 deletions(-) diff --git a/hyperstation/code/obj/condom.dm b/hyperstation/code/obj/condom.dm index 727ff4739..2c3122fe2 100644 --- a/hyperstation/code/obj/condom.dm +++ b/hyperstation/code/obj/condom.dm @@ -115,7 +115,6 @@ obj/item/condom/update_icon() return if(!P.condom) return - var/obj/item/condom/filled/C = new P.linked_organ.reagents.trans_to(C, P.linked_organ.reagents.total_volume) C.loc = loc diff --git a/modular_citadel/code/modules/arousal/arousal.dm b/modular_citadel/code/modules/arousal/arousal.dm index a26348e2c..3da56d68b 100644 --- a/modular_citadel/code/modules/arousal/arousal.dm +++ b/modular_citadel/code/modules/arousal/arousal.dm @@ -256,7 +256,6 @@ var/mutable_appearance/cumoverlaylarge = mutable_appearance('hyperstation/icons/effects/cumoverlay.dmi') cumoverlaylarge.icon_state = "cum_large" src.add_overlay(cumoverlaylarge) - if(total_fluids > 5) fluid_source.reaction(src.loc, TOUCH, 1, 0) var/mob/living/carbon/human/H = src @@ -271,13 +270,13 @@ src.add_overlay(cumoverlay) if(condomed) //condomed - src.visible_message("[src] orgasms, climaxing into [p_their()] condom ", \ - "You cum into your condom.", \ - "You have relieved yourself.") + src.visible_message("[src] orgasms, climaxing into [p_their()] condom!", \ + "You cum into your condom.", \ + "You have relieved yourself.") if(sounded) //sounded src.visible_message("[src] orgasms, but the rod blocks anything from leaking out!", \ - "You cum with the rod inside.", \ - "You don't quite feel totally relieved.") + "You cum with the rod inside.", \ + "You don't quite feel totally relieved.") if(total_fluids > 0 &&condomed &&!sounded) src.condomclimax() @@ -303,31 +302,30 @@ if(unable_to_come) src.visible_message("[src] shudders, their [G.name] unable to cum.", \ - "Your [G.name] cannot cum, giving no relief.", \ - "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(spillage) - if(total_fluids > 5) - fluid_source.reaction(src.loc, TOUCH, 1, 0) + "Your [G.name] cannot cum, giving no relief.", \ + "Your [G.name] cannot cum, giving no relief.") + return + 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(spillage) + 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]" : ""], with [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].") + else + src.visible_message("[src] orgasms with [p_their()] [G.name]!", \ + "You climax with your [G.name].", \ + "You climax using your [G.name].") - fluid_source.clear_reagents() - src.visible_message("[src] orgasms[istype(src.loc, /turf/open/floor) ? ", spilling onto [src.loc]" : ""], with [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].") - else //Else from spillage check, also note subtle text change - src.visible_message("[src] orgasms with [p_their()] [G.name]!", \ - "You climax 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) + SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "orgasm", /datum/mood_event/orgasm) + if(G.can_climax) + setArousalLoss(min_arousal) /mob/living/carbon/human/proc/mob_climax_partner(obj/item/organ/genital/G, atom/partner, spillage = TRUE, impreg = FALSE,cover = FALSE,remote = FALSE, mb_time = 30) //Used for climaxing with any person @@ -435,21 +433,8 @@ to_chat(src, "You feel deep satisfaction with yourself.") //Hyper - impreg if(impreg) - //Role them odds, only people with the dicks can send the chance to the person with the settings enabled at the momment. - if(prob(partner_carbon.impregchance)) - var/obj/item/organ/genital/womb/W = partner_carbon.getorganslot("womb") - if(W) //check if they have a womb. - if (partner_carbon.breedable && !W.pregnant) //Dont get pregnant again, if you are pregnant. - log_game("Debug: [partner] has been impregnated by [src]") - to_chat(partner, "You feel your hormones change, and a motherly instinct take over.") //leting them know magic has happened. - W.pregnant = 1 - if (HAS_TRAIT(partner, TRAIT_HEAT)) - SEND_SIGNAL(partner, COMSIG_ADD_MOOD_EVENT, "heat", /datum/mood_event/heat) //well done you perv. - REMOVE_TRAIT(partner, TRAIT_HEAT, ROUNDSTART_TRAIT) //take the heat away, you satisfied it! - //Make breasts produce quicker. - var/obj/item/organ/genital/breasts/B = partner_carbon.getorganslot("breasts") - if (B.fluid_mult < 0.5 && B) - B.fluid_mult = 0.5 + partner_carbon.impregnate(by = src) + /mob/living/carbon/human/proc/mob_climax_partner_spillage(obj/item/organ/genital/picked_organ, mob/living/carbon/partner, impreg = FALSE) var/obj/item/organ/genital/penis/_penis = picked_organ @@ -461,15 +446,17 @@ var/spillage = input(src, _question, _title, "Yes") as anything in list("Yes", "No") mob_climax_partner(picked_organ, partner, spillage == "Yes", impreg, FALSE) -/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 + +/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.name == "penis")//if the select organ is a penis + if(G.name == "penis") var/obj/item/organ/genital/penis/P = src.getorganslot("penis") - if(P.condom) //if the penis is condomed + if(P.condom) to_chat(src, "You cannot fill containers when there is a condom over your [G.name].") return - if(P.sounding) //if the penis is sounded + if(P.sounding) to_chat(src, "You cannot fill containers when there is a rod inside your [G.name].") return if(G.producing) //Can it produce its own fluids, such as breasts? @@ -563,13 +550,11 @@ /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) if(container.is_open_container() || istype(container, /obj/item/reagent_containers/food/snacks)) containers_list += container - if(containers_list.len) - SC = input(src, "Into or onto what?(Cancel for nowhere)", null) as null|obj in containers_list + 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 @@ -594,7 +579,8 @@ if(getArousalLoss() < 33) to_chat(src, "You aren't aroused enough for that!") return - var/choice = input(src, "Select sexual activity", "Sexual activity:") in list("Masturbate", "Climax alone", "Climax with partner","Climax over partner", "Fill container", "Remove condom", "Remove sounding rod") + var/list/choices = list("Masturbate", "Climax alone", "Climax with partner","Climax over partner", "Fill container", "Remove condom", "Remove sounding rod") + var/choice = input(src, "Select sexual activity", "Sexual activity:") as null|anything in choices switch(choice) if("Remove sounding rod") if(restrained(TRUE)) //TRUE ignores grabs @@ -774,4 +760,21 @@ user_human.mob_climax_partner(current_genital, partner, mb_time = 0) continue user_human.mob_climax_outside(current_genital, mb_time = 0) - return \ No newline at end of file + return + + +/mob/living/carbon/proc/impregnate(mob/living/carbon/by) + var/obj/item/organ/genital/womb/W = getorganslot("womb") + if(!W || W.pregnant || !breedable) + return + if(!prob(impregchance)) + return + W.pregnant = TRUE + log_game("DEBUG: [src] has been impregnated by [by]") + to_chat(src, "You feel your hormones change, and a motherly instinct take over.") + if(HAS_TRAIT(src, TRAIT_HEAT)) + SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "heat", /datum/mood_event/heat) + REMOVE_TRAIT(src, TRAIT_HEAT, ROUNDSTART_TRAIT) + var/obj/item/organ/genital/breasts/B = src.getorganslot("breasts") + if (B && B.fluid_mult < 0.5) + B.fluid_mult = 0.5 \ No newline at end of file From 116fbebfdef1e96af365daf567254844402a58c8 Mon Sep 17 00:00:00 2001 From: sarcoph <83266791+sarcoph@users.noreply.github.com> Date: Thu, 5 May 2022 03:01:31 -0800 Subject: [PATCH 17/28] oh my god look at her butt apparently did not merge right --- hyperstation/icons/obj/genitals/butt.dmi | Bin 2632 -> 4551 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/hyperstation/icons/obj/genitals/butt.dmi b/hyperstation/icons/obj/genitals/butt.dmi index 186dfffbdb6901e95ddf5a6bf07b4a189f64db8c..3d702211ddcfea9179b961ebc74fa98d00089657 100644 GIT binary patch literal 4551 zcmZu!2Q(Yr8b{P#C9T#dEmgEettch2)ks4rwG|yoqiD58Vymq~%^Edp_K(=4RH;2` z)Qr6eNr*%w&wKBjciwsbch9-!yZ5{Ip8I{@{l@P`!=MJ7Yyxa_bab3|40X-v=;(7! zdoT;&lry8NZ+}XxU?vuNr+)4(ZVkS0|U;^&O{;+hr?}eZ!az` zPE1Uk?(FUDB@hU!tESo`X_`M7vL_40iRe@;jDIx~5!i7OPs6S0sU6vIh~Z1H;P z!J#V|9zMj!QR)#QV7+i~^gNQyDzv;Ol-WMQXSQYnIA4SD}9Pm2giS%k(T>VfAkXv&s@<< z^N788MNxP4ZQt1kqE!&r=wH0=G;|MnCJkIg-T`#Ecy8$~^SlG6n7=Fw$(?IFsa%|>bcC%pG{?n~Xi`RU zFxH5yo?h2mc#&k%$sn3WQ5oZFX8_3Ymquaa5a=o7&KBG^_c6{Jg&^#-x1J!Xht|F} z&om#An;dej*72?myUmTX{?9j2s9Kd(R_BnAfU23~9zT(1y;THb-!Ip2-pAyDx>xy$ zR%`t6)y9$p-RE!(B3xhZK?*=QD)QS+qU~bd?FU?yWk}-Wp4L8M!R_&EJ2QJIeE01 z=+D+#KlvV+9(=Q1_&(1%l-Y>t{InkMz-395-cBcMMi}K?-r6xce2p~0dAqX~#d@8^ zH|k5-iT933wK%Q4f(6{OdX@0z(gqqQyP1BbBzI8pEHEB8ejdq2sa8XgrLXd&{ z?Q+{$(K%jc8G@KM3ecTLW``o+flh35_8ss2=KUXAo$RAWFI0g3m%0!6eo$CT;T-=A zi2rFvFLaSnt+I0aI*~Qmdaflc2gs7_ijY>eP3@Wy6yzJTrpJkNJ&Wc3PVdO|nj*{l z5oKd+y4~;M*R!G@-uj6EKB;W_^%u#*L3HJ!%{Ryy_K$U{{=3q9S4RVW>3=L@{!8nt zlUN!~*3~2V3anr&Cj#BR<7rp2*b6X`yL)ec5q=Jz?9V$`=ymot*mZ@#wA;8_Q7yOtQ{snM)`knNA2Jo+CS{AWu4vn7px zH@Cb+d7th+9BViYg=4=hz%Svyw|CzxeiaCIJm?)eC=mm`;(+lxTNaYx7Hlsbs2#&` zqvPhLH_@>1^Y6EA+gK%7L}viuT{h?h8r*DDcqOH_#bQh_uvS9 zWfGAGns@yfcP2ysLF3cn^)%@wyvdxI2?Z2$h{qO|Yy)Zih)Sshi#6<(e#HAVNEXM$UK6d*BE8)zB9@nkXn8HZK5bRc=9fzjbrYU zOK%x6+1ldd2Xh_CG>kv5gGFk#<)5_6FIPt#xbEmsVJ5otg4O;;0!k$H-S z7Zs5^Ut}zPSVO_9*}3!_**V+rMLr83Iw<(YI9H;i1T}+GvoJh1GrpIjsj}N&pM)i% zj6_<^yo1wL|~j#y?x2>5cBp~Y!qF&%J;NcY~{9a)s)J3(M(efMOef*AC{^Tyd&c* zqxoZL8ze;)9OF=3mHvL?FrgZv9T3HieYcD~_r9a+X(H*mfat3n??>c>`Qao%uZO{I zdzi8cSPkaX3lt(UWeP~Ki~=Jf_!JPt%U+yWQh7eym`B;xuF}>)oz3@D1}-NTawtWQ zE2SEue;u~>^P?2~CpG}*j%K)rOE3>>=E`j3aclP;gEM5G>1Wk>}5 zmD=y~=m*omI$0s?w0?&tdv6bOmMIaeNn4xJ$Of~?jrJ$oMoCet@!GuD)}^&UeN7S<&Lz?yPKdl+ zi$!;T2LJs5_jJ;LYU?o)3a2Te@tO+vqF5b4joFSc*OwKF$qhmlbEo3|CZ)Y23j8>wVzLqM34Q`oufef9c>9?|gxcdtUcFLJX@X{! zmV3w)FvMJ?kv4FO8~tc^kEvZkQ)W4@GWZ*aiJt%-U_wg$$MVq>)lCiTXzWKUvab!5 zA2;!JcGG@+)@)N`lk1}(l9PIbjiR#M{?SI<(XnIT#Euhph};>*q6YTYZnT}hRbzm@ z{RKe(H+}xiFsa^r1oAcA(zKs;E!n}^5in2s0j7(AH=q-Av(p)PQd1qs6QET4(uWzI z`K(+4GEr;b=b=b);d%}4AL~V)Rxo z;(x1dpiR}W8td?5Q6ExSl5(dR0Q#%E?@! z0=U0(B&#{0PGOqLpya;na`C&}czfj}DjL!VP%>4VzO^npR=nHBj3ly>n(`Xy)i9LA zx;uwBXLr?QD+=|_2lQ?zts>RBF_&US ze6swR`R)0kR>#{@gX1WC0ZIlgi9vSB4DBg|XmqeS-q_?`sFzIkjD8k?(nzf z?mAUeJWpG+aWsr@~jzOve+CUQr6KI@%-d#59glSu`d~)7L2!N9tH)vTG~~X4Rt$^;Q3UplvVVt zH95XwKPyrtGA4n(il%S(Q-fvnG2i+KQtX^$s=&y$OdIp%sS`;UjWHy%vvabmLZf0L zervgc0x}0c2icUR7$RicSP8q*G&=@8TKr7#?`#irIy1B+y96@sRgpKRHk0m}Ay^1C8skRyGD7dj=JE$31Cm~#wP2!^u~t5SIO?_1BYDu*Vyro3)v|k+$JGwNBAT` z8t@fjejX#_kj)+t3(J)+ijhP*1H$Q;1EN&F&!MujZ%b*%&>|_q+2zIl3Cqq_27^?t zx+?mp5j2nCI9;aZ-HH#Z;Ft_!^WxcLT4ywe>ddM*>^<$#A8W7R^-C8hpl4QV6EBJ= zdbdM!=p*mRjv$_%gkb{>>9okBYG0gaexU$`YPKoh&3VcPwH)TP2N zj7$-y2=GtvQg%!I!dji{<$}Sdd2(ggiHXNwhEmZ-jGljp$?w5%Nd(O8xPKBU2I3(A zU8V|wpO0>$O3JFY(YXgxObqGAUGXG!6410o3E9uh`%i!;kbm@n}3PTO^cuWODu>Al^N!x4~)_N^{-#z9X+USg|<`ZKLFe;y6^x1 literal 2632 zcmY*Y2~-kT7bdba$w`|MwHnK^$;MJtYOEC33^g@%Dp$xQwNxB8TtEf4axKd(RJ2Jb zQ!};PP%yW01NWs8+#pw!R4|Z!JO7z;rgzRg-?{hPci#KH``!CCR%SBNO40xTKn8xr z#1;V9VeliQc5YX`S^br>4fZyc_NLo7UR@~?i8ePk`}_L`Nl$xwdvD#k#pm;RJl^8s z;?&gC$jHccTUS@t+S(e0LYbSJqtoewgM(}~yP~3^wzjskv~+oSnZaOCsnn{fDp#pU zh3yMFf^Dtr00!*Q+uKQdg#FE66VD*`K%anMACx};5SEuY*eD&Vc_3j@w=StLvQL!a zl2mlT-tbeKo1?b3h2{FjAJR+1-~2dn*@*^6k6oM#%Bq^l==)IHr@uSYgC~1U>*FxG zOXW}1{MY1#Jgy$;Z{hsatF8h7QVh6>p?z51QhsVEp;rEK8D7gh9uMt<{w)%7!|8IBzxxdU z61^9nMUrvlf64ZuBdJs{Gzx46^-toUvrF=ELi`Vx>Z*7glqEMe7 z(vu=b6R9m?-2UpRchfEIG~yBPhM;O13pV;fp@x|0t642VuO7EcV&Lr}nQQu_=E5B# z!9DS5k=;L2g=Wt3|Z$W*$p||K;;(t+SRZ+?3^i5gAY;AVQDkTV`UeA zIQ8EXeO8rt`}?QJuNrc1uSx}V#W8Yf2I57YF4*1CS8pi7czuf=qbIH@%Y0&(=7317opQMS* z7jn$eR}T;|xp8X${`CJy(<)VN5{63ghOS2-V>J3m$aL}6bvLslD{u5$&9S1)IrRX%|kO-DeD^KPX zbw0WuicZ@#i$Uc3CN!8xr;P1QZNI`~KUIvCu8sqf!dwYt`PeB`Cx5OQ-#oX~)&P$y z-g1uNZIu&zWaV*DVX6$b3aQ{B2`jF~L@pC?cn#om!Y14KGvznho$~HszJ_wMD)UAe zu!ce%O?(He3$svuaU3yW+LJJZ_A;!iJ3e!Uo3Xhi)hiQ3%L>1(nzI_f^q!$ zeLu-?y6VpfbVCfn<qt%p zw}BegZjZ~x5Q~9Bom#m1XGK87tZ?}?uwmsi(`(Oj9{{Szz*yh9C3foS_VlPQoNiv| zwx@s@6Le*QuFLIkJR*&si6QE;ZXD#FW}?$;d^TA!o)HVZl=}^A;c_2hQ*R&YyWY?A z0Hg0G$-1S}vR#O$Lo67iwa(MyVRT9lx4=zYS?)?O&bzGK0|X14Y8iw}ZP+krVFNVm ziYZbHlwu)q*5S(%lrP*eY${tAVXqu`)NPBYRDNfXrKSAN5i40{H2rNz_r%ipqdLId z7eQGP29Gt`!H_{<4yT;AEEsxCvXLkGQr5x+5=Z?=6hq%*F zn5ZcESV(6n-f)%A63 z_?^_XGV8YYXAKZ3)9ih5!g!f()6u9Ffgq~}-ZQAl8lzL(bZm9i4X{Rk3lpnZ>OdtRoc+I_ElE+;kO|`0IcU zd*1YUL~~*CtJ;daK1>7`{Mk9Sz0JjTsWCHfGmWK}I|p`OR*Xs^l($aT&ZuZP?#zgg zQ?&kT9(8`Hu)irpG8J9mJ5aP_HN-=ksreraE4jvsmgvaPY*YR(cN&>@GNGW>AIW>yz;uTKi2qDk;kat=`tMQP5y>+5emR(382z3AJ-)e@fp8tcpsv{UY+ zr4PvojGO33HP3wDyR@TvIhJzf$uSV(#ep31K?xF^6}~^`I;h+0%NT~~DcTsQO{3P7 z>a&p^F!tvghREz)p`5dz#bKgEM-;pXrL;ZM!jLuhiIp6o!?a3&$O|dU{AMEQ5O`Lo z!@4=AOVgfFI{b2w$a^YnS~y=N5K5$&B8#`k=kXd5TA~v1e+2;m<^%ohGEljs4a`C> z#>o5*`HW(L6Ph#daO-~E+ipm0Mlwws=$A(}KJUV*S!Q@mU(yp)3|ZXA)86FS{gFra u%Acgube{!Ekz-&WPN@}iYJ2rrFxGd+h-5S1@@Mdm=isJRCgny*{Qm&g-ZIbt From 975eec750370b1dd911559811a0161ca27f8c079 Mon Sep 17 00:00:00 2001 From: sarcoph <83266791+sarcoph@users.noreply.github.com> Date: Thu, 5 May 2022 03:02:43 -0800 Subject: [PATCH 18/28] makes selectable butt size a variable --- code/__DEFINES/hyper_arousal.dm | 1 + code/modules/client/preferences.dm | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/code/__DEFINES/hyper_arousal.dm b/code/__DEFINES/hyper_arousal.dm index d3f9d6ceb..6b16fba9b 100644 --- a/code/__DEFINES/hyper_arousal.dm +++ b/code/__DEFINES/hyper_arousal.dm @@ -5,4 +5,5 @@ #define BELLY_STRETCH_SIZE 6 // for flavor text #define BUTT_MIN_SIZE 0 +#define BUTT_MAX_SIZE_SELECTABLE 5 #define BUTT_MAX_SIZE 8 \ No newline at end of file diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm index fb1a9fa74..d0abb7d46 100644 --- a/code/modules/client/preferences.dm +++ b/code/modules/client/preferences.dm @@ -2435,9 +2435,10 @@ GLOBAL_LIST_EMPTY(preferences_datums) features["belly_size"] = clamp(new_bellysize, BELLY_MIN_SIZE, BELLY_MAX_SIZE) if("butt_size") - var/new_buttsize = input(user, "Butt size :\n([BUTT_MIN_SIZE]-5)", "Character Preference") as num|null + var/new_buttsize = input(user, "Butt size :\n([BUTT_MIN_SIZE]-[BUTT_MAX_SIZE_SELECTABLE])", "Character Preference") as num|null if(new_buttsize != null) - features["butt_size"] = clamp(new_buttsize, BUTT_MIN_SIZE, 5) //Restricted to 5 in menu, because we have chems to make them big IC, like with breasts and what not. + features["butt_size"] = clamp(new_buttsize, BUTT_MIN_SIZE, BUTT_MAX_SIZE_SELECTABLE) + //Restricted to 5 in menu, because we have chems to make them big IC, like with breasts and what not. if("vag_shape") var/new_shape From 03bf3afede57e7697bbc4ba010f8d293bccf453e Mon Sep 17 00:00:00 2001 From: sarcoph <83266791+sarcoph@users.noreply.github.com> Date: Thu, 5 May 2022 03:07:13 -0800 Subject: [PATCH 19/28] getpercentaroused a little more sane to read --- modular_citadel/code/modules/arousal/arousal.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modular_citadel/code/modules/arousal/arousal.dm b/modular_citadel/code/modules/arousal/arousal.dm index 3da56d68b..d465c1f61 100644 --- a/modular_citadel/code/modules/arousal/arousal.dm +++ b/modular_citadel/code/modules/arousal/arousal.dm @@ -112,7 +112,7 @@ * despite the name of this, it actually returns a number between 0 and 100 */ /mob/living/proc/getPercentAroused() - var/percentage = ((100 / max_arousal) * arousalloss) + var/percentage = ((arousalloss / max_arousal) * 100) return percentage /mob/living/proc/isPercentAroused(percentage)//returns true if the mob's arousal (measured in a percent of 100) is greater than the arg percentage. From e555f0ea9143d8b83b70fdf4271eeaffb950fd25 Mon Sep 17 00:00:00 2001 From: sarcoph <83266791+sarcoph@users.noreply.github.com> Date: Thu, 5 May 2022 03:19:23 -0800 Subject: [PATCH 20/28] standardize genital visibility --- code/__DEFINES/hyper_arousal.dm | 7 ++++++- .../code/modules/arousal/arousalhud.dm | 10 +++++++++- .../code/modules/arousal/arousal.dm | 19 +++++-------------- .../code/modules/arousal/organs/genitals.dm | 7 +++---- 4 files changed, 23 insertions(+), 20 deletions(-) diff --git a/code/__DEFINES/hyper_arousal.dm b/code/__DEFINES/hyper_arousal.dm index 6b16fba9b..438a97898 100644 --- a/code/__DEFINES/hyper_arousal.dm +++ b/code/__DEFINES/hyper_arousal.dm @@ -6,4 +6,9 @@ #define BUTT_MIN_SIZE 0 #define BUTT_MAX_SIZE_SELECTABLE 5 -#define BUTT_MAX_SIZE 8 \ No newline at end of file +#define BUTT_MAX_SIZE 8 + + +#define GENITALS_HIDDEN "hidden" +#define GENITALS_CLOTHES "clothes" +#define GENITALS_VISIBLE "visible" diff --git a/hyperstation/code/modules/arousal/arousalhud.dm b/hyperstation/code/modules/arousal/arousalhud.dm index 375728cf5..757fd2330 100644 --- a/hyperstation/code/modules/arousal/arousalhud.dm +++ b/hyperstation/code/modules/arousal/arousalhud.dm @@ -11,7 +11,15 @@ for(var/obj/item/organ/genital/G in U.internal_organs) if(!G.nochange) if(!G.dontlist) - dat += "[G.mode == "hidden" ? "[G.name] (Hidden)" : (G.mode == "clothes" ? "[G.name] (Hidden by Clothes)" : (G.mode == "visable" ? "[G.name] (Visible)" : "[G.name] (Visible)"))]
" + var/genital_visibility = "[G.name] (Visible)" + switch(G.mode) + if(GENITALS_HIDDEN) + genital_visibility = "[G.name] (Hidden)" + if(GENITALS_CLOTHES) + genital_visibility = "[G.name] (Hidden by Clothes)" + if(GENITALS_VISIBLE) + genital_visibility = "[G.name] (Visible)" + dat += "[genital_visibility]
" dat += {"
Contexual Options

"} var/obj/item/organ/genital/penis/P = user.getorganslot("penis") diff --git a/modular_citadel/code/modules/arousal/arousal.dm b/modular_citadel/code/modules/arousal/arousal.dm index d465c1f61..e7f8b4f17 100644 --- a/modular_citadel/code/modules/arousal/arousal.dm +++ b/modular_citadel/code/modules/arousal/arousal.dm @@ -489,11 +489,9 @@ /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 + if(G.is_exposed()) //Nude or through_clothing if(!G.dontlist) genitals_list += G if(genitals_list.len) @@ -504,10 +502,8 @@ /mob/living/carbon/human/proc/target_genitals(mob/living/carbon/human/T) //used for targeting others 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 T.internal_organs) - if(G.is_exposed(worn_stuff)) //Nude or through_clothing + if(G.is_exposed()) //Nude or through_clothing if(!G.dontlist) genitals_list += G if(genitals_list.len) @@ -518,13 +514,9 @@ /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 - if(!G.dontlist) - genitals_list += G + if(G.can_climax && G.is_exposed() && !G.dontlist) + genitals_list += G if(genitals_list.len) ret_organ = input(src, "with what?", "Climax", null) as null|obj in genitals_list return ret_organ @@ -744,8 +736,7 @@ continue // no wombs or testicles var/mob/living/carbon/partner var/check_target - var/list/worn_stuff = get_equipped_items() - if(current_genital.is_exposed(worn_stuff)) + if(current_genital.is_exposed()) if(src.pulling) if(iscarbon(src.pulling)) check_target = src.pulling diff --git a/modular_citadel/code/modules/arousal/organs/genitals.dm b/modular_citadel/code/modules/arousal/organs/genitals.dm index bdf4d7856..9edea910a 100644 --- a/modular_citadel/code/modules/arousal/organs/genitals.dm +++ b/modular_citadel/code/modules/arousal/organs/genitals.dm @@ -78,22 +78,21 @@ if("Always visible") through_clothes = TRUE hidden = FALSE - mode = "visible" + mode = GENITALS_VISIBLE if(!(src in owner.exposed_genitals)) owner.exposed_genitals += src if("Hidden by clothes") through_clothes = FALSE hidden = FALSE - mode = "clothes" + mode = GENITALS_CLOTHES if(src in owner.exposed_genitals) owner.exposed_genitals -= src if("Always hidden") through_clothes = FALSE hidden = TRUE - mode = "hidden" + mode = GENITALS_HIDDEN if(src in owner.exposed_genitals) owner.exposed_genitals -= src - if(ishuman(owner)) //recast to use update genitals proc var/mob/living/carbon/human/H = owner H.update_genitals() From 42f33b2194b186879370ac35e964a74dea9783a5 Mon Sep 17 00:00:00 2001 From: sarcoph <83266791+sarcoph@users.noreply.github.com> Date: Thu, 5 May 2022 05:01:50 -0800 Subject: [PATCH 21/28] portallight cleanup --- code/__DEFINES/hyper_arousal.dm | 1 - hyperstation/code/obj/fleshlight.dm | 153 +++++++++--------- .../code/modules/arousal/arousal.dm | 34 ++-- 3 files changed, 94 insertions(+), 94 deletions(-) diff --git a/code/__DEFINES/hyper_arousal.dm b/code/__DEFINES/hyper_arousal.dm index 438a97898..a0450b138 100644 --- a/code/__DEFINES/hyper_arousal.dm +++ b/code/__DEFINES/hyper_arousal.dm @@ -8,7 +8,6 @@ #define BUTT_MAX_SIZE_SELECTABLE 5 #define BUTT_MAX_SIZE 8 - #define GENITALS_HIDDEN "hidden" #define GENITALS_CLOTHES "clothes" #define GENITALS_VISIBLE "visible" diff --git a/hyperstation/code/obj/fleshlight.dm b/hyperstation/code/obj/fleshlight.dm index a7410a204..2bbd063db 100644 --- a/hyperstation/code/obj/fleshlight.dm +++ b/hyperstation/code/obj/fleshlight.dm @@ -94,7 +94,6 @@ var/paired = 0 var/obj/item/portalunderwear var/useable = FALSE - var/option = "" /obj/item/portallight/examine(mob/user) . = ..() @@ -104,103 +103,103 @@ . += "The device is paired, and awaiting input. " /obj/item/portallight/attack(mob/living/carbon/holder, mob/living/user) -//use portallight! nearly the same as the fleshlight apart from you have a buddy! - var/obj/item/organ/genital/penis/P = holder.getorganslot("penis") if(inuse) //just to stop stacking and causing people to cum instantly return - if(!useable) - to_chat(user, "It seems the device has failed or your partner is not wearing their device.") - if(holder == user)//if your using it on yourself, more options! otherwise, just fuck. - option = input(usr, "Choose action", "Portal Fleshlight", "Fuck") in list("Fuck", "Lick", "Touch") - else - option = "Fuck" - var/obj/item/organ/genital/target_genital - if(istype(portalunderwear.loc, /obj/item/organ/genital)) //Sanity check. Without this it will runtime error. - target_genital = portalunderwear.loc - if(!target_genital) + if(!UpdateUsability()) + to_chat(user, "\The [src] appears to be currently unusable.") return + var/option = "Fuck" + if(holder == user) + option = input(usr, "Choose action", "Portal Fleshlight", "Fuck") in list("Fuck", "Lick", "Touch") + var/obj/item/organ/genital/target_genital = portalunderwear.loc var/mob/living/carbon/human/target = target_genital.owner - if(option == "Fuck"&&!P.is_exposed()) //we are trying to fuck with no penis! + var/obj/item/organ/genital/penis/P = holder.getorganslot("penis") + if(option == "Fuck" && !P.is_exposed()) to_chat(user, "You don't see anywhere to use this on.") return - else //other options dont need checks - inuse = 1 - if(!(holder == user)) //if we are targeting someone else. - holder.visible_message("[user] is trying to use [src] on [holder]'s penis.", "[user] is trying to use [src] on your penis.") - if(!do_mob(user, holder, 3 SECONDS)) //3 second delay - inuse = 0 - return - //checked if not used on yourself, if not, carry on. - if(option == "Fuck") - playsound(src, 'sound/lewd/slaps.ogg', 30, 1, -1) //slapping sound for fuck. - inuse = 0 - if(!(holder == user)) - holder.visible_message("[user] pumps [src] on [holder]'s penis.", "[user] pumps [src] up and down on your penis.") - else - if(option == "Fuck") - user.visible_message("[user] pumps [src] on their penis.", "You pump the fleshlight on your penis.") - if(option == "Lick") - user.visible_message("[user] licks into [src].", "You lick into [src].") - if(option == "Touch") - user.visible_message("[user] touches softly against [src].", "You touch softly on [src].") - if(prob(30)) //30% chance to make your partner moan. - target.emote("moan") - if(option == "Fuck")// normal fuck - to_chat(target, "You feel a [P.length] inch, [P.shape] shaped penis pumping through the portal into your [target_genital.name].")//message your partner, and kinky! - if(prob(30)) //30% chance to make them moan. + /* + WARMUP START - prevents spam/instant climax + */ + inuse = TRUE + if(holder != user) + holder.visible_message("[user] is trying to use [src] on [holder]'s penis.",\ + "[user] is trying to use [src] on your penis.") + if(!do_mob(user, holder, 3 SECONDS)) + inuse = FALSE + return + inuse = FALSE + /* + WARMUP END - proceed with the action + */ + switch(option) + if("Fuck") + playsound(src, 'sound/lewd/slaps.ogg', 30, 1, -1) + if(holder == user) + user.visible_message("[user] pumps [src] on their penis.", + "You pump the fleshlight on your penis.") + else + holder.visible_message("[user] pumps [src] on [holder]'s penis.",\ + "[user] pumps [src] up and down on your penis.") + to_chat(target, "You feel a [P.length] inch, [P.shape] shaped penis pumping through the portal into your [target_genital.name].") + if(prob(30)) holder.emote("moan") - if(prob(30)) //30% chance to make your partner moan. - target.emote("moan") holder.adjustArousalLoss(20) target.adjustArousalLoss(20) - target.do_jitter_animation() //make your partner shake too! - // Why not have a probability to cum when someone's getting nailed with max arousal?~ - if (target.can_orgasm() && prob(5)) - // if vagina is not exposed, the climax will not cause a spill - target.mob_climax_outside(target_genital, target_genital.is_exposed()) - if (holder.can_orgasm()) + target.do_jitter_animation() + if(target.can_orgasm() && prob(5)) + target.mob_climax_outside(target_genital, spillage = target_genital.is_exposed()) + if(holder.can_orgasm()) var/mob/living/carbon/human/O = holder var/impreg_chance = target_genital.name == "vagina" && !P.condom && !P.sounding O.mob_climax_partner(P, target, FALSE, impreg_chance, FALSE, TRUE) - if(option == "Lick") + if("Lick") + user.visible_message("[user] licks into [src].",\ + "You lick into [src].") to_chat(target, "You feel a tongue lick you through the portal against your [target_genital.name].") target.adjustArousalLoss(10) - if(option == "Touch") + if("Touch") + user.visible_message("[user] touches softly against [src].",\ + "You touch softly on [src].") to_chat(target, "You feel someone touching your [target_genital.name] through the portal.") target.adjustArousalLoss(5) - return + if(prob(30)) + target.emote("moan") ..() /obj/item/portallight/proc/updatesleeve() //get their looks and vagina colour! - cut_overlays()//remove current overlays - var/obj/item/organ/genital/G - if(istype(portalunderwear.loc, /obj/item/organ/genital)) //Sanity check. Without this it will runtime. - G = portalunderwear.loc - if(!G) - useable = FALSE + cut_overlays() + if(!UpdateUsability()) return - var/mob/living/carbon/human/H = G.owner - if(H) //if the portal panties are on someone. - sleeve = mutable_appearance('hyperstation/icons/obj/fleshlight.dmi', "portal_sleeve_normal") - if(H.dna.species.name == "Lizardperson") // lizard nerd - sleeve = mutable_appearance('hyperstation/icons/obj/fleshlight.dmi', "portal_sleeve_lizard") - if(H.dna.species.name == "Slimeperson") // slime nerd - sleeve = mutable_appearance('hyperstation/icons/obj/fleshlight.dmi', "portal_sleeve_slime") - if(H.dna.species.name == "Avian") // bird nerd - sleeve = mutable_appearance('hyperstation/icons/obj/fleshlight.dmi', "portal_sleeve_avian") - sleeve.color = "#" + H.dna.features["mcolor"] - add_overlay(sleeve) - if(G.name == "vagina") - organ = mutable_appearance('hyperstation/icons/obj/fleshlight.dmi', "portal_vag") - organ.color = portalunderwear.loc.color - if(G.name == "anus") - organ = mutable_appearance('hyperstation/icons/obj/fleshlight.dmi', "portal_anus") - organ.color = "#" + H.dna.features["mcolor"] - useable = TRUE - add_overlay(organ) - else - useable = FALSE + var/obj/item/organ/genital/G = portalunderwear.loc + var/mob/living/carbon/human/H = G.owner // H is verified by UpdateUsability() + var/sleeve_species = "normal" + switch(H.dna.species.name) + if("Lizardperson") + sleeve_species = "lizard" + if("Slimeperson") + sleeve_species = "slime" + if("Avian") + sleeve_species = "avian" + sleeve = mutable_appearance('hyperstation/icons/obj/fleshlight.dmi', "portal_sleeve_[sleeve_species]") + sleeve.color = "#" + H.dna.features["mcolor"] + add_overlay(sleeve) + if(G.name == "vagina") + organ = mutable_appearance('hyperstation/icons/obj/fleshlight.dmi', "portal_vag") + organ.color = portalunderwear.loc.color + if(G.name == "anus") + organ = mutable_appearance('hyperstation/icons/obj/fleshlight.dmi', "portal_anus") + organ.color = "#" + H.dna.features["mcolor"] + add_overlay(organ) + +/obj/item/portallight/proc/UpdateUsability() + var/useable = FALSE + if(portalunderwear && istype(portalunderwear.loc, /obj/item/organ/genital)) + var/obj/item/organ/genital/loc_genitals = portalunderwear.loc + if(loc_genitals.owner && ishuman(loc_genitals.owner)) + useable = TRUE + src.useable = useable + return useable //Hyperstation 13 portal underwear diff --git a/modular_citadel/code/modules/arousal/arousal.dm b/modular_citadel/code/modules/arousal/arousal.dm index e7f8b4f17..682edba75 100644 --- a/modular_citadel/code/modules/arousal/arousal.dm +++ b/modular_citadel/code/modules/arousal/arousal.dm @@ -285,7 +285,8 @@ setArousalLoss(min_arousal) -/mob/living/carbon/human/proc/mob_climax_outside(obj/item/organ/genital/G, mb_time = 30, spillage = TRUE) //This is used for forced orgasms and other hands-free climaxes +/mob/living/carbon/human/proc/mob_climax_outside(obj/item/organ/genital/G, mb_time = 30, spillage = TRUE) +//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 @@ -736,21 +737,22 @@ continue // no wombs or testicles var/mob/living/carbon/partner var/check_target - if(current_genital.is_exposed()) - if(src.pulling) - if(iscarbon(src.pulling)) - check_target = src.pulling - else if(src.pulledby) - if(iscarbon(src.pulledby)) - check_target = src.pulledby - if(check_target) - var/mob/living/carbon/C = check_target - if(C.exposed_genitals.len || C.is_groin_exposed() || C.is_chest_exposed()) - partner = C - if(partner) - user_human.mob_climax_partner(current_genital, partner, mb_time = 0) - continue - user_human.mob_climax_outside(current_genital, mb_time = 0) + if(!current_genital.is_exposed()) + user_human.mob_climax_outside(current_genital, mb_time = 0) + continue + if(src.pulling) + if(iscarbon(src.pulling)) + check_target = src.pulling + else if(src.pulledby) + if(iscarbon(src.pulledby)) + check_target = src.pulledby + if(check_target) + var/mob/living/carbon/C = check_target + if(C.exposed_genitals.len || C.is_groin_exposed() || C.is_chest_exposed()) + partner = C + if(partner) + user_human.mob_climax_partner(current_genital, partner, mb_time = 0) + continue return From 5bd0427c22178328d88cfb25e8218f81d9464140 Mon Sep 17 00:00:00 2001 From: sarcoph <83266791+sarcoph@users.noreply.github.com> Date: Thu, 5 May 2022 05:08:18 -0800 Subject: [PATCH 22/28] mob_climax_forced -> mob_climax_instant "mob_climax_instant()" feels like a better representation of what the proc does. "forced" has a very negative connotation even though contextually, it's just used for any climaxes caused by indirect arousal gain, with no warmup time or selection menus. --- code/modules/mob/living/carbon/human/species.dm | 4 ++-- code/modules/mob/living/carbon/life.dm | 2 +- code/modules/ruins/objects_and_mobs/sin_ruins.dm | 2 +- code/modules/surgery/organs/vocal_cords.dm | 4 ++-- hyperstation/code/obj/fleshlight.dm | 2 +- hyperstation/code/obj/vibrator.dm | 4 ++-- modular_citadel/code/datums/status_effects/chems.dm | 2 +- modular_citadel/code/modules/arousal/arousal.dm | 2 +- .../modules/integrated_electronics/subtypes/manipulation.dm | 2 +- 9 files changed, 12 insertions(+), 12 deletions(-) diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm index 57ce2307c..7238bae03 100644 --- a/code/modules/mob/living/carbon/human/species.dm +++ b/code/modules/mob/living/carbon/human/species.dm @@ -1648,7 +1648,7 @@ GLOBAL_LIST_EMPTY(roundstart_races) if (target.canbearoused) target.adjustArousalLoss(5) if (target.can_orgasm() && HAS_TRAIT(target, TRAIT_MASO)) - target.mob_climax_forced() + target.mob_climax_instant() if (!HAS_TRAIT(target, TRAIT_NYMPHO)) stop_wagging_tail(target) @@ -2006,7 +2006,7 @@ GLOBAL_LIST_EMPTY(roundstart_races) if(HAS_TRAIT(H, TRAIT_MASO)) H.adjustArousalLoss(damage * brutemod * H.physiology.brute_mod) if (H.can_orgasm()) - H.mob_climax_forced() + H.mob_climax_instant() else//no bodypart, we deal damage with a more general method. H.adjustBruteLoss(damage * hit_percent * brutemod * H.physiology.brute_mod) diff --git a/code/modules/mob/living/carbon/life.dm b/code/modules/mob/living/carbon/life.dm index 7484bdbd6..310eb3d7f 100644 --- a/code/modules/mob/living/carbon/life.dm +++ b/code/modules/mob/living/carbon/life.dm @@ -78,7 +78,7 @@ if(HAS_TRAIT(B, TRAIT_CHOKE_SLUT)) B.adjustArousalLoss(7) if (B.can_orgasm()) - B.mob_climax_forced() + B.mob_climax_instant() else SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "suffocation", /datum/mood_event/suffocation) else diff --git a/code/modules/ruins/objects_and_mobs/sin_ruins.dm b/code/modules/ruins/objects_and_mobs/sin_ruins.dm index c4ca810ba..edd7734a8 100644 --- a/code/modules/ruins/objects_and_mobs/sin_ruins.dm +++ b/code/modules/ruins/objects_and_mobs/sin_ruins.dm @@ -290,7 +290,7 @@ return if(user.can_orgasm()) var/mob/living/carbon/user_carbon = user - user_carbon.mob_climax_forced() + user_carbon.mob_climax_instant() to_chat(user, "You hear a voice in your head... \"You are worthy of my blessing, dear~\"") to_chat(user, "You feel overpowering pleasure surge through your entire body.") var/A = new /obj/item/reagent_containers/chalice/lust diff --git a/code/modules/surgery/organs/vocal_cords.dm b/code/modules/surgery/organs/vocal_cords.dm index 3d9b5d637..7c6fe05ca 100644 --- a/code/modules/surgery/organs/vocal_cords.dm +++ b/code/modules/surgery/organs/vocal_cords.dm @@ -581,7 +581,7 @@ for(var/V in listeners) var/mob/living/carbon/human/H = V if(H.canbearoused && H.has_dna() && HAS_TRAIT(H, TRAIT_NYMPHO)) // probably a redundant check but for good measure - H.mob_climax_forced() + H.mob_climax_instant() */ else if((findtext(message, family_friendly_words))) cooldown = COOLDOWN_MEME @@ -1123,7 +1123,7 @@ if(E.phase > 1) if(HAS_TRAIT(H, TRAIT_NYMPHO) && H.canbearoused && E.lewd) // probably a redundant check but for good measure addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, H, "Your [E.enthrallGender] pushes you over the limit, overwhelming your body with pleasure."), 5) - H.mob_climax_forced() + H.mob_climax_instant() H.SetStun(20) H.setArousalLoss(H.min_arousal) E.resistanceTally = 0 //makes resistance 0, but resets arousal, resistance buildup is faster unaroused (massively so). diff --git a/hyperstation/code/obj/fleshlight.dm b/hyperstation/code/obj/fleshlight.dm index 2bbd063db..8a6932906 100644 --- a/hyperstation/code/obj/fleshlight.dm +++ b/hyperstation/code/obj/fleshlight.dm @@ -64,7 +64,7 @@ C.do_jitter_animation() C.adjustArousalLoss(20) //make the target more aroused. if (C.can_orgasm()) - C.mob_climax_forced() //make them cum if they are over the edge. + C.mob_climax_instant() //make them cum if they are over the edge. return diff --git a/hyperstation/code/obj/vibrator.dm b/hyperstation/code/obj/vibrator.dm index f0911b4f3..bef2a7969 100644 --- a/hyperstation/code/obj/vibrator.dm +++ b/hyperstation/code/obj/vibrator.dm @@ -133,13 +133,13 @@ Code: to_chat(U, "You feel intense pleasure surge through your [G.name]") U.do_jitter_animation() if (U.can_orgasm()) - U.mob_climax_forced() + U.mob_climax_instant() if(3) //high, makes you stun to_chat(U, "You feel overpowering pleasure surge through your [G.name]") U.Jitter(3) U.Stun(30) if (U.can_orgasm()) - U.mob_climax_forced() + U.mob_climax_instant() if(prob(50)) U.emote("moan") diff --git a/modular_citadel/code/datums/status_effects/chems.dm b/modular_citadel/code/datums/status_effects/chems.dm index 2720bc97c..433c20135 100644 --- a/modular_citadel/code/datums/status_effects/chems.dm +++ b/modular_citadel/code/datums/status_effects/chems.dm @@ -620,7 +620,7 @@ else if (lowertext(customTriggers[trigger]) == "cum")//aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa if (HAS_TRAIT(C, TRAIT_NYMPHO) && lewd) if (C.getArousalLoss() > 80) - C.mob_climax_forced() + C.mob_climax_instant() C.SetStun(10)//We got your stun effects in somewhere, Kev. else C.adjustArousalLoss(10) diff --git a/modular_citadel/code/modules/arousal/arousal.dm b/modular_citadel/code/modules/arousal/arousal.dm index 682edba75..f41d1ee58 100644 --- a/modular_citadel/code/modules/arousal/arousal.dm +++ b/modular_citadel/code/modules/arousal/arousal.dm @@ -722,7 +722,7 @@ return //Just end it in that case. -/mob/living/carbon/proc/mob_climax_forced() +/mob/living/carbon/proc/mob_climax_instant() if(stat == DEAD) //corpses can't cum to_chat(src, "You can't do that while dead!") return diff --git a/modular_citadel/code/modules/integrated_electronics/subtypes/manipulation.dm b/modular_citadel/code/modules/integrated_electronics/subtypes/manipulation.dm index 6ec3687b4..e3eab59c5 100644 --- a/modular_citadel/code/modules/integrated_electronics/subtypes/manipulation.dm +++ b/modular_citadel/code/modules/integrated_electronics/subtypes/manipulation.dm @@ -30,7 +30,7 @@ var/orgasm_message = pick("A sharp pulse of electricity pushes you to orgasm!", "You feel a jolt of electricity force you into orgasm!") H.visible_message("\The [assembly] electrodes shock [H]!", "[orgasm_message]") playsound(src, "sound/effects/light_flicker.ogg", 30, 1) - H.mob_climax_forced() + H.mob_climax_instant() orgasm = TRUE else M.adjustArousalLoss(arousal_gain) From 8db668700610846ef28692e85087e7c5667d4b2a Mon Sep 17 00:00:00 2001 From: sarcoph <83266791+sarcoph@users.noreply.github.com> Date: Thu, 5 May 2022 08:17:59 -0800 Subject: [PATCH 23/28] documentation and modularization "mob_climax_cover" is now separate from "mob_climax_partner", and impreg chance is separated from those as well --- .../code/modules/arousal/arousalhud.dm | 15 +- .../code/modules/arousal/organs/genitals.dm | 6 + hyperstation/code/obj/fleshlight.dm | 41 +- .../code/modules/arousal/arousal.dm | 391 +++++++++--------- tgstation.dme | 1 + 5 files changed, 241 insertions(+), 213 deletions(-) create mode 100644 hyperstation/code/modules/arousal/organs/genitals.dm diff --git a/hyperstation/code/modules/arousal/arousalhud.dm b/hyperstation/code/modules/arousal/arousalhud.dm index 757fd2330..586e6608c 100644 --- a/hyperstation/code/modules/arousal/arousalhud.dm +++ b/hyperstation/code/modules/arousal/arousalhud.dm @@ -334,7 +334,7 @@ obj/screen/arousal/proc/kiss() return //We got hands, let's pick an organ var/obj/item/organ/genital/picked_organ - picked_organ = pick_masturbate_genitals() + picked_organ = pick_climax_genitals(masturbation=TRUE, title="Masturbation") if(picked_organ) src << browse(null, "window=arousal") //closes the window mob_masturbate(picked_organ) @@ -378,7 +378,7 @@ obj/screen/arousal/proc/kiss() to_chat(src, "You cannot climax without choosing genitals.") return src << browse(null, "window=arousal") // close arousal window - mob_climax_partner_spillage(picked_organ, partner, FALSE) + mob_climax_partner_spillage(picked_organ, partner, impreg=FALSE) /mob/living/carbon/human/proc/climaxover(mob/living/carbon/human/partner) @@ -398,7 +398,7 @@ obj/screen/arousal/proc/kiss() if(P.sounding) to_chat(src, "You cannot do this action with a sounding in.") return - mob_climax_partner(picked_organ, partner, FALSE, FALSE, TRUE) + mob_climax_cover(picked_organ, partner) /mob/living/carbon/human/proc/clothesplosion() @@ -435,7 +435,7 @@ obj/screen/arousal/proc/kiss() to_chat(src, "You cannot impregnate someone with a sounding rod in.") return src << browse(null, "window=arousal") //alls fine, we can close the window now. - mob_climax_partner_spillage(picked_organ, partner, TRUE) + mob_climax_partner_spillage(picked_organ, partner, impreg=TRUE) /mob/living/carbon/human/proc/cumcontainer(mob/living/T) @@ -476,6 +476,11 @@ obj/screen/arousal/proc/kiss() cum_splatter_icon.Blend(icon('hyperstation/icons/effects/cumoverlay.dmi', "cum_obj"), ICON_MULTIPLY) add_overlay(cum_splatter_icon) +/mob/living/carbon/add_cum_overlay(type="normal") + var/mutable_appearance/cumoverlay = mutable_appearance('hyperstation/icons/effects/cumoverlay.dmi') + cumoverlay.icon_state = "cum_[type]" + add_overlay(cumoverlay) + /atom/proc/wash_cum() cut_overlay(mutable_appearance('hyperstation/icons/effects/cumoverlay.dmi', "cum_normal")) cut_overlay(mutable_appearance('hyperstation/icons/effects/cumoverlay.dmi', "cum_large")) @@ -499,7 +504,7 @@ obj/screen/arousal/proc/kiss() return //We got hands, let's pick an organ var/obj/item/organ/genital/picked_organ - picked_organ = pick_masturbate_genitals() + picked_organ = pick_climax_genitals(masturbation=TRUE, title="Masturbation") if(picked_organ) src << browse(null, "window=arousal") //closes the window mob_masturbate(picked_organ, cover = TRUE) diff --git a/hyperstation/code/modules/arousal/organs/genitals.dm b/hyperstation/code/modules/arousal/organs/genitals.dm new file mode 100644 index 000000000..9da552021 --- /dev/null +++ b/hyperstation/code/modules/arousal/organs/genitals.dm @@ -0,0 +1,6 @@ +/obj/item/organ/genital/proc/get_fluid_source() + if(producing) + return src.reagents + if(linked_organ && linked_organ.producing) + return linked_organ.reagents + return null \ No newline at end of file diff --git a/hyperstation/code/obj/fleshlight.dm b/hyperstation/code/obj/fleshlight.dm index 8a6932906..3d5c7ab48 100644 --- a/hyperstation/code/obj/fleshlight.dm +++ b/hyperstation/code/obj/fleshlight.dm @@ -102,29 +102,29 @@ else . += "The device is paired, and awaiting input. " -/obj/item/portallight/attack(mob/living/carbon/holder, mob/living/user) +/obj/item/portallight/attack(mob/living/carbon/user, mob/living/holder) if(inuse) //just to stop stacking and causing people to cum instantly return if(!UpdateUsability()) - to_chat(user, "\The [src] appears to be currently unusable.") + to_chat(holder, "\The [src] appears to be currently unusable.") return var/option = "Fuck" - if(holder == user) + if(user == holder) option = input(usr, "Choose action", "Portal Fleshlight", "Fuck") in list("Fuck", "Lick", "Touch") var/obj/item/organ/genital/target_genital = portalunderwear.loc var/mob/living/carbon/human/target = target_genital.owner - var/obj/item/organ/genital/penis/P = holder.getorganslot("penis") + var/obj/item/organ/genital/penis/P = user.getorganslot("penis") if(option == "Fuck" && !P.is_exposed()) - to_chat(user, "You don't see anywhere to use this on.") + to_chat(holder, "You don't see anywhere to use this on.") return /* WARMUP START - prevents spam/instant climax */ inuse = TRUE - if(holder != user) - holder.visible_message("[user] is trying to use [src] on [holder]'s penis.",\ - "[user] is trying to use [src] on your penis.") - if(!do_mob(user, holder, 3 SECONDS)) + if(user != holder) + user.visible_message("[holder] is trying to use [src] on [user]'s penis.",\ + "[holder] is trying to use [src] on your penis.") + if(!do_mob(holder, user, 3 SECONDS)) inuse = FALSE return inuse = FALSE @@ -134,31 +134,32 @@ switch(option) if("Fuck") playsound(src, 'sound/lewd/slaps.ogg', 30, 1, -1) - if(holder == user) - user.visible_message("[user] pumps [src] on their penis.", + if(user == holder) + holder.visible_message("[holder] pumps [src] on their penis.", "You pump the fleshlight on your penis.") else - holder.visible_message("[user] pumps [src] on [holder]'s penis.",\ - "[user] pumps [src] up and down on your penis.") + user.visible_message("[holder] pumps [src] on [user]'s penis.",\ + "[holder] pumps [src] up and down on your penis.") to_chat(target, "You feel a [P.length] inch, [P.shape] shaped penis pumping through the portal into your [target_genital.name].") if(prob(30)) - holder.emote("moan") - holder.adjustArousalLoss(20) + user.emote("moan") + user.adjustArousalLoss(20) target.adjustArousalLoss(20) target.do_jitter_animation() if(target.can_orgasm() && prob(5)) target.mob_climax_outside(target_genital, spillage = target_genital.is_exposed()) - if(holder.can_orgasm()) - var/mob/living/carbon/human/O = holder + if(user.can_orgasm()) + var/mob/living/carbon/human/O = user var/impreg_chance = target_genital.name == "vagina" && !P.condom && !P.sounding - O.mob_climax_partner(P, target, FALSE, impreg_chance, FALSE, TRUE) + if(O.mob_climax_partner(P, target, spillage=FALSE, remote=TRUE) && impreg_chance) + target.impregnate(by=O) if("Lick") - user.visible_message("[user] licks into [src].",\ + holder.visible_message("[holder] licks into [src].",\ "You lick into [src].") to_chat(target, "You feel a tongue lick you through the portal against your [target_genital.name].") target.adjustArousalLoss(10) if("Touch") - user.visible_message("[user] touches softly against [src].",\ + holder.visible_message("[holder] touches softly against [src].",\ "You touch softly on [src].") to_chat(target, "You feel someone touching your [target_genital.name] through the portal.") target.adjustArousalLoss(5) diff --git a/modular_citadel/code/modules/arousal/arousal.dm b/modular_citadel/code/modules/arousal/arousal.dm index f41d1ee58..8d2de3d34 100644 --- a/modular_citadel/code/modules/arousal/arousal.dm +++ b/modular_citadel/code/modules/arousal/arousal.dm @@ -189,19 +189,30 @@ if(M.canbearoused) ui_interact(usr) +/** + * Checks if this mob can orgasm. Criteria includes: + * - Mob is human + * - Mob is capable of arousal + * - Mob has DNA + * - Mob is aroused past a certain threshold + * + * Arguments: + * - `arousal` - The minimum arousal needed to pass the check. Default is `100`. + * + * Returns: `TRUE/FALSE` - Whether or not the mob passes all of the above checks. + */ /mob/living/proc/can_orgasm(arousal = 100) return src.canbearoused && src.getArousalLoss() >= arousal && ishuman(src) && src.has_dna() + /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" if(canbearoused && !restrained() && !stat) if(mb_cd_timer <= world.time) //start the cooldown even if it fails mb_cd_timer = world.time + mb_cd_length - if(getArousalLoss() >= isPercentAroused(33))//33% arousal or greater required + if(isPercentAroused(33))//33% arousal or greater required src.visible_message("[src] starts masturbating!", \ "You start masturbating.") if(do_after(src, 30, target = src)) @@ -213,33 +224,24 @@ to_chat(src, "You aren't aroused enough for that.") -//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, cover = FALSE, mb_time = 30) -//Masturbation, keep it gender-neutral var/total_fluids = 0 - var/datum/reagents/fluid_source = null - var/condomed = 0 - var/sounded = 0 - if(G.name == "penis")//if the select organ is a penis + var/datum/reagents/fluid_source = G.get_fluid_source() + var/condomed = FALSE + var/sounded = FALSE + if(G.name == "penis") var/obj/item/organ/genital/penis/P = src.getorganslot("penis") - if(P.condom) //if the penis is condomed - condomed = 1 - if(P.sounding) - sounded = 1 - 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 + condomed = P.condom + sounded = P.sounding + if(!fluid_source) + to_chat(src, "Your [G.name] is unable to produce it's own fluids, it's missing the organs for it.") + return total_fluids = fluid_source.total_volume 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].", \ "You start to [G.masturbation_verb] your [G.name].") - if(do_after(src, mb_time, target = src)) if(total_fluids > 5 &&!condomed &&!sounded) fluid_source.reaction(src.loc, TOUCH, 1, 0) @@ -248,14 +250,11 @@ 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.") - if(!condomed &&!sounded && cover)//For when you want to make a mess of yourself. fluid_source.trans_to(src, total_fluids*G.fluid_transfer_factor) total_fluids -= total_fluids*G.fluid_transfer_factor if(total_fluids > 80) // now thats a big cum! - var/mutable_appearance/cumoverlaylarge = mutable_appearance('hyperstation/icons/effects/cumoverlay.dmi') - cumoverlaylarge.icon_state = "cum_large" - src.add_overlay(cumoverlaylarge) + src.add_cum_overlay("large") if(total_fluids > 5) fluid_source.reaction(src.loc, TOUCH, 1, 0) var/mob/living/carbon/human/H = src @@ -265,10 +264,7 @@ src.visible_message("[src] climaxes over [p_their()] self, using [p_their()] [G.name]!", \ "You orgasm over yourself, using your [G.name].", \ "You have climaxed over something, using your [G.name].") - var/mutable_appearance/cumoverlay = mutable_appearance('hyperstation/icons/effects/cumoverlay.dmi') - cumoverlay.icon_state = "cum_normal" - src.add_overlay(cumoverlay) - + src.add_cum_overlay() if(condomed) //condomed src.visible_message("[src] orgasms, climaxing into [p_their()] condom!", \ "You cum into your condom.", \ @@ -279,7 +275,6 @@ "You don't quite feel totally relieved.") if(total_fluids > 0 &&condomed &&!sounded) src.condomclimax() - SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "orgasm", /datum/mood_event/orgasm) if(G.can_climax) setArousalLoss(min_arousal) @@ -288,19 +283,12 @@ /mob/living/carbon/human/proc/mob_climax_outside(obj/item/organ/genital/G, mb_time = 30, spillage = TRUE) //This is used for forced orgasms and other hands-free climaxes var/total_fluids = 0 - var/datum/reagents/fluid_source = null + var/datum/reagents/fluid_source = G.get_fluid_source() var/unable_to_come = FALSE - - if(G.producing) //Can it produce its own fluids, such as breasts? - fluid_source = G.reagents + if(fluid_source) 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 - + unable_to_come = TRUE if(unable_to_come) src.visible_message("[src] shudders, their [G.name] unable to cum.", \ "Your [G.name] cannot cum, giving no relief.", \ @@ -323,108 +311,107 @@ src.visible_message("[src] orgasms with [p_their()] [G.name]!", \ "You climax 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) -/mob/living/carbon/human/proc/mob_climax_partner(obj/item/organ/genital/G, atom/partner, spillage = TRUE, impreg = FALSE,cover = FALSE,remote = FALSE, mb_time = 30) //Used for climaxing with any person - if(isnoncarbon(partner)) // deny animals - return +/mob/living/carbon/human/proc/mob_climax_cover(obj/item/organ/genital/genital, atom/partner, mb_time=3 SECONDS) 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 + var/datum/reagents/fluid_source = genital.get_fluid_source() + if(!fluid_source) + to_chat(src, "Your [genital.name] is unable to produce it's own fluids, it's missing the organs for it.") + return total_fluids = fluid_source.total_volume - if(mb_time && !remote) //Skip warning if this is an instant climax. + var/mob/living/carbon/partner_carbon = partner + if(mb_time) src.visible_message("[src] is about to climax with [partner]!", \ "You're about to climax with [partner]!", \ "You're preparing to climax with something!") + if(!do_after(src, mb_time, target = src)) + return + if(!in_range(src, partner)) + return + var/transferred_units = total_fluids * genital.fluid_transfer_factor + fluid_source.trans_to(partner, transferred_units) + total_fluids -= transferred_units + if(total_fluids > 80 && iscarbon(partner)) // now thats a big cum! + partner_carbon.add_cum_overlay("large") + if(total_fluids > 5) + fluid_source.reaction(partner.loc, TOUCH, 1, 0) + var/mob/living/carbon/human/H = partner + if(H) + H.cumdrip_rate += rand(5,10) + fluid_source.clear_reagents() + if(iscarbon(partner)) + partner_carbon.add_cum_overlay("normal") + else + partner.add_cum_overlay() + src.visible_message("[src] climaxes over [partner], using [p_their()] [genital.name]!", \ + "You orgasm over [partner], using your [genital.name].", \ + "You have climaxed over something, using your [genital.name].") + SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "orgasm", /datum/mood_event/orgasm) + setArousalLoss(min_arousal) + + +/mob/living/carbon/human/proc/mob_climax_partner(obj/item/organ/genital/G, atom/partner, spillage=TRUE, remote=FALSE, mb_time = 3 SECONDS) + if(isnoncarbon(partner)) // deny animals + return FALSE + var/total_fluids = 0 + var/datum/reagents/fluid_source = G.get_fluid_source() + if(!fluid_source) + to_chat(src, "Your [G.name] is unable to produce it's own fluids, it's missing the organs for it.") + return FALSE + total_fluids = fluid_source.total_volume if(remote) src.visible_message("[src] is about to climax with someone!", \ "You're about to climax with someone!", \ "You're preparing to climax with something!") - if(cover)//covering the partner in cum, this overrides other options. - if(do_after(src, mb_time, target = src) && in_range(src, partner)) - fluid_source.trans_to(partner, total_fluids*G.fluid_transfer_factor) - total_fluids -= total_fluids*G.fluid_transfer_factor - if(total_fluids > 80 && iscarbon(partner)) // now thats a big cum! - var/mutable_appearance/cumoverlaylarge = mutable_appearance('hyperstation/icons/effects/cumoverlay.dmi') - cumoverlaylarge.icon_state = "cum_large" - partner.add_overlay(cumoverlaylarge) - if(total_fluids > 5) - fluid_source.reaction(partner.loc, TOUCH, 1, 0) - var/mob/living/carbon/human/H = partner - if(H) - H.cumdrip_rate += rand(5,10) - fluid_source.clear_reagents() - src.visible_message("[src] climaxes over [partner], using [p_their()] [G.name]!", \ - "You orgasm over [partner], using your [G.name].", \ - "You have climaxed over something, using your [G.name].") - SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "orgasm", /datum/mood_event/orgasm) - if(iscarbon(partner)) - var/mutable_appearance/cumoverlay = mutable_appearance('hyperstation/icons/effects/cumoverlay.dmi') - cumoverlay.icon_state = "cum_normal" - partner.add_overlay(cumoverlay) - else - partner.add_cum_overlay() - setArousalLoss(min_arousal) - if(G.can_climax) - setArousalLoss(min_arousal) - if(spillage && !cover) - if(do_after(src, mb_time, target = src)) - if(!in_range(src, partner) && !remote) - return - fluid_source.trans_to(partner, total_fluids*G.fluid_transfer_factor) - total_fluids -= total_fluids*G.fluid_transfer_factor - if(total_fluids > 5) - fluid_source.reaction(partner.loc, TOUCH, 1, 0) - var/mob/living/carbon/human/H = partner - if(H) - H.cumdrip_rate += rand(5,10) - fluid_source.clear_reagents() - src.visible_message("[src] climaxes with [partner][spillage ? ", overflowing and spilling":""], using [p_their()] [G.name]!", \ - "You orgasm with [partner][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(partner, COMSIG_ADD_MOOD_EVENT, "orgasm", /datum/mood_event/orgasm) - if(G.can_climax) - setArousalLoss(min_arousal) + else if(mb_time) + src.visible_message("[src] is about to climax with [partner]!", \ + "You're about to climax with [partner]!", \ + "You're preparing to climax with something!") + if(!do_after(src, mb_time, target = src)) + return FALSE + if(!remote && !in_range(src, partner)) + return FALSE + if(spillage) + fluid_source.trans_to(partner, total_fluids*G.fluid_transfer_factor) + total_fluids -= total_fluids*G.fluid_transfer_factor + if(total_fluids > 5) + fluid_source.reaction(partner.loc, TOUCH, 1, 0) + var/mob/living/carbon/human/H = partner + if(H) + H.cumdrip_rate += rand(5,10) + fluid_source.clear_reagents() + src.visible_message("[src] climaxes with [partner][spillage ? ", overflowing and spilling":""], using [p_their()] [G.name]!",\ + "You orgasm with [partner][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(partner, COMSIG_ADD_MOOD_EVENT, "orgasm", /datum/mood_event/orgasm) else //knots, portal fleshlights, and other non-spilling orgasms - if(!cover) - if(!remote && !in_range(src, partner)) - return - if(do_after(src, mb_time, target = src)) - var/mob/living/carbon/H = partner - if(!spillage && total_fluids > 80) //hyper inflation; requires a big cumshot to expand - H.expand_belly(1) - var/obj/item/organ/genital/penis/P = G - if (P.condom)//condomed. - src.condomclimax() - else - fluid_source.trans_to(partner, total_fluids) - total_fluids = 0 - if(!remote) - src.visible_message("[src] climaxes with [partner], [p_their()] [G.name] spilling nothing!", \ - "You ejaculate with [partner], your [G.name] spilling nothing.", \ - "You have climaxed inside someone, your [G.name] spilling nothing.") - else - src.visible_message("[src] climaxes with someone, using [p_their()] [G.name]!", \ - "You ejaculate with someone, using your [G.name].", \ - "You have climaxed inside someone, using your [G.name].") - to_chat(partner, "You feel someone ejaculate inside you.") - - SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "orgasm", /datum/mood_event/orgasm) - SEND_SIGNAL(partner, COMSIG_ADD_MOOD_EVENT, "orgasm", /datum/mood_event/orgasm) - - if(G.can_climax) - setArousalLoss(min_arousal) + var/mob/living/carbon/H = partner + if(!spillage && total_fluids > 80) //hyper inflation; requires a big cumshot to expand + H.expand_belly(1) + var/obj/item/organ/genital/penis/P = G + if(P.condom)//condomed. + src.condomclimax() + else + fluid_source.trans_to(partner, total_fluids) + total_fluids = 0 + if(!remote) + src.visible_message("[src] climaxes with [partner], [p_their()] [G.name] spilling nothing!", \ + "You ejaculate with [partner], your [G.name] spilling nothing.", \ + "You have climaxed inside someone, your [G.name] spilling nothing.") + else + src.visible_message("[src] climaxes with someone, using [p_their()] [G.name]!", \ + "You ejaculate with someone, using your [G.name].", \ + "You have climaxed inside someone, using your [G.name].") + to_chat(partner, "You feel someone ejaculate inside you.") + SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "orgasm", /datum/mood_event/orgasm) + SEND_SIGNAL(partner, COMSIG_ADD_MOOD_EVENT, "orgasm", /datum/mood_event/orgasm) + if(G.can_climax) + setArousalLoss(min_arousal) //Hyper - antag code var/mob/living/carbon/partner_carbon = partner if(src.mind.special_role == ROLE_LEWD_TRAITOR) @@ -432,98 +419,107 @@ if (partner_carbon.mind == obj.target) partner_carbon.mind.sexed = TRUE //sexed to_chat(src, "You feel deep satisfaction with yourself.") - //Hyper - impreg - if(impreg) - partner_carbon.impregnate(by = src) + return TRUE /mob/living/carbon/human/proc/mob_climax_partner_spillage(obj/item/organ/genital/picked_organ, mob/living/carbon/partner, impreg = FALSE) var/obj/item/organ/genital/penis/_penis = picked_organ if(picked_organ.name != "penis" || _penis.sounding || _penis.condom) - mob_climax_partner(picked_organ, partner, FALSE, FALSE, FALSE) + mob_climax_partner(picked_organ, partner, spillage=FALSE) return var/_question = "Would your fluids spill outside?" var/_title = "Choose overflowing option" var/spillage = input(src, _question, _title, "Yes") as anything in list("Yes", "No") - mob_climax_partner(picked_organ, partner, spillage == "Yes", impreg, FALSE) + if(mob_climax_partner(picked_organ, partner, spillage == "Yes") && impreg) + partner.impregnate(by=src) -/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.name == "penis") - var/obj/item/organ/genital/penis/P = src.getorganslot("penis") - if(P.condom) - to_chat(src, "You cannot fill containers when there is a condom over your [G.name].") - return - if(P.sounding) - to_chat(src, "You cannot fill containers when there is a rod inside your [G.name].") - return - 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 - +/** + * Attempt to climax into a container it, filling it with whatever fluids are + * associated to the selected genitals. + * + * Arguments: + * - `genital`: The genital being used for climax. + * - `container`: The container being targeted. + * - `mb_time`: The warm-up time for this interaction. + */ +/mob/living/carbon/human/proc/mob_fill_container(obj/item/organ/genital/genital, obj/item/reagent_containers/container, mb_time = 30) 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.") + var/total_fluids = 0 + var/datum/reagents/fluid_source = genital.get_fluid_source() + if(!fluid_source) + to_chat(src, "Your [genital.name] is unable to produce it's own fluids, it's missing the organs for it.") + return + total_fluids = fluid_source.total_volume + if(genital.name == "penis") + var/obj/item/organ/genital/penis/P = src.getorganslot("penis") + if(P.condom) + to_chat(src, "You cannot fill containers when there is a condom over your [genital.name].") + return + if(P.sounding) + to_chat(src, "You cannot fill containers when there is a rod inside your [genital.name].") + return + src.visible_message("[src] starts to [genital.masturbation_verb] their [genital.name] over [container].", \ + "You start to [genital.masturbation_verb] your [genital.name] over [container].", \ + "You start to [genital.masturbation_verb] your [genital.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] and fill [container] with a total of [total_fluids]u's.", \ - "You have relieved some pressure.") + src.visible_message("[src] uses [p_their()] [genital.name] to fill [container]!", \ + "You used your [genital.name] and fill [container] with a total of [total_fluids]u's.", \ + "You have relieved some pressure.") SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "orgasm", /datum/mood_event/orgasm) container.add_cum_overlay() //your aim is bad... - if(G.can_climax) + if(genital.can_climax) setArousalLoss(min_arousal) -/mob/living/carbon/human/proc/pick_masturbate_genitals() - var/obj/item/organ/genital/ret_organ - var/list/genitals_list = list() - 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()) //Nude or through_clothing - if(!G.dontlist) - genitals_list += G - if(genitals_list.len) - 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/target_genitals(mob/living/carbon/human/T) //used for targeting others +/** + * Prompts the user to select one of their target's genitals to interact with. + * The target must have their genitals visible to be selectable. + * + * Returns: `null`|`obj/item/organ/genital`: The selected genital. + */ +/mob/living/carbon/human/proc/target_genitals(mob/living/carbon/human/T) var/obj/item/organ/genital/ret_organ var/list/genitals_list = list() for(var/obj/item/organ/genital/G in T.internal_organs) - if(G.is_exposed()) //Nude or through_clothing - if(!G.dontlist) - genitals_list += G + if(G.is_exposed() && !G.dontlist) + genitals_list += G if(genitals_list.len) ret_organ = input(src, "", "Genitals", null) as null|obj in genitals_list return ret_organ return null //error stuff -/mob/living/carbon/human/proc/pick_climax_genitals() + +/** + * Prompts the user to select genitals. The genitals must be exposed to be selectable. + * + * Arguments: + * - `masturbation`: Whether or not this is being used for masturbation interactions. + * - `title`: The title of the prompt window. + * + * Returns: `null`|`obj/item/organ/genital`: The selected genital. + */ +/mob/living/carbon/human/proc/pick_climax_genitals(masturbation=FALSE, title="Climax") var/obj/item/organ/genital/ret_organ var/list/genitals_list = list() for(var/obj/item/organ/genital/G in internal_organs) if(G.can_climax && G.is_exposed() && !G.dontlist) - genitals_list += G + if(!masturbation || G.can_masturbate_with) + genitals_list += G if(genitals_list.len) - ret_organ = input(src, "with what?", "Climax", null) as null|obj in genitals_list + ret_organ = input(src, "with what?", title, null) as null|obj in genitals_list return ret_organ return null //error stuff +/** + * Prompts the user to select a mob that they are either pulling or being pulled by. + * + * Returns: `null`|`mob/living/carbon`: The selected mob. + */ /mob/living/carbon/human/proc/pick_partner(needs_exposed = TRUE) var/list/partners = list(src.pulling, src.pulledby) for(var/I in partners) @@ -537,9 +533,14 @@ partners -= I if(!partners.len) return null - return input(src, "With whom?", "Sexual partner", null) as null|anything in partners + return input(src, "With whom?", "Sexual partner", null) as null|mob in partners +/** + * Prompts the user to provide a container (or food item) based on what's in their hands. + * + * Returns: `null`|`obj/item/reagent_containers` - The selected container. + */ /mob/living/carbon/human/proc/pick_climax_container() var/obj/item/reagent_containers/SC = null var/list/containers_list = list() @@ -551,12 +552,14 @@ if(SC) if(in_range(src, SC)) return SC - return null //If nothing correct, give null. + return null +/** + * The old arousal menu. This shows a BYOND-style input selection menu that + * emulates the same functionality as the newer one. + */ /mob/living/carbon/human/mob_climax() - if(stat == DEAD) //corpses can't cum - return if(!canbearoused || !has_dna()) return if(mb_cd_timer > world.time) @@ -627,7 +630,7 @@ return //We got hands, let's pick an organ var/obj/item/organ/genital/picked_organ - picked_organ = pick_masturbate_genitals() + picked_organ = pick_climax_genitals(masturbation=TRUE, title="Masturbation") if(picked_organ) mob_masturbate(picked_organ) return @@ -684,7 +687,7 @@ if(picked_organ) var/mob/living/carbon/partner = pick_partner(FALSE) //Get your partner, clothed or not. if(partner) - mob_climax_partner(picked_organ, partner, FALSE, FALSE, TRUE) + mob_climax_cover(picked_organ, partner) else to_chat(src, "You cannot do this alone.") @@ -722,6 +725,12 @@ return //Just end it in that case. +/** + * Causes a mob to climax on the spot. There is no warmup time, nor a + * menu for selecting genitals. Instead, the mob will climax using all + * climaxable genitals, either onto their location (floor) or on whatever + * is pulling/being pulled by them. + */ /mob/living/carbon/proc/mob_climax_instant() if(stat == DEAD) //corpses can't cum to_chat(src, "You can't do that while dead!") @@ -756,6 +765,12 @@ return +/** + * Rolls a chance for the mob to get pregnant, assuming they are capable of doing so. + * + * Arguments: + * - `by` - The mob that is impregnating this one. + */ /mob/living/carbon/proc/impregnate(mob/living/carbon/by) var/obj/item/organ/genital/womb/W = getorganslot("womb") if(!W || W.pregnant || !breedable) diff --git a/tgstation.dme b/tgstation.dme index 7ab0343dd..b6c7c761e 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -3145,6 +3145,7 @@ #include "hyperstation\code\modules\arousal\arousalhud.dm" #include "hyperstation\code\modules\arousal\creampie.dm" #include "hyperstation\code\modules\arousal\expansion.dm" +#include "hyperstation\code\modules\arousal\organs\genitals.dm" #include "hyperstation\code\modules\busy_space\air_traffic.dm" #include "hyperstation\code\modules\busy_space\atc_controller.dm" #include "hyperstation\code\modules\busy_space\loremaster.dm" From 7531da14916e87e00da6c50fe390f1f5fde9dfb8 Mon Sep 17 00:00:00 2001 From: sarcoph <83266791+sarcoph@users.noreply.github.com> Date: Thu, 5 May 2022 18:12:53 -0800 Subject: [PATCH 24/28] cleaning up mob_climax_partner --- .../code/modules/arousal/arousalhud.dm | 13 +-- hyperstation/code/obj/fleshlight.dm | 2 +- .../code/modules/arousal/arousal.dm | 95 +++++++++++-------- 3 files changed, 58 insertions(+), 52 deletions(-) diff --git a/hyperstation/code/modules/arousal/arousalhud.dm b/hyperstation/code/modules/arousal/arousalhud.dm index 586e6608c..318edefd0 100644 --- a/hyperstation/code/modules/arousal/arousalhud.dm +++ b/hyperstation/code/modules/arousal/arousalhud.dm @@ -378,10 +378,10 @@ obj/screen/arousal/proc/kiss() to_chat(src, "You cannot climax without choosing genitals.") return src << browse(null, "window=arousal") // close arousal window - mob_climax_partner_spillage(picked_organ, partner, impreg=FALSE) + mob_climax_inside_spillage(picked_organ, partner, impreg=FALSE) -/mob/living/carbon/human/proc/climaxover(mob/living/carbon/human/partner) +/mob/living/carbon/human/proc/climaxover(atom/partner) var/obj/item/organ/genital/picked_organ picked_organ = pick_climax_genitals() if(!picked_organ) @@ -391,13 +391,6 @@ obj/screen/arousal/proc/kiss() if(!partner || isnoncarbon(partner)) to_chat(src, "You cannot do this alone.") return - var/obj/item/organ/genital/penis/P = picked_organ - if(P.condom) - to_chat(src, "You cannot do this action with a condom on.") - return - if(P.sounding) - to_chat(src, "You cannot do this action with a sounding in.") - return mob_climax_cover(picked_organ, partner) @@ -435,7 +428,7 @@ obj/screen/arousal/proc/kiss() to_chat(src, "You cannot impregnate someone with a sounding rod in.") return src << browse(null, "window=arousal") //alls fine, we can close the window now. - mob_climax_partner_spillage(picked_organ, partner, impreg=TRUE) + mob_climax_inside_spillage(picked_organ, partner, impreg=TRUE) /mob/living/carbon/human/proc/cumcontainer(mob/living/T) diff --git a/hyperstation/code/obj/fleshlight.dm b/hyperstation/code/obj/fleshlight.dm index 3d5c7ab48..0c640b23f 100644 --- a/hyperstation/code/obj/fleshlight.dm +++ b/hyperstation/code/obj/fleshlight.dm @@ -151,7 +151,7 @@ if(user.can_orgasm()) var/mob/living/carbon/human/O = user var/impreg_chance = target_genital.name == "vagina" && !P.condom && !P.sounding - if(O.mob_climax_partner(P, target, spillage=FALSE, remote=TRUE) && impreg_chance) + if(O.mob_climax_in_partner(P, target, spillage=FALSE, remote=TRUE) && impreg_chance) target.impregnate(by=O) if("Lick") holder.visible_message("[holder] licks into [src].",\ diff --git a/modular_citadel/code/modules/arousal/arousal.dm b/modular_citadel/code/modules/arousal/arousal.dm index 8d2de3d34..f078e9e19 100644 --- a/modular_citadel/code/modules/arousal/arousal.dm +++ b/modular_citadel/code/modules/arousal/arousal.dm @@ -317,13 +317,20 @@ /mob/living/carbon/human/proc/mob_climax_cover(obj/item/organ/genital/genital, atom/partner, mb_time=3 SECONDS) + if(istype(genital, /obj/item/organ/genital/penis)) + var/obj/item/organ/genital/penis/P = genital + if(P.condom) + to_chat(src, "You cannot do this action with a condom on.") + return + if(P.sounding) + to_chat(src, "You cannot do this action with a sounding in.") + return var/total_fluids = 0 var/datum/reagents/fluid_source = genital.get_fluid_source() if(!fluid_source) to_chat(src, "Your [genital.name] is unable to produce it's own fluids, it's missing the organs for it.") return total_fluids = fluid_source.total_volume - var/mob/living/carbon/partner_carbon = partner if(mb_time) src.visible_message("[src] is about to climax with [partner]!", \ "You're about to climax with [partner]!", \ @@ -335,16 +342,19 @@ var/transferred_units = total_fluids * genital.fluid_transfer_factor fluid_source.trans_to(partner, transferred_units) total_fluids -= transferred_units - if(total_fluids > 80 && iscarbon(partner)) // now thats a big cum! - partner_carbon.add_cum_overlay("large") if(total_fluids > 5) fluid_source.reaction(partner.loc, TOUCH, 1, 0) - var/mob/living/carbon/human/H = partner - if(H) - H.cumdrip_rate += rand(5,10) fluid_source.clear_reagents() - if(iscarbon(partner)) - partner_carbon.add_cum_overlay("normal") + if(ismob(partner)) + var/mob/living/carbon/partner_carbon = partner + if(partner_carbon) + var/cum_overlay = "normal" + if(total_fluids > 80) + cum_overlay = "large" + partner_carbon.add_cum_overlay(cum_overlay) + var/mob/living/carbon/human/partner_human = partner_carbon + if(partner_human) + partner_human.cumdrip_rate += rand(5,10) else partner.add_cum_overlay() src.visible_message("[src] climaxes over [partner], using [p_their()] [genital.name]!", \ @@ -354,7 +364,7 @@ setArousalLoss(min_arousal) -/mob/living/carbon/human/proc/mob_climax_partner(obj/item/organ/genital/G, atom/partner, spillage=TRUE, remote=FALSE, mb_time = 3 SECONDS) +/mob/living/carbon/human/proc/mob_climax_in_partner(obj/item/organ/genital/G, mob/living/carbon/partner, spillage=TRUE, remote=FALSE, mb_time=3 SECONDS) if(isnoncarbon(partner)) // deny animals return FALSE var/total_fluids = 0 @@ -363,14 +373,12 @@ to_chat(src, "Your [G.name] is unable to produce it's own fluids, it's missing the organs for it.") return FALSE total_fluids = fluid_source.total_volume + var/partner_text = partner if(remote) - src.visible_message("[src] is about to climax with someone!", \ - "You're about to climax with someone!", \ - "You're preparing to climax with something!") - else if(mb_time) - src.visible_message("[src] is about to climax with [partner]!", \ - "You're about to climax with [partner]!", \ - "You're preparing to climax with something!") + partner_text = "someone" + src.visible_message("[src] is about to climax with [partner_text]!", \ + "You're about to climax with [partner_text]!", \ + "You're preparing to climax with something!") if(!do_after(src, mb_time, target = src)) return FALSE if(!remote && !in_range(src, partner)) @@ -384,29 +392,26 @@ if(H) H.cumdrip_rate += rand(5,10) fluid_source.clear_reagents() - src.visible_message("[src] climaxes with [partner][spillage ? ", overflowing and spilling":""], using [p_their()] [G.name]!",\ - "You orgasm with [partner][spillage ? ", spilling out of them":""], using your [G.name].",\ - "You have climaxed with someone[spillage ? ", spilling out of them":""], using your [G.name].") + src.visible_message("[src] climaxes with [partner], overflowing and spilling, using [p_their()] [G.name]!",\ + "You orgasm with [partner], spilling out of them, using your [G.name].",\ + "You have climaxed with someone, spilling out of them, using your [G.name].") SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "orgasm", /datum/mood_event/orgasm) SEND_SIGNAL(partner, COMSIG_ADD_MOOD_EVENT, "orgasm", /datum/mood_event/orgasm) else //knots, portal fleshlights, and other non-spilling orgasms - var/mob/living/carbon/H = partner - if(!spillage && total_fluids > 80) //hyper inflation; requires a big cumshot to expand - H.expand_belly(1) - var/obj/item/organ/genital/penis/P = G - if(P.condom)//condomed. - src.condomclimax() - else + var/can_inflate = TRUE + if(istype(G, /obj/item/organ/genital/penis)) + var/obj/item/organ/genital/penis/P = G + if(P.condom)//condomed. + can_inflate = FALSE + src.condomclimax() + if(can_inflate) fluid_source.trans_to(partner, total_fluids) - total_fluids = 0 - if(!remote) - src.visible_message("[src] climaxes with [partner], [p_their()] [G.name] spilling nothing!", \ - "You ejaculate with [partner], your [G.name] spilling nothing.", \ - "You have climaxed inside someone, your [G.name] spilling nothing.") - else - src.visible_message("[src] climaxes with someone, using [p_their()] [G.name]!", \ - "You ejaculate with someone, using your [G.name].", \ - "You have climaxed inside someone, using your [G.name].") + if(!spillage && total_fluids > 80) // hyper - cum inflation, ONLY if not wearing a condom + partner.expand_belly(1) + src.visible_message("[src] climaxes with [partner_text], [p_their()] [G.name] spilling nothing!", \ + "You ejaculate with [partner_text], your [G.name] spilling nothing.", \ + "You have climaxed inside someone, your [G.name] spilling nothing.") + if(remote) to_chat(partner, "You feel someone ejaculate inside you.") SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "orgasm", /datum/mood_event/orgasm) SEND_SIGNAL(partner, COMSIG_ADD_MOOD_EVENT, "orgasm", /datum/mood_event/orgasm) @@ -422,15 +427,23 @@ return TRUE -/mob/living/carbon/human/proc/mob_climax_partner_spillage(obj/item/organ/genital/picked_organ, mob/living/carbon/partner, impreg = FALSE) +/** + * User chooses whether or not their climax will spill outside of their partner. + * + * Arguments: + * - `picked_organ`: The user's genital being used. + * - `partner`: This mob's partner for the interaction. + * - `impreg`: Whether or not this interaction has a chance to impregnate. + */ +/mob/living/carbon/human/proc/mob_climax_inside_spillage(obj/item/organ/genital/picked_organ, mob/living/carbon/partner, impreg = FALSE) var/obj/item/organ/genital/penis/_penis = picked_organ if(picked_organ.name != "penis" || _penis.sounding || _penis.condom) - mob_climax_partner(picked_organ, partner, spillage=FALSE) + mob_climax_in_partner(picked_organ, partner, spillage=FALSE) return var/_question = "Would your fluids spill outside?" var/_title = "Choose overflowing option" var/spillage = input(src, _question, _title, "Yes") as anything in list("Yes", "No") - if(mob_climax_partner(picked_organ, partner, spillage == "Yes") && impreg) + if(mob_climax_in_partner(picked_organ, partner, spillage == "Yes") && impreg) partner.impregnate(by=src) @@ -679,12 +692,12 @@ var/impreg_question = "Would this action carry the risk of pregnancy?" var/impreg_title = "Choose a option" impreg = input(src, impreg_question, impreg_title, "Yes") as anything in list("Yes", "No") - mob_climax_partner_spillage(picked_organ, partner, impreg == "Yes") + mob_climax_inside_spillage(picked_organ, partner, impreg == "Yes") if("Climax over partner") var/obj/item/organ/genital/picked_organ picked_organ = pick_climax_genitals() - if(picked_organ) + if(picked_organ) var/mob/living/carbon/partner = pick_partner(FALSE) //Get your partner, clothed or not. if(partner) mob_climax_cover(picked_organ, partner) @@ -760,7 +773,7 @@ if(C.exposed_genitals.len || C.is_groin_exposed() || C.is_chest_exposed()) partner = C if(partner) - user_human.mob_climax_partner(current_genital, partner, mb_time = 0) + user_human.mob_climax_in_partner(current_genital, partner, mb_time = 0) continue return From 9507a9a4ab22a6e02a1a4261303a8bccdad56ad2 Mon Sep 17 00:00:00 2001 From: sarcoph <83266791+sarcoph@users.noreply.github.com> Date: Thu, 5 May 2022 18:49:40 -0800 Subject: [PATCH 25/28] fixed instant climax --- .../mob/living/carbon/human/species.dm | 5 +-- code/modules/mob/living/carbon/life.dm | 3 +- .../ruins/objects_and_mobs/sin_ruins.dm | 15 ++++--- hyperstation/code/obj/fleshlight.dm | 10 +---- hyperstation/code/obj/vibrator.dm | 3 +- .../code/modules/arousal/arousal.dm | 41 ++++++++++--------- 6 files changed, 33 insertions(+), 44 deletions(-) diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm index 7238bae03..fc87bd816 100644 --- a/code/modules/mob/living/carbon/human/species.dm +++ b/code/modules/mob/living/carbon/human/species.dm @@ -1647,7 +1647,7 @@ GLOBAL_LIST_EMPTY(roundstart_races) ) if (target.canbearoused) target.adjustArousalLoss(5) - if (target.can_orgasm() && HAS_TRAIT(target, TRAIT_MASO)) + if (HAS_TRAIT(target, TRAIT_MASO)) target.mob_climax_instant() if (!HAS_TRAIT(target, TRAIT_NYMPHO)) stop_wagging_tail(target) @@ -2005,8 +2005,7 @@ GLOBAL_LIST_EMPTY(roundstart_races) H.update_damage_overlays() if(HAS_TRAIT(H, TRAIT_MASO)) H.adjustArousalLoss(damage * brutemod * H.physiology.brute_mod) - if (H.can_orgasm()) - H.mob_climax_instant() + H.mob_climax_instant() else//no bodypart, we deal damage with a more general method. H.adjustBruteLoss(damage * hit_percent * brutemod * H.physiology.brute_mod) diff --git a/code/modules/mob/living/carbon/life.dm b/code/modules/mob/living/carbon/life.dm index 310eb3d7f..fc3c25c15 100644 --- a/code/modules/mob/living/carbon/life.dm +++ b/code/modules/mob/living/carbon/life.dm @@ -77,8 +77,7 @@ var/mob/living/carbon/human/B = src if(HAS_TRAIT(B, TRAIT_CHOKE_SLUT)) B.adjustArousalLoss(7) - if (B.can_orgasm()) - B.mob_climax_instant() + B.mob_climax_instant() else SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "suffocation", /datum/mood_event/suffocation) else diff --git a/code/modules/ruins/objects_and_mobs/sin_ruins.dm b/code/modules/ruins/objects_and_mobs/sin_ruins.dm index edd7734a8..5fba1aa4b 100644 --- a/code/modules/ruins/objects_and_mobs/sin_ruins.dm +++ b/code/modules/ruins/objects_and_mobs/sin_ruins.dm @@ -288,11 +288,10 @@ if(user.getArousalLoss() < 100) to_chat(user, "You hear a voice in your head... \"You are not horny enough to receive my blessing, dear~\"") return - if(user.can_orgasm()) - var/mob/living/carbon/user_carbon = user - user_carbon.mob_climax_instant() - to_chat(user, "You hear a voice in your head... \"You are worthy of my blessing, dear~\"") - to_chat(user, "You feel overpowering pleasure surge through your entire body.") - var/A = new /obj/item/reagent_containers/chalice/lust - user.put_in_hands(A) - chalice_taken = TRUE \ No newline at end of file + var/mob/living/carbon/user_carbon = user + user_carbon.mob_climax_instant() + to_chat(user, "You hear a voice in your head... \"You are worthy of my blessing, dear~\"") + to_chat(user, "You feel overpowering pleasure surge through your entire body.") + var/A = new /obj/item/reagent_containers/chalice/lust + user.put_in_hands(A) + chalice_taken = TRUE \ No newline at end of file diff --git a/hyperstation/code/obj/fleshlight.dm b/hyperstation/code/obj/fleshlight.dm index 0c640b23f..b1174156e 100644 --- a/hyperstation/code/obj/fleshlight.dm +++ b/hyperstation/code/obj/fleshlight.dm @@ -45,11 +45,9 @@ inuse = 1 if(!(C == user)) //if we are targeting someone else. C.visible_message("[user] is trying to use [src] on [C]'s penis.", "[user] is trying to use [src] on your penis.") - if(!do_mob(user, C, 3 SECONDS)) //3 second delay inuse = 0 return - //checked if not used on yourself, if not, carry on. playsound(src, 'sound/lewd/slaps.ogg', 30, 1, -1) //slapping sound inuse = 0 @@ -57,20 +55,14 @@ C.visible_message("[user] pumps [src] on [C]'s penis.", "[user] pumps [src] up and down on your penis.") else user.visible_message("[user] pumps [src] on their penis.", "You pump the fleshlight on your penis.") - if(prob(30)) //30% chance to make them moan. C.emote("moan") - C.do_jitter_animation() C.adjustArousalLoss(20) //make the target more aroused. - if (C.can_orgasm()) - C.mob_climax_instant() //make them cum if they are over the edge. - + C.mob_climax_instant() //make them cum if they are over the edge. return - else to_chat(user, "You don't see anywhere to use this on.") - inuse = 0 ..() diff --git a/hyperstation/code/obj/vibrator.dm b/hyperstation/code/obj/vibrator.dm index bef2a7969..40e1446e9 100644 --- a/hyperstation/code/obj/vibrator.dm +++ b/hyperstation/code/obj/vibrator.dm @@ -132,8 +132,7 @@ Code: if(2) //med, can make you cum to_chat(U, "You feel intense pleasure surge through your [G.name]") U.do_jitter_animation() - if (U.can_orgasm()) - U.mob_climax_instant() + U.mob_climax_instant() if(3) //high, makes you stun to_chat(U, "You feel overpowering pleasure surge through your [G.name]") U.Jitter(3) diff --git a/modular_citadel/code/modules/arousal/arousal.dm b/modular_citadel/code/modules/arousal/arousal.dm index f078e9e19..df888287d 100644 --- a/modular_citadel/code/modules/arousal/arousal.dm +++ b/modular_citadel/code/modules/arousal/arousal.dm @@ -202,7 +202,9 @@ * Returns: `TRUE/FALSE` - Whether or not the mob passes all of the above checks. */ /mob/living/proc/can_orgasm(arousal = 100) - return src.canbearoused && src.getArousalLoss() >= arousal && ishuman(src) && src.has_dna() + if(src.canbearoused && src.getArousalLoss() >= arousal && ishuman(src) && src.has_dna()) + return TRUE + return FALSE /mob/living/proc/mob_climax() @@ -744,37 +746,36 @@ * climaxable genitals, either onto their location (floor) or on whatever * is pulling/being pulled by them. */ -/mob/living/carbon/proc/mob_climax_instant() +/mob/living/carbon/proc/mob_climax_instant(arousal=100) if(stat == DEAD) //corpses can't cum to_chat(src, "You can't do that while dead!") return - if(!canbearoused || !has_dna()) + if(!can_orgasm(arousal)) return var/mob/living/carbon/human/user_human = src for(var/obj/item/organ/O in internal_organs) if(!istype(O, /obj/item/organ/genital)) - return + continue var/obj/item/organ/genital/current_genital = O if(!current_genital.can_climax) continue // no wombs or testicles var/mob/living/carbon/partner var/check_target - if(!current_genital.is_exposed()) - user_human.mob_climax_outside(current_genital, mb_time = 0) - continue - if(src.pulling) - if(iscarbon(src.pulling)) - check_target = src.pulling - else if(src.pulledby) - if(iscarbon(src.pulledby)) - check_target = src.pulledby - if(check_target) - var/mob/living/carbon/C = check_target - if(C.exposed_genitals.len || C.is_groin_exposed() || C.is_chest_exposed()) - partner = C - if(partner) - user_human.mob_climax_in_partner(current_genital, partner, mb_time = 0) - continue + if(current_genital.is_exposed()) + if(src.pulling) + if(iscarbon(src.pulling)) + check_target = src.pulling + else if(src.pulledby) + if(iscarbon(src.pulledby)) + check_target = src.pulledby + if(check_target) + var/mob/living/carbon/C = check_target + if(C.exposed_genitals.len || C.is_groin_exposed() || C.is_chest_exposed()) + partner = C + if(partner) + user_human.mob_climax_in_partner(current_genital, partner, mb_time = 0) + continue + user_human.mob_climax_outside(current_genital, mb_time = 0) return From d09d138aa61e37fa713fdc7aa1cf749c81d7097e Mon Sep 17 00:00:00 2001 From: sarcoph <83266791+sarcoph@users.noreply.github.com> Date: Thu, 5 May 2022 19:26:58 -0800 Subject: [PATCH 26/28] documenting arousal code --- hyperstation/code/obj/fleshlight.dm | 6 +- .../code/modules/arousal/arousal.dm | 194 +++++++++++------- 2 files changed, 121 insertions(+), 79 deletions(-) diff --git a/hyperstation/code/obj/fleshlight.dm b/hyperstation/code/obj/fleshlight.dm index b1174156e..421cfb8f6 100644 --- a/hyperstation/code/obj/fleshlight.dm +++ b/hyperstation/code/obj/fleshlight.dm @@ -59,7 +59,9 @@ C.emote("moan") C.do_jitter_animation() C.adjustArousalLoss(20) //make the target more aroused. - C.mob_climax_instant() //make them cum if they are over the edge. + if(C.can_orgasm() && ishuman(C)) + var/mob/living/carbon/human/user_human = C + user_human.mob_climax_outside(P, mb_time=0) // instant, because we already did a warmup return else to_chat(user, "You don't see anywhere to use this on.") @@ -139,7 +141,7 @@ target.adjustArousalLoss(20) target.do_jitter_animation() if(target.can_orgasm() && prob(5)) - target.mob_climax_outside(target_genital, spillage = target_genital.is_exposed()) + target.mob_climax_outside(target_genital, spillage=target_genital.is_exposed()) if(user.can_orgasm()) var/mob/living/carbon/human/O = user var/impreg_chance = target_genital.name == "vagina" && !P.condom && !P.sounding diff --git a/modular_citadel/code/modules/arousal/arousal.dm b/modular_citadel/code/modules/arousal/arousal.dm index df888287d..ca9b99bf9 100644 --- a/modular_citadel/code/modules/arousal/arousal.dm +++ b/modular_citadel/code/modules/arousal/arousal.dm @@ -128,25 +128,25 @@ /mob/living/carbon/updatearousal() . = ..() - for(var/obj/item/organ/genital/G in internal_organs) - if(istype(G)) + for(var/obj/item/organ/genital/genital in internal_organs) + if(istype(genital)) var/datum/sprite_accessory/S - switch(G.type) + switch(genital.type) if(/obj/item/organ/genital/penis) - S = GLOB.cock_shapes_list[G.shape] + S = GLOB.cock_shapes_list[genital.shape] if(/obj/item/organ/genital/testicles) - S = GLOB.balls_shapes_list[G.shape] + S = GLOB.balls_shapes_list[genital.shape] if(/obj/item/organ/genital/vagina) - S = GLOB.vagina_shapes_list[G.shape] + S = GLOB.vagina_shapes_list[genital.shape] if(/obj/item/organ/genital/breasts) - S = GLOB.breasts_shapes_list[G.shape] + S = GLOB.breasts_shapes_list[genital.shape] if(S?.alt_aroused) - G.aroused_state = isPercentAroused(G.aroused_amount) + genital.aroused_state = isPercentAroused(genital.aroused_amount) if(getArousalLoss() >= isPercentAroused(33)) - G.aroused_state = TRUE + genital.aroused_state = TRUE else - G.aroused_state = FALSE - G.update_appearance() + genital.aroused_state = FALSE + genital.update_appearance() @@ -199,7 +199,7 @@ * Arguments: * - `arousal` - The minimum arousal needed to pass the check. Default is `100`. * - * Returns: `TRUE/FALSE` - Whether or not the mob passes all of the above checks. + * Returns: `TRUE`/`FALSE` - Whether or not the mob passes all of the above checks. */ /mob/living/proc/can_orgasm(arousal = 100) if(src.canbearoused && src.getArousalLoss() >= arousal && ishuman(src) && src.has_dna()) @@ -226,47 +226,53 @@ to_chat(src, "You aren't aroused enough for that.") - -/mob/living/carbon/human/proc/mob_masturbate(obj/item/organ/genital/G, cover = FALSE, mb_time = 30) +/** + * Arguments: + * - `genital`: Genitals being used for this interaction. + * - `cover`: Whether or not the mob is climaxing over themselves. + * - `mb_time`: Warm-up time for this interaction. + */ +/mob/living/carbon/human/proc/mob_masturbate(obj/item/organ/genital/genital, cover = FALSE, mb_time = 30) var/total_fluids = 0 - var/datum/reagents/fluid_source = G.get_fluid_source() + var/datum/reagents/fluid_source = genital.get_fluid_source() var/condomed = FALSE var/sounded = FALSE - if(G.name == "penis") + if(genital.name == "penis") var/obj/item/organ/genital/penis/P = src.getorganslot("penis") condomed = P.condom sounded = P.sounding if(!fluid_source) - to_chat(src, "Your [G.name] is unable to produce it's own fluids, it's missing the organs for it.") + to_chat(src, "Your [genital.name] is unable to produce it's own fluids, it's missing the organs for it.") return total_fluids = fluid_source.total_volume 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].", \ - "You start to [G.masturbation_verb] your [G.name].") + src.visible_message("[src] starts to [genital.masturbation_verb] [p_their()] [genital.name].", \ + "You start to [genital.masturbation_verb] your [genital.name].", \ + "You start to [genital.masturbation_verb] your [genital.name].") if(do_after(src, mb_time, target = src)) if(total_fluids > 5 &&!condomed &&!sounded) fluid_source.reaction(src.loc, TOUCH, 1, 0) fluid_source.clear_reagents() - if(!condomed && !sounded && !cover) - 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.") - if(!condomed &&!sounded && cover)//For when you want to make a mess of yourself. - fluid_source.trans_to(src, total_fluids*G.fluid_transfer_factor) - total_fluids -= total_fluids*G.fluid_transfer_factor - if(total_fluids > 80) // now thats a big cum! - src.add_cum_overlay("large") - if(total_fluids > 5) - fluid_source.reaction(src.loc, TOUCH, 1, 0) - var/mob/living/carbon/human/H = src - if(H && G.name == "penis") - H.cumdrip_rate += rand(5,10) - fluid_source.clear_reagents() - src.visible_message("[src] climaxes over [p_their()] self, using [p_their()] [G.name]!", \ - "You orgasm over yourself, using your [G.name].", \ - "You have climaxed over something, using your [G.name].") - src.add_cum_overlay() + if(!condomed && !sounded)//For when you want to make a mess of yourself. + if(cover) + fluid_source.trans_to(src, total_fluids*genital.fluid_transfer_factor) + total_fluids -= total_fluids*genital.fluid_transfer_factor + if(total_fluids > 80) // now thats a big cum! + src.add_cum_overlay("large") + if(total_fluids > 5) + fluid_source.reaction(src.loc, TOUCH, 1, 0) + var/mob/living/carbon/human/H = src + if(H && genital.name == "penis") + H.cumdrip_rate += rand(5,10) + fluid_source.clear_reagents() + src.visible_message("[src] climaxes over [p_their()] self, using [p_their()] [genital.name]!", \ + "You orgasm over yourself, using your [genital.name].", \ + "You have climaxed over something, using your [genital.name].") + src.add_cum_overlay() + else + 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.") if(condomed) //condomed src.visible_message("[src] orgasms, climaxing into [p_their()] condom!", \ "You cum into your condom.", \ @@ -275,26 +281,34 @@ src.visible_message("[src] orgasms, but the rod blocks anything from leaking out!", \ "You cum with the rod inside.", \ "You don't quite feel totally relieved.") - if(total_fluids > 0 &&condomed &&!sounded) + if(total_fluids > 0 && condomed && !sounded) src.condomclimax() SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "orgasm", /datum/mood_event/orgasm) - if(G.can_climax) + if(genital.can_climax) setArousalLoss(min_arousal) -/mob/living/carbon/human/proc/mob_climax_outside(obj/item/organ/genital/G, mb_time = 30, spillage = TRUE) -//This is used for forced orgasms and other hands-free climaxes +/** + * Mob climaxes using provided genitals without a partner. This is in contrast with `mob_climax_instant()`, + * which does not have a warm-up time and uses all genitals at once to climax. + * + * Arguments: + * - `genital`: The selected genitals for this interaction. Determines fluid type. + * - `mb_time`: The warm-up time for this interaction. + * - `spillage`: Whether or not climaxing causes this mob to spill fluids on the floor. + */ +/mob/living/carbon/human/proc/mob_climax_outside(obj/item/organ/genital/genital, spillage = TRUE, mb_time = 30) var/total_fluids = 0 - var/datum/reagents/fluid_source = G.get_fluid_source() + var/datum/reagents/fluid_source = genital.get_fluid_source() var/unable_to_come = FALSE if(fluid_source) total_fluids = fluid_source.total_volume else unable_to_come = TRUE if(unable_to_come) - src.visible_message("[src] shudders, their [G.name] unable to cum.", \ - "Your [G.name] cannot cum, giving no relief.", \ - "Your [G.name] cannot cum, giving no relief.") + src.visible_message("[src] shudders, their [genital.name] unable to cum.", \ + "Your [genital.name] cannot cum, giving no relief.", \ + "Your [genital.name] cannot cum, giving no relief.") return total_fluids = fluid_source.total_volume if(mb_time) //as long as it's not instant, give a warning @@ -306,19 +320,31 @@ 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]" : ""], with [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].") + src.visible_message("[src] orgasms[istype(src.loc, /turf/open/floor) ? ", spilling onto [src.loc]" : ""], with [p_their()] [genital.name]!", \ + "You climax[istype(src.loc, /turf/open/floor) ? ", spilling onto [src.loc]" : ""] with your [genital.name].", \ + "You climax using your [genital.name].") else - src.visible_message("[src] orgasms with [p_their()] [G.name]!", \ - "You climax with your [G.name].", \ - "You climax using your [G.name].") + src.visible_message("[src] orgasms with [p_their()] [genital.name]!", \ + "You climax with your [genital.name].", \ + "You climax using your [genital.name].") SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "orgasm", /datum/mood_event/orgasm) - if(G.can_climax) + if(genital.can_climax) setArousalLoss(min_arousal) +/** + * Climax over a partner with a selected organ. This is external and creates spills on the partner/floor, + * and does not have a chance to impregnate. For this interaction, the partner may be an object instead of + * a person (but it cannot be an animal). + * + * Arguments: + * - `genital`: The genital being used for this interaction. Determines fluid type and volume. + * - `partner`: The thing being used as a partner. Generally an object or a person. + * - `mb_time`: The warm-up time for this interaction. Default is 3 seconds + */ /mob/living/carbon/human/proc/mob_climax_cover(obj/item/organ/genital/genital, atom/partner, mb_time=3 SECONDS) + if(isnoncarbon(partner)) // deny animals + return FALSE if(istype(genital, /obj/item/organ/genital/penis)) var/obj/item/organ/genital/penis/P = genital if(P.condom) @@ -366,13 +392,25 @@ setArousalLoss(min_arousal) -/mob/living/carbon/human/proc/mob_climax_in_partner(obj/item/organ/genital/G, mob/living/carbon/partner, spillage=TRUE, remote=FALSE, mb_time=3 SECONDS) +/** + * Climax inside a partner using a selected organ. + * + * Arguments: + * - `genital`: The genital being used for this interaction. Determines type/volume of fluids. + * - `partner`: The person that this mob is climaxing in. + * - `spillage`: Whether or not the fluids will spill on the ground. + * - `remote`: Whether or not this interaction is being triggered long-distance. + * - `mb_time`: Warm-up time for this interaction. + * + * Returns: `TRUE`/`FALSE` - whether or not this interaction succeeded. + */ +/mob/living/carbon/human/proc/mob_climax_in_partner(obj/item/organ/genital/genital, mob/living/carbon/partner, spillage=TRUE, remote=FALSE, mb_time=3 SECONDS) if(isnoncarbon(partner)) // deny animals return FALSE var/total_fluids = 0 - var/datum/reagents/fluid_source = G.get_fluid_source() + var/datum/reagents/fluid_source = genital.get_fluid_source() if(!fluid_source) - to_chat(src, "Your [G.name] is unable to produce it's own fluids, it's missing the organs for it.") + to_chat(src, "Your [genital.name] is unable to produce it's own fluids, it's missing the organs for it.") return FALSE total_fluids = fluid_source.total_volume var/partner_text = partner @@ -386,23 +424,23 @@ if(!remote && !in_range(src, partner)) return FALSE if(spillage) - fluid_source.trans_to(partner, total_fluids*G.fluid_transfer_factor) - total_fluids -= total_fluids*G.fluid_transfer_factor + fluid_source.trans_to(partner, total_fluids*genital.fluid_transfer_factor) + total_fluids -= total_fluids*genital.fluid_transfer_factor if(total_fluids > 5) fluid_source.reaction(partner.loc, TOUCH, 1, 0) var/mob/living/carbon/human/H = partner if(H) H.cumdrip_rate += rand(5,10) fluid_source.clear_reagents() - src.visible_message("[src] climaxes with [partner], overflowing and spilling, using [p_their()] [G.name]!",\ - "You orgasm with [partner], spilling out of them, using your [G.name].",\ - "You have climaxed with someone, spilling out of them, using your [G.name].") + src.visible_message("[src] climaxes with [partner], overflowing and spilling, using [p_their()] [genital.name]!",\ + "You orgasm with [partner], spilling out of them, using your [genital.name].",\ + "You have climaxed with someone, spilling out of them, using your [genital.name].") SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "orgasm", /datum/mood_event/orgasm) SEND_SIGNAL(partner, COMSIG_ADD_MOOD_EVENT, "orgasm", /datum/mood_event/orgasm) else //knots, portal fleshlights, and other non-spilling orgasms var/can_inflate = TRUE - if(istype(G, /obj/item/organ/genital/penis)) - var/obj/item/organ/genital/penis/P = G + if(istype(genital, /obj/item/organ/genital/penis)) + var/obj/item/organ/genital/penis/P = genital if(P.condom)//condomed. can_inflate = FALSE src.condomclimax() @@ -410,14 +448,14 @@ fluid_source.trans_to(partner, total_fluids) if(!spillage && total_fluids > 80) // hyper - cum inflation, ONLY if not wearing a condom partner.expand_belly(1) - src.visible_message("[src] climaxes with [partner_text], [p_their()] [G.name] spilling nothing!", \ - "You ejaculate with [partner_text], your [G.name] spilling nothing.", \ - "You have climaxed inside someone, your [G.name] spilling nothing.") + src.visible_message("[src] climaxes with [partner_text], [p_their()] [genital.name] spilling nothing!", \ + "You ejaculate with [partner_text], your [genital.name] spilling nothing.", \ + "You have climaxed inside someone, your [genital.name] spilling nothing.") if(remote) to_chat(partner, "You feel someone ejaculate inside you.") SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "orgasm", /datum/mood_event/orgasm) SEND_SIGNAL(partner, COMSIG_ADD_MOOD_EVENT, "orgasm", /datum/mood_event/orgasm) - if(G.can_climax) + if(genital.can_climax) setArousalLoss(min_arousal) //Hyper - antag code var/mob/living/carbon/partner_carbon = partner @@ -499,9 +537,9 @@ /mob/living/carbon/human/proc/target_genitals(mob/living/carbon/human/T) var/obj/item/organ/genital/ret_organ var/list/genitals_list = list() - for(var/obj/item/organ/genital/G in T.internal_organs) - if(G.is_exposed() && !G.dontlist) - genitals_list += G + for(var/obj/item/organ/genital/genital in T.internal_organs) + if(genital.is_exposed() && !genital.dontlist) + genitals_list += genital if(genitals_list.len) ret_organ = input(src, "", "Genitals", null) as null|obj in genitals_list return ret_organ @@ -520,10 +558,10 @@ /mob/living/carbon/human/proc/pick_climax_genitals(masturbation=FALSE, title="Climax") var/obj/item/organ/genital/ret_organ var/list/genitals_list = list() - for(var/obj/item/organ/genital/G in internal_organs) - if(G.can_climax && G.is_exposed() && !G.dontlist) - if(!masturbation || G.can_masturbate_with) - genitals_list += G + for(var/obj/item/organ/genital/genital in internal_organs) + if(genital.can_climax && genital.is_exposed() && !genital.dontlist) + if(!masturbation || genital.can_masturbate_with) + genitals_list += genital if(genitals_list.len) ret_organ = input(src, "with what?", title, null) as null|obj in genitals_list return ret_organ @@ -533,9 +571,11 @@ /** * Prompts the user to select a mob that they are either pulling or being pulled by. * + * Arguments: + * - `needs_exposed`: Whether or not the partner must have exposed genitals. * Returns: `null`|`mob/living/carbon`: The selected mob. */ -/mob/living/carbon/human/proc/pick_partner(needs_exposed = TRUE) +/mob/living/carbon/human/proc/pick_partner(needs_exposed=TRUE) var/list/partners = list(src.pulling, src.pulledby) for(var/I in partners) if(!iscarbon(I)) @@ -700,7 +740,7 @@ var/obj/item/organ/genital/picked_organ picked_organ = pick_climax_genitals() if(picked_organ) - var/mob/living/carbon/partner = pick_partner(FALSE) //Get your partner, clothed or not. + var/mob/living/carbon/partner = pick_partner(needs_exposed=FALSE) //Get your partner, clothed or not. if(partner) mob_climax_cover(picked_organ, partner) else From 852eee166d4adba01330cbc699bbe9c1a6c56991 Mon Sep 17 00:00:00 2001 From: sarcoph <83266791+sarcoph@users.noreply.github.com> Date: Thu, 5 May 2022 19:42:35 -0800 Subject: [PATCH 27/28] consistency's sake --- code/game/objects/structures.dm | 4 ++-- .../objects/structures/crates_lockers/closets.dm | 2 +- .../objects/structures/crates_lockers/crates.dm | 2 +- modular_citadel/code/modules/arousal/arousal.dm | 14 +++++++------- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/code/game/objects/structures.dm b/code/game/objects/structures.dm index b25e58157..4f404015b 100644 --- a/code/game/objects/structures.dm +++ b/code/game/objects/structures.dm @@ -3,7 +3,7 @@ pressure_resistance = 8 max_integrity = 300 interaction_flags_atom = INTERACT_ATOM_ATTACK_HAND | INTERACT_ATOM_UI_INTERACT - var/climb_time = 20 + var/climb_time=20 var/climb_stun = 20 var/climbable = FALSE var/mob/living/structureclimber @@ -66,7 +66,7 @@ src.add_fingerprint(user) user.visible_message("[user] starts climbing onto [src].", \ "You start climbing onto [src]...") - var/adjusted_climb_time = climb_time + var/adjusted_climb_time=climb_time if(user.restrained()) //climbing takes twice as long when restrained. adjusted_climb_time *= 2 if(isalien(user)) diff --git a/code/game/objects/structures/crates_lockers/closets.dm b/code/game/objects/structures/crates_lockers/closets.dm index 1d960b210..b8627c554 100644 --- a/code/game/objects/structures/crates_lockers/closets.dm +++ b/code/game/objects/structures/crates_lockers/closets.dm @@ -243,7 +243,7 @@ return FALSE take_contents() playsound(loc, close_sound, 15, 1, -3) - climb_time = initial(climb_time) + climb_time=initial(climb_time) opened = FALSE density = TRUE update_icon() diff --git a/code/game/objects/structures/crates_lockers/crates.dm b/code/game/objects/structures/crates_lockers/crates.dm index 5b16126e0..5e7e7091c 100644 --- a/code/game/objects/structures/crates_lockers/crates.dm +++ b/code/game/objects/structures/crates_lockers/crates.dm @@ -10,7 +10,7 @@ allow_dense = TRUE dense_when_open = TRUE climbable = TRUE - climb_time = 10 //real fast, because let's be honest stepping into or onto a crate is easy + climb_time=10 //real fast, because let's be honest stepping into or onto a crate is easy climb_stun = 0 //climbing onto crates isn't hard, guys delivery_icon = "deliverycrate" var/obj/item/paper/fluff/jobs/cargo/manifest/manifest diff --git a/modular_citadel/code/modules/arousal/arousal.dm b/modular_citadel/code/modules/arousal/arousal.dm index ca9b99bf9..8b8780b46 100644 --- a/modular_citadel/code/modules/arousal/arousal.dm +++ b/modular_citadel/code/modules/arousal/arousal.dm @@ -201,7 +201,7 @@ * * Returns: `TRUE`/`FALSE` - Whether or not the mob passes all of the above checks. */ -/mob/living/proc/can_orgasm(arousal = 100) +/mob/living/proc/can_orgasm(arousal=100) if(src.canbearoused && src.getArousalLoss() >= arousal && ishuman(src) && src.has_dna()) return TRUE return FALSE @@ -232,7 +232,7 @@ * - `cover`: Whether or not the mob is climaxing over themselves. * - `mb_time`: Warm-up time for this interaction. */ -/mob/living/carbon/human/proc/mob_masturbate(obj/item/organ/genital/genital, cover = FALSE, mb_time = 30) +/mob/living/carbon/human/proc/mob_masturbate(obj/item/organ/genital/genital, cover=FALSE, mb_time=3 SECONDS) var/total_fluids = 0 var/datum/reagents/fluid_source = genital.get_fluid_source() var/condomed = FALSE @@ -297,7 +297,7 @@ * - `mb_time`: The warm-up time for this interaction. * - `spillage`: Whether or not climaxing causes this mob to spill fluids on the floor. */ -/mob/living/carbon/human/proc/mob_climax_outside(obj/item/organ/genital/genital, spillage = TRUE, mb_time = 30) +/mob/living/carbon/human/proc/mob_climax_outside(obj/item/organ/genital/genital, spillage=TRUE, mb_time=3 SECONDS) var/total_fluids = 0 var/datum/reagents/fluid_source = genital.get_fluid_source() var/unable_to_come = FALSE @@ -475,7 +475,7 @@ * - `partner`: This mob's partner for the interaction. * - `impreg`: Whether or not this interaction has a chance to impregnate. */ -/mob/living/carbon/human/proc/mob_climax_inside_spillage(obj/item/organ/genital/picked_organ, mob/living/carbon/partner, impreg = FALSE) +/mob/living/carbon/human/proc/mob_climax_inside_spillage(obj/item/organ/genital/picked_organ, mob/living/carbon/partner, impreg=FALSE) var/obj/item/organ/genital/penis/_penis = picked_organ if(picked_organ.name != "penis" || _penis.sounding || _penis.condom) mob_climax_in_partner(picked_organ, partner, spillage=FALSE) @@ -496,7 +496,7 @@ * - `container`: The container being targeted. * - `mb_time`: The warm-up time for this interaction. */ -/mob/living/carbon/human/proc/mob_fill_container(obj/item/organ/genital/genital, obj/item/reagent_containers/container, mb_time = 30) +/mob/living/carbon/human/proc/mob_fill_container(obj/item/organ/genital/genital, obj/item/reagent_containers/container, mb_time=3 SECONDS) if(!container) //Something weird happened to_chat(src, "You need a container to do this!") return @@ -813,9 +813,9 @@ if(C.exposed_genitals.len || C.is_groin_exposed() || C.is_chest_exposed()) partner = C if(partner) - user_human.mob_climax_in_partner(current_genital, partner, mb_time = 0) + user_human.mob_climax_in_partner(current_genital, partner, mb_time=0) continue - user_human.mob_climax_outside(current_genital, mb_time = 0) + user_human.mob_climax_outside(current_genital, mb_time=0) return From c469820069e1d1d54ad664d83561f9627a862c8d Mon Sep 17 00:00:00 2001 From: sarcoph <83266791+sarcoph@users.noreply.github.com> Date: Thu, 5 May 2022 19:44:25 -0800 Subject: [PATCH 28/28] oops --- code/game/objects/structures.dm | 4 ++-- code/game/objects/structures/crates_lockers/closets.dm | 2 +- code/game/objects/structures/crates_lockers/crates.dm | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/code/game/objects/structures.dm b/code/game/objects/structures.dm index 4f404015b..b25e58157 100644 --- a/code/game/objects/structures.dm +++ b/code/game/objects/structures.dm @@ -3,7 +3,7 @@ pressure_resistance = 8 max_integrity = 300 interaction_flags_atom = INTERACT_ATOM_ATTACK_HAND | INTERACT_ATOM_UI_INTERACT - var/climb_time=20 + var/climb_time = 20 var/climb_stun = 20 var/climbable = FALSE var/mob/living/structureclimber @@ -66,7 +66,7 @@ src.add_fingerprint(user) user.visible_message("[user] starts climbing onto [src].", \ "You start climbing onto [src]...") - var/adjusted_climb_time=climb_time + var/adjusted_climb_time = climb_time if(user.restrained()) //climbing takes twice as long when restrained. adjusted_climb_time *= 2 if(isalien(user)) diff --git a/code/game/objects/structures/crates_lockers/closets.dm b/code/game/objects/structures/crates_lockers/closets.dm index b8627c554..1d960b210 100644 --- a/code/game/objects/structures/crates_lockers/closets.dm +++ b/code/game/objects/structures/crates_lockers/closets.dm @@ -243,7 +243,7 @@ return FALSE take_contents() playsound(loc, close_sound, 15, 1, -3) - climb_time=initial(climb_time) + climb_time = initial(climb_time) opened = FALSE density = TRUE update_icon() diff --git a/code/game/objects/structures/crates_lockers/crates.dm b/code/game/objects/structures/crates_lockers/crates.dm index 5e7e7091c..5b16126e0 100644 --- a/code/game/objects/structures/crates_lockers/crates.dm +++ b/code/game/objects/structures/crates_lockers/crates.dm @@ -10,7 +10,7 @@ allow_dense = TRUE dense_when_open = TRUE climbable = TRUE - climb_time=10 //real fast, because let's be honest stepping into or onto a crate is easy + climb_time = 10 //real fast, because let's be honest stepping into or onto a crate is easy climb_stun = 0 //climbing onto crates isn't hard, guys delivery_icon = "deliverycrate" var/obj/item/paper/fluff/jobs/cargo/manifest/manifest