diff --git a/Content.Shared/_DEN/SolutionExpulsion/Components/SolutionExpellableComponent.cs b/Content.Shared/_DEN/SolutionExpulsion/Components/SolutionExpellableComponent.cs
new file mode 100644
index 0000000000..eab8bc19ee
--- /dev/null
+++ b/Content.Shared/_DEN/SolutionExpulsion/Components/SolutionExpellableComponent.cs
@@ -0,0 +1,47 @@
+using Content.Shared.FixedPoint;
+using Robust.Shared.GameStates;
+
+namespace Content.Shared._DEN.SolutionExpulsion.Components;
+
+[RegisterComponent, NetworkedComponent]
+public sealed partial class SolutionExpellableComponent : Component
+{
+ ///
+ /// Maximum amount of the solution you can expel at once
+ ///
+ [DataField]
+ public FixedPoint2 MaximumExpulsion = 10;
+
+ [DataField]
+ public TimeSpan DoAfterDuration = TimeSpan.FromSeconds(3);
+
+ ///
+ /// Solution name to use, should be kept seperate from other expellable solutions unless you specifically want them mixing.
+ ///
+ [DataField]
+ public string DefaultSolutionName = "testicles";
+
+ ///
+ /// Determines if the verb icon is NSFW or not.. I'd love to specify an actual texture here but YOU CANT SPECIFY SPECIFIC TEXTURES IN YAML !!!!!!!!!!
+ ///
+ [DataField]
+ public bool NsfwVerbIcon;
+
+ ///
+ /// Text to display on the verb.
+ ///
+ [DataField]
+ public string VerbText = "cum-verb-text";
+
+ ///
+ /// Popup that occurs when your solution is empty
+ ///
+ [DataField]
+ public string PopupEmpty = "cum-verb-dry";
+
+ ///
+ /// Popup that occurs when successfully expel the solution.
+ ///
+ [DataField]
+ public string PopupSuccess = "cum-verb-success";
+}
diff --git a/Content.Shared/_DEN/SolutionExpulsion/Components/SolutionExpellerComponent.cs b/Content.Shared/_DEN/SolutionExpulsion/Components/SolutionExpellerComponent.cs
new file mode 100644
index 0000000000..4572b1bb4c
--- /dev/null
+++ b/Content.Shared/_DEN/SolutionExpulsion/Components/SolutionExpellerComponent.cs
@@ -0,0 +1,12 @@
+using Content.Shared.Chemistry.Components;
+using Robust.Shared.GameStates;
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared._DEN.SolutionExpulsion.Components;
+
+[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
+public sealed partial class SolutionExpellerComponent : Component
+{
+ [ViewVariables, AutoNetworkedField]
+ public Dictionary SolutionEntities = [];
+}
diff --git a/Content.Shared/_DEN/SolutionExpulsion/EntitySystems/SolutionExpulsionSystem.cs b/Content.Shared/_DEN/SolutionExpulsion/EntitySystems/SolutionExpulsionSystem.cs
new file mode 100644
index 0000000000..1c4eb8a1ae
--- /dev/null
+++ b/Content.Shared/_DEN/SolutionExpulsion/EntitySystems/SolutionExpulsionSystem.cs
@@ -0,0 +1,197 @@
+using Content.Shared._DEN.SolutionExpulsion.Components;
+using Content.Shared._DEN.SolutionExpulsion.Events;
+using Content.Shared.Chemistry.Components;
+using Content.Shared.Chemistry.EntitySystems;
+using Content.Shared.DoAfter;
+using Content.Shared.FixedPoint;
+using Content.Shared.IdentityManagement;
+using Content.Shared.Popups;
+using Content.Shared.Verbs;
+using Robust.Shared.Prototypes;
+using Robust.Shared.Utility;
+
+namespace Content.Shared._DEN.SolutionExpulsion.EntitySystems;
+
+public sealed partial class SolutionExpulsionSystem : EntitySystem
+{
+ [Dependency] private IPrototypeManager _protoMan = default!;
+ [Dependency] private SharedDoAfterSystem _doAfter = default!;
+ [Dependency] private SharedPopupSystem _popup = default!;
+ [Dependency] private SharedSolutionContainerSystem _solutionContainer = default!;
+
+ private static readonly VerbCategory ReagentFillCategory = new("verb-categories-fill", "/Textures/Interface/VerbIcons/spill.svg.192dpi.png");
+
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ SubscribeLocalEvent>(AddVerbs);
+
+ SubscribeLocalEvent(FinishFillDoAfter);
+
+ SubscribeLocalEvent(SolutionExpellerAdded);
+ SubscribeLocalEvent(SolutionExpulsionRemoved);
+ }
+
+ ///
+ /// Add an expellable solution to an entity.
+ ///
+ /// The entity to add the expellable solution to.
+ /// The entity prototype of the solution you want the entity to expel.
+ public void AddExpellableSolution(EntityUid entity, EntProtoId expellableSolutionPrototype)
+ {
+ EnsureComp(entity);
+
+ RaiseLocalEvent(entity, new SolutionExpulsionEvents.SolutionExpellableAdded(expellableSolutionPrototype));
+ }
+
+ ///
+ /// Remove an expellable solution from an entity, if there are no more solutions remaining to expel,
+ /// the SolutionExpellerComponent on the entity is deleted.
+ ///
+ /// The entity to remove the expellable solution from.
+ /// The entity prototype of the solution you don't want the entity to expel.
+ public void RemoveExpellableSolution(EntityUid entity, EntProtoId expellableSolutionPrototype)
+ {
+ EnsureComp(entity);
+
+ RaiseLocalEvent(entity, new SolutionExpulsionEvents.SolutionExpellableRemoved(expellableSolutionPrototype));
+ }
+
+ private void SolutionExpellerAdded(Entity ent, ref SolutionExpulsionEvents.SolutionExpellableAdded args)
+ {
+ if (!_protoMan.TryIndex(args.ExpellableSolutionPrototype, out _))
+ return;
+
+ var expellableSolutionEntity = PredictedSpawnAttachedTo(args.ExpellableSolutionPrototype,Transform(ent).Coordinates);
+
+ if (!TryComp(expellableSolutionEntity, out _))
+ return;
+
+ // Add the expellable solution entity to the expeller so they can be iterated over for verbs.
+ ent.Comp.SolutionEntities.Add(args.ExpellableSolutionPrototype,expellableSolutionEntity);
+ Dirty(ent);
+ }
+
+ private void SolutionExpulsionRemoved(Entity ent, ref SolutionExpulsionEvents.SolutionExpellableRemoved args)
+ {
+ if (!_protoMan.TryIndex(args.ExpellableSolutionPrototype, out _))
+ return;
+
+ // Remove the entity from the expellers list and get it so we can remove the real solution too!
+ if (!ent.Comp.SolutionEntities.Remove(args.ExpellableSolutionPrototype, out var expellableSolutionEntity))
+ return;
+
+ // Delete the solution entity entirely, we don't need it anymore!
+ PredictedDel(expellableSolutionEntity);
+
+ // If there are no more solutions to worry about, kill the component
+ if (ent.Comp.SolutionEntities.Count == 0)
+ RemCompDeferred(ent.Owner);
+
+ Dirty(ent);
+ }
+
+ private void AddVerbs(Entity container, ref GetVerbsEvent args)
+ {
+ var user = args.User;
+
+ if (!TryComp(user, out var expellerComponent))
+ return;
+
+ foreach (var (_, expellableSolutionEntity) in expellerComponent.SolutionEntities)
+ {
+ if (!TryComp(expellableSolutionEntity, out var solutionExpellableComponent))
+ return;
+
+ var icon = solutionExpellableComponent.NsfwVerbIcon
+ ? new SpriteSpecifier.Texture(new ResPath("/Textures/_DEN/Interface/VerbIcons/lewd.svg.192dpi.png"))
+ : null;
+
+ var verb = new InteractionVerb
+ {
+ Category = ReagentFillCategory,
+ Act = () => StartFillDoAfter((user, expellerComponent ), container, (expellableSolutionEntity, solutionExpellableComponent)),
+ Text = Loc.GetString(solutionExpellableComponent.VerbText),
+ Priority = -1,
+ CloseMenu = false,
+ Icon = icon,
+ };
+
+ args.Verbs.Add(verb);
+ }
+ }
+
+ private void StartFillDoAfter(
+ Entity user,
+ Entity target,
+ Entity solution
+ )
+ {
+ _doAfter.TryStartDoAfter(
+ new DoAfterArgs(EntityManager,
+ user,
+ solution.Comp.DoAfterDuration,
+ new SolutionExpulsionEvents.SolutionExpulsionFillEvent(GetNetEntity(solution)),
+ user,
+ target: target)
+ {
+ BreakOnMove = true,
+ BreakOnDropItem = true,
+ });
+ }
+
+ private void FinishFillDoAfter(Entity ent, ref SolutionExpulsionEvents.SolutionExpulsionFillEvent args)
+ {
+ if (args.Target == null || args.Cancelled || args.Handled)
+ return;
+
+ if (!TryComp(GetEntity(args.ExpellableSolution), out var expellableComponent))
+ return;
+
+ // Get the solution we're expelling
+ if (!TryComp(GetEntity(args.ExpellableSolution), out var expellableSolutionComponent))
+ return;
+
+ var expellableSolution = expellableSolutionComponent.Solution;
+
+ // Get the solution of the container
+ if (!_solutionContainer.TryGetRefillableSolution(args.Target.Value,
+ out var targetSolutionComponent,
+ out var targetSolution))
+ return;
+
+
+ // If there's no cum to cum you cant cum, okay?
+ if (expellableSolution.Volume <= 0)
+ {
+ _popup.PopupPredicted(Loc.GetString(expellableComponent.PopupEmpty),args.Args.User,args.Args.User);
+ return;
+ }
+
+ // Get available volume in target solution
+ var targetAvailableVolume = targetSolution.MaxVolume - targetSolution.Volume;
+
+ // If theres no room just silently return
+ if (targetAvailableVolume <= 0)
+ return;
+
+ // Get amount to add, attempts to add the largest amount with the maximum set from production type
+ var amountToAdd =
+ FixedPoint2.Clamp(targetAvailableVolume, FixedPoint2.Zero, expellableComponent.MaximumExpulsion);
+
+ var split = expellableSolution.SplitSolution(amountToAdd);
+ var quantity = _solutionContainer.AddSolution(targetSolutionComponent.Value, split);
+
+ _popup.PopupPredicted(
+ Loc.GetString(
+ expellableComponent.PopupSuccess,
+ ("amount", quantity),
+ ("target", Identity.Entity(args.Target.Value, EntityManager))),
+ args.Args.User,
+ args.Args.User,
+ PopupType.Medium);
+
+ args.Handled = true;
+ }
+}
diff --git a/Content.Shared/_DEN/SolutionExpulsion/Events/SolutionExpulsionEvents.cs b/Content.Shared/_DEN/SolutionExpulsion/Events/SolutionExpulsionEvents.cs
new file mode 100644
index 0000000000..ddecf0537e
--- /dev/null
+++ b/Content.Shared/_DEN/SolutionExpulsion/Events/SolutionExpulsionEvents.cs
@@ -0,0 +1,54 @@
+using Content.Shared._DEN.SolutionExpulsion.Components;
+using Content.Shared._DEN.SolutionExpulsion.EntitySystems;
+using Content.Shared.DoAfter;
+using Robust.Shared.Prototypes;
+using Robust.Shared.Serialization;
+
+namespace Content.Shared._DEN.SolutionExpulsion.Events;
+
+public sealed partial class SolutionExpulsionEvents
+{
+ ///
+ /// When this event is called, an expellable solution is added to the entity it's called on.
+ /// Do not call this directly, and instead use
+ ///
+ /// Expellable solution prototype to add.
+ [Serializable, NetSerializable]
+ public sealed class SolutionExpellableAdded(EntProtoId expellableSolutionPrototype) : EntityEventArgs
+ {
+ public EntProtoId ExpellableSolutionPrototype { get; } = expellableSolutionPrototype;
+ }
+
+ ///
+ /// When this event is called, an expellable solution is removed from the entity it's called on.
+ /// Do not call this directly, and instead use
+ ///
+ /// Expellable solution prototype to remove.
+ [Serializable, NetSerializable]
+ public sealed class SolutionExpellableRemoved(EntProtoId expellableSolutionPrototype) : EntityEventArgs
+ {
+ public EntProtoId ExpellableSolutionPrototype { get; } = expellableSolutionPrototype;
+ }
+
+ ///
+ /// Classic doafter event, called when attempting to fill a solution container with an expellable solution.
+ ///
+ [Serializable, NetSerializable]
+ public sealed partial class SolutionExpulsionFillEvent : DoAfterEvent
+ {
+ ///
+ /// Solution entity to fill with.
+ ///
+ public NetEntity ExpellableSolution;
+
+ public SolutionExpulsionFillEvent(NetEntity expellableSolution)
+ {
+ ExpellableSolution = expellableSolution;
+ }
+
+ public override DoAfterEvent Clone()
+ {
+ return this;
+ }
+ }
+}
diff --git a/Content.Shared/_DEN/Traits/TraitFunctions/TraitFunctions.SolutionExpulsion.cs b/Content.Shared/_DEN/Traits/TraitFunctions/TraitFunctions.SolutionExpulsion.cs
new file mode 100644
index 0000000000..dd71824493
--- /dev/null
+++ b/Content.Shared/_DEN/Traits/TraitFunctions/TraitFunctions.SolutionExpulsion.cs
@@ -0,0 +1,43 @@
+using Content.Shared._DEN.SolutionExpulsion.EntitySystems;
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared._DEN.Traits.TraitFunctions;
+
+public sealed partial class AddSolutionExpulsionTrait : ITraitFunction
+{
+ ///
+ /// Solution entities types this trait adds to the entity.
+ ///
+ [DataField(required: true)] public List SolutionExpellableEntities { get; private set; } = [];
+
+ [ViewVariables] public List? AddedComponents = null;
+
+ public void OnTraitAdded(EntityUid owner, EntityManager entityManager)
+ {
+
+ var prototypeManager = IoCManager.Resolve();
+ var solutionExpulsion = entityManager.System();
+
+ foreach (var solutionToExpel in SolutionExpellableEntities)
+ {
+ if (!prototypeManager.TryIndex(solutionToExpel, out var prototype))
+ continue;
+
+ solutionExpulsion.AddExpellableSolution(owner, prototype);
+ }
+ }
+
+ public void OnTraitRemoved(EntityUid owner, EntityManager entityManager)
+ {
+ var prototypeManager = IoCManager.Resolve();
+ var solutionExpulsion = entityManager.System();
+
+ foreach (var solutionToExpel in SolutionExpellableEntities)
+ {
+ if (!prototypeManager.TryIndex(solutionToExpel, out var prototype))
+ continue;
+
+ solutionExpulsion.RemoveExpellableSolution(owner, prototype);
+ }
+ }
+}
diff --git a/Resources/Locale/en-US/_DEN/guidebook/guides.ftl b/Resources/Locale/en-US/_DEN/guidebook/guides.ftl
new file mode 100644
index 0000000000..96cd47026b
--- /dev/null
+++ b/Resources/Locale/en-US/_DEN/guidebook/guides.ftl
@@ -0,0 +1,2 @@
+# Chemical Tabs
+guide-entry-lewd = Lewd
diff --git a/Resources/Locale/en-US/_DEN/reagents/meta/chemicals.ftl b/Resources/Locale/en-US/_DEN/reagents/meta/chemicals.ftl
new file mode 100644
index 0000000000..1ddad48b08
--- /dev/null
+++ b/Resources/Locale/en-US/_DEN/reagents/meta/chemicals.ftl
@@ -0,0 +1,5 @@
+reagent-name-glycerol = glycerol
+reagent-desc-glycerol = A sweet tasting, colorless, and oderless hydrating chemical.
+
+reagent-name-hydro-cellulose = hydroxyethyl cellulose
+reagent-desc-hydro-cellulose = A commonly used thickening agent, often found in foods, lubes, and cosmetics.
diff --git a/Resources/Locale/en-US/_DEN/reagents/meta/lewd.ftl b/Resources/Locale/en-US/_DEN/reagents/meta/lewd.ftl
new file mode 100644
index 0000000000..828445c3d5
--- /dev/null
+++ b/Resources/Locale/en-US/_DEN/reagents/meta/lewd.ftl
@@ -0,0 +1,11 @@
+reagent-name-cum = cum
+reagent-desc-cum = A sticky cloudy-white liquid.
+
+reagent-name-nat-lube = natural lubricant
+reagent-desc-nat-lube = A slippery clear liquid.
+
+reagent-name-synth-cum = synthetic cum
+reagent-desc-synth-cum = A flavorless lubricant made to look like cum.
+
+reagent-name-synth-lube = synthetic lube
+reagent-desc-synth-lube = Flavorless lubricant, made with maximum slipperyness in mind! Silicon free.
diff --git a/Resources/Locale/en-US/_DEN/traits/categories.ftl b/Resources/Locale/en-US/_DEN/traits/categories.ftl
index ea2c28cb06..59fc07d97a 100644
--- a/Resources/Locale/en-US/_DEN/traits/categories.ftl
+++ b/Resources/Locale/en-US/_DEN/traits/categories.ftl
@@ -1,2 +1,3 @@
trait-category-species-morphs = Morphotypes
trait-category-species-specific = Species-specific
+trait-category-lewd = Lewd
diff --git a/Resources/Locale/en-US/_DEN/traits/lewd.ftl b/Resources/Locale/en-US/_DEN/traits/lewd.ftl
new file mode 100644
index 0000000000..54263bd518
--- /dev/null
+++ b/Resources/Locale/en-US/_DEN/traits/lewd.ftl
@@ -0,0 +1,34 @@
+trait-cum-producer-name = Cum Producer
+trait-cum-producer-desc = This trait allows you to fill containers (such as beakers) with cum, to suit your roleplay needs.
+
+ Keep server rules in mind and ABSOLUTELY NEVER expose people to lewd reagents without their explicit consent.
+ This includes, for example, leaving it in public places for others to see, or tricking people into consuming it.
+ You WILL be banned for breaking this rule.
+
+trait-synth-cum-producer-name = Synthetic Cum Producer
+trait-synth-cum-producer-desc = This trait allows you to fill containers (such as beakers) with synthetic cum, to suit your roleplay needs.
+
+ Keep server rules in mind and ABSOLUTELY NEVER expose people to lewd reagents without their explicit consent.
+ This includes, for example, leaving it in public places for others to see, or tricking people into consuming it.
+ You WILL be banned for breaking this rule.
+
+trait-squirt-producer-name = Natural Lubricant Producer
+trait-squirt-producer-desc = This trait allows you to fill containers (such as beakers) with your natural lubricant, to suit your roleplay needs.
+
+ Keep server rules in mind and ABSOLUTELY NEVER expose people to lewd reagents without their explicit consent.
+ This includes, for example, leaving it in public places for others to see, or tricking people into consuming it.
+ You WILL be banned for breaking this rule.
+
+trait-synth-lube-producer-name = Synthetic Lube Producer
+trait-synth-lube-producer-desc = This trait allows you to fill containers (such as beakers) with synthetic lube, to suit your roleplay needs.
+
+ Keep server rules in mind and ABSOLUTELY NEVER expose people to lewd reagents without their explicit consent.
+ This includes, for example, leaving it in public places for others to see, or tricking people into consuming it.
+ You WILL be banned for breaking this rule.
+
+trait-milk-producer-name = Breast Milk Producer
+trait-milk-producer-desc = This trait allows you to fill containers (such as beakers) with milk, to suit your roleplay needs.
+
+ Keep server rules in mind and ABSOLUTELY NEVER expose people to lewd reagents without their explicit consent.
+ This includes, for example, leaving it in public places for others to see, or tricking people into consuming it.
+ You WILL be banned for breaking this rule.
diff --git a/Resources/Locale/en-US/_DEN/traits/quirks.ftl b/Resources/Locale/en-US/_DEN/traits/quirks.ftl
new file mode 100644
index 0000000000..c585ddeb3d
--- /dev/null
+++ b/Resources/Locale/en-US/_DEN/traits/quirks.ftl
@@ -0,0 +1,2 @@
+trait-honey-producer-name = Honey Stomach
+trait-honey-producer-desc = Your abdomen contains an extra stomach that processes nutrients into honey.
diff --git a/Resources/Locale/en-US/_DEN/verbs/solution-explusion-verbs.ftl b/Resources/Locale/en-US/_DEN/verbs/solution-explusion-verbs.ftl
new file mode 100644
index 0000000000..a3b2006eac
--- /dev/null
+++ b/Resources/Locale/en-US/_DEN/verbs/solution-explusion-verbs.ftl
@@ -0,0 +1,25 @@
+verb-categories-fill = Fill with
+
+cum-verb-text = Cum
+cum-verb-dry = Your cum tank is empty.
+cum-verb-success = You fill {THE($target)} with {$amount}u of cum from your cock.
+
+milk-verb-text = Milk
+milk-verb-dry = Your breasts are empty.
+milk-verb-success = You fill {THE($target)} with {$amount}u of milk from your breasts.
+
+squirt-verb-text = Squirt
+squirt-verb-dry = You're too dry.
+squirt-verb-success = You fill {THE($target)} with {$amount}u of natural lubricant.
+
+synth-verb-text = Synthetic Lube
+synth-lube-verb-dry = Your lube tube is empty.
+synth-lube-verb-success = You dispense {$amount}u of synthetic lubricant into {THE($target)}.
+
+synth-verb-text = Synthetic Cum
+synth-cum-verb-dry = Your synthetic balls are empty.
+synth-cum-verb-success = You dispense {$amount}u of synthetic cum into {THE($target)}.
+
+honey-verb-text = Honey
+honey-verb-dry = Your honey stomach is empty.
+honey-verb-success = You fill {THE($target)} with {$amount}u of honey from your extra stomach.
diff --git a/Resources/Prototypes/Guidebook/chemicals.yml b/Resources/Prototypes/Guidebook/chemicals.yml
index 730d7b3045..7313c192a9 100644
--- a/Resources/Prototypes/Guidebook/chemicals.yml
+++ b/Resources/Prototypes/Guidebook/chemicals.yml
@@ -12,6 +12,7 @@
- Botanical
- Biological
- Special
+ - Lewd # DEN
- Others
filterEnabled: True
diff --git a/Resources/Prototypes/_DEN/Entities/ExpellableSolutions/lewd.yml b/Resources/Prototypes/_DEN/Entities/ExpellableSolutions/lewd.yml
new file mode 100644
index 0000000000..9a80ea63ce
--- /dev/null
+++ b/Resources/Prototypes/_DEN/Entities/ExpellableSolutions/lewd.yml
@@ -0,0 +1,108 @@
+- type: entity
+ parent: [Solution]
+ id: SolutionTesticles # Cum
+ categories: [ HideSpawnMenu ]
+ components:
+ - type: Solution
+ solution:
+ maxVol: 30
+ reagents:
+ - ReagentId: Cum
+ Quantity: 30
+ - type: SolutionRegeneration
+ generated:
+ reagents:
+ - ReagentId: Cum
+ Quantity: 0.2 # One unit every 5 seconds.
+ - type: SolutionExpellable
+
+- type: entity
+ parent: [Solution]
+ id: SolutionSyntheticTesticles # Synth Cum
+ categories: [ HideSpawnMenu ]
+ components:
+ - type: Solution
+ solution:
+ maxVol: 50
+ reagents:
+ - ReagentId: SyntheticCum
+ Quantity: 50
+ - type: SolutionRegeneration
+ generated:
+ reagents:
+ - ReagentId: SyntheticCum
+ Quantity: 0.4 # One unit every 2.5 seconds.
+ - type: SolutionExpellable
+ verbText: synth-cum-verb-text
+ popupEmpty: synth-cum-verb-dry
+ popupSuccess: synth-cum-verb-success
+
+- type: entity
+ parent: [Solution]
+ id: SolutionBreasts # Milk
+ categories: [ HideSpawnMenu ]
+ components:
+ - type: Solution
+ solution:
+ maxVol: 50
+ reagents:
+ - ReagentId: Milk
+ Quantity: 50
+ - type: SolutionRegeneration
+ generated:
+ reagents:
+ - ReagentId: Milk
+ Quantity: 0.2 # One unit every 5 seconds.
+ - type: SolutionExpellable
+ defaultSolutionName: breasts
+ maximumExpulsion: 5
+ verbText: milk-verb-text
+ popupEmpty: milk-verb-dry
+ popupSuccess: milk-verb-success
+ doAfterDuration: 1
+
+- type: entity
+ parent: [Solution]
+ id: SolutionSquirt # Technically its from like, the bladder and the skene's glands??? but whatever. it's natural lube
+ categories: [ HideSpawnMenu ]
+ components:
+ - type: Solution
+ solution:
+ maxVol: 15
+ reagents:
+ - ReagentId: NaturalLubricant
+ Quantity: 15
+ - type: SolutionRegeneration
+ generated:
+ reagents:
+ - ReagentId: NaturalLubricant
+ Quantity: 0.1 # One unit every 10 seconds.
+ - type: SolutionExpellable
+ defaultSolutionName: vagina #?
+ maximumExpulsion: 5
+ verbText: squirt-verb-text
+ popupEmpty: squirt-verb-dry
+ popupSuccess: squirt-verb-success
+
+- type: entity
+ parent: [Solution]
+ id: SolutionSyntheticLube # Synthetic Lube
+ categories: [ HideSpawnMenu ]
+ components:
+ - type: Solution
+ solution:
+ maxVol: 70
+ reagents:
+ - ReagentId: NaturalLubricant
+ Quantity: 70
+ - type: SolutionRegeneration
+ generated:
+ reagents:
+ - ReagentId: NaturalLubricant
+ Quantity: 0.4 # One unit every 2.5 seconds.
+ - type: SolutionExpellable
+ defaultSolutionName: vagina #?
+ maximumExpulsion: 15
+ verbText: synth-lube-verb-text
+ popupEmpty: synth-lube-verb-dry
+ popupSuccess: synth-lube-verb-success
diff --git a/Resources/Prototypes/_DEN/EntityTraits/categories.yml b/Resources/Prototypes/_DEN/EntityTraits/categories.yml
index 723ce83024..2f3e085d77 100644
--- a/Resources/Prototypes/_DEN/EntityTraits/categories.yml
+++ b/Resources/Prototypes/_DEN/EntityTraits/categories.yml
@@ -1,3 +1,4 @@
+# Species
- type: traitCategory
id: SpeciesMorphs
name: trait-category-species-morphs
@@ -8,3 +9,10 @@
id: SpeciesSpecific
priority: -10
name: trait-category-species-specific
+
+# Misc
+- type: traitCategory
+ id: Lewd
+ name: trait-category-lewd
+ priority: 20
+ maxTraitPoints: 3
diff --git a/Resources/Prototypes/_DEN/EntityTraits/lewd.yml b/Resources/Prototypes/_DEN/EntityTraits/lewd.yml
new file mode 100644
index 0000000000..d53552f5a6
--- /dev/null
+++ b/Resources/Prototypes/_DEN/EntityTraits/lewd.yml
@@ -0,0 +1,56 @@
+# Reagent Production Traits
+
+- type: entityTrait
+ id: CumProducer
+ name: trait-cum-producer-name
+ description: trait-cum-producer-desc
+ category: Lewd
+ cost: 1
+ functions:
+ - !type:AddSolutionExpulsionTrait
+ solutionExpellableEntities:
+ - SolutionTesticles
+
+- type: entityTrait
+ id: SyntheticCumProducer
+ name: trait-synth-cum-producer-name
+ description: trait-synth-cum-producer-desc
+ category: Lewd
+ cost: 1
+ functions:
+ - !type:AddSolutionExpulsionTrait
+ solutionExpellableEntities:
+ - SolutionSyntheticTesticles
+
+- type: entityTrait
+ id: SquirtProducer
+ name: trait-squirt-producer-name
+ description: trait-squirt-producer-desc
+ category: Lewd
+ cost: 1
+ functions:
+ - !type:AddSolutionExpulsionTrait
+ solutionExpellableEntities:
+ - SolutionSquirt
+
+- type: entityTrait
+ id: SyntheticLubeProducer
+ name: trait-synth-lube-producer-name
+ description: trait-synth-lube-producer-desc
+ category: Lewd
+ cost: 1
+ functions:
+ - !type:AddSolutionExpulsionTrait
+ solutionExpellableEntities:
+ - SolutionSyntheticLube
+
+- type: entityTrait
+ id: MilkProducer
+ name: trait-milk-producer-name
+ description: trait-milk-producer-desc
+ category: Lewd
+ cost: 1
+ functions:
+ - !type:AddSolutionExpulsionTrait
+ solutionExpellableEntities:
+ - SolutionBreasts
diff --git a/Resources/Prototypes/_DEN/Guidebook/chemicals.yml b/Resources/Prototypes/_DEN/Guidebook/chemicals.yml
new file mode 100644
index 0000000000..7caf5c713e
--- /dev/null
+++ b/Resources/Prototypes/_DEN/Guidebook/chemicals.yml
@@ -0,0 +1,5 @@
+- type: guideEntry
+ id: Lewd
+ name: guide-entry-lewd
+ text: "/ServerInfo/Guidebook/_DEN/ChemicalTabs/Lewd.xml"
+ filterEnabled: True
diff --git a/Resources/Prototypes/_DEN/Reagents/chemicals.yml b/Resources/Prototypes/_DEN/Reagents/chemicals.yml
new file mode 100644
index 0000000000..112025cc18
--- /dev/null
+++ b/Resources/Prototypes/_DEN/Reagents/chemicals.yml
@@ -0,0 +1,24 @@
+- type: reagent
+ id: Glycerol
+ group: Foods
+ name: reagent-name-glycerol
+ desc: reagent-desc-glycerol
+ color: "#E9EAF2"
+ flavor: sweet
+ viscosity: 0.35
+ physicalDesc: reagent-physical-desc-thick
+ metabolisms:
+ Digestion:
+ effects:
+ - !type:SatiateThirst
+ factor: 6
+
+- type: reagent
+ id: HydroxyethylCellulose
+ color: "#E9EAF2"
+ group: Foods
+ name: reagent-name-hydro-cellulose
+ desc: reagent-desc-hydro-cellulose
+ flavor: nothing
+ viscosity: 0.35
+ physicalDesc: reagent-physical-desc-thick
diff --git a/Resources/Prototypes/_DEN/Reagents/lewd.yml b/Resources/Prototypes/_DEN/Reagents/lewd.yml
new file mode 100644
index 0000000000..311eddd7f3
--- /dev/null
+++ b/Resources/Prototypes/_DEN/Reagents/lewd.yml
@@ -0,0 +1,66 @@
+- type: reagent
+ id: Cum
+ name: reagent-name-cum
+ group: Lewd
+ desc: reagent-desc-cum
+ physicalDesc: reagent-physical-desc-sticky
+ flavor: salty
+ color: "#ffffff"
+ viscosity: 0.35
+ recognizable: true
+ evaporationSpeed: 0.3
+ metabolisms:
+ Digestion:
+ effects:
+ - !type:SatiateThirst
+ factor: 0.2
+ - !type:SatiateHunger
+ factor: 1
+ footstepSound:
+ collection: FootstepSticky
+ params:
+ volume: 6
+
+- type: reagent
+ id: SyntheticCum
+ parent: Cum
+ name: reagent-name-synth-cum
+ desc: reagent-desc-synth-cum
+ flavor: nothing
+ metabolisms:
+ Digestion:
+ effects:
+ - !type:SatiateThirst
+ factor: 0.1
+
+- type: reagent
+ id: NaturalLubricant
+ name: reagent-name-nat-lube
+ desc: reagent-desc-nat-lube
+ parent: SpaceLube
+ group: Lewd
+ physicalDesc: reagent-physical-desc-shiny
+ flavor: funny
+ color: "#d6d6d6"
+ evaporationSpeed: 0.3
+ metabolisms:
+ Digestion:
+ effects:
+ - !type:SatiateThirst
+ factor: 0.3
+ footstepSound:
+ collection: FootstepSticky
+ params:
+ volume: 4
+
+- type: reagent
+ id: SyntheticLubricant
+ parent: NaturalLubricant
+ name: reagent-name-synth-lube
+ desc: reagent-desc-synth-lube
+ flavor: nothing
+ metabolisms:
+ Digestion:
+ effects:
+ - !type:SatiateThirst
+ factor: 0.1
diff --git a/Resources/Prototypes/_DEN/Recipes/Reactions/chemicals.yml b/Resources/Prototypes/_DEN/Recipes/Reactions/chemicals.yml
new file mode 100644
index 0000000000..5495fa89cb
--- /dev/null
+++ b/Resources/Prototypes/_DEN/Recipes/Reactions/chemicals.yml
@@ -0,0 +1,22 @@
+# This is NOT accurate.
+- type: reaction
+ id: Glycerol
+ minTemp: 373.15
+ reactants:
+ Water:
+ amount: 3
+ Fat:
+ amount: 1
+ products:
+ Glycerol: 4
+
+- type: reaction
+ id: HydroxyethylCellulose
+ reactants:
+ Cellulose:
+ amount: 1
+ SodiumHydroxide:
+ amount: 1
+ products:
+ HydroxyethylCellulose: 1
+ SodiumHydroxide: 1
diff --git a/Resources/Prototypes/_DEN/Recipes/Reactions/lewd.yml b/Resources/Prototypes/_DEN/Recipes/Reactions/lewd.yml
new file mode 100644
index 0000000000..9dfc5919bc
--- /dev/null
+++ b/Resources/Prototypes/_DEN/Recipes/Reactions/lewd.yml
@@ -0,0 +1,22 @@
+- type: reaction
+ id: SyntheticLubricant
+ minTemp: 398.15
+ requiredMixerCategories:
+ - Stir
+ reactants:
+ Water:
+ amount: 2
+ Glycerol:
+ amount: 1
+ products:
+ SyntheticLubricant: 3
+
+- type: reaction
+ id: SyntheticCum
+ reactants:
+ SyntheticLubricant:
+ amount: 3
+ SodiumCarbonate:
+ amount: 1
+ products:
+ SyntheticCum: 4
diff --git a/Resources/ServerInfo/Guidebook/_DEN/ChemicalTabs/Lewd.xml b/Resources/ServerInfo/Guidebook/_DEN/ChemicalTabs/Lewd.xml
new file mode 100644
index 0000000000..aeaaf2f135
--- /dev/null
+++ b/Resources/ServerInfo/Guidebook/_DEN/ChemicalTabs/Lewd.xml
@@ -0,0 +1,5 @@
+
+# Lewd
+The reagents listed in this category includes bodily fluids and libido enhancing stimulants.
+
+
diff --git a/Resources/Textures/_DEN/Interface/VerbIcons/ATTRIBUTION.txt b/Resources/Textures/_DEN/Interface/VerbIcons/ATTRIBUTION.txt
new file mode 100644
index 0000000000..8d0a923ba2
--- /dev/null
+++ b/Resources/Textures/_DEN/Interface/VerbIcons/ATTRIBUTION.txt
@@ -0,0 +1,3 @@
+All icons are public domain.
+
+lewd.svg by portfiend (GitHub)
diff --git a/Resources/Textures/_DEN/Interface/VerbIcons/lewd.svg b/Resources/Textures/_DEN/Interface/VerbIcons/lewd.svg
new file mode 100644
index 0000000000..1baa326034
--- /dev/null
+++ b/Resources/Textures/_DEN/Interface/VerbIcons/lewd.svg
@@ -0,0 +1,65 @@
+
+
+
+
diff --git a/Resources/Textures/_DEN/Interface/VerbIcons/lewd.svg.192dpi.png b/Resources/Textures/_DEN/Interface/VerbIcons/lewd.svg.192dpi.png
new file mode 100644
index 0000000000..2f1ab44a29
Binary files /dev/null and b/Resources/Textures/_DEN/Interface/VerbIcons/lewd.svg.192dpi.png differ
diff --git a/Resources/Textures/_DEN/Interface/VerbIcons/lewd.svg.192dpi.png.yml b/Resources/Textures/_DEN/Interface/VerbIcons/lewd.svg.192dpi.png.yml
new file mode 100644
index 0000000000..5c43e23305
--- /dev/null
+++ b/Resources/Textures/_DEN/Interface/VerbIcons/lewd.svg.192dpi.png.yml
@@ -0,0 +1,2 @@
+sample:
+ filter: true