Demodularizing the arousal module.

This commit is contained in:
Ghommie
2020-05-08 03:35:29 +02:00
parent 5e0235bd76
commit 192c0dcc1a
24 changed files with 24 additions and 24 deletions
+282
View File
@@ -0,0 +1,282 @@
/mob/living
var/mb_cd_length = 5 SECONDS //5 second cooldown for masturbating because fuck spam.
var/mb_cd_timer = 0 //The timer itself
/mob/living/carbon/human
var/saved_underwear = ""//saves their underwear so it can be toggled later
var/saved_undershirt = ""
var/saved_socks = ""
var/hidden_underwear = FALSE
var/hidden_undershirt = FALSE
var/hidden_socks = FALSE
//Mob procs
/mob/living/carbon/human/proc/underwear_toggle()
set name = "Toggle undergarments"
set category = "IC"
var/confirm = input(src, "Select what part of your form to alter", "Undergarment Toggling") as null|anything in list("Top", "Bottom", "Socks", "All")
if(!confirm)
return
if(confirm == "Top")
hidden_undershirt = !hidden_undershirt
if(confirm == "Bottom")
hidden_underwear = !hidden_underwear
if(confirm == "Socks")
hidden_socks = !hidden_socks
if(confirm == "All")
var/on_off = (hidden_undershirt || hidden_underwear || hidden_socks) ? FALSE : TRUE
hidden_undershirt = on_off
hidden_underwear = on_off
hidden_socks = on_off
update_body(TRUE)
/mob/living/carbon/human/proc/adjust_arousal(strength,aphro = FALSE,maso = FALSE) // returns all genitals that were adjust
var/list/obj/item/organ/genital/genit_list = list()
if(!client?.prefs.arousable || (aphro && (client?.prefs.cit_toggles & NO_APHRO)) || (maso && !HAS_TRAIT(src, TRAIT_MASO)))
return // no adjusting made here
for(var/obj/item/organ/genital/G in internal_organs)
if(G.genital_flags & GENITAL_CAN_AROUSE && !G.aroused_state && prob(strength*G.sensitivity))
G.set_aroused_state(strength > 0)
G.update_appearance()
if(G.aroused_state)
genit_list += G
return genit_list
/obj/item/organ/genital/proc/climaxable(mob/living/carbon/human/H, silent = FALSE) //returns the fluid source (ergo reagents holder) if found.
if(CHECK_BITFIELD(genital_flags, GENITAL_FUID_PRODUCTION))
. = reagents
else
if(linked_organ)
. = linked_organ.reagents
if(!. && !silent)
to_chat(H, "<span class='warning'>Your [name] is unable to produce it's own fluids, it's missing the organs for it.</span>")
/mob/living/carbon/human/proc/do_climax(datum/reagents/R, atom/target, obj/item/organ/genital/G, spill = TRUE)
if(!G)
return
if(!target || !R)
return
var/turfing = isturf(target)
G.generate_fluid()
if(spill && R.total_volume >= 5)
R.reaction(turfing ? target : target.loc, TOUCH, 1, 0)
if(!turfing)
R.trans_to(target, R.total_volume * (spill ? G.fluid_transfer_factor : 1))
G.time_since_last_orgasm = 0
R.clear_reagents()
/mob/living/carbon/human/proc/mob_climax_outside(obj/item/organ/genital/G, mb_time = 30) //This is used for forced orgasms and other hands-free climaxes
var/datum/reagents/fluid_source = G.climaxable(src, TRUE)
if(!fluid_source)
to_chat(src,"<span class='userdanger'>Your [G.name] cannot cum.</span>")
return
if(mb_time) //as long as it's not instant, give a warning
to_chat(src,"<span class='userlove'>You feel yourself about to orgasm.</span>")
if(!do_after(src, mb_time, target = src) || !G.climaxable(src, TRUE))
return
to_chat(src,"<span class='userlove'>You climax[isturf(loc) ? " onto [loc]" : ""] with your [G.name].</span>")
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,"<span class='userlove'>You're about to climax with [L]!</span>")
to_chat(L,"<span class='userlove'>[src] is about to climax with you!</span>")
if(!do_after(src, mb_time, target = src) || !in_range(src, L) || !G.climaxable(src, TRUE))
return
if(spillage)
to_chat(src,"<span class='userlove'>You orgasm with [L], spilling out of them, using your [G.name].</span>")
to_chat(L,"<span class='userlove'>[src] climaxes with you, overflowing and spilling, using [p_their()] [G.name]!</span>")
else //knots and other non-spilling orgasms
to_chat(src,"<span class='userlove'>You climax with [L], your [G.name] spilling nothing.</span>")
to_chat(L,"<span class='userlove'>[src] climaxes with you, [p_their()] [G.name] spilling nothing!</span>")
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)
return
if(mb_time)
to_chat(src,"<span class='userlove'>You start to [G.masturbation_verb] your [G.name] over [container].</span>")
if(!do_after(src, mb_time, target = src) || !in_range(src, container) || !G.climaxable(src, TRUE))
return
to_chat(src,"<span class='userlove'>You used your [G.name] to fill [container].</span>")
do_climax(fluid_source, container, G, FALSE)
/mob/living/carbon/human/proc/pick_climax_genitals(silent = FALSE)
var/list/genitals_list
var/list/worn_stuff = get_equipped_items()
for(var/obj/item/organ/genital/G in internal_organs)
if(CHECK_BITFIELD(G.genital_flags, CAN_CLIMAX_WITH) && G.is_exposed(worn_stuff)) //filter out what you can't masturbate with
LAZYADD(genitals_list, G)
if(LAZYLEN(genitals_list))
var/obj/item/organ/genital/ret_organ = input(src, "with what?", "Climax", null) as null|obj in genitals_list
return ret_organ
else if(!silent)
to_chat(src, "<span class='warning'>You cannot climax without available genitals.</span>")
/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, "<span class='warning'>You cannot do this alone.</span>")
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))
to_chat(src,"<span class='notice'>Waiting for consent...</span>")
var/consenting = input(target, "Do you want [src] to climax with you?","Climax mechanics","No") in list("Yes","No")
if(consenting == "Yes")
return target
else
message_admins("[src] tried to climax with [target], but [target] did not consent.")
log_consent("[src] tried to climax with [target], but [target] did not consent.")
/mob/living/carbon/human/proc/pick_climax_container(silent = FALSE)
var/list/containers_list = list()
for(var/obj/item/reagent_containers/C in held_items)
if(C.is_open_container() || istype(C, /obj/item/reagent_containers/food/snacks))
containers_list += C
for(var/obj/item/reagent_containers/C in range(1, src))
if((C.is_open_container() || istype(C, /obj/item/reagent_containers/food/snacks)) && CanReach(C))
containers_list += C
if(containers_list.len)
var/obj/item/reagent_containers/SC = input(src, "Into or onto what?(Cancel for nowhere)", null) as null|obj in containers_list
if(SC && CanReach(SC))
return SC
else if(!silent)
to_chat(src, "<span class='warning'>You cannot do this without an appropriate container.</span>")
/mob/living/carbon/human/proc/available_rosie_palms(silent = FALSE, list/whitelist_typepaths = list(/obj/item/dildo))
if(restrained(TRUE)) //TRUE ignores grabs
if(!silent)
to_chat(src, "<span class='warning'>You can't do that while restrained!</span>")
return FALSE
if(!get_num_arms() || !get_empty_held_indexes())
if(whitelist_typepaths)
if(!islist(whitelist_typepaths))
whitelist_typepaths = list(whitelist_typepaths)
for(var/path in whitelist_typepaths)
if(is_holding_item_of_type(path))
return TRUE
if(!silent)
to_chat(src, "<span class='warning'>You need at least one free arm.</span>")
return FALSE
return TRUE
//Here's the main proc itself
/mob/living/carbon/human/proc/mob_climax(forced_climax=FALSE) //Forced is instead of the other proc, makes you cum if you have the tools for it, ignoring restraints
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, "<span class='warning'>You need to wait [DisplayTimeText((mb_cd_timer - world.time), TRUE)] before you can do that again!</span>")
return
if(!client?.prefs.arousable || !has_dna())
return
if(stat == DEAD)
if(!forced_climax)
to_chat(src, "<span class='warning'>You can't do that while dead!</span>")
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
mb_cd_timer = world.time + mb_cd_length
return
//If we get here, then this is not a forced climax and we gotta check a few things.
if(stat == UNCONSCIOUS) //No sleep-masturbation, you're unconscious.
to_chat(src, "<span class='warning'>You must be conscious to do that!</span>")
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 alone","Climax with partner", "Fill container")
if(!choice)
return
switch(choice)
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))
return
//We got hands, let's pick an organ
var/obj/item/organ/genital/picked_organ
picked_organ = pick_climax_genitals() //Gotta be climaxable, not just masturbation, to fill with fluids.
if(picked_organ)
//Good, got an organ, time to pick a container
var/obj/item/reagent_containers/fluid_container = pick_climax_container()
if(fluid_container && available_rosie_palms(TRUE, /obj/item/reagent_containers))
mob_fill_container(picked_organ, fluid_container)
mb_cd_timer = world.time + mb_cd_length
/mob/living/carbon/human/verb/climax_verb()
set category = "IC"
set name = "Climax"
set desc = "Lets you choose a couple ways to ejaculate."
mob_climax()
+374
View File
@@ -0,0 +1,374 @@
/obj/item/organ/genital
color = "#fcccb3"
w_class = WEIGHT_CLASS_SMALL
organ_flags = ORGAN_NO_DISMEMBERMENT
var/shape
var/sensitivity = 1 // wow if this were ever used that'd be cool but it's not but i'm keeping it for my unshit code
var/genital_flags //see citadel_defines.dm
var/masturbation_verb = "masturbate"
var/orgasm_verb = "cumming" //present continous
var/arousal_verb = "You feel aroused"
var/unarousal_verb = "You no longer feel aroused"
var/fluid_transfer_factor = 0 //How much would a partner get in them if they climax using this?
var/size = 2 //can vary between num or text, just used in icon_state strings
var/datum/reagent/fluid_id = null
var/fluid_max_volume = 50
var/fluid_efficiency = 1
var/fluid_rate = CUM_RATE
var/fluid_mult = 1
var/time_since_last_orgasm = 500
var/aroused_state = FALSE //Boolean used in icon_state strings
var/obj/item/organ/genital/linked_organ
var/linked_organ_slot //used for linking an apparatus' organ to its other half on update_link().
var/layer_index = GENITAL_LAYER_INDEX //Order should be very important. FIRST vagina, THEN testicles, THEN penis, as this affects the order they are rendered in.
/obj/item/organ/genital/Initialize(mapload, do_update = TRUE)
. = ..()
if(fluid_id)
create_reagents(fluid_max_volume, NONE, NO_REAGENTS_VALUE)
if(CHECK_BITFIELD(genital_flags, GENITAL_FUID_PRODUCTION))
reagents.add_reagent(fluid_id, fluid_max_volume)
if(do_update)
update()
/obj/item/organ/genital/proc/set_aroused_state(new_state)
if(!(genital_flags & GENITAL_CAN_AROUSE))
return FALSE
if(!((HAS_TRAIT(owner,TRAIT_PERMABONER) && !new_state) || HAS_TRAIT(owner,TRAIT_NEVERBONER) && new_state))
aroused_state = new_state
return aroused_state
/obj/item/organ/genital/proc/update()
if(QDELETED(src))
return
update_size()
update_appearance()
if(genital_flags & UPDATE_OWNER_APPEARANCE && owner && ishuman(owner))
var/mob/living/carbon/human/H = owner
H.update_genitals()
if(linked_organ_slot || (linked_organ && !owner))
update_link()
//exposure and through-clothing code
/mob/living/carbon
var/list/exposed_genitals = list() //Keeping track of them so we don't have to iterate through every genitalia and see if exposed
/obj/item/organ/genital/proc/is_exposed()
if(!owner || genital_flags & (GENITAL_INTERNAL|GENITAL_HIDDEN))
return FALSE
if(genital_flags & GENITAL_UNDIES_HIDDEN && ishuman(owner))
var/mob/living/carbon/human/H = owner
if(!(NO_UNDERWEAR in H.dna.species.species_traits))
var/datum/sprite_accessory/underwear/top/T = H.hidden_undershirt ? null : GLOB.undershirt_list[H.undershirt]
var/datum/sprite_accessory/underwear/bottom/B = H.hidden_underwear ? null : GLOB.underwear_list[H.underwear]
if(zone == BODY_ZONE_CHEST ? (T?.covers_chest || B?.covers_chest) : (T?.covers_groin || B?.covers_groin))
return FALSE
if(genital_flags & GENITAL_THROUGH_CLOTHES)
return TRUE
switch(zone) //update as more genitals are added
if(BODY_ZONE_CHEST)
return owner.is_chest_exposed()
if(BODY_ZONE_PRECISE_GROIN)
return owner.is_groin_exposed()
/obj/item/organ/genital/proc/toggle_visibility(visibility, update = TRUE)
genital_flags &= ~(GENITAL_THROUGH_CLOTHES|GENITAL_HIDDEN|GENITAL_UNDIES_HIDDEN)
if(owner)
owner.exposed_genitals -= src
switch(visibility)
if(GEN_VISIBLE_ALWAYS)
genital_flags |= GENITAL_THROUGH_CLOTHES
if(owner)
owner.exposed_genitals += src
if(GEN_VISIBLE_NO_UNDIES)
genital_flags |= GENITAL_UNDIES_HIDDEN
if(GEN_VISIBLE_NEVER)
genital_flags |= GENITAL_HIDDEN
if(update && owner && ishuman(owner)) //recast to use update genitals proc
var/mob/living/carbon/human/H = owner
H.update_genitals()
/mob/living/carbon/verb/toggle_genitals()
set category = "IC"
set name = "Expose/Hide genitals"
set desc = "Allows you to toggle which genitals should show through clothes or not."
if(stat != CONSCIOUS)
to_chat(usr, "<span class='warning'>You can toggle genitals visibility right now...</span>")
return
var/list/genital_list = list()
for(var/obj/item/organ/genital/G in internal_organs)
if(!CHECK_BITFIELD(G.genital_flags, GENITAL_INTERNAL))
genital_list += G
if(!genital_list.len) //There is nothing to expose
return
//Full list of exposable genitals created
var/obj/item/organ/genital/picked_organ
picked_organ = input(src, "Choose which genitalia to expose/hide", "Expose/Hide genitals") as null|anything in genital_list
if(picked_organ && (picked_organ in internal_organs))
var/picked_visibility = input(src, "Choose visibility setting", "Expose/Hide genitals") as null|anything in GLOB.genitals_visibility_toggles
if(picked_visibility && picked_organ && (picked_organ in internal_organs))
picked_organ.toggle_visibility(picked_visibility)
return
/mob/living/carbon/verb/toggle_arousal_state()
set category = "IC"
set name = "Toggle genital arousal"
set desc = "Allows you to toggle which genitals are showing signs of arousal."
var/list/genital_list = list()
for(var/obj/item/organ/genital/G in internal_organs)
if(G.genital_flags & GENITAL_CAN_AROUSE)
genital_list += G
if(!genital_list.len) //There's nothing that can show arousal
return
var/obj/item/organ/genital/picked_organ
picked_organ = input(src, "Choose which genitalia to toggle arousal on", "Set genital arousal", null) in genital_list
if(picked_organ)
var/original_state = picked_organ.aroused_state
picked_organ.set_aroused_state(!picked_organ.aroused_state)
if(original_state != picked_organ.aroused_state)
to_chat(src,"<span class='userlove'>[picked_organ.aroused_state ? picked_organ.arousal_verb : picked_organ.unarousal_verb].</span>")
else
to_chat(src,"<span class='userlove'>You can't make that genital [picked_organ.aroused_state ? "unaroused" : "aroused"]!</span>")
picked_organ.update_appearance()
return
/obj/item/organ/genital/proc/modify_size(modifier, min = -INFINITY, max = INFINITY)
fluid_max_volume += modifier*2.5
fluid_rate += modifier/10
if(reagents)
reagents.maximum_volume = fluid_max_volume
return
/obj/item/organ/genital/proc/update_size()
return
/obj/item/organ/genital/proc/update_appearance()
if(!owner || owner.stat == DEAD)
aroused_state = FALSE
/obj/item/organ/genital/on_life()
. = ..()
if(!reagents || !.)
return
reagents.maximum_volume = fluid_max_volume
if(fluid_id && CHECK_BITFIELD(genital_flags, GENITAL_FUID_PRODUCTION))
time_since_last_orgasm++
/obj/item/organ/genital/proc/generate_fluid()
var/amount = clamp(fluid_rate * time_since_last_orgasm * fluid_mult,0,fluid_max_volume)
reagents.clear_reagents()
reagents.add_reagent(fluid_id,amount)
return TRUE
/obj/item/organ/genital/proc/update_link()
if(owner)
if(linked_organ)
return FALSE
linked_organ = owner.getorganslot(linked_organ_slot)
if(linked_organ)
linked_organ.linked_organ = src
linked_organ.upon_link()
upon_link()
return TRUE
if(linked_organ)
linked_organ.linked_organ = null
linked_organ = null
return FALSE
//post organ duo making arrangements.
/obj/item/organ/genital/proc/upon_link()
return
/obj/item/organ/genital/Insert(mob/living/carbon/M, special = FALSE, drop_if_replaced = TRUE)
. = ..()
if(.)
update()
RegisterSignal(owner, COMSIG_MOB_DEATH, .proc/update_appearance)
if(genital_flags & GENITAL_THROUGH_CLOTHES)
owner.exposed_genitals += src
/obj/item/organ/genital/Remove(special = FALSE)
. = ..()
var/mob/living/carbon/C = .
update()
if(!QDELETED(C))
if(genital_flags & UPDATE_OWNER_APPEARANCE && ishuman(C))
var/mob/living/carbon/human/H = .
H.update_genitals()
C.exposed_genitals -= src
UnregisterSignal(C, COMSIG_MOB_DEATH)
//proc to give a player their genitals and stuff when they log in
/mob/living/carbon/human/proc/give_genitals(clean = FALSE)//clean will remove all pre-existing genitals. proc will then give them any genitals that are enabled in their DNA
if(clean)
for(var/obj/item/organ/genital/G in internal_organs)
qdel(G)
if (NOGENITALS in dna.species.species_traits)
return
if(dna.features["has_vag"])
give_genital(/obj/item/organ/genital/vagina)
if(dna.features["has_womb"])
give_genital(/obj/item/organ/genital/womb)
if(dna.features["has_balls"])
give_genital(/obj/item/organ/genital/testicles)
if(dna.features["has_breasts"])
give_genital(/obj/item/organ/genital/breasts)
if(dna.features["has_cock"])
give_genital(/obj/item/organ/genital/penis)
/mob/living/carbon/human/proc/give_genital(obj/item/organ/genital/G)
if(!dna || (NOGENITALS in dna.species.species_traits) || getorganslot(initial(G.slot)))
return FALSE
G = new G(null, FALSE)
G.get_features(src)
G.Insert(src)
return G
/obj/item/organ/genital/proc/get_features(mob/living/carbon/human/H)
return
//procs to handle sprite overlays being applied to humans
/mob/living/carbon/human/equip_to_slot(obj/item/I, slot)
. = ..()
if(!. && I && slot && !(slot in GLOB.no_genitals_update_slots)) //the item was successfully equipped, and the chosen slot wasn't merely storage, hands or cuffs.
update_genitals()
/mob/living/carbon/human/doUnEquip(obj/item/I, force, newloc, no_move, invdrop = TRUE)
var/no_update = FALSE
if(!I || I == l_store || I == r_store || I == s_store || I == handcuffed || I == legcuffed || get_held_index_of_item(I)) //stops storages, cuffs and held items from triggering it.
no_update = TRUE
. = ..()
if(!. || no_update)
return
update_genitals()
/mob/living/carbon/human/proc/update_genitals()
if(QDELETED(src))
return
var/static/list/relevant_layers = list("[GENITALS_BEHIND_LAYER]" = "BEHIND", "[GENITALS_FRONT_LAYER]" = "FRONT")
var/static/list/layers_num
if(!layers_num)
for(var/L in relevant_layers)
LAZYSET(layers_num, L, text2num(L))
for(var/L in relevant_layers) //Less hardcode
remove_overlay(layers_num[L])
remove_overlay(GENITALS_EXPOSED_LAYER)
if(!LAZYLEN(internal_organs) || ((NOGENITALS in dna.species.species_traits) && !genital_override) || HAS_TRAIT(src, TRAIT_HUSK))
return
//start scanning for genitals
var/list/gen_index[GENITAL_LAYER_INDEX_LENGTH]
var/list/genitals_to_add
var/list/fully_exposed
for(var/obj/item/organ/genital/G in internal_organs)
if(G.is_exposed()) //Checks appropriate clothing slot and if it's through_clothes
LAZYADD(gen_index[G.layer_index], G)
for(var/L in gen_index)
if(L) //skip nulls
LAZYADD(genitals_to_add, L)
if(!genitals_to_add)
return
//Now we added all genitals that aren't internal and should be rendered
//start applying overlays
for(var/layer in relevant_layers)
var/list/standing = list()
var/layertext = relevant_layers[layer]
for(var/A in genitals_to_add)
var/obj/item/organ/genital/G = A
var/datum/sprite_accessory/S
var/size = G.size
switch(G.type)
if(/obj/item/organ/genital/penis)
S = GLOB.cock_shapes_list[G.shape]
if(/obj/item/organ/genital/testicles)
S = GLOB.balls_shapes_list[G.shape]
if(/obj/item/organ/genital/vagina)
S = GLOB.vagina_shapes_list[G.shape]
if(/obj/item/organ/genital/breasts)
S = GLOB.breasts_shapes_list[G.shape]
if(!S || S.icon_state == "none")
continue
var/aroused_state = G.aroused_state && S.alt_aroused
var/accessory_icon = S.icon
var/do_center = S.center
var/dim_x = S.dimension_x
var/dim_y = S.dimension_y
if(G.genital_flags & GENITAL_CAN_TAUR && S.taur_icon && (!S.feat_taur || dna.features[S.feat_taur]) && dna.species.mutant_bodyparts["taur"])
var/datum/sprite_accessory/taur/T = GLOB.taur_list[dna.features["taur"]]
if(T?.taur_mode & S.accepted_taurs)
accessory_icon = S.taur_icon
do_center = TRUE
dim_x = S.taur_dimension_x
dim_y = S.taur_dimension_y
var/mutable_appearance/genital_overlay = mutable_appearance(accessory_icon, layer = -layer)
if(do_center)
genital_overlay = center_image(genital_overlay, dim_x, dim_y)
if(dna.species.use_skintones && dna.features["genitals_use_skintone"])
genital_overlay.color = SKINTONE2HEX(skin_tone)
else
switch(S.color_src)
if("cock_color")
genital_overlay.color = "#[dna.features["cock_color"]]"
if("balls_color")
genital_overlay.color = "#[dna.features["balls_color"]]"
if("breasts_color")
genital_overlay.color = "#[dna.features["breasts_color"]]"
if("vag_color")
genital_overlay.color = "#[dna.features["vag_color"]]"
genital_overlay.icon_state = "[G.slot]_[S.icon_state]_[size][(dna.species.use_skintones && !dna.skin_tone_override) ? "_s" : ""]_[aroused_state]_[layertext]"
if(layers_num[layer] == GENITALS_FRONT_LAYER && G.genital_flags & GENITAL_THROUGH_CLOTHES)
genital_overlay.layer = -GENITALS_EXPOSED_LAYER
LAZYADD(fully_exposed, genital_overlay)
else
genital_overlay.layer = -layers_num[layer]
standing += genital_overlay
if(LAZYLEN(standing))
overlays_standing[layers_num[layer]] = standing
if(LAZYLEN(fully_exposed))
overlays_standing[GENITALS_EXPOSED_LAYER] = fully_exposed
apply_overlay(GENITALS_EXPOSED_LAYER)
for(var/L in relevant_layers)
apply_overlay(layers_num[L])
//Checks to see if organs are new on the mob, and changes their colours so that they don't get crazy colours.
/mob/living/carbon/human/proc/emergent_genital_call()
if(!client.prefs.arousable)
return FALSE
var/organCheck = locate(/obj/item/organ/genital) in internal_organs
var/breastCheck = getorganslot(ORGAN_SLOT_BREASTS)
var/willyCheck = getorganslot(ORGAN_SLOT_PENIS)
if(organCheck == FALSE)
if(ishuman(src) && dna.species.use_skintones)
dna.features["genitals_use_skintone"] = TRUE
if(src.dna.species.fixed_mut_color)
dna.features["cock_color"] = "[dna.species.fixed_mut_color]"
dna.features["breasts_color"] = "[dna.species.fixed_mut_color]"
return
//So people who haven't set stuff up don't get rainbow surprises.
dna.features["cock_color"] = "[dna.features["mcolor"]]"
dna.features["breasts_color"] = "[dna.features["mcolor"]]"
else //If there's a new organ, make it the same colour.
if(breastCheck == FALSE)
dna.features["breasts_color"] = dna.features["cock_color"]
else if (willyCheck == FALSE)
dna.features["cock_color"] = dna.features["breasts_color"]
return TRUE
@@ -0,0 +1,121 @@
/datum/sprite_accessory
var/alt_aroused = FALSE //CIT CODE if this is TRUE, then the genitals will use an alternate icon_state when aroused.
var/taur_icon //leave null if the genital doesn't have a taur counterpart.
var/accepted_taurs = STYLE_HOOF_TAURIC|STYLE_PAW_TAURIC //Types that match with the accessory.
var/feat_taur //the text string of the dna feature to check for those who want to opt out.
var/taur_dimension_y = 32
var/taur_dimension_x = 32
//DICKS,COCKS,PENISES,WHATEVER YOU WANT TO CALL THEM
/datum/sprite_accessory/penis
icon = 'icons/obj/genitals/penis_onmob.dmi'
name = "penis" //the preview name of the accessory
color_src = "cock_color"
alt_aroused = TRUE
feat_taur = "cock_taur"
/datum/sprite_accessory/penis/human
icon_state = "human"
name = "Human"
/datum/sprite_accessory/penis/knotted
icon_state = "knotted"
name = "Knotted"
taur_icon = 'icons/obj/genitals/taur_penis_onmob.dmi'
taur_dimension_x = 64
/datum/sprite_accessory/penis/flared
icon_state = "flared"
name = "Flared"
taur_icon = 'icons/obj/genitals/taur_penis_onmob.dmi'
taur_dimension_x = 64
/datum/sprite_accessory/penis/barbknot
icon_state = "barbknot"
name = "Barbed, Knotted"
/datum/sprite_accessory/penis/tapered
icon_state = "tapered"
name = "Tapered"
taur_icon = 'icons/obj/genitals/taur_penis_onmob.dmi'
taur_dimension_x = 64
/datum/sprite_accessory/penis/tentacle
icon_state = "tentacle"
name = "Tentacled"
/datum/sprite_accessory/penis/hemi
icon_state = "hemi"
name = "Hemi"
/datum/sprite_accessory/penis/hemiknot
icon_state = "hemiknot"
name = "Knotted Hemi"
//Testicles
/datum/sprite_accessory/testicles
icon = 'icons/obj/genitals/testicles_onmob.dmi'
icon_state = "testicle"
name = "testicle" //the preview name of the accessory
color_src = "balls_color"
/datum/sprite_accessory/testicles/single
icon_state = "single"
name = "Single" //Single as "single pair", for clarity.
//Vaginas
/datum/sprite_accessory/vagina
icon = 'icons/obj/genitals/vagina_onmob.dmi'
name = "vagina"
color_src = "vag_color"
alt_aroused = TRUE
/datum/sprite_accessory/vagina/human
icon_state = "human"
name = "Human"
/datum/sprite_accessory/vagina/tentacles
icon_state = "tentacle"
name = "Tentacle"
/datum/sprite_accessory/vagina/dentata
icon_state = "dentata"
name = "Dentata"
/datum/sprite_accessory/vagina/hairy
icon_state = "hairy"
name = "Hairy"
alt_aroused = FALSE
/datum/sprite_accessory/vagina/spade
icon_state = "spade"
name = "Spade"
alt_aroused = FALSE
/datum/sprite_accessory/vagina/furred
icon_state = "furred"
name = "Furred"
alt_aroused = FALSE
/datum/sprite_accessory/vagina/gaping
icon_state = "gaping"
name = "Gaping"
//BREASTS BE HERE
/datum/sprite_accessory/breasts
icon = 'icons/obj/genitals/breasts_onmob.dmi'
name = "breasts"
color_src = "breasts_color"
/datum/sprite_accessory/breasts/pair
icon_state = "pair"
name = "Pair"
/datum/sprite_accessory/breasts/quad
icon_state = "quad"
name = "Quad"
/datum/sprite_accessory/breasts/sextuple
icon_state = "sextuple"
name = "Sextuple"
+137
View File
@@ -0,0 +1,137 @@
#define BREASTS_ICON_MIN_SIZE 1
#define BREASTS_ICON_MAX_SIZE 6
/obj/item/organ/genital/breasts
name = "breasts"
desc = "Female milk producing organs."
icon_state = "breasts"
icon = 'icons/obj/genitals/breasts.dmi'
zone = BODY_ZONE_CHEST
slot = ORGAN_SLOT_BREASTS
size = BREASTS_SIZE_DEF // "c". Refer to the breast_values static list below for the cups associated number values
fluid_id = /datum/reagent/consumable/milk
fluid_rate = MILK_RATE
shape = DEF_BREASTS_SHAPE
genital_flags = CAN_MASTURBATE_WITH|CAN_CLIMAX_WITH|GENITAL_FUID_PRODUCTION|GENITAL_CAN_AROUSE|UPDATE_OWNER_APPEARANCE|GENITAL_UNDIES_HIDDEN
masturbation_verb = "massage"
arousal_verb = "Your breasts start feeling sensitive"
unarousal_verb = "Your breasts no longer feel sensitive"
orgasm_verb = "leaking"
fluid_transfer_factor = 0.5
var/static/list/breast_values = list("a" = 1, "b" = 2, "c" = 3, "d" = 4, "e" = 5, "f" = 6, "g" = 7, "h" = 8, "i" = 9, "j" = 10, "k" = 11, "l" = 12, "m" = 13, "n" = 14, "o" = 15, "huge" = 16, "flat" = 0)
var/cached_size //these two vars pertain size modifications and so should be expressed in NUMBERS.
var/prev_size //former cached_size value, to allow update_size() to early return should be there no significant changes.
/obj/item/organ/genital/breasts/Initialize(mapload, do_update = TRUE)
if(do_update)
cached_size = breast_values[size]
prev_size = cached_size
return ..()
/obj/item/organ/genital/breasts/update_appearance()
. = ..()
var/lowershape = lowertext(shape)
switch(lowershape)
if("pair")
desc = "You see a pair of breasts."
if("quad")
desc = "You see two pairs of breast, one just under the other."
if("sextuple")
desc = "You see three sets of breasts, running from their chest to their belly."
else
desc = "You see some breasts, they seem to be quite exotic."
if(size == "huge")
desc = "You see [pick("some serious honkers", "a real set of badonkers", "some dobonhonkeros", "massive dohoonkabhankoloos", "two big old tonhongerekoogers", "a couple of giant bonkhonagahoogs", "a pair of humongous hungolomghnonoloughongous")]. Their volume is way beyond cupsize now, measuring in about [round(cached_size)]cm in diameter."
else
if (size == "flat")
desc += " They're very small and flatchested, however."
else
desc += " You estimate that they're [uppertext(size)]-cups."
if(CHECK_BITFIELD(genital_flags, GENITAL_FUID_PRODUCTION) && aroused_state)
var/datum/reagent/R = GLOB.chemical_reagents_list[fluid_id]
if(R)
desc += " They're leaking [lowertext(R.name)]."
var/datum/sprite_accessory/S = GLOB.breasts_shapes_list[shape]
var/icon_shape = S ? S.icon_state : "pair"
var/icon_size = clamp(breast_values[size], BREASTS_ICON_MIN_SIZE, BREASTS_ICON_MAX_SIZE)
icon_state = "breasts_[icon_shape]_[icon_size]"
if(owner)
if(owner.dna.species.use_skintones && owner.dna.features["genitals_use_skintone"])
if(ishuman(owner)) // Check before recasting type, although someone fucked up if you're not human AND have use_skintones somehow...
var/mob/living/carbon/human/H = owner // only human mobs have skin_tone, which we need.
color = SKINTONE2HEX(H.skin_tone)
if(!H.dna.skin_tone_override)
icon_state += "_s"
else
color = "#[owner.dna.features["breasts_color"]]"
//Allows breasts to grow and change size, with sprite changes too.
//maximum wah
//Comical sizes slow you down in movement and actions.
//Ridiculous sizes makes you more cumbersome.
//this is far too lewd wah
/obj/item/organ/genital/breasts/modify_size(modifier, min = -INFINITY, max = INFINITY)
var/new_value = clamp(cached_size + modifier, min, max)
if(new_value == cached_size)
return
prev_size = cached_size
cached_size = new_value
update()
..()
/obj/item/organ/genital/breasts/update_size()//wah
var/rounded_cached = round(cached_size)
if(cached_size < 0)//I don't actually know what round() does to negative numbers, so to be safe!!fixed
if(owner)
to_chat(owner, "<span class='warning'>You feel your breasts shrinking away from your body as your chest flattens out.</span>")
QDEL_IN(src, 1)
return
var/enlargement = FALSE
switch(rounded_cached)
if(0) //flatchested
size = "flat"
if(1 to 8) //modest
size = breast_values[rounded_cached]
if(9 to 15) //massive
size = breast_values[rounded_cached]
enlargement = TRUE
if(16 to INFINITY) //rediculous
size = "huge"
enlargement = TRUE
if(owner)
var/status_effect = owner.has_status_effect(STATUS_EFFECT_BREASTS_ENLARGEMENT)
if(enlargement && !status_effect)
owner.apply_status_effect(STATUS_EFFECT_BREASTS_ENLARGEMENT)
else if(!enlargement && status_effect)
owner.remove_status_effect(STATUS_EFFECT_BREASTS_ENLARGEMENT)
if(rounded_cached < 16 && owner)//Because byond doesn't count from 0, I have to do this.
var/mob/living/carbon/human/H = owner
var/r_prev_size = round(prev_size)
if (rounded_cached > r_prev_size)
to_chat(H, "<span class='warning'>Your breasts [pick("swell up to", "flourish into", "expand into", "burst forth into", "grow eagerly into", "amplify into")] a [uppertext(size)]-cup.</span>")
else if (rounded_cached < r_prev_size)
to_chat(H, "<span class='warning'>Your breasts [pick("shrink down to", "decrease into", "diminish into", "deflate into", "shrivel regretfully into", "contracts into")] a [uppertext(size)]-cup.</span>")
/obj/item/organ/genital/breasts/get_features(mob/living/carbon/human/H)
var/datum/dna/D = H.dna
if(D.species.use_skintones && D.features["genitals_use_skintone"])
color = SKINTONE2HEX(H.skin_tone)
else
color = "#[D.features["breasts_color"]]"
size = D.features["breasts_size"]
shape = D.features["breasts_shape"]
if(!D.features["breasts_producing"])
DISABLE_BITFIELD(genital_flags, GENITAL_FUID_PRODUCTION|CAN_CLIMAX_WITH|CAN_MASTURBATE_WITH)
if(!isnum(size))
cached_size = breast_values[size]
else
cached_size = size
size = breast_values[size]
prev_size = cached_size
toggle_visibility(D.features["breasts_visibility"], FALSE)
#undef BREASTS_ICON_MIN_SIZE
#undef BREASTS_ICON_MAX_SIZE
+109
View File
@@ -0,0 +1,109 @@
/obj/item/organ/genital/penis
name = "penis"
desc = "A male reproductive organ."
icon_state = "penis"
icon = 'icons/obj/genitals/penis.dmi'
zone = BODY_ZONE_PRECISE_GROIN
slot = ORGAN_SLOT_PENIS
masturbation_verb = "stroke"
arousal_verb = "You pop a boner"
unarousal_verb = "Your boner goes down"
genital_flags = CAN_MASTURBATE_WITH|CAN_CLIMAX_WITH|GENITAL_CAN_AROUSE|UPDATE_OWNER_APPEARANCE|GENITAL_UNDIES_HIDDEN|GENITAL_CAN_TAUR
linked_organ_slot = ORGAN_SLOT_TESTICLES
fluid_transfer_factor = 0.5
shape = DEF_COCK_SHAPE
size = 2 //arbitrary value derived from length and diameter for sprites.
layer_index = PENIS_LAYER_INDEX
var/length = 6 //inches
var/prev_length = 6 //really should be renamed to prev_length
var/diameter = 4.38
var/diameter_ratio = COCK_DIAMETER_RATIO_DEF //0.25; check citadel_defines.dm
/obj/item/organ/genital/penis/modify_size(modifier, min = -INFINITY, max = INFINITY)
var/new_value = clamp(length + modifier, min, max)
if(new_value == length)
return
prev_length = length
length = clamp(length + modifier, min, max)
update()
..()
/obj/item/organ/genital/penis/update_size(modified = FALSE)
if(length <= 0)//I don't actually know what round() does to negative numbers, so to be safe!!
if(owner)
to_chat(owner, "<span class='warning'>You feel your tallywacker shrinking away from your body as your groin flattens out!</b></span>")
QDEL_IN(src, 1)
if(linked_organ)
QDEL_IN(linked_organ, 1)
return
var/rounded_length = round(length)
var/new_size
var/enlargement = FALSE
switch(rounded_length)
if(0 to 6) //If modest size
new_size = 1
if(7 to 11) //If large
new_size = 2
if(12 to 20) //If massive
new_size = 3
if(21 to 34) //If massive and due for large effects
new_size = 3
enlargement = TRUE
if(35 to INFINITY) //If comical
new_size = 4 //no new sprites for anything larger yet
enlargement = TRUE
if(owner)
var/status_effect = owner.has_status_effect(STATUS_EFFECT_PENIS_ENLARGEMENT)
if(enlargement && !status_effect)
owner.apply_status_effect(STATUS_EFFECT_PENIS_ENLARGEMENT)
else if(!enlargement && status_effect)
owner.remove_status_effect(STATUS_EFFECT_PENIS_ENLARGEMENT)
if(linked_organ)
linked_organ.size = clamp(size + new_size, BALLS_SIZE_MIN, BALLS_SIZE_MAX)
linked_organ.update()
size = new_size
if(owner)
if (round(length) > round(prev_length))
to_chat(owner, "<span class='warning'>Your [pick(GLOB.dick_nouns)] [pick("swells up to", "flourishes into", "expands into", "bursts forth into", "grows eagerly into", "amplifys into")] a [uppertext(round(length))] inch penis.</b></span>")
else if ((round(length) < round(prev_length)) && (length > 0.5))
to_chat(owner, "<span class='warning'>Your [pick(GLOB.dick_nouns)] [pick("shrinks down to", "decreases into", "diminishes into", "deflates into", "shrivels regretfully into", "contracts into")] a [uppertext(round(length))] inch penis.</b></span>")
icon_state = sanitize_text("penis_[shape]_[size]")
diameter = (length * diameter_ratio)//Is it just me or is this ludicous, why not make it exponentially decay?
/obj/item/organ/genital/penis/update_appearance()
. = ..()
var/datum/sprite_accessory/S = GLOB.cock_shapes_list[shape]
var/icon_shape = S ? S.icon_state : "human"
icon_state = "penis_[icon_shape]_[size]"
var/lowershape = lowertext(shape)
if(owner)
if(owner.dna.species.use_skintones && owner.dna.features["genitals_use_skintone"])
if(ishuman(owner)) // Check before recasting type, although someone fucked up if you're not human AND have use_skintones somehow...
var/mob/living/carbon/human/H = owner // only human mobs have skin_tone, which we need.
color = SKINTONE2HEX(H.skin_tone)
if(!H.dna.skin_tone_override)
icon_state += "_s"
else
color = "#[owner.dna.features["cock_color"]]"
if(genital_flags & GENITAL_CAN_TAUR && S?.taur_icon && (!S.feat_taur || owner.dna.features[S.feat_taur]) && owner.dna.species.mutant_bodyparts["taur"])
var/datum/sprite_accessory/taur/T = GLOB.taur_list[owner.dna.features["taur"]]
if(T.taur_mode & S.accepted_taurs) //looks out of place on those.
lowershape = "taur, [lowershape]"
desc = "You see [aroused_state ? "an erect" : "a flaccid"] [lowershape] [name]. You estimate it's about [round(length, 0.25)] inch[round(length, 0.25) != 1 ? "es" : ""] long and [round(diameter, 0.25)] inch[round(diameter, 0.25) != 1 ? "es" : ""] in diameter."
/obj/item/organ/genital/penis/get_features(mob/living/carbon/human/H)
var/datum/dna/D = H.dna
if(D.species.use_skintones && D.features["genitals_use_skintone"])
color = SKINTONE2HEX(H.skin_tone)
else
color = "#[D.features["cock_color"]]"
length = D.features["cock_length"]
diameter_ratio = D.features["cock_diameter_ratio"]
shape = D.features["cock_shape"]
prev_length = length
toggle_visibility(D.features["cock_visibility"], FALSE)
+67
View File
@@ -0,0 +1,67 @@
/obj/item/organ/genital/testicles
name = "testicles"
desc = "A male reproductive organ."
icon_state = "testicles"
icon = 'icons/obj/genitals/testicles.dmi'
zone = BODY_ZONE_PRECISE_GROIN
slot = ORGAN_SLOT_TESTICLES
size = BALLS_SIZE_MIN
arousal_verb = "Your balls ache a little"
unarousal_verb = "Your balls finally stop aching, again"
linked_organ_slot = ORGAN_SLOT_PENIS
genital_flags = CAN_MASTURBATE_WITH|MASTURBATE_LINKED_ORGAN|GENITAL_FUID_PRODUCTION|UPDATE_OWNER_APPEARANCE|GENITAL_UNDIES_HIDDEN
var/size_name = "average"
shape = DEF_BALLS_SHAPE
fluid_id = /datum/reagent/consumable/semen
masturbation_verb = "massage"
layer_index = TESTICLES_LAYER_INDEX
/obj/item/organ/genital/testicles/generate_fluid()
if(!linked_organ && !update_link())
return FALSE
return ..()
// in memoriam "Your balls finally feel full, again." ??-2020
/obj/item/organ/genital/testicles/upon_link()
size = linked_organ.size
update_size()
update_appearance()
/obj/item/organ/genital/testicles/update_size(modified = FALSE)
switch(size)
if(BALLS_SIZE_MIN)
size_name = "average"
if(BALLS_SIZE_DEF)
size_name = "enlarged"
if(BALLS_SIZE_MAX)
size_name = "engorged"
else
size_name = "nonexistant"
/obj/item/organ/genital/testicles/update_appearance()
. = ..()
desc = "You see an [size_name] pair of testicles."
var/datum/sprite_accessory/S = GLOB.balls_shapes_list[shape]
var/icon_shape = S ? S.icon_state : "single"
icon_state = "testicles_[icon_shape]_[size]"
if(owner)
if(owner.dna.species.use_skintones && owner.dna.features["genitals_use_skintone"])
if(ishuman(owner)) // Check before recasting type, although someone fucked up if you're not human AND have use_skintones somehow...
var/mob/living/carbon/human/H = owner // only human mobs have skin_tone, which we need.
color = SKINTONE2HEX(H.skin_tone)
if(!H.dna.skin_tone_override)
icon_state += "_s"
else
color = "#[owner.dna.features["balls_color"]]"
/obj/item/organ/genital/testicles/get_features(mob/living/carbon/human/H)
var/datum/dna/D = H.dna
if(D.species.use_skintones && D.features["genitals_use_skintone"])
color = SKINTONE2HEX(H.skin_tone)
else
color = "#[D.features["balls_color"]]"
shape = D.features["balls_shape"]
fluid_rate = D.features["balls_cum_rate"]
fluid_mult = D.features["balls_cum_mult"]
fluid_efficiency = D.features["balls_efficiency"]
toggle_visibility(D.features["balls_visibility"], FALSE)
+74
View File
@@ -0,0 +1,74 @@
/obj/item/organ/genital/vagina
name = "vagina"
desc = "A female reproductive organ."
icon = 'icons/obj/genitals/vagina.dmi'
icon_state = ORGAN_SLOT_VAGINA
zone = BODY_ZONE_PRECISE_GROIN
slot = "vagina"
size = 1 //There is only 1 size right now
shape = DEF_VAGINA_SHAPE
genital_flags = CAN_MASTURBATE_WITH|CAN_CLIMAX_WITH|GENITAL_CAN_AROUSE|GENITAL_UNDIES_HIDDEN
masturbation_verb = "finger"
arousal_verb = "You feel wetness on your crotch"
unarousal_verb = "You no longer feel wet"
fluid_transfer_factor = 0.1 //Yes, some amount is exposed to you, go get your AIDS
layer_index = VAGINA_LAYER_INDEX
var/cap_length = 8//D E P T H (cap = capacity)
var/cap_girth = 12
var/cap_girth_ratio = 1.5
var/clits = 1
var/clit_diam = 0.25
var/clit_len = 0.25
var/list/vag_types = list("tentacle", "dentata", "hairy", "spade", "furred")
/obj/item/organ/genital/vagina/update_appearance()
. = ..()
icon_state = "vagina"
var/lowershape = lowertext(shape)
var/details
switch(lowershape)
if("tentacle")
details = "Its opening is lined with several tentacles and "
if("dentata")
details = "There's teeth inside it and it "
if("hairy")
details = "It has quite a bit of hair growing on it and "
if("human")
details = "It is taut with smooth skin, though without much hair and "
if("gaping")
details = "It is gaping slightly open, though without much hair and "
if("spade")
details = "It is a plush canine spade, it "
if("furred")
details = "It has neatly groomed fur around the outer folds, it "
else
details = "It has an exotic shape and "
if(aroused_state)
details += "is slick with female arousal."
else
details += "seems to be dry."
desc = "You see a vagina. [details]"
if(owner)
if(owner.dna.species.use_skintones && owner.dna.features["genitals_use_skintone"])
if(ishuman(owner)) // Check before recasting type, although someone fucked up if you're not human AND have use_skintones somehow...
var/mob/living/carbon/human/H = owner // only human mobs have skin_tone, which we need.
color = SKINTONE2HEX(H.skin_tone)
if(!H.dna.skin_tone_override)
icon_state += "_s"
else
color = "#[owner.dna.features["vag_color"]]"
if(ishuman(owner))
var/mob/living/carbon/human/H = owner
H.update_genitals()
/obj/item/organ/genital/vagina/get_features(mob/living/carbon/human/H)
var/datum/dna/D = H.dna
if(D.species.use_skintones && D.features["genitals_use_skintone"])
color = SKINTONE2HEX(H.skin_tone)
else
color = "[D.features["vag_color"]]"
shape = "[D.features["vag_shape"]]"
toggle_visibility(D.features["vag_visibility"], FALSE)
+10
View File
@@ -0,0 +1,10 @@
/obj/item/organ/genital/womb
name = "womb"
desc = "A female reproductive organ."
icon = 'icons/obj/genitals/vagina.dmi'
icon_state = "womb"
zone = BODY_ZONE_PRECISE_GROIN
slot = ORGAN_SLOT_WOMB
genital_flags = GENITAL_INTERNAL|GENITAL_FUID_PRODUCTION
fluid_id = /datum/reagent/consumable/femcum
linked_organ_slot = ORGAN_SLOT_VAGINA
+159
View File
@@ -0,0 +1,159 @@
//////////
//DILDOS//
//////////
/obj/item/dildo
name = "dildo"
desc = "Floppy!"
icon = 'icons/obj/genitals/dildo.dmi'
force = 0
hitsound = 'sound/weapons/tap.ogg'
throwforce = 0
icon_state = "dildo_knotted_2"
alpha = 192//transparent
var/can_customize = FALSE
var/dildo_shape = "human"
var/dildo_size = 2
var/dildo_type = "dildo"//pretty much just used for the icon state
var/random_color = TRUE
var/random_size = FALSE
var/random_shape = FALSE
var/is_knotted = FALSE
//Lists moved to _cit_helpers.dm as globals so they're not instanced individually
/obj/item/dildo/proc/update_appearance()
icon_state = "[dildo_type]_[dildo_shape]_[dildo_size]"
var/sizeword = ""
switch(dildo_size)
if(1)
sizeword = "small "
if(3)
sizeword = "big "
if(4)
sizeword = "huge "
if(5)
sizeword = "gigantic "
name = "[sizeword][dildo_shape] [can_customize ? "custom " : ""][dildo_type]"
/obj/item/dildo/AltClick(mob/living/user)
. = ..()
if(!istype(user) || !user.canUseTopic(src, BE_CLOSE, FALSE, NO_TK))
return
customize(user)
return TRUE
/obj/item/dildo/proc/customize(mob/living/user)
if(!can_customize)
return FALSE
if(src && !user.incapacitated() && in_range(user,src))
var/color_choice = input(user,"Choose a color for your dildo.","Dildo Color") as null|anything in GLOB.dildo_colors
if(src && color_choice && !user.incapacitated() && in_range(user,src))
sanitize_inlist(color_choice, GLOB.dildo_colors, "Red")
color = GLOB.dildo_colors[color_choice]
update_appearance()
if(src && !user.incapacitated() && in_range(user,src))
var/shape_choice = input(user,"Choose a shape for your dildo.","Dildo Shape") as null|anything in GLOB.dildo_shapes
if(src && shape_choice && !user.incapacitated() && in_range(user,src))
sanitize_inlist(shape_choice, GLOB.dildo_colors, "Knotted")
dildo_shape = GLOB.dildo_shapes[shape_choice]
update_appearance()
if(src && !user.incapacitated() && in_range(user,src))
var/size_choice = input(user,"Choose the size for your dildo.","Dildo Size") as null|anything in GLOB.dildo_sizes
if(src && size_choice && !user.incapacitated() && in_range(user,src))
sanitize_inlist(size_choice, GLOB.dildo_colors, "Medium")
dildo_size = GLOB.dildo_sizes[size_choice]
update_appearance()
if(src && !user.incapacitated() && in_range(user,src))
var/transparency_choice = input(user,"Choose the transparency of your dildo. Lower is more transparent!(192-255)","Dildo Transparency") as null|num
if(src && transparency_choice && !user.incapacitated() && in_range(user,src))
sanitize_integer(transparency_choice, 192, 255, 192)
alpha = transparency_choice
update_appearance()
return TRUE
/obj/item/dildo/Initialize()
. = ..()
if(random_color == TRUE)
var/randcolor = pick(GLOB.dildo_colors)
color = GLOB.dildo_colors[randcolor]
if(random_shape == TRUE)
var/randshape = pick(GLOB.dildo_shapes)
dildo_shape = GLOB.dildo_shapes[randshape]
if(random_size == TRUE)
var/randsize = pick(GLOB.dildo_sizes)
dildo_size = GLOB.dildo_sizes[randsize]
update_appearance()
alpha = rand(192, 255)
pixel_y = rand(-7,7)
pixel_x = rand(-7,7)
/obj/item/dildo/examine(mob/user)
. = ..()
if(can_customize)
. += "<span class='notice'>Alt-Click \the [src.name] to customize it.</span>"
/obj/item/dildo/random//totally random
name = "random dildo"//this name will show up in vendors and shit so you know what you're vending(or don't, i guess :^))
random_color = TRUE
random_shape = TRUE
random_size = TRUE
/obj/item/dildo/knotted
dildo_shape = "knotted"
name = "knotted dildo"
attack_verb = list("penetrated", "knotted", "slapped", "inseminated")
obj/item/dildo/human
dildo_shape = "human"
name = "human dildo"
attack_verb = list("penetrated", "slapped", "inseminated")
obj/item/dildo/plain
dildo_shape = "plain"
name = "plain dildo"
attack_verb = list("penetrated", "slapped", "inseminated")
obj/item/dildo/flared
dildo_shape = "flared"
name = "flared dildo"
attack_verb = list("penetrated", "slapped", "neighed", "gaped", "prolapsed", "inseminated")
obj/item/dildo/flared/huge
name = "literal horse cock"
desc = "THIS THING IS HUGE!"
dildo_size = 4
obj/item/dildo/custom
name = "customizable dildo"
desc = "Thanks to significant advances in synthetic nanomaterials, this dildo is capable of taking on many different forms to fit the user's preferences! Pricy!"
can_customize = TRUE
random_color = TRUE
random_shape = TRUE
random_size = TRUE
// Suicide acts, by request
/obj/item/dildo/proc/manual_suicide(mob/living/user)
user.visible_message("<span class='suicide'>[user] finally finishes deepthroating the [src], and their life.</span>")
user.adjustOxyLoss(200)
user.death(0)
/obj/item/dildo/suicide_act(mob/living/user)
// is_knotted = ((src.dildo_shape == "knotted")?"They swallowed the knot":"Their face is turning blue")
if(do_after(user,17,target=src))
user.visible_message("<span class='suicide'>[user] tears-up and gags as they shove [src] down their throat! It looks like [user.p_theyre()] trying to commit suicide!</span>")
playsound(loc, 'sound/weapons/gagging.ogg', 50, 1, -1)
user.Stun(150)
user.adjust_blurriness(8)
var/obj/item/organ/eyes/eyes = user.getorganslot(ORGAN_SLOT_EYES)
eyes?.applyOrganDamage(10)
return MANUAL_SUICIDE
/obj/item/dildo/flared/huge/suicide_act(mob/living/user)
if(do_after(user,35,target=src))
user.visible_message("<span class='suicide'>[user] tears-up and gags as they try to deepthroat the [src]! WHY WOULD THEY DO THAT? It looks like [user.p_theyre()] trying to commit suicide!!</span>")
playsound(loc, 'sound/weapons/gagging.ogg', 50, 2, -1)
user.Stun(300)
user.adjust_blurriness(8)
return MANUAL_SUICIDE