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 @@ + + + +18+ 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