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