From f58cf51ae4bccabc41b2e429467203c22fa6ae73 Mon Sep 17 00:00:00 2001 From: RimiNosha <106692773+RimiNosha@users.noreply.github.com> Date: Tue, 4 Oct 2022 16:06:12 +0100 Subject: [PATCH] [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 :crab: * 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 :crab: * 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> --- code/__DEFINES/inventory.dm | 16 +- .../~skyrat_defines/_organ_defines.dm | 1 + code/__DEFINES/~skyrat_defines/inventory.dm | 6 + .../__DEFINES/~skyrat_defines/lewd_defines.dm | 49 + code/__HELPERS/type2type.dm | 8 - code/_onclick/hud/hud.dm | 30 - code/_onclick/hud/human.dm | 143 -- code/game/objects/items.dm | 11 - code/modules/client/preferences/ui_style.dm | 1 - .../mob/living/carbon/human/examine.dm | 2 +- .../mob/living/carbon/human/inventory.dm | 81 +- .../mob/living/carbon/human/species.dm | 26 +- code/modules/mob/login.dm | 1 - code/modules/reagents/chemistry/reagents.dm | 8 - .../modules/client/preferences/body_size.dm | 17 + .../client/preferences/erp_preferences.dm | 29 + .../{cursed_shit.dm => genitals.dm} | 95 +- .../modules/client/preferences_savefile.dm | 9 +- .../customization/_globalvars/lists.dm | 154 ++- .../new_player/sprite_accessories/genitals.dm | 12 +- .../modules/mob/living/carbon/human/human.dm | 5 +- .../mob/living/carbon/human/species.dm | 12 +- .../modules/surgery/organs/genitals.dm | 38 +- .../modules/event_vote/code/event_vote.dm | 6 +- .../code/interaction_component.dm | 113 +- .../code/interaction_datum.dm | 12 +- .../lewd_items/code/arousal_system.dm | 880 ------------ .../modular_items/lewd_items/code/decals.dm | 15 + .../lewd_items/code/lewd_arousal/arousal.dm | 22 + .../lewd_items/code/lewd_arousal/climax.dm | 159 +++ .../code/lewd_arousal/mood_events.dm | 11 + .../lewd_items/code/lewd_arousal/pain.dm | 25 + .../lewd_items/code/lewd_arousal/pleasure.dm | 8 + .../lewd_arousal/status_effects/aroused.dm | 63 + .../lewd_arousal/status_effects/climax.dm | 63 + .../status_effects/fluid_generation.dm | 53 + .../lewd_arousal/status_effects/ropebunny.dm | 19 + .../status_effects/spank_related.dm | 39 + .../code/lewd_chemistry/chemistry_for_ERP.dm | 742 ---------- .../code/lewd_chemistry/items/bottles.dm | 34 + .../code/lewd_chemistry/items/pills.dm | 34 + .../code/lewd_chemistry/mood_events.dm | 6 + .../lewd_chemistry/reagents/_aphrodisiac.dm | 71 + .../reagents/_chemical_reaction.dm | 3 + .../lewd_chemistry/reagents/breast_milk.dm | 9 + .../code/lewd_chemistry/reagents/camphor.dm | 94 ++ .../code/lewd_chemistry/reagents/crocin.dm | 53 + .../code/lewd_chemistry/reagents/cum.dm | 25 + .../code/lewd_chemistry/reagents/dopamine.dm | 49 + .../lewd_chemistry/reagents/hexacrocin.dm | 55 + .../lewd_chemistry/reagents/incubus_draft.dm | 200 +++ .../lewd_chemistry/reagents/pentacamphor.dm | 37 + .../lewd_chemistry/reagents/succubus_milk.dm | 196 +++ .../lewd_items/code/lewd_clothing/erp_belt.dm | 4 +- .../code/lewd_clothing/latex_catsuit.dm | 4 +- .../lewd_clothing/shibari_worn_uniform.dm | 22 +- .../code/lewd_clothing/shockcollar.dm | 2 +- .../lewd_items/code/lewd_clothing/strapon.dm | 14 +- .../code/lewd_helpers/appearance.dm | 76 ++ .../lewd_items/code/lewd_helpers/carbon.dm | 5 + .../lewd_items/code/lewd_helpers/human.dm | 378 ++++++ .../lewd_items/code/lewd_helpers/misc.dm | 62 + .../lewd_items/code/lewd_helpers/organs.dm | 6 + .../lewd_items/code/lewd_helpers/species.dm | 91 ++ .../_erp_disabled_item_enforcement.dm} | 0 .../lewd_items/code/lewd_items/_kits.dm | 56 + .../code/lewd_items/_masturbation_item.dm | 63 + .../lewd_items/code/lewd_items/_sex_toy.dm | 34 + .../code/lewd_items/attachable_vibrator.dm | 18 +- .../lewd_items/code/lewd_items/buttplug.dm | 16 +- .../lewd_items/code/lewd_items/clamps.dm | 8 +- .../lewd_items/code/lewd_items/condom.dm | 8 +- .../lewd_items/code/lewd_items/dildo.dm | 48 +- .../lewd_items/code/lewd_items/feather.dm | 2 +- .../lewd_items/code/lewd_items/fleshlight.dm | 4 +- .../code/lewd_items/kinky_shocker.dm | 2 +- .../code/lewd_items/leather_whip.dm | 26 +- .../lewd_items/code/lewd_items/magic_wand.dm | 25 +- .../code/lewd_items/spanking_pad.dm | 4 +- .../code/lewd_items/torture_candle.dm | 13 +- .../lewd_items/code/lewd_items/vibrator.dm | 37 +- .../lewd_items/code/lewd_items/vibroring.dm | 6 +- .../lustwish.dm | 4 +- .../code/lewd_machinery/milking_machine.dm | 31 +- .../lewd_items/code/lewd_organs/_genital.dm | 30 + .../lewd_items/code/lewd_organs/breasts.dm | 18 + .../lewd_items/code/lewd_organs/testicles.dm | 10 + .../lewd_items/code/lewd_organs/vagina.dm | 6 + .../lewd_items/code/lewd_quirks.dm | 41 +- .../lewd_items/code/screen_icons.dm | 24 + .../code/technical_stuff_for_lewd.dm | 1206 ----------------- .../modular_items/lewd_items/code/verbs.dm | 18 + .../modules/modular_items/readme.md | 1 + tgstation.dme | 51 +- .../tgui/interfaces/InteractionMenu.js | 49 - .../tgui/interfaces/InteractionMenu.tsx | 123 ++ .../skyrat/{cursed_shit.tsx => genitals.tsx} | 18 +- .../skyrat/erp_preferences.tsx | 8 + 98 files changed, 2982 insertions(+), 3540 deletions(-) create mode 100644 code/__DEFINES/~skyrat_defines/lewd_defines.dm create mode 100644 modular_skyrat/master_files/code/modules/client/preferences/body_size.dm rename modular_skyrat/master_files/code/modules/client/preferences/{cursed_shit.dm => genitals.dm} (89%) delete mode 100644 modular_skyrat/modules/modular_items/lewd_items/code/arousal_system.dm create mode 100644 modular_skyrat/modules/modular_items/lewd_items/code/decals.dm create mode 100644 modular_skyrat/modules/modular_items/lewd_items/code/lewd_arousal/arousal.dm create mode 100644 modular_skyrat/modules/modular_items/lewd_items/code/lewd_arousal/climax.dm create mode 100644 modular_skyrat/modules/modular_items/lewd_items/code/lewd_arousal/mood_events.dm create mode 100644 modular_skyrat/modules/modular_items/lewd_items/code/lewd_arousal/pain.dm create mode 100644 modular_skyrat/modules/modular_items/lewd_items/code/lewd_arousal/pleasure.dm create mode 100644 modular_skyrat/modules/modular_items/lewd_items/code/lewd_arousal/status_effects/aroused.dm create mode 100644 modular_skyrat/modules/modular_items/lewd_items/code/lewd_arousal/status_effects/climax.dm create mode 100644 modular_skyrat/modules/modular_items/lewd_items/code/lewd_arousal/status_effects/fluid_generation.dm create mode 100644 modular_skyrat/modules/modular_items/lewd_items/code/lewd_arousal/status_effects/ropebunny.dm create mode 100644 modular_skyrat/modules/modular_items/lewd_items/code/lewd_arousal/status_effects/spank_related.dm delete mode 100644 modular_skyrat/modules/modular_items/lewd_items/code/lewd_chemistry/chemistry_for_ERP.dm create mode 100644 modular_skyrat/modules/modular_items/lewd_items/code/lewd_chemistry/items/bottles.dm create mode 100644 modular_skyrat/modules/modular_items/lewd_items/code/lewd_chemistry/items/pills.dm create mode 100644 modular_skyrat/modules/modular_items/lewd_items/code/lewd_chemistry/mood_events.dm create mode 100644 modular_skyrat/modules/modular_items/lewd_items/code/lewd_chemistry/reagents/_aphrodisiac.dm create mode 100644 modular_skyrat/modules/modular_items/lewd_items/code/lewd_chemistry/reagents/_chemical_reaction.dm create mode 100644 modular_skyrat/modules/modular_items/lewd_items/code/lewd_chemistry/reagents/breast_milk.dm create mode 100644 modular_skyrat/modules/modular_items/lewd_items/code/lewd_chemistry/reagents/camphor.dm create mode 100644 modular_skyrat/modules/modular_items/lewd_items/code/lewd_chemistry/reagents/crocin.dm create mode 100644 modular_skyrat/modules/modular_items/lewd_items/code/lewd_chemistry/reagents/cum.dm create mode 100644 modular_skyrat/modules/modular_items/lewd_items/code/lewd_chemistry/reagents/dopamine.dm create mode 100644 modular_skyrat/modules/modular_items/lewd_items/code/lewd_chemistry/reagents/hexacrocin.dm create mode 100644 modular_skyrat/modules/modular_items/lewd_items/code/lewd_chemistry/reagents/incubus_draft.dm create mode 100644 modular_skyrat/modules/modular_items/lewd_items/code/lewd_chemistry/reagents/pentacamphor.dm create mode 100644 modular_skyrat/modules/modular_items/lewd_items/code/lewd_chemistry/reagents/succubus_milk.dm create mode 100644 modular_skyrat/modules/modular_items/lewd_items/code/lewd_helpers/appearance.dm create mode 100644 modular_skyrat/modules/modular_items/lewd_items/code/lewd_helpers/carbon.dm create mode 100644 modular_skyrat/modules/modular_items/lewd_items/code/lewd_helpers/human.dm create mode 100644 modular_skyrat/modules/modular_items/lewd_items/code/lewd_helpers/misc.dm create mode 100644 modular_skyrat/modules/modular_items/lewd_items/code/lewd_helpers/organs.dm create mode 100644 modular_skyrat/modules/modular_items/lewd_items/code/lewd_helpers/species.dm rename modular_skyrat/modules/modular_items/lewd_items/code/{lewd_remove_erp_items.dm => lewd_items/_erp_disabled_item_enforcement.dm} (100%) create mode 100644 modular_skyrat/modules/modular_items/lewd_items/code/lewd_items/_kits.dm create mode 100644 modular_skyrat/modules/modular_items/lewd_items/code/lewd_items/_masturbation_item.dm create mode 100644 modular_skyrat/modules/modular_items/lewd_items/code/lewd_items/_sex_toy.dm rename modular_skyrat/modules/modular_items/lewd_items/code/{lewd_structures => lewd_machinery}/lustwish.dm (95%) create mode 100644 modular_skyrat/modules/modular_items/lewd_items/code/lewd_organs/_genital.dm create mode 100644 modular_skyrat/modules/modular_items/lewd_items/code/lewd_organs/breasts.dm create mode 100644 modular_skyrat/modules/modular_items/lewd_items/code/lewd_organs/testicles.dm create mode 100644 modular_skyrat/modules/modular_items/lewd_items/code/lewd_organs/vagina.dm create mode 100644 modular_skyrat/modules/modular_items/lewd_items/code/screen_icons.dm delete mode 100644 modular_skyrat/modules/modular_items/lewd_items/code/technical_stuff_for_lewd.dm create mode 100644 modular_skyrat/modules/modular_items/lewd_items/code/verbs.dm delete mode 100644 tgui/packages/tgui/interfaces/InteractionMenu.js create mode 100644 tgui/packages/tgui/interfaces/InteractionMenu.tsx rename tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/skyrat/{cursed_shit.tsx => genitals.tsx} (93%) diff --git a/code/__DEFINES/inventory.dm b/code/__DEFINES/inventory.dm index 2d989821cf4..718ebccdb77 100644 --- a/code/__DEFINES/inventory.dm +++ b/code/__DEFINES/inventory.dm @@ -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) diff --git a/code/__DEFINES/~skyrat_defines/_organ_defines.dm b/code/__DEFINES/~skyrat_defines/_organ_defines.dm index 1002254fa48..c944243da57 100644 --- a/code/__DEFINES/~skyrat_defines/_organ_defines.dm +++ b/code/__DEFINES/~skyrat_defines/_organ_defines.dm @@ -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" diff --git a/code/__DEFINES/~skyrat_defines/inventory.dm b/code/__DEFINES/~skyrat_defines/inventory.dm index 9ae86967643..318c11e19fe 100644 --- a/code/__DEFINES/~skyrat_defines/inventory.dm +++ b/code/__DEFINES/~skyrat_defines/inventory.dm @@ -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) diff --git a/code/__DEFINES/~skyrat_defines/lewd_defines.dm b/code/__DEFINES/~skyrat_defines/lewd_defines.dm new file mode 100644 index 00000000000..a1edae8aa01 --- /dev/null +++ b/code/__DEFINES/~skyrat_defines/lewd_defines.dm @@ -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" diff --git a/code/__HELPERS/type2type.dm b/code/__HELPERS/type2type.dm index 900a635bdc4..e9df60b699e 100644 --- a/code/__HELPERS/type2type.dm +++ b/code/__HELPERS/type2type.dm @@ -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)) diff --git a/code/_onclick/hud/hud.dm b/code/_onclick/hud/hud.dm index b93c50fc143..d615d17abde 100644 --- a/code/_onclick/hud/hud.dm +++ b/code/_onclick/hud/hud.dm @@ -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" diff --git a/code/_onclick/hud/human.dm b/code/_onclick/hud/human.dm index 9ba867ad381..a7bc7370e72 100644 --- a/code/_onclick/hud/human.dm +++ b/code/_onclick/hud/human.dm @@ -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)) diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index 9590a662f37..8d20a87e474 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -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 diff --git a/code/modules/client/preferences/ui_style.dm b/code/modules/client/preferences/ui_style.dm index d7e9907df59..08f1af6c7dd 100644 --- a/code/modules/client/preferences/ui_style.dm +++ b/code/modules/client/preferences/ui_style.dm @@ -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 diff --git a/code/modules/mob/living/carbon/human/examine.dm b/code/modules/mob/living/carbon/human/examine.dm index 1800fd258ad..b2be241a78d 100644 --- a/code/modules/mob/living/carbon/human/examine.dm +++ b/code/modules/mob/living/carbon/human/examine.dm @@ -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) diff --git a/code/modules/mob/living/carbon/human/inventory.dm b/code/modules/mob/living/carbon/human/inventory.dm index 9cdd58eb869..703ec886d5c 100644 --- a/code/modules/mob/living/carbon/human/inventory.dm +++ b/code/modules/mob/living/carbon/human/inventory.dm @@ -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 diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm index 9b30ba3f092..fa8e79b3a27 100644 --- a/code/modules/mob/living/carbon/human/species.dm +++ b/code/modules/mob/living/carbon/human/species.dm @@ -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) diff --git a/code/modules/mob/login.dm b/code/modules/mob/login.dm index 9cf0de05daa..1053b6672dd 100644 --- a/code/modules/mob/login.dm +++ b/code/modules/mob/login.dm @@ -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 diff --git a/code/modules/reagents/chemistry/reagents.dm b/code/modules/reagents/chemistry/reagents.dm index 5a1ce5826cc..7d2b4e72d51 100644 --- a/code/modules/reagents/chemistry/reagents.dm +++ b/code/modules/reagents/chemistry/reagents.dm @@ -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 diff --git a/modular_skyrat/master_files/code/modules/client/preferences/body_size.dm b/modular_skyrat/master_files/code/modules/client/preferences/body_size.dm new file mode 100644 index 00000000000..afb8364f20c --- /dev/null +++ b/modular_skyrat/master_files/code/modules/client/preferences/body_size.dm @@ -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 diff --git a/modular_skyrat/master_files/code/modules/client/preferences/erp_preferences.dm b/modular_skyrat/master_files/code/modules/client/preferences/erp_preferences.dm index b658c510ef3..767af505b0e 100644 --- a/modular_skyrat/master_files/code/modules/client/preferences/erp_preferences.dm +++ b/modular_skyrat/master_files/code/modules/client/preferences/erp_preferences.dm @@ -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 diff --git a/modular_skyrat/master_files/code/modules/client/preferences/cursed_shit.dm b/modular_skyrat/master_files/code/modules/client/preferences/genitals.dm similarity index 89% rename from modular_skyrat/master_files/code/modules/client/preferences/cursed_shit.dm rename to modular_skyrat/master_files/code/modules/client/preferences/genitals.dm index 4a6c6c65ddc..8a3a7e1e43f 100644 --- a/modular_skyrat/master_files/code/modules/client/preferences/cursed_shit.dm +++ b/modular_skyrat/master_files/code/modules/client/preferences/genitals.dm @@ -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 diff --git a/modular_skyrat/master_files/code/modules/client/preferences_savefile.dm b/modular_skyrat/master_files/code/modules/client/preferences_savefile.dm index ba6b51ad1b1..9a4eeff33c1 100644 --- a/modular_skyrat/master_files/code/modules/client/preferences_savefile.dm +++ b/modular_skyrat/master_files/code/modules/client/preferences_savefile.dm @@ -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."))) diff --git a/modular_skyrat/modules/customization/_globalvars/lists.dm b/modular_skyrat/modules/customization/_globalvars/lists.dm index a7bec54f41d..03a9d43be53 100644 --- a/modular_skyrat/modules/customization/_globalvars/lists.dm +++ b/modular_skyrat/modules/customization/_globalvars/lists.dm @@ -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( \ diff --git a/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/genitals.dm b/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/genitals.dm index 6562d4b5fd5..b4877bd423d 100644 --- a/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/genitals.dm +++ b/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/genitals.dm @@ -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) diff --git a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/human.dm b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/human.dm index 8b6b08d6a18..edfa5bbbabe 100644 --- a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/human.dm +++ b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/human.dm @@ -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]] diff --git a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species.dm b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species.dm index 5de48571504..b1b708e16bd 100644 --- a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species.dm +++ b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species.dm @@ -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() diff --git a/modular_skyrat/modules/customization/modules/surgery/organs/genitals.dm b/modular_skyrat/modules/customization/modules/surgery/organs/genitals.dm index b80e7eba944..2f889b56098 100644 --- a/modular_skyrat/modules/customization/modules/surgery/organs/genitals.dm +++ b/modular_skyrat/modules/customization/modules/surgery/organs/genitals.dm @@ -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 diff --git a/modular_skyrat/modules/event_vote/code/event_vote.dm b/modular_skyrat/modules/event_vote/code/event_vote.dm index a97301c36de..5632b6de8b8 100644 --- a/modular_skyrat/modules/event_vote/code/event_vote.dm +++ b/modular_skyrat/modules/event_vote/code/event_vote.dm @@ -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" diff --git a/modular_skyrat/modules/interaction_menu/code/interaction_component.dm b/modular_skyrat/modules/interaction_menu/code/interaction_component.dm index ac48006f265..b39449501b8 100644 --- a/modular_skyrat/modules/interaction_menu/code/interaction_component.dm +++ b/modular_skyrat/modules/interaction_menu/code/interaction_component.dm @@ -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 diff --git a/modular_skyrat/modules/interaction_menu/code/interaction_datum.dm b/modular_skyrat/modules/interaction_menu/code/interaction_datum.dm index 0ea0df638a2..0991f09b9db 100644 --- a/modular_skyrat/modules/interaction_menu/code/interaction_datum.dm +++ b/modular_skyrat/modules/interaction_menu/code/interaction_datum.dm @@ -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 diff --git a/modular_skyrat/modules/modular_items/lewd_items/code/arousal_system.dm b/modular_skyrat/modules/modular_items/lewd_items/code/arousal_system.dm deleted file mode 100644 index cdc0d4c305b..00000000000 --- a/modular_skyrat/modules/modular_items/lewd_items/code/arousal_system.dm +++ /dev/null @@ -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) diff --git a/modular_skyrat/modules/modular_items/lewd_items/code/decals.dm b/modular_skyrat/modules/modular_items/lewd_items/code/decals.dm new file mode 100644 index 00000000000..9b79648728b --- /dev/null +++ b/modular_skyrat/modules/modular_items/lewd_items/code/decals.dm @@ -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 diff --git a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_arousal/arousal.dm b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_arousal/arousal.dm new file mode 100644 index 00000000000..3f5d02cc53a --- /dev/null +++ b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_arousal/arousal.dm @@ -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) + diff --git a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_arousal/climax.dm b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_arousal/climax.dm new file mode 100644 index 00000000000..0d6bdcc4c0f --- /dev/null +++ b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_arousal/climax.dm @@ -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 diff --git a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_arousal/mood_events.dm b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_arousal/mood_events.dm new file mode 100644 index 00000000000..42771f906e8 --- /dev/null +++ b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_arousal/mood_events.dm @@ -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 diff --git a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_arousal/pain.dm b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_arousal/pain.dm new file mode 100644 index 00000000000..072de283139 --- /dev/null +++ b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_arousal/pain.dm @@ -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) diff --git a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_arousal/pleasure.dm b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_arousal/pleasure.dm new file mode 100644 index 00000000000..bcda8503d21 --- /dev/null +++ b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_arousal/pleasure.dm @@ -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) diff --git a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_arousal/status_effects/aroused.dm b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_arousal/status_effects/aroused.dm new file mode 100644 index 00000000000..f500f87857a --- /dev/null +++ b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_arousal/status_effects/aroused.dm @@ -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 diff --git a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_arousal/status_effects/climax.dm b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_arousal/status_effects/climax.dm new file mode 100644 index 00000000000..6dcf4e37e14 --- /dev/null +++ b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_arousal/status_effects/climax.dm @@ -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 diff --git a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_arousal/status_effects/fluid_generation.dm b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_arousal/status_effects/fluid_generation.dm new file mode 100644 index 00000000000..f45fe00a6d8 --- /dev/null +++ b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_arousal/status_effects/fluid_generation.dm @@ -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 diff --git a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_arousal/status_effects/ropebunny.dm b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_arousal/status_effects/ropebunny.dm new file mode 100644 index 00000000000..6203b73c9c4 --- /dev/null +++ b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_arousal/status_effects/ropebunny.dm @@ -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. diff --git a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_arousal/status_effects/spank_related.dm b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_arousal/status_effects/spank_related.dm new file mode 100644 index 00000000000..1a6420e7b49 --- /dev/null +++ b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_arousal/status_effects/spank_related.dm @@ -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 diff --git a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_chemistry/chemistry_for_ERP.dm b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_chemistry/chemistry_for_ERP.dm deleted file mode 100644 index 56fd662e034..00000000000 --- a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_chemistry/chemistry_for_ERP.dm +++ /dev/null @@ -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 = "I think I took a bit too much [drug_name]...\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) diff --git a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_chemistry/items/bottles.dm b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_chemistry/items/bottles.dm new file mode 100644 index 00000000000..ac51f3d5a9b --- /dev/null +++ b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_chemistry/items/bottles.dm @@ -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) diff --git a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_chemistry/items/pills.dm b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_chemistry/items/pills.dm new file mode 100644 index 00000000000..b2a6a8e2e6d --- /dev/null +++ b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_chemistry/items/pills.dm @@ -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) diff --git a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_chemistry/mood_events.dm b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_chemistry/mood_events.dm new file mode 100644 index 00000000000..b0e72c57800 --- /dev/null +++ b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_chemistry/mood_events.dm @@ -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 = "I think I took a bit too much [drug_name]...\n" diff --git a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_chemistry/reagents/_aphrodisiac.dm b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_chemistry/reagents/_aphrodisiac.dm new file mode 100644 index 00000000000..3637d5bbde3 --- /dev/null +++ b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_chemistry/reagents/_aphrodisiac.dm @@ -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) diff --git a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_chemistry/reagents/_chemical_reaction.dm b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_chemistry/reagents/_chemical_reaction.dm new file mode 100644 index 00000000000..9ef83b8afa5 --- /dev/null +++ b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_chemistry/reagents/_chemical_reaction.dm @@ -0,0 +1,3 @@ +/datum/chemical_reaction + /// Will this reaction be disabled by the ERP config being turned off? + var/erp_reaction = FALSE diff --git a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_chemistry/reagents/breast_milk.dm b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_chemistry/reagents/breast_milk.dm new file mode 100644 index 00000000000..b104b6c879b --- /dev/null +++ b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_chemistry/reagents/breast_milk.dm @@ -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 diff --git a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_chemistry/reagents/camphor.dm b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_chemistry/reagents/camphor.dm new file mode 100644 index 00000000000..a93679181b0 --- /dev/null +++ b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_chemistry/reagents/camphor.dm @@ -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 diff --git a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_chemistry/reagents/crocin.dm b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_chemistry/reagents/crocin.dm new file mode 100644 index 00000000000..09499beead6 --- /dev/null +++ b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_chemistry/reagents/crocin.dm @@ -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 diff --git a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_chemistry/reagents/cum.dm b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_chemistry/reagents/cum.dm new file mode 100644 index 00000000000..77214a0ebc5 --- /dev/null +++ b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_chemistry/reagents/cum.dm @@ -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 diff --git a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_chemistry/reagents/dopamine.dm b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_chemistry/reagents/dopamine.dm new file mode 100644 index 00000000000..7712ee530b7 --- /dev/null +++ b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_chemistry/reagents/dopamine.dm @@ -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 diff --git a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_chemistry/reagents/hexacrocin.dm b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_chemistry/reagents/hexacrocin.dm new file mode 100644 index 00000000000..5323a8ddc86 --- /dev/null +++ b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_chemistry/reagents/hexacrocin.dm @@ -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 diff --git a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_chemistry/reagents/incubus_draft.dm b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_chemistry/reagents/incubus_draft.dm new file mode 100644 index 00000000000..98998af059b --- /dev/null +++ b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_chemistry/reagents/incubus_draft.dm @@ -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 diff --git a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_chemistry/reagents/pentacamphor.dm b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_chemistry/reagents/pentacamphor.dm new file mode 100644 index 00000000000..2c2e6083c8c --- /dev/null +++ b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_chemistry/reagents/pentacamphor.dm @@ -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 diff --git a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_chemistry/reagents/succubus_milk.dm b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_chemistry/reagents/succubus_milk.dm new file mode 100644 index 00000000000..3efcd2fea4a --- /dev/null +++ b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_chemistry/reagents/succubus_milk.dm @@ -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 diff --git a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_clothing/erp_belt.dm b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_clothing/erp_belt.dm index db2fc7eaacb..c9cf41361f6 100644 --- a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_clothing/erp_belt.dm +++ b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_clothing/erp_belt.dm @@ -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, diff --git a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_clothing/latex_catsuit.dm b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_clothing/latex_catsuit.dm index bf5ec6c3a75..f8690a49c9f 100644 --- a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_clothing/latex_catsuit.dm +++ b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_clothing/latex_catsuit.dm @@ -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 diff --git a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_clothing/shibari_worn_uniform.dm b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_clothing/shibari_worn_uniform.dm index c117f081c5c..a4115f079d0 100644 --- a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_clothing/shibari_worn_uniform.dm +++ b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_clothing/shibari_worn_uniform.dm @@ -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 diff --git a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_clothing/shockcollar.dm b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_clothing/shockcollar.dm index 804eb2a7318..34bd9975408 100644 --- a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_clothing/shockcollar.dm +++ b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_clothing/shockcollar.dm @@ -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) diff --git a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_clothing/strapon.dm b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_clothing/strapon.dm index 60f4dfa91ac..d9d947e10cb 100644 --- a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_clothing/strapon.dm +++ b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_clothing/strapon.dm @@ -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]!")) diff --git a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_helpers/appearance.dm b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_helpers/appearance.dm new file mode 100644 index 00000000000..15c4b2c895e --- /dev/null +++ b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_helpers/appearance.dm @@ -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) + diff --git a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_helpers/carbon.dm b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_helpers/carbon.dm new file mode 100644 index 00000000000..fae48e53f14 --- /dev/null +++ b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_helpers/carbon.dm @@ -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) diff --git a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_helpers/human.dm b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_helpers/human.dm new file mode 100644 index 00000000000..9f5b51f1bbf --- /dev/null +++ b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_helpers/human.dm @@ -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 + ..() diff --git a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_helpers/misc.dm b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_helpers/misc.dm new file mode 100644 index 00000000000..3d9ee0d297c --- /dev/null +++ b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_helpers/misc.dm @@ -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 diff --git a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_helpers/organs.dm b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_helpers/organs.dm new file mode 100644 index 00000000000..a90348ca396 --- /dev/null +++ b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_helpers/organs.dm @@ -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) diff --git a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_helpers/species.dm b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_helpers/species.dm new file mode 100644 index 00000000000..69a63d89d15 --- /dev/null +++ b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_helpers/species.dm @@ -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 diff --git a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_remove_erp_items.dm b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_items/_erp_disabled_item_enforcement.dm similarity index 100% rename from modular_skyrat/modules/modular_items/lewd_items/code/lewd_remove_erp_items.dm rename to modular_skyrat/modules/modular_items/lewd_items/code/lewd_items/_erp_disabled_item_enforcement.dm diff --git a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_items/_kits.dm b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_items/_kits.dm new file mode 100644 index 00000000000..62b5a8d84a6 --- /dev/null +++ b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_items/_kits.dm @@ -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!" diff --git a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_items/_masturbation_item.dm b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_items/_masturbation_item.dm new file mode 100644 index 00000000000..a6010e2d229 --- /dev/null +++ b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_items/_masturbation_item.dm @@ -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 diff --git a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_items/_sex_toy.dm b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_items/_sex_toy.dm new file mode 100644 index 00000000000..9ad53e50828 --- /dev/null +++ b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_items/_sex_toy.dm @@ -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) diff --git a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_items/attachable_vibrator.dm b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_items/attachable_vibrator.dm index fc255a5ad91..bd6b1e48f9b 100644 --- a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_items/attachable_vibrator.dm +++ b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_items/attachable_vibrator.dm @@ -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) diff --git a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_items/buttplug.dm b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_items/buttplug.dm index 766347e739b..1dc74c3f811 100644 --- a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_items/buttplug.dm +++ b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_items/buttplug.dm @@ -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) diff --git a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_items/clamps.dm b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_items/clamps.dm index 412cf8b6ce3..81632b61a68 100644 --- a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_items/clamps.dm +++ b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_items/clamps.dm @@ -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 diff --git a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_items/condom.dm b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_items/condom.dm index 75f4b028640..0658c211bd7 100644 --- a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_items/condom.dm +++ b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_items/condom.dm @@ -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() diff --git a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_items/dildo.dm b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_items/dildo.dm index 5b92cedd37f..063ae27dca7 100644 --- a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_items/dildo.dm +++ b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_items/dildo.dm @@ -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) . = ..() diff --git a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_items/feather.dm b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_items/feather.dm index 89b2049c89b..26b633a9f80 100644 --- a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_items/feather.dm +++ b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_items/feather.dm @@ -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. diff --git a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_items/fleshlight.dm b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_items/fleshlight.dm index ac428f7824d..0f504c1a660 100644 --- a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_items/fleshlight.dm +++ b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_items/fleshlight.dm @@ -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', diff --git a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_items/kinky_shocker.dm b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_items/kinky_shocker.dm index 258c9f14374..5a9b2609113 100644 --- a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_items/kinky_shocker.dm +++ b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_items/kinky_shocker.dm @@ -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) diff --git a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_items/leather_whip.dm b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_items/leather_whip.dm index 55253696d4f..3d8c0c0e196 100644 --- a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_items/leather_whip.dm +++ b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_items/leather_whip.dm @@ -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 diff --git a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_items/magic_wand.dm b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_items/magic_wand.dm index dedbbb86ad1..706d4568f65 100644 --- a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_items/magic_wand.dm +++ b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_items/magic_wand.dm @@ -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")) diff --git a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_items/spanking_pad.dm b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_items/spanking_pad.dm index 7c58533aa3a..3bb885d041b 100644 --- a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_items/spanking_pad.dm +++ b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_items/spanking_pad.dm @@ -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) diff --git a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_items/torture_candle.dm b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_items/torture_candle.dm index 7f27870b28b..0b9a8fdb491 100644 --- a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_items/torture_candle.dm +++ b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_items/torture_candle.dm @@ -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!")) diff --git a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_items/vibrator.dm b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_items/vibrator.dm index 92fd8b4087a..2277e464181 100644 --- a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_items/vibrator.dm +++ b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_items/vibrator.dm @@ -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")) diff --git a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_items/vibroring.dm b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_items/vibroring.dm index 75cadfcfd11..4d0ab49232b 100644 --- a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_items/vibroring.dm +++ b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_items/vibroring.dm @@ -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. diff --git a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_structures/lustwish.dm b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_machinery/lustwish.dm similarity index 95% rename from modular_skyrat/modules/modular_items/lewd_items/code/lewd_structures/lustwish.dm rename to modular_skyrat/modules/modular_items/lewd_items/code/lewd_machinery/lustwish.dm index 52c558cea8e..98eeed47403 100644 --- a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_structures/lustwish.dm +++ b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_machinery/lustwish.dm @@ -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) diff --git a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_machinery/milking_machine.dm b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_machinery/milking_machine.dm index 39f41cf8873..f6a7acbefd6 100644 --- a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_machinery/milking_machine.dm +++ b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_machinery/milking_machine.dm @@ -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]) diff --git a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_organs/_genital.dm b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_organs/_genital.dm new file mode 100644 index 00000000000..5e199453db0 --- /dev/null +++ b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_organs/_genital.dm @@ -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 + diff --git a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_organs/breasts.dm b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_organs/breasts.dm new file mode 100644 index 00000000000..8899db9d003 --- /dev/null +++ b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_organs/breasts.dm @@ -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. diff --git a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_organs/testicles.dm b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_organs/testicles.dm new file mode 100644 index 00000000000..e9864538174 --- /dev/null +++ b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_organs/testicles.dm @@ -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 diff --git a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_organs/vagina.dm b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_organs/vagina.dm new file mode 100644 index 00000000000..c74995845a1 --- /dev/null +++ b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_organs/vagina.dm @@ -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 diff --git a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_quirks.dm b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_quirks.dm index ac9faa8f5cb..ea66041e467 100644 --- a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_quirks.dm +++ b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_quirks.dm @@ -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" + diff --git a/modular_skyrat/modules/modular_items/lewd_items/code/screen_icons.dm b/modular_skyrat/modules/modular_items/lewd_items/code/screen_icons.dm new file mode 100644 index 00000000000..63aa2c1452c --- /dev/null +++ b/modular_skyrat/modules/modular_items/lewd_items/code/screen_icons.dm @@ -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]") diff --git a/modular_skyrat/modules/modular_items/lewd_items/code/technical_stuff_for_lewd.dm b/modular_skyrat/modules/modular_items/lewd_items/code/technical_stuff_for_lewd.dm deleted file mode 100644 index b9f5dbb14b8..00000000000 --- a/modular_skyrat/modules/modular_items/lewd_items/code/technical_stuff_for_lewd.dm +++ /dev/null @@ -1,1206 +0,0 @@ -// Moved from my old interactions file 'cause skyrats already did interactions - -#define REQUIRE_NONE 0 -#define REQUIRE_EXPOSED 1 -#define REQUIRE_UNEXPOSED 2 -#define REQUIRE_ANY 3 - -/mob/living/carbon/human - var/has_penis = FALSE - var/has_vagina = FALSE - var/has_breasts = FALSE - var/has_anus = FALSE - -/* -* 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 - -/* -* Boxes for vending machine, to spawn stuff with important cheap tools in pack -*/ - -// 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!" - -/* -* This code is supposed to be placed in "code/modules/mob/living/carbon/human/inventory.dm" -* If you are nice person you can transfer this part of code to it, but i didn't for modularisation reasons -*/ - -/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 - ..() - -/* -* I needed this code for ballgag, because it doesn't muzzle, it kinda voxbox -* wearer for moaning. So i really need it, don't touch or whole ballgag will be broken -* for ballgag mute audible emotes -* adding is_ballgagged() proc here. Hope won't break anything important. -* This is kinda shitcode, but they said don't touch main code or they will break my knees. -* i love my knees, please merge. -* more shitcode can be found in code/datums/emotes.dm -* in /datum/emote/proc/select_message_type(mob/user, intentional) proc. Sorry for that, i had no other choise. -*/ - -//false for default -/mob/proc/is_ballgagged() - return FALSE - -/mob/living/carbon/is_ballgagged() - return(istype(src.wear_mask, /obj/item/clothing/mask/ballgag) || istype(src.wear_mask, /obj/item/clothing/head/helmet/space/deprivation_helmet)) - -//proc for condoms. Need to prevent cum appearing on the floor. -/mob/proc/wear_condom() - return FALSE - -/mob/living/carbon/human/wear_condom() - . = ..() - if(.) - return TRUE - if(penis != null && istype(penis, /obj/item/clothing/sextoy/condom)) - return TRUE - return FALSE - -/* -* This shouldn't be put anywhere, get your dirty hands off! -* For dancing pole -*/ - -/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 - -/* -* This code needed to determine if the human is naked in that part of body or not -* You can you 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) - -/mob/living/carbon/human/proc/has_penis(required_state = REQUIRE_ANY) - if(issilicon(src) && has_penis) - return TRUE - var/obj/item/organ/external/genital/peepee = getorganslot(ORGAN_SLOT_PENIS) - if(peepee) - switch(required_state) - if(REQUIRE_ANY) - return TRUE - if(REQUIRE_EXPOSED) - if(peepee.visibility_preference == GENITAL_ALWAYS_SHOW || is_bottomless()) - return TRUE - else - return FALSE - if(REQUIRE_UNEXPOSED) - if(peepee.visibility_preference != GENITAL_ALWAYS_SHOW && !is_bottomless()) - return TRUE - else - return FALSE - else - return TRUE - return FALSE - -/mob/living/carbon/human/proc/has_balls(required_state = REQUIRE_ANY) - var/obj/item/organ/external/genital/peepee = getorganslot(ORGAN_SLOT_TESTICLES) - if(peepee) - switch(required_state) - if(REQUIRE_ANY) - return TRUE - if(REQUIRE_EXPOSED) - if(peepee.visibility_preference == GENITAL_ALWAYS_SHOW || is_bottomless()) - return TRUE - else - return FALSE - if(REQUIRE_UNEXPOSED) - if(peepee.visibility_preference != GENITAL_ALWAYS_SHOW && !is_bottomless()) - return TRUE - else - return FALSE - else - return TRUE - return FALSE - -/mob/living/carbon/human/proc/has_vagina(required_state = REQUIRE_ANY) - if(issilicon(src) && has_vagina) - return TRUE - var/obj/item/organ/external/genital/peepee = getorganslot(ORGAN_SLOT_VAGINA) - if(peepee) - switch(required_state) - if(REQUIRE_ANY) - return TRUE - if(REQUIRE_EXPOSED) - if(peepee.visibility_preference == GENITAL_ALWAYS_SHOW || is_bottomless()) - return TRUE - else - return FALSE - if(REQUIRE_UNEXPOSED) - if(peepee.visibility_preference != GENITAL_ALWAYS_SHOW && !is_bottomless()) - return TRUE - else - return FALSE - else - return TRUE - return FALSE - -/mob/living/carbon/human/proc/has_breasts(required_state = REQUIRE_ANY) - var/obj/item/organ/external/genital/peepee = getorganslot(ORGAN_SLOT_BREASTS) - if(peepee) - switch(required_state) - if(REQUIRE_ANY) - return TRUE - if(REQUIRE_EXPOSED) - if(peepee.visibility_preference == GENITAL_ALWAYS_SHOW || is_topless()) - return TRUE - else - return FALSE - if(REQUIRE_UNEXPOSED) - if(peepee.visibility_preference != GENITAL_ALWAYS_SHOW && !is_topless()) - return TRUE - else - return FALSE - else - return TRUE - return FALSE - -/mob/living/carbon/human/proc/has_anus(required_state = REQUIRE_ANY) - if(issilicon(src)) - return TRUE - var/obj/item/organ/external/genital/peepee = getorganslot(ORGAN_SLOT_ANUS) - if(peepee) - switch(required_state) - if(REQUIRE_ANY) - return TRUE - if(REQUIRE_EXPOSED) - if(peepee.visibility_preference == GENITAL_ALWAYS_SHOW || is_bottomless()) - return TRUE - else - return FALSE - if(REQUIRE_UNEXPOSED) - if(peepee.visibility_preference != GENITAL_ALWAYS_SHOW && !is_bottomless()) - return TRUE - else - return FALSE - else - return TRUE - -/mob/living/carbon/human/proc/has_arms(required_state = REQUIRE_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_ANY) - return hand_count - if(REQUIRE_EXPOSED) - if(is_covered) - return FALSE - else - return hand_count - if(REQUIRE_UNEXPOSED) - if(!is_covered) - return FALSE - else - return hand_count - else - return hand_count - -/mob/living/carbon/human/proc/has_feet(required_state = REQUIRE_ANY) - var/feet_count = 0 - var/covered = 0 - var/is_covered = FALSE - 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++ - if(!is_barefoot()) - covered = TRUE - if(covered) - is_covered = TRUE - switch(required_state) - if(REQUIRE_ANY) - return feet_count - if(REQUIRE_EXPOSED) - if(is_covered) - return FALSE - else - return feet_count - if(REQUIRE_UNEXPOSED) - if(!is_covered) - return FALSE - else - return feet_count - else - return feet_count - -/mob/living/carbon/human/proc/get_num_feet() - return has_feet(REQUIRE_ANY) - -// Weird procs go here -/mob/living/carbon/human/proc/has_ears(required_state = REQUIRE_ANY) - var/obj/item/organ/peepee = getorganslot(ORGAN_SLOT_EARS) - if(peepee) - switch(required_state) - if(REQUIRE_ANY) - return TRUE - if(REQUIRE_EXPOSED) - if(get_item_by_slot(ITEM_SLOT_EARS)) - return FALSE - else - return TRUE - if(REQUIRE_UNEXPOSED) - if(!get_item_by_slot(ITEM_SLOT_EARS)) - return FALSE - else - return TRUE - else - return TRUE - return FALSE - -/mob/living/carbon/human/proc/has_earsockets(required_state = REQUIRE_ANY) - var/obj/item/organ/peepee = getorganslot(ORGAN_SLOT_EARS) - if(!peepee) - switch(required_state) - if(REQUIRE_ANY) - return TRUE - if(REQUIRE_EXPOSED) - if(get_item_by_slot(ITEM_SLOT_EARS)) - return FALSE - else - return TRUE - if(REQUIRE_UNEXPOSED) - if(!get_item_by_slot(ITEM_SLOT_EARS)) - return FALSE - else - return TRUE - else - return TRUE - return FALSE - -/mob/living/carbon/human/proc/has_eyes(required_state = REQUIRE_ANY) - var/obj/item/organ/peepee = getorganslot(ORGAN_SLOT_EYES) - if(peepee) - switch(required_state) - if(REQUIRE_ANY) - return TRUE - if(REQUIRE_EXPOSED) - if(get_item_by_slot(ITEM_SLOT_EYES)) - return FALSE - else - return TRUE - if(REQUIRE_UNEXPOSED) - if(!get_item_by_slot(ITEM_SLOT_EYES)) - return FALSE - else - return TRUE - else - return TRUE - return FALSE - -/mob/living/carbon/human/proc/has_eyesockets(required_state = REQUIRE_ANY) - var/obj/item/organ/peepee = getorganslot(ORGAN_SLOT_EYES) - if(!peepee) - switch(required_state) - if(REQUIRE_ANY) - return TRUE - if(REQUIRE_EXPOSED) - if(get_item_by_slot(ITEM_SLOT_EYES)) - return FALSE - else - return TRUE - if(REQUIRE_UNEXPOSED) - if(!get_item_by_slot(ITEM_SLOT_EYES)) - return FALSE - else - return TRUE - else - return TRUE - return FALSE - - -/* -* This code needed for changing character's gender by chems -*/ - -/mob/living/carbon/human/proc/set_gender(ngender = NEUTER, silent = FALSE, update_icon = TRUE, forced = FALSE) - if(forced || (!ckey || client?.prefs.read_preference(/datum/preference/toggle/erp/gender_change))) - gender = ngender - return TRUE - return FALSE - -/mob/living/carbon/human/set_gender(ngender = NEUTER, silent = FALSE, update_icon = TRUE, forced = FALSE) - var/bender = !(gender == ngender) - . = ..() - if(!.) - return - if(dna && bender) - 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 - if(update_icon) - update_body() - -/* -* INVENTORY SYSTEM EXTENTION -*/ - -/* -* ERP INVENTORY ITEM SLOTS -*/ - -/* -/// Vagina slot -#define ITEM_SLOT_VAGINA (1<<21) - -/// Anus slot -#define ITEM_SLOT_ANUS (1<<22) - -/// Nipples slot -#define ITEM_SLOT_NIPPLES (1<<23) - -/// Penis slot -#define ITEM_SLOT_PENIS (1<<20) -*/ - -// SLOT GROUP HELPERS -#define ITEM_SLOT_ERP_INSERTABLE (ITEM_SLOT_VAGINA|ITEM_SLOT_ANUS) -#define ITEM_SLOT_ERP_ATTACHABLE (ITEM_SLOT_NIPPLES|ITEM_SLOT_PENIS) - -// Strippable Defines -#define ERP_SLOT_EQUIP_DELAY (5 SECONDS) // Lamella TODO: delay need to be balanced - -#define STRIPPABLE_ITEM_VAGINA "vagina" -#define STRIPPABLE_ITEM_ANUS "anus" -#define STRIPPABLE_ITEM_NIPPLES "nipples" -#define STRIPPABLE_ITEM_PEINS "penis" - -/* -* OUTFIT SYSTEM ERP SLOT SUPPORT -*/ - -// Variables for ERP slots -/datum/outfit - /// Type path of item for vagina slot - var/vagina = null - /// Type path of item for anus slot - var/anus = null - /// Type path of item for nipples slot - var/nipples = null - /// Type path of item for penis slot - var/penis = null - -// Complementing the equipment procedure -/datum/outfit/equip(mob/living/carbon/human/target, visualsOnly = FALSE) - . = ..() - if(.) - var/need_updating = FALSE - if(vagina) - target.equip_to_slot_or_del(new vagina(target), ITEM_SLOT_VAGINA, TRUE) - need_updating = TRUE - - if(anus) - target.equip_to_slot_or_del(new anus(target), ITEM_SLOT_ANUS, TRUE) - need_updating = TRUE - - if(nipples) - target.equip_to_slot_or_del(new nipples(target), ITEM_SLOT_NIPPLES, TRUE) - need_updating = TRUE - - if(penis) - target.equip_to_slot_or_del(new penis(target), ITEM_SLOT_PENIS, TRUE) - need_updating = TRUE - - if(need_updating) - target.update_body() - target?.hud_used?.hidden_inventory_update(target) - - return TRUE - - return . - - -// Support fingerprints when working with ERP slots -/datum/outfit/apply_fingerprints(mob/living/carbon/human/target) - . = ..() - if(.) - if(!istype(target)) - return - if(target.vagina) - target.vagina.add_fingerprint(target, 1) - if(target.anus) - target.anus.add_fingerprint(target, 1) - if(target.nipples) - target.nipples.add_fingerprint(target, 1) - if(target.penis) - target.penis.add_fingerprint(target, 1) - return 1 - -// Supplementing the data structure with ERP slot data -/datum/outfit/get_json_data() - var/list/genital_list = ..() - - genital_list["vagina"] = vagina - genital_list["anus"] = anus - genital_list["nipples"] = nipples - genital_list["penis"] = penis - -// Supplementing the data structure with ERP slot data -/datum/outfit/load_from(list/outfit_data) - vagina = text2path(outfit_data["vagina"]) - anus = text2path(outfit_data["anus"]) - nipples = text2path(outfit_data["nipples"]) - penis = text2path(outfit_data["penis"]) - . = ..() - -// Just by analogy with the TG code. No ideas for what this is. -/mob/proc/update_inv_vagina() - return -/mob/proc/update_inv_anus() - return -/mob/proc/update_inv_nipples() - return -/mob/proc/update_inv_penis() - return - -// Add variables for slots to the Carbon class -/mob/living/carbon/human - var/obj/item/vagina = null - var/obj/item/anus = null - var/obj/item/nipples = null - var/obj/item/penis = null - -/* -* SEXTOY CLOTH TYPE -*/ - -/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' - slot_flags = ITEM_SLOT_VAGINA | ITEM_SLOT_ANUS | ITEM_SLOT_PENIS | ITEM_SLOT_NIPPLES - -/obj/item/clothing/sextoy/dropped(mob/user) - ..() - - update_appearance() - if(!ishuman(loc)) - return - - var/mob/living/carbon/human/holder = loc - holder.update_inv_vagina() - holder.update_inv_anus() - holder.update_inv_nipples() - holder.update_inv_penis() - 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 - -/* -* ICON UPDATING EXTENTION -*/ - -// Regenerate ERP icons to -/mob/living/carbon/human/regenerate_icons() - .=..() - update_inv_vagina() - update_inv_anus() - update_inv_nipples() - update_inv_penis() - -// Updating vagina slot -/mob/living/carbon/human/update_inv_vagina() - if(client?.prefs?.read_preference(/datum/preference/toggle/erp/sex_toy)) - if(client && hud_used && hud_used.inv_slots[TOBITSHIFT(ITEM_SLOT_VAGINA) + 1]) - var/atom/movable/screen/inventory/inv = hud_used.inv_slots[TOBITSHIFT(ITEM_SLOT_VAGINA) + 1] - inv.update_icon() - - if(vagina) - if(hud_used.inventory_shown && hud_used) - vagina?.screen_loc = ui_vagina - else - vagina?.screen_loc = ui_vagina_down - if(hud_used.hud_shown) - client.screen += vagina - update_observer_view(vagina) - hud_used.hidden_inventory_update(src) - - // 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/update_inv_anus() - if(client?.prefs?.read_preference(/datum/preference/toggle/erp/sex_toy)) - if(client && hud_used && hud_used.inv_slots[TOBITSHIFT(ITEM_SLOT_ANUS) + 1]) - var/atom/movable/screen/inventory/inv = hud_used.inv_slots[TOBITSHIFT(ITEM_SLOT_ANUS) + 1] - inv.update_icon() - - if(anus) - if(hud_used.inventory_shown && hud_used) - anus?.screen_loc = ui_anus - else - anus?.screen_loc = ui_anus_down - if(hud_used.hud_shown) - client.screen += anus - update_observer_view(anus) - hud_used.hidden_inventory_update(src) - - // 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/update_inv_nipples() - if(client?.prefs?.read_preference(/datum/preference/toggle/erp/sex_toy)) - if(client && hud_used && hud_used.inv_slots[TOBITSHIFT(ITEM_SLOT_NIPPLES) + 1]) - var/atom/movable/screen/inventory/inv = hud_used.inv_slots[TOBITSHIFT(ITEM_SLOT_NIPPLES) + 1] - inv.update_icon() - - if(nipples) - if(hud_used.inventory_shown && hud_used) - nipples?.screen_loc = ui_nipples - else - nipples?.screen_loc = ui_nipples_down - if(hud_used.hud_shown) - client.screen += nipples - update_observer_view(nipples) - hud_used.hidden_inventory_update(src) - - // 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/update_inv_penis() - if(client?.prefs?.read_preference(/datum/preference/toggle/erp/sex_toy)) - if(client && hud_used && hud_used.inv_slots[TOBITSHIFT(ITEM_SLOT_PENIS) + 1]) - var/atom/movable/screen/inventory/inv = hud_used.inv_slots[TOBITSHIFT(ITEM_SLOT_PENIS) + 1] - inv.update_icon() - - if(penis) - if(hud_used.inventory_shown && hud_used) - penis?.screen_loc = ui_penis - else - penis?.screen_loc = ui_penis_down - if(hud_used.hud_shown) - client.screen += penis - update_observer_view(penis) - hud_used.hidden_inventory_update(src) - - // 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() - -// Updating vagina hud slot -/mob/living/carbon/human/update_hud_vagina(obj/item/contained_item) - contained_item.screen_loc = ui_vagina - if(client && src.hud_used?.hud_shown) - if(src.hud_used.inventory_shown) - client.screen += contained_item - update_observer_view(contained_item, 1) - -// Updating anus hud slot -/mob/living/carbon/human/update_hud_anus(obj/item/contained_item) - contained_item.screen_loc = ui_anus - if(client && src.hud_used?.hud_shown) - if(src.hud_used.inventory_shown) - client.screen += contained_item - update_observer_view(contained_item, 1) - -// Updating nipples hud slot -/mob/living/carbon/human/update_hud_nipples(obj/item/contained_item) - contained_item.screen_loc = ui_nipples - if(client && src.hud_used?.hud_shown) - if(src.hud_used.inventory_shown) - client.screen += contained_item - update_observer_view(contained_item, 1) - -// Updating penis hud slot -/mob/living/carbon/human/update_hud_penis(obj/item/contained_item) - contained_item.screen_loc = ui_penis - if(client && src.hud_used?.hud_shown) - if(src.hud_used.inventory_shown) - client.screen += contained_item - update_observer_view(contained_item, 1) - -// Update whether our back item appears on our hud. -/mob/living/carbon/proc/update_hud_vagina(obj/item/contained_item) - return - -// Update whether our back item appears on our hud. -/mob/living/carbon/proc/update_hud_anus(obj/item/contained_item) - return - -// Update whether our back item appears on our hud. -/mob/living/carbon/proc/update_hud_nipples(obj/item/contained_item) - return - -// Update whether our back item appears on our hud. -/mob/living/carbon/proc/update_hud_penis(obj/item/contained_item) - return - -/* -* UI CONSTRUCTION AND HANDLING -*/ - -// Add to hud class additional ERP variable boolean for check inventiry status (equipped or not) -/datum/hud - /// The screen ERP objects which can be hidden - var/list/erp_toggleable_inventory = list() - /// Equipped item ERP inventory - var/ERP_inventory_shown = FALSE - -// Define additional button for ERP hud slots for expand/collapse like default inventory -/atom/movable/screen/human/erp_toggle - name = "erp_toggle" - icon_state = "toggle" - -// ERP inventory button logic. Just expand/collapse -/atom/movable/screen/human/erp_toggle/Click() - - var/mob/target_mob = usr - - if(isobserver(usr)) - if(ishuman(usr.client.eye) && (usr.client.eye != usr)) - var/mob/target_eye = usr.client.eye - target_mob = target_eye - - if(usr.hud_used.ERP_inventory_shown && target_mob.hud_used) - usr.hud_used.ERP_inventory_shown = FALSE - usr.client.screen -= target_mob.hud_used.erp_toggleable_inventory - else - usr.hud_used.ERP_inventory_shown = TRUE - usr.client.screen += target_mob.hud_used.erp_toggleable_inventory - - target_mob.hud_used.hidden_inventory_update(usr) - -/* -* STRIPPING ERP SYSTEM EXTENTION -*/ - -// Extend stripping menus with ERP slots -/datum/strippable_item/mob_item_slot/vagina - key = STRIPPABLE_ITEM_VAGINA - item_slot = ITEM_SLOT_VAGINA - -/datum/strippable_item/mob_item_slot/anus - key = STRIPPABLE_ITEM_ANUS - item_slot = ITEM_SLOT_ANUS - -/datum/strippable_item/mob_item_slot/nipples - key = STRIPPABLE_ITEM_NIPPLES - item_slot = ITEM_SLOT_NIPPLES - -/datum/strippable_item/mob_item_slot/penis - key = STRIPPABLE_ITEM_PEINS - item_slot = ITEM_SLOT_PENIS - -// Obscuring for ERP slots -/datum/strippable_item/mob_item_slot/vagina/get_obscuring(atom/source) - var/mob/source_mob = source - if(source_mob.client?.prefs?.read_preference(/datum/preference/toggle/erp/sex_toy)) - return isnull(get_item(source)) \ - ? STRIPPABLE_OBSCURING_NONE \ - : STRIPPABLE_OBSCURING_HIDDEN - else - return STRIPPABLE_OBSCURING_COMPLETELY -// Obscuring for ERP slots -/datum/strippable_item/mob_item_slot/anus/get_obscuring(atom/source) - var/mob/source_mob = source - if(source_mob.client?.prefs?.read_preference(/datum/preference/toggle/erp/sex_toy)) - return isnull(get_item(source)) \ - ? STRIPPABLE_OBSCURING_NONE \ - : STRIPPABLE_OBSCURING_HIDDEN - else - return STRIPPABLE_OBSCURING_COMPLETELY -// Obscuring for ERP slots -/datum/strippable_item/mob_item_slot/nipples/get_obscuring(atom/source) - var/mob/source_mob = source - if(source_mob.client?.prefs?.read_preference(/datum/preference/toggle/erp/sex_toy)) - return isnull(get_item(source)) \ - ? STRIPPABLE_OBSCURING_NONE \ - : STRIPPABLE_OBSCURING_HIDDEN - else - return STRIPPABLE_OBSCURING_COMPLETELY -// Obscuring for ERP slots -/datum/strippable_item/mob_item_slot/penis/get_obscuring(atom/source) - var/mob/source_mob = source - if(source_mob.client?.prefs?.read_preference(/datum/preference/toggle/erp/sex_toy)) - return isnull(get_item(source)) \ - ? STRIPPABLE_OBSCURING_NONE \ - : STRIPPABLE_OBSCURING_HIDDEN - else - return STRIPPABLE_OBSCURING_COMPLETELY - -// Strippable ERP items slot list -GLOBAL_LIST_INIT(strippable_human_erp_items, create_erp_strippable_list(list( - /datum/strippable_item/mob_item_slot/vagina, - /datum/strippable_item/mob_item_slot/anus, - /datum/strippable_item/mob_item_slot/nipples, - /datum/strippable_item/mob_item_slot/penis, -))) - -// This list is only needed in order to immediately add the necessary elements to a typical global list -/proc/create_erp_strippable_list(types) - var/list/strippable_items = list() - - for (var/strippable_type in types) - var/datum/strippable_item/strippable_item = new strippable_type - strippable_items[strippable_item.key] = strippable_item - GLOB.strippable_human_items += strippable_items - return strippable_items - -//Disables ERP strippable inventory depending on config -/datum/element/strippable/Attach(datum/target, list/items, should_strip_proc_path) - . = ..() - if(CONFIG_GET(flag/disable_erp_preferences)) - src.items -= GLOB.strippable_human_erp_items - -/* -* EXTENTIONS FOR SPRITE_ACCESSORY IS_HIDDEN CHECKS FOR ERP STUFF -*/ - -// Extends default proc check for hidden ears for supporting our sleepbag and catsuit to -/datum/sprite_accessory/ears/is_hidden(mob/living/carbon/human/target_human, obj/item/bodypart/HD) - /* - // Default proc code - if(target_human.head && (target_human.head.flags_inv & HIDEHAIR) || (target_human.wear_mask && (target_human.wear_mask.flags_inv & HIDEHAIR)) || !HD) - //return TRUE - return FALSE - */ - - // First lets proc default code - . = ..() - if(!.) // If true, ears already hidden - 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 TRUE - return FALSE - else if(target_human.w_uniform && istype(target_human.w_uniform, /obj/item/clothing/under/misc/latex_catsuit/)) - return FALSE - return FALSE - return TRUE // Return TRUE if superfuncitons already retuns TRUE - -// Extends default proc check for hidden frills for supporting our sleepbag and catsuit to -/datum/sprite_accessory/frills/is_hidden(mob/living/carbon/human/target_human, obj/item/bodypart/HD) - /* - // Default proc code - if(target_human.head && (target_human.try_hide_mutant_parts || (target_human.head.flags_inv & HIDEEARS) || !HD || HD.status == BODYPART_ROBOTIC)) - //return TRUE - return FALSE - */ - - . = ..() - if(!.) // If true, frills already hidden - 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 TRUE - return FALSE - else if(target_human.w_uniform && istype(target_human.w_uniform, /obj/item/clothing/under/misc/latex_catsuit/)) - return FALSE - return FALSE - return TRUE // Return TRUE if superfuncitons already retuns TRUE - -// Extends default proc check for hidden head accessory for supporting our sleepbag and catsuit to -/datum/sprite_accessory/head_accessory/is_hidden(mob/living/carbon/human/target_human, obj/item/bodypart/HD) - /* - // Default proc code - if(target_human.head && (target_human.head.flags_inv & HIDEHAIR) || (target_human.wear_mask && (target_human.wear_mask.flags_inv & HIDEHAIR))) - //return TRUE - return FALSE - */ - - . = ..() - if(!.) // If true, head accessory already hidden - 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 TRUE - return FALSE - else if(target_human.w_uniform && istype(target_human.w_uniform, /obj/item/clothing/under/misc/latex_catsuit/)) - return FALSE - return FALSE - return TRUE // Return TRUE if superfuncitons already retuns TRUE - -// Extends default proc check for hidden horns for supporting our sleepbag and catsuit to -/datum/sprite_accessory/horns/is_hidden(mob/living/carbon/human/target_human, obj/item/bodypart/HD) - /* - // Default proc code - if(target_human.head && (target_human.head.flags_inv & HIDEHAIR) || (target_human.wear_mask && (target_human.wear_mask.flags_inv & HIDEHAIR)) || !HD) - return TRUE - return FALSE - */ - - . = ..() - if(!.) // If true, horns already hidden - 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 TRUE - return FALSE - else if(target_human.w_uniform && istype(target_human.w_uniform, /obj/item/clothing/under/misc/latex_catsuit/)) - return FALSE - return FALSE - return TRUE // Return TRUE if superfuncitons already retuns TRUE - -// Extends default proc check for hidden antenna for supporting our sleepbag and catsuit to -/datum/sprite_accessory/antenna/is_hidden(mob/living/carbon/human/target_human, obj/item/bodypart/HD) - /* - // Default proc code - if(target_human.head && (target_human.head.flags_inv & HIDEHAIR) || (target_human.wear_mask && (target_human.wear_mask.flags_inv & HIDEHAIR)) || !HD) - //return TRUE - return FALSE - */ - - . = ..() - if(!.) // If true, antenna already hidden - 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 TRUE - return FALSE - else if(target_human.w_uniform && istype(target_human.w_uniform, /obj/item/clothing/under/misc/latex_catsuit/)) - return FALSE - return FALSE - return TRUE // Return TRUE if superfuncitons already retuns TRUE - -// Extends default proc check for hidden moth antenna for supporting our sleepbag and catsuit to -/datum/sprite_accessory/moth_antennae/is_hidden(mob/living/carbon/human/target_human, obj/item/bodypart/HD) - /* - // Default proc code - if(target_human.head && (target_human.head.flags_inv & HIDEHAIR) || (target_human.wear_mask && (target_human.wear_mask.flags_inv & HIDEHAIR)) || !HD) - //return TRUE - return FALSE - */ - - . = ..() - if(!.) // If true, moth antenna already hidden - 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 TRUE - return FALSE - else if(target_human.w_uniform && istype(target_human.w_uniform, /obj/item/clothing/under/misc/latex_catsuit/)) - return FALSE - return FALSE - return TRUE // Return TRUE if superfuncitons already retuns TRUE - -// Extends default proc check for hidden skrell hair for supporting our sleepbag and catsuit to -/datum/sprite_accessory/skrell_hair/is_hidden(mob/living/carbon/human/target_human, obj/item/bodypart/HD) - /* - // Default proc code - if(target_human.head && (target_human.head.flags_inv & HIDEHAIR) || (target_human.wear_mask && (target_human.wear_mask.flags_inv & HIDEHAIR))) - return TRUE - return FALSE - */ - - . = ..() - if(!.) // If true, skrell hair already hidden - 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 TRUE - return FALSE - else if(target_human.w_uniform && istype(target_human.w_uniform, /obj/item/clothing/under/misc/latex_catsuit/)) - return FALSE - return FALSE - return TRUE // Return TRUE if superfuncitons already retuns TRUE - -// Extends default proc check for hidden skrell hair for supporting our sleepbag and catsuit to -/datum/sprite_accessory/tails/is_hidden(mob/living/carbon/human/target_human, obj/item/bodypart/HD) - - . = ..() - if(!.) // If true, tail already hidden - 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 TRUE - return TRUE /* return FALSE */ - else if(target_human.w_uniform && istype(target_human.w_uniform, /obj/item/clothing/under/misc/latex_catsuit/)) - return TRUE - return FALSE - return TRUE // Return TRUE if superfuncitons already retuns TRUE - -// Extends default proc check for hidden wings for supporting our sleepbag and catsuit to -/datum/sprite_accessory/wings/is_hidden(mob/living/carbon/human/target_human, obj/item/bodypart/HD) - . = ..() - if(.) - return TRUE - if(target_human.wear_suit && istype(target_human.wear_suit, /obj/item/clothing/suit/straight_jacket/kinky_sleepbag)) - return TRUE - return FALSE - -/mob/living/carbon/human/set_handcuffed(new_value) - if(wear_suit && istype(wear_suit, /obj/item/clothing/suit/straight_jacket/kinky_sleepbag)) - return FALSE - ..() - -/datum/sprite_accessory/xenodorsal/is_hidden(mob/living/carbon/human/target_human, obj/item/bodypart/HD) - if(target_human.wear_suit && istype(target_human.wear_suit, /obj/item/clothing/suit/straight_jacket/kinky_sleepbag)) - return TRUE - else if(target_human.w_uniform && istype(target_human.w_uniform, /obj/item/clothing/under/misc/latex_catsuit/)) - return TRUE - return FALSE - -/datum/sprite_accessory/xenohead/is_hidden(mob/living/carbon/human/target_human, obj/item/bodypart/HD) - 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 TRUE - return FALSE - else if(target_human.w_uniform && istype(target_human.w_uniform, /obj/item/clothing/under/misc/latex_catsuit/)) - return FALSE - return FALSE - -/datum/preference/toggle/erp/sex_toy/apply_to_client_updated(client/client, value) - . = ..() - if(client?.prefs?.read_preference(/datum/preference/toggle/erp/sex_toy)) - if(client.mob.hud_used) - for(var/atom/movable/screen/human/erp_toggle/toggle in client.mob.hud_used.static_inventory) - if(istype(toggle, /atom/movable/screen/human/erp_toggle)) - toggle.invisibility = 0 - else - 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) - if(client.mob.hud_used) - if(client.mob.hud_used.ERP_inventory_shown) - client.mob.hud_used.ERP_inventory_shown = FALSE - client.screen -= client.mob.hud_used.erp_toggleable_inventory - - for(var/atom/movable/screen/human/erp_toggle/erp_button in client.mob.hud_used.static_inventory) - if(istype(erp_button, /atom/movable/screen/human/erp_toggle)) - erp_button.invisibility = 100 - - - client.mob.hud_used.hidden_inventory_update(client.mob) - client.mob.hud_used.persistent_inventory_update(client.mob) - -/// If the item this is called in, is in a genital slot of the target -/obj/item/proc/is_in_genital(mob/living/carbon/human/the_guy) - return (src == the_guy.penis || src == the_guy.vagina || src == the_guy.anus || src == the_guy.nipples) - -/// 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 diff --git a/modular_skyrat/modules/modular_items/lewd_items/code/verbs.dm b/modular_skyrat/modules/modular_items/lewd_items/code/verbs.dm new file mode 100644 index 00000000000..4edd2ccf3ed --- /dev/null +++ b/modular_skyrat/modules/modular_items/lewd_items/code/verbs.dm @@ -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 diff --git a/modular_skyrat/modules/modular_items/readme.md b/modular_skyrat/modules/modular_items/readme.md index e42eed6c332..b55bb62b4be 100644 --- a/modular_skyrat/modules/modular_items/readme.md +++ b/modular_skyrat/modules/modular_items/readme.md @@ -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. diff --git a/tgstation.dme b/tgstation.dme index 858aca6407e..1d267fe8b3e 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -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" diff --git a/tgui/packages/tgui/interfaces/InteractionMenu.js b/tgui/packages/tgui/interfaces/InteractionMenu.js deleted file mode 100644 index c6f01b0a9ab..00000000000 --- a/tgui/packages/tgui/interfaces/InteractionMenu.js +++ /dev/null @@ -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 ( - - - {(block_interact && Unable to Interact) || ( - Able to Interact - )} -
- {categories.map((category) => ( -
- {interactions[category].map((interaction) => ( -
- -
- ))} -
- ))} -
-
-
- ); -}; diff --git a/tgui/packages/tgui/interfaces/InteractionMenu.tsx b/tgui/packages/tgui/interfaces/InteractionMenu.tsx new file mode 100644 index 00000000000..c41e611ddb4 --- /dev/null +++ b/tgui/packages/tgui/interfaces/InteractionMenu.tsx @@ -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(context); + const { + categories, + interactions, + descriptions, + colors, + lewd_slots, + self, + ref_self, + ref_user, + block_interact, + } = data; + + return ( + + + {(block_interact && Unable to Interact) || ( + Able to Interact + )} +
+ {categories.map((category) => ( +
+ {interactions[category].map((interaction) => ( +
+
+ ))} +
+ ))} +
+ {lewd_slots.length > 0 ? ( +
+ + {lewd_slots.map((element: LewdSlot) => { + return ( + + + + ); + })} + +
+ ) : ( + '' + )} +
+
+ ); +}; diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/skyrat/cursed_shit.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/skyrat/genitals.tsx similarity index 93% rename from tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/skyrat/cursed_shit.tsx rename to tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/skyrat/genitals.tsx index 43ffd2b3a63..5ffd9f414e6 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/skyrat/cursed_shit.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/skyrat/genitals.tsx @@ -106,38 +106,38 @@ export const feature_womb: Feature = { }; export const feature_breasts: Feature = { - 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 = { - name: 'Breasts Color', + name: 'Breast Color', component: FeatureTriColorInput, }; export const breasts_emissive: Feature = { - 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 = { + name: 'Breast Size', + component: FeatureDropdownInput, }; export const feature_anus: Feature = { diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/game_preferences/skyrat/erp_preferences.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/game_preferences/skyrat/erp_preferences.tsx index 8cb3b1b8099..d5d5f378ea9 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/game_preferences/skyrat/erp_preferences.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/game_preferences/skyrat/erp_preferences.tsx @@ -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, +};