[MODULARIZING] Partial Refactoring of Organic Interface Code (#16019)

This took a long time to review, but at long last, it's done.

* HUD clutter, good bye, you will not be missed.

* Oh my god so much pain

* No commented code. Bad.

* Uwaaaa

* Add a couple of warning messages for common scenarios, use defines

* AAAAA

* AAAAAAAAAAA

* UWAAAA

* UUUUWAAAA, DOCUMENTED SNOWFLAKE CODE

* FUCK

* Apply suggestions!

* Apply suggestions part one!

Co-authored-by: GoldenAlpharex <58045821+GoldenAlpharex@users.noreply.github.com>

* Apply suggestions part two!

* Static list

I think this is how it works, it compiles, sooo

* Split the giga monolith that's known as technical_stuff_for_lewd into two parts, human_helpers, and whatever else isn't a human helper. Also add a helper proc for mass update_inv on organic interface slots.

* I can't believe you did this

* Did you know that organic interface code didn't clean up it's defines? Neither did I!

* Less ifs

* Apply last suggestion that I know how to

* That was a lie

* AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

I HAVEN'T EVEN TOUCHED THE WORST CODE

* Oops

* Pain

* No copypaste

* Proc is 🦀

* No, bad, no commenting code.

* List prittification for chems, reduces the sheer amount of update_body calls

* Allow non-lewd empath users to not have to suffer raunchy inspect messages

* Oop

* DEEEEEEEEEEEEFINES

* Oh yea, that review. Definitely remembered.

* Formatting

* Breast defines

* MUCH cleaner and MUCH MUCH EASIER to expand incubus draft code

* Credit myself if I'm gonna spend days of my time combing through this

* Oops

* Chems cleanup

* Whyyyyyyy

* Climax rework, suffering.

* Wtf is this name

* Oh yea, arousal clamping.

* Haha, oops

* Bad, this is stupid easy to modularize

* Why is body_size in here

* List formatting, grammar stuff, and also breast size is now letters

* This took too long for me to figure out and I'm not proud

* Even I can make shitcode!

* Oops, typo

* You know, this makes more sense.

* Mhhh, this shouldn't be named like this

* Wrong file

* Rename `adjustPain`

* Dead code go yeet

* Y U NO READ DOCS

* Doc proc, minor optimisation

* Reviews part 1

* Whoever made this should read good coding practices. For any language.

* DEEEEFINNNEEEEESSSS

* SUFFER

* No more fluids

* EEEEEEEEEEE

* AAAAAAAAAAAAAAA

* MOB IS 🦀

* AAAAAAAAAAAAAAAAAA

* AAAAAA

* UWA

* And also solve tastfish's reviews!

* Partial revert, cause DM hates that

* I am very smart

* EEE

* AAAAAA

* Haha keyboard go click clack

* CODE

* FUCK

* FUUUUUCK

* PERFORMANCE

* Reset horny to 0 if erp disabled

* Arousal minimum is now 0, cause negatives are dumb and I hate them

Also cuts out some code that isn't needed as far as I can tell.

* Apply suggestions!

Co-authored-by: GoldenAlpharex <58045821+GoldenAlpharex@users.noreply.github.com>

* AAAAA

* AAAAAAAAAA I CAN'T CODE

* Aaaaa

* WHY GIT

* I am very smart part... uh, four?

* Minor formatting changes

* Oops, fix potential cause of multiple climax attempts

* WAIT, WHY AREN'T YOU USING THE DEFINE?!

* Magic number slightly less magicky, sorta.

Co-authored-by: GoldenAlpharex <58045821+GoldenAlpharex@users.noreply.github.com>
This commit is contained in:
RimiNosha
2022-10-04 11:06:12 -04:00
committed by GitHub
co-authored by GoldenAlpharex
parent 4ece9155a6
commit f58cf51ae4
98 changed files with 2982 additions and 3540 deletions
+1 -15
View File
@@ -61,22 +61,8 @@
/// Legcuff slot (bolas, beartraps)
#define ITEM_SLOT_LEGCUFFED (1<<19)
//SKYRAT EDIT ADDITION BEGIN - ERP UPDATE
/// Penis slot
#define ITEM_SLOT_PENIS (1<<20)
/// Vagina slot
#define ITEM_SLOT_VAGINA (1<<21)
/// Anus slot
#define ITEM_SLOT_ANUS (1<<22)
/// Nipples slot
#define ITEM_SLOT_NIPPLES (1<<23)
//SKYRATE EDIT ADDITION END
/// Total amount of slots
//SKYRAT EDIT CHANGE BEGIN
// #define SLOTS_AMT 20 // Keep this up to date! - SKYRAT EDIT - ORIGINAL
#define SLOTS_AMT 24 // Keep this up to date!
//SKYRAT EDIT CHANGE END
#define SLOTS_AMT 20 // Keep this up to date!
//SLOT GROUP HELPERS
#define ITEM_SLOT_POCKETS (ITEM_SLOT_LPOCKET|ITEM_SLOT_RPOCKET)
@@ -6,5 +6,6 @@
#define ORGAN_SLOT_TESTICLES "testicles"
#define ORGAN_SLOT_BREASTS "breasts"
#define ORGAN_SLOT_ANUS "anus"
#define ORGAN_SLOT_NIPPLES "nipples"
#define ORGAN_SLOT_WINGS "wings"
@@ -4,3 +4,9 @@
#define STYLE_TAUR_HOOF (1<<4)
#define STYLE_TAUR_ALL (STYLE_TAUR_SNAKE|STYLE_TAUR_PAW|STYLE_TAUR_HOOF)
#define STYLE_TESHARI (1<<6) //teshari clothes and shit
// We don't use the HUD for these, they have their own menu.
#define LEWD_SLOT_VAGINA (1<<0)
#define LEWD_SLOT_PENIS (1<<1)
#define LEWD_SLOT_ANUS (1<<2)
#define LEWD_SLOT_NIPPLES (1<<3)
@@ -0,0 +1,49 @@
/// To prevent an issue with stupidly low negative values.
#define AROUSAL_MINIMUM 0
#define AROUSAL_MINIMUM_DETECTABLE 10
#define AROUSAL_LOW 30
#define AROUSAL_MEDIUM 70
#define AROUSAL_HIGH 85
#define AROUSAL_AUTO_CLIMAX_THRESHOLD 90
#define AROUSAL_LIMIT 100
#define REQUIRE_GENITAL_EXPOSED 1
#define REQUIRE_GENITAL_UNEXPOSED 2
#define REQUIRE_GENITAL_ANY 3
#define TRAIT_MASOCHISM "masochism"
#define TRAIT_SADISM "sadism"
#define TRAIT_NEVERBONER "neverboner"
#define TRAIT_BIMBO "bimbo"
#define TRAIT_RIGGER "rigger"
#define TRAIT_ROPEBUNNY "rope bunny"
///traits gained by brain traumas, can be removed if the brain trauma is gone
#define APHRO_TRAIT "aphro"
///traits gained by quirks, cannot be removed unless the quirk itself is gone
#define LEWDQUIRK_TRAIT "lewdquirks"
///traits gained by chemicals, you get the idea
#define LEWDCHEM_TRAIT "lewdchem"
#define STRAPON_TRAIT "strapon"
#define CONDOM_BROKEN "broken"
#define BREAST_SIZE_FLATCHESTED "Flatchested"
#define BREAST_SIZE_A "A"
#define BREAST_SIZE_B "B"
#define BREAST_SIZE_C "C"
#define BREAST_SIZE_D "D"
// Ouch, my back.
#define BREAST_SIZE_E "E"
#define BREAST_SIZE_F "F"
#define BREAST_SIZE_G "G"
#define BREAST_SIZE_H "H"
#define BREAST_SIZE_I "I"
#define BREAST_SIZE_J "J"
#define BREAST_SIZE_K "K"
#define BREAST_SIZE_L "L"
#define BREAST_SIZE_M "M"
#define BREAST_SIZE_N "N"
#define BREAST_SIZE_O "O"
#define BREAST_SIZE_P "P"
#define BREAST_SIZE_BEYOND_MEASUREMENT "beyond measurement"
-8
View File
@@ -244,14 +244,6 @@ GLOBAL_LIST_INIT(modulo_angle_to_dir, list(NORTH,NORTHEAST,EAST,SOUTHEAST,SOUTH,
if(ITEM_SLOT_LEGCUFFED)
return pick(BODY_ZONE_L_LEG, BODY_ZONE_R_LEG)
//SKYRAT EDIT ADDITION BEGIN - ERP_SLOT_SYSTEM
if(ITEM_SLOT_PENIS, ITEM_SLOT_VAGINA, ITEM_SLOT_ANUS)
return BODY_ZONE_PRECISE_GROIN
if(ITEM_SLOT_NIPPLES)
return BODY_ZONE_CHEST
//SKYRAT EDIT ADDITION END
//adapted from http://www.tannerhelland.com/4435/convert-temperature-rgb-algorithm-code/
/proc/heat2colour(temp)
return rgb(heat2colour_r(temp), heat2colour_g(temp), heat2colour_b(temp))
-30
View File
@@ -223,9 +223,6 @@ GLOBAL_LIST_INIT(available_erp_ui_styles, list(
pull_icon = null
QDEL_LIST(toggleable_inventory)
//SKYRAT EDIT ADDITION BEGIN - ERP_SLOT_SYSTEM
QDEL_LIST(erp_toggleable_inventory) // Destroy ERP stuff
//SKYRAT EDIT ADDITION END
QDEL_LIST(hotkeybuttons)
throw_icon = null
QDEL_LIST(infodisplay)
@@ -321,10 +318,6 @@ GLOBAL_LIST_INIT(available_erp_ui_styles, list(
screenmob.client.screen += static_inventory
if(toggleable_inventory.len && screenmob.hud_used && screenmob.hud_used.inventory_shown)
screenmob.client.screen += toggleable_inventory
//SKYRAT EDIT ADDITION BEGIN - ERP_SLOT_SYSTEM
if(erp_toggleable_inventory.len && screenmob.hud_used && screenmob.hud_used.ERP_inventory_shown && screenmob.client?.prefs?.read_preference(/datum/preference/toggle/erp/sex_toy))
screenmob.client.screen += erp_toggleable_inventory
//SKYRAT EDIT ADDITION END
if(hotkeybuttons.len && !hotkey_ui_hidden)
screenmob.client.screen += hotkeybuttons
if(infodisplay.len)
@@ -341,10 +334,6 @@ GLOBAL_LIST_INIT(available_erp_ui_styles, list(
screenmob.client.screen -= static_inventory
if(toggleable_inventory.len)
screenmob.client.screen -= toggleable_inventory
//SKYRAT EDIT ADDITION BEGIN - ERP_SLOT_SYSTEM
if(erp_toggleable_inventory.len && screenmob.hud_used && screenmob.hud_used.ERP_inventory_shown && screenmob.client?.prefs?.read_preference(/datum/preference/toggle/erp/sex_toy))
screenmob.client.screen -= erp_toggleable_inventory
//SKYRAT EDIT ADDITION END
if(hotkeybuttons.len)
screenmob.client.screen -= hotkeybuttons
if(infodisplay.len)
@@ -365,10 +354,6 @@ GLOBAL_LIST_INIT(available_erp_ui_styles, list(
screenmob.client.screen -= static_inventory
if(toggleable_inventory.len)
screenmob.client.screen -= toggleable_inventory
//SKYRAT EDIT ADDITION BEGIN - ERP_SLOT_SYSTEM
if(toggleable_inventory.len && screenmob.hud_used && screenmob.hud_used.ERP_inventory_shown && screenmob.client?.prefs?.read_preference(/datum/preference/toggle/erp/sex_toy))
screenmob.client.screen -= erp_toggleable_inventory
//SKYRAT EDIT ADDITION END
if(hotkeybuttons.len)
screenmob.client.screen -= hotkeybuttons
if(infodisplay.len)
@@ -430,21 +415,6 @@ GLOBAL_LIST_INIT(available_erp_ui_styles, list(
ui_style = new_ui_style
build_hand_slots()
//SKYRAT EDIT - ADDITION - ERP ICONS FIX
/datum/hud/proc/update_erp_ui_style(new_erp_ui_style)
// do nothing if overridden by a subtype or already on that style
if (initial(erp_ui_style) || erp_ui_style == new_erp_ui_style)
return
for(var/atom/item in erp_toggleable_inventory)
if (item.icon == erp_ui_style)
item.icon = new_erp_ui_style
erp_ui_style = new_erp_ui_style
//SKYRAT EDIT - ADDITION - ERP ICONS FIX - END
//Triggered when F12 is pressed (Unless someone changed something in the DMF)
/mob/verb/button_pressed_F12()
set name = "F12"
-143
View File
@@ -21,37 +21,6 @@
usr.hud_used.inventory_shown = TRUE
usr.client.screen += targetmob.hud_used.toggleable_inventory
//SKYRAT EDIT ADDITION BEGIN - ERP_SLOT_SYSTEM
if(usr.hud_used.inventory_shown && targetmob.hud_used)
for (var/atom/movable/screen/human/using in targetmob.hud_used.static_inventory)
if(using.screen_loc == ui_erp_inventory)
using.screen_loc = ui_erp_inventory_up // Move up ERP inventory button
for (var/atom/movable/screen/inventory/inv in targetmob.hud_used.erp_toggleable_inventory)
// Move up ERP hud slots
if(inv.screen_loc == ui_vagina_down)
inv.screen_loc = ui_vagina
if(inv.screen_loc == ui_anus_down)
inv.screen_loc = ui_anus
if(inv.screen_loc == ui_nipples_down)
inv.screen_loc = ui_nipples
if(inv.screen_loc == ui_penis_down)
inv.screen_loc = ui_penis
else
for (var/atom/movable/screen/human/using in targetmob.hud_used.static_inventory)
if(using.screen_loc == ui_erp_inventory_up)
using.screen_loc = ui_erp_inventory // Move down ERP inventory button
for (var/atom/movable/screen/inventory/inv in targetmob.hud_used.erp_toggleable_inventory)
// Move up ERP hud slots
if(inv.screen_loc == ui_vagina)
inv.screen_loc = ui_vagina_down
if(inv.screen_loc == ui_anus)
inv.screen_loc = ui_anus_down
if(inv.screen_loc == ui_nipples)
inv.screen_loc = ui_nipples_down
if(inv.screen_loc == ui_penis)
inv.screen_loc = ui_penis_down
//SKYRAT EDIT ADDITION END
targetmob.hud_used.hidden_inventory_update(usr)
/atom/movable/screen/human/equip
@@ -233,17 +202,6 @@
using.hud = src
static_inventory += using
//SKYRAT EDIT ADDITION BEGIN - ERP_SLOT_SYSTEM
using = new /atom/movable/screen/human/erp_toggle()
using.icon = ui_style
using.screen_loc = ui_erp_inventory
using.hud = src
// When creating a character, we will check if the ERP is enabled on the client, if not, then the ERP button is immediately invisible
if(!owner.client?.prefs?.read_preference(/datum/preference/toggle/erp/sex_toy))
using.invisibility = 100
static_inventory += using
//SKYRAT EDIT ADDITION END
using = new /atom/movable/screen/human/equip()
using.icon = ui_style
using.screen_loc = ui_equip_position(mymob)
@@ -305,44 +263,6 @@
inv_box.hud = src
static_inventory += inv_box
//SKYRAT EDIT ADDITION BEGIN - ERP_SLOT_SYSTEM
inv_box = new /atom/movable/screen/inventory()
inv_box.name = "vagina"
inv_box.icon = erp_ui_style
inv_box.icon_state = "vagina"
inv_box.screen_loc = ui_vagina_down
inv_box.slot_id = ITEM_SLOT_VAGINA
inv_box.hud = src
erp_toggleable_inventory += inv_box
inv_box = new /atom/movable/screen/inventory()
inv_box.name = "anus"
inv_box.icon = erp_ui_style
inv_box.icon_state = "anus"
inv_box.screen_loc = ui_anus_down
inv_box.slot_id = ITEM_SLOT_ANUS
inv_box.hud = src
erp_toggleable_inventory += inv_box
inv_box = new /atom/movable/screen/inventory()
inv_box.name = "nipples"
inv_box.icon = erp_ui_style
inv_box.icon_state = "nipples"
inv_box.screen_loc = ui_nipples_down
inv_box.slot_id = ITEM_SLOT_NIPPLES
inv_box.hud = src
erp_toggleable_inventory += inv_box
inv_box = new /atom/movable/screen/inventory()
inv_box.name = "penis"
inv_box.icon = erp_ui_style
inv_box.icon_state = "penis"
inv_box.screen_loc = ui_penis_down
inv_box.slot_id = ITEM_SLOT_PENIS
inv_box.hud = src
erp_toggleable_inventory += inv_box
//SKYRAT EDIT ADDITION END
throw_icon = new /atom/movable/screen/throw_catch()
throw_icon.icon = ui_style
throw_icon.screen_loc = ui_drop_throw
@@ -461,42 +381,6 @@
if(H.wear_neck) screenmob.client.screen -= H.wear_neck
if(H.head) screenmob.client.screen -= H.head
//SKYRAT EDIT ADDITION BEGIN - ERP_SLOT_SYSTEM
if(screenmob.hud_used.ERP_inventory_shown && screenmob.hud_used.hud_shown && H.client.prefs?.read_preference(/datum/preference/toggle/erp/sex_toy))
if(H.vagina)
// This shity code need for hanlde an moving UI stuff when default inventory expand/collapse
if(screenmob.hud_used.inventory_shown && screenmob.hud_used)
H.vagina.screen_loc = ui_vagina
else
H.vagina.screen_loc = ui_vagina_down
screenmob.client.screen += H.vagina
if(H.anus)
if(screenmob.hud_used.inventory_shown && screenmob.hud_used)
H.anus.screen_loc = ui_anus
else
H.anus.screen_loc = ui_anus_down
screenmob.client.screen += H.anus
if(H.nipples)
if(screenmob.hud_used.inventory_shown && screenmob.hud_used)
H.nipples.screen_loc = ui_nipples
else
H.nipples.screen_loc = ui_nipples_down
screenmob.client.screen += H.nipples
if(H.penis)
if(screenmob.hud_used.inventory_shown && screenmob.hud_used)
H.penis.screen_loc = ui_penis
else
H.penis.screen_loc = ui_penis_down
screenmob.client.screen += H.penis
else
if(H.vagina) screenmob.client.screen -= H.vagina
if(H.anus) screenmob.client.screen -= H.anus
if(H.nipples) screenmob.client.screen -= H.nipples
if(H.penis) screenmob.client.screen -= H.penis
//SKYRAT EDIT ADDITION END
/datum/hud/human/persistent_inventory_update(mob/viewer)
if(!mymob)
return
@@ -526,22 +410,6 @@
H.r_store.screen_loc = ui_storage2
screenmob.client.screen += H.r_store
//SKYRAT EDIT ADDITION BEGIN - ERP_SLOT_SYSTEM
if(H.client?.prefs?.read_preference(/datum/preference/toggle/erp/sex_toy))
if(H.vagina)
H.vagina.screen_loc = ui_vagina
screenmob.client.screen += H.vagina
if(H.anus)
H.anus.screen_loc = ui_anus
screenmob.client.screen += H.anus
if(H.nipples)
H.nipples.screen_loc = ui_nipples
screenmob.client.screen += H.nipples
if(H.penis)
H.penis.screen_loc = ui_penis
screenmob.client.screen += H.penis
//SKYRAT EDIT ADDITION END
else
if(H.s_store)
screenmob.client.screen -= H.s_store
@@ -556,17 +424,6 @@
if(H.r_store)
screenmob.client.screen -= H.r_store
//SKYRAT EDIT ADDITION BEGIN - ERP_SLOT_SYSTEM
if(H.vagina)
screenmob.client.screen -= H.vagina
if(H.anus)
screenmob.client.screen -= H.anus
if(H.nipples)
screenmob.client.screen -= H.nipples
if(H.penis)
screenmob.client.screen -= H.penis
//SKYRAT EDIT ADDITION END
if(hud_version != HUD_STYLE_NOHUD)
for(var/obj/item/I in H.held_items)
I.screen_loc = ui_hand_position(H.get_held_index_of_item(I))
-11
View File
@@ -876,17 +876,6 @@ GLOBAL_DATUM_INIT(welding_sparks, /mutable_appearance, mutable_appearance('icons
if(flags & ITEM_SLOT_NECK)
owner.update_worn_neck()
//SKYRAT EDIT ADDITION BEGIN - ERP_SLOT_SYSTEM
if(flags & ITEM_SLOT_VAGINA)
owner.update_inv_vagina()
if(flags & ITEM_SLOT_ANUS)
owner.update_inv_anus()
if(flags & ITEM_SLOT_NIPPLES)
owner.update_inv_nipples()
if(flags & ITEM_SLOT_PENIS)
owner.update_inv_penis()
//SKYRAT EDIT ADDITION END
///Returns the temperature of src. If you want to know if an item is hot use this proc.
/obj/item/proc/get_temperature()
return heat
@@ -24,4 +24,3 @@
/datum/preference/choiced/ui_style/apply_to_client(client/client, value)
client.mob?.hud_used?.update_ui_style(ui_style2icon(value))
client.mob?.hud_used?.update_erp_ui_style(erp_ui_style2icon(value)) //SKYRAT EDIT - ADDITION - ERP ICONS FIX
@@ -473,7 +473,7 @@
//SKYRAT EDIT ADDITION END
//SKYRAT EDIT ADDITION BEGIN - CUSTOMIZATION
for(var/genital in list("penis", "testicles", "vagina", "breasts", "anus"))
for(var/genital in possible_genitals)
if(dna.species.mutant_bodyparts[genital])
var/datum/sprite_accessory/genital/G = GLOB.sprite_accessories[genital][dna.species.mutant_bodyparts[genital][MUTANT_INDEX_NAME]]
if(G)
@@ -25,16 +25,6 @@
return r_store
if(ITEM_SLOT_SUITSTORE)
return s_store
//SKYRAT EDIT ADDITION BEGIN - ERP_SLOT_SYSTEM
if(ITEM_SLOT_VAGINA)
return vagina
if(ITEM_SLOT_ANUS)
return anus
if(ITEM_SLOT_NIPPLES)
return nipples
if(ITEM_SLOT_PENIS)
return penis
//SKYRAT EDIT ADDITION END
return ..()
/mob/living/carbon/human/get_slot_by_item(obj/item/looking_for)
@@ -175,13 +165,6 @@
if(I.flags_inv & HIDEJUMPSUIT)
update_worn_undersuit()
//SKYRAT EDIT ADDITION - ERP UPDATE
if(I.flags_inv & HIDESEXTOY)
update_inv_anus()
update_inv_vagina()
update_inv_penis()
update_inv_nipples()
//SKYRAT EDIT ADDITION END
if(wear_suit.breakouttime) //when equipping a straightjacket
ADD_TRAIT(src, TRAIT_RESTRAINED, SUIT_TRAIT)
stop_pulling() //can't pull if restrained
@@ -205,44 +188,6 @@
s_store = I
update_suit_storage()
//SKYRAT EDIT ADDITION BEGIN - ERP_SLOT_SYSTEM
if(ITEM_SLOT_PENIS)
if(src.is_bottomless())
if(penis)
return
penis = I
update_inv_penis()
else
to_chat(usr, "[src] is not bottomless, you cannot access [usr == src ? "your" : src.p_their()] penis!")
if(ITEM_SLOT_VAGINA)
if(src.is_bottomless())
if(vagina)
return
vagina = I
update_inv_vagina()
else
to_chat(usr, "[src] is not bottomless, you cannot access [usr == src ? "your" : src.p_their()] vagina!")
if(ITEM_SLOT_ANUS)
if(src.is_bottomless())
if(anus)
return
anus = I
update_inv_anus()
else
to_chat(usr, "[src] is not bottomless, you cannot access [usr == src ? "your" : src.p_their()] anus!")
if(ITEM_SLOT_NIPPLES)
if(src.is_topless())
if(nipples)
return
nipples = I
update_inv_nipples()
else
to_chat(usr, "[src] is not topless, you cannot access [usr == src ? "your" : src.p_their()] nipples!")
//SKYRAT EDIT ADDITION END
else
to_chat(src, span_danger("You are trying to equip this item to an unsupported inventory slot. Report this to a coder!"))
@@ -281,12 +226,9 @@
if(I.flags_inv & HIDEJUMPSUIT)
update_worn_undersuit()
// SKYRAT EDIT ADDITION START
// SKYRAT EDIT ADDITION START - ERP Overlays
if(I.flags_inv & HIDESEXTOY)
update_inv_anus()
update_inv_vagina()
update_inv_penis()
update_inv_nipples()
update_inv_lewd()
// SKYRAT EDIT ADDITION END
update_worn_oversuit()
@@ -358,25 +300,6 @@
if(!QDELETED(src))
update_suit_storage()
//SKYRAT EDIT ADDITION BEGIN - ERP_SLOT_SYSTEM
else if(I == vagina)
vagina = null
if(!QDELETED(src))
update_inv_vagina()
else if(I == anus)
anus = null
if(!QDELETED(src))
update_inv_anus()
else if(I == nipples)
nipples = null
if(!QDELETED(src))
update_inv_nipples()
else if(I == penis)
penis = null
if(!QDELETED(src))
update_inv_penis()
//SKYRAT EDIT ADDITION END
update_equipment_speed_mods()
// Send a signal for when we unequip an item that used to cover our feet/shoes. Used for bloody feet
@@ -987,30 +987,6 @@ GLOBAL_LIST_EMPTY(features_by_species)
return TRUE
return FALSE
//SKYRAT EDIT ADDITION BEGIN - ERP_SLOT_SYSTEM
if(ITEM_SLOT_VAGINA)
if(H.is_bottomless())
if(H.getorganslot(ORGAN_SLOT_VAGINA))
return equip_delay_self_check(I, H, bypass_equip_delay_self)
return FALSE
return FALSE
if(ITEM_SLOT_ANUS)
if(H.is_bottomless())
if(H.getorganslot(ORGAN_SLOT_ANUS))
return equip_delay_self_check(I, H, bypass_equip_delay_self)
return FALSE
if(ITEM_SLOT_NIPPLES)
if(H.is_topless())
return equip_delay_self_check(I, H, bypass_equip_delay_self)
return FALSE
if(ITEM_SLOT_PENIS)
if(H.is_bottomless())
if(H.getorganslot(ORGAN_SLOT_PENIS))
return equip_delay_self_check(I, H, bypass_equip_delay_self)
return FALSE
return FALSE
//SKYRAT EDIT ADDITION END
return FALSE //Unsupported slot
/datum/species/proc/equip_delay_self_check(obj/item/I, mob/living/carbon/human/H, bypass_equip_delay_self)
@@ -1402,6 +1378,7 @@ GLOBAL_LIST_EMPTY(features_by_species)
H.update_damage_overlays()
else//no bodypart, we deal damage with a more general method.
H.adjustBruteLoss(damage_amount)
INVOKE_ASYNC(H, /mob/living/carbon/human/.proc/adjust_pain, damage_amount) // SKYRAT EDIT ADDITION - ERP Pain
if(BURN)
H.damageoverlaytemp = 20
var/damage_amount = forced ? damage : damage * hit_percent * burnmod * H.physiology.burn_mod
@@ -1410,6 +1387,7 @@ GLOBAL_LIST_EMPTY(features_by_species)
H.update_damage_overlays()
else
H.adjustFireLoss(damage_amount)
INVOKE_ASYNC(H, /mob/living/carbon/human/.proc/adjust_pain, damage_amount) // SKYRAT EDIT ADDITION - ERP Pain
if(TOX)
var/damage_amount = forced ? damage : damage * hit_percent * H.physiology.tox_mod
H.adjustToxLoss(damage_amount)
-1
View File
@@ -42,7 +42,6 @@
if(hud_used)
hud_used.show_hud(hud_used.hud_version)
hud_used.update_ui_style(ui_style2icon(client.prefs?.read_preference(/datum/preference/choiced/ui_style)))
hud_used.update_erp_ui_style(erp_ui_style2icon(client.prefs?.read_preference(/datum/preference/choiced/ui_style))) //SKYRAT EDIT - ADDITION - ERP ICONS FIX
next_move = 1
@@ -212,14 +212,6 @@ Primarily used in reagents/reaction_agents
/// Called when an overdose starts
/datum/reagent/proc/overdose_start(mob/living/M)
///SKYRAT EDIT ADDITION: Because these chemicals shouldn't bear the same weight as normal / debatably more harmful chemicals.
if(name == "dopamine")///This one also shouldn't have any negative mood effect.
return
if(name == "succubus milk" || name == "incubus draft" || name == "Camphor" || name == "Pentacamphor")
to_chat(M, span_userdanger("You feel like you took too much [name]!"))
M.add_mood_event("[type]_overdose", /datum/mood_event/minor_overdose, name)
return
///SKYRAT EDIT END
to_chat(M, span_userdanger("You feel like you took too much of [name]!"))
M.add_mood_event("[type]_overdose", /datum/mood_event/overdose, name)
return
@@ -0,0 +1,17 @@
/datum/preference/numeric/body_size
category = PREFERENCE_CATEGORY_SECONDARY_FEATURES
savefile_identifier = PREFERENCE_CHARACTER
savefile_key = "body_size"
minimum = BODY_SIZE_MIN
maximum = BODY_SIZE_MAX
step = 0.01
/datum/preference/numeric/body_size/is_accessible(datum/preferences/preferences)
var/passed_initial_check = ..(preferences)
return passed_initial_check
/datum/preference/numeric/body_size/apply_to_human(mob/living/carbon/human/target, value)
target.dna.features["body_size"] = value
/datum/preference/numeric/body_size/create_default_value()
return BODY_SIZE_NORMAL
@@ -53,9 +53,35 @@
return FALSE
. = ..()
/datum/preference/toggle/erp/apply_to_client_updated(client/client, value)
. = ..()
var/mob/living/carbon/human/target = client?.mob
if(!value && istype(target))
target.arousal = 0
target.pain = 0
target.pleasure = 0
/datum/preference/toggle/erp/sex_toy
savefile_key = "sextoy_pref"
/datum/preference/toggle/erp/sex_toy/apply_to_client_updated(client/client, value)
apply_to_client(client, value)
if(!value)
if(ishuman(client.mob))
var/mob/living/carbon/human/target = client.mob
if(target.vagina != null)
target.dropItemToGround(target.vagina, TRUE, target.loc, TRUE, FALSE, TRUE)
if(target.anus != null)
target.dropItemToGround(target.anus, TRUE, target.loc, TRUE, FALSE, TRUE)
if(target.nipples != null)
target.dropItemToGround(target.nipples, TRUE, target.loc, TRUE, FALSE, TRUE)
if(target.penis != null)
target.dropItemToGround(target.penis, TRUE, target.loc, TRUE, FALSE, TRUE)
client.mob.hud_used.hidden_inventory_update(client.mob)
client.mob.hud_used.persistent_inventory_update(client.mob)
/datum/preference/toggle/erp/bimbofication
savefile_key = "bimbofication_pref"
@@ -77,6 +103,9 @@
/datum/preference/toggle/erp/autoemote
savefile_key = "autoemote_pref"
/datum/preference/toggle/erp/new_genitalia_growth
savefile_key = "new_genitalia_growth_pref"
/datum/preference/choiced/erp_status
category = PREFERENCE_CATEGORY_NON_CONTEXTUAL
savefile_identifier = PREFERENCE_CHARACTER
@@ -95,7 +95,7 @@
/datum/preference/choiced/genital/penis
savefile_key = "feature_penis"
relevant_mutant_bodypart = "penis"
relevant_mutant_bodypart = ORGAN_SLOT_PENIS
/datum/preference/choiced/genital/penis/create_default_value()
var/datum/sprite_accessory/genital/penis/none/default = /datum/sprite_accessory/genital/penis/none
@@ -103,7 +103,7 @@
/datum/preference/toggle/genital_skin_tone/penis
savefile_key = "penis_skin_tone"
relevant_mutant_bodypart = "penis"
relevant_mutant_bodypart = ORGAN_SLOT_PENIS
genital_pref_type = /datum/preference/choiced/genital/penis
/datum/preference/toggle/genital_skin_tone/penis/apply_to_human(mob/living/carbon/human/target, value, datum/preferences/preferences)
@@ -111,7 +111,7 @@
/datum/preference/toggle/genital_skin_color/penis
savefile_key = "penis_skin_color"
relevant_mutant_bodypart = "penis"
relevant_mutant_bodypart = ORGAN_SLOT_PENIS
genital_pref_type = /datum/preference/choiced/genital/penis
/datum/preference/toggle/genital_skin_color/penis/apply_to_human(mob/living/carbon/human/target, value, datum/preferences/preferences)
@@ -121,7 +121,7 @@
category = PREFERENCE_CATEGORY_SECONDARY_FEATURES
savefile_identifier = PREFERENCE_CHARACTER
savefile_key = "penis_length"
relevant_mutant_bodypart = "penis"
relevant_mutant_bodypart = ORGAN_SLOT_PENIS
minimum = PENIS_MIN_LENGTH
maximum = PENIS_MAX_LENGTH
@@ -141,7 +141,7 @@
category = PREFERENCE_CATEGORY_SECONDARY_FEATURES
savefile_identifier = PREFERENCE_CHARACTER
savefile_key = "penis_girth"
relevant_mutant_bodypart = "penis"
relevant_mutant_bodypart = ORGAN_SLOT_PENIS
minimum = PENIS_MIN_LENGTH
maximum = PENIS_MAX_GIRTH
@@ -159,13 +159,13 @@
/datum/preference/tri_color/genital/penis
savefile_key = "penis_color"
relevant_mutant_bodypart = "penis"
relevant_mutant_bodypart = ORGAN_SLOT_PENIS
type_to_check = /datum/preference/choiced/genital/penis
skin_color_type = /datum/preference/toggle/genital_skin_color/penis
/datum/preference/tri_bool/genital/penis
savefile_key = "penis_emissive"
relevant_mutant_bodypart = "penis"
relevant_mutant_bodypart = ORGAN_SLOT_PENIS
type_to_check = /datum/preference/choiced/genital/penis
skin_color_type = /datum/preference/toggle/genital_skin_color/penis
@@ -174,7 +174,7 @@
savefile_identifier = PREFERENCE_CHARACTER
savefile_key = "penis_taur_mode_toggle"
default_value = FALSE
relevant_mutant_bodypart = "penis"
relevant_mutant_bodypart = ORGAN_SLOT_PENIS
/datum/preference/toggle/penis_taur_mode/apply_to_human(mob/living/carbon/human/target, value, datum/preferences/preferences)
target.dna.features["penis_taur"] = value
@@ -191,7 +191,7 @@
savefile_key = "penis_sheath"
savefile_identifier = PREFERENCE_CHARACTER
category = PREFERENCE_CATEGORY_SECONDARY_FEATURES
relevant_mutant_bodypart = "penis"
relevant_mutant_bodypart = ORGAN_SLOT_PENIS
/datum/preference/choiced/penis_sheath/is_accessible(datum/preferences/preferences)
var/passed_initial_check = ..(preferences)
@@ -212,7 +212,7 @@
/datum/preference/choiced/genital/testicles
savefile_key = "feature_testicles"
relevant_mutant_bodypart = "testicles"
relevant_mutant_bodypart = ORGAN_SLOT_TESTICLES
/datum/preference/choiced/genital/testicles/create_default_value()
var/datum/sprite_accessory/genital/testicles/none/default = /datum/sprite_accessory/genital/testicles/none
@@ -220,7 +220,7 @@
/datum/preference/toggle/genital_skin_tone/testicles
savefile_key = "testicles_skin_tone"
relevant_mutant_bodypart = "testicles"
relevant_mutant_bodypart = ORGAN_SLOT_TESTICLES
genital_pref_type = /datum/preference/choiced/genital/testicles
/datum/preference/toggle/genital_skin_tone/testicles/apply_to_human(mob/living/carbon/human/target, value, datum/preferences/preferences)
@@ -228,7 +228,7 @@
/datum/preference/toggle/genital_skin_color/testicles
savefile_key = "testicles_skin_color"
relevant_mutant_bodypart = "testicles"
relevant_mutant_bodypart = ORGAN_SLOT_TESTICLES
genital_pref_type = /datum/preference/choiced/genital/testicles
/datum/preference/toggle/genital_skin_color/testicles/apply_to_human(mob/living/carbon/human/target, value, datum/preferences/preferences)
@@ -236,13 +236,13 @@
/datum/preference/tri_color/genital/testicles
savefile_key = "testicles_color"
relevant_mutant_bodypart = "testicles"
relevant_mutant_bodypart = ORGAN_SLOT_TESTICLES
type_to_check = /datum/preference/choiced/genital/testicles
skin_color_type = /datum/preference/toggle/genital_skin_color/testicles
/datum/preference/tri_bool/genital/testicles
savefile_key = "testicles_emissive"
relevant_mutant_bodypart = "testicles"
relevant_mutant_bodypart = ORGAN_SLOT_TESTICLES
type_to_check = /datum/preference/choiced/genital/testicles
skin_color_type = /datum/preference/toggle/genital_skin_color/testicles
@@ -250,7 +250,7 @@
category = PREFERENCE_CATEGORY_SECONDARY_FEATURES
savefile_identifier = PREFERENCE_CHARACTER
savefile_key = "balls_size"
relevant_mutant_bodypart = "testicles"
relevant_mutant_bodypart = ORGAN_SLOT_TESTICLES
minimum = 0
maximum = 3
@@ -270,11 +270,11 @@
/datum/preference/choiced/genital/vagina
savefile_key = "feature_vagina"
relevant_mutant_bodypart = "vagina"
relevant_mutant_bodypart = ORGAN_SLOT_VAGINA
/datum/preference/toggle/genital_skin_tone/vagina
savefile_key = "vagina_skin_tone"
relevant_mutant_bodypart = "vagina"
relevant_mutant_bodypart = ORGAN_SLOT_VAGINA
genital_pref_type = /datum/preference/choiced/genital/vagina
/datum/preference/toggle/genital_skin_tone/vagina/apply_to_human(mob/living/carbon/human/target, value, datum/preferences/preferences)
@@ -282,7 +282,7 @@
/datum/preference/toggle/genital_skin_color/vagina
savefile_key = "vagina_skin_color"
relevant_mutant_bodypart = "vagina"
relevant_mutant_bodypart = ORGAN_SLOT_VAGINA
genital_pref_type = /datum/preference/choiced/genital/vagina
/datum/preference/toggle/genital_skin_color/vagina/apply_to_human(mob/living/carbon/human/target, value, datum/preferences/preferences)
@@ -294,13 +294,13 @@
/datum/preference/tri_color/genital/vagina
savefile_key = "vagina_color"
relevant_mutant_bodypart = "vagina"
relevant_mutant_bodypart = ORGAN_SLOT_VAGINA
type_to_check = /datum/preference/choiced/genital/vagina
skin_color_type = /datum/preference/toggle/genital_skin_color/vagina
/datum/preference/tri_bool/genital/vagina
savefile_key = "vagina_emissive"
relevant_mutant_bodypart = "vagina"
relevant_mutant_bodypart = ORGAN_SLOT_VAGINA
type_to_check = /datum/preference/choiced/genital/vagina
skin_color_type = /datum/preference/toggle/genital_skin_color/vagina
@@ -308,7 +308,7 @@
/datum/preference/choiced/genital/womb
savefile_key = "feature_womb"
relevant_mutant_bodypart = "womb"
relevant_mutant_bodypart = ORGAN_SLOT_WOMB
/datum/preference/choiced/genital/womb/create_default_value()
var/datum/sprite_accessory/genital/womb/none/default = /datum/sprite_accessory/genital/womb/none
@@ -318,7 +318,7 @@
/datum/preference/choiced/genital/breasts
savefile_key = "feature_breasts"
relevant_mutant_bodypart = "breasts"
relevant_mutant_bodypart = ORGAN_SLOT_BREASTS
/datum/preference/choiced/genital/breasts/create_default_value()
var/datum/sprite_accessory/genital/breasts/none/default = /datum/sprite_accessory/genital/breasts/none
@@ -326,7 +326,7 @@
/datum/preference/toggle/genital_skin_tone/breasts
savefile_key = "breasts_skin_tone"
relevant_mutant_bodypart = "breasts"
relevant_mutant_bodypart = ORGAN_SLOT_BREASTS
genital_pref_type = /datum/preference/choiced/genital/breasts
/datum/preference/toggle/genital_skin_tone/breasts/apply_to_human(mob/living/carbon/human/target, value, datum/preferences/preferences)
@@ -334,7 +334,7 @@
/datum/preference/toggle/genital_skin_color/breasts
savefile_key = "breasts_skin_color"
relevant_mutant_bodypart = "breasts"
relevant_mutant_bodypart = ORGAN_SLOT_BREASTS
genital_pref_type = /datum/preference/choiced/genital/breasts
/datum/preference/toggle/genital_skin_color/breasts/apply_to_human(mob/living/carbon/human/target, value, datum/preferences/preferences)
@@ -342,13 +342,13 @@
/datum/preference/tri_color/genital/breasts
savefile_key = "breasts_color"
relevant_mutant_bodypart = "breasts"
relevant_mutant_bodypart = ORGAN_SLOT_BREASTS
type_to_check = /datum/preference/choiced/genital/breasts
skin_color_type = /datum/preference/toggle/genital_skin_color/breasts
/datum/preference/tri_bool/genital/breasts
savefile_key = "breasts_emissive"
relevant_mutant_bodypart = "breasts"
relevant_mutant_bodypart = ORGAN_SLOT_BREASTS
type_to_check = /datum/preference/choiced/genital/breasts
skin_color_type = /datum/preference/toggle/genital_skin_color/breasts
@@ -357,7 +357,7 @@
savefile_identifier = PREFERENCE_CHARACTER
savefile_key = "breasts_lactation_toggle"
default_value = FALSE
relevant_mutant_bodypart = "breasts"
relevant_mutant_bodypart = ORGAN_SLOT_BREASTS
/datum/preference/toggle/breasts_lactation/apply_to_human(mob/living/carbon/human/target, value, datum/preferences/preferences)
target.dna.features["breasts_lactation"] = value
@@ -368,52 +368,33 @@
var/part_enabled = is_factual_sprite_accessory(relevant_mutant_bodypart, preferences.read_preference(/datum/preference/choiced/genital/breasts))
return part_enabled && (passed_initial_check || allowed)
/datum/preference/numeric/breasts_size
/datum/preference/choiced/breasts_size
category = PREFERENCE_CATEGORY_SECONDARY_FEATURES
savefile_identifier = PREFERENCE_CHARACTER
savefile_key = "breasts_size"
relevant_mutant_bodypart = "breasts"
minimum = 0
maximum = 16
relevant_mutant_bodypart = ORGAN_SLOT_BREASTS
/datum/preference/numeric/breasts_size/is_accessible(datum/preferences/preferences)
/datum/preference/choiced/breasts_size/init_possible_values()
return GLOB.preference_breast_sizes
/datum/preference/choiced/breasts_size/is_accessible(datum/preferences/preferences)
var/passed_initial_check = ..(preferences)
var/allowed = preferences.read_preference(/datum/preference/toggle/allow_mismatched_parts)
var/part_enabled = is_factual_sprite_accessory(relevant_mutant_bodypart, preferences.read_preference(/datum/preference/choiced/genital/breasts))
return ((passed_initial_check || allowed) && part_enabled)
/datum/preference/numeric/breasts_size/apply_to_human(mob/living/carbon/human/target, value)
target.dna.features["breasts_size"] = value
/datum/preference/choiced/breasts_size/apply_to_human(mob/living/carbon/human/target, value)
target.dna.features["breasts_size"] = GLOB.breast_size_to_number[value]
/datum/preference/numeric/breasts_size/create_default_value()
return 4
/datum/preference/choiced/breasts_size/create_default_value()
return BREAST_SIZE_C
// ANUS
/datum/preference/choiced/genital/anus
savefile_key = "feature_anus"
relevant_mutant_bodypart = "anus"
relevant_mutant_bodypart = ORGAN_SLOT_ANUS
/datum/preference/choiced/genital/anus/create_default_value()
var/datum/sprite_accessory/genital/anus/none/default = /datum/sprite_accessory/genital/anus/none
return initial(default.name)
// OTHER
/datum/preference/numeric/body_size
category = PREFERENCE_CATEGORY_SECONDARY_FEATURES
savefile_identifier = PREFERENCE_CHARACTER
savefile_key = "body_size"
minimum = BODY_SIZE_MIN
maximum = BODY_SIZE_MAX
step = 0.01
/datum/preference/numeric/body_size/is_accessible(datum/preferences/preferences)
var/passed_initial_check = ..(preferences)
return passed_initial_check
/datum/preference/numeric/body_size/apply_to_human(mob/living/carbon/human/target, value)
target.dna.features["body_size"] = value
/datum/preference/numeric/body_size/create_default_value()
return BODY_SIZE_NORMAL
@@ -3,7 +3,7 @@
* You can't really use the non-modular version, least you eventually want asinine merge
* conflicts and/or potentially disastrous issues to arise, so here's your own.
*/
#define MODULAR_SAVEFILE_VERSION_MAX 1
#define MODULAR_SAVEFILE_VERSION_MAX 2
#define MODULAR_SAVEFILE_UP_TO_DATE -1
@@ -110,6 +110,13 @@
for(var/pref_type in subtypesof(/datum/preference/toggle/genital_skin_tone))
write_preference(GLOB.preference_entries[pref_type], TRUE)
if(current_version < 2)
var/list/old_breast_prefs
READ_FILE(save["breasts_size"], old_breast_prefs)
if(old_breast_prefs) // Can't be too careful
// You weren't meant to be able to pick sizes over this anyways.
write_preference(GLOB.preference_entries[/datum/preference/choiced/breasts_size], min(GLOB.breast_size_translation["[old_breast_prefs]"], 10))
/datum/preferences/proc/check_migration()
if(!tgui_prefs_migration)
to_chat(parent, examine_block(span_redtext("CRITICAL FAILURE IN PREFERENCE MIGRATION, REPORT THIS IMMEDIATELY.")))
@@ -1,67 +1,115 @@
//DO NOT CHANGE THOSE LISTS UNLESS YOU KNOW WHAT YOURE DOING (will mess savefiles)
GLOBAL_LIST_INIT(breasts_size_translation, list("0" = "Flatchested",
"1" = "A",
"2" = "B",
"3" = "C",
"4" = "D",
"5" = "E",
"6" = "F",
"7" = "G",
"8" = "H",
"9" = "I",
"10" = "J",
"11" = "K",
"12" = "L",
"13" = "M",
"14" = "N",
"15" = "O",
"16" = "P",
))
GLOBAL_LIST_INIT(breast_size_translation, list(
"0" = BREAST_SIZE_FLATCHESTED,
"1" = BREAST_SIZE_A,
"2" = BREAST_SIZE_B,
"3" = BREAST_SIZE_C,
"4" = BREAST_SIZE_D,
"5" = BREAST_SIZE_E,
"6" = BREAST_SIZE_F,
"7" = BREAST_SIZE_G,
"8" = BREAST_SIZE_H,
"9" = BREAST_SIZE_I,
"10" = BREAST_SIZE_J,
"11" = BREAST_SIZE_K, // Succubus milk moment.
"12" = BREAST_SIZE_L,
"13" = BREAST_SIZE_M,
"14" = BREAST_SIZE_N,
"15" = BREAST_SIZE_O,
"16" = BREAST_SIZE_P,
))
GLOBAL_LIST_INIT(balls_size_translation, list("0" = "Small",
"1" = "Average",
"2" = "Big",
"3" = "Enormous"
))
GLOBAL_LIST_INIT(breast_size_to_number, list(
BREAST_SIZE_FLATCHESTED = 0,
BREAST_SIZE_A = 1,
BREAST_SIZE_B = 2,
BREAST_SIZE_C = 3,
BREAST_SIZE_D = 4,
BREAST_SIZE_E = 5,
BREAST_SIZE_F = 6,
BREAST_SIZE_G = 7,
BREAST_SIZE_H = 8,
BREAST_SIZE_I = 9,
BREAST_SIZE_J = 10,
BREAST_SIZE_K = 11, // Succubus milk moment.
BREAST_SIZE_L = 12,
BREAST_SIZE_M = 13,
BREAST_SIZE_N = 14,
BREAST_SIZE_O = 15,
BREAST_SIZE_P = 16,
))
GLOBAL_LIST_INIT(marking_zone_to_bitflag, list(BODY_ZONE_HEAD = HEAD,
BODY_ZONE_CHEST = CHEST,
BODY_ZONE_L_LEG = LEG_LEFT,
BODY_ZONE_R_LEG = LEG_RIGHT,
BODY_ZONE_L_ARM = ARM_LEFT,
BODY_ZONE_R_ARM = ARM_RIGHT,
BODY_ZONE_PRECISE_L_HAND = HAND_LEFT,
BODY_ZONE_PRECISE_R_HAND = HAND_RIGHT
))
GLOBAL_LIST_INIT(balls_size_translation, list(
"0" = "Small",
"1" = "Average",
"2" = "Big",
"3" = "Enormous"
))
//GLOBAL_LIST_INIT(marking_zones, list("Head","Chest","Left Leg","Right Leg","Left Arm","Right Arm","Left Hand","Right Hand"))
GLOBAL_LIST_INIT(marking_zone_to_bitflag, list(
BODY_ZONE_HEAD = HEAD,
BODY_ZONE_CHEST = CHEST,
BODY_ZONE_L_LEG = LEG_LEFT,
BODY_ZONE_R_LEG = LEG_RIGHT,
BODY_ZONE_L_ARM = ARM_LEFT,
BODY_ZONE_R_ARM = ARM_RIGHT,
BODY_ZONE_PRECISE_L_HAND = HAND_LEFT,
BODY_ZONE_PRECISE_R_HAND = HAND_RIGHT
))
GLOBAL_LIST_INIT(marking_zones, list(BODY_ZONE_HEAD,BODY_ZONE_CHEST,BODY_ZONE_L_LEG,BODY_ZONE_R_LEG,BODY_ZONE_L_ARM,BODY_ZONE_R_ARM,BODY_ZONE_PRECISE_L_HAND,BODY_ZONE_PRECISE_R_HAND))
GLOBAL_LIST_INIT(marking_zones, list(
BODY_ZONE_HEAD,
BODY_ZONE_CHEST,
BODY_ZONE_L_LEG,
BODY_ZONE_R_LEG,
BODY_ZONE_L_ARM,
BODY_ZONE_R_ARM,
BODY_ZONE_PRECISE_L_HAND,
BODY_ZONE_PRECISE_R_HAND,
))
///Those are the values available from prefs
GLOBAL_LIST_INIT(preference_breast_sizes, list("Flatchested","A","B","C","D","E","F","G","H","I","J"))
GLOBAL_LIST_INIT(preference_breast_sizes, list(
BREAST_SIZE_FLATCHESTED,
BREAST_SIZE_A,
BREAST_SIZE_B,
BREAST_SIZE_C,
BREAST_SIZE_D,
BREAST_SIZE_E,
BREAST_SIZE_F,
BREAST_SIZE_G,
BREAST_SIZE_H,
BREAST_SIZE_I,
BREAST_SIZE_J,
))
GLOBAL_LIST_INIT(preference_balls_sizes, list("Small","Average","Big","Enormous"))
GLOBAL_LIST_INIT(preference_balls_sizes, list(
"Small",
"Average",
"Big",
"Enormous",
))
GLOBAL_LIST_INIT(robotic_styles_list, list("None" = "None",
"Surplus" = 'icons/mob/augmentation/surplus_augments.dmi',
"Cyborg" = 'icons/mob/augmentation/augments.dmi',
"Engineering" = 'icons/mob/augmentation/augments_engineer.dmi',
"Mining" = 'icons/mob/augmentation/augments_mining.dmi',
"Security" = 'icons/mob/augmentation/augments_security.dmi',
"Morpheus Cyberkinetics" = 'modular_skyrat/master_files/icons/mob/augmentation/mcgipc.dmi',
"Bishop Cyberkinetics" = 'modular_skyrat/master_files/icons/mob/augmentation/bshipc.dmi',
"Bishop Cyberkinetics 2.0" = 'modular_skyrat/master_files/icons/mob/augmentation/bs2ipc.dmi',
"Hephaestus Industries" = 'modular_skyrat/master_files/icons/mob/augmentation/hsiipc.dmi',
"Hephaestus Industries 2.0" = 'modular_skyrat/master_files/icons/mob/augmentation/hi2ipc.dmi',
"Shellguard Munitions Standard Series" = 'modular_skyrat/master_files/icons/mob/augmentation/sgmipc.dmi',
"Ward-Takahashi Manufacturing" = 'modular_skyrat/master_files/icons/mob/augmentation/wtmipc.dmi',
"Xion Manufacturing Group" = 'modular_skyrat/master_files/icons/mob/augmentation/xmgipc.dmi',
"Xion Manufacturing Group 2.0" = 'modular_skyrat/master_files/icons/mob/augmentation/xm2ipc.dmi',
"Zeng-Hu Pharmaceuticals" = 'modular_skyrat/master_files/icons/mob/augmentation/zhpipc.dmi'
))
GLOBAL_LIST_INIT(robotic_styles_list, list(
"None" = "None",
"Surplus" = 'icons/mob/augmentation/surplus_augments.dmi',
"Cyborg" = 'icons/mob/augmentation/augments.dmi',
"Engineering" = 'icons/mob/augmentation/augments_engineer.dmi',
"Mining" = 'icons/mob/augmentation/augments_mining.dmi',
"Security" = 'icons/mob/augmentation/augments_security.dmi',
"Morpheus Cyberkinetics" = 'modular_skyrat/master_files/icons/mob/augmentation/mcgipc.dmi',
"Bishop Cyberkinetics" = 'modular_skyrat/master_files/icons/mob/augmentation/bshipc.dmi',
"Bishop Cyberkinetics 2.0" = 'modular_skyrat/master_files/icons/mob/augmentation/bs2ipc.dmi',
"Hephaestus Industries" = 'modular_skyrat/master_files/icons/mob/augmentation/hsiipc.dmi',
"Hephaestus Industries 2.0" = 'modular_skyrat/master_files/icons/mob/augmentation/hi2ipc.dmi',
"Shellguard Munitions Standard Series" = 'modular_skyrat/master_files/icons/mob/augmentation/sgmipc.dmi',
"Ward-Takahashi Manufacturing" = 'modular_skyrat/master_files/icons/mob/augmentation/wtmipc.dmi',
"Xion Manufacturing Group" = 'modular_skyrat/master_files/icons/mob/augmentation/xmgipc.dmi',
"Xion Manufacturing Group 2.0" = 'modular_skyrat/master_files/icons/mob/augmentation/xm2ipc.dmi',
"Zeng-Hu Pharmaceuticals" = 'modular_skyrat/master_files/icons/mob/augmentation/zhpipc.dmi'
))
//ghoul colors
GLOBAL_LIST_INIT(color_list_ghoul, list( \
@@ -35,7 +35,7 @@
icon = 'modular_skyrat/master_files/icons/mob/sprite_accessory/genitals/penis_onmob.dmi'
organ_type = /obj/item/organ/external/genital/penis
associated_organ_slot = ORGAN_SLOT_PENIS
key = "penis"
key = ORGAN_SLOT_PENIS
color_src = USE_MATRIXED_COLORS
always_color_customizable = TRUE
center = TRUE
@@ -117,7 +117,7 @@
icon = 'modular_skyrat/master_files/icons/mob/sprite_accessory/genitals/testicles_onmob.dmi'
organ_type = /obj/item/organ/external/genital/testicles
associated_organ_slot = ORGAN_SLOT_TESTICLES
key = "testicles"
key = ORGAN_SLOT_TESTICLES
always_color_customizable = TRUE
special_icon_case = TRUE
special_x_dimension = TRUE
@@ -168,7 +168,7 @@
icon = 'modular_skyrat/master_files/icons/mob/sprite_accessory/genitals/vagina_onmob.dmi'
organ_type = /obj/item/organ/external/genital/vagina
associated_organ_slot = ORGAN_SLOT_VAGINA
key = "vagina"
key = ORGAN_SLOT_VAGINA
always_color_customizable = TRUE
default_color = "#FFCCCC"
relevent_layers = list(BODY_FRONT_LAYER)
@@ -224,7 +224,7 @@
/datum/sprite_accessory/genital/womb
organ_type = /obj/item/organ/external/genital/womb
associated_organ_slot = ORGAN_SLOT_WOMB
key = "womb"
key = ORGAN_SLOT_WOMB
genetic = TRUE
/datum/sprite_accessory/genital/womb/none
@@ -241,7 +241,7 @@
/datum/sprite_accessory/genital/anus
organ_type = /obj/item/organ/external/genital/anus
associated_organ_slot = ORGAN_SLOT_ANUS
key = "anus"
key = ORGAN_SLOT_ANUS
genetic = TRUE
/datum/sprite_accessory/genital/anus/is_hidden(mob/living/carbon/human/owner, obj/item/bodypart/bodypart)
@@ -264,7 +264,7 @@
icon = 'modular_skyrat/master_files/icons/mob/sprite_accessory/genitals/breasts_onmob.dmi'
organ_type = /obj/item/organ/external/genital/breasts
associated_organ_slot = ORGAN_SLOT_BREASTS
key = "breasts"
key = ORGAN_SLOT_BREASTS
always_color_customizable = TRUE
default_color = DEFAULT_SKIN_OR_PRIMARY
relevent_layers = list(BODY_BEHIND_LAYER, BODY_FRONT_LAYER)
@@ -1,3 +1,6 @@
/mob/living/carbon/human
var/static/list/possible_genitals = list(ORGAN_SLOT_PENIS, ORGAN_SLOT_TESTICLES, ORGAN_SLOT_VAGINA, ORGAN_SLOT_BREASTS, ORGAN_SLOT_ANUS)
/mob/living/carbon/human/Topic(href, href_list)
. = ..()
@@ -5,7 +8,7 @@
switch(href_list["lookup_info"])
if("genitals")
var/list/line = list()
for(var/genital in list("penis", "testicles", "vagina", "breasts", "anus"))
for(var/genital in possible_genitals)
if(!dna.species.mutant_bodyparts[genital])
continue
var/datum/sprite_accessory/genital/G = GLOB.sprite_accessories[genital][dna.species.mutant_bodyparts[genital][MUTANT_INDEX_NAME]]
@@ -262,12 +262,12 @@ GLOBAL_LIST_EMPTY(customizable_races)
/datum/species/New()
. = ..()
if(can_have_genitals)
default_mutant_bodyparts["vagina"] = "None"
default_mutant_bodyparts["womb"] = "None"
default_mutant_bodyparts["testicles"] = "None"
default_mutant_bodyparts["breasts"] = "None"
default_mutant_bodyparts["anus"] = "None"
default_mutant_bodyparts["penis"] = "None"
default_mutant_bodyparts[ORGAN_SLOT_VAGINA] = "None"
default_mutant_bodyparts[ORGAN_SLOT_WOMB] = "None"
default_mutant_bodyparts[ORGAN_SLOT_TESTICLES] = "None"
default_mutant_bodyparts[ORGAN_SLOT_BREASTS] = "None"
default_mutant_bodyparts[ORGAN_SLOT_ANUS] = "None"
default_mutant_bodyparts[ORGAN_SLOT_PENIS] = "None"
/datum/species/dullahan
mutant_bodyparts = list()
@@ -92,7 +92,7 @@
icon = 'modular_skyrat/master_files/icons/obj/genitals/penis.dmi'
zone = BODY_ZONE_PRECISE_GROIN
slot = ORGAN_SLOT_PENIS
mutantpart_key = "penis"
mutantpart_key = ORGAN_SLOT_PENIS
mutantpart_info = list(MUTANT_INDEX_NAME = "Human", MUTANT_INDEX_COLOR_LIST = list("#FFEEBB"))
drop_when_organ_spilling = FALSE
var/girth = 9
@@ -181,7 +181,7 @@
uses_skintones = accessory.has_skintone_shading
/obj/item/organ/external/genital/penis/get_global_feature_list()
return GLOB.sprite_accessories["penis"]
return GLOB.sprite_accessories[ORGAN_SLOT_PENIS]
/obj/item/organ/external/genital/testicles
@@ -189,7 +189,7 @@
desc = "A male reproductive organ."
icon_state = "testicles"
icon = 'modular_skyrat/master_files/icons/obj/genitals/testicles.dmi'
mutantpart_key = "testicles"
mutantpart_key = ORGAN_SLOT_TESTICLES
mutantpart_info = list(MUTANT_INDEX_NAME = "Pair", MUTANT_INDEX_COLOR_LIST = list("#FFEEBB"))
zone = BODY_ZONE_PRECISE_GROIN
slot = ORGAN_SLOT_TESTICLES
@@ -228,7 +228,7 @@
return passed_string
/obj/item/organ/external/genital/testicles/get_global_feature_list()
return GLOB.sprite_accessories["testicles"]
return GLOB.sprite_accessories[ORGAN_SLOT_TESTICLES]
/obj/item/organ/external/genital/testicles/proc/balls_size_to_description(number)
@@ -236,7 +236,7 @@
number = 0
var/returned = GLOB.balls_size_translation["[number]"]
if(!returned)
returned = "beyond measurement"
returned = BREAST_SIZE_BEYOND_MEASUREMENT
return returned
/obj/item/organ/external/genital/testicles/proc/balls_description_to_size(cup)
@@ -250,7 +250,7 @@
name = "vagina"
icon = 'modular_skyrat/master_files/icons/obj/genitals/vagina.dmi'
icon_state = "vagina"
mutantpart_key = "vagina"
mutantpart_key = ORGAN_SLOT_VAGINA
mutantpart_info = list(MUTANT_INDEX_NAME = "Human", MUTANT_INDEX_COLOR_LIST = list("#FFEEBB"))
zone = BODY_ZONE_PRECISE_GROIN
slot = ORGAN_SLOT_VAGINA
@@ -285,7 +285,7 @@
uses_skintones = accessory.has_skintone_shading
/obj/item/organ/external/genital/vagina/get_global_feature_list()
return GLOB.sprite_accessories["vagina"]
return GLOB.sprite_accessories[ORGAN_SLOT_VAGINA]
/obj/item/organ/external/genital/womb
@@ -293,7 +293,7 @@
desc = "A female reproductive organ."
icon = 'modular_skyrat/master_files/icons/obj/genitals/vagina.dmi'
icon_state = "womb"
mutantpart_key = "womb"
mutantpart_key = ORGAN_SLOT_WOMB
mutantpart_info = list(MUTANT_INDEX_NAME = "Normal", MUTANT_INDEX_COLOR_LIST = list("FFEEBB"))
zone = BODY_ZONE_PRECISE_GROIN
slot = ORGAN_SLOT_WOMB
@@ -303,7 +303,7 @@
drop_when_organ_spilling = FALSE
/obj/item/organ/external/genital/womb/get_global_feature_list()
return GLOB.sprite_accessories["womb"]
return GLOB.sprite_accessories[ORGAN_SLOT_WOMB]
/obj/item/organ/external/genital/anus
@@ -311,7 +311,7 @@
desc = "What do you want me to tell you?"
icon = 'modular_skyrat/master_files/icons/obj/genitals/anus.dmi'
icon_state = "anus"
mutantpart_key = "anus"
mutantpart_key = ORGAN_SLOT_ANUS
mutantpart_info = list(MUTANT_INDEX_NAME = "Normal", MUTANT_INDEX_COLOR_LIST = list("FEB"))
zone = BODY_ZONE_PRECISE_GROIN
slot = ORGAN_SLOT_ANUS
@@ -327,7 +327,7 @@
return returned_string
/obj/item/organ/external/genital/anus/get_global_feature_list()
return GLOB.sprite_accessories["anus"]
return GLOB.sprite_accessories[ORGAN_SLOT_ANUS]
/obj/item/organ/external/genital/breasts
@@ -336,7 +336,7 @@
icon_state = "breasts"
icon = 'modular_skyrat/master_files/icons/obj/genitals/breasts.dmi'
genital_type = "pair"
mutantpart_key = "breasts"
mutantpart_key = ORGAN_SLOT_BREASTS
mutantpart_info = list(MUTANT_INDEX_NAME = "Pair", MUTANT_INDEX_COLOR_LIST = list("#FFEEBB"))
zone = BODY_ZONE_CHEST
slot = ORGAN_SLOT_BREASTS
@@ -349,9 +349,9 @@
var/size_description
var/translation = breasts_size_to_cup(genital_size)
switch(translation)
if("Flatchested")
if(BREAST_SIZE_FLATCHESTED)
size_description = " They are small and flat, however."
if("beyond measurement")
if(BREAST_SIZE_BEYOND_MEASUREMENT)
size_description = " Their size is enormous, you estimate they're around [genital_size] inches in diameter."
else
size_description = " You estimate they are [translation]-cups."
@@ -400,19 +400,19 @@
uses_skintones = accessory.has_skintone_shading
/obj/item/organ/external/genital/breasts/get_global_feature_list()
return GLOB.sprite_accessories["breasts"]
return GLOB.sprite_accessories[ORGAN_SLOT_BREASTS]
/obj/item/organ/external/genital/breasts/proc/breasts_size_to_cup(number)
if(number < 0)
number = 0
var/returned = GLOB.breasts_size_translation["[number]"]
var/returned = GLOB.breast_size_translation["[number]"]
if(!returned)
returned = "beyond measurement"
returned = BREAST_SIZE_BEYOND_MEASUREMENT
return returned
/obj/item/organ/external/genital/breasts/proc/breasts_cup_to_size(cup)
for(var/key in GLOB.breasts_size_translation)
if(GLOB.breasts_size_translation[key] == cup)
for(var/key in GLOB.breast_size_translation)
if(GLOB.breast_size_translation[key] == cup)
return text2num(key)
return 0
@@ -505,9 +505,9 @@
log_data += "Sex: [iterating_human.gender]"
log_data += "Age: [iterating_human.age]"
log_data += "Body Type: [iterating_human.physique]"
log_data += "Penis: [iterating_human.dna.mutant_bodyparts["penis"]["name"]]"
log_data += "Vagina: [iterating_human.dna.mutant_bodyparts["vagina"]["name"]]"
log_data += "Breasts: [iterating_human.dna.mutant_bodyparts["breasts"]["name"]]"
log_data += "Penis: [iterating_human.dna.mutant_bodyparts[ORGAN_SLOT_PENIS]["name"]]"
log_data += "Vagina: [iterating_human.dna.mutant_bodyparts[ORGAN_SLOT_VAGINA]["name"]]"
log_data += "Breasts: [iterating_human.dna.mutant_bodyparts[ORGAN_SLOT_BREASTS]["name"]]"
log_data += "Body size: [iterating_human.dna.features["body_size"]]"
log_data += "END ENTRY"
@@ -61,7 +61,6 @@
return TRUE
/// UI Control
/datum/component/interactable/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
@@ -95,8 +94,39 @@
data["self"] = self.name
data["block_interact"] = interact_next >= world.time
data["interactions"] = categories
var/list/parts = list()
if(ishuman(user) && can_lewd_strip(user, self))
if(self.client?.prefs?.read_preference(/datum/preference/toggle/erp/sex_toy))
if(self.has_vagina())
parts += list(generate_strip_entry(ORGAN_SLOT_VAGINA, self, user, self.vagina))
if(self.has_penis())
parts += list(generate_strip_entry(ORGAN_SLOT_PENIS, self, user, self.penis))
if(self.has_anus())
parts += list(generate_strip_entry(ORGAN_SLOT_ANUS, self, user, self.anus))
parts += list(generate_strip_entry(ORGAN_SLOT_NIPPLES, self, user, self.nipples))
data["lewd_slots"] = parts
return data
/**
* Takes the organ slot name, along with a target and source, along with the item on the target that the source can potentially interact with.
* If the source can't interact with said slot, or there is no item in the first place, it'll set the icon to null to indicate that TGUI should put a placeholder sprite.
*
* Arguments:
* * name - The name of slot to check and return inside the generated list.
* * target - The mob that's being interacted with.
* * source - The mob that's interacting.
* * item - The item that's currently inside said slot. Can be null.
*/
/datum/component/interactable/proc/generate_strip_entry(name, mob/living/carbon/human/target, mob/living/carbon/human/source, obj/item/clothing/sextoy/item)
return list(
"name" = name,
"img" = (item && can_lewd_strip(source, target, name)) ? icon2base64(icon(item.icon, item.icon_state, SOUTH, 1)) : null
)
/datum/component/interactable/ui_act(action, list/params)
. = ..()
if(.)
@@ -113,4 +143,85 @@
interact_next = interaction_component.interact_last + INTERACTION_COOLDOWN
interaction_component.interact_next = interact_next
return TRUE
if(params["item_slot"])
// This code should be easy enough to follow... I hope.
var/item_index = params["item_slot"]
var/mob/living/carbon/human/source = locate(params["userref"])
var/mob/living/carbon/human/target = locate(params["selfref"])
var/obj/item/new_item = source.get_active_held_item()
var/obj/item/existing_item = target.vars[item_index]
if(!existing_item && !new_item)
source.show_message(span_warning("No item to insert or remove!"))
return
if(!existing_item && !istype(new_item, /obj/item/clothing/sextoy))
source.show_message(span_warning("The item you're holding is not a toy!"))
return
if(can_lewd_strip(source, target, item_index) && is_toy_compatible(new_item, item_index))
var/internal = (item_index in list(ORGAN_SLOT_VAGINA, ORGAN_SLOT_ANUS))
var/insert_or_attach = internal ? "insert" : "attach"
var/into_or_onto = internal ? "into" : "onto"
if(existing_item)
source.visible_message(span_purple("[source.name] starts trying to remove something from [target.name]'s [item_index]."), span_purple("You start to remove [existing_item.name] from [target.name]'s [item_index]."), span_purple("You hear someone trying to remove something from someone nearby."), vision_distance = 1, ignored_mobs = list(target))
else if (new_item)
source.visible_message(span_purple("[source.name] starts trying to [insert_or_attach] the [new_item.name] [into_or_onto] [target.name]'s [item_index]."), span_purple("You start to [insert_or_attach] the [new_item.name] [into_or_onto] [target.name]'s [item_index]."), span_purple("You hear someone trying to [insert_or_attach] something [into_or_onto] someone nearby."), vision_distance = 1, ignored_mobs = list(target))
if (source != target)
target.show_message(span_warning("[source.name] is trying to [existing_item ? "remove the [existing_item.name] [internal ? "in" : "on"]" : new_item ? "is trying to [insert_or_attach] the [new_item.name] [into_or_onto]" : span_alert("What the fuck, impossible condition? interaction_component.dm!")] your [item_index]!"))
if(do_after(
source,
5 SECONDS,
target,
interaction_key = "interation_[item_index]"
) && can_lewd_strip(source, target, item_index))
if(existing_item)
source.visible_message(span_purple("[source.name] removes [existing_item.name] from [target.name]'s [item_index]."), span_purple("You remove [existing_item.name] from [target.name]'s [item_index]."), span_purple("You hear someone remove something from someone nearby."), vision_distance = 1)
target.dropItemToGround(existing_item, force = TRUE) // Force is true, cause nodrop shouldn't affect lewd items.
target.vars[item_index] = null
else if (new_item)
source.visible_message(span_purple("[source.name] [internal ? "inserts" : "attaches"] the [new_item.name] [into_or_onto] [target.name]'s [item_index]."), span_purple("You [insert_or_attach] the [new_item.name] [into_or_onto] [target.name]'s [item_index]."), span_purple("You hear someone [insert_or_attach] something [into_or_onto] someone nearby."), vision_distance = 1)
target.vars[item_index] = new_item
new_item.forceMove(target)
target.update_inv_lewd()
else
source.show_message(span_warning("Failed to adjust [target.name]'s toys!"))
return TRUE
message_admins("Unhandled interaction '[params["interaction"]]'. Inform coders.")
/// Checks if the target has ERP toys enabled, and can be logially reached by the user.
/datum/component/interactable/proc/can_lewd_strip(mob/living/carbon/human/source, mob/living/carbon/human/target, slot_index)
if(!target.client?.prefs?.read_preference(/datum/preference/toggle/erp/sex_toy))
return FALSE
if(!(source.loc == target.loc || source.Adjacent(target)))
return FALSE
if(!source.has_arms())
return FALSE
if(!slot_index) // This condition is for the UI to decide if the button is shown at all. Slot index should never be null otherwise.
return TRUE
if(slot_index == ORGAN_SLOT_NIPPLES && !target.is_topless())
return FALSE
return target.is_bottomless()
/// Decides if a player should be able to insert or remove an item from a provided lewd slot_index.
/datum/component/interactable/proc/is_toy_compatible(obj/item/clothing/sextoy/item, slot_index)
if(!item) // Used for UI code, should never be actually null during actual logic code.
return TRUE
switch(slot_index)
if(ORGAN_SLOT_VAGINA)
return item.lewd_slot_flags & LEWD_SLOT_VAGINA
if(ORGAN_SLOT_PENIS)
return item.lewd_slot_flags & LEWD_SLOT_PENIS
if(ORGAN_SLOT_ANUS)
return item.lewd_slot_flags & LEWD_SLOT_ANUS
if(ORGAN_SLOT_NIPPLES)
return item.lewd_slot_flags & LEWD_SLOT_NIPPLES
else
return FALSE
@@ -119,12 +119,12 @@ GLOBAL_LIST_EMPTY_TYPED(interaction_instances, /datum/interaction)
SEND_SOUND(sound_cache, mob)
if(lewd)
user.adjustPleasure(user_pleasure)
user.adjustArousal(user_arousal)
user.adjustPain(user_pain)
target.adjustPleasure(target_pleasure)
target.adjustArousal(target_arousal)
target.adjustPain(target_pain)
user.adjust_pleasure(user_pleasure)
user.adjust_arousal(user_arousal)
user.adjust_pain(user_pain)
target.adjust_pleasure(target_pleasure)
target.adjust_arousal(target_arousal)
target.adjust_pain(target_pain)
/datum/interaction/proc/load_from_json(path)
var/fpath = path
@@ -1,880 +0,0 @@
#define AROUS_SYS_LITTLE 30
#define AROUS_SYS_STRONG 70
#define AROUS_SYS_READYTOCUM 90
#define PAIN_SYS_LIMIT 50
#define PLEAS_SYS_EDGE 85
#define CUM_MALE 1
#define CUM_FEMALE 2
// #define ITEM_SLOT_PENIS (1<<20)
#define TRAIT_MASOCHISM "masochism"
#define TRAIT_SADISM "sadism"
#define TRAIT_NEVERBONER "neverboner"
#define TRAIT_BIMBO "bimbo"
#define TRAIT_RIGGER "rigger"
#define TRAIT_ROPEBUNNY "rope bunny"
#define APHRO_TRAIT "aphro" ///traits gained by brain traumas, can be removed if the brain trauma is gone
#define LEWDQUIRK_TRAIT "lewdquirks" ///traits gained by quirks, cannot be removed unless the quirk itself is gone
#define LEWDCHEM_TRAIT "lewdchem" ///traits gained by chemicals, you get the idea
#define STRAPON_TRAIT "strapon"
/*
* DECALS
*/
/obj/effect/decal/cleanable/cum
name = "cum"
desc = "Ew... Gross."
icon = 'modular_skyrat/modules/modular_items/lewd_items/icons/obj/lewd_decals/lewd_decals.dmi'
icon_state = "cum_1"
random_icon_states = list("cum_1", "cum_2", "cum_3", "cum_4")
beauty = -50
/obj/effect/decal/cleanable/cum/femcum
name = "female cum"
desc = "Uhh... Someone had fun..."
icon = 'modular_skyrat/modules/modular_items/lewd_items/icons/obj/lewd_decals/lewd_decals.dmi'
icon_state = "femcum_1"
random_icon_states = list("femcum_1", "femcum_2", "femcum_3", "femcum_4")
beauty = -50
/*
* REAGENTS
*/
/datum/reagent/consumable/girlcum
name = "girlcum"
description = "Uhh... Someone had fun."
taste_description = "astringent and sweetish"
color = "#ffffffb0"
glass_name = "glass of girlcum"
glass_desc = "A strange white liquid... Ew!"
reagent_state = LIQUID
shot_glass_icon_state = "shotglasswhite"
/datum/reagent/consumable/cum
name = "cum"
description = "A fluid secreted by the sexual organs of many species."
taste_description = "musky and salty"
color = "#ffffffff"
glass_name = "glass of cum"
glass_desc = "O-oh, my...~"
reagent_state = LIQUID
shot_glass_icon_state = "shotglasswhite"
/datum/reagent/consumable/breast_milk
name = "breast milk"
description = "This looks familiar... Wait, it's milk!"
taste_description = "warm and creamy"
color = "#ffffffff"
glass_icon_state = "glass_white"
glass_name = "glass of breast milk"
glass_desc = "almost like normal milk."
reagent_state = LIQUID
/datum/reagent/drug/dopamine
name = "dopamine"
description = "Pure happiness"
taste_description = "passion fruit, banana and hint of apple"
color = "#97ffee"
glass_name = "dopamine"
glass_desc = "A deliciously flavored reagent. You feel happy even looking at it."
reagent_state = LIQUID
overdose_threshold = 10
/datum/reagent/drug/dopamine/on_mob_add(mob/living/carbon/human/affected_mob)
affected_mob.add_mood_event("[type]_start", /datum/mood_event/orgasm, name)
..()
/datum/reagent/drug/dopamine/on_mob_life(mob/living/carbon/affected_mob, delta_time, times_fired)
affected_mob.set_drugginess(2 SECONDS * REM * delta_time)
if(prob(7))
affected_mob.try_lewd_autoemote(pick("shaking", "moan"))
..()
/datum/reagent/drug/dopamine/overdose_start(mob/living/carbon/human/human_mob)
if(HAS_TRAIT(human_mob, TRAIT_BIMBO))
return
to_chat(human_mob, span_userdanger("You don't want to cum anymore!"))
human_mob.add_mood_event("[type]_overdose", /datum/mood_event/overgasm, name)
/datum/reagent/drug/dopamine/overdose_process(mob/living/carbon/human/affected_mob)
affected_mob.adjustArousal(0.5)
affected_mob.adjustPleasure(0.3)
affected_mob.adjustPain(-0.5)
if(prob(2))
affected_mob.try_lewd_autoemote(pick("moan", "twitch_s"))
return
/*
* INITIALISE
*/
/obj/item/organ/external/genital
var/datum/reagents/internal_fluids
var/list/contained_item
var/obj/item/inserted_item //Used for toys
/obj/item/organ/external/genital/breasts/build_from_dna(datum/dna/DNA, associated_key)
. = ..()
var/breasts_count = 0
var/size = 0.5
if(DNA.features["breasts_size"] > 0)
size = DNA.features["breasts_size"]
switch(genital_type)
if("pair")
breasts_count = 2
if("quad")
breasts_count = 2.5
if("sextuple")
breasts_count = 3
internal_fluids = new /datum/reagents(size * breasts_count * 60)
/obj/item/organ/external/genital/testicles/build_from_dna(datum/dna/DNA, associated_key)
. = ..()
var/size = 0.5
if(DNA.features["balls_size"] > 0)
size = DNA.features["balls_size"]
internal_fluids = new /datum/reagents(size * 20)
/obj/item/organ/external/genital/vagina/build_from_dna(datum/dna/DNA, associated_key)
. = ..()
internal_fluids = new /datum/reagents(10)
/mob/living/carbon/human
var/arousal = 0
var/pleasure = 0
var/pain = 0
var/pain_limit = 0
var/arousal_status = AROUSAL_NONE
/mob/living/carbon/human/Initialize(mapload)
. = ..()
if(!istype(src, /mob/living/carbon/human/species/monkey))
apply_status_effect(/datum/status_effect/aroused)
apply_status_effect(/datum/status_effect/body_fluid_regen)
/*
* VERBS
*/
/mob/living/carbon/human/verb/arousal_panel()
set name = "Climax"
set category = "IC"
if(!has_status_effect(/datum/status_effect/climax_cooldown))
if(tgui_alert(usr, "Are you sure you want to cum?", "Climax", list("Yes", "No")) == "Yes")
if(stat != CONSCIOUS)
to_chat(usr, span_warning("You can't climax right now..."))
return
else
climax(TRUE)
else
to_chat(src, span_warning("You can't cum right now!"))
//Removing ERP IC verb depending on config
/mob/living/carbon/human/Initialize(mapload)
. = ..()
if(CONFIG_GET(flag/disable_erp_preferences))
verbs -= /mob/living/carbon/human/verb/arousal_panel
/*
* FLUIDS
*/
/datum/status_effect/body_fluid_regen
id = "body fluid regen"
tick_interval = 50
duration = -1
alert_type = null
/datum/status_effect/body_fluid_regen/tick()
var/mob/living/carbon/human/affected_mob = owner
if(owner.stat != DEAD && affected_mob.client?.prefs?.read_preference(/datum/preference/toggle/erp/sex_toy))
var/obj/item/organ/external/genital/testicles/balls = owner.getorganslot(ORGAN_SLOT_TESTICLES)
var/obj/item/organ/external/genital/breasts/breasts = owner.getorganslot(ORGAN_SLOT_BREASTS)
var/obj/item/organ/external/genital/vagina/vagina = owner.getorganslot(ORGAN_SLOT_VAGINA)
var/interval = 5
if(balls)
if(affected_mob.arousal >= AROUS_SYS_LITTLE)
var/regen = (affected_mob.arousal / 25) * (balls.internal_fluids.maximum_volume / 235) * interval
balls.internal_fluids.add_reagent(/datum/reagent/consumable/cum, regen)
if(breasts)
if(breasts.lactates == TRUE)
var/regen = ((owner.nutrition / (NUTRITION_LEVEL_WELL_FED / 100)) / 100) * (breasts.internal_fluids.maximum_volume / 11000) * interval
if(!breasts.internal_fluids.holder_full())
owner.adjust_nutrition(-regen / 2)
breasts.internal_fluids.add_reagent(/datum/reagent/consumable/breast_milk, regen)
if(vagina)
if(affected_mob.arousal >= AROUS_SYS_LITTLE)
var/regen = (affected_mob.arousal / 25) * (vagina.internal_fluids.maximum_volume / 250) * interval
vagina.internal_fluids.add_reagent(/datum/reagent/consumable/girlcum, regen)
if(vagina.internal_fluids.holder_full() && regen >= 0.15)
regen = regen
else
vagina.internal_fluids.remove_any(0.05)
/*
* AROUSAL
*/
/mob/living/carbon/human/proc/get_arousal()
return arousal
/mob/living/carbon/human/proc/adjustArousal(arous = 0)
if(stat != DEAD && client?.prefs?.read_preference(/datum/preference/toggle/erp))
arousal += arous
var/arousal_flag = AROUSAL_NONE
if(arousal >= AROUS_SYS_STRONG)
arousal_flag = AROUSAL_FULL
else if(arousal >= AROUS_SYS_LITTLE)
arousal_flag = AROUSAL_PARTIAL
if(arousal_status != arousal_flag) // Set organ arousal status
arousal_status = arousal_flag
if(istype(src, /mob/living/carbon/human))
var/mob/living/carbon/human/target = src
for(var/i = 1, i <= target.external_organs.len, i++)
if(istype(target.external_organs[i], /obj/item/organ/external/genital))
var/obj/item/organ/external/genital/target_genital = target.external_organs[i]
if(!target_genital.aroused == AROUSAL_CANT)
target_genital.aroused = arousal_status
target_genital.update_sprite_suffix()
target.update_body()
else
arousal -= abs(arous)
arousal = min(max(arousal, 0), 100)
/datum/status_effect/aroused
id = "aroused"
tick_interval = 10
duration = -1
alert_type = null
/datum/status_effect/aroused/tick()
var/mob/living/carbon/human/affected_mob = owner
var/temp_arousal = -0.1
var/temp_pleasure = -0.5
var/temp_pain = -0.5
if(affected_mob.stat != DEAD)
var/obj/item/organ/external/genital/testicles/balls = affected_mob.getorganslot(ORGAN_SLOT_TESTICLES)
if(balls)
if(balls.internal_fluids.holder_full())
temp_arousal += 0.08
if(HAS_TRAIT(affected_mob, TRAIT_MASOCHISM))
temp_pain -= 0.5
if(HAS_TRAIT(affected_mob, TRAIT_NEVERBONER))
temp_pleasure -= 50
temp_arousal -= 50
if(affected_mob.pain > affected_mob.pain_limit)
temp_arousal -= 0.1
if(affected_mob.arousal >= AROUS_SYS_STRONG && affected_mob.stat != DEAD)
if(prob(3))
affected_mob.try_lewd_autoemote(pick("moan", "blush"))
temp_pleasure += 0.1
//moan
if(affected_mob.pleasure >= PLEAS_SYS_EDGE && affected_mob.stat != DEAD)
if(prob(3))
affected_mob.try_lewd_autoemote(pick("moan", "twitch_s"))
//moan x2
affected_mob.adjustArousal(temp_arousal)
affected_mob.adjustPleasure(temp_pleasure)
affected_mob.adjustPain(temp_pain)
/*
* PAIN
*/
/mob/living/carbon/human/proc/get_pain()
return pain
/mob/living/carbon/human/proc/adjustPain(change_amount = 0)
if(stat != DEAD && client?.prefs?.read_preference(/datum/preference/toggle/erp))
if(pain > pain_limit || change_amount > pain_limit / 10) // pain system // YOUR SYSTEM IS PAIN, WHY WE'RE GETTING AROUSED BY STEPPING ON ANTS?!
if(HAS_TRAIT(src, TRAIT_MASOCHISM))
var/arousal_adjustment = change_amount - (pain_limit / 10)
if(arousal_adjustment > 0)
adjustArousal(-arousal_adjustment)
else
if(change_amount > 0)
adjustArousal(-change_amount)
if(prob(2) && pain > pain_limit && change_amount > pain_limit / 10)
try_lewd_autoemote(pick("scream", "shiver")) //SCREAM!!!
else
if(change_amount > 0)
adjustArousal(change_amount)
if(HAS_TRAIT(src, TRAIT_MASOCHISM))
var/pleasure_adjustment = change_amount / 2
adjustPleasure(pleasure_adjustment)
pain += change_amount
else
pain -= abs(change_amount)
pain = min(max(pain, 0), 100)
/*
* PLEASURE
*/
/mob/living/carbon/human/proc/get_pleasure()
return pleasure
/mob/living/carbon/human/proc/adjustPleasure(pleas = 0)
if(stat != DEAD && client?.prefs?.read_preference(/datum/preference/toggle/erp))
pleasure += pleas
if(pleasure >= 100) // lets cum
climax(FALSE)
else
pleasure -= abs(pleas)
pleasure = min(max(pleasure, 0), 100)
// Get damage for pain system
/datum/species/apply_damage(damage, damagetype, def_zone, blocked, mob/living/carbon/human/affected_mob, forced, spread_damage, wound_bonus, bare_wound_bonus, sharpness, attack_direction)
. = ..()
if(!.)
return
if(affected_mob.client?.prefs?.read_preference(/datum/preference/toggle/erp/sex_toy))
return
var/hit_percent = (100 - (blocked + armor)) / 100
hit_percent = (hit_percent * (100 - affected_mob.physiology.damage_resistance)) / 100
switch(damagetype)
if(BRUTE)
var/amount = forced ? damage : damage * hit_percent * brutemod * affected_mob.physiology.brute_mod
INVOKE_ASYNC(affected_mob, /mob/living/carbon/human/.proc/adjustPain, amount)
if(BURN)
var/amount = forced ? damage : damage * hit_percent * burnmod * affected_mob.physiology.burn_mod
INVOKE_ASYNC(affected_mob, /mob/living/carbon/human/.proc/adjustPain, amount)
/*
* CLIMAX
*/
/datum/mood_event/orgasm
description = span_purple("Woah... This pleasant tiredness... I love it.\n")
timeout = 5 MINUTES
/datum/mood_event/climaxself
description = span_purple("I just came in my own underwear. Messy.\n")
timeout = 4 MINUTES
/datum/mood_event/overgasm
description = span_warning("Uhh... I don't want to be horny anymore.\n") //Me too, buddy. Me too.
timeout = 10 MINUTES
/mob/living/carbon/human/proc/climax(manual = TRUE)
if (CONFIG_GET(flag/disable_erp_preferences))
return
if(!client?.prefs?.read_preference(/datum/preference/toggle/erp/autocum) && manual != TRUE)
return
var/obj/item/organ/external/genital/penis/penis = getorganslot(ORGAN_SLOT_PENIS)
var/obj/item/organ/external/genital/testicles/testicles = getorganslot(ORGAN_SLOT_TESTICLES)
var/obj/item/organ/external/genital/vagina/vagina = getorganslot(ORGAN_SLOT_VAGINA)
if(!has_status_effect(/datum/status_effect/climax_cooldown) && client?.prefs?.read_preference(/datum/preference/toggle/erp/sex_toy))
if(!HAS_TRAIT(src, TRAIT_NEVERBONER) && !has_status_effect(/datum/status_effect/climax_cooldown))
switch(gender)
if(MALE)
playsound(get_turf(src), pick('modular_skyrat/modules/modular_items/lewd_items/sounds/final_m1.ogg',
'modular_skyrat/modules/modular_items/lewd_items/sounds/final_m2.ogg',
'modular_skyrat/modules/modular_items/lewd_items/sounds/final_m3.ogg'), 50, TRUE, ignore_walls = FALSE)
if(FEMALE)
playsound(get_turf(src), pick('modular_skyrat/modules/modular_items/lewd_items/sounds/final_f1.ogg',
'modular_skyrat/modules/modular_items/lewd_items/sounds/final_f2.ogg',
'modular_skyrat/modules/modular_items/lewd_items/sounds/final_f3.ogg'), 50, TRUE, ignore_walls = FALSE)
if(penis)
if(!testicles) //If we have no god damn balls, we can't cum anywhere... GET BALLS!
visible_message(span_userlove("[src] orgasms, but nothing comes out of [p_their()] dick!"), \
span_userlove("You orgasm, it feels great, but nothing comes out of your dick!"))
apply_status_effect(/datum/status_effect/climax)
apply_status_effect(/datum/status_effect/climax_cooldown)
add_mood_event("orgasm", /datum/mood_event/climaxself)
return TRUE
if(!is_bottomless() && penis.visibility_preference != GENITAL_ALWAYS_SHOW)
visible_message(span_userlove("[src] cums into their clothes!"), \
span_userlove("You shoot your load, but you weren't naked, so you mess up your clothes!"))
apply_status_effect(/datum/status_effect/climax)
apply_status_effect(/datum/status_effect/climax_cooldown)
add_mood_event("orgasm", /datum/mood_event/climaxself)
return TRUE
var/list/interactable_inrange_humans = list()
for(var/mob/living/carbon/human/iterating_human in view(1, src))
if(iterating_human == src)
continue
//if(iterating_human.client?.prefs?.read_preference(/datum/preference/toggle/erp))
interactable_inrange_humans[iterating_human.name] = iterating_human
var/list/buttons = list("On the floor")
if(interactable_inrange_humans.len)
buttons += "Inside/on someone"
var/climax_choice = tgui_alert(src, "You are cumming, choose where to shoot your load.", "Load preference!", buttons)
visible_message(span_purple("[src] is cumming!"), span_purple("You are cumming!"))
var/create_cum_decal = FALSE
if(!climax_choice || climax_choice == "On the floor")
if(wear_condom())
var/obj/item/clothing/sextoy/condom/condom = get_item_by_slot(ITEM_SLOT_PENIS)
if(condom.condom_state == "broken")
create_cum_decal = TRUE
visible_message(span_userlove("[src] shoots [p_their()] load into [condom], sending cum onto the floor!"), \
span_userlove("You shoot string after string of cum, but it sprays out of [condom], hitting the floor!"))
else
condom.condom_use()
visible_message(span_userlove("[src] shoots [p_their()] load into [condom], filling it up!"), \
span_userlove("You shoot your thick load into [condom] and it catches it all!"))
else
create_cum_decal = TRUE
visible_message(span_userlove("[src] shoots their sticky load onto the floor!"), \
span_userlove("You shoot string after string of hot cum, hitting the floor!"))
else
var/target_choice = tgui_input_list(src, "Choose a person to cum in or on~", "Choose target!", interactable_inrange_humans)
if(!target_choice)
create_cum_decal = TRUE
visible_message(span_userlove("[src] shoots their sticky load onto the floor!"), \
span_userlove("You shoot string after string of hot cum, hitting the floor!"))
else
var/mob/living/carbon/human/target_human = interactable_inrange_humans[target_choice]
var/obj/item/organ/external/genital/vagina/target_vagina = target_human.getorganslot(ORGAN_SLOT_VAGINA)
var/obj/item/organ/external/genital/anus/target_anus = target_human.getorganslot(ORGAN_SLOT_ANUS)
var/obj/item/organ/external/genital/penis/target_penis = target_human.getorganslot(ORGAN_SLOT_PENIS)
var/list/target_buttons = list()
if(!target_human.wear_mask)
target_buttons += "mouth"
if(target_vagina && target_vagina?.is_exposed())
target_buttons += "vagina"
if(target_anus && target_anus?.is_exposed())
target_buttons += "asshole"
if(target_penis && target_penis.is_exposed() && target_penis.sheath != "None")
target_buttons += "sheath"
target_buttons += "On them"
var/climax_into_choice = tgui_input_list(src, "Where on or in [target_human] do you wish to cum?", "Final frontier!", target_buttons)
if(!climax_into_choice)
create_cum_decal = TRUE
visible_message(span_userlove("[src] shoots their sticky load onto the floor!"), \
span_userlove("You shoot string after string of hot cum, hitting the floor!"))
else if(climax_into_choice == "On them")
create_cum_decal = TRUE
visible_message(span_userlove("[src] shoots their sticky load onto the [target_human]!"), \
span_userlove("You shoot string after string of hot cum onto [target_human]!"))
else
visible_message(span_userlove("[src] hilts [p_their()] cock into [target_human]'s [climax_into_choice], shooting cum into it!"), \
span_userlove("You hilt your cock into [target_human]'s [climax_into_choice], shooting cum into it!"))
to_chat(target_human, span_userlove("Your [climax_into_choice] fills with warm cum as [src] shoots [p_their()] load into it."))
try_lewd_autoemote("moan")
testicles.reagents.remove_all(testicles.reagents.total_volume * 0.6)
apply_status_effect(/datum/status_effect/climax)
apply_status_effect(/datum/status_effect/climax_cooldown)
if(create_cum_decal)
add_cum_splatter_floor(get_turf(src))
return TRUE
if(vagina)
if(is_bottomless() || vagina.visibility_preference == GENITAL_ALWAYS_SHOW)
apply_status_effect(/datum/status_effect/climax)
apply_status_effect(/datum/status_effect/climax_cooldown)
visible_message(span_purple("[src] is cumming!"), span_purple("You are cumming!"))
var/turf/our_turf = get_turf(src)
add_cum_splatter_floor(our_turf, female = TRUE)
else
apply_status_effect(/datum/status_effect/climax)
apply_status_effect(/datum/status_effect/climax_cooldown)
visible_message(span_purple("[src] cums in their underwear!"), \
span_purple("You cum in your underwear! Eww."))
add_mood_event("orgasm", /datum/mood_event/climaxself)
return TRUE
else
visible_message(span_purple("[src] twitches, trying to cum, but with no result."), \
span_purple("You can't have an orgasm!"))
return TRUE
// Let's not force lewd emotes from folk who don't want them, mmm~?
/mob/living/carbon/proc/try_lewd_autoemote(emote)
if(!client?.prefs?.read_preference(/datum/preference/toggle/erp/autoemote))
return
emote(emote)
/datum/status_effect/climax_cooldown
id = "climax_cooldown"
tick_interval = 10
duration = 30 SECONDS
alert_type = null
/datum/status_effect/climax_cooldown/tick()
var/obj/item/organ/external/genital/vagina/vagina = owner.getorganslot(ORGAN_SLOT_VAGINA)
var/obj/item/organ/external/genital/testicles/balls = owner.getorganslot(ORGAN_SLOT_TESTICLES)
var/obj/item/organ/external/genital/testicles/penis = owner.getorganslot(ORGAN_SLOT_PENIS)
var/obj/item/organ/external/genital/testicles/anus = owner.getorganslot(ORGAN_SLOT_ANUS)
if(penis)
penis.aroused = AROUSAL_NONE
if(vagina)
vagina.aroused = AROUSAL_NONE
if(balls)
balls.aroused = AROUSAL_NONE
if(anus)
anus.aroused = AROUSAL_NONE
/datum/status_effect/masturbation_climax
id = "climax"
tick_interval = 10
duration = 50 //Multiplayer better than singleplayer mode.
alert_type = null
/datum/status_effect/masturbation_climax/tick() //this one should not leave decals on the floor. Used in case if character cumming in beaker.
var/mob/living/carbon/human/affected_mob = owner
if(affected_mob.client?.prefs?.read_preference(/datum/preference/toggle/erp/sex_toy))
var/temp_arousal = -12
var/temp_pleasure = -12
var/temp_stamina = 8
owner.reagents.add_reagent(/datum/reagent/drug/dopamine, 0.3)
owner.adjustStaminaLoss(temp_stamina)
affected_mob.adjustArousal(temp_arousal)
affected_mob.adjustPleasure(temp_pleasure)
/datum/status_effect/climax
id = "climax"
tick_interval = 10
duration = 100
alert_type = null
/datum/status_effect/climax/tick()
var/mob/living/carbon/human/affected_mob = owner
if(affected_mob.client?.prefs?.read_preference(/datum/preference/toggle/erp/sex_toy))
var/temp_arousal = -12
var/temp_pleasure = -12
var/temp_stamina = 15
owner.reagents.add_reagent(/datum/reagent/drug/dopamine, 0.5)
owner.adjustStaminaLoss(temp_stamina)
affected_mob.adjustArousal(temp_arousal)
affected_mob.adjustPleasure(temp_pleasure)
/*
* SPANKING
*/
//Hips are red after spanking
/datum/status_effect/spanked
id = "spanked"
duration = 300 SECONDS
alert_type = null
/mob/living/carbon/human/examine(mob/user)
. = ..()
var/mob/living/affected_mob = user
if(stat != DEAD && !HAS_TRAIT(src, TRAIT_FAKEDEATH) && src != affected_mob)
if(src != user)
if(has_status_effect(/datum/status_effect/spanked) && is_bottomless())
. += span_purple("[user.p_their(TRUE)] butt has a red tint to it.") + "\n"
//Mood boost for masochist
/datum/mood_event/perv_spanked
description = span_purple("Ah, yes! More! Punish me!\n")
timeout = 5 MINUTES
/*
* SUBSPACE EFFECT
*/
/datum/status_effect/subspace
id = "subspace"
tick_interval = 10
duration = 5 MINUTES
alert_type = null
/datum/status_effect/subspace/on_apply()
. = ..()
var/mob/living/carbon/human/target = owner
target.add_mood_event("subspace", /datum/mood_event/subspace)
/datum/status_effect/subspace/on_remove()
. = ..()
var/mob/living/carbon/human/target = owner
target.clear_mood_event("subspace")
/datum/mood_event/subspace
description = span_purple("Everything is so woozy... Pain feels so... Awesome.\n")
/datum/status_effect/ropebunny
id = "ropebunny"
tick_interval = 10
duration = INFINITE
alert_type = null
/datum/status_effect/ropebunny/on_apply()
. = ..()
var/mob/living/carbon/human/target = owner
target.add_mood_event("ropebunny", /datum/mood_event/ropebunny)
/datum/status_effect/ropebunny/on_remove()
. = ..()
var/mob/living/carbon/human/target = owner
target.clear_mood_event("ropebunny")
/datum/mood_event/ropebunny
description = span_purple("I'm tied! Cannot move! These ropes... Ah!~")
mood_change = 0 // I don't want to doom the station to sonic-speed perverts, but still want to keep this as mood modifier.
/*
* AROUSAL INDICATOR
*/
/obj/item/organ/internal/brain/on_life(delta_time, times_fired) //All your horny is here *points to the head*
. = ..()
var/mob/living/carbon/human/brain_owner = owner
if(istype(brain_owner, /mob/living/carbon/human) && brain_owner.client?.prefs?.read_preference(/datum/preference/toggle/erp/sex_toy))
if(!(organ_flags & ORGAN_FAILING))
brain_owner.dna.species.handle_arousal(brain_owner, delta_time, times_fired)
//screen alert
/atom/movable/screen/alert/aroused_x
name = "Aroused"
desc = "It's a little hot in here"
icon = 'modular_skyrat/modules/modular_items/lewd_items/icons/obj/lewd_items/lewd_icons.dmi'
icon_state = "arousal_small"
var/mutable_appearance/pain_overlay
var/mutable_appearance/pleasure_overlay
var/pain_level = "small"
var/pleasure_level = "small"
/atom/movable/screen/alert/aroused_x/Initialize(mapload)
.=..()
pain_overlay = update_pain()
pleasure_overlay = update_pleasure()
/atom/movable/screen/alert/aroused_x/proc/update_pain()
if(pain_level)
return mutable_appearance('modular_skyrat/modules/modular_items/lewd_items/icons/obj/lewd_items/lewd_icons.dmi', "pain_[pain_level]")
/atom/movable/screen/alert/aroused_x/proc/update_pleasure()
if(pleasure_level)
return mutable_appearance('modular_skyrat/modules/modular_items/lewd_items/icons/obj/lewd_items/lewd_icons.dmi', "pleasure_[pleasure_level]")
/datum/species/proc/throw_arousalalert(level, atom/movable/screen/alert/aroused_x/arousal_alert, mob/living/carbon/human/targeted_human)
targeted_human.throw_alert("aroused", /atom/movable/screen/alert/aroused_x)
arousal_alert?.icon_state = level
arousal_alert?.update_icon()
/datum/species/proc/overlay_pain(level, atom/movable/screen/alert/aroused_x/arousal_alert)
arousal_alert?.cut_overlay(arousal_alert.pain_overlay)
arousal_alert?.pain_level = level
arousal_alert?.pain_overlay = arousal_alert.update_pain()
arousal_alert?.add_overlay(arousal_alert.pain_overlay)
arousal_alert?.update_overlays()
/datum/species/proc/overlay_pleasure(level, atom/movable/screen/alert/aroused_x/arousal_alert)
arousal_alert?.cut_overlay(arousal_alert.pleasure_overlay)
arousal_alert?.pleasure_level = level
arousal_alert?.pleasure_overlay = arousal_alert.update_pleasure()
arousal_alert?.add_overlay(arousal_alert.pleasure_overlay)
arousal_alert?.update_overlays()
/datum/species/proc/handle_arousal(mob/living/carbon/human/target_human, atom/movable/screen/alert/aroused_x)
var/atom/movable/screen/alert/aroused_x/arousal_alert = target_human.alerts["aroused"]
if(target_human.client?.prefs?.read_preference(/datum/preference/toggle/erp/sex_toy))
switch(target_human.arousal)
if(-100 to 1)
target_human.clear_alert("aroused", /atom/movable/screen/alert/aroused_x)
if(1 to 25)
throw_arousalalert("arousal_small", arousal_alert, target_human)
if(25 to 50)
throw_arousalalert("arousal_medium", arousal_alert, target_human)
if(50 to 75)
throw_arousalalert("arousal_high", arousal_alert, target_human)
if(75 to INFINITY) //to prevent that 101 arousal that can make icon disappear or something.
throw_arousalalert("arousal_max", arousal_alert, target_human)
if(target_human.arousal > 1)
switch(target_human.pain)
if(-100 to 1) //to prevent same thing with pain
arousal_alert?.cut_overlay(arousal_alert.pain_overlay)
if(1 to 25)
overlay_pain("small", arousal_alert)
if(25 to 50)
overlay_pain("medium", arousal_alert)
if(50 to 75)
overlay_pain("high", arousal_alert)
if(75 to INFINITY)
overlay_pain("max", arousal_alert)
if(target_human.arousal > 1)
switch(target_human.pleasure)
if(-100 to 1) //to prevent same thing with pleasure
arousal_alert?.cut_overlay(arousal_alert.pleasure_overlay)
if(1 to 25)
overlay_pleasure("small", arousal_alert)
if(25 to 60)
overlay_pleasure("medium", arousal_alert)
if(60 to 85)
overlay_pleasure("high", arousal_alert)
if(85 to INFINITY)
overlay_pleasure("max", arousal_alert)
else
if(arousal_alert?.pleasure_level in list("small", "medium", "high", "max"))
arousal_alert.cut_overlay(arousal_alert.pleasure_overlay)
if(arousal_alert?.pain_level in list("small", "medium", "high", "max"))
arousal_alert.cut_overlay(arousal_alert.pain_overlay)
/datum/emote/living/cum
key = "cum"
key_third_person = "cums"
cooldown = 30 SECONDS
/datum/emote/living/cum/check_config()
return !CONFIG_GET(flag/disable_erp_preferences)
/datum/emote/living/cum/can_run_emote(mob/user, status_check = TRUE, intentional = FALSE)
if (!check_config())
return FALSE
. = ..()
/datum/emote/living/cum/run_emote(mob/living/user, params, type_override, intentional)
if (!check_config())
return
. = ..()
if(!.)
return
var/obj/item/coomer = new /obj/item/hand_item/coom(user)
var/mob/living/carbon/human/target = user
var/obj/item/held = user.get_active_held_item()
var/obj/item/unheld = user.get_inactive_held_item()
if(user.put_in_hands(coomer) && target.dna.species.mutant_bodyparts["testicles"] && target.dna.species.mutant_bodyparts["penis"])
if(held || unheld)
if(!((held.name == "cum" && held.item_flags == DROPDEL | ABSTRACT | HAND_ITEM) || (unheld.name == "cum" && unheld.item_flags == DROPDEL | ABSTRACT | HAND_ITEM)))
to_chat(user, span_notice("You mentally prepare yourself to masturbate."))
else
qdel(coomer)
else
to_chat(user, span_notice("You mentally prepare yourself to masturbate."))
else
qdel(coomer)
to_chat(user, span_warning("You're incapable of masturbating."))
/obj/item/hand_item/coom
name = "cum"
desc = "C-can I watch...?"
icon = 'icons/obj/hydroponics/harvest.dmi'
icon_state = "eggplant"
inhand_icon_state = "nothing"
/obj/item/hand_item/coom/attack(mob/living/target, mob/user, proximity)
if (CONFIG_GET(flag/disable_erp_preferences))
return
if(!proximity)
return
if(!ishuman(target))
return
if(user.stat == DEAD)
return
var/mob/living/carbon/human/human_cumvictim = target
if(!human_cumvictim.client)
to_chat(user, span_warning("You can't cum onto [target]."))
return
var/mob/living/carbon/human/affected_human = user
var/obj/item/organ/external/genital/testicles/testicles = affected_human.getorganslot(ORGAN_SLOT_TESTICLES)
var/obj/item/organ/external/genital/penis/penis = affected_human.getorganslot(ORGAN_SLOT_PENIS)
var/datum/sprite_accessory/genital/penis_accessory = GLOB.sprite_accessories["penis"][affected_human.dna.species.mutant_bodyparts["penis"][MUTANT_INDEX_NAME]]
if(penis_accessory.is_hidden(affected_human))
to_chat(user, span_notice("You need to expose yourself in order to masturbate."))
return
else if(penis.aroused != AROUSAL_FULL)
to_chat(user, span_notice("You need to be aroused in order to masturbate."))
return
var/cum_volume = testicles.genital_size * 5 + 5
var/datum/reagents/applied_reagents = new/datum/reagents(50)
applied_reagents.add_reagent(/datum/reagent/consumable/cum, cum_volume)
if(target == user)
user.visible_message(span_warning("[user] starts masturbating onto [target.p_them()]self!"), span_danger("You start masturbating onto yourself!"))
else
user.visible_message(span_warning("[user] starts masturbating onto [target]!"), span_danger("You start masturbating onto [target]!"))
if(do_after(user, 60, target))
if(target == user)
user.visible_message(span_warning("[user] cums on [target.p_them()]self!"), span_danger("You cum on yourself!"))
else
user.visible_message(span_warning("[user] cums on [target]!"), span_danger("You cum on [target]!"))
applied_reagents.expose(target, TOUCH)
log_combat(user, target, "came on")
if(prob(40))
affected_human.try_lewd_autoemote("moan")
qdel(src)
// Jerk off into bottles
/obj/item/hand_item/coom/afterattack(obj/target, mob/user, proximity)
. = ..()
if (CONFIG_GET(flag/disable_erp_preferences))
return
if(!proximity)
return
if(ishuman(target))
return
if(user.stat == DEAD)
return
var/mob/living/carbon/human/affected_human = user
var/obj/item/organ/external/genital/testicles/testicles = affected_human.getorganslot(ORGAN_SLOT_TESTICLES)
var/obj/item/organ/external/genital/penis/penis = affected_human.getorganslot(ORGAN_SLOT_PENIS)
var/datum/sprite_accessory/genital/spriteP = GLOB.sprite_accessories["penis"][affected_human.dna.species.mutant_bodyparts["penis"][MUTANT_INDEX_NAME]]
if(spriteP.is_hidden(affected_human))
to_chat(user, span_notice("You need to expose yourself in order to masturbate."))
return
else if(penis.aroused != AROUSAL_FULL)
to_chat(user, span_notice("You need to be aroused in order to masturbate."))
return
if(target.is_refillable() && target.is_drainable())
var/cum_volume = testicles.genital_size*5+5
if(target.reagents.holder_full())
to_chat(user, span_warning("[target] is full."))
return
var/datum/reagents/applied_reagents = new/datum/reagents(50)
applied_reagents.add_reagent(/datum/reagent/consumable/cum, cum_volume)
user.visible_message(span_warning("[user] starts masturbating into [target]!"), span_danger("You start masturbating into [target]!"))
if(do_after(user, 60))
user.visible_message(span_warning("[user] cums into [target]!"), span_danger("You cum into [target]!"))
playsound(target, SFX_DESECRATION, 50, TRUE, ignore_walls = FALSE)
applied_reagents.trans_to(target, cum_volume)
if(prob(40))
affected_human.try_lewd_autoemote("moan")
qdel(src)
else
user.visible_message(span_warning("[user] starts masturbating onto [target]!"), span_danger("You start masturbating onto [target]!"))
if(do_after(user, 60))
user.visible_message(span_warning("[user] cums on [target]!"), span_danger("You cum on [target]!"))
playsound(target, SFX_DESECRATION, 50, TRUE, ignore_walls = FALSE)
affected_human.add_cum_splatter_floor(get_turf(target))
if(prob(40))
affected_human.try_lewd_autoemote("moan")
if(target.icon_state=="stickyweb1"|target.icon_state=="stickyweb2")
target.icon = 'modular_skyrat/modules/modular_items/lewd_items/icons/obj/lewd_decals/lewd_decals.dmi'
qdel(src)
@@ -0,0 +1,15 @@
/obj/effect/decal/cleanable/cum
name = "cum"
desc = "Ew... Gross."
icon = 'modular_skyrat/modules/modular_items/lewd_items/icons/obj/lewd_decals/lewd_decals.dmi'
icon_state = "cum_1"
random_icon_states = list("cum_1", "cum_2", "cum_3", "cum_4")
beauty = -50
/obj/effect/decal/cleanable/cum/femcum
name = "female cum"
desc = "Uhh... Someone had fun..."
icon = 'modular_skyrat/modules/modular_items/lewd_items/icons/obj/lewd_decals/lewd_decals.dmi'
icon_state = "femcum_1"
random_icon_states = list("femcum_1", "femcum_2", "femcum_3", "femcum_4")
beauty = -50
@@ -0,0 +1,22 @@
/mob/living/carbon/human/proc/adjust_arousal(arous = 0)
if(stat >= DEAD || !client?.prefs?.read_preference(/datum/preference/toggle/erp))
return
var/arousal_flag = AROUSAL_NONE
if(arousal >= AROUSAL_MEDIUM)
arousal_flag = AROUSAL_FULL
else if(arousal >= AROUSAL_LOW)
arousal_flag = AROUSAL_PARTIAL
if(arousal_status != arousal_flag) // Set organ arousal status
arousal_status = arousal_flag
if(istype(src, /mob/living/carbon/human))
var/mob/living/carbon/human/target = src
for(var/obj/item/organ/external/genital/target_genital in target.external_organs)
if(!target_genital.aroused == AROUSAL_CANT)
target_genital.aroused = arousal_status
target_genital.update_sprite_suffix()
target.update_body()
arousal = clamp(arousal + arous, AROUSAL_MINIMUM, AROUSAL_LIMIT)
@@ -0,0 +1,159 @@
#define CLIMAX_VAGINA "Vagina"
#define CLIMAX_PENIS "Penis"
#define CLIMAX_BOTH "Both"
#define CLIMAX_ON_FLOOR "On the floor"
#define CLIMAX_IN_OR_ON "Climax in or on someone"
/mob/living/carbon/human/proc/climax(manual = TRUE)
if (CONFIG_GET(flag/disable_erp_preferences))
return
if(!client?.prefs?.read_preference(/datum/preference/toggle/erp/autocum) && !manual)
return
if(has_status_effect(/datum/status_effect/climax_cooldown) || !client?.prefs?.read_preference(/datum/preference/toggle/erp/sex_toy))
return
if(HAS_TRAIT(src, TRAIT_NEVERBONER) || has_status_effect(/datum/status_effect/climax_cooldown) || (!has_vagina() && !has_penis()))
visible_message(span_purple("[src] twitches, trying to cum, but with no result."), \
span_purple("You can't have an orgasm!"))
return TRUE
// Reduce pop-ups and make it slightly more frictionless (lewd).
var/climax_choice = has_penis() ? CLIMAX_PENIS : CLIMAX_VAGINA
if(manual)
var/list/genitals = list()
if(has_vagina())
genitals.Add(CLIMAX_VAGINA)
if(has_penis())
genitals.Add(CLIMAX_PENIS)
genitals.Add(CLIMAX_BOTH)
else if(has_penis())
genitals.Add(CLIMAX_PENIS)
climax_choice = tgui_alert(src, "You are climaxing, choose which genitalia to climax with.", "Genitalia Preference!", genitals)
switch(gender)
if(MALE)
playsound(get_turf(src), pick('modular_skyrat/modules/modular_items/lewd_items/sounds/final_m1.ogg',
'modular_skyrat/modules/modular_items/lewd_items/sounds/final_m2.ogg',
'modular_skyrat/modules/modular_items/lewd_items/sounds/final_m3.ogg'), 50, TRUE, ignore_walls = FALSE)
if(FEMALE)
playsound(get_turf(src), pick('modular_skyrat/modules/modular_items/lewd_items/sounds/final_f1.ogg',
'modular_skyrat/modules/modular_items/lewd_items/sounds/final_f2.ogg',
'modular_skyrat/modules/modular_items/lewd_items/sounds/final_f3.ogg'), 50, TRUE, ignore_walls = FALSE)
var/self_orgasm = FALSE
var/self_their = p_their()
if(climax_choice == CLIMAX_PENIS || climax_choice == CLIMAX_BOTH)
var/obj/item/organ/external/genital/penis/penis = getorganslot(ORGAN_SLOT_PENIS)
if(!getorganslot(ORGAN_SLOT_TESTICLES)) //If we have no god damn balls, we can't cum anywhere... GET BALLS!
visible_message(span_userlove("[src] orgasms, but nothing comes out of [self_their] penis!"), \
span_userlove("You orgasm, it feels great, but nothing comes out of your penis!"))
else if(is_wearing_condom())
var/obj/item/clothing/sextoy/condom/condom = get_item_by_slot(LEWD_SLOT_PENIS)
condom.condom_use()
visible_message(span_userlove("[src] shoots [self_their] load into the [condom], filling it up!"), \
span_userlove("You shoot your thick load into the [condom] and it catches it all!"))
else if(!is_bottomless() && penis.visibility_preference != GENITAL_ALWAYS_SHOW)
visible_message(span_userlove("[src] cums inside [self_their] clothes!"), \
span_userlove("You shoot your load, but you weren't naked, so you mess up your clothes!"))
self_orgasm = TRUE
else
var/list/interactable_inrange_humans = list()
// Unfortunately prefs can't be checked here, because byond/tgstation moment.
for(var/mob/living/carbon/human/iterating_human in (view(1, src) - src))
interactable_inrange_humans[iterating_human.name] = iterating_human
var/list/buttons = list(CLIMAX_ON_FLOOR)
if(interactable_inrange_humans.len)
buttons += CLIMAX_IN_OR_ON
var/penis_climax_choice = tgui_alert(src, "Choose where to shoot your load.", "Load preference!", buttons)
var/create_cum_decal = FALSE
if(!penis_climax_choice || penis_climax_choice == CLIMAX_ON_FLOOR)
create_cum_decal = TRUE
visible_message(span_userlove("[src] shoots [self_their] sticky load onto the floor!"), \
span_userlove("You shoot string after string of hot cum, hitting the floor!"))
else
var/target_choice = tgui_input_list(src, "Choose a person to cum in or on.", "Choose target!", interactable_inrange_humans)
if(!target_choice)
create_cum_decal = TRUE
visible_message(span_userlove("[src] shoots [self_their] sticky load onto the floor!"), \
span_userlove("You shoot string after string of hot cum, hitting the floor!"))
else
var/mob/living/carbon/human/target_human = interactable_inrange_humans[target_choice]
var/target_human_them = target_human.p_them()
var/list/target_buttons = list()
if(!target_human.wear_mask)
target_buttons += "mouth"
if(target_human.has_vagina(REQUIRE_GENITAL_EXPOSED))
target_buttons += ORGAN_SLOT_VAGINA
if(target_human.has_anus(REQUIRE_GENITAL_EXPOSED))
target_buttons += "asshole"
if(target_human.has_penis(REQUIRE_GENITAL_EXPOSED))
var/obj/item/organ/external/genital/penis/other_penis = target_human.getorganslot(ORGAN_SLOT_PENIS)
if(other_penis.sheath != "None")
target_buttons += "sheath"
target_buttons += "On [target_human_them]"
var/climax_into_choice = tgui_input_list(src, "Where on or in [target_human] do you wish to cum?", "Final frontier!", target_buttons)
if(!climax_into_choice)
create_cum_decal = TRUE
visible_message(span_userlove("[src] shoots their sticky load onto the floor!"), \
span_userlove("You shoot string after string of hot cum, hitting the floor!"))
else if(climax_into_choice == "On [target_human_them]")
create_cum_decal = TRUE
visible_message(span_userlove("[src] shoots their sticky load onto [target_human]!"), \
span_userlove("You shoot string after string of hot cum onto [target_human]!"))
else
visible_message(span_userlove("[src] hilts [self_their] cock into [target_human]'s [climax_into_choice], shooting cum into [target_human_them]!"), \
span_userlove("You hilt your cock into [target_human]'s [climax_into_choice], shooting cum into [target_human_them]!"))
to_chat(target_human, span_userlove("Your [climax_into_choice] fills with warm cum as [src] shoots [self_their] load into it."))
var/obj/item/organ/external/genital/testicles/testicles = getorganslot(ORGAN_SLOT_TESTICLES)
testicles.reagents.remove_all(testicles.reagents.total_volume * 0.6)
if(create_cum_decal)
add_cum_splatter_floor(get_turf(src))
try_lewd_autoemote("moan")
if(climax_choice == CLIMAX_PENIS)
apply_status_effect(/datum/status_effect/climax)
apply_status_effect(/datum/status_effect/climax_cooldown)
if(self_orgasm)
add_mood_event("orgasm", /datum/mood_event/climaxself)
return TRUE
if(climax_choice == CLIMAX_VAGINA || climax_choice == CLIMAX_BOTH)
var/obj/item/organ/external/genital/vagina/vagina = getorganslot(ORGAN_SLOT_VAGINA)
if(is_bottomless() || vagina.visibility_preference == GENITAL_ALWAYS_SHOW)
visible_message(span_userlove("[src] twitches and moans as [p_they()] climax from their vagina!"), span_userlove("You twitch and moan as you climax from your vagina!"))
add_cum_splatter_floor(get_turf(src), female = TRUE)
else
visible_message(span_userlove("[src] cums in [self_their] underwear from [self_their] vagina!"), \
span_userlove("You cum in your underwear from your vagina! Eww."))
self_orgasm = TRUE
apply_status_effect(/datum/status_effect/climax)
apply_status_effect(/datum/status_effect/climax_cooldown)
if(self_orgasm)
add_mood_event("orgasm", /datum/mood_event/climaxself)
return TRUE
#undef CLIMAX_VAGINA
#undef CLIMAX_PENIS
#undef CLIMAX_BOTH
#undef CLIMAX_ON_FLOOR
#undef CLIMAX_IN_OR_ON
@@ -0,0 +1,11 @@
/datum/mood_event/orgasm
description = span_purple("Woah... This pleasant tiredness... I love it.\n")
timeout = 5 MINUTES
/datum/mood_event/climaxself
description = span_purple("I just came in my own underwear. Messy.\n")
timeout = 4 MINUTES
/datum/mood_event/overgasm
description = span_warning("Uhh... I don't want to be horny anymore.\n") //Me too, buddy. Me too.
timeout = 10 MINUTES
@@ -0,0 +1,25 @@
// I guess some people enjoy it.
/// Adds or removes pain, this should be used instead of the modifying the var, due to quirk logic.
/// Makes the human scream and shiver when pain hits the soft limit, provided autoemote is enabled.
/mob/living/carbon/human/proc/adjust_pain(change_amount = 0)
if(stat >= DEAD || !client?.prefs?.read_preference(/datum/preference/toggle/erp))
return
if(pain > pain_limit || change_amount > pain_limit / 10) // pain system // YOUR SYSTEM IS PAIN, WHY WE'RE GETTING AROUSED BY STEPPING ON ANTS?!
if(HAS_TRAIT(src, TRAIT_MASOCHISM))
var/arousal_adjustment = change_amount - (pain_limit / 10)
if(arousal_adjustment > 0)
adjust_arousal(-arousal_adjustment)
else
if(change_amount > 0)
adjust_arousal(-change_amount)
if(prob(2) && pain > pain_limit && change_amount > pain_limit / 10)
try_lewd_autoemote(pick("scream", "shiver")) //SCREAM!!!
else if(HAS_TRAIT(src, TRAIT_MASOCHISM))
if(change_amount > 0)
adjust_arousal(change_amount)
adjust_pleasure(change_amount / 2)
pain = clamp(pain + change_amount, AROUSAL_MINIMUM, AROUSAL_LIMIT)
@@ -0,0 +1,8 @@
/mob/living/carbon/human/proc/adjust_pleasure(pleas = 0)
if(stat >= DEAD || !client?.prefs?.read_preference(/datum/preference/toggle/erp))
return
pleasure = clamp(pleasure + pleas, AROUSAL_MINIMUM, AROUSAL_LIMIT)
if(pleasure >= AROUSAL_AUTO_CLIMAX_THRESHOLD) // lets cum
climax(manual = FALSE)
@@ -0,0 +1,63 @@
#define AUTO_EMOTE_CHANCE 3
#define MASOCHISM_PAIN_OFFSET 0.5
#define NEVERBONER_PLEASURE_OFFSET 50
#define BLUEBALL_AROUSAL_MODIFIER 0.08
#define TOO_MUCH_PAIN_MODIFIER 0.1
#define ITS_PRETTY_HOT_IN_HERE_MODIFIER 0.1
#define BASE_AROUSAL_ADJUSTMENT -0.1
#define BASE_PAIN_AND_PLEASURE_ADJUSTMENT -0.5
/datum/status_effect/aroused
id = "aroused"
tick_interval = 10
duration = -1
alert_type = null
/datum/status_effect/aroused/tick()
if(owner.stat >= DEAD || !owner.client?.prefs?.read_preference(/datum/preference/toggle/erp))
return
var/mob/living/carbon/human/affected_mob = owner
var/temp_arousal = BASE_AROUSAL_ADJUSTMENT
var/temp_pleasure = BASE_PAIN_AND_PLEASURE_ADJUSTMENT
var/temp_pain = BASE_PAIN_AND_PLEASURE_ADJUSTMENT
var/obj/item/organ/external/genital/testicles/balls = affected_mob.getorganslot(ORGAN_SLOT_TESTICLES)
if(balls && balls.internal_fluid_full())
temp_arousal += BLUEBALL_AROUSAL_MODIFIER
if(HAS_TRAIT(affected_mob, TRAIT_MASOCHISM))
temp_pain -= MASOCHISM_PAIN_OFFSET
if(HAS_TRAIT(affected_mob, TRAIT_NEVERBONER))
temp_pleasure -= NEVERBONER_PLEASURE_OFFSET
temp_arousal -= NEVERBONER_PLEASURE_OFFSET
if(affected_mob.pain > affected_mob.pain_limit)
temp_arousal -= TOO_MUCH_PAIN_MODIFIER
if(affected_mob.arousal >= AROUSAL_MEDIUM)
if(prob(AUTO_EMOTE_CHANCE))
affected_mob.try_lewd_autoemote(pick("moan", "blush"))
temp_pleasure += ITS_PRETTY_HOT_IN_HERE_MODIFIER
//moan
if(affected_mob.pleasure >= AROUSAL_HIGH && prob(AUTO_EMOTE_CHANCE))
affected_mob.try_lewd_autoemote(pick("moan", "twitch_s"))
//moan x2
affected_mob.adjust_arousal(temp_arousal)
affected_mob.adjust_pleasure(temp_pleasure)
affected_mob.adjust_pain(temp_pain)
#undef AUTO_EMOTE_CHANCE
#undef MASOCHISM_PAIN_OFFSET
#undef NEVERBONER_PLEASURE_OFFSET
#undef BLUEBALL_AROUSAL_MODIFIER
#undef TOO_MUCH_PAIN_MODIFIER
#undef ITS_PRETTY_HOT_IN_HERE_MODIFIER
#undef BASE_AROUSAL_ADJUSTMENT
#undef BASE_PAIN_AND_PLEASURE_ADJUSTMENT
@@ -0,0 +1,63 @@
#define AROUSAL_REMOVAL_AMOUNT -12
#define STAMINA_REMOVAL_AMOUNT_EXTERNAL 15
#define STAMINA_REMOVAL_AMOUNT_SELF 8
// Lowers arousal and pleasure by a bunch to not chain climax.
/datum/status_effect/climax
id = "climax"
tick_interval = 1 SECONDS
duration = 10 SECONDS
alert_type = null
/datum/status_effect/climax/tick()
if(!owner.client?.prefs?.read_preference(/datum/preference/toggle/erp/sex_toy))
return
var/mob/living/carbon/human/affected_mob = owner
owner.reagents.add_reagent(/datum/reagent/drug/aphrodisiac/dopamine, 0.5)
owner.adjustStaminaLoss(STAMINA_REMOVAL_AMOUNT_EXTERNAL)
affected_mob.adjust_arousal(AROUSAL_REMOVAL_AMOUNT)
affected_mob.adjust_pleasure(AROUSAL_REMOVAL_AMOUNT)
// Likely ready to be deprecated code that could be removed, due to nymphomaniac not existing anymore.
/datum/status_effect/masturbation_climax
id = "climax"
tick_interval = 1 SECONDS
duration = 5 SECONDS // Multiplayer better than singleplayer mode.
alert_type = null
// This one should not leave decals on the floor. Used in case if character cumming in beaker.
/datum/status_effect/masturbation_climax/tick()
if(!owner.client?.prefs?.read_preference(/datum/preference/toggle/erp/sex_toy))
return
var/mob/living/carbon/human/affected_mob = owner
owner.reagents.add_reagent(/datum/reagent/drug/aphrodisiac/dopamine, 0.3)
owner.adjustStaminaLoss(STAMINA_REMOVAL_AMOUNT_SELF)
affected_mob.adjust_arousal(AROUSAL_REMOVAL_AMOUNT)
affected_mob.adjust_pleasure(AROUSAL_REMOVAL_AMOUNT)
// A second step in preventing chain climax, and also prevents spam.
/datum/status_effect/climax_cooldown
id = "climax_cooldown"
tick_interval = 1 SECONDS
duration = 30 SECONDS
alert_type = null
/datum/status_effect/climax_cooldown/tick()
var/obj/item/organ/external/genital/vagina/vagina = owner.getorganslot(ORGAN_SLOT_VAGINA)
var/obj/item/organ/external/genital/testicles/balls = owner.getorganslot(ORGAN_SLOT_TESTICLES)
var/obj/item/organ/external/genital/testicles/penis = owner.getorganslot(ORGAN_SLOT_PENIS)
var/obj/item/organ/external/genital/testicles/anus = owner.getorganslot(ORGAN_SLOT_ANUS)
if(penis)
penis.aroused = AROUSAL_NONE
if(vagina)
vagina.aroused = AROUSAL_NONE
if(balls)
balls.aroused = AROUSAL_NONE
if(anus)
anus.aroused = AROUSAL_NONE
@@ -0,0 +1,53 @@
// These are effectively magic numbers.
#define AROUSAL_MULTIPLIER 25
#define BALLS_MULTIPLIER 235
#define NUTRITION_MULTIPLIER 100
#define NUTRITION_COST_MULTIPLIER 2
// Breasts have ungodly scaling at larger sizes, so the massive multiplier to ensure there's no runaway production makes sense here.
#define BREASTS_MULTIPLIER 11000
#define VAGINA_MULTIPLIER 250
#define VAGINA_FLUID_REMOVAL_AMOUNT -0.05
#define BASE_MULTIPLIER 5
/datum/status_effect/body_fluid_regen
id = "body fluid regen"
tick_interval = 5 SECONDS
duration = -1
alert_type = null
/datum/status_effect/body_fluid_regen/tick()
if(owner.stat >= DEAD || !owner.client?.prefs?.read_preference(/datum/preference/toggle/erp/sex_toy))
return
var/mob/living/carbon/human/affected_mob = owner
var/obj/item/organ/external/genital/testicles/balls = owner.getorganslot(ORGAN_SLOT_TESTICLES)
var/obj/item/organ/external/genital/breasts/breasts = owner.getorganslot(ORGAN_SLOT_BREASTS)
var/obj/item/organ/external/genital/vagina/vagina = owner.getorganslot(ORGAN_SLOT_VAGINA)
if(balls)
if(affected_mob.arousal >= AROUSAL_LOW)
var/regen = (affected_mob.arousal / AROUSAL_MULTIPLIER) * (balls.internal_fluid_maximum / BALLS_MULTIPLIER) * BASE_MULTIPLIER
balls.internal_fluid_count += regen
if(breasts)
if(breasts.lactates == TRUE)
var/regen = ((owner.nutrition / (NUTRITION_LEVEL_WELL_FED / NUTRITION_MULTIPLIER)) / NUTRITION_MULTIPLIER) * (breasts.internal_fluid_maximum / BREASTS_MULTIPLIER) * BASE_MULTIPLIER
if(!breasts.internal_fluid_full())
owner.adjust_nutrition(-regen / NUTRITION_COST_MULTIPLIER)
breasts.adjust_internal_fluid(regen)
if(vagina)
if(affected_mob.arousal >= AROUSAL_LOW)
var/regen = (affected_mob.arousal / AROUSAL_MULTIPLIER) * (vagina.internal_fluid_maximum / VAGINA_MULTIPLIER) * BASE_MULTIPLIER
vagina.adjust_internal_fluid(regen)
else
vagina.adjust_internal_fluid(VAGINA_FLUID_REMOVAL_AMOUNT)
#undef AROUSAL_MULTIPLIER
#undef BALLS_MULTIPLIER
#undef NUTRITION_MULTIPLIER
#undef NUTRITION_COST_MULTIPLIER
#undef BREASTS_MULTIPLIER
#undef VAGINA_MULTIPLIER
#undef VAGINA_FLUID_REMOVAL_AMOUNT
#undef BASE_MULTIPLIER
@@ -0,0 +1,19 @@
/datum/status_effect/ropebunny
id = "ropebunny"
tick_interval = 10
duration = INFINITE
alert_type = null
/datum/status_effect/ropebunny/on_apply()
. = ..()
var/mob/living/carbon/human/target = owner
target.add_mood_event("ropebunny", /datum/mood_event/ropebunny)
/datum/status_effect/ropebunny/on_remove()
. = ..()
var/mob/living/carbon/human/target = owner
target.clear_mood_event("ropebunny")
/datum/mood_event/ropebunny
description = span_purple("I'm tied! Cannot move! These ropes... Ah!~")
mood_change = 0 // I don't want to doom the station to sonic-speed perverts, but still want to keep this as mood modifier.
@@ -0,0 +1,39 @@
// This name means nothing. What does this even do?
/datum/status_effect/subspace
id = "subspace"
tick_interval = 10
duration = 5 MINUTES
alert_type = null
/datum/status_effect/subspace/on_apply()
. = ..()
var/mob/living/carbon/human/target = owner
target.add_mood_event("subspace", /datum/mood_event/subspace)
/datum/status_effect/subspace/on_remove()
. = ..()
var/mob/living/carbon/human/target = owner
target.clear_mood_event("subspace")
/datum/mood_event/subspace
description = span_purple("Everything is so woozy... Pain feels so... Awesome.\n")
//Hips are red after spanking
/datum/status_effect/spanked
id = "spanked"
duration = 300 SECONDS
alert_type = null
/mob/living/carbon/human/examine(mob/user)
. = ..()
if(stat >= DEAD || HAS_TRAIT(src, TRAIT_FAKEDEATH) || src == user || !has_status_effect(/datum/status_effect/spanked) || !is_bottomless())
return
. += span_purple("[user.p_their(TRUE)] butt has a red tint to it.") + "\n"
//Mood boost for masochist
/datum/mood_event/perv_spanked
description = span_purple("Ah, yes! More! Punish me!\n")
timeout = 5 MINUTES
@@ -1,742 +0,0 @@
// The base ERP chem. It handles pref and human type checks for you, so ALL chems relating to ERP should be subtypes of this.
/datum/reagent/drug/aphrodisiac
name = "liquid ERP"
description = "ERP in its liquified form. Complain to a coder."
/// What preference you need enabled for effects on life
var/life_pref_datum = /datum/preference/toggle/erp
/// What preference you need enabled for effects on overdose
var/overdose_pref_datum = /datum/preference/toggle/erp
/// The amount to adjust the mob's arousal by
var/arousal_adjust_amount = 1
/// The amount to adjust the mob's pleasure by
var/pleasure_adjust_amount = 0
/// The amount to adjust the mob's pain by
var/pain_adjust_amount = 0
// Vars for enlargement chems from here on
/// Counts up to a threshold before triggering enlargement effects
var/enlargement_amount = 0
/// How much to increase the count by each process
var/enlarger_increase_step = 5
/// Count to reach before effects
var/enlargement_threshold = 100
/// % chance for damage to be applied when the organ is too large and the mob is clothed
var/damage_chance = 20
/// Largest length the chem can make a mob's penis
var/penis_max_length = PENIS_MAX_LENGTH
/// Smallest size the chem can make a mob's penis
var/penis_min_length = PENIS_MIN_LENGTH
/// How much the penis is increased in size each time it's run
var/penis_length_increase_step = 1
/// How much the penis is increased in girth each time it's run
var/penis_girth_increase_step = 1
/// Largest girth the chem can make a mob's penis
var/penis_max_girth = PENIS_MAX_GIRTH
/// Smallest girth the chem can make a mob's penis
var/penis_minimum_girth = 2
/// How much to reduce the size of the penis each time it's run
var/penis_size_reduction_step = 2
/// How much to reduce the girth of the penis each time it's run
var/penis_girth_reduction_step = 2
/// Largest size the chem can make a mob's breasts
var/max_breast_size = 16
/// How much breasts are increased in size each time it's run
var/breast_size_increase_step = 1
/// Smallest size the chem can make a mob's breasts
var/breast_minimum_size = 2
/// How much to reduce the size of the breasts each time it's run
var/breast_size_reduction_step = 1
/// Runs on life after preference checks. Use this instead of on_mob_life
/datum/reagent/drug/aphrodisiac/proc/life_effects(mob/living/carbon/human/exposed_mob)
return
/// Runs on OD process after preference checks. Use this instead of overdose_process
/datum/reagent/drug/aphrodisiac/proc/overdose_effects(mob/living/carbon/human/exposed_mob)
return
/datum/reagent/drug/aphrodisiac/on_mob_life(mob/living/carbon/human/exposed_mob)
. = ..()
if(life_pref_datum && exposed_mob.client?.prefs.read_preference(life_pref_datum) && ishuman(exposed_mob))
life_effects(exposed_mob)
/datum/reagent/drug/aphrodisiac/overdose_process(mob/living/carbon/human/exposed_mob)
. = ..()
if(overdose_pref_datum && exposed_mob.client?.prefs.read_preference(overdose_pref_datum) && ishuman(exposed_mob))
overdose_effects(exposed_mob)
/*
* APHRODISIACS
*/
///To notify, but not harm the player in terms of mood. Used for camphor, pentacamphor, succubus milk, and incubus draft.
/datum/mood_event/minor_overdose
timeout = 5 MINUTES
/datum/mood_event/minor_overdose/add_effects(drug_name)
description = "<span class='warning'>I think I took a bit too much [drug_name]...</span>\n"
//Crocin. Basic aphrodisiac with no consequences
/datum/reagent/drug/aphrodisiac/crocin
name = "crocin"
description = "Naturally found in the crocus and gardenia flowers, this drug acts as a natural and safe aphrodisiac."
taste_description = "strawberries"
color = "#FFADFF"
life_pref_datum = /datum/preference/toggle/erp/aphro
arousal_adjust_amount = 1
pleasure_adjust_amount = 0
pain_adjust_amount = 0
/// Probability of the chem triggering an emote, as a %, run on mob life
var/emote_probability = 3
/// Probability of the chem triggering a to_chat, as a %, run on mob life
var/thought_probability = 2
/// A list of possible emotes the chem is able to trigger
var/list/possible_aroused_emotes = list("moan", "blush")
/// A list of possible to_chat messages the chem is able to trigger
var/list/possible_aroused_thoughts = list("You feel frisky.", "You're having trouble suppressing your urges.", "You feel in the mood.")
/datum/reagent/drug/aphrodisiac/crocin/life_effects(mob/living/carbon/human/exposed_mob)
if(prob(emote_probability))
exposed_mob.emote(pick(possible_aroused_emotes))
if(prob(thought_probability))
var/displayed_thought = pick(possible_aroused_thoughts)
to_chat(exposed_mob, span_notice("[displayed_thought]"))
exposed_mob.adjustArousal(arousal_adjust_amount)
exposed_mob.adjustPleasure(pleasure_adjust_amount)
exposed_mob.adjustPain(pain_adjust_amount)
for(var/obj/item/organ/external/genital/mob_genitals in exposed_mob.external_organs)
if(!mob_genitals.aroused == AROUSAL_CANT)
mob_genitals.aroused = AROUSAL_FULL
mob_genitals.update_sprite_suffix()
exposed_mob.update_body()
//Hexacrocin. Advanced aphrodisiac that can cause brain traumas.
/datum/reagent/drug/aphrodisiac/crocin/hexacrocin
name = "hexacrocin"
description = "Chemically condensed form of basic crocin. This aphrodisiac is extremely powerful and addictive for most animals.\
Addiction withdrawals can cause brain damage and shortness of breath. Overdose can lead to brain traumas."
taste_description = "liquid desire"
color = "#FF2BFF"
overdose_threshold = 25
overdose_pref_datum = /datum/preference/toggle/erp/bimbofication
emote_probability = 5
thought_probability = 5
arousal_adjust_amount = 2
pleasure_adjust_amount = 1.5
pain_adjust_amount = 0.2
possible_aroused_thoughts = list("You feel a bit hot.", "You feel strong sexual urges.", "You feel in the mood.", "You're ready to go down on someone.")
/// A list of possible to_chat messages the chem is able to trigger after enough cycles in the mobs system
var/list/extreme_aroused_thoughts = list("You need to fuck someone!", "You're bursting with sexual tension!", "You can't get sex off your mind!")
/// How many cycles the chem has to be in the mob's system before triggering extreme effects
var/extreme_thought_threshold = 25
/datum/reagent/drug/aphrodisiac/crocin/hexacrocin/life_effects(mob/living/carbon/human/exposed_mob)
. = ..()
if(prob(thought_probability) && current_cycle >= extreme_thought_threshold)
var/displayed_extreme_thought = pick(extreme_aroused_thoughts)
to_chat(exposed_mob, span_purple("[displayed_extreme_thought]"))
/datum/reagent/drug/aphrodisiac/crocin/hexacrocin/overdose_effects(mob/living/carbon/human/exposed_mob)
if(prob(95) || HAS_TRAIT(exposed_mob, TRAIT_BIMBO))
return ..()
to_chat(exposed_mob, span_purple("Your libido is going haywire! It feels like speaking is much harder..."))
exposed_mob.gain_trauma(/datum/brain_trauma/very_special/bimbo, TRAUMA_RESILIENCE_BASIC)
ADD_TRAIT(exposed_mob, TRAIT_BIMBO, LEWDCHEM_TRAIT)
//Dopamine. Generates in character after orgasm.
/datum/reagent/drug/aphrodisiac/dopamine
name = "dopamine...?"
description = "Pure happiness"
taste_description = "an indescribable, slightly sour taste. Something in it relaxes you, filling you with pleasure."
color = "#97ffee"
glass_name = "dopamine"
glass_desc = "Delicious flavored reagent. You feel happy even looking at it."
reagent_state = LIQUID
overdose_threshold = 10
life_pref_datum = /datum/preference/toggle/erp/aphro
overdose_pref_datum = /datum/preference/toggle/erp/aphro
arousal_adjust_amount = 0.5
pleasure_adjust_amount = 0.3
pain_adjust_amount = -0.5
/// How druggy the chem will make the mob
var/drugginess_amount = 5 SECONDS
/// How likely the drug is to make the mob druggy per life process
var/drugginess_chance = 7
/datum/reagent/drug/aphrodisiac/dopamine/on_mob_add(mob/living/carbon/human/exposed_mob)
if(!(exposed_mob.client?.prefs.read_preference(/datum/preference/toggle/erp/aphro)))
return ..()
exposed_mob.add_mood_event("[type]_start", /datum/mood_event/orgasm, name)
..()
/datum/reagent/drug/aphrodisiac/dopamine/life_effects(mob/living/carbon/human/exposed_mob)
exposed_mob.set_drugginess(drugginess_amount)
if(prob(drugginess_chance))
exposed_mob.emote(pick("twitch", "drool", "moan", "giggle", "shaking"))
/datum/reagent/drug/aphrodisiac/dopamine/overdose_start(mob/living/carbon/human/exposed_mob)
. = ..()
to_chat(exposed_mob, span_purple("You feel so happy!"))
exposed_mob.add_mood_event("[type]_overdose", /datum/mood_event/overgasm, name)
/datum/reagent/drug/aphrodisiac/dopamine/overdose_effects(mob/living/carbon/human/exposed_mob)
if(!(exposed_mob.hallucination < volume && prob(20)))
return ..()
exposed_mob.adjustArousal(arousal_adjust_amount)
exposed_mob.adjustPleasure(pleasure_adjust_amount)
exposed_mob.adjustPain(pain_adjust_amount)
if(prob(2))
exposed_mob.emote(pick("moan", "twitch_s"))
/*
* ANAPHRODISIACS
*/
//Camphor. Used to reduce libido.
///Able to reset one's genital size back to normal upon OD, or alternatively, if the user sets the size and then disables the organ, that size.
/datum/reagent/drug/aphrodisiac/camphor
name = "Camphor"
description = "Naturally found in some species of evergreen trees, camphor is a waxy substance. When ingested by most animals it acts as an anaphrodisiac, \
reducing libido and calming them. Non-habit forming and non-addictive."
taste_description = "dull bitterness"
taste_mult = 2
color = "#D9D9D9"//rgb(157, 157, 157)
reagent_state = SOLID
overdose_threshold = 25 ///OD will reset sizes of genitals back to normal.
life_pref_datum = /datum/preference/toggle/erp/aphro
arousal_adjust_amount = -12
pleasure_adjust_amount = -3
overdose_pref_datum = /datum/preference/toggle/erp ///This will work without having aphrodisiacs enabled.
/datum/reagent/drug/aphrodisiac/camphor/life_effects(mob/living/carbon/human/exposed_mob)
var/old_arousal = exposed_mob.arousal
exposed_mob.adjustArousal(arousal_adjust_amount)
exposed_mob.adjustPleasure(pleasure_adjust_amount)
if(exposed_mob.arousal <= 0 && old_arousal > 0)
to_chat(exposed_mob, span_notice("You no longer feel aroused."))
/datum/reagent/drug/aphrodisiac/camphor/overdose_effects(mob/living/carbon/human/exposed_mob)
///Grows and shrinks organs depending on prefs, returning to normal. Offers a way of resetting succubus milk / incubus draft sizes, but not organs.
///Resets gender if prefs enabled.
if(exposed_mob.client?.prefs.read_preference(/datum/preference/toggle/erp/gender_change))
if(exposed_mob.gender != exposed_mob.client?.prefs?.read_preference(/datum/preference/choiced/gender))
exposed_mob.set_gender(exposed_mob.client?.prefs?.read_preference(/datum/preference/choiced/gender))
if(exposed_mob.getorganslot(ORGAN_SLOT_BREASTS))
var/obj/item/organ/external/genital/breasts/mob_breasts = exposed_mob.getorganslot(ORGAN_SLOT_BREASTS)
if(exposed_mob.client?.prefs.read_preference(/datum/preference/numeric/breasts_size))
var/original_breast_size = exposed_mob.client?.prefs.read_preference(/datum/preference/numeric/breasts_size)
if(mob_breasts?.genital_size > original_breast_size)
mob_breasts.genital_size -= breast_size_reduction_step
mob_breasts.update_sprite_suffix()
exposed_mob.update_body()
return
if(mob_breasts?.genital_size < original_breast_size)
mob_breasts.genital_size += breast_size_increase_step
mob_breasts.update_sprite_suffix()
exposed_mob.update_body()
return
if(exposed_mob.getorganslot(ORGAN_SLOT_PENIS))
var/obj/item/organ/external/genital/penis/mob_penis = exposed_mob.getorganslot(ORGAN_SLOT_PENIS)
if(exposed_mob.client?.prefs?.read_preference(/datum/preference/numeric/penis_length))
var/original_penis_length = exposed_mob.client?.prefs.read_preference(/datum/preference/numeric/penis_length)
var/original_penis_girth = exposed_mob.client?.prefs.read_preference(/datum/preference/numeric/penis_girth)
///Run to go through girth first.
if(mob_penis?.girth > original_penis_girth)
mob_penis.girth -= penis_girth_reduction_step
mob_penis.update_sprite_suffix()
exposed_mob.update_body()
if(mob_penis?.girth < original_penis_girth)
mob_penis.girth += penis_girth_increase_step
mob_penis.update_sprite_suffix()
exposed_mob.update_body()
///No returns in order to continue code.
if(mob_penis?.genital_size > original_penis_length)
mob_penis.genital_size -= penis_size_reduction_step
mob_penis.update_sprite_suffix()
exposed_mob.update_body()
return
if(mob_penis?.genital_size < original_penis_length)
mob_penis.genital_size += penis_length_increase_step
mob_penis.update_sprite_suffix()
exposed_mob.update_body()
return
if(exposed_mob.getorganslot(ORGAN_SLOT_TESTICLES))
var/obj/item/organ/external/genital/testicles/mob_testicles = exposed_mob.getorganslot(ORGAN_SLOT_TESTICLES)
if(exposed_mob.client?.prefs?.read_preference(/datum/preference/numeric/balls_size))
var/original_ball_size = exposed_mob.client?.prefs.read_preference(/datum/preference/numeric/balls_size)
if(mob_testicles?.genital_size > original_ball_size)
mob_testicles.genital_size -= 1
mob_testicles.update_sprite_suffix()
exposed_mob.update_body()
return
if(mob_testicles?.genital_size < original_ball_size)
mob_testicles.genital_size += 1
mob_testicles.update_sprite_suffix()
exposed_mob.update_body()
return
// Pentacamphor. Used to purge crocin and hexacrocin. Can permanently disable arousal or cure bimbofication on overdose.
/datum/reagent/drug/aphrodisiac/camphor/pentacamphor
name = "Pentacamphor"
description = "Chemically condensed camphor. Causes an extreme reduction in libido and a permanent one if overdosed. Non-addictive."
taste_description = "tranquil celibacy"
color = "#D9D9D9"//rgb(255, 255, 255)
reagent_state = SOLID
overdose_threshold = 20
arousal_adjust_amount = -18
overdose_pref_datum = /datum/preference/toggle/erp/aphro
/// How much of the given reagent to remove per operation
var/reagent_reduction_amount = 20
/datum/reagent/drug/aphrodisiac/camphor/pentacamphor/life_effects(mob/living/carbon/human/exposed_mob)
. = ..()
if(exposed_mob.reagents.has_reagent(/datum/reagent/drug/aphrodisiac/crocin))
exposed_mob.reagents.remove_reagent(/datum/reagent/drug/aphrodisiac/crocin, reagent_reduction_amount)
if(exposed_mob.reagents.has_reagent(/datum/reagent/drug/aphrodisiac/crocin/hexacrocin))
exposed_mob.reagents.remove_reagent(/datum/reagent/drug/aphrodisiac/crocin/hexacrocin, reagent_reduction_amount)
/datum/reagent/drug/aphrodisiac/camphor/pentacamphor/overdose_start(mob/living/carbon/human/exposed_mob)
if(!HAS_TRAIT(exposed_mob, TRAIT_NEVERBONER))
to_chat(exposed_mob, span_notice("You feel like you'll never feel aroused again..."))
ADD_TRAIT(exposed_mob, TRAIT_NEVERBONER, LEWDCHEM_TRAIT)
if(!HAS_TRAIT(exposed_mob, TRAIT_BIMBO))
return
exposed_mob.cure_trauma_type(/datum/brain_trauma/very_special/bimbo, TRAUMA_RESILIENCE_ABSOLUTE)
to_chat(exposed_mob, span_notice("Your mind is free. Your thoughts are pure and innocent once more."))
REMOVE_TRAIT(exposed_mob, TRAIT_BIMBO, LEWDCHEM_TRAIT)
/*
* GENITAL ENLARGEMENT CHEMICALS
*/
/*
* BREAST ENLARGEMENT
* Normal function increases the player's breast size.
* If the player's breasts are near or at the maximum size and they're wearing clothing, they press against the player's clothes and causes brute and oxygen damage.
* If gender change preference is enabled: Overdosing makes you female if male, makes the player grow breasts, sets the player's testicles to the minimum size, and shrinks the player's penis to a minimum size.
* If the gender change preference is not enabled: Overdosing will just make you grow breasts if you don't have any.
* Credit to Citadel for the original code before modification
*/
/datum/reagent/drug/aphrodisiac/breast_enlarger
name = "succubus milk"
description = "A volatile collodial mixture derived from milk that encourages mammary production via a potent estrogen mix."
color = "#E60584" // rgb: 96, 0, 255
taste_description = "a milky ice cream like flavour" /// Edited so it doesn't trail off and act strangely with other taste descriptions.
overdose_threshold = 20
metabolization_rate = 0.25
life_pref_datum = /datum/preference/toggle/erp/breast_enlargement
overdose_pref_datum = /datum/preference/toggle/erp ///Changed from breast_enlargement in order to have gender swapping as a separate feature within overdose.
/datum/reagent/drug/aphrodisiac/breast_enlarger/life_effects(mob/living/carbon/human/exposed_mob) //Increases breast size
var/obj/item/organ/external/genital/breasts/mob_breasts = exposed_mob.getorganslot(ORGAN_SLOT_BREASTS)
enlargement_amount += enlarger_increase_step
/// Adds a check for breasts in the first place. I HATE ERRORS.
if(!mob_breasts)
return
if(enlargement_amount >= enlargement_threshold)
if(mob_breasts?.genital_size >= max_breast_size)
return
mob_breasts.genital_size += breast_size_increase_step
mob_breasts.update_sprite_suffix()
exposed_mob.update_body()
enlargement_amount = 0
/// Words for the breasts when huge.
var/static/list/words_for_bigger = list("huge", "massive", "squishy", "gigantic", "rather large", "jiggly", "hefty", )
/// Synonyms for breasts.
var/static/list/boob_text_list = list("boobs", "tits", "breasts", )
/// Synonyms for the chest.
var/static/list/covered_boobs_list = list("bust", "chest", "bosom", )
/// Synonyms for bigger breasts.
var/static/list/bigger_boob_text_list = list("jigglies", "melons", "jugs", "boobies", "milkers", "boobs", "tits", "breasts", )
/// Wording chosen to expand the breasts, shown only to the mob.
var/static/list/action_text_list = list("expand outward to ", "grow out to ", "begin to enlarge, growing to ", "suddenly expand to ", "swell out to ", )
/// Wording chosen to be seen by other mobs, regardless of whether mob is clothed/unclothed.
var/static/list/public_bigger_action_text_list = list("expand and jiggle outward.", "grow a bit larger, bouncing about.", "seem a bit bigger than they were before.", "bounce and jiggle as they suddenly expand.", )
/// Wording chosen to be seen by other mobs, while mob is unclothed.
var/static/list/public_action_text_list = list("expand outward.", "seem to grow a bit larger.", "appear a bit bigger than they were before.", "bounce and jiggle as they suddenly expand.", )
/// Wording chosen to be seen by other mobs, while mob is clothed.
var/static/list/notice_boobs = list("seems to be a bit tighter.", "appears to be a bit bigger.", "seems to swell outward a bit.", )
/// Checks for cup size.
var/translation = mob_breasts.breasts_size_to_cup(mob_breasts.genital_size)
if(mob_breasts.visibility_preference == GENITAL_ALWAYS_SHOW || exposed_mob.is_topless())
switch(translation)
if("Flatchested")
return
if("beyond measurement")
exposed_mob.visible_message(span_notice("[exposed_mob]'s [pick(words_for_bigger)] [pick(bigger_boob_text_list)] [pick(public_bigger_action_text_list)]"))
to_chat(exposed_mob, span_purple("Your [pick(words_for_bigger)] [pick(bigger_boob_text_list)] [pick(action_text_list)]about [mob_breasts.genital_size] inches in diameter."))
return
else
if(mob_breasts?.genital_size >= (max_breast_size - 2))
exposed_mob.visible_message(span_notice("[exposed_mob]'s [pick(words_for_bigger)] [pick(bigger_boob_text_list)] [pick(public_bigger_action_text_list)]"))
to_chat(exposed_mob, span_purple("Your [pick(words_for_bigger)] [pick(bigger_boob_text_list)] [pick(action_text_list)]about [translation]-cups."))
return
else
exposed_mob.visible_message(span_notice("[exposed_mob]'s [pick(boob_text_list)] [pick(public_action_text_list)]"))
to_chat(exposed_mob, span_purple("Your [pick(boob_text_list)] [pick(action_text_list)]about [translation]-cups."))
return
else
switch(translation)
if("Flatchested")
return
if("beyond measurement")
exposed_mob.visible_message(span_notice("[exposed_mob]'s [pick(boob_text_list)] [pick(public_bigger_action_text_list)]"))
to_chat(exposed_mob, span_purple("Your [pick(words_for_bigger)] [pick(bigger_boob_text_list)] [pick(action_text_list)]about [mob_breasts.genital_size] inches in diameter."))
return
else
if(mob_breasts?.genital_size >= (max_breast_size - 2))
exposed_mob.visible_message(span_notice("[exposed_mob]'s [pick(boob_text_list)] [pick(public_bigger_action_text_list)]"))
to_chat(exposed_mob, span_purple("Your [pick(words_for_bigger)] [pick(bigger_boob_text_list)] [pick(action_text_list)]about [translation]-cups."))
return
else
exposed_mob.visible_message(span_notice("The area around [exposed_mob]'s [pick(covered_boobs_list)] [pick(notice_boobs)]"))
to_chat(exposed_mob, span_purple("Your [pick(boob_text_list)] [pick(action_text_list)]about [translation]-cups."))
return
if((mob_breasts?.genital_size >= (max_breast_size - 2)) && (exposed_mob.w_uniform || exposed_mob.wear_suit))
var/target_bodypart = exposed_mob.get_bodypart(BODY_ZONE_CHEST)
if(prob(damage_chance))
to_chat(exposed_mob, span_danger("Your breasts begin to strain against your clothes!"))
exposed_mob.adjustOxyLoss(5, 0)
exposed_mob.apply_damage(1, BRUTE, target_bodypart)
/datum/reagent/drug/aphrodisiac/breast_enlarger/overdose_effects(mob/living/carbon/human/exposed_mob) //Turns you into a female if character is male. Also supposed to add breasts but enlargement_amount'm too dumb to figure out how to make it work
var/obj/item/organ/external/genital/penis/mob_penis = exposed_mob.getorganslot(ORGAN_SLOT_PENIS)
var/obj/item/organ/external/genital/testicles/mob_testicles = exposed_mob.getorganslot(ORGAN_SLOT_TESTICLES)
if(exposed_mob.client?.prefs.read_preference(/datum/preference/toggle/erp/breast_enlargement))
/// Makes above comment actually work.
if(!exposed_mob.getorganslot(ORGAN_SLOT_BREASTS))
var/obj/item/organ/path = /obj/item/organ/external/genital/breasts
exposed_mob.dna.mutant_bodyparts["breasts"][MUTANT_INDEX_NAME] = "Pair"
path = new /obj/item/organ/external/genital/breasts
path.build_from_dna(exposed_mob.dna, "breasts")
path.Insert(exposed_mob, 0, FALSE)
var/obj/item/organ/external/genital/new_breasts = exposed_mob.getorganslot(ORGAN_SLOT_BREASTS)
new_breasts.genital_size = 2
new_breasts.update_sprite_suffix()
exposed_mob.update_body()
enlargement_amount = 0
if(new_breasts.visibility_preference == GENITAL_ALWAYS_SHOW || exposed_mob.is_topless())
exposed_mob.visible_message(span_notice("[exposed_mob]'s bust suddenly expands!"))
to_chat(exposed_mob, span_purple("Your chest feels warm, tingling with sensitivity as it expands outward."))
return
else
exposed_mob.visible_message(span_notice("The area around [exposed_mob]'s chest suddenly bounces a bit."))
to_chat(exposed_mob, span_purple("Your chest feels warm, tingling with sensitivity as it strains against your clothes."))
return
///Separates gender change stuff from breast growth.
if(exposed_mob.client?.prefs.read_preference(/datum/preference/toggle/erp/gender_change))
if(exposed_mob.gender == MALE)
exposed_mob.set_gender(FEMALE)
exposed_mob.physique = exposed_mob.gender
exposed_mob.update_body()
exposed_mob.update_mutations_overlay()
if(!mob_penis)
return
if(exposed_mob.client?.prefs.read_preference(/datum/preference/toggle/erp/penis_enlargement)) ///To do cock shrinkage, check if prefs allow for this.
if(mob_penis.genital_size > penis_min_length)
mob_penis.genital_size -= penis_size_reduction_step
mob_penis.update_sprite_suffix()
exposed_mob.update_body()
if(mob_penis.girth > penis_minimum_girth)
mob_penis.girth -= penis_girth_reduction_step
mob_penis.update_sprite_suffix()
exposed_mob.update_body()
if(!mob_testicles || mob_testicles.genital_size <= 1)
return
mob_testicles.genital_size -= 1
return
/*
* PENIS ENLARGEMENT
* Normal function increases the player's penis size.
* If the player's penis is near or at the maximum size and they're wearing clothing, it presses against the player's clothes and causes brute damage.
* If gender change preference is enabled: Overdosing makes you male if female, makes the player grow a cock, and shrinks the player's breasts to a minimum size.
* If the gender change preference is not enabled: Overdosing will just make you grow a cock if you don't have one.
*/
/datum/reagent/drug/aphrodisiac/penis_enlarger
name = "incubus draft"
description = "A volatile collodial mixture derived from various masculine solutions that encourages a larger gentleman's package via a potent testosterone mix."
color = "#888888"
taste_description = "chinese dragon powder"
overdose_threshold = 20 ///ODing makes you male and shrinks female genitals if gender change prefs are enabled. Otherwise, grows a cock.
metabolization_rate = 0.25
life_pref_datum = /datum/preference/toggle/erp/penis_enlargement
overdose_pref_datum = /datum/preference/toggle/erp ///Changed from penis_enlargement in order to have gender swapping as a separate feature within overdose.
/datum/reagent/drug/aphrodisiac/penis_enlarger/life_effects(mob/living/carbon/human/exposed_mob)
var/obj/item/organ/external/genital/penis/mob_penis = exposed_mob.getorganslot(ORGAN_SLOT_PENIS)
enlargement_amount += enlarger_increase_step
/// Add yet another check because I hate errors!!
if(!mob_penis)
return
if(enlargement_amount >= enlargement_threshold)
if(mob_penis?.genital_size >= penis_max_length)
return ..()
mob_penis.genital_size += penis_length_increase_step
///Improvision to girth to not make it random chance.
if(mob_penis?.girth < penis_max_girth) ///Because any higher is ridiculous. However, should still allow for regular penis growth.
mob_penis.girth = round(mob_penis.girth + (mob_penis.genital_size/mob_penis.girth))
mob_penis.update_sprite_suffix()
exposed_mob.update_body()
enlargement_amount = 0
/// Words for the cock when huge.
var/static/list/words_for_bigger_cock = list("huge", "massive", "gigantic", "rather lengthy", "colossal", "hefty", )
/// Synonyms for cock.
var/static/list/cock_text_list = list("cock", "penis", "dick", "member", "richard", "johnston", "johnson", )
/// Synonyms for bigger cock.
var/static/list/bigger_cock_text_list = list("rod", "shaft", "cock", "penis", "dick", "member", "richard", "johnston", "johnson", )
/// Wording chosen to extend the cock, shown only to the mob.
var/static/list/cock_action_text_list = list("extends to ", "grows out to ", "begins to enlarge, growing to ", "suddenly expands to ", "lengthens out to ", )
/// Wording chosen to be seen by other mobs, while mob is unclothed.
var/static/list/public_cock_action_text_list = list("expands by an inch or so.", "appears to grow a bit longer.", "seems a bit bigger than it was before.", "suddenly lengthens about an inch or two.", )
if(mob_penis.visibility_preference == GENITAL_ALWAYS_SHOW || exposed_mob.is_bottomless())
if(mob_penis?.genital_size >= (penis_max_length - 2))
if(exposed_mob.dna.features["penis_sheath"] == SHEATH_SLIT)
if(mob_penis.aroused != AROUSAL_FULL)
to_chat(exposed_mob, span_purple("Your [pick(words_for_bigger_cock)] [pick(bigger_cock_text_list)] [pick(cock_action_text_list)]about [mob_penis.genital_size] inches long, and [mob_penis.girth] inches in circumference."))
return
exposed_mob.visible_message(span_notice("[exposed_mob]'s [pick(words_for_bigger_cock)] [pick(bigger_cock_text_list)] [pick(public_cock_action_text_list)]"))
to_chat(exposed_mob, span_purple("Your [pick(words_for_bigger_cock)] [pick(bigger_cock_text_list)] [pick(cock_action_text_list)]about [mob_penis.genital_size] inches long, and [mob_penis.girth] inches in circumference."))
return
else
if(exposed_mob.dna.features["penis_sheath"] == SHEATH_SLIT)
if(mob_penis.aroused != AROUSAL_FULL)
to_chat(exposed_mob, span_purple("Your [pick(cock_text_list)] [pick(cock_action_text_list)]about [mob_penis.genital_size] inches long, and [mob_penis.girth] inches in circumference."))
return
exposed_mob.visible_message(span_notice("[exposed_mob]'s [pick(cock_text_list)] [pick(public_cock_action_text_list)]"))
to_chat(exposed_mob, span_purple("Your [pick(cock_text_list)] [pick(cock_action_text_list)]about [mob_penis.genital_size] inches long, and [mob_penis.girth] inches in circumference."))
return
else
if(mob_penis?.genital_size >= (penis_max_length - 2))
to_chat(exposed_mob, span_purple("Your [pick(words_for_bigger_cock)] [pick(bigger_cock_text_list)] [pick(cock_action_text_list)]about [mob_penis.genital_size] inches long, and [mob_penis.girth] inches in circumference."))
return
else
to_chat(exposed_mob, span_purple("Your [pick(cock_text_list)] [pick(cock_action_text_list)]about [mob_penis.genital_size] inches long, and [mob_penis.girth] inches in circumference."))
return
if((mob_penis?.genital_size >= (penis_max_length - 2)) && (exposed_mob.w_uniform || exposed_mob.wear_suit))
var/target_bodypart = exposed_mob.get_bodypart(BODY_ZONE_PRECISE_GROIN)
if(prob(damage_chance))
to_chat(exposed_mob, span_danger("You feel a tightness in your pants!"))
exposed_mob.apply_damage(1, BRUTE, target_bodypart)
return ..()
/datum/reagent/drug/aphrodisiac/penis_enlarger/overdose_effects(mob/living/carbon/human/exposed_mob)
if(exposed_mob.client?.prefs.read_preference(/datum/preference/toggle/erp/penis_enlargement))
if(!exposed_mob.getorganslot(ORGAN_SLOT_PENIS))
///Check if human. If not do messy code. (This only supports lizards and human penises (for now))
exposed_mob.dna.features["penis_sheath"] = SHEATH_NONE
exposed_mob.dna.mutant_bodyparts["penis"][MUTANT_INDEX_NAME] = "Human"
exposed_mob.dna.mutant_bodyparts["testicles"][MUTANT_INDEX_NAME] = "Pair"
if((exposed_mob.dna.species.id == SPECIES_HUMAN) && (exposed_mob.dna.species.id != SPECIES_LIZARD) && (exposed_mob.dna.species.id != SPECIES_LIZARD_ASH))
if (!exposed_mob.getorganslot(ORGAN_SLOT_TESTICLES))
var/obj/item/organ/balls_path = /obj/item/organ/external/genital/testicles
balls_path = new /obj/item/organ/external/genital/testicles
balls_path.build_from_dna(exposed_mob.dna, "testicles")
balls_path.Insert(exposed_mob, 0, FALSE)
var/obj/item/organ/external/genital/new_balls = exposed_mob.getorganslot(ORGAN_SLOT_TESTICLES)
new_balls.genital_size = 1
new_balls.update_sprite_suffix()
if((exposed_mob.dna.species.id == SPECIES_LIZARD) || (exposed_mob.dna.species.id == SPECIES_LIZARD_ASH))
exposed_mob.dna.features["penis_sheath"] = SHEATH_SLIT
exposed_mob.dna.mutant_bodyparts["penis"][MUTANT_INDEX_NAME] = "Flared"
exposed_mob.dna.mutant_bodyparts["penis"][MUTANT_INDEX_COLOR_LIST] = list("#FFB6C1")
exposed_mob.dna.mutant_bodyparts["testicles"][MUTANT_INDEX_NAME] = "Internal"
if (!exposed_mob.getorganslot(ORGAN_SLOT_TESTICLES))
var/obj/item/organ/balls_path = /obj/item/organ/external/genital/testicles
balls_path = new /obj/item/organ/external/genital/testicles
balls_path.build_from_dna(exposed_mob.dna, "testicles")
balls_path.Insert(exposed_mob, 0, FALSE)
var/obj/item/organ/external/genital/new_balls = exposed_mob.getorganslot(ORGAN_SLOT_TESTICLES)
new_balls.genital_size = 1
new_balls.update_sprite_suffix()
var/obj/item/organ/cock_path = /obj/item/organ/external/genital/penis
cock_path = new /obj/item/organ/external/genital/penis
cock_path.build_from_dna(exposed_mob.dna, "penis")
cock_path.Insert(exposed_mob, 0, FALSE)
var/obj/item/organ/external/genital/penis/new_penis = exposed_mob.getorganslot(ORGAN_SLOT_PENIS)
new_penis.genital_size = 4
new_penis.girth = 3
new_penis.update_sprite_suffix()
exposed_mob.update_body()
to_chat(exposed_mob, span_purple("Your crotch feels warm as something suddenly sprouts between your legs."))
///Makes the balls bigger if they're small.
var/obj/item/organ/external/genital/testicles/mob_testicles = exposed_mob.getorganslot(ORGAN_SLOT_TESTICLES)
if(mob_testicles)
if(mob_testicles.genital_size > 2)
return
mob_testicles.genital_size = 2
///Separates gender change stuff from cock growth.
var/obj/item/organ/external/genital/breasts/mob_breasts = exposed_mob.getorganslot(ORGAN_SLOT_BREASTS)
if(exposed_mob.client?.prefs.read_preference(/datum/preference/toggle/erp/gender_change))
if(exposed_mob.gender == FEMALE)
exposed_mob.set_gender(MALE)
exposed_mob.physique = exposed_mob.gender
exposed_mob.update_body()
exposed_mob.update_mutations_overlay()
if(!mob_breasts)
return
if(exposed_mob.client?.prefs.read_preference(/datum/preference/toggle/erp/breast_enlargement)) ///To do breast shrinkage, check if prefs allow for this.
if(mob_breasts.genital_size > breast_minimum_size)
mob_breasts.genital_size -= breast_size_reduction_step
mob_breasts.update_sprite_suffix()
exposed_mob.update_body()
return
/*
* CHEMICAL REACTIONS
*/
/datum/chemical_reaction
/// Will this reaction be disabled by the ERP config being turned off?
var/erp_reaction = FALSE
/datum/chemical_reaction/crocin
results = list(/datum/reagent/drug/aphrodisiac/crocin = 6)
required_reagents = list(/datum/reagent/carbon = 2, /datum/reagent/hydrogen = 2, /datum/reagent/oxygen = 2, /datum/reagent/water = 1)
required_temp = 400
mix_message = "The mixture boils off a pink vapor..."
erp_reaction = TRUE
/datum/chemical_reaction/hexacrocin
results = list(/datum/reagent/drug/aphrodisiac/crocin/hexacrocin = 1)
required_reagents = list(/datum/reagent/drug/aphrodisiac/crocin = 6, /datum/reagent/phenol = 1)
required_temp = 600
mix_message = "The mixture rapidly condenses and darkens in color..."
erp_reaction = TRUE
/datum/chemical_reaction/camphor
results = list(/datum/reagent/drug/aphrodisiac/camphor = 6)
required_reagents = list(/datum/reagent/carbon = 2, /datum/reagent/hydrogen = 2, /datum/reagent/oxygen = 2, /datum/reagent/sulfur = 1)
required_temp = 400
mix_message = "The mixture boils off a yellow, smelly vapor..."
erp_reaction = TRUE
/datum/chemical_reaction/pentacamphor
results = list(/datum/reagent/drug/aphrodisiac/camphor/pentacamphor = 1)
required_reagents = list(/datum/reagent/drug/aphrodisiac/camphor = 5, /datum/reagent/acetone = 1)
required_temp = 500
mix_message = "The mixture thickens and heats up slighty..."
erp_reaction = TRUE
/datum/chemical_reaction/cum
results = list(/datum/reagent/consumable/cum = 5)
required_reagents = list(/datum/reagent/blood = 2, /datum/reagent/consumable/milk = 2, /datum/reagent/consumable/salt = 1)
mix_message = "The mixture turns into a gooey, musky white liquid..."
erp_reaction = TRUE
/datum/chemical_reaction/breast_enlarger
results = list(/datum/reagent/drug/aphrodisiac/breast_enlarger = 8)
required_reagents = list(/datum/reagent/medicine/salglu_solution = 1, /datum/reagent/consumable/milk = 1, /datum/reagent/medicine/c2/synthflesh = 2, /datum/reagent/silicon = 3, /datum/reagent/drug/aphrodisiac/crocin = 3)
mix_message = "the reaction gives off a mist of milk."
erp_reaction = TRUE
/datum/chemical_reaction/penis_enlarger
results = list(/datum/reagent/drug/aphrodisiac/penis_enlarger = 8)
required_reagents = list(/datum/reagent/blood = 5, /datum/reagent/medicine/c2/synthflesh = 2, /datum/reagent/carbon = 2, /datum/reagent/drug/aphrodisiac/crocin = 2, /datum/reagent/medicine/salglu_solution = 1)
mix_message = "the reaction gives off a mist of milk."
erp_reaction = TRUE
/*
* PREMADE CONTAINERS
*/
// BOTTLES
/obj/item/reagent_containers/cup/bottle/crocin
name = "crocin bottle"
desc = "A bottle of mild aphrodisiac. Increases libido."
list_reagents = list(/datum/reagent/drug/aphrodisiac/crocin = 30)
/obj/item/reagent_containers/cup/bottle/hexacrocin
name = "hexacrocin bottle"
desc = "A bottle of strong aphrodisiac. Increases libido. Potentially dangerous."
list_reagents = list(/datum/reagent/drug/aphrodisiac/crocin/hexacrocin = 30)
/obj/item/reagent_containers/cup/bottle/dopamine
name = "dopamine bottle"
desc = "Pure pleasure and happines in a bottle."
list_reagents = list(/datum/reagent/drug/aphrodisiac/dopamine = 30)
/obj/item/reagent_containers/cup/bottle/camphor
name = "camphor bottle"
desc = "A bottle of mild anaphrodisiac. Reduces libido."
list_reagents = list(/datum/reagent/drug/aphrodisiac/camphor = 30)
/obj/item/reagent_containers/cup/bottle/pentacamphor
name = "pentacamphor bottle"
desc = "A bottle of strong anaphrodisiac. Reduces libido."
list_reagents = list(/datum/reagent/drug/aphrodisiac/camphor/pentacamphor = 30)
/obj/item/reagent_containers/cup/bottle/breast_enlarger
name = "succubus milk bottle"
desc = "A bottle of strong breast enlargement reagent."
list_reagents = list(/datum/reagent/drug/aphrodisiac/breast_enlarger = 30)
/obj/item/reagent_containers/cup/bottle/penis_enlarger
name = "incubus draft bottle"
desc = "A bottle of strong penis enlargement reagent."
list_reagents = list(/datum/reagent/drug/aphrodisiac/penis_enlarger = 30)
// PILLS
/obj/item/reagent_containers/pill/crocin
name = "crocin pill (10u)"
desc = "I've fallen, and I can't get it up!"
icon = 'modular_skyrat/modules/modular_items/lewd_items/icons/obj/lewd_items/lewd_pills.dmi'
icon_state = "crocin"
list_reagents = list(/datum/reagent/drug/aphrodisiac/crocin = 10)
/obj/item/reagent_containers/pill/hexacrocin
name = "hexacrocin pill (10u)"
desc = "Pill in creepy heart form."
icon = 'modular_skyrat/modules/modular_items/lewd_items/icons/obj/lewd_items/lewd_pills.dmi'
icon_state = "hexacrocin"
list_reagents = list(/datum/reagent/drug/aphrodisiac/crocin/hexacrocin = 10)
/obj/item/reagent_containers/pill/dopamine
name = "dopamine pill (5u)"
desc = "Feelings of orgasm, contained in a pill... Weird."
icon = 'modular_skyrat/modules/modular_items/lewd_items/icons/obj/lewd_items/lewd_pills.dmi'
icon_state = "dopamine"
list_reagents = list(/datum/reagent/drug/aphrodisiac/dopamine = 5)
/obj/item/reagent_containers/pill/camphor
name = "camphor pill (10u)"
desc = "For the early bird."
icon = 'modular_skyrat/modules/modular_items/lewd_items/icons/obj/lewd_items/lewd_pills.dmi'
icon_state = "camphor"
list_reagents = list(/datum/reagent/drug/aphrodisiac/camphor = 10)
/obj/item/reagent_containers/pill/pentacamphor
name = "pentacamphor pill (10u)"
desc = "The chemical equivalent of horny jail."
icon = 'modular_skyrat/modules/modular_items/lewd_items/icons/obj/lewd_items/lewd_pills.dmi'
icon_state = "pentacamphor"
list_reagents = list(/datum/reagent/drug/aphrodisiac/camphor/pentacamphor = 10)
@@ -0,0 +1,34 @@
/obj/item/reagent_containers/cup/bottle/crocin
name = "crocin bottle"
desc = "A bottle of mild aphrodisiac. Increases libido."
list_reagents = list(/datum/reagent/drug/aphrodisiac/crocin = 30)
/obj/item/reagent_containers/cup/bottle/hexacrocin
name = "hexacrocin bottle"
desc = "A bottle of strong aphrodisiac. Increases libido. Potentially dangerous."
list_reagents = list(/datum/reagent/drug/aphrodisiac/crocin/hexacrocin = 30)
/obj/item/reagent_containers/cup/bottle/dopamine
name = "dopamine bottle"
desc = "Pure pleasure and happines in a bottle."
list_reagents = list(/datum/reagent/drug/aphrodisiac/dopamine = 30)
/obj/item/reagent_containers/cup/bottle/camphor
name = "camphor bottle"
desc = "A bottle of mild anaphrodisiac. Reduces libido."
list_reagents = list(/datum/reagent/drug/aphrodisiac/camphor = 30)
/obj/item/reagent_containers/cup/bottle/pentacamphor
name = "pentacamphor bottle"
desc = "A bottle of strong anaphrodisiac. Reduces libido."
list_reagents = list(/datum/reagent/drug/aphrodisiac/camphor/pentacamphor = 30)
/obj/item/reagent_containers/cup/bottle/succubus_milk
name = "succubus milk bottle"
desc = "A bottle of strong breast enlargement reagent."
list_reagents = list(/datum/reagent/drug/aphrodisiac/succubus_milk = 30)
/obj/item/reagent_containers/cup/bottle/incubus_draft
name = "incubus draft bottle"
desc = "A bottle of strong penis enlargement reagent."
list_reagents = list(/datum/reagent/drug/aphrodisiac/incubus_draft = 30)
@@ -0,0 +1,34 @@
/obj/item/reagent_containers/pill/crocin
name = "crocin pill (10u)"
desc = "I've fallen, and I can't get it up!"
icon = 'modular_skyrat/modules/modular_items/lewd_items/icons/obj/lewd_items/lewd_pills.dmi'
icon_state = "crocin"
list_reagents = list(/datum/reagent/drug/aphrodisiac/crocin = 10)
/obj/item/reagent_containers/pill/hexacrocin
name = "hexacrocin pill (10u)"
desc = "Pill in creepy heart form."
icon = 'modular_skyrat/modules/modular_items/lewd_items/icons/obj/lewd_items/lewd_pills.dmi'
icon_state = "hexacrocin"
list_reagents = list(/datum/reagent/drug/aphrodisiac/crocin/hexacrocin = 10)
/obj/item/reagent_containers/pill/dopamine
name = "dopamine pill (5u)"
desc = "Feelings of orgasm, contained in a pill... Weird."
icon = 'modular_skyrat/modules/modular_items/lewd_items/icons/obj/lewd_items/lewd_pills.dmi'
icon_state = "dopamine"
list_reagents = list(/datum/reagent/drug/aphrodisiac/dopamine = 5)
/obj/item/reagent_containers/pill/camphor
name = "camphor pill (10u)"
desc = "For the early bird."
icon = 'modular_skyrat/modules/modular_items/lewd_items/icons/obj/lewd_items/lewd_pills.dmi'
icon_state = "camphor"
list_reagents = list(/datum/reagent/drug/aphrodisiac/camphor = 10)
/obj/item/reagent_containers/pill/pentacamphor
name = "pentacamphor pill (10u)"
desc = "The chemical equivalent of horny jail."
icon = 'modular_skyrat/modules/modular_items/lewd_items/icons/obj/lewd_items/lewd_pills.dmi'
icon_state = "pentacamphor"
list_reagents = list(/datum/reagent/drug/aphrodisiac/camphor/pentacamphor = 10)
@@ -0,0 +1,6 @@
///To notify, but not harm the player in terms of mood. Used for camphor, pentacamphor, succubus milk, and incubus draft.
/datum/mood_event/minor_overdose
timeout = 5 MINUTES
/datum/mood_event/minor_overdose/add_effects(drug_name)
description = "<span class='warning'>I think I took a bit too much [drug_name]...</span>\n"
@@ -0,0 +1,71 @@
// The base ERP chem. It handles pref and human type checks for you, so ALL chems relating to ERP should be subtypes of this.
/datum/reagent/drug/aphrodisiac
name = "liquid ERP"
description = "ERP in its liquified form. Complain to a coder."
/// What preference you need enabled for effects on life
var/life_pref_datum = /datum/preference/toggle/erp
/// What preference you need enabled for effects on overdose
var/overdose_pref_datum = /datum/preference/toggle/erp
/// The amount to adjust the mob's arousal by
var/arousal_adjust_amount = 1
/// The amount to adjust the mob's pleasure by
var/pleasure_adjust_amount = 0
/// The amount to adjust the mob's pain by
var/pain_adjust_amount = 0
// Vars for enlargement chems from here on
/// Counts up to a threshold before triggering enlargement effects
var/enlargement_amount = 0
/// How much to increase the count by each process
var/enlarger_increase_step = 5
/// Count to reach before effects
var/enlargement_threshold = 100
/// % chance for damage to be applied when the organ is too large and the mob is clothed
var/damage_chance = 20
/// Largest length the chem can make a mob's penis
var/penis_max_length = PENIS_MAX_LENGTH
/// Smallest size the chem can make a mob's penis
var/penis_min_length = PENIS_MIN_LENGTH
/// How much the penis is increased in size each time it's run
var/penis_length_increase_step = 1
/// How much the penis is increased in girth each time it's run
var/penis_girth_increase_step = 1
/// Largest girth the chem can make a mob's penis
var/penis_max_girth = PENIS_MAX_GIRTH
/// Smallest girth the chem can make a mob's penis
var/penis_minimum_girth = 2
/// How much to reduce the size of the penis each time it's run
var/penis_size_reduction_step = 2
/// How much to reduce the girth of the penis each time it's run
var/penis_girth_reduction_step = 2
/// Largest size the chem can make a mob's breasts
var/max_breast_size = 16
/// How much breasts are increased in size each time it's run
var/breast_size_increase_step = 1
/// Smallest size the chem can make a mob's breasts
var/breast_minimum_size = 2
/// How much to reduce the size of the breasts each time it's run
var/breast_size_reduction_step = 1
/// Runs on life after preference checks. Use this instead of on_mob_life
/datum/reagent/drug/aphrodisiac/proc/life_effects(mob/living/carbon/human/exposed_mob)
return
/// Runs on OD process after preference checks. Use this instead of overdose_process
/datum/reagent/drug/aphrodisiac/proc/overdose_effects(mob/living/carbon/human/exposed_mob)
return
/datum/reagent/drug/aphrodisiac/on_mob_life(mob/living/carbon/human/exposed_mob)
. = ..()
if(life_pref_datum && exposed_mob.client?.prefs.read_preference(life_pref_datum) && ishuman(exposed_mob))
life_effects(exposed_mob)
/datum/reagent/drug/aphrodisiac/overdose_process(mob/living/carbon/human/exposed_mob)
. = ..()
if(overdose_pref_datum && exposed_mob.client?.prefs.read_preference(overdose_pref_datum) && ishuman(exposed_mob))
overdose_effects(exposed_mob)
@@ -0,0 +1,3 @@
/datum/chemical_reaction
/// Will this reaction be disabled by the ERP config being turned off?
var/erp_reaction = FALSE
@@ -0,0 +1,9 @@
/datum/reagent/consumable/breast_milk
name = "breast milk"
description = "This looks familiar... Wait, it's milk!"
taste_description = "warm and creamy"
color = "#ffffffff"
glass_icon_state = "glass_white"
glass_name = "glass of breast milk"
glass_desc = "almost like normal milk."
reagent_state = LIQUID
@@ -0,0 +1,94 @@
// Camphor. Used to reduce libido.
/// Able to reset one's genital size back to normal upon OD, or alternatively, if the user sets the size and then disables the organ, that size.
/datum/reagent/drug/aphrodisiac/camphor
name = "Camphor"
description = "Naturally found in some species of evergreen trees, camphor is a waxy substance. When ingested by most animals it acts as an anaphrodisiac, \
reducing libido and calming them. Non-habit forming and non-addictive. This is not an aphrodisiac."
taste_description = "dull bitterness"
taste_mult = 2
color = "#D9D9D9"
reagent_state = SOLID
overdose_threshold = 25 // OD will reset sizes of genitals back to normal.
life_pref_datum = /datum/preference/toggle/erp/aphro
arousal_adjust_amount = -12
pleasure_adjust_amount = -3
overdose_pref_datum = /datum/preference/toggle/erp // This will work without having aphrodisiacs enabled.
/datum/reagent/drug/aphrodisiac/camphor/life_effects(mob/living/carbon/human/exposed_mob)
var/old_arousal = exposed_mob.arousal
exposed_mob.adjust_arousal(arousal_adjust_amount)
exposed_mob.adjust_pleasure(pleasure_adjust_amount)
if(exposed_mob.arousal <= 0 && old_arousal > 0)
to_chat(exposed_mob, span_notice("You no longer feel aroused."))
/datum/reagent/drug/aphrodisiac/camphor/overdose_effects(mob/living/carbon/human/exposed_mob)
var/modified_genitals = FALSE
// Grows and shrinks organs depending on prefs, returning to normal. Offers a way of resetting succubus milk / incubus draft sizes, but not organs.
// Resets gender if prefs enabled.
if(exposed_mob.client?.prefs.read_preference(/datum/preference/toggle/erp/gender_change) && exposed_mob.gender != exposed_mob.client?.prefs?.read_preference(/datum/preference/choiced/gender))
exposed_mob.set_gender(exposed_mob.client?.prefs?.read_preference(/datum/preference/choiced/gender))
if(exposed_mob.getorganslot(ORGAN_SLOT_BREASTS))
var/obj/item/organ/external/genital/breasts/mob_breasts = exposed_mob.getorganslot(ORGAN_SLOT_BREASTS)
var/original_breast_size = GLOB.breast_size_to_number[exposed_mob.client?.prefs.read_preference(/datum/preference/choiced/breasts_size)]
if(original_breast_size)
if(mob_breasts?.genital_size > original_breast_size)
mob_breasts.genital_size -= breast_size_reduction_step
mob_breasts.update_sprite_suffix()
modified_genitals = TRUE
if(mob_breasts?.genital_size < original_breast_size)
mob_breasts.genital_size += breast_size_increase_step
mob_breasts.update_sprite_suffix()
modified_genitals = TRUE
if(exposed_mob.getorganslot(ORGAN_SLOT_PENIS))
var/obj/item/organ/external/genital/penis/mob_penis = exposed_mob.getorganslot(ORGAN_SLOT_PENIS)
if(exposed_mob.client?.prefs?.read_preference(/datum/preference/numeric/penis_length))
var/original_penis_length = exposed_mob.client?.prefs.read_preference(/datum/preference/numeric/penis_length)
var/original_penis_girth = exposed_mob.client?.prefs.read_preference(/datum/preference/numeric/penis_girth)
// Run to go through girth first.
if(mob_penis?.girth > original_penis_girth)
mob_penis.girth -= penis_girth_reduction_step
mob_penis.update_sprite_suffix()
modified_genitals = TRUE
if(mob_penis?.girth < original_penis_girth)
mob_penis.girth += penis_girth_increase_step
mob_penis.update_sprite_suffix()
modified_genitals = TRUE
if(mob_penis?.genital_size > original_penis_length)
mob_penis.genital_size -= penis_size_reduction_step
mob_penis.update_sprite_suffix()
modified_genitals = TRUE
if(mob_penis?.genital_size < original_penis_length)
mob_penis.genital_size += penis_length_increase_step
mob_penis.update_sprite_suffix()
modified_genitals = TRUE
if(exposed_mob.getorganslot(ORGAN_SLOT_TESTICLES))
var/obj/item/organ/external/genital/testicles/mob_testicles = exposed_mob.getorganslot(ORGAN_SLOT_TESTICLES)
if(exposed_mob.client?.prefs?.read_preference(/datum/preference/numeric/balls_size))
var/original_ball_size = exposed_mob.client?.prefs.read_preference(/datum/preference/numeric/balls_size)
if(mob_testicles?.genital_size > original_ball_size)
mob_testicles.genital_size -= 1
mob_testicles.update_sprite_suffix()
modified_genitals = TRUE
if(mob_testicles?.genital_size < original_ball_size)
mob_testicles.genital_size += 1
mob_testicles.update_sprite_suffix()
modified_genitals = TRUE
if(modified_genitals)
exposed_mob.update_body()
// Notify the user that they're overdosing. Doesn't affect their mood.
/datum/reagent/drug/aphrodisiac/camphor/overdose_process(mob/living/carbon/human/exposed_mob)
to_chat(exposed_mob, span_userdanger("You feel like you took too much [name]!"))
exposed_mob.add_mood_event("[type]_overdose", /datum/mood_event/minor_overdose, name)
/datum/chemical_reaction/camphor
results = list(/datum/reagent/drug/aphrodisiac/camphor = 6)
required_reagents = list(/datum/reagent/carbon = 2, /datum/reagent/hydrogen = 2, /datum/reagent/oxygen = 2, /datum/reagent/sulfur = 1)
required_temp = 400
mix_message = "The mixture boils off a yellow, smelly vapor..."
erp_reaction = TRUE
@@ -0,0 +1,53 @@
// Crocin. Basic aphrodisiac with no consequences
/datum/reagent/drug/aphrodisiac/crocin
name = "crocin"
description = "Naturally found in the crocus and gardenia flowers, this drug acts as a natural and safe aphrodisiac."
taste_description = "strawberries"
color = "#FFADFF"
life_pref_datum = /datum/preference/toggle/erp/aphro
arousal_adjust_amount = 1
pleasure_adjust_amount = 0
pain_adjust_amount = 0
/// Probability of the chem triggering an emote, as a %, run on mob life
var/emote_probability = 3
/// Probability of the chem triggering a to_chat, as a %, run on mob life
var/thought_probability = 2
/// A list of possible emotes the chem is able to trigger
var/list/possible_aroused_emotes = list("moan", "blush")
/// A list of possible to_chat messages the chem is able to trigger
var/list/possible_aroused_thoughts = list(
"You feel frisky.",
"You're having trouble suppressing your urges.",
"You feel in the mood.",
)
/datum/reagent/drug/aphrodisiac/crocin/life_effects(mob/living/carbon/human/exposed_mob)
if(prob(emote_probability))
exposed_mob.emote(pick(possible_aroused_emotes))
if(prob(thought_probability))
var/displayed_thought = pick(possible_aroused_thoughts)
to_chat(exposed_mob, span_notice("[displayed_thought]"))
exposed_mob.adjust_arousal(arousal_adjust_amount)
exposed_mob.adjust_pleasure(pleasure_adjust_amount)
exposed_mob.adjust_pain(pain_adjust_amount)
var/modified_genitals = FALSE
for(var/obj/item/organ/external/genital/mob_genitals in exposed_mob.external_organs)
if(!mob_genitals.aroused == AROUSAL_CANT)
mob_genitals.aroused = AROUSAL_FULL
mob_genitals.update_sprite_suffix()
modified_genitals = TRUE
if (modified_genitals)
exposed_mob.update_body()
/datum/chemical_reaction/crocin
results = list(/datum/reagent/drug/aphrodisiac/crocin = 6)
required_reagents = list(/datum/reagent/carbon = 2, /datum/reagent/hydrogen = 2, /datum/reagent/oxygen = 2, /datum/reagent/water = 1)
required_temp = 400
mix_message = "The mixture boils off a pink vapor..."
erp_reaction = TRUE
@@ -0,0 +1,25 @@
/datum/reagent/consumable/femcum
name = "femcum"
description = "Uhh... Someone had fun."
taste_description = "astringent and sweetish"
color = "#ffffffb0"
glass_name = "glass of girlcum"
glass_desc = "A strange white liquid... Ew!"
reagent_state = LIQUID
shot_glass_icon_state = "shotglasswhite"
/datum/reagent/consumable/cum
name = "cum"
description = "A fluid secreted by the sexual organs of many species."
taste_description = "musky and salty"
color = "#ffffffff"
glass_name = "glass of cum"
glass_desc = "O-oh, my...~"
reagent_state = LIQUID
shot_glass_icon_state = "shotglasswhite"
/datum/chemical_reaction/cum
results = list(/datum/reagent/consumable/cum = 5)
required_reagents = list(/datum/reagent/blood = 2, /datum/reagent/consumable/milk = 2, /datum/reagent/consumable/salt = 1) // Iiiinteresting...
mix_message = "The mixture turns into a gooey, musky white liquid..."
erp_reaction = TRUE
@@ -0,0 +1,49 @@
// Dopamine. Generates in character after orgasm.
/datum/reagent/drug/aphrodisiac/dopamine
name = "dopamine...?"
description = "Pure happiness"
taste_description = "an indescribable, slightly sour taste. Something in it relaxes you, filling you with pleasure."
color = "#97ffee"
glass_name = "dopamine"
glass_desc = "Delicious flavored reagent. You feel happy even looking at it."
reagent_state = LIQUID
overdose_threshold = 10
life_pref_datum = /datum/preference/toggle/erp/aphro
overdose_pref_datum = /datum/preference/toggle/erp/aphro
arousal_adjust_amount = 0.5
pleasure_adjust_amount = 0.3
pain_adjust_amount = -0.5
/// How druggy the chem will make the mob
var/drugginess_amount = 5 SECONDS
/// How likely the drug is to make the mob druggy per life process
var/drugginess_chance = 7
/datum/reagent/drug/aphrodisiac/dopamine/on_mob_add(mob/living/carbon/human/exposed_mob)
if(!(exposed_mob.client?.prefs.read_preference(/datum/preference/toggle/erp/aphro)))
return ..()
exposed_mob.add_mood_event("[type]_start", /datum/mood_event/orgasm, name)
return ..()
/datum/reagent/drug/aphrodisiac/dopamine/life_effects(mob/living/carbon/human/exposed_mob)
exposed_mob.set_drugginess(drugginess_amount)
if(prob(drugginess_chance))
exposed_mob.emote(pick("twitch", "drool", "moan", "giggle", "shaking"))
/datum/reagent/drug/aphrodisiac/dopamine/overdose_start(mob/living/carbon/human/exposed_mob)
. = ..()
to_chat(exposed_mob, span_purple("You feel so happy!"))
exposed_mob.add_mood_event("[type]_overdose", /datum/mood_event/overgasm, name)
/datum/reagent/drug/aphrodisiac/dopamine/overdose_effects(mob/living/carbon/human/exposed_mob)
if(!(exposed_mob.hallucination < volume && prob(20)))
return ..()
exposed_mob.adjust_arousal(arousal_adjust_amount)
exposed_mob.adjust_pleasure(pleasure_adjust_amount)
exposed_mob.adjust_pain(pain_adjust_amount)
if(prob(2))
exposed_mob.emote(pick("moan", "twitch_s"))
// This chem shouldn't affect user's mood negatively.
/datum/reagent/drug/aphrodisiac/dopamine/overdose_process(mob/living/carbon/human/exposed_mob)
return
@@ -0,0 +1,55 @@
#define OD_CHANCE_NO_TRAUMA 95
// Hexacrocin. Advanced aphrodisiac that can cause brain traumas.
/datum/reagent/drug/aphrodisiac/crocin/hexacrocin
name = "hexacrocin"
description = "Chemically condensed form of basic crocin. This aphrodisiac is extremely powerful and addictive for most animals.\
Addiction withdrawals can cause brain damage and shortness of breath. Overdose can lead to brain traumas."
taste_description = "liquid desire"
color = "#FF2BFF"
overdose_threshold = 25
overdose_pref_datum = /datum/preference/toggle/erp/bimbofication
emote_probability = 5
thought_probability = 5
arousal_adjust_amount = 2
pleasure_adjust_amount = 1.5
pain_adjust_amount = 0.2
possible_aroused_thoughts = list(
"You feel a bit hot.",
"You feel strong sexual urges.",
"You feel in the mood.",
"You're ready to go down on someone.",
)
/// A list of possible to_chat messages the chem is able to trigger after enough cycles in the mobs system
var/list/extreme_aroused_thoughts = list(
"You need to fuck someone!",
"You're bursting with sexual tension!",
"You can't get sex off your mind!",
)
/// How many cycles the chem has to be in the mob's system before triggering extreme effects
var/extreme_thought_threshold = 25
/datum/reagent/drug/aphrodisiac/crocin/hexacrocin/life_effects(mob/living/carbon/human/exposed_mob)
. = ..()
if(prob(thought_probability) && current_cycle >= extreme_thought_threshold)
var/displayed_extreme_thought = pick(extreme_aroused_thoughts)
to_chat(exposed_mob, span_purple("[displayed_extreme_thought]"))
/datum/reagent/drug/aphrodisiac/crocin/hexacrocin/overdose_effects(mob/living/carbon/human/exposed_mob)
if(prob(OD_CHANCE_NO_TRAUMA) || HAS_TRAIT(exposed_mob, TRAIT_BIMBO))
return ..()
to_chat(exposed_mob, span_purple("Your libido is going haywire! It feels like speaking is much harder..."))
exposed_mob.gain_trauma(/datum/brain_trauma/very_special/bimbo, TRAUMA_RESILIENCE_BASIC)
ADD_TRAIT(exposed_mob, TRAIT_BIMBO, LEWDCHEM_TRAIT)
/datum/chemical_reaction/hexacrocin
results = list(/datum/reagent/drug/aphrodisiac/crocin/hexacrocin = 1)
required_reagents = list(/datum/reagent/drug/aphrodisiac/crocin = 6, /datum/reagent/phenol = 1)
required_temp = 600
mix_message = "The mixture rapidly condenses and darkens in color..."
erp_reaction = TRUE
#undef OD_CHANCE_NO_TRAUMA
@@ -0,0 +1,200 @@
/*
* PENIS ENLARGEMENT
* Normal function increases the player's penis size.
* If the player's penis is near or at the maximum size and they're wearing clothing, it presses against the player's clothes and causes brute damage.
* If gender change preference is enabled: Overdosing makes you male if female, makes the player grow a cock, and shrinks the player's breasts to a minimum size.
* If the gender change preference is not enabled: Overdosing will just make you grow a cock if you don't have one.
*/
/datum/reagent/drug/aphrodisiac/incubus_draft
name = "incubus draft"
description = "A volatile collodial mixture derived from various masculine solutions that encourages a larger gentleman's package via a potent testosterone mix."
color = "#888888"
taste_description = "chinese dragon powder"
overdose_threshold = 20 // ODing makes you male and shrinks female genitals if gender change prefs are enabled. Otherwise, grows a cock.
metabolization_rate = 0.25
life_pref_datum = /datum/preference/toggle/erp/penis_enlargement
overdose_pref_datum = /datum/preference/toggle/erp
// Not important at all, really, but I don't want folk complaining about a removed feature.
var/static/list/species_to_penis = list(
SPECIES_HUMAN = list(
"sheath" = SHEATH_NONE,
"mutant_index" = "Human",
"balls" = "Pair"
),
SPECIES_LIZARD = list(
"sheath" = SHEATH_SLIT,
"color" = "#FFB6C1",
"mutant_index" = "Flared",
"balls" = "Internal"
),
SPECIES_LIZARD_ASH = list(
"sheath" = SHEATH_SLIT,
"color" = "#FFB6C1",
"mutant_index" = "Flared",
"balls" = "Internal"
),
)
/// Words for the cock when huge.
var/static/list/words_for_bigger_cock = list(
"huge",
"massive",
"gigantic",
"rather lengthy",
"colossal",
"hefty",
)
/// Synonyms for cock.
var/static/list/cock_text_list = list(
"cock",
"penis",
"dick",
"member",
"richard",
"johnston",
"johnson",
)
/// Synonyms for bigger cock.
var/static/list/bigger_cock_text_list = list(
"rod",
"shaft",
"cock",
"penis",
"dick",
"member",
"richard",
"johnston",
"johnson",
)
/// Wording chosen to extend the cock, shown only to the mob.
var/static/list/cock_action_text_list = list(
"extends to ",
"grows out to ",
"begins to enlarge, growing to ",
"suddenly expands to ",
"lengthens out to ",
)
/// Wording chosen to be seen by other mobs, while mob is unclothed.
var/static/list/public_cock_action_text_list = list(
"expands by an inch or so.",
"appears to grow a bit longer.",
"seems a bit bigger than it was before.",
"suddenly lengthens about an inch or two.",
)
/datum/reagent/drug/aphrodisiac/incubus_draft/life_effects(mob/living/carbon/human/exposed_mob)
var/obj/item/organ/external/genital/penis/mob_penis = exposed_mob.getorganslot(ORGAN_SLOT_PENIS)
enlargement_amount += enlarger_increase_step
// Add yet another check because I hate errors!!
if(!mob_penis)
return
if(enlargement_amount >= enlargement_threshold)
if(mob_penis?.genital_size >= penis_max_length)
return ..()
mob_penis.genital_size += penis_length_increase_step
// Improvision to girth to not make it random chance.
if(mob_penis?.girth < penis_max_girth) // Because any higher is ridiculous. However, should still allow for regular penis growth.
mob_penis.girth = round(mob_penis.girth + (mob_penis.genital_size/mob_penis.girth))
mob_penis.update_sprite_suffix()
exposed_mob.update_body()
enlargement_amount = 0
if(mob_penis.visibility_preference == GENITAL_ALWAYS_SHOW || exposed_mob.is_bottomless())
if(mob_penis?.genital_size >= (penis_max_length - 2))
if(exposed_mob.dna.features["penis_sheath"] == SHEATH_SLIT)
if(mob_penis.aroused != AROUSAL_FULL)
to_chat(exposed_mob, span_purple("Your [pick(words_for_bigger_cock)] [pick(bigger_cock_text_list)] [pick(cock_action_text_list)]about [mob_penis.genital_size] inches long, and [mob_penis.girth] inches in circumference."))
return
exposed_mob.visible_message(span_notice("[exposed_mob]'s [pick(words_for_bigger_cock)] [pick(bigger_cock_text_list)] [pick(public_cock_action_text_list)]"))
to_chat(exposed_mob, span_purple("Your [pick(words_for_bigger_cock)] [pick(bigger_cock_text_list)] [pick(cock_action_text_list)]about [mob_penis.genital_size] inches long, and [mob_penis.girth] inches in circumference."))
return
else
if(exposed_mob.dna.features["penis_sheath"] == SHEATH_SLIT)
if(mob_penis.aroused != AROUSAL_FULL)
to_chat(exposed_mob, span_purple("Your [pick(cock_text_list)] [pick(cock_action_text_list)]about [mob_penis.genital_size] inches long, and [mob_penis.girth] inches in circumference."))
return
exposed_mob.visible_message(span_notice("[exposed_mob]'s [pick(cock_text_list)] [pick(public_cock_action_text_list)]"))
to_chat(exposed_mob, span_purple("Your [pick(cock_text_list)] [pick(cock_action_text_list)]about [mob_penis.genital_size] inches long, and [mob_penis.girth] inches in circumference."))
return
else
if(mob_penis?.genital_size >= (penis_max_length - 2))
to_chat(exposed_mob, span_purple("Your [pick(words_for_bigger_cock)] [pick(bigger_cock_text_list)] [pick(cock_action_text_list)]about [mob_penis.genital_size] inches long, and [mob_penis.girth] inches in circumference."))
return
else
to_chat(exposed_mob, span_purple("Your [pick(cock_text_list)] [pick(cock_action_text_list)]about [mob_penis.genital_size] inches long, and [mob_penis.girth] inches in circumference."))
return
if((mob_penis?.genital_size >= (penis_max_length - 2)) && (exposed_mob.w_uniform || exposed_mob.wear_suit))
var/target_bodypart = exposed_mob.get_bodypart(BODY_ZONE_PRECISE_GROIN)
if(prob(damage_chance))
to_chat(exposed_mob, span_danger("You feel a tightness in your pants!"))
exposed_mob.apply_damage(1, BRUTE, target_bodypart)
return ..()
/datum/reagent/drug/aphrodisiac/incubus_draft/overdose_effects(mob/living/carbon/human/exposed_mob)
if(exposed_mob.client?.prefs?.read_preference(/datum/preference/toggle/erp/penis_enlargement))
if(!exposed_mob.getorganslot(ORGAN_SLOT_PENIS) && exposed_mob.client?.prefs?.read_preference(/datum/preference/toggle/erp/new_genitalia_growth))
var/list/data = species_to_penis[exposed_mob.dna.species.id]
if(!data)
data = species_to_penis[SPECIES_HUMAN]
exposed_mob.dna.features["penis_sheath"] = data["sheath"]
exposed_mob.dna.mutant_bodyparts[ORGAN_SLOT_PENIS][MUTANT_INDEX_NAME] = data["index_name"]
exposed_mob.dna.mutant_bodyparts[ORGAN_SLOT_TESTICLES][MUTANT_INDEX_NAME] = data["balls"]
var/colour = data["colour"]
if(colour)
exposed_mob.dna.mutant_bodyparts[ORGAN_SLOT_PENIS][MUTANT_INDEX_COLOR_LIST] = list(colour)
if(!exposed_mob.getorganslot(ORGAN_SLOT_TESTICLES))
var/obj/item/organ/balls_path = /obj/item/organ/external/genital/testicles
balls_path = new /obj/item/organ/external/genital/testicles
balls_path.build_from_dna(exposed_mob.dna, ORGAN_SLOT_TESTICLES)
balls_path.Insert(exposed_mob, 0, FALSE)
var/obj/item/organ/external/genital/new_balls = exposed_mob.getorganslot(ORGAN_SLOT_TESTICLES)
new_balls.genital_size = 1
new_balls.update_sprite_suffix()
var/obj/item/organ/external/genital/penis/new_penis = new /obj/item/organ/external/genital/penis
new_penis.build_from_dna(exposed_mob.dna, ORGAN_SLOT_PENIS)
new_penis.Insert(exposed_mob, 0, FALSE)
new_penis.genital_size = 4
new_penis.girth = 3
new_penis.update_sprite_suffix()
exposed_mob.update_body()
to_chat(exposed_mob, span_purple("Your crotch feels warm as something suddenly sprouts between your legs."))
// Makes the balls bigger if they're small.
var/obj/item/organ/external/genital/testicles/mob_testicles = exposed_mob.getorganslot(ORGAN_SLOT_TESTICLES)
if(mob_testicles)
if(mob_testicles.genital_size > 2)
return
mob_testicles.genital_size = 2
// Separates gender change stuff from cock growth.
var/obj/item/organ/external/genital/breasts/mob_breasts = exposed_mob.getorganslot(ORGAN_SLOT_BREASTS)
if(exposed_mob.client?.prefs?.read_preference(/datum/preference/toggle/erp/gender_change))
if(exposed_mob.gender == FEMALE)
exposed_mob.set_gender(MALE)
exposed_mob.physique = exposed_mob.gender
exposed_mob.update_body()
exposed_mob.update_mutations_overlay()
if(!mob_breasts)
return
if(exposed_mob.client?.prefs?.read_preference(/datum/preference/toggle/erp/breast_enlargement)) // To do breast shrinkage, check if prefs allow for this.
if(mob_breasts.genital_size > breast_minimum_size)
mob_breasts.genital_size -= breast_size_reduction_step
mob_breasts.update_sprite_suffix()
exposed_mob.update_body()
return
// Notify the user that they're overdosing. Doesn't affect their mood.
/datum/reagent/drug/aphrodisiac/incubus_draft/overdose_process(mob/living/carbon/human/exposed_mob)
to_chat(exposed_mob, span_userdanger("You feel like you took too much [name]!"))
exposed_mob.add_mood_event("[type]_overdose", /datum/mood_event/minor_overdose, name)
/datum/chemical_reaction/incubus_draft
results = list(/datum/reagent/drug/aphrodisiac/incubus_draft = 8)
required_reagents = list(/datum/reagent/blood = 5, /datum/reagent/medicine/c2/synthflesh = 2, /datum/reagent/carbon = 2, /datum/reagent/drug/aphrodisiac/crocin = 2, /datum/reagent/medicine/salglu_solution = 1)
mix_message = "the reaction gives off a mist of milk."
erp_reaction = TRUE
@@ -0,0 +1,37 @@
// Pentacamphor. Used to purge crocin and hexacrocin. Can permanently disable arousal or cure bimbofication on overdose.
/datum/reagent/drug/aphrodisiac/camphor/pentacamphor
name = "Pentacamphor"
description = "Chemically condensed camphor. Causes an extreme reduction in libido and a permanent one if overdosed. Non-addictive."
taste_description = "tranquil celibacy"
color = "#D9D9D9"//rgb(255, 255, 255)
reagent_state = SOLID
overdose_threshold = 20
arousal_adjust_amount = -18
overdose_pref_datum = /datum/preference/toggle/erp/aphro
/// How much of the given reagent to remove per operation
var/reagent_reduction_amount = 20
/datum/reagent/drug/aphrodisiac/camphor/pentacamphor/life_effects(mob/living/carbon/human/exposed_mob)
. = ..()
if(exposed_mob.reagents.has_reagent(/datum/reagent/drug/aphrodisiac/crocin))
exposed_mob.reagents.remove_reagent(/datum/reagent/drug/aphrodisiac/crocin, reagent_reduction_amount)
if(exposed_mob.reagents.has_reagent(/datum/reagent/drug/aphrodisiac/crocin/hexacrocin))
exposed_mob.reagents.remove_reagent(/datum/reagent/drug/aphrodisiac/crocin/hexacrocin, reagent_reduction_amount)
/datum/reagent/drug/aphrodisiac/camphor/pentacamphor/overdose_start(mob/living/carbon/human/exposed_mob)
if(HAS_TRAIT(exposed_mob, TRAIT_BIMBO))
exposed_mob.cure_trauma_type(/datum/brain_trauma/very_special/bimbo, TRAUMA_RESILIENCE_ABSOLUTE)
to_chat(exposed_mob, span_notice("Your mind is free. Your thoughts are pure and innocent once more."))
REMOVE_TRAIT(exposed_mob, TRAIT_BIMBO, LEWDCHEM_TRAIT)
return
if(!HAS_TRAIT(exposed_mob, TRAIT_NEVERBONER))
to_chat(exposed_mob, span_notice("You feel like you'll never feel aroused again..."))
ADD_TRAIT(exposed_mob, TRAIT_NEVERBONER, LEWDCHEM_TRAIT)
/datum/chemical_reaction/pentacamphor
results = list(/datum/reagent/drug/aphrodisiac/camphor/pentacamphor = 1)
required_reagents = list(/datum/reagent/drug/aphrodisiac/camphor = 5, /datum/reagent/acetone = 1)
required_temp = 500
mix_message = "The mixture thickens and heats up slighty..."
erp_reaction = TRUE
@@ -0,0 +1,196 @@
/*
* BREAST ENLARGEMENT
* Normal function increases the player's breast size.
* If the player's breasts are near or at the maximum size and they're wearing clothing, they press against the player's clothes and causes brute and oxygen damage.
* If gender change preference is enabled: Overdosing makes you female if male, makes the player grow breasts, sets the player's testicles to the minimum size, and shrinks the player's penis to a minimum size.
* If the gender change preference is not enabled: Overdosing will just make you grow breasts if you don't have any.
* Credit to Citadel for the original code before modification
*/
/datum/reagent/drug/aphrodisiac/succubus_milk
name = "succubus milk"
description = "A volatile collodial mixture derived from milk that encourages mammary production via a potent estrogen mix."
color = "#E60584"
taste_description = "a milky ice cream like flavour"
overdose_threshold = 20
metabolization_rate = 0.25
life_pref_datum = /datum/preference/toggle/erp/breast_enlargement
overdose_pref_datum = /datum/preference/toggle/erp
/// Words for the breasts when huge.
var/static/list/words_for_bigger = list(
"huge",
"massive",
"squishy",
"gigantic",
"rather large",
"jiggly",
"hefty",
)
/// Synonyms for breasts.
var/static/list/boob_text_list = list(
"boobs",
"tits",
"breasts",
)
/// Synonyms for the chest.
var/static/list/covered_boobs_list = list(
"bust",
"chest",
"bosom",
)
/// Synonyms for bigger breasts.
var/static/list/bigger_boob_text_list = list(
"jigglies",
"melons",
"jugs",
"boobies",
"milkers",
"boobs",
"tits",
"breasts",
)
/// Wording chosen to expand the breasts,shown only to the mob.
var/static/list/action_text_list = list(
"expand outward to ",
"grow out to ",
"begin to enlarge, growing to ",
"suddenly expand to ",
"swell out to ",
)
/// Wording chosen to be seen by other mobs, regardless of whether mob is clothed/unclothed.
var/static/list/public_bigger_action_text_list = list(
"expand and jiggle outward.",
"grow a bit larger, bouncing about.",
"seem a bit bigger than they were before.",
"bounce and jiggle as they suddenly expand.",
)
/// Wording chosen to be seen by other mobs, while mob is unclothed.
var/static/list/public_action_text_list = list(
"expand outward.",
"seem to grow a bit larger.",
"appear a bit bigger than they were before.",
"bounce and jiggle as they suddenly expand.",
)
/// Wording chosen to be seen by other mobs, while mob is clothed.
var/static/list/notice_boobs = list(
"seems to be a bit tighter.",
"appears to be a bit bigger.",
"seems to swell outward a bit.",
)
/datum/reagent/drug/aphrodisiac/succubus_milk/life_effects(mob/living/carbon/human/exposed_mob) //Increases breast size
var/obj/item/organ/external/genital/breasts/mob_breasts = exposed_mob.getorganslot(ORGAN_SLOT_BREASTS)
enlargement_amount += enlarger_increase_step
// Adds a check for breasts in the first place.
if(!mob_breasts)
return
if(enlargement_amount >= enlargement_threshold)
if(mob_breasts?.genital_size >= max_breast_size)
return
mob_breasts.genital_size += breast_size_increase_step
mob_breasts.update_sprite_suffix()
exposed_mob.update_body()
enlargement_amount = 0
// Checks for cup size.
var/translation = mob_breasts.breasts_size_to_cup(mob_breasts.genital_size)
if(mob_breasts.visibility_preference == GENITAL_ALWAYS_SHOW || exposed_mob.is_topless())
switch(translation)
if(BREAST_SIZE_FLATCHESTED)
return
if(BREAST_SIZE_BEYOND_MEASUREMENT)
exposed_mob.visible_message(span_notice("[exposed_mob]'s [pick(words_for_bigger)] [pick(bigger_boob_text_list)] [pick(public_bigger_action_text_list)]"))
to_chat(exposed_mob, span_purple("Your [pick(words_for_bigger)] [pick(bigger_boob_text_list)] [pick(action_text_list)]about [mob_breasts.genital_size] inches in diameter."))
return
else
if(mob_breasts?.genital_size >= (max_breast_size - 2))
exposed_mob.visible_message(span_notice("[exposed_mob]'s [pick(words_for_bigger)] [pick(bigger_boob_text_list)] [pick(public_bigger_action_text_list)]"))
to_chat(exposed_mob, span_purple("Your [pick(words_for_bigger)] [pick(bigger_boob_text_list)] [pick(action_text_list)]about [translation]-cups."))
return
else
exposed_mob.visible_message(span_notice("[exposed_mob]'s [pick(boob_text_list)] [pick(public_action_text_list)]"))
to_chat(exposed_mob, span_purple("Your [pick(boob_text_list)] [pick(action_text_list)]about [translation]-cups."))
return
else
switch(translation)
if(BREAST_SIZE_FLATCHESTED)
return
if(BREAST_SIZE_BEYOND_MEASUREMENT)
exposed_mob.visible_message(span_notice("[exposed_mob]'s [pick(boob_text_list)] [pick(public_bigger_action_text_list)]"))
to_chat(exposed_mob, span_purple("Your [pick(words_for_bigger)] [pick(bigger_boob_text_list)] [pick(action_text_list)]about [mob_breasts.genital_size] inches in diameter."))
return
else
if(mob_breasts?.genital_size >= (max_breast_size - 2))
exposed_mob.visible_message(span_notice("[exposed_mob]'s [pick(boob_text_list)] [pick(public_bigger_action_text_list)]"))
to_chat(exposed_mob, span_purple("Your [pick(words_for_bigger)] [pick(bigger_boob_text_list)] [pick(action_text_list)]about [translation]-cups."))
return
else
exposed_mob.visible_message(span_notice("The area around [exposed_mob]'s [pick(covered_boobs_list)] [pick(notice_boobs)]"))
to_chat(exposed_mob, span_purple("Your [pick(boob_text_list)] [pick(action_text_list)]about [translation]-cups."))
return
if((mob_breasts?.genital_size >= (max_breast_size - 2)) && (exposed_mob.w_uniform || exposed_mob.wear_suit))
if(prob(damage_chance))
to_chat(exposed_mob, span_danger("Your breasts begin to strain against your clothes!"))
exposed_mob.adjustOxyLoss(5)
exposed_mob.apply_damage(1, BRUTE, exposed_mob.get_bodypart(BODY_ZONE_CHEST))
// Turns you into a female if character is male. Also adds breasts.
/datum/reagent/drug/aphrodisiac/succubus_milk/overdose_effects(mob/living/carbon/human/exposed_mob)
if(exposed_mob.client?.prefs.read_preference(/datum/preference/toggle/erp/breast_enlargement))
if(!exposed_mob.getorganslot(ORGAN_SLOT_BREASTS) && exposed_mob.client?.prefs.read_preference(/datum/preference/toggle/erp/new_genitalia_growth))
var/obj/item/organ/path = /obj/item/organ/external/genital/breasts
exposed_mob.dna.mutant_bodyparts[ORGAN_SLOT_BREASTS][MUTANT_INDEX_NAME] = "Pair"
path = new /obj/item/organ/external/genital/breasts
path.build_from_dna(exposed_mob.dna, ORGAN_SLOT_BREASTS)
path.Insert(exposed_mob, FALSE, FALSE)
var/obj/item/organ/external/genital/new_breasts = exposed_mob.getorganslot(ORGAN_SLOT_BREASTS)
new_breasts.genital_size = 2
new_breasts.update_sprite_suffix()
exposed_mob.update_body()
enlargement_amount = 0
if(new_breasts.visibility_preference == GENITAL_ALWAYS_SHOW || exposed_mob.is_topless())
exposed_mob.visible_message(span_notice("[exposed_mob]'s bust suddenly expands!"))
to_chat(exposed_mob, span_purple("Your chest feels warm, tingling with sensitivity as it expands outward."))
return
else
exposed_mob.visible_message(span_notice("The area around [exposed_mob]'s chest suddenly bounces a bit."))
to_chat(exposed_mob, span_purple("Your chest feels warm, tingling with sensitivity as it strains against your clothes."))
return
// Separates gender change stuff from breast growth.
if(exposed_mob.client?.prefs.read_preference(/datum/preference/toggle/erp/gender_change))
var/obj/item/organ/external/genital/penis/mob_penis = exposed_mob.getorganslot(ORGAN_SLOT_PENIS)
var/obj/item/organ/external/genital/testicles/mob_testicles = exposed_mob.getorganslot(ORGAN_SLOT_TESTICLES)
if(exposed_mob.gender == MALE)
exposed_mob.set_gender(FEMALE)
exposed_mob.physique = exposed_mob.gender
exposed_mob.update_body()
exposed_mob.update_mutations_overlay()
if(!mob_penis)
return
if(exposed_mob.client?.prefs.read_preference(/datum/preference/toggle/erp/penis_enlargement)) // To do cock shrinkage, check if prefs allow for this.
if(mob_penis.genital_size > penis_min_length)
mob_penis.genital_size -= penis_size_reduction_step
mob_penis.update_sprite_suffix()
exposed_mob.update_body()
if(mob_penis.girth > penis_minimum_girth)
mob_penis.girth -= penis_girth_reduction_step
mob_penis.update_sprite_suffix()
exposed_mob.update_body()
if(!mob_testicles || mob_testicles.genital_size <= 1)
return
mob_testicles.genital_size -= 1
return
// Notify the user that they're overdosing. Doesn't affect their mood.
/datum/reagent/drug/aphrodisiac/succubus_milk/overdose_process(mob/living/carbon/human/exposed_mob)
to_chat(exposed_mob, span_userdanger("You feel like you took too much [name]!"))
exposed_mob.add_mood_event("[type]_overdose", /datum/mood_event/minor_overdose, name)
/datum/chemical_reaction/succubus_milk
results = list(/datum/reagent/drug/aphrodisiac/succubus_milk = 8)
required_reagents = list(/datum/reagent/medicine/salglu_solution = 1, /datum/reagent/consumable/milk = 1, /datum/reagent/medicine/c2/synthflesh = 2, /datum/reagent/silicon = 3, /datum/reagent/drug/aphrodisiac/crocin = 3)
mix_message = "the reaction gives off a mist of milk."
erp_reaction = TRUE
@@ -82,8 +82,8 @@
//chems
/obj/item/reagent_containers/pill/crocin,
/obj/item/reagent_containers/pill/camphor,
/obj/item/reagent_containers/cup/bottle/breast_enlarger,
/obj/item/reagent_containers/cup/bottle/penis_enlarger,
/obj/item/reagent_containers/cup/bottle/succubus_milk,
/obj/item/reagent_containers/cup/bottle/incubus_draft,
/obj/item/reagent_containers/pill/hexacrocin,
/obj/item/reagent_containers/pill/pentacamphor,
/obj/item/reagent_containers/cup/bottle/hexacrocin,
@@ -92,6 +92,6 @@
/obj/item/clothing/under/misc/latex_catsuit/Initialize(mapload)
. = ..()
breasts_overlay = mutable_appearance('modular_skyrat/modules/modular_items/lewd_items/icons/mob/lewd_clothing/lewd_uniform/lewd_uniform.dmi', "none", ABOVE_MOB_LAYER)
breasts_overlay.icon_state = "breasts"
breasts_overlay.icon_state = ORGAN_SLOT_BREASTS
breasts_icon_overlay = mutable_appearance('modular_skyrat/modules/modular_items/lewd_items/icons/obj/lewd_clothing/lewd_uniform.dmi', "none")
breasts_icon_overlay.icon_state = "breasts"
breasts_icon_overlay.icon_state = ORGAN_SLOT_BREASTS
@@ -87,11 +87,11 @@
src.dropped(hooman)
return PROCESS_KILL
if(tightness == SHIBARI_TIGHTNESS_LOW && hooman.arousal < 15)
hooman.adjustArousal(0.6 * delta_time)
hooman.adjust_arousal(0.6 * delta_time)
if(tightness == SHIBARI_TIGHTNESS_MED && hooman.arousal < 25)
hooman.adjustArousal(0.6 * delta_time)
hooman.adjust_arousal(0.6 * delta_time)
if(tightness == SHIBARI_TIGHTNESS_HIGH && hooman.arousal < 30)
hooman.adjustArousal(0.6 * delta_time)
hooman.adjust_arousal(0.6 * delta_time)
//stuff to apply processing on equip and add mood event for perverts
/obj/item/clothing/under/shibari/equipped(mob/user, slot)
@@ -133,7 +133,7 @@
return PROCESS_KILL
var/mob/living/carbon/human/hooman = loc
if(tightness == SHIBARI_TIGHTNESS_HIGH && hooman.pain < 25)
hooman.adjustPain(0.6 * delta_time)
hooman.adjust_pain(0.6 * delta_time)
/obj/item/clothing/under/shibari/groin
name = "crotch rope shibari"
@@ -161,11 +161,11 @@
return PROCESS_KILL
var/mob/living/carbon/human/hooman = loc
if(tightness == SHIBARI_TIGHTNESS_LOW && hooman.pleasure < 20)
hooman.adjustPleasure(0.6 * delta_time)
hooman.adjust_pleasure(0.6 * delta_time)
if(tightness == SHIBARI_TIGHTNESS_MED && hooman.pleasure < 60)
hooman.adjustPleasure(0.6 * delta_time)
hooman.adjust_pleasure(0.6 * delta_time)
if(tightness == SHIBARI_TIGHTNESS_HIGH)
hooman.adjustPleasure(0.6 * delta_time)
hooman.adjust_pleasure(0.6 * delta_time)
/obj/item/clothing/under/shibari/full
name = "shibari fullbody ropes"
@@ -188,13 +188,13 @@
return PROCESS_KILL
var/mob/living/carbon/human/hooman = loc
if(tightness == SHIBARI_TIGHTNESS_LOW && hooman.pleasure< 20)
hooman.adjustPleasure(0.6 * delta_time)
hooman.adjust_pleasure(0.6 * delta_time)
if(tightness == SHIBARI_TIGHTNESS_MED && hooman.pleasure < 60)
hooman.adjustPleasure(0.6 * delta_time)
hooman.adjust_pleasure(0.6 * delta_time)
if(tightness == SHIBARI_TIGHTNESS_HIGH)
hooman.adjustPleasure(0.6 * delta_time)
hooman.adjust_pleasure(0.6 * delta_time)
if(hooman.pain < 40)
hooman.adjustPain(0.6 * delta_time)
hooman.adjust_pain(0.6 * delta_time)
#undef SHIBARI_TIGHTNESS_LOW
#undef SHIBARI_TIGHTNESS_MED
@@ -49,7 +49,7 @@
created_sparks.start()
affected_mob.Paralyze(30)
affected_mob.adjustPain(10)
affected_mob.adjust_pain(10)
affected_mob.adjust_stutter(30 SECONDS)
if(master)
@@ -140,7 +140,7 @@
return
else if(held == null)
if(unheld.name =="strapon" && unheld.item_flags == ABSTRACT | HAND_ITEM)
if(istype(unheld, /obj/item/strapon_dildo) && unheld.item_flags == ABSTRACT | HAND_ITEM)
if(src == user.belt)
qdel(unheld)
//CODE FOR PUTTING STRAPON IN HANDS
@@ -201,8 +201,8 @@
if(vagina)
if(hit_mob.is_bottomless() || vagina.visibility_preference == GENITAL_ALWAYS_SHOW)
message = pick("delicately rubs [hit_mob]'s vagina with [src]", "uses [src] to fuck [hit_mob]'s vagina", "jams [hit_mob]'s pussy with [src]", "teases [hit_mob]'s pussy with [src]")
hit_mob.adjustArousal(6)
hit_mob.adjustPleasure(8)
hit_mob.adjust_arousal(6)
hit_mob.adjust_pleasure(8)
if(prob(40))
hit_mob.try_lewd_autoemote(pick("twitch_s", "moan"))
user.visible_message(span_purple("[user] [message]!"))
@@ -222,8 +222,8 @@
if(BODY_ZONE_HEAD, BODY_ZONE_PRECISE_MOUTH, BODY_ZONE_PRECISE_EYES) //Mouth only. Sorry, perverts. No eye/ear penetration for you today.
if(!hit_mob.is_mouth_covered())
message = pick("fucks [hit_mob]'s mouth with [src]", "chokes [hit_mob] by inserting [src] into [hit_mob.p_their()] throat", "forces [hit_mob] to suck [src]", "inserts [src] into [hit_mob]'s throat")
hit_mob.adjustArousal(4)
hit_mob.adjustPleasure(1)
hit_mob.adjust_arousal(4)
hit_mob.adjust_pleasure(1)
hit_mob.adjustOxyLoss(1.5)
if(prob(70))
hit_mob.try_lewd_autoemote(pick("gasp", "moan"))
@@ -242,8 +242,8 @@
else
if(hit_mob.is_bottomless())
message = pick("fucks [hit_mob]'s ass with [src]", "uses [src] to fuck [hit_mob]'s anus", "jams [hit_mob]'s ass with [src]", "roughly fucks [hit_mob]'s ass with [src], causing their eyes to roll back")
hit_mob.adjustArousal(5)
hit_mob.adjustPleasure(5)
hit_mob.adjust_arousal(5)
hit_mob.adjust_pleasure(5)
if(prob(60))
hit_mob.try_lewd_autoemote(pick("twitch_s", "moan", "shiver"))
user.visible_message(span_purple("[user] [message]!"))
@@ -0,0 +1,76 @@
/// Helper proc for adding overrides to bodyparts to hide them if a catsuit or sleeping bag is worn. Allows for overrides for each, in case a part shouldn't be hidden.
/datum/sprite_accessory/proc/lewd_is_hidden(mob/living/carbon/human/target_human, hide_if_catsuit = TRUE, hide_if_sleeping_bag = TRUE)
if(target_human.wear_suit && istype(target_human.wear_suit, /obj/item/clothing/suit/straight_jacket/kinky_sleepbag))
var/obj/item/clothing/suit/straight_jacket/kinky_sleepbag/sleeping_bag = target_human.wear_suit
if(sleeping_bag.state_thing == "inflated")
return hide_if_sleeping_bag
return FALSE
else if(target_human.w_uniform && istype(target_human.w_uniform, /obj/item/clothing/under/misc/latex_catsuit))
return hide_if_catsuit
return FALSE
// Extends default proc check for hidden ears for supporting our sleepbag and catsuit too
/datum/sprite_accessory/ears/is_hidden(mob/living/carbon/human/target_human, obj/item/bodypart/bodypart)
// First lets proc default code
. = ..()
if(!.) // If true, ears already hidden
return lewd_is_hidden(target_human)
// Extends default proc check for hidden frills for supporting our sleepbag and catsuit too
/datum/sprite_accessory/frills/is_hidden(mob/living/carbon/human/target_human, obj/item/bodypart/bodypart)
. = ..()
if(!.) // If true, frills already hidden
return lewd_is_hidden(target_human)
// Extends default proc check for hidden head accessory for supporting our sleepbag and catsuit too
/datum/sprite_accessory/head_accessory/is_hidden(mob/living/carbon/human/target_human, obj/item/bodypart/bodypart)
. = ..()
if(!.) // If true, head accessory already hidden
return lewd_is_hidden(target_human)
// Extends default proc check for hidden horns for supporting our sleepbag and catsuit too
/datum/sprite_accessory/horns/is_hidden(mob/living/carbon/human/target_human, obj/item/bodypart/bodypart)
. = ..()
if(!.) // If true, horns already hidden
return lewd_is_hidden(target_human)
// Extends default proc check for hidden antenna for supporting our sleepbag and catsuit too
/datum/sprite_accessory/antenna/is_hidden(mob/living/carbon/human/target_human, obj/item/bodypart/bodypart)
. = ..()
if(!.) // If true, antenna already hidden
return lewd_is_hidden(target_human)
// Extends default proc check for hidden moth antenna for supporting our sleepbag and catsuit too
/datum/sprite_accessory/moth_antennae/is_hidden(mob/living/carbon/human/target_human, obj/item/bodypart/bodypart)
. = ..()
if(!.) // If true, moth antenna already hidden
return lewd_is_hidden(target_human)
// Extends default proc check for hidden skrell hair for supporting our sleepbag and catsuit too
/datum/sprite_accessory/skrell_hair/is_hidden(mob/living/carbon/human/target_human, obj/item/bodypart/bodypart)
. = ..()
if(!.) // If true, skrell hair already hidden
return lewd_is_hidden(target_human)
// Extends default proc check for hidden skrell hair for supporting our sleepbag and catsuit too
/datum/sprite_accessory/tails/is_hidden(mob/living/carbon/human/target_human, obj/item/bodypart/bodypart)
. = ..()
if(!.) // If true, tail already hidden
return lewd_is_hidden(target_human, hide_if_catsuit = FALSE)
/datum/sprite_accessory/xenodorsal/is_hidden(mob/living/carbon/human/target_human, obj/item/bodypart/bodypart)
. = ..()
if(!.)
return lewd_is_hidden(target_human)
/datum/sprite_accessory/xenohead/is_hidden(mob/living/carbon/human/target_human, obj/item/bodypart/bodypart)
. = ..()
if(!.)
return lewd_is_hidden(target_human, hide_if_catsuit = FALSE, hide_if_sleeping_bag = FALSE)
// Extends default proc check for hidden wings for supporting our sleepbag and catsuit too
/datum/sprite_accessory/wings/is_hidden(mob/living/carbon/human/target_human, obj/item/bodypart/bodypart)
. = ..()
if(!.)
return lewd_is_hidden(target_human)
@@ -0,0 +1,5 @@
// Let's not force lewd emotes from folk who don't want them, mmm~?
/mob/living/carbon/proc/try_lewd_autoemote(emote)
if(!client?.prefs?.read_preference(/datum/preference/toggle/erp/autoemote))
return
emote(emote)
@@ -0,0 +1,378 @@
/mob/living/carbon/human
var/arousal = 0
var/pleasure = 0
var/pain = 0
var/pain_limit = 0
var/arousal_status = AROUSAL_NONE
// Add variables for slots to the human class
var/obj/item/vagina = null
var/obj/item/anus = null
var/obj/item/nipples = null
var/obj/item/penis = null
var/has_penis = FALSE
var/has_vagina = FALSE
var/has_breasts = FALSE
var/has_anus = FALSE
// For tracking arousal and fluid regen.
/mob/living/carbon/human/Initialize(mapload)
. = ..()
if(!istype(src, /mob/living/carbon/human/species/monkey))
apply_status_effect(/datum/status_effect/aroused)
apply_status_effect(/datum/status_effect/body_fluid_regen)
/*
* This code needed to determine if the human is naked in that part of body or not
* You can use this for your own stuff if you want, haha.
*/
/// Are we wearing something that covers our chest?
/mob/living/carbon/human/proc/is_topless()
return (!(wear_suit) || !(wear_suit.body_parts_covered & CHEST)) && (!(w_uniform) || !(w_uniform.body_parts_covered & CHEST))
/// Are we wearing something that covers our groin?
/mob/living/carbon/human/proc/is_bottomless()
return (!(wear_suit) || !(wear_suit.body_parts_covered & GROIN)) && (!(w_uniform) || !(w_uniform.body_parts_covered & GROIN))
/// Are we wearing something that covers our shoes?
/mob/living/carbon/human/proc/is_barefoot()
return (!(wear_suit) || !(wear_suit.body_parts_covered & GROIN)) && (!(shoes) || !(shoes.body_parts_covered & FEET))
/mob/living/carbon/human/proc/is_hands_uncovered()
return (gloves?.body_parts_covered & ARMS)
/mob/living/carbon/human/proc/is_head_uncovered()
return (head?.body_parts_covered & HEAD)
/// Returns true if the human has an accessible penis for the parameter. Accepts any of the `REQUIRE_GENITAL_` defines.
/mob/living/carbon/human/proc/has_penis(required_state = REQUIRE_GENITAL_ANY)
var/obj/item/organ/external/genital/genital = getorganslot(ORGAN_SLOT_PENIS)
if(!genital)
return FALSE
switch(required_state)
if(REQUIRE_GENITAL_ANY)
return TRUE
if(REQUIRE_GENITAL_EXPOSED)
return genital.visibility_preference == GENITAL_ALWAYS_SHOW || is_bottomless()
if(REQUIRE_GENITAL_UNEXPOSED)
return genital.visibility_preference != GENITAL_ALWAYS_SHOW && !is_bottomless()
else
return TRUE
/// Returns true if the human has a accessible balls for the parameter. Accepts any of the `REQUIRE_GENITAL_` defines.
/mob/living/carbon/human/proc/has_balls(required_state = REQUIRE_GENITAL_ANY)
var/obj/item/organ/external/genital/genital = getorganslot(ORGAN_SLOT_TESTICLES)
if(!genital)
return FALSE
switch(required_state)
if(REQUIRE_GENITAL_ANY)
return TRUE
if(REQUIRE_GENITAL_EXPOSED)
return genital.visibility_preference == GENITAL_ALWAYS_SHOW || is_bottomless()
if(REQUIRE_GENITAL_UNEXPOSED)
return genital.visibility_preference != GENITAL_ALWAYS_SHOW && !is_bottomless()
else
return TRUE
/// Returns true if the human has an accessible vagina for the parameter. Accepts any of the `REQUIRE_GENITAL_` defines.
/mob/living/carbon/human/proc/has_vagina(required_state = REQUIRE_GENITAL_ANY)
var/obj/item/organ/external/genital/genital = getorganslot(ORGAN_SLOT_VAGINA)
if(!genital)
return FALSE
switch(required_state)
if(REQUIRE_GENITAL_ANY)
return TRUE
if(REQUIRE_GENITAL_EXPOSED)
return genital.visibility_preference == GENITAL_ALWAYS_SHOW || is_bottomless()
if(REQUIRE_GENITAL_UNEXPOSED)
return genital.visibility_preference != GENITAL_ALWAYS_SHOW && !is_bottomless()
else
return TRUE
/// Returns true if the human has a accessible breasts for the parameter. Accepts any of the `REQUIRE_GENITAL_` defines.
/mob/living/carbon/human/proc/has_breasts(required_state = REQUIRE_GENITAL_ANY)
var/obj/item/organ/external/genital/genital = getorganslot(ORGAN_SLOT_BREASTS)
if(!genital)
return FALSE
switch(required_state)
if(REQUIRE_GENITAL_ANY)
return TRUE
if(REQUIRE_GENITAL_EXPOSED)
return genital.visibility_preference == GENITAL_ALWAYS_SHOW || is_topless()
if(REQUIRE_GENITAL_UNEXPOSED)
return genital.visibility_preference != GENITAL_ALWAYS_SHOW && !is_topless()
else
return TRUE
/// Returns true if the human has an accessible anus for the parameter. Accepts any of the `REQUIRE_GENITAL_` defines.
/mob/living/carbon/human/proc/has_anus(required_state = REQUIRE_GENITAL_ANY)
if(issilicon(src))
return TRUE
var/obj/item/organ/external/genital/genital = getorganslot(ORGAN_SLOT_ANUS)
if(!genital)
return FALSE
switch(required_state)
if(REQUIRE_GENITAL_ANY)
return TRUE
if(REQUIRE_GENITAL_EXPOSED)
return genital.visibility_preference == GENITAL_ALWAYS_SHOW || is_bottomless()
if(REQUIRE_GENITAL_UNEXPOSED)
return genital.visibility_preference != GENITAL_ALWAYS_SHOW && !is_bottomless()
else
return TRUE
/// Returns true if the human has a accessible feet for the parameter, returning the number of feet the human has if they do. Accepts any of the `REQUIRE_GENITAL_` defines.
/mob/living/carbon/human/proc/has_arms(required_state = REQUIRE_GENITAL_ANY)
var/hand_count = 0
var/covered = 0
var/is_covered = FALSE
for(var/obj/item/bodypart/l_arm/left_arm in bodyparts)
hand_count++
for(var/obj/item/bodypart/r_arm/right_arm in bodyparts)
hand_count++
if(get_item_by_slot(ITEM_SLOT_HANDS))
var/obj/item/clothing/gloves/worn_gloves = get_item_by_slot(ITEM_SLOT_HANDS)
covered = worn_gloves.body_parts_covered
if(covered & HANDS)
is_covered = TRUE
switch(required_state)
if(REQUIRE_GENITAL_ANY)
return hand_count
if(REQUIRE_GENITAL_EXPOSED)
if(is_covered)
return FALSE
else
return hand_count
if(REQUIRE_GENITAL_UNEXPOSED)
if(!is_covered)
return FALSE
else
return hand_count
else
return hand_count
/// Returns true if the human has a accessible feet for the parameter, returning the number of feet the human has if they do. Accepts any of the `REQUIRE_GENITAL_` defines.
/mob/living/carbon/human/proc/has_feet(required_state = REQUIRE_GENITAL_ANY)
var/feet_count = 0
for(var/obj/item/bodypart/l_leg/left_leg in bodyparts)
feet_count++
for(var/obj/item/bodypart/r_leg/right_leg in bodyparts)
feet_count++
switch(required_state)
if(REQUIRE_GENITAL_ANY)
return feet_count
if(REQUIRE_GENITAL_EXPOSED)
if(!is_barefoot())
return FALSE
else
return feet_count
if(REQUIRE_GENITAL_UNEXPOSED)
if(is_barefoot())
return FALSE
else
return feet_count
else
return feet_count
/// Gets the number of feet the human has.
/mob/living/carbon/human/proc/get_num_feet()
return has_feet(REQUIRE_GENITAL_ANY)
/// Returns true if the human has a accessible ears for the parameter. Accepts any of the `REQUIRE_GENITAL_` defines.
/mob/living/carbon/human/proc/has_ears(required_state = REQUIRE_GENITAL_ANY)
var/obj/item/organ/genital = getorganslot(ORGAN_SLOT_EARS)
if(!genital)
return FALSE
switch(required_state)
if(REQUIRE_GENITAL_ANY)
return TRUE
if(REQUIRE_GENITAL_EXPOSED)
return !get_item_by_slot(ITEM_SLOT_EARS)
if(REQUIRE_GENITAL_UNEXPOSED)
return get_item_by_slot(ITEM_SLOT_EARS)
else
return TRUE
/// Returns true if the human has accessible eyes for the parameter. Accepts any of the `REQUIRE_GENITAL_` defines.
/mob/living/carbon/human/proc/has_eyes(required_state = REQUIRE_GENITAL_ANY)
var/obj/item/organ/genital = getorganslot(ORGAN_SLOT_EYES)
if(!genital)
return FALSE
switch(required_state)
if(REQUIRE_GENITAL_ANY)
return TRUE
if(REQUIRE_GENITAL_EXPOSED)
return !get_item_by_slot(ITEM_SLOT_EYES)
if(REQUIRE_GENITAL_UNEXPOSED)
return get_item_by_slot(ITEM_SLOT_EYES)
else
return TRUE
/*
* This code needed for changing character's gender by chems
*/
/// Sets the gender of the human, respecting prefs unless it's forced. Do not force in non-admin operations.
/mob/living/carbon/human/proc/set_gender(ngender = NEUTER, silent = FALSE, update_icon = TRUE, forced = FALSE)
var/bender = gender != ngender
if((!client?.prefs?.read_preference(/datum/preference/toggle/erp/gender_change) && !forced) || !dna || !bender)
return FALSE
if(ngender == MALE || ngender == FEMALE)
dna.features["body_model"] = ngender
if(!silent)
var/adj = ngender == MALE ? "masculine" : "feminine"
visible_message(span_boldnotice("[src] suddenly looks more [adj]!"), span_boldwarning("You suddenly feel more [adj]!"))
else if(ngender == NEUTER)
dna.features["body_model"] = MALE
gender = ngender
if(update_icon)
update_body()
/*
* ICON UPDATING EXTENTION
*/
/// Updating vagina slot
/mob/living/carbon/human/proc/update_inv_vagina()
// on_mob stuff
remove_overlay(VAGINA_LAYER)
var/obj/item/clothing/sextoy/sex_toy = vagina
if(wear_suit && (wear_suit.flags_inv & HIDESEXTOY)) // You can add proper flags here if required
return
var/icon_file = vagina?.worn_icon
var/mutable_appearance/vagina_overlay
if(!vagina_overlay)
vagina_overlay = sex_toy?.build_worn_icon(default_layer = VAGINA_LAYER, default_icon_file = 'icons/mob/clothing/under/default.dmi', isinhands = FALSE, override_file = icon_file)
if(OFFSET_UNIFORM in dna.species.offset_features)
vagina_overlay?.pixel_x += dna.species.offset_features[OFFSET_UNIFORM][1]
vagina_overlay?.pixel_y += dna.species.offset_features[OFFSET_UNIFORM][2]
overlays_standing[VAGINA_LAYER] = vagina_overlay
apply_overlay(VAGINA_LAYER)
update_mutant_bodyparts()
/// Updating anus slot
/mob/living/carbon/human/proc/update_inv_anus()
// on_mob stuff
remove_overlay(ANUS_LAYER)
var/obj/item/clothing/sextoy/sex_toy = anus
if(wear_suit && (wear_suit.flags_inv & HIDESEXTOY)) // You can add proper flags here if required
return
var/icon_file = anus?.worn_icon
var/mutable_appearance/anus_overlay
if(!anus_overlay)
anus_overlay = sex_toy?.build_worn_icon(default_layer = ANUS_LAYER, default_icon_file = 'icons/mob/clothing/under/default.dmi', isinhands = FALSE, override_file = icon_file)
if(OFFSET_UNIFORM in dna.species.offset_features)
anus_overlay?.pixel_x += dna.species.offset_features[OFFSET_UNIFORM][1]
anus_overlay?.pixel_y += dna.species.offset_features[OFFSET_UNIFORM][2]
overlays_standing[ANUS_LAYER] = anus_overlay
apply_overlay(ANUS_LAYER)
update_mutant_bodyparts()
/// Updating nipples slot
/mob/living/carbon/human/proc/update_inv_nipples()
// on_mob stuff
remove_overlay(NIPPLES_LAYER)
var/obj/item/clothing/sextoy/sex_toy = nipples
if(wear_suit && (wear_suit.flags_inv & HIDESEXTOY)) // You can add proper flags here if required
return
var/icon_file = nipples?.worn_icon
var/mutable_appearance/nipples_overlay
if(!nipples_overlay)
nipples_overlay = sex_toy?.build_worn_icon(default_layer = NIPPLES_LAYER, default_icon_file = 'icons/mob/clothing/under/default.dmi', isinhands = FALSE, override_file = icon_file)
if(OFFSET_UNIFORM in dna.species.offset_features)
nipples_overlay?.pixel_x += dna.species.offset_features[OFFSET_UNIFORM][1]
nipples_overlay?.pixel_y += dna.species.offset_features[OFFSET_UNIFORM][2]
overlays_standing[NIPPLES_LAYER] = nipples_overlay
apply_overlay(NIPPLES_LAYER)
update_mutant_bodyparts()
/// Updating penis slot
/mob/living/carbon/human/proc/update_inv_penis()
// on_mob stuff
remove_overlay(PENIS_LAYER)
var/obj/item/clothing/sextoy/sex_toy = penis
if(wear_suit && (wear_suit.flags_inv & HIDESEXTOY)) // You can add proper flags here if required
return
var/icon_file = penis?.worn_icon
var/mutable_appearance/penis_overlay
if(!penis_overlay)
penis_overlay = sex_toy?.build_worn_icon(default_layer = PENIS_LAYER, default_icon_file = 'icons/mob/clothing/under/default.dmi', isinhands = FALSE, override_file = icon_file)
if(OFFSET_UNIFORM in dna.species.offset_features)
penis_overlay?.pixel_x += dna.species.offset_features[OFFSET_UNIFORM][1]
penis_overlay?.pixel_y += dna.species.offset_features[OFFSET_UNIFORM][2]
overlays_standing[PENIS_LAYER] = penis_overlay
apply_overlay(PENIS_LAYER)
update_mutant_bodyparts()
/// Helper proc for calling all the lewd slot update_inv_ procs.
/mob/living/carbon/human/proc/update_inv_lewd()
update_inv_vagina()
update_inv_anus()
update_inv_nipples()
update_inv_penis()
/*
* MISC LOGIC
*/
// Handles breaking out of gloves that restrain people.
/mob/living/carbon/human/resist_restraints()
if(gloves?.breakouttime)
changeNext_move(CLICK_CD_BREAKOUT)
last_special = world.time + CLICK_CD_BREAKOUT
cuff_resist(gloves)
else
..()
/// Checks if the human is wearing a condom, and also hasn't broken it.
/mob/living/carbon/human/proc/is_wearing_condom()
if(!penis || !istype(penis, /obj/item/clothing/sextoy/condom))
return FALSE
var/obj/item/clothing/sextoy/condom/condom = penis
return condom.condom_state == CONDOM_BROKEN
// For handling things that don't already have handcuff handlers.
/mob/living/carbon/human/set_handcuffed(new_value)
if(wear_suit && istype(wear_suit, /obj/item/clothing/suit/straight_jacket/kinky_sleepbag))
return FALSE
..()
@@ -0,0 +1,62 @@
/*
* Looping sound for vibrating stuff
*/
/datum/looping_sound/vibrator
start_sound = 'modular_skyrat/modules/modular_items/lewd_items/sounds/bzzz-loop-1.ogg'
start_length = 1
mid_sounds = 'modular_skyrat/modules/modular_items/lewd_items/sounds/bzzz-loop-1.ogg'
mid_length = 1
end_sound = 'modular_skyrat/modules/modular_items/lewd_items/sounds/bzzz-loop-1.ogg'
falloff_distance = 1
falloff_exponent = 5
extra_range = SILENCED_SOUND_EXTRARANGE
ignore_walls = FALSE
/datum/looping_sound/vibrator/low
volume = 80
/datum/looping_sound/vibrator/medium
volume = 90
/datum/looping_sound/vibrator/high
volume = 100
/*
* Dancing pole code.
*/
/atom
var/pseudo_z_axis
/atom/proc/get_fake_z()
return pseudo_z_axis
/obj/structure/table
pseudo_z_axis = 8
/turf/open/get_fake_z()
var/objschecked
for(var/obj/structure/structurestocheck in contents)
objschecked++
if(structurestocheck.pseudo_z_axis)
return structurestocheck.pseudo_z_axis
if(objschecked >= 25)
break
return pseudo_z_axis
/mob/living/Move(atom/newloc, direct)
. = ..()
if(.)
pseudo_z_axis = newloc.get_fake_z()
pixel_z = pseudo_z_axis
/// Used to add a cum decal to the floor while transferring viruses and DNA to it
/mob/living/proc/add_cum_splatter_floor(turf/the_turf, female = FALSE)
if(!the_turf)
the_turf = get_turf(src)
var/selected_type = female ? /obj/effect/decal/cleanable/cum/femcum : /obj/effect/decal/cleanable/cum
var/atom/stain = new selected_type(the_turf, get_static_viruses())
stain.transfer_mob_blood_dna(src) //I'm not adding a new forensics category for cumstains
@@ -0,0 +1,6 @@
/obj/item/organ/internal/brain/on_life(delta_time, times_fired) //All your horny is here *points to the head*
. = ..()
var/mob/living/carbon/human/brain_owner = owner
if(istype(brain_owner, /mob/living/carbon/human) && brain_owner.client?.prefs?.read_preference(/datum/preference/toggle/erp/sex_toy))
if(!(organ_flags & ORGAN_FAILING))
brain_owner.dna.species.handle_arousal(brain_owner, delta_time, times_fired)
@@ -0,0 +1,91 @@
#define AROUSED_ALERT "aroused"
#define AROUSED_SMALL "small"
#define AROUSED_MEDIUM "medium"
#define AROUSED_HIGH "high"
#define AROUSED_MAX "max"
/// Sends an icon to the screen that gives an approximate indication of the mob's arousal.
/datum/species/proc/throw_arousal_alert(level, atom/movable/screen/alert/aroused/arousal_alert, mob/living/carbon/human/targeted_human)
targeted_human.throw_alert(AROUSED_ALERT, /atom/movable/screen/alert/aroused)
arousal_alert?.icon_state = "arousal_[level]"
arousal_alert?.update_icon()
/// Sends an icon to the screen that gives an approximate indication of the mob's pain. Looks like spikes/barbed wire.
/datum/species/proc/overlay_pain(level, atom/movable/screen/alert/aroused/arousal_alert)
arousal_alert?.cut_overlay(arousal_alert.pain_overlay)
arousal_alert?.pain_level = level
arousal_alert?.pain_overlay = arousal_alert.update_pain()
arousal_alert?.add_overlay(arousal_alert.pain_overlay)
arousal_alert?.update_overlays()
/// Sends an icon to the screen that gives an approximate indication of the mob's pleasure. Looks like a pink-white border on the arousal alert heart.
/datum/species/proc/overlay_pleasure(level, atom/movable/screen/alert/aroused/arousal_alert)
arousal_alert?.cut_overlay(arousal_alert.pleasure_overlay)
arousal_alert?.pleasure_level = level
arousal_alert?.pleasure_overlay = arousal_alert.update_pleasure()
arousal_alert?.add_overlay(arousal_alert.pleasure_overlay)
arousal_alert?.update_overlays()
/// Handles throwing the arousal alerts to screen.
/datum/species/proc/handle_arousal(mob/living/carbon/human/target_human, atom/movable/screen/alert/aroused)
if(!target_human.client?.prefs?.read_preference(/datum/preference/toggle/erp/sex_toy))
return
var/atom/movable/screen/alert/aroused/arousal_alert = target_human.alerts[AROUSED_ALERT]
var/alert_state
switch(target_human.arousal)
if(-INFINITY to AROUSAL_MINIMUM_DETECTABLE)
target_human.clear_alert(AROUSED_ALERT, /atom/movable/screen/alert/aroused)
if(target_human.arousal < AROUSAL_MINIMUM)
target_human.arousal = AROUSAL_MINIMUM // To prevent massively negative values that break the lewd system for some.
if(AROUSAL_MINIMUM_DETECTABLE to AROUSAL_LOW)
alert_state = AROUSED_SMALL
if(AROUSAL_LOW to AROUSAL_MEDIUM)
alert_state = AROUSED_MEDIUM
if(AROUSAL_HIGH to AROUSAL_AUTO_CLIMAX_THRESHOLD)
alert_state = AROUSED_HIGH
if(AROUSAL_AUTO_CLIMAX_THRESHOLD to INFINITY) //to prevent that 101 arousal that can make icon disappear or something.
alert_state = AROUSED_MAX
if(alert_state)
throw_arousal_alert(alert_state, arousal_alert, target_human)
alert_state = null
switch(target_human.pain)
if(-INFINITY to AROUSAL_MINIMUM_DETECTABLE) //to prevent same thing with pain
arousal_alert?.cut_overlay(arousal_alert.pain_overlay)
if(target_human.pain < AROUSAL_MINIMUM)
target_human.pain = AROUSAL_MINIMUM // To prevent massively negative values that break the lewd system for some.
if(AROUSAL_MINIMUM_DETECTABLE to AROUSAL_LOW)
alert_state = AROUSED_SMALL
if(AROUSAL_LOW to AROUSAL_MEDIUM)
alert_state = AROUSED_MEDIUM
if(AROUSAL_HIGH to AROUSAL_AUTO_CLIMAX_THRESHOLD)
alert_state = AROUSED_HIGH
if(AROUSAL_AUTO_CLIMAX_THRESHOLD to INFINITY)
alert_state = AROUSED_MAX
if(alert_state)
overlay_pain(alert_state, arousal_alert)
alert_state = null
switch(target_human.pleasure)
if(-INFINITY to AROUSAL_MINIMUM_DETECTABLE) //to prevent same thing with pleasure
arousal_alert?.cut_overlay(arousal_alert.pleasure_overlay)
if(target_human.pleasure < AROUSAL_MINIMUM)
target_human.pleasure = AROUSAL_MINIMUM // To prevent massively negative values that break the lewd system for some.
if(AROUSAL_MINIMUM_DETECTABLE to AROUSAL_LOW)
alert_state = AROUSED_SMALL
if(AROUSAL_LOW to AROUSAL_MEDIUM)
alert_state = AROUSED_MEDIUM
if(AROUSAL_HIGH to AROUSAL_AUTO_CLIMAX_THRESHOLD)
alert_state = AROUSED_HIGH
if(AROUSAL_AUTO_CLIMAX_THRESHOLD to INFINITY)
alert_state = AROUSED_MAX
if(alert_state)
overlay_pleasure(alert_state, arousal_alert)
#undef AROUSED_ALERT
#undef AROUSED_SMALL
#undef AROUSED_MEDIUM
#undef AROUSED_HIGH
#undef AROUSED_MAX
@@ -0,0 +1,56 @@
// Milking machine
/obj/item/storage/box/milking_kit
name = "DIY milking machine kit"
desc = "Contains everything you need to build your own milking machine!"
/obj/item/storage/box/milking_kit/PopulateContents()
var/static/items_inside = list(
/obj/item/milking_machine/constructionkit = 1)
generate_items_inside(items_inside, src)
// X-Stand
/obj/item/storage/box/xstand_kit
name = "DIY x-stand kit"
desc = "Contains everything you need to build your own X-stand!"
/obj/item/storage/box/xstand_kit/PopulateContents()
var/static/items_inside = list(
/obj/item/x_stand_kit = 1)
generate_items_inside(items_inside, src)
// BDSM bed
/obj/item/storage/box/bdsmbed_kit
name = "DIY BDSM bed kit"
desc = "Contains everything you need to build your own BDSM bed!"
/obj/item/storage/box/bdsmbed_kit/PopulateContents()
var/static/items_inside = list(
/obj/item/bdsm_bed_kit = 1)
generate_items_inside(items_inside, src)
// Striptease pole
/obj/item/storage/box/strippole_kit
name = "DIY stripper pole kit"
desc = "Contains everything you need to build your own stripper pole!"
/obj/item/storage/box/strippole_kit/PopulateContents()
var/static/items_inside = list(
/obj/item/polepack = 1)
generate_items_inside(items_inside, src)
// Shibari stand
/obj/item/storage/box/shibari_stand
name = "DIY shibari stand kit"
desc = "Contains everything you need to build your own shibari stand!"
/obj/item/storage/box/shibari_stand/PopulateContents()
var/static/items_inside = list(
/obj/item/shibari_stand_kit = 1,
/obj/item/paper/shibari_kit_instructions = 1)
generate_items_inside(items_inside, src)
// Paper instructions for shibari kit
/obj/item/paper/shibari_kit_instructions
default_raw_text = "Hello! Congratulations on your purchase of the shibari kit by LustWish! Some newbies may get confused by our ropes, so we prepared a small instructions for you! First of all, you have to have a wrench to construct the stand itself. Secondly, you can use screwdrivers to change the color of your shibari stand. Just replace the plastic fittings! Thirdly, if you want to tie somebody to a bondage stand you need to fully tie their body, on both groin and chest!. To do that you need to use rope on body and then on groin of character, then you can just buckle them to the stand like any chair. Don't forget to have some ropes on your hand to actually tie them to the stand, as there's no ropes included with it! And that's it!"
@@ -0,0 +1,63 @@
#define CUM_VOLUME_MULTIPLIER 5 + 5
/obj/item/hand_item/coom
name = "cum"
desc = "C-can I watch...?"
icon = 'icons/obj/hydroponics/harvest.dmi'
icon_state = "eggplant"
inhand_icon_state = "nothing"
// Jerk off into bottles and onto people.
/obj/item/hand_item/coom/afterattack(obj/target, mob/user, proximity)
. = ..()
do_masturbate(target, user, proximity)
/// Handles masturbation onto a living mob, or an atom.
/// Attempts to fill the atom's reagent container, if it has one, and it isn't full.
/obj/item/hand_item/coom/proc/do_masturbate(obj/target, mob/user, proximity)
if (CONFIG_GET(flag/disable_erp_preferences) || !proximity || user.stat >= DEAD)
return
var/mob/living/carbon/human/affected_human = user
var/obj/item/organ/external/genital/testicles/testicles = affected_human.getorganslot(ORGAN_SLOT_TESTICLES)
var/obj/item/organ/external/genital/penis/penis = affected_human.getorganslot(ORGAN_SLOT_PENIS)
var/datum/sprite_accessory/genital/penis_sprite = GLOB.sprite_accessories[ORGAN_SLOT_PENIS][affected_human.dna.species.mutant_bodyparts[ORGAN_SLOT_PENIS][MUTANT_INDEX_NAME]]
if(penis_sprite.is_hidden(affected_human))
to_chat(user, span_notice("You need to expose yourself in order to masturbate."))
return
else if(penis.aroused != AROUSAL_FULL)
to_chat(user, span_notice("You need to be aroused in order to masturbate."))
return
var/cum_volume = testicles.genital_size * CUM_VOLUME_MULTIPLIER
if(target == user)
user.visible_message(span_warning("[user] starts masturbating onto [target.p_them()]self!"), span_danger("You start masturbating onto yourself!"))
else if(target.is_refillable() && target.is_drainable())
if(target.reagents.holder_full())
to_chat(user, span_warning("[target] is full."))
return
user.visible_message(span_warning("[user] starts masturbating into [target]!"), span_danger("You start masturbating into [target]!"))
else
user.visible_message(span_warning("[user] starts masturbating onto [target]!"), span_danger("You start masturbating onto [target]!"))
if(do_after(user, 6 SECONDS, target))
if(target == user)
user.visible_message(span_warning("[user] cums on [target.p_them()]self!"), span_danger("You cum on yourself!"))
else if(target.is_refillable() && target.is_drainable())
var/datum/reagents/applied_reagents = new/datum/reagents(50)
applied_reagents.add_reagent(/datum/reagent/consumable/cum, cum_volume)
user.visible_message(span_warning("[user] cums into [target]!"), span_danger("You cum into [target]!"))
playsound(target, SFX_DESECRATION, 50, TRUE, ignore_walls = FALSE)
applied_reagents.trans_to(target, cum_volume)
else
user.visible_message(span_warning("[user] cums on [target]!"), span_danger("You cum on [target]!"))
playsound(target, SFX_DESECRATION, 50, TRUE, ignore_walls = FALSE)
affected_human.add_cum_splatter_floor(get_turf(target))
log_combat(user, target, "came on")
if(prob(40))
affected_human.try_lewd_autoemote("moan")
qdel(src)
#undef CUM_VOLUME_MULTIPLIER
@@ -0,0 +1,34 @@
/obj/item/clothing/sextoy
name = "sextoy"
icon = 'modular_skyrat/modules/modular_items/lewd_items/icons/obj/lewd_items/lewd_items.dmi'
worn_icon = 'modular_skyrat/modules/modular_items/lewd_items/icons/mob/lewd_items/lewd_items.dmi'
equip_sound = 'modular_skyrat/modules/modular_items/lewd_items/sounds/bang1.ogg'
drop_sound = 'modular_skyrat/modules/modular_items/lewd_items/sounds/bang2.ogg'
pickup_sound = 'sound/items/handling/cloth_pickup.ogg'
/// This is used to decide what lewd slot a toy should be able to be inserted into.
/// The currently accepted defines are all prefixes with LEWD_SLOT_, and there is one for each lewd organ.
/// See code/__DEFINES/~skyrat_defines/inventory.dm for the full list.
var/lewd_slot_flags = NONE
/obj/item/clothing/sextoy/dropped(mob/user)
..()
update_appearance()
if(!ishuman(loc))
return
var/mob/living/carbon/human/holder = loc
holder.update_inv_lewd()
holder.fan_hud_set_fandom()
/// A check to confirm if you can open the toy's color/design radial menu
/obj/item/clothing/sextoy/proc/check_menu(mob/living/user)
if(!istype(user))
return FALSE
if(user.incapacitated())
return FALSE
return TRUE
/// Returns if the item is inside a lewd slot.
/obj/item/clothing/sextoy/proc/is_inside_lewd_slot(mob/living/carbon/human/target)
return (src == target.penis || src == target.vagina || src == target.anus || src == target.nipples)
@@ -10,7 +10,7 @@
icon = 'modular_skyrat/modules/modular_items/lewd_items/icons/obj/lewd_items/lewd_items.dmi'
lefthand_file = 'modular_skyrat/modules/modular_items/lewd_items/icons/mob/lewd_inhands/lewd_inhand_left.dmi'
righthand_file = 'modular_skyrat/modules/modular_items/lewd_items/icons/mob/lewd_inhands/lewd_inhand_right.dmi'
slot_flags = ITEM_SLOT_PENIS | ITEM_SLOT_VAGINA | ITEM_SLOT_NIPPLES | ITEM_SLOT_ANUS
lewd_slot_flags = LEWD_SLOT_PENIS | LEWD_SLOT_VAGINA | LEWD_SLOT_NIPPLES | LEWD_SLOT_ANUS
clothing_flags = INEDIBLE_CLOTHING
/// Is the toy currently on
var/toy_on = FALSE
@@ -113,7 +113,7 @@
. = ..()
if(!istype(user))
return
if(is_in_genital(user))
if(is_inside_lewd_slot(user))
START_PROCESSING(SSobj, src)
/obj/item/clothing/sextoy/eggvib/dropped(mob/user, silent)
@@ -127,14 +127,14 @@
if(!istype(target))
return
if(vibration_mode == "low")
target.adjustArousal(0.5 * delta_time)
target.adjustPleasure(0.5 * delta_time)
target.adjust_arousal(0.5 * delta_time)
target.adjust_pleasure(0.5 * delta_time)
if(vibration_mode == "medium")
target.adjustArousal(0.6 * delta_time)
target.adjustPleasure(0.6 * delta_time)
target.adjust_arousal(0.6 * delta_time)
target.adjust_pleasure(0.6 * delta_time)
if(vibration_mode == "high")
target.adjustArousal(0.7 * delta_time)
target.adjustPleasure(0.7 * delta_time)
target.adjust_arousal(0.7 * delta_time)
target.adjust_pleasure(0.7 * delta_time)
/*
* SIGNALLER CONTROLLED EGG
@@ -249,7 +249,7 @@
to_chat(vibrated, span_purple("You feel pleasant vibrations deep below..."))
else if(src == vibrated.nipples)
to_chat(vibrated, span_purple("You feel pleasant stimulation in your nipples."))
else if(!toy_on && is_in_genital(vibrated))
else if(!toy_on && is_inside_lewd_slot(vibrated))
to_chat(vibrated, span_purple("The vibrating toy no longer drives you mad."))
if(!master)
@@ -7,7 +7,7 @@
icon = 'modular_skyrat/modules/modular_items/lewd_items/icons/obj/lewd_items/lewd_items.dmi'
lefthand_file = 'modular_skyrat/modules/modular_items/lewd_items/icons/mob/lewd_inhands/lewd_inhand_left.dmi'
righthand_file = 'modular_skyrat/modules/modular_items/lewd_items/icons/mob/lewd_inhands/lewd_inhand_right.dmi'
slot_flags = ITEM_SLOT_ANUS|ITEM_SLOT_VAGINA
lewd_slot_flags = LEWD_SLOT_ANUS | LEWD_SLOT_VAGINA
/// Current color of the toy, can be changed, affects sprite
var/current_color = "pink"
/// Current size of the toy, can be changed, affects sprite and arousal
@@ -106,14 +106,14 @@
return
// I tried using switch here, but it need static value, and u.arousal can't be it. So fuck switches. Reject it, embrace the IFs
if(current_size == "small" && target.arousal < 30)
target.adjustArousal(0.6 * delta_time)
target.adjustPleasure(0.7 * delta_time)
target.adjust_arousal(0.6 * delta_time)
target.adjust_pleasure(0.7 * delta_time)
else if(current_size == "medium" && target.arousal < 40)
target.adjustArousal(0.8 * delta_time)
target.adjustPleasure(0.8 * delta_time)
target.adjust_arousal(0.8 * delta_time)
target.adjust_pleasure(0.8 * delta_time)
else if(current_size == "big" && target.arousal < 50)
target.adjustArousal(1 * delta_time)
target.adjustPleasure(1 * delta_time)
target.adjust_arousal(delta_time)
target.adjust_pleasure(delta_time)
if(!(target.pain < 22.5)) //yeah, this will cause pain. No buttplug gib intended, sry
return
target.adjustPain(target*delta_time)
target.adjust_pain(target * delta_time)
@@ -6,7 +6,7 @@
icon_state = "clamps"
icon = 'modular_skyrat/modules/modular_items/lewd_items/icons/obj/lewd_items/lewd_items.dmi'
w_class = WEIGHT_CLASS_TINY
slot_flags = ITEM_SLOT_NIPPLES
lewd_slot_flags = LEWD_SLOT_NIPPLES
/// What kind are the wearer's breasts?
var/breast_type = null
/// What size are the wearer's breasts?
@@ -73,12 +73,12 @@
var/obj/item/organ/external/genital/breasts/target_breast = target.getorganslot(ORGAN_SLOT_BREASTS)
if(!target || !target_breast)
return
target.adjustArousal(1 * delta_time)
target.adjust_arousal(1 * delta_time)
if(target.pain < 27.5) //To prevent maxing pain by just pair of clamps.
target.adjustPain(1 * delta_time)
target.adjust_pain(1 * delta_time)
if(target.arousal < 15)
target.adjustArousal(1 * delta_time)
target.adjust_arousal(1 * delta_time)
if(target_breast.aroused != AROUSAL_CANT)
target_breast.aroused = AROUSAL_FULL //Clamps keeping nipples aroused
@@ -53,7 +53,7 @@
w_class = WEIGHT_CLASS_TINY
var/current_color = "pink"
var/condom_state = "unused"
slot_flags = ITEM_SLOT_PENIS
lewd_slot_flags = LEWD_SLOT_PENIS
/obj/item/clothing/sextoy/condom/Initialize(mapload)
. = ..()
@@ -72,20 +72,20 @@
condom_state = "dirty"
if(prob(10)) //chance of condom to break on first time.
name = "broken condom"
condom_state = "broken"
condom_state = CONDOM_BROKEN
update_icon_state()
update_icon()
if("dirty")
name = "broken condom"
condom_state = "broken"
condom_state = CONDOM_BROKEN
update_icon_state()
update_icon()
//When condom equipped we doing stuff
/obj/item/clothing/sextoy/condom/equipped(mob/user, slot, initial)
. = ..()
if((slot & ITEM_SLOT_PENIS) && condom_state == "unused")
if((slot == LEWD_SLOT_PENIS) && condom_state == "unused")
condom_state = "used"
update_icon_state()
update_icon()
@@ -27,7 +27,7 @@
/// If the toy can have its sprite changed
var/change_sprite = TRUE
w_class = WEIGHT_CLASS_TINY
slot_flags = ITEM_SLOT_ANUS|ITEM_SLOT_VAGINA
lewd_slot_flags = LEWD_SLOT_ANUS | LEWD_SLOT_VAGINA
clothing_flags = INEDIBLE_CLOTHING
/// Create an assoc list of designs for the radial color/design menu
@@ -81,14 +81,14 @@
if(!istype(user))
return
if(poly_size == "small" && user.arousal < (AROUSAL_REGULAR_THRESHOLD * 0.8))
user.adjustArousal(0.6 * delta_time)
user.adjustPleasure(0.6 * delta_time)
user.adjust_arousal(0.6 * delta_time)
user.adjust_pleasure(0.6 * delta_time)
else if(poly_size == "medium" && user.arousal < AROUSAL_REGULAR_THRESHOLD)
user.adjustArousal(0.8 * delta_time)
user.adjustPleasure(0.8 * delta_time)
user.adjust_arousal(0.8 * delta_time)
user.adjust_pleasure(0.8 * delta_time)
else if(poly_size == "big" && user.arousal < (AROUSAL_REGULAR_THRESHOLD * 1.2))
user.adjustArousal(1 * delta_time)
user.adjustPleasure(1 * delta_time)
user.adjust_arousal(1 * delta_time)
user.adjust_pleasure(1 * delta_time)
/obj/item/clothing/sextoy/dildo/attack(mob/living/carbon/human/target, mob/living/carbon/human/user)
. = ..()
@@ -110,32 +110,32 @@
return
message = (user == target) ? pick("rubs [target.p_their()] vagina with [src]", "gently jams [target.p_their()] pussy with [src]", "fucks [target.p_their()] vagina with a [src]") : pick("delicately rubs [target]'s vagina with [src]", "uses [src] to fuck [target]'s vagina", "jams [target]'s pussy with [src]", "teasing [target]'s pussy with [src]")
if(poly_size == "small")
target.adjustArousal(4)
target.adjustPleasure(5)
target.adjust_arousal(4)
target.adjust_pleasure(5)
if(prob(20) && (target.stat != DEAD))
target.try_lewd_autoemote("moan")
else if(poly_size == "medium")
target.adjustArousal(6)
target.adjustPleasure(8)
target.adjust_arousal(6)
target.adjust_pleasure(8)
if(prob(40) && (target.stat != DEAD))
target.try_lewd_autoemote(pick("twitch_s", "moan"))
else if(poly_size == "big")
target.adjustArousal(8)
target.adjustPleasure(10)
target.adjustPain(2)
target.adjust_arousal(8)
target.adjust_pleasure(10)
target.adjust_pain(2)
if(prob(60) && (target.stat != DEAD))
target.try_lewd_autoemote(pick("twitch_s", "moan", "gasp"))
if(side_double)
user.adjustArousal(6)
user.adjustPleasure(8)
user.adjust_arousal(6)
user.adjust_pleasure(8)
if(BODY_ZONE_HEAD, BODY_ZONE_PRECISE_MOUTH, BODY_ZONE_PRECISE_EYES) //Mouth only. Sorry, perverts. No eye/ear penetration for you today.
if(!target.is_mouth_covered())
to_chat(user, span_danger("Looks like [target]'s mouth is covered!"))
return
message = (user == target) ? pick("licks [src] erotically", "sucks on [src], slowly inserting it into [target.p_their()] throat") : pick("fucks [target]'s mouth with [src]", "inserts [src] into [target]'s throat, choking [target.p_them()]", "forces [target] to suck [src]", "inserts [src] into [target]'s throat")
target.adjustArousal(4)
target.adjustPleasure(1)
target.adjust_arousal(4)
target.adjust_pleasure(1)
if(prob(70) && (target.stat != DEAD))
target.try_lewd_autoemote(pick("gasp", "moan"))
@@ -145,8 +145,8 @@
to_chat(user, span_danger("[target]'s anus is covered!"))
return
message = (user == target) ? pick("puts [src] into [target.p_their()] anus", "slowly inserts [src] into [target.p_their()] ass") : pick("fucks [target]'s ass with [src]", "uses [src] to fuck [target]'s anus", "jams [target]'s ass with [src]", "roughly fucks [target]'s ass with [src], making [target.p_their()] eyes roll back")
target.adjustArousal(5)
target.adjustPleasure(5)
target.adjust_arousal(5)
target.adjust_pleasure(5)
if(prob(60) && (target.stat != DEAD))
target.try_lewd_autoemote(pick("twitch_s", "moan", "shiver"))
@@ -190,7 +190,7 @@ GLOBAL_LIST_INIT(dildo_colors, list(//mostly neon colors
var/static/list/dildo_sizes = list()
w_class = WEIGHT_CLASS_TINY
slot_flags = ITEM_SLOT_ANUS|ITEM_SLOT_VAGINA
lewd_slot_flags = LEWD_SLOT_ANUS | LEWD_SLOT_VAGINA
/obj/item/clothing/sextoy/dildo/custom_dildo/populate_dildo_designs()
dildo_sizes = list(
@@ -256,7 +256,7 @@ GLOBAL_LIST_INIT(dildo_colors, list(//mostly neon colors
lefthand_file = 'modular_skyrat/modules/modular_items/lewd_items/icons/mob/lewd_inhands/lewd_inhand_left.dmi'
righthand_file = 'modular_skyrat/modules/modular_items/lewd_items/icons/mob/lewd_inhands/lewd_inhand_right.dmi'
w_class = WEIGHT_CLASS_TINY
slot_flags = ITEM_SLOT_ANUS|ITEM_SLOT_VAGINA
lewd_slot_flags = LEWD_SLOT_ANUS | LEWD_SLOT_VAGINA
actions_types = list(/datum/action/item_action/take_dildo)
/// If one end of the toy is in your hand
var/in_hands = FALSE
@@ -370,8 +370,8 @@ GLOBAL_LIST_INIT(dildo_colors, list(//mostly neon colors
if(!istype(user))
return
if(user.arousal < AROUSAL_REGULAR_THRESHOLD)
user.adjustArousal(0.8 * delta_time)
user.adjustPleasure(0.8 * delta_time)
user.adjust_arousal(0.8 * delta_time)
user.adjust_pleasure(0.8 * delta_time)
/obj/item/clothing/sextoy/dildo/double_dildo/dropped(mob/living/carbon/human/user)
. = ..()
@@ -69,7 +69,7 @@
target.do_jitter_animation()
target.adjustStaminaLoss(4)
target.add_mood_event("tickled", /datum/mood_event/tickled)
target.adjustArousal(3)
target.adjust_arousal(3)
user.visible_message(span_purple("[user] [message]!"))
playsound(loc, pick('sound/items/handling/cloth_drop.ogg', // I duplicate this part of code because im useless shitcoder that can't make it work properly without tons of repeating code blocks
'sound/items/handling/cloth_pickup.ogg', // If you can make it better - go ahead, modify it, please.
@@ -72,8 +72,8 @@
if(!(prob(40) && (target.stat != DEAD)))
return
target.try_lewd_autoemote(pick("twitch_s", "moan", "blush"))
target.adjustArousal(6)
target.adjustPleasure(9)
target.adjust_arousal(6)
target.adjust_pleasure(9)
user.visible_message(span_purple("[user] [message]!"))
playsound(loc, pick('modular_skyrat/modules/modular_items/lewd_items/sounds/bang1.ogg',
'modular_skyrat/modules/modular_items/lewd_items/sounds/bang2.ogg',
@@ -283,5 +283,5 @@
target.try_lewd_autoemote(pick("twitch", "twitch_s", "shiver", "scream"))
target.do_jitter_animation()
target.adjustStaminaLoss(3)
target.adjustPain(9)
target.adjust_pain(9)
target.adjust_stutter(30 SECONDS)
@@ -176,7 +176,7 @@
if(prob(10))
target.apply_status_effect(/datum/status_effect/subspace)
target.Paralyze(1)//don't touch it. It's domination tool, it should have ability to put someone on kneels. I already inserted check for PREF YOU CAN'T ABUSE THIS ITEM
target.adjustPain(5)
target.adjust_pain(5)
playsound(loc, 'sound/weapons/whip.ogg', 100)
else
message = (user == target) ? pick("knocks [target.p_them()]self down with [src]", "gently uses [src] to knock [target.p_them()]self on the ground") : pick("drops [target] to the ground with [src]", "uses [src] to put [target] on [target.p_their()] knees")
@@ -186,7 +186,7 @@
if(prob(10))
target.apply_status_effect(/datum/status_effect/subspace)
target.Paralyze(1)
target.adjustPain(3)
target.adjust_pain(3)
playsound(loc, 'sound/weapons/whip.ogg', 60)
if(BODY_ZONE_R_LEG)
@@ -202,7 +202,7 @@
if(prob(10))
target.apply_status_effect(/datum/status_effect/subspace)
target.Paralyze(1)//don't touch it. It's domination tool, it should have ability to put someone on kneels. I already inserted check for PREF YOU CAN'T ABUSE THIS ITEM
target.adjustPain(5)
target.adjust_pain(5)
playsound(loc, 'sound/weapons/whip.ogg', 100)
else
message = (user == target) ? pick("Knocks [target.p_them()]self down with [src]", "gently uses [src] to knock [target.p_them()]self on the ground") : pick("drops [target] to the ground with [src]", "uses [src] to put [target] on [target.p_their()] knees")
@@ -212,7 +212,7 @@
if(prob(10))
target.apply_status_effect(/datum/status_effect/subspace)
target.Paralyze(1)
target.adjustPain(3)
target.adjust_pain(3)
playsound(loc, 'sound/weapons/whip.ogg', 60)
if(BODY_ZONE_HEAD)
@@ -220,8 +220,8 @@
message = (user == target) ? pick("wraps [src] around [target.p_their()] neck, choking [target.p_them()]self", "chokes [target.p_them()]self with [src]") : pick("chokes [target] with [src]", "twines [src] around [target]'s neck!")
if(prob(70) && (target.stat != DEAD))
target.try_lewd_autoemote(pick("gasp", "choke", "moan"))
target.adjustArousal(3)
target.adjustPain(5)
target.adjust_arousal(3)
target.adjust_pain(5)
playsound(loc, 'modular_skyrat/modules/modular_items/lewd_items/sounds/latex.ogg', 80)
if(BODY_ZONE_PRECISE_GROIN)
@@ -236,8 +236,8 @@
target.try_lewd_autoemote(pick("moan", "twitch"))
if(prob(10))
target.apply_status_effect(/datum/status_effect/subspace)
target.adjustArousal(5)
target.adjustPain(5)
target.adjust_arousal(5)
target.adjust_pain(5)
target.apply_status_effect(/datum/status_effect/spanked)
if(HAS_TRAIT(target, TRAIT_MASOCHISM || TRAIT_BIMBO))
target.add_mood_event("pervert spanked", /datum/mood_event/perv_spanked)
@@ -250,8 +250,8 @@
target.try_lewd_autoemote(pick("moan", "twitch", "twitch_s", "scream"))
if(prob(10))
target.apply_status_effect(/datum/status_effect/subspace)
target.adjustArousal(3)
target.adjustPain(8)
target.adjust_arousal(3)
target.adjust_pain(8)
target.apply_status_effect(/datum/status_effect/spanked)
if(HAS_TRAIT(target, TRAIT_MASOCHISM || TRAIT_BIMBO))
target.add_mood_event("pervert spanked", /datum/mood_event/perv_spanked)
@@ -265,7 +265,7 @@
if(prob(10))
target.apply_status_effect(/datum/status_effect/subspace)
target.do_jitter_animation()
target.adjustPain(7)
target.adjust_pain(7)
playsound(loc, 'sound/weapons/whip.ogg', 100)
else
@@ -276,8 +276,8 @@
if(prob(10))
target.apply_status_effect(/datum/status_effect/subspace)
target.do_jitter_animation()
target.adjustPain(4)
target.adjustArousal(5)
target.adjust_pain(4)
target.adjust_arousal(5)
playsound(loc, 'sound/weapons/whip.ogg', 60)
if(!targetedsomewhere)
return
@@ -23,7 +23,7 @@
/// Mutable appearance for the human overlay of this itme
var/mutable_appearance/magicwand_overlay
w_class = WEIGHT_CLASS_TINY
slot_flags = ITEM_SLOT_VAGINA|ITEM_SLOT_PENIS
lewd_slot_flags = LEWD_SLOT_VAGINA | LEWD_SLOT_PENIS
clothing_flags = INEDIBLE_CLOTHING
//some stuff for making overlay of this item. Why? Because.
@@ -74,14 +74,14 @@
return
// I tried using switch here, but it need static value, and u.arousal can't be it. So fuck switches. Reject it, embrace the IFs
if(vibration_mode == "low" && vibrated.arousal < 30)
vibrated.adjustArousal(0.6 * delta_time)
vibrated.adjustPleasure(0.7 * delta_time)
vibrated.adjust_arousal(0.6 * delta_time)
vibrated.adjust_pleasure(0.7 * delta_time)
else if(vibration_mode == "medium" && vibrated.arousal < 60)
vibrated.adjustArousal(0.8 * delta_time)
vibrated.adjustPleasure(0.8 * delta_time)
vibrated.adjust_arousal(0.8 * delta_time)
vibrated.adjust_pleasure(0.8 * delta_time)
else if(vibration_mode == "hard")
vibrated.adjustArousal(1 * delta_time)
vibrated.adjustPleasure(1 * delta_time)
vibrated.adjust_arousal(1 * delta_time)
vibrated.adjust_pleasure(1 * delta_time)
/obj/item/clothing/sextoy/magic_wand/attack(mob/living/carbon/human/target, mob/living/carbon/human/user)
. = ..()
@@ -124,17 +124,18 @@
to_chat(user, span_danger("Looks like [target]'s groin is covered!"))
return
message = (user == target) ? pick("massages their pussy with the [src]", "[vibration_mode == "low" ? "gently" : ""][vibration_mode = "hard" ? "roughly" : ""] teases their pussy with [src]") : pick("[vibration_mode == "low" ? "delicately" : ""][vibration_mode = "hard" ? "aggressively" : ""] massages [target]'s pussy with [src]", "uses [src] to [vibration_mode == "low" ? "gently" : ""][vibration_mode = "hard" ? "roughly" : ""] massage [target]'s pussy", "leans the vibrator against [target]'s pussy")
target.adjustArousal((vibration_mode == "low" ? 4 : (vibration_mode == "hard" ? 8 : 5)))
target.adjustPleasure((vibration_mode == "low" ? 2 : (vibration_mode == "hard" ? 10 : 5)))
target.adjust_arousal((vibration_mode == "low" ? 4 : (vibration_mode == "hard" ? 8 : 5)))
target.adjust_pleasure((vibration_mode == "low" ? 2 : (vibration_mode == "hard" ? 10 : 5)))
if(BODY_ZONE_CHEST)
var/obj/item/organ/external/genital/breasts = target.getorganslot(ORGAN_SLOT_BREASTS)
if(!(target.is_topless() || breasts.visibility_preference == GENITAL_ALWAYS_SHOW))
to_chat(user, span_danger("Looks like [target]'s chest is covered!"))
return
message = (user == target) ? pick("massages their [breasts ? "breasts" : "nipples"] with the [src]", "[vibration_mode == "low" ? "gently" : ""][vibration_mode = "hard" ? "roughly" : ""] teases their [breasts ? "tits" : "nipples"] with [src]") : pick("[vibration_mode == "low" ? "delicately" : ""][vibration_mode = "hard" ? "aggressively" : ""] teases [target]'s [breasts ? "breasts" : "nipples"] with [src]", "uses [src] to[vibration_mode == "low" ? " slowly" : ""] massage [target]'s [breasts ? "tits" : "nipples"]", "uses [src] to tease [target]'s [breasts ? "boobs" : "nipples"]")
target.adjustArousal((vibration_mode == "low" ? 3 : (vibration_mode == "hard" ? 7 : 4)))
target.adjustPleasure((vibration_mode == "low" ? 1 : (vibration_mode == "hard" ? 9 : 4)))
var/breasts_or_nipples = breasts ? ORGAN_SLOT_BREASTS : ORGAN_SLOT_NIPPLES
message = (user == target) ? pick("massages their [breasts_or_nipples] with the [src]", "[vibration_mode == "low" ? "gently" : ""][vibration_mode = "hard" ? "roughly" : ""] teases their [breasts ? "tits" : ORGAN_SLOT_NIPPLES] with [src]") : pick("[vibration_mode == "low" ? "delicately" : ""][vibration_mode = "hard" ? "aggressively" : ""] teases [target]'s [breasts_or_nipples] with [src]", "uses [src] to[vibration_mode == "low" ? " slowly" : ""] massage [target]'s [breasts ? "tits" : ORGAN_SLOT_NIPPLES]", "uses [src] to tease [target]'s [breasts ? "boobs" : ORGAN_SLOT_NIPPLES]")
target.adjust_arousal((vibration_mode == "low" ? 3 : (vibration_mode == "hard" ? 7 : 4)))
target.adjust_pleasure((vibration_mode == "low" ? 1 : (vibration_mode == "hard" ? 9 : 4)))
if(prob(30) && (target.stat != DEAD))
target.try_lewd_autoemote(pick("twitch_s", "moan"))
@@ -72,8 +72,8 @@
message = (user == target) ? pick("spanks themselves with [src]", "uses [src] to slap their hips") : pick("slaps [target]'s hips with [src]", "uses [src] to slap [target]'s butt", "spanks [target] with [src], making a loud slapping noise", "slaps [target]'s thighs with [src]")
if(prob(40) && (target.stat != DEAD))
target.try_lewd_autoemote(pick("twitch_s", "moan", "blush", "gasp"))
target.adjustArousal(2)
target.adjustPain(4)
target.adjust_arousal(2)
target.adjust_pain(4)
target.apply_status_effect(/datum/status_effect/spanked)
if(HAS_TRAIT(target, TRAIT_MASOCHISM || TRAIT_BIMBO))
target.add_mood_event("pervert spanked", /datum/mood_event/perv_spanked)
@@ -152,7 +152,7 @@
"drips hot wax from the [src] onto [attacked]'s genitalia, causing [attacked.p_them()] to shiver",
"tilts [src], dripping wax right onto [attacked]'s genitals, causing [attacked.p_them()] to moan",
"drips some wax onto [attacked]'s genitals, making [attacked.p_them()] moan in pleasure")
attacked.adjustPain(PAIN_DEFAULT)
attacked.adjust_pain(PAIN_DEFAULT)
else if(penis && (attacked.is_bottomless() || penis.visibility_preference == GENITAL_ALWAYS_SHOW))
message = (user == attacked) ? pick("drips some wax on [attacked.p_their()] penis, causing [attacked.p_them()] to moan in pleasure",
@@ -160,15 +160,15 @@
"drips wax right on [attacked]'s penis. It slightly itches.",
"drips hot wax from the [src] on the [attacked]'s penis, he slightly shivers.",
"tilts the candle. Drops of wax, dripping right from [src] right on the [attacked]'s penis, made him moan.")
attacked.adjustPain(PAIN_DEFAULT)
attacked.adjust_pain(PAIN_DEFAULT)
else if(vagina && (attacked.is_bottomless() || vagina.visibility_preference == GENITAL_ALWAYS_SHOW))
message = (user == attacked) ? pick("drips some wax on themselves, letting it reach his vagina. He moans in pleasure.", "drips some wax on the [attacked]'s pussy, he moans in pleasure") : pick("drips some wax on the [attacked]'s vagina, he moans in pleasure", "tilts the candle. Wax slowly goes down, reaching the [attacked]'s vagina.", "tilts the candle. Drops of wax, dripping right from [src] right on the [attacked]'s pussy, made him moan.")
attacked.adjustPain(PAIN_DEFAULT)
attacked.adjust_pain(PAIN_DEFAULT)
else if(attacked.is_bottomless())
message = (user == attacked) ? pick("drips some wax on themselves, letting it reach his belly. He moans in pleasure.", "drips some wax on the [attacked]'s tummy, he moans in pleasure") : pick("drips some wax on the [attacked]'s belly, he moans in pleasure", "tilts the candle. Wax slowly goes down, reaching the [attacked]'s tummy.", "tilts the candle. Drops of wax, dripping right from [src] right on the [attacked]'s groin, made him moan.")
attacked.adjustPain(PAIN_DEFAULT)
attacked.adjust_pain(PAIN_DEFAULT)
else
to_chat(user, span_danger("Looks like [attacked]'s groin is covered!"))
@@ -178,8 +178,9 @@
targeted_somewhere = TRUE
var/obj/item/organ/external/genital/breasts = attacked.getorganslot(ORGAN_SLOT_BREASTS)
if(attacked.is_topless() || breasts.visibility_preference == GENITAL_ALWAYS_SHOW)
message = (user == attacked) ? pick("drips some wax on [attacked.p_their()] [breasts ? "breasts" : "nipples"], releasing all [attacked.p_their()] lustness", "drips some wax right on [attacked.p_their()] [breasts ? "tits" : "chest"], making [attacked.p_their()] feel faint.") : pick("pours the wax that is slowly dripping from [src] onto [attacked]'s [breasts ? "breasts" : "nipples"], [attacked.p_they()] shows pure enjoyment.", "tilts the candle. Right in the moment when wax drips on [attacked]'s [breasts ? "breasts" : "nipples"], [attacked.p_they()] shivers", "tilts the candle. Just when hot drops of wax fell on [attacked]'s [breasts ? "breasts" : "nipples"], [attacked.p_they()] quietly moans in pleasure")
attacked.adjustPain(PAIN_DEFAULT * 0.66)
var/breasts_or_nipples = breasts ? ORGAN_SLOT_BREASTS : ORGAN_SLOT_NIPPLES
message = (user == attacked) ? pick("drips some wax on [attacked.p_their()] [breasts_or_nipples], releasing all [attacked.p_their()] lustness", "drips some wax right on [attacked.p_their()] [breasts ? "tits" : "chest"], making [attacked.p_their()] feel faint.") : pick("pours the wax that is slowly dripping from [src] onto [attacked]'s [breasts_or_nipples], [attacked.p_they()] shows pure enjoyment.", "tilts the candle. Right in the moment when wax drips on [attacked]'s [breasts_or_nipples], [attacked.p_they()] shivers", "tilts the candle. Just when hot drops of wax fell on [attacked]'s [breasts_or_nipples], [attacked.p_they()] quietly moans in pleasure")
attacked.adjust_pain(PAIN_DEFAULT * 0.66)
else
to_chat(user, span_danger("Looks like [attacked]'s chest is covered!"))
@@ -10,7 +10,7 @@
icon = 'modular_skyrat/modules/modular_items/lewd_items/icons/obj/lewd_items/lewd_items.dmi'
lefthand_file = 'modular_skyrat/modules/modular_items/lewd_items/icons/mob/lewd_inhands/lewd_inhand_left.dmi'
righthand_file = 'modular_skyrat/modules/modular_items/lewd_items/icons/mob/lewd_inhands/lewd_inhand_right.dmi'
slot_flags = ITEM_SLOT_VAGINA | ITEM_SLOT_ANUS
lewd_slot_flags = LEWD_SLOT_VAGINA | LEWD_SLOT_ANUS
/// If the toy is on or not
var/toy_on = FALSE
/// Current color of the toy, can be changed and affects sprite
@@ -94,17 +94,17 @@
return
if(toy_on)
if(vibration_mode == "low" && user.arousal < 40) //prevent non-stop cumming from wearing this thing
user.adjustArousal(0.7 * delta_time)
user.adjustPleasure(0.7 * delta_time)
user.adjust_arousal(0.7 * delta_time)
user.adjust_pleasure(0.7 * delta_time)
if(vibration_mode == "medium" && user.arousal < 70)
user.adjustArousal(1 * delta_time)
user.adjustPleasure(1 * delta_time)
user.adjust_arousal(1 * delta_time)
user.adjust_pleasure(1 * delta_time)
if(vibration_mode == "hard") //no mercy
user.adjustArousal(1.5 * delta_time)
user.adjustPleasure(1.5 * delta_time)
user.adjust_arousal(1.5 * delta_time)
user.adjust_pleasure(1.5 * delta_time)
else if(!toy_on && user.arousal < 30)
user.adjustArousal(0.5 * delta_time)
user.adjustPleasure(0.5 * delta_time)
user.adjust_arousal(0.5 * delta_time)
user.adjust_pleasure(0.5 * delta_time)
//SHITCODESHITCODESHITCODESHITCODESHITCODESHITCODESHITCODESHITCODESHITCODESHITCODESHITCODESHITCODESHITCODESHITCODESHITCODESHITCODE
/obj/item/clothing/sextoy/vibrator/attack(mob/living/carbon/human/target, mob/living/carbon/human/user)
@@ -128,18 +128,18 @@
var/obj/item/organ/external/genital/vagina = target.getorganslot(ORGAN_SLOT_VAGINA)
if((vagina && penis) && (vagina.visibility_preference == GENITAL_ALWAYS_SHOW && penis.visibility_preference == GENITAL_ALWAYS_SHOW || target.is_bottomless()))
message = (user == target) ? pick("massages their vagina with the [src]", "[vibration_mode == "low" ? "gently" : ""][vibration_mode = "hard" ? "roughly" : ""] teases their pussy with [src]", "massages their penis with the [src]", "[vibration_mode == "low" ? "gently" : ""][vibration_mode = "hard" ? "roughly" : ""] teases their penis with [src]") : pick("[vibration_mode == "low" ? "delicately" : ""][vibration_mode = "hard" ? "aggressively" : ""] massages [target]'s vagina with [src]", "uses [src] to [vibration_mode == "low" ? "gently" : ""][vibration_mode = "hard" ? "roughly" : ""] massage [target]'s crotch", "leans the massager against [target]'s pussy", "[vibration_mode == "low" ? "delicately" : ""][vibration_mode = "hard" ? "aggressively" : ""] massages [target]'s penis with [src]", "uses [src] to [vibration_mode == "low" ? "gently" : ""][vibration_mode = "hard" ? "roughly" : ""] massage [target]'s penis", "leans the massager against [target]'s penis")
target.adjustArousal(DEFAULT_AROUSAL_INCREASE)
target.adjustPleasure(DEFAULT_PLEASURE_INCREASE)
target.adjust_arousal(DEFAULT_AROUSAL_INCREASE)
target.adjust_pleasure(DEFAULT_PLEASURE_INCREASE)
else if(vagina && (vagina.visibility_preference == GENITAL_ALWAYS_SHOW || target.is_bottomless()))
message = (user == target) ? pick("massages their vagina with the [src]", "[vibration_mode == "low" ? "gently" : ""][vibration_mode = "hard" ? "roughly" : ""] teases their pussy with [src]") : pick("[vibration_mode == "low" ? "delicately" : ""][vibration_mode = "hard" ? "aggressively" : ""] massages [target]'s vagina with [src]", "uses [src] to [vibration_mode == "low" ? "gently" : ""][vibration_mode = "hard" ? "roughly" : ""] massage [target]'s crotch", "leans the massager against [target]'s pussy")
target.adjustArousal(DEFAULT_AROUSAL_INCREASE)
target.adjustPleasure(DEFAULT_PLEASURE_INCREASE)
target.adjust_arousal(DEFAULT_AROUSAL_INCREASE)
target.adjust_pleasure(DEFAULT_PLEASURE_INCREASE)
else if(penis && (penis.visibility_preference == GENITAL_ALWAYS_SHOW || target.is_bottomless()))
message = (user == target) ? pick("massages their penis with the [src]", "[vibration_mode == "low" ? "gently" : ""][vibration_mode = "hard" ? "roughly" : ""] teases their penis with [src]") : pick("[vibration_mode == "low" ? "delicately" : ""][vibration_mode = "hard" ? "aggressively" : ""] massages [target]'s penis with [src]", "uses [src] to [vibration_mode == "low" ? "gently" : ""][vibration_mode = "hard" ? "roughly" : ""] massage [target]'s penis", "leans the massager against [target]'s penis")
target.adjustArousal(DEFAULT_AROUSAL_INCREASE)
target.adjustPleasure(DEFAULT_PLEASURE_INCREASE)
target.adjust_arousal(DEFAULT_AROUSAL_INCREASE)
target.adjust_pleasure(DEFAULT_PLEASURE_INCREASE)
else
to_chat(user, span_danger("Looks like [target]'s groin is covered!"))
@@ -152,9 +152,10 @@
targetedsomewhere = TRUE
var/obj/item/organ/external/genital/breasts = target.getorganslot(ORGAN_SLOT_BREASTS)
if(target.is_topless() || breasts.visibility_preference == GENITAL_ALWAYS_SHOW)
message = (user == target) ? pick("massages their [breasts ? "breasts" : "nipples"] with the [src]", "[vibration_mode == "low" ? "gently" : ""][vibration_mode = "hard" ? "roughly" : ""] teases their tits with [src]") : pick("[vibration_mode == "low" ? "delicately" : ""][vibration_mode = "hard" ? "aggressively" : ""] teases [target]'s [breasts ? "breasts" : "nipples"] with [src]", "uses [src] to[vibration_mode == "low" ? " slowly" : ""] massage [target]'s [breasts ? "tits" : "nipples"]", "uses [src] to tease [target]'s [breasts ? "boobs" : "nipples"]", "rubs [target]'s [breasts ? "tits" : "nipples"] with [src]")
target.adjustArousal(DEFAULT_AROUSAL_INCREASE)
target.adjustPleasure(DEFAULT_PLEASURE_INCREASE * 0.5)
var/breasts_or_nipples = breasts ? ORGAN_SLOT_BREASTS : ORGAN_SLOT_NIPPLES
message = (user == target) ? pick("massages their [breasts_or_nipples] with the [src]", "[vibration_mode == "low" ? "gently" : ""][vibration_mode = "hard" ? "roughly" : ""] teases their tits with [src]") : pick("[vibration_mode == "low" ? "delicately" : ""][vibration_mode = "hard" ? "aggressively" : ""] teases [target]'s [breasts_or_nipples] with [src]", "uses [src] to[vibration_mode == "low" ? " slowly" : ""] massage [target]'s [breasts ? "tits" : ORGAN_SLOT_NIPPLES]", "uses [src] to tease [target]'s [breasts ? "boobs" : ORGAN_SLOT_NIPPLES]", "rubs [target]'s [breasts ? "tits" : ORGAN_SLOT_NIPPLES] with [src]")
target.adjust_arousal(DEFAULT_AROUSAL_INCREASE)
target.adjust_pleasure(DEFAULT_PLEASURE_INCREASE * 0.5)
if(prob(30) && (target.stat != DEAD))
target.try_lewd_autoemote(pick("twitch_s", "moan"))
@@ -14,7 +14,7 @@
/// Looping sound called on process
var/datum/looping_sound/vibrator/medium/soundloop
w_class = WEIGHT_CLASS_TINY
slot_flags = ITEM_SLOT_PENIS
lewd_slot_flags = LEWD_SLOT_PENIS
clothing_flags = INEDIBLE_CLOTHING
/obj/item/clothing/sextoy/vibroring/attack_self(mob/user)
@@ -84,7 +84,7 @@
var/obj/item/organ/external/genital/testicles/balls = user.getorganslot(ORGAN_SLOT_PENIS)
if(!toy_on || !balls)
return
user.adjustArousal(1 * delta_time)
user.adjustPleasure(1 * delta_time)
user.adjust_arousal(1 * delta_time)
user.adjust_pleasure(1 * delta_time)
if(balls.aroused != AROUSAL_CANT)
balls.aroused = AROUSAL_FULL //Vibroring keep penis erected.
@@ -97,8 +97,8 @@
/obj/item/reagent_containers/pill/camphor = 10,
/obj/item/reagent_containers/cup/bottle/crocin = 6,
/obj/item/reagent_containers/cup/bottle/camphor = 3,
/obj/item/reagent_containers/cup/bottle/breast_enlarger = 6, //Those are legal 'cause you can just turn off prefs in round in "CLOWN SMOKE MACHINE+PENIS ENLARGEMENT CHEMICAL CASE". Yes, i have special code-phrase for this. I've seen some shit.
/obj/item/reagent_containers/cup/bottle/penis_enlarger = 6,
/obj/item/reagent_containers/cup/bottle/succubus_milk = 6, //Those are legal 'cause you can just turn off prefs in round in "CLOWN SMOKE MACHINE+PENIS ENLARGEMENT CHEMICAL CASE". Yes, i have special code-phrase for this. I've seen some shit.
/obj/item/reagent_containers/cup/bottle/incubus_draft = 6,
//special
/obj/item/clothing/glasses/nice_goggles = 1, //easter egg, don't touch plz)
@@ -530,13 +530,6 @@
used_item.play_tool_sound(src, 50)
deconstruct(TRUE)
// // Object disassembly handler by wrench
// /obj/structure/chair/milking_machine/default_unfasten_wrench(mob/user, obj/item/used_item, time = 20)
// . = !(flags_1 & NODECONSTRUCT_1) && used_item.tool_behaviour == TOOL_WRENCH
// if(.)
// used_item.play_tool_sound(src, 50)
// deconstruct(TRUE)
// Machine Workflow Processor
/obj/structure/chair/milking_machine/process(delta_time)
@@ -546,8 +539,6 @@
pump_state = pump_state_list[1]
update_all_visuals()
return
// if(current_mode == mode_list[1] && pump_state == pump_state_list[1])
// cell.give(charge_rate * delta_time)
// Check if the machine should work
if(!current_mob)
@@ -600,17 +591,17 @@
if(istype(current_selected_organ, /obj/item/organ/external/genital/breasts))
if(current_selected_organ.reagents.total_volume > 0)
current_selected_organ.internal_fluids.trans_to(milk_vessel, milk_retrive_amount[current_mode] * fluid_multiplier * delta_time)
current_selected_organ.transfer_internal_fluid(milk_vessel, milk_retrive_amount[current_mode] * fluid_multiplier * delta_time)
else
return
else if (istype(current_selected_organ, /obj/item/organ/external/genital/vagina))
if(current_selected_organ.reagents.total_volume > 0)
current_selected_organ.internal_fluids.trans_to(girlcum_vessel, girlcum_retrive_amount[current_mode] * fluid_multiplier * delta_time)
current_selected_organ.transfer_internal_fluid(girlcum_vessel, girlcum_retrive_amount[current_mode] * fluid_multiplier * delta_time)
else
return
else if (istype(current_selected_organ, /obj/item/organ/external/genital/testicles))
if(current_selected_organ.reagents.total_volume > 0)
current_selected_organ.internal_fluids.trans_to(semen_vessel, semen_retrive_amount[current_mode] * fluid_multiplier * delta_time)
current_selected_organ.transfer_internal_fluid(semen_vessel, semen_retrive_amount[current_mode] * fluid_multiplier * delta_time)
else
return
else
@@ -619,9 +610,9 @@
// Handling the process of the impact of the machine on the organs of the mob
/obj/structure/chair/milking_machine/proc/increase_current_mob_arousal(delta_time)
src.current_mob.adjustArousal(src.arousal_amounts[src.current_mode] * delta_time)
src.current_mob.adjustPleasure(src.pleasure_amounts[src.current_mode] * delta_time)
src.current_mob.adjustPain(src.pain_amounts[src.current_mode] * delta_time)
current_mob.adjust_arousal(arousal_amounts[current_mode] * delta_time)
current_mob.adjust_pleasure(pleasure_amounts[current_mode] * delta_time)
current_mob.adjust_pain(pain_amounts[current_mode] * delta_time)
// Energy consumption processor
/obj/structure/chair/milking_machine/proc/draw_power_from_cell(delta_time)
@@ -765,7 +756,7 @@
organ_overlay.icon_state = organ_overlay_new_icon_state
if(istype(current_selected_organ, /obj/item/organ/external/genital/testicles))
current_selected_organ_type = "penis"
current_selected_organ_type = ORGAN_SLOT_PENIS
current_selected_organ_size = current_selected_organ.genital_size
if(current_mode == mode_list[1])
pump_state = pump_state_list[1]
@@ -779,7 +770,7 @@
organ_overlay.icon_state = organ_overlay_new_icon_state
if(istype(current_selected_organ, /obj/item/organ/external/genital/vagina))
current_selected_organ_type = "vagina"
current_selected_organ_type = ORGAN_SLOT_VAGINA
current_selected_organ_size = current_selected_organ.genital_size
if(current_mode == mode_list[1])
pump_state = pump_state_list[1]
@@ -859,12 +850,6 @@
/obj/structure/chair/milking_machine/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
/* Standard behavior. Uncomment for UI debugging
if(!ui)
ui = new(user, src, "MilkingMachine", name)
ui.open()
*/
//Block the interface if we are in the machine. Use in production
if(LAZYLEN(buckled_mobs))
if(user != src.buckled_mobs[1])
@@ -0,0 +1,30 @@
/obj/item/organ/external/genital
/// The fluid count of the genital.
var/internal_fluid_count = 0
/// The maximum amount of fluid that can be stored in the genital.
var/internal_fluid_maximum = 0
/// The datum to be used for the tracked fluid, should it need to be added to a fluid container.
var/internal_fluid_datum
/// The currently inserted sex toy.
var/obj/item/inserted_item
/// Helper proc for checking if internal fluids are full or not.
/obj/item/organ/external/genital/proc/internal_fluid_full()
return internal_fluid_count >= internal_fluid_maximum
/// Adds the given amount to the internal fluid count, clamping it between 0 and internal_fluid_maximum.
/obj/item/organ/external/genital/proc/adjust_internal_fluid(amount)
internal_fluid_count = clamp(internal_fluid_count + amount, 0, internal_fluid_maximum)
/// Tries to add the specified amount to the target reagent container. Keeps in mind internal_fluid_count.
/obj/item/organ/external/genital/proc/transfer_internal_fluid(datum/reagents/reagent_container, attempt_amount)
if(!internal_fluid_datum || !internal_fluid_count || !internal_fluid_maximum)
return
attempt_amount = clamp(attempt_amount, 0, internal_fluid_count)
reagent_container.add_reagent(internal_fluid_datum, attempt_amount)
internal_fluid_count -= attempt_amount
@@ -0,0 +1,18 @@
/obj/item/organ/external/genital/breasts
internal_fluid_datum = /datum/reagent/consumable/breast_milk
/obj/item/organ/external/genital/breasts/build_from_dna(datum/dna/DNA, associated_key)
. = ..()
var/breasts_capacity = 0
var/size = 0.5
if(DNA.features["breasts_size"] > 0)
size = DNA.features["breasts_size"]
switch(genital_type)
if("pair")
breasts_capacity = 2
if("quad")
breasts_capacity = 2.5
if("sextuple")
breasts_capacity = 3
internal_fluid_maximum = size * breasts_capacity * 60 // This seems like it could balloon drastically out of proportion with larger breast sizes.
@@ -0,0 +1,10 @@
/obj/item/organ/external/genital/testicles
internal_fluid_datum = /datum/reagent/consumable/cum
/obj/item/organ/external/genital/testicles/build_from_dna(datum/dna/DNA, associated_key)
. = ..()
var/size = 0.5
if(DNA.features["balls_size"] > 0)
size = DNA.features["balls_size"]
internal_fluid_maximum = size * 20
@@ -0,0 +1,6 @@
/obj/item/organ/external/genital/vagina
internal_fluid_datum = /datum/reagent/consumable/femcum
/obj/item/organ/external/genital/vagina/build_from_dna(datum/dna/DNA, associated_key)
. = ..()
internal_fluid_maximum = 10
@@ -93,9 +93,9 @@
else
stress = clamp(stress + 1, 0, 300)
human_owner.adjustArousal(10)
human_owner.adjust_arousal(10)
if(human_owner.pleasure < 80)
human_owner.adjustPleasure(5)
human_owner.adjust_pleasure(5)
//Anything beyond this obeys a cooldown system because we don't want to spam it
if(!COOLDOWN_FINISHED(src, desire_cooldown))
@@ -260,7 +260,7 @@
/datum/brain_trauma/very_special/sadism/on_life(delta_time, times_fired)
var/mob/living/carbon/human/affected_mob = owner
if(someone_suffering() && affected_mob.client?.prefs?.read_preference(/datum/preference/toggle/erp))
affected_mob.adjustArousal(2)
affected_mob.adjust_arousal(2)
owner.add_mood_event("sadistic", /datum/mood_event/sadistic)
else
owner.clear_mood_event("sadistic")
@@ -327,19 +327,22 @@
/mob/living/carbon/human/examine(mob/user)
. = ..()
var/mob/living/examiner = user
if(stat != DEAD && !HAS_TRAIT(src, TRAIT_FAKEDEATH) && src != examiner)
if(src != user)
if(HAS_TRAIT(examiner, TRAIT_EMPATH))
switch(arousal)
if(11 to 21)
. += span_purple("[p_they()] [p_are()] excited.") + "\n"
if(21.01 to 41)
. += span_purple("[p_they()] [p_are()] slightly blushed.") + "\n"
if(41.01 to 51)
. += span_purple("[p_they()] [p_are()] quite aroused and seems to be stirring up lewd thoughts in [p_their()] head.") + "\n"
if(51.01 to 61)
. += span_purple("[p_they()] [p_are()] very aroused and [p_their()] movements are seducing.") + "\n"
if(61.01 to 91)
. += span_purple("[p_they()] [p_are()] aroused as hell.") + "\n"
if(91.01 to INFINITY)
. += span_purple("[p_they()] [p_are()] extremely excited, exhausting from entolerable desire.") + "\n"
if(stat >= DEAD || HAS_TRAIT(src, TRAIT_FAKEDEATH) || src == examiner || !HAS_TRAIT(examiner, TRAIT_EMPATH))
return
if(examiner.client?.prefs?.read_preference(/datum/preference/toggle/erp))
var/arousal_message
switch(arousal)
if(AROUSAL_MINIMUM_DETECTABLE to AROUSAL_LOW)
arousal_message = span_purple("[p_they()] [p_are()] slightly blushed.") + "\n"
if(AROUSAL_LOW to AROUSAL_MEDIUM)
arousal_message = span_purple("[p_they()] [p_are()] quite aroused and seems to be stirring up lewd thoughts in [p_their()] head.") + "\n"
if(AROUSAL_HIGH to AROUSAL_AUTO_CLIMAX_THRESHOLD)
arousal_message = span_purple("[p_they()] [p_are()] aroused as hell.") + "\n"
if(AROUSAL_AUTO_CLIMAX_THRESHOLD to INFINITY)
arousal_message = span_purple("[p_they()] [p_are()] extremely excited, exhausting from entolerable desire.") + "\n"
if(arousal_message)
. += arousal_message
else if(arousal > AROUSAL_MINIMUM_DETECTABLE)
. += span_purple("[p_they()] [p_are()] slightly blushed.") + "\n"
@@ -0,0 +1,24 @@
//screen alert
/atom/movable/screen/alert/aroused
name = "Aroused"
desc = "It's a little hot in here"
icon = 'modular_skyrat/modules/modular_items/lewd_items/icons/obj/lewd_items/lewd_icons.dmi'
icon_state = "arousal_small"
var/mutable_appearance/pain_overlay
var/mutable_appearance/pleasure_overlay
var/pain_level = "small"
var/pleasure_level = "small"
/atom/movable/screen/alert/aroused/Initialize(mapload)
.=..()
pain_overlay = update_pain()
pleasure_overlay = update_pleasure()
/atom/movable/screen/alert/aroused/proc/update_pain()
if(pain_level)
return mutable_appearance(icon, "pain_[pain_level]")
/atom/movable/screen/alert/aroused/proc/update_pleasure()
if(pleasure_level)
return mutable_appearance(icon, "pleasure_[pleasure_level]")
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,18 @@
/mob/living/carbon/human/verb/climax_verb()
set name = "Climax"
set category = "IC"
if(!has_status_effect(/datum/status_effect/climax_cooldown))
if(tgui_alert(usr, "Are you sure you want to cum?", "Climax", list("Yes", "No")) == "Yes")
if(stat != CONSCIOUS)
to_chat(usr, span_warning("You can't climax right now..."))
return
else
climax(TRUE)
else
to_chat(src, span_warning("You can't cum right now!"))
/mob/living/carbon/human/Initialize(mapload)
. = ..()
if(CONFIG_GET(flag/disable_erp_preferences))
verbs -= /mob/living/carbon/human/verb/climax_verb
@@ -29,3 +29,4 @@ A modular folder for various single-item additions that don't deserve their own
Ranged66 - Material pouch ported
KathrinBailey - Pretty much a whole bunch of clothes.
mel-byond - Ported Baystation12 Aviators
RimiNosha - Fixing up code no one else would touch.
+45 -6
View File
@@ -325,6 +325,7 @@
#include "code\__DEFINES\~skyrat_defines\jobs.dm"
#include "code\__DEFINES\~skyrat_defines\keybindings.dm"
#include "code\__DEFINES\~skyrat_defines\layers.dm"
#include "code\__DEFINES\~skyrat_defines\lewd_defines.dm"
#include "code\__DEFINES\~skyrat_defines\liquids.dm"
#include "code\__DEFINES\~skyrat_defines\loadouts.dm"
#include "code\__DEFINES\~skyrat_defines\logging.dm"
@@ -4906,14 +4907,15 @@
#include "modular_skyrat\master_files\code\modules\client\preferences\_preference.dm"
#include "modular_skyrat\master_files\code\modules\client\preferences\auto_dementor.dm"
#include "modular_skyrat\master_files\code\modules\client\preferences\be_antag.dm"
#include "modular_skyrat\master_files\code\modules\client\preferences\body_size.dm"
#include "modular_skyrat\master_files\code\modules\client\preferences\clothing.dm"
#include "modular_skyrat\master_files\code\modules\client\preferences\cursed_shit.dm"
#include "modular_skyrat\master_files\code\modules\client\preferences\delete_sparks.dm"
#include "modular_skyrat\master_files\code\modules\client\preferences\emote_overlay.dm"
#include "modular_skyrat\master_files\code\modules\client\preferences\emote_panel.dm"
#include "modular_skyrat\master_files\code\modules\client\preferences\erp_preferences.dm"
#include "modular_skyrat\master_files\code\modules\client\preferences\face_cursor_combat_mode.dm"
#include "modular_skyrat\master_files\code\modules\client\preferences\flavor_text.dm"
#include "modular_skyrat\master_files\code\modules\client\preferences\genitals.dm"
#include "modular_skyrat\master_files\code\modules\client\preferences\headshot.dm"
#include "modular_skyrat\master_files\code\modules\client\preferences\laugh.dm"
#include "modular_skyrat\master_files\code\modules\client\preferences\loadout_override_preference.dm"
@@ -5864,11 +5866,34 @@
#include "modular_skyrat\modules\modular_items\code\summon_beacon.dm"
#include "modular_skyrat\modules\modular_items\code\tailoring.dm"
#include "modular_skyrat\modules\modular_items\code\thieving_gloves.dm"
#include "modular_skyrat\modules\modular_items\lewd_items\code\arousal_system.dm"
#include "modular_skyrat\modules\modular_items\lewd_items\code\decals.dm"
#include "modular_skyrat\modules\modular_items\lewd_items\code\lewd_quirks.dm"
#include "modular_skyrat\modules\modular_items\lewd_items\code\lewd_remove_erp_items.dm"
#include "modular_skyrat\modules\modular_items\lewd_items\code\technical_stuff_for_lewd.dm"
#include "modular_skyrat\modules\modular_items\lewd_items\code\lewd_chemistry\chemistry_for_ERP.dm"
#include "modular_skyrat\modules\modular_items\lewd_items\code\screen_icons.dm"
#include "modular_skyrat\modules\modular_items\lewd_items\code\verbs.dm"
#include "modular_skyrat\modules\modular_items\lewd_items\code\lewd_arousal\arousal.dm"
#include "modular_skyrat\modules\modular_items\lewd_items\code\lewd_arousal\climax.dm"
#include "modular_skyrat\modules\modular_items\lewd_items\code\lewd_arousal\mood_events.dm"
#include "modular_skyrat\modules\modular_items\lewd_items\code\lewd_arousal\pain.dm"
#include "modular_skyrat\modules\modular_items\lewd_items\code\lewd_arousal\pleasure.dm"
#include "modular_skyrat\modules\modular_items\lewd_items\code\lewd_arousal\status_effects\aroused.dm"
#include "modular_skyrat\modules\modular_items\lewd_items\code\lewd_arousal\status_effects\climax.dm"
#include "modular_skyrat\modules\modular_items\lewd_items\code\lewd_arousal\status_effects\fluid_generation.dm"
#include "modular_skyrat\modules\modular_items\lewd_items\code\lewd_arousal\status_effects\ropebunny.dm"
#include "modular_skyrat\modules\modular_items\lewd_items\code\lewd_arousal\status_effects\spank_related.dm"
#include "modular_skyrat\modules\modular_items\lewd_items\code\lewd_chemistry\mood_events.dm"
#include "modular_skyrat\modules\modular_items\lewd_items\code\lewd_chemistry\items\bottles.dm"
#include "modular_skyrat\modules\modular_items\lewd_items\code\lewd_chemistry\items\pills.dm"
#include "modular_skyrat\modules\modular_items\lewd_items\code\lewd_chemistry\reagents\_aphrodisiac.dm"
#include "modular_skyrat\modules\modular_items\lewd_items\code\lewd_chemistry\reagents\_chemical_reaction.dm"
#include "modular_skyrat\modules\modular_items\lewd_items\code\lewd_chemistry\reagents\breast_milk.dm"
#include "modular_skyrat\modules\modular_items\lewd_items\code\lewd_chemistry\reagents\camphor.dm"
#include "modular_skyrat\modules\modular_items\lewd_items\code\lewd_chemistry\reagents\crocin.dm"
#include "modular_skyrat\modules\modular_items\lewd_items\code\lewd_chemistry\reagents\cum.dm"
#include "modular_skyrat\modules\modular_items\lewd_items\code\lewd_chemistry\reagents\dopamine.dm"
#include "modular_skyrat\modules\modular_items\lewd_items\code\lewd_chemistry\reagents\hexacrocin.dm"
#include "modular_skyrat\modules\modular_items\lewd_items\code\lewd_chemistry\reagents\incubus_draft.dm"
#include "modular_skyrat\modules\modular_items\lewd_items\code\lewd_chemistry\reagents\pentacamphor.dm"
#include "modular_skyrat\modules\modular_items\lewd_items\code\lewd_chemistry\reagents\succubus_milk.dm"
#include "modular_skyrat\modules\modular_items\lewd_items\code\lewd_clothing\ballgag.dm"
#include "modular_skyrat\modules\modular_items\lewd_items\code\lewd_clothing\bdsm_mask.dm"
#include "modular_skyrat\modules\modular_items\lewd_items\code\lewd_clothing\corset.dm"
@@ -5893,6 +5918,16 @@
#include "modular_skyrat\modules\modular_items\lewd_items\code\lewd_clothing\shockcollar.dm"
#include "modular_skyrat\modules\modular_items\lewd_items\code\lewd_clothing\strapon.dm"
#include "modular_skyrat\modules\modular_items\lewd_items\code\lewd_clothing\stripper_outfit.dm"
#include "modular_skyrat\modules\modular_items\lewd_items\code\lewd_helpers\appearance.dm"
#include "modular_skyrat\modules\modular_items\lewd_items\code\lewd_helpers\carbon.dm"
#include "modular_skyrat\modules\modular_items\lewd_items\code\lewd_helpers\human.dm"
#include "modular_skyrat\modules\modular_items\lewd_items\code\lewd_helpers\misc.dm"
#include "modular_skyrat\modules\modular_items\lewd_items\code\lewd_helpers\organs.dm"
#include "modular_skyrat\modules\modular_items\lewd_items\code\lewd_helpers\species.dm"
#include "modular_skyrat\modules\modular_items\lewd_items\code\lewd_items\_erp_disabled_item_enforcement.dm"
#include "modular_skyrat\modules\modular_items\lewd_items\code\lewd_items\_kits.dm"
#include "modular_skyrat\modules\modular_items\lewd_items\code\lewd_items\_masturbation_item.dm"
#include "modular_skyrat\modules\modular_items\lewd_items\code\lewd_items\_sex_toy.dm"
#include "modular_skyrat\modules\modular_items\lewd_items\code\lewd_items\attachable_vibrator.dm"
#include "modular_skyrat\modules\modular_items\lewd_items\code\lewd_items\buttplug.dm"
#include "modular_skyrat\modules\modular_items\lewd_items\code\lewd_items\clamps.dm"
@@ -5912,10 +5947,14 @@
#include "modular_skyrat\modules\modular_items\lewd_items\code\lewd_items\torture_candle.dm"
#include "modular_skyrat\modules\modular_items\lewd_items\code\lewd_items\vibrator.dm"
#include "modular_skyrat\modules\modular_items\lewd_items\code\lewd_items\vibroring.dm"
#include "modular_skyrat\modules\modular_items\lewd_items\code\lewd_machinery\lustwish.dm"
#include "modular_skyrat\modules\modular_items\lewd_items\code\lewd_machinery\milking_machine.dm"
#include "modular_skyrat\modules\modular_items\lewd_items\code\lewd_organs\_genital.dm"
#include "modular_skyrat\modules\modular_items\lewd_items\code\lewd_organs\breasts.dm"
#include "modular_skyrat\modules\modular_items\lewd_items\code\lewd_organs\testicles.dm"
#include "modular_skyrat\modules\modular_items\lewd_items\code\lewd_organs\vagina.dm"
#include "modular_skyrat\modules\modular_items\lewd_items\code\lewd_structures\bdsm_furniture.dm"
#include "modular_skyrat\modules\modular_items\lewd_items\code\lewd_structures\dancing_pole.dm"
#include "modular_skyrat\modules\modular_items\lewd_items\code\lewd_structures\lustwish.dm"
#include "modular_skyrat\modules\modular_items\lewd_items\code\lewd_structures\pillow.dm"
#include "modular_skyrat\modules\modular_reagents\code\alert.dm"
#include "modular_skyrat\modules\modular_reagents\code\reagents\medicine.dm"
@@ -1,49 +0,0 @@
import { useBackend } from '../backend';
import { Button, NoticeBox, Section } from '../components';
import { Window } from '../layouts';
export const InteractionMenu = (props, context) => {
const { act, data } = useBackend(context);
const { categories, interactions, descriptions, colors } = data;
const { self, ref_self, ref_user } = data;
const { block_interact } = data;
return (
<Window width={400} height={600} title={'Interact - ' + self}>
<Window.Content scrollable>
{(block_interact && <NoticeBox>Unable to Interact</NoticeBox>) || (
<NoticeBox>Able to Interact</NoticeBox>
)}
<Section key="interactions">
{categories.map((category) => (
<Section key={category} title={category}>
{interactions[category].map((interaction) => (
<Section key={interaction}>
<left>
<Button
margin={0}
padding={0}
disabled={block_interact}
color={block_interact ? 'grey' : colors[interaction]}
content={interaction}
icon="exclamation-circle"
onClick={() =>
act('interact', {
interaction: interaction,
selfref: ref_self,
userref: ref_user,
})
}
/>
<br />
{descriptions[interaction]}
</left>
</Section>
))}
</Section>
))}
</Section>
</Window.Content>
</Window>
);
};
@@ -0,0 +1,123 @@
import { useBackend } from '../backend';
import { Button, NoticeBox, Section, Icon, Box, Stack } from '../components';
import { Window } from '../layouts';
class Interaction {
categories;
interactions;
descriptions;
colors;
lewd_slots: LewdSlot[];
self;
ref_self;
ref_user;
block_interact;
}
class LewdSlot {
img;
name;
}
export const InteractionMenu = (props, context) => {
const { act, data } = useBackend<Interaction>(context);
const {
categories,
interactions,
descriptions,
colors,
lewd_slots,
self,
ref_self,
ref_user,
block_interact,
} = data;
return (
<Window width={400} height={600} title={'Interact - ' + self}>
<Window.Content scrollable>
{(block_interact && <NoticeBox>Unable to Interact</NoticeBox>) || (
<NoticeBox>Able to Interact</NoticeBox>
)}
<Section key="interactions">
{categories.map((category) => (
<Section key={category} title={category}>
{interactions[category].map((interaction) => (
<Section key={interaction}>
<Button
margin={0}
padding={0}
disabled={block_interact}
color={block_interact ? 'grey' : colors[interaction]}
content={interaction}
icon="exclamation-circle"
onClick={() =>
act('interact', {
interaction: interaction,
selfref: ref_self,
userref: ref_user,
})
}
/>
<br />
{descriptions[interaction]}
</Section>
))}
</Section>
))}
</Section>
{lewd_slots.length > 0 ? (
<Section key="item_slots" title={'Lewd Slots'}>
<Stack fill>
{lewd_slots.map((element: LewdSlot) => {
return (
<Stack.Item key={element.name}>
<Button
onClick={() =>
act('remove_lewd_item', {
item_slot: element.name,
selfref: ref_self,
userref: ref_user,
})
}
tooltip={element.name}>
<Box
style={{
'width': '32px',
'height': '32px',
'margin': '0.5em 0',
}}>
{element.img ? (
<img
src={'data:image/png;base64,' + element.img}
style={{
'-ms-interpolation-mode': 'nearest-neighbor',
'width': '100%',
'height': '100%',
}}
/>
) : (
<Icon
name="eye-slash"
size={2}
ml={0}
mt={0.75}
style={{
'text-align': 'center',
}}
/>
)}
</Box>
</Button>
</Stack.Item>
);
})}
</Stack>
</Section>
) : (
''
)}
</Window.Content>
</Window>
);
};
@@ -106,38 +106,38 @@ export const feature_womb: Feature<string> = {
};
export const feature_breasts: Feature<string> = {
name: 'Breasts Choice',
name: 'Breast Choice',
component: FeatureDropdownInput,
};
export const breasts_skin_tone: FeatureToggle = {
name: 'Breasts uses Skin Tone',
name: 'Breasts use Skin Tone',
component: CheckboxInput,
};
export const breasts_skin_color: FeatureToggle = {
name: 'Breasts uses Skin Color',
name: 'Breasts use Skin Color',
component: CheckboxInput,
};
export const breasts_color: Feature<string[]> = {
name: 'Breasts Color',
name: 'Breast Color',
component: FeatureTriColorInput,
};
export const breasts_emissive: Feature<boolean[]> = {
name: 'Breasts Emissives',
name: 'Breast Emissives',
component: FeatureTriBoolInput,
};
export const breasts_lactation_toggle: FeatureToggle = {
name: 'Breasts Lactation',
name: 'Breast Lactation',
component: CheckboxInput,
};
export const breasts_size: FeatureNumeric = {
name: 'Breasts Size',
component: FeatureNumberInput,
export const breasts_size: Feature<string> = {
name: 'Breast Size',
component: FeatureDropdownInput,
};
export const feature_anus: Feature<string> = {
@@ -83,3 +83,11 @@ export const erp_sexuality_pref: FeatureChoiced = {
'Determines what sexual content you see, limited use. None will show all content.',
component: FeatureDropdownInput,
};
export const new_genitalia_growth_pref: FeatureToggle = {
name: 'ERP New Genitalia Growth',
category: 'ERP',
description:
'If checked, allows drugs to grow new genitalia on your character.',
component: CheckboxInput,
};