diff --git a/modular_citadel/code/modules/arousal/arousal.dm b/modular_citadel/code/modules/arousal/arousal.dm
index 818c5c7b1e..0753f8149a 100644
--- a/modular_citadel/code/modules/arousal/arousal.dm
+++ b/modular_citadel/code/modules/arousal/arousal.dm
@@ -95,6 +95,24 @@
to_chat(src,"You climax[isturf(loc) ? " onto [loc]" : ""] with your [G.name].")
do_climax(fluid_source, loc, G)
+/mob/living/carbon/human/proc/mob_climax_partner(obj/item/organ/genital/G, mob/living/L, spillage = TRUE, mb_time = 30) //Used for climaxing with any living thing
+ var/datum/reagents/fluid_source = G.climaxable(src)
+ if(!fluid_source)
+ return
+ if(mb_time) //Skip warning if this is an instant climax.
+ to_chat(src,"You're about to climax with [L]!")
+ to_chat(L,"[src] is about to climax with you!")
+ if(!do_after(src, mb_time, target = src) || !in_range(src, L) || !G.climaxable(src, TRUE))
+ return
+ if(spillage)
+ to_chat(src,"You orgasm with [L], spilling out of them, using your [G.name].")
+ to_chat(L,"[src] climaxes with you, overflowing and spilling, using [p_their()] [G.name]!")
+ else //knots and other non-spilling orgasms
+ to_chat(src,"You climax with [L], your [G.name] spilling nothing.")
+ to_chat(L,"[src] climaxes with you, [p_their()] [G.name] spilling nothing!")
+ SEND_SIGNAL(L, COMSIG_ADD_MOOD_EVENT, "orgasm", /datum/mood_event/orgasm)
+ do_climax(fluid_source, spillage ? loc : L, G, spillage)
+
/mob/living/carbon/human/proc/mob_fill_container(obj/item/organ/genital/G, obj/item/reagent_containers/container, mb_time = 30) //For beaker-filling, beware the bartender
var/datum/reagents/fluid_source = G.climaxable(src)
if(!fluid_source)
@@ -119,6 +137,29 @@
else if(!silent)
to_chat(src, "You cannot climax without available genitals.")
+/mob/living/carbon/human/proc/pick_partner(silent = FALSE)
+ var/list/partners = list()
+ if(pulling)
+ partners += pulling
+ if(pulledby)
+ partners += pulledby
+ //Now we got both of them, let's check if they're proper
+ for(var/mob/living/L in partners)
+ if(!L?.client || !L?.mind) // can't consent, not a partner
+ partners -= L
+ if(iscarbon(L))
+ var/mob/living/carbon/C = L
+ if(!C.exposed_genitals.len && !C.is_groin_exposed() && !C.is_chest_exposed()) //Nothing through_clothing, no proper partner.
+ partners -= C
+ //NOW the list should only contain correct partners
+ if(!partners.len)
+ if(!silent)
+ to_chat(src, "You cannot do this alone.")
+ return //No one left.
+ var/mob/living/target = input(src, "With whom?", "Sexual partner", null) as null|anything in partners //pick one, default to null
+ if(target && in_range(src, target))
+ return target
+
/mob/living/carbon/human/proc/pick_climax_container(silent = FALSE)
var/list/containers_list = list()
@@ -168,6 +209,31 @@
return
if(forced_climax) //Something forced us to cum, this is not a masturbation thing and does not progress to the other checks
for(var/obj/item/organ/genital/G in internal_organs)
+ if(!CHECK_BITFIELD(G.genital_flags, CAN_CLIMAX_WITH)) //Skip things like wombs and testicles
+ continue
+ var/mob/living/partner
+ var/check_target
+ var/list/worn_stuff = get_equipped_items()
+
+ if(G.is_exposed(worn_stuff))
+ if(pulling) //Are we pulling someone? Priority target, we can't be making option menus for this, has to be quick
+ if(isliving(pulling)) //Don't fuck objects
+ check_target = pulling
+ if(pulledby && !check_target) //prioritise pulled over pulledby
+ if(isliving(pulledby))
+ check_target = pulledby
+ //Now we should have a partner, or else we have to come alone
+ if(check_target)
+ if(iscarbon(check_target)) //carbons can have clothes
+ var/mob/living/carbon/C = check_target
+ if(C.exposed_genitals.len || C.is_groin_exposed() || C.is_chest_exposed()) //Are they naked enough?
+ partner = C
+ else //A cat is fine too
+ partner = check_target
+ if(partner) //Did they pass the clothing checks?
+ mob_climax_partner(G, partner, mb_time = 0) //Instant climax due to forced
+ continue //You've climaxed once with this organ, continue on
+ //not exposed OR if no partner was found while exposed, climax alone
mob_climax_outside(G, mb_time = 0) //removed climax timer for sudden, forced orgasms
//Now all genitals that could climax, have.
//Since this was a forced climax, we do not need to continue with the other stuff
@@ -180,18 +246,26 @@
return
//Ok, now we check what they want to do.
- var/choice = input(src, "Select sexual activity", "Sexual activity:") as null|anything in list("Climax", "Fill container")
+ var/choice = input(src, "Select sexual activity", "Sexual activity:") as null|anything in list("Climax alone","Climax with partner", "Fill container")
if(!choice)
return
switch(choice)
- if("Climax")
+ if("Climax alone")
if(!available_rosie_palms())
return
var/obj/item/organ/genital/picked_organ = pick_climax_genitals()
if(picked_organ && available_rosie_palms(TRUE))
mob_climax_outside(picked_organ)
-
+ if("Climax with partner")
+ //We need no hands, we can be restrained and so on, so let's pick an organ
+ var/obj/item/organ/genital/picked_organ = pick_climax_genitals()
+ if(picked_organ)
+ var/mob/living/partner = pick_partner() //Get someone
+ if(partner)
+ var/spillage = input(src, "Would your fluids spill outside?", "Choose overflowing option", "Yes") as null|anything in list("Yes", "No")
+ if(spillage && in_range(src, partner))
+ mob_climax_partner(picked_organ, partner, spillage == "Yes" ? TRUE : FALSE)
if("Fill container")
//We'll need hands and no restraints.
if(!available_rosie_palms(FALSE, /obj/item/reagent_containers))