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