Skip to content

Commit

Permalink
Merge branch 'Fansana:master' into friend-shaped
Browse files Browse the repository at this point in the history
  • Loading branch information
fenndragon authored Aug 23, 2024
2 parents cb08895 + f6dc16c commit cf1bde0
Show file tree
Hide file tree
Showing 31 changed files with 927 additions and 109 deletions.
4 changes: 4 additions & 0 deletions Content.Client/Physics/JointVisualsOverlay.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
using System.Numerics;
using Content.Shared.Physics;
using Robust.Client.GameObjects;
using Robust.Client.Graphics;
using Robust.Shared.Enums;
using Robust.Shared.Map;
using Robust.Shared.Physics;
using Robust.Shared.Physics.Dynamics.Joints;

Expand All @@ -27,6 +29,8 @@ protected override void Draw(in OverlayDrawArgs args)
{
_drawn.Clear();
var worldHandle = args.WorldHandle;
// Floofstation: fix incorrect drawing box location due to incorrect coordinate system
worldHandle.SetTransform(Vector2.Zero, Angle.Zero);

var spriteSystem = _entManager.System<SpriteSystem>();
var xformSystem = _entManager.System<SharedTransformSystem>();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
using Content.Shared.FixedPoint;
using Content.Shared.Chemistry.Components;
using Content.Shared.Chemistry.Reagent;
using Content.Shared.FloofStation.Traits;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
using Robust.Shared.GameStates;

namespace Content.Server.FloofStation.Traits;

[RegisterComponent, Access(typeof(LewdTraitSystem))]
public sealed partial class SquirtProducerComponent : Component
{
[DataField("solutionname")]
public string SolutionName = "vagina";

[DataField]
public ProtoId<ReagentPrototype> ReagentId = "NaturalLubricant";

[DataField]
public FixedPoint2 MaxVolume = FixedPoint2.New(25);

[DataField]
public Entity<SolutionComponent>? Solution = null;

[DataField]
public FixedPoint2 QuantityPerUpdate = 5;

[DataField]
public float HungerUsage = 10f;

[DataField]
public TimeSpan GrowthDelay = TimeSpan.FromSeconds(10);

[DataField(customTypeSerializer: typeof(TimeOffsetSerializer))]
public TimeSpan NextGrowth = TimeSpan.FromSeconds(0);
}
161 changes: 85 additions & 76 deletions Content.Server/FloofStation/Traits/LewdTraitSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,17 +31,17 @@ public override void Initialize()
//Initializers
SubscribeLocalEvent<CumProducerComponent, ComponentStartup>(OnComponentInitCum);
SubscribeLocalEvent<MilkProducerComponent, ComponentStartup>(OnComponentInitMilk);
//SubscribeLocalEvent<SquirtProducerComponent, ComponentStartup>(OnComponentInitSquirt); //Unused-Trait is WIP
SubscribeLocalEvent<SquirtProducerComponent, ComponentStartup>(OnComponentInitSquirt);

//Verbs
SubscribeLocalEvent<CumProducerComponent, GetVerbsEvent<InnateVerb>>(AddCumVerb);
SubscribeLocalEvent<MilkProducerComponent, GetVerbsEvent<InnateVerb>>(AddMilkVerb);
//SubscribeLocalEvent<SquirtProducerComponent, GetVerbsEvent<InnateVerb>>(AddSquirtVerb); //Unused-Trait is WIP
SubscribeLocalEvent<SquirtProducerComponent, GetVerbsEvent<InnateVerb>>(AddSquirtVerb);

//Events
SubscribeLocalEvent<CumProducerComponent, CummingDoAfterEvent>(OnDoAfterCum);
SubscribeLocalEvent<MilkProducerComponent, MilkingDoAfterEvent>(OnDoAfterMilk);
//SubscribeLocalEvent<SquirtProducerComponent, SquirtingDoAfterEvent>(OnDoAfterSquirt); //Unused-Trait is WIP
SubscribeLocalEvent<SquirtProducerComponent, SquirtingDoAfterEvent>(OnDoAfterSquirt);
}

#region event handling
Expand All @@ -61,13 +61,13 @@ private void OnComponentInitMilk(Entity<MilkProducerComponent> entity, ref Compo
solutionMilk.AddReagent(entity.Comp.ReagentId, entity.Comp.MaxVolume - solutionMilk.Volume);
}

//private void OnComponentInitSquirt(Entity<SquirtProducerComponent> entity, ref ComponentStartup args) //Unused-Trait is WIP
//{
// var solutionSquirt = _solutionContainer.EnsureSolution(entity.Owner, entity.Comp.SolutionName);
// solutionSquirt.MaxVolume = entity.Comp.MaxVolume;
private void OnComponentInitSquirt(Entity<SquirtProducerComponent> entity, ref ComponentStartup args)
{
var solutionSquirt = _solutionContainer.EnsureSolution(entity.Owner, entity.Comp.SolutionName);
solutionSquirt.MaxVolume = entity.Comp.MaxVolume;

// solutionSquirt.AddReagent(entity.Comp.ReagentId, entity.Comp.MaxVolume - solutionSquirt.Volume);
//}
solutionSquirt.AddReagent(entity.Comp.ReagentId, entity.Comp.MaxVolume - solutionSquirt.Volume);
}

public void AddCumVerb(Entity<CumProducerComponent> entity, ref GetVerbsEvent<InnateVerb> args)
{
Expand Down Expand Up @@ -113,26 +113,26 @@ public void AddMilkVerb(Entity<MilkProducerComponent> entity, ref GetVerbsEvent<
args.Verbs.Add(verbMilk);
}

//public void AddSquirtVerb(Entity<SquirtProducerComponent> entity, ref GetVerbsEvent<InnateVerb> args) //Unused-Trait is WIP
//{
// if (args.Using == null ||
// !args.CanInteract ||
// !EntityManager.HasComponent<RefillableSolutionComponent>(args.Using.Value)) //see if removing this part lets you milk on the ground.
// return;
public void AddSquirtVerb(Entity<SquirtProducerComponent> entity, ref GetVerbsEvent<InnateVerb> args)
{
if (args.Using == null ||
!args.CanInteract ||
!EntityManager.HasComponent<RefillableSolutionComponent>(args.Using.Value)) //see if removing this part lets you milk on the ground.
return;

// _solutionContainer.EnsureSolution(entity.Owner, entity.Comp.SolutionName);
_solutionContainer.EnsureSolution(entity.Owner, entity.Comp.SolutionName);

// var user = args.User;
// var used = args.Using.Value;
var user = args.User;
var used = args.Using.Value;

// InnateVerb verbSquirt = new()
// {
// Act = () => AttemptSquirt(entity, user, used),
// Text = Loc.GetString($"squirt-verb-get-text"),
// Priority = 1
// };
// args.Verbs.Add(verbSquirt);
//}
InnateVerb verbSquirt = new()
{
Act = () => AttemptSquirt(entity, user, used),
Text = Loc.GetString($"squirt-verb-get-text"),
Priority = 1
};
args.Verbs.Add(verbSquirt);
}

private void OnDoAfterCum(Entity<CumProducerComponent> entity, ref CummingDoAfterEvent args)
{
Expand Down Expand Up @@ -188,32 +188,32 @@ private void OnDoAfterMilk(Entity<MilkProducerComponent> entity, ref MilkingDoAf
_popupSystem.PopupEntity(Loc.GetString("milk-verb-success", ("amount", quantity), ("target", Identity.Entity(args.Args.Used.Value, EntityManager))), entity.Owner, args.Args.User, PopupType.Medium);
}

//private void OnDoAfterSquirt(Entity<SquirtProducerComponent> entity, ref SquirtingDoAfterEvent args) //Unused-Trait is WIP
//{
// if (args.Cancelled || args.Handled || args.Args.Used == null)
// return;
private void OnDoAfterSquirt(Entity<SquirtProducerComponent> entity, ref SquirtingDoAfterEvent args)
{
if (args.Cancelled || args.Handled || args.Args.Used == null)
return;

// if (!_solutionContainer.ResolveSolution(entity.Owner, entity.Comp.SolutionName, ref entity.Comp.Solution, out var solution))
// return;
if (!_solutionContainer.ResolveSolution(entity.Owner, entity.Comp.SolutionName, ref entity.Comp.Solution, out var solution))
return;

// if (!_solutionContainer.TryGetRefillableSolution(args.Args.Used.Value, out var targetSoln, out var targetSolution))
// return;
if (!_solutionContainer.TryGetRefillableSolution(args.Args.Used.Value, out var targetSoln, out var targetSolution))
return;

// args.Handled = true;
// var quantity = solution.Volume;
// if (quantity == 0)
// {
// _popupSystem.PopupEntity(Loc.GetString("squirt-verb-dry"), entity.Owner, args.Args.User);
// return;
// }
args.Handled = true;
var quantity = solution.Volume;
if (quantity == 0)
{
_popupSystem.PopupEntity(Loc.GetString("squirt-verb-dry"), entity.Owner, args.Args.User);
return;
}

// if (quantity > targetSolution.AvailableVolume)
// quantity = targetSolution.AvailableVolume;
if (quantity > targetSolution.AvailableVolume)
quantity = targetSolution.AvailableVolume;

// var split = _solutionContainer.SplitSolution(entity.Comp.Solution.Value, quantity);
// _solutionContainer.TryAddSolution(targetSoln.Value, split);
// _popupSystem.PopupEntity(Loc.GetString("squirt-verb-success", ("amount", quantity), ("target", Identity.Entity(args.Args.Used.Value, EntityManager))), entity.Owner, args.Args.User, PopupType.Medium);
//}
var split = _solutionContainer.SplitSolution(entity.Comp.Solution.Value, quantity);
_solutionContainer.TryAddSolution(targetSoln.Value, split);
_popupSystem.PopupEntity(Loc.GetString("squirt-verb-success", ("amount", quantity), ("target", Identity.Entity(args.Args.Used.Value, EntityManager))), entity.Owner, args.Args.User, PopupType.Medium);
}
#endregion

#region utilities
Expand Down Expand Up @@ -249,27 +249,28 @@ private void AttemptMilk(Entity<MilkProducerComponent> lewd, EntityUid userUid,
_doAfterSystem.TryStartDoAfter(doargs);
}

//private void AttemptSquirt(Entity<SquirtProducerComponent> lewd, EntityUid userUid, EntityUid containerUid) //Unused-Trait is WIP
//{
// if (!HasComp<SquirtProducerComponent>(userUid))
// return;
private void AttemptSquirt(Entity<SquirtProducerComponent> lewd, EntityUid userUid, EntityUid containerUid)
{
if (!HasComp<SquirtProducerComponent>(userUid))
return;

// var doargs = new DoAfterArgs(EntityManager, userUid, 5, new SquirtingDoAfterEvent(), lewd, lewd, used: containerUid)
// {
// BreakOnUserMove = true,
// BreakOnDamage = true,
// BreakOnTargetMove = true,
// MovementThreshold = 1.0f,
// };
var doargs = new DoAfterArgs(EntityManager, userUid, 5, new SquirtingDoAfterEvent(), lewd, lewd, used: containerUid)
{
BreakOnUserMove = true,
BreakOnDamage = true,
BreakOnTargetMove = true,
MovementThreshold = 1.0f,
};

// _doAfterSystem.TryStartDoAfter(doargs);
//}
_doAfterSystem.TryStartDoAfter(doargs);
}

public override void Update(float frameTime)
{
base.Update(frameTime);
var queryCum = EntityQueryEnumerator<CumProducerComponent>(); //SquirtProducerComponent -unused ,
var queryCum = EntityQueryEnumerator<CumProducerComponent>();
var queryMilk = EntityQueryEnumerator<MilkProducerComponent>();
var querySquirt = EntityQueryEnumerator<SquirtProducerComponent>();
var now = _timing.CurTime;

while (queryCum.MoveNext(out var uid, out var containerCum))
Expand Down Expand Up @@ -320,21 +321,29 @@ public override void Update(float frameTime)
_solutionContainer.TryAddReagent(containerMilk.Solution.Value, containerMilk.ReagentId, containerMilk.QuantityPerUpdate, out _);
}

//if (!(now < containerSquirt.NextGrowth)) //Unused-Trait is WIP
//{
// containerSquirt.NextGrowth = now + containerSquirt.GrowthDelay;

//
// if (EntityManager.TryGetComponent(uid, out HungerComponent? hunger))
// {
//
// if (!(_hunger.GetHungerThreshold(hunger) < HungerThreshold.Okay))
// _hunger.ModifyHunger(uid, -containerSquirt.HungerUsage, hunger);
// }

// if (_solutionContainer.ResolveSolution(uid, containerSquirt.SolutionName, ref containerSquirt.Solution))
// _solutionContainer.TryAddReagent(containerSquirt.Solution.Value, containerSquirt.ReagentId, containerSquirt.QuantityPerUpdate, out _);
//}
while (querySquirt.MoveNext(out var uid, out var containerSquirt))
{
if (now < containerSquirt.NextGrowth)
continue;

containerSquirt.NextGrowth = now + containerSquirt.GrowthDelay;

if (_mobState.IsDead(uid))
continue;

if (EntityManager.TryGetComponent(uid, out HungerComponent? hunger))
{
if (_hunger.GetHungerThreshold(hunger) < HungerThreshold.Okay)
continue;

//_hunger.ModifyHunger(uid, -containerMilk.HungerUsage, hunger);
}

if (!_solutionContainer.ResolveSolution(uid, containerSquirt.SolutionName, ref containerSquirt.Solution))
continue;

_solutionContainer.TryAddReagent(containerSquirt.Solution.Value, containerSquirt.ReagentId, containerSquirt.QuantityPerUpdate, out _);
}
}
#endregion
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace Content.Shared.Floofstation.Leash.Components;

/// <summary>
/// Indicates that this entity or the entity that wears this entity can be leashed.
/// </summary>
[RegisterComponent]
public sealed partial class LeashAnchorComponent : Component
{
}
103 changes: 103 additions & 0 deletions Content.Shared/Floofstation/Leash/Components/LeashComponent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
using Robust.Shared.GameStates;
using Robust.Shared.Serialization;
using Robust.Shared.Utility;

namespace Content.Shared.Floofstation.Leash.Components;

[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
public sealed partial class LeashComponent : Component
{
/// <summary>
/// Maximum number of leash joints that this entity can create.
/// </summary>
[DataField, AutoNetworkedField]
public int MaxJoints = 1;

/// <summary>
/// Default length of the leash joint.
/// </summary>
[DataField, AutoNetworkedField]
public float Length = 3.5f;

/// <summary>
/// Maximum distance between the anchor and the puller beyond which the leash will break.
/// </summary>
[DataField, AutoNetworkedField]
public float MaxDistance = 8f;

/// <summary>
/// The time it takes for one entity to attach/detach the leash to/from another entity.
/// </summary>
[DataField, AutoNetworkedField]
public TimeSpan AttachDelay = TimeSpan.FromSeconds(2f), DetachDelay = TimeSpan.FromSeconds(2f);

/// <summary>
/// The time it takes for the leashed entity to detach itself from this leash.
/// </summary>
[DataField, AutoNetworkedField]
public TimeSpan SelfDetachDelay = TimeSpan.FromSeconds(8f);

[DataField, AutoNetworkedField]
public SpriteSpecifier? LeashSprite;

[DataField]
public TimeSpan NextPull = TimeSpan.Zero;

[DataField, AutoNetworkedField]
public TimeSpan PullInterval = TimeSpan.FromSeconds(1.5f);

/// <summary>
/// How much damage each leash joint can sustain before it breaks.
/// </summary>
/// <remarks>Not currently implemented; needs to be reworked in order to work.</remarks>
[DataField, AutoNetworkedField]
public float BreakDamage = 20f;

/// <summary>
/// How much damage each leash joint loses every <see cref="DamageInterval"/>.
/// </summary>
/// <remarks>Not currently implemented; needs to be reworked in order to work.</remarks>
[DataField, AutoNetworkedField]
public float JointRepairDamage = 1f;

/// <summary>
/// Interval at which damage is calculated for each joint.
/// </summary>
/// <remarks>Not currently implemented; needs to be reworked in order to work.</remarks>
[DataField, AutoNetworkedField]
public TimeSpan DamageInterval = TimeSpan.FromMilliseconds(200);

/// <summary>
/// List of all joints and their respective pulled entities created by this leash.
/// </summary>
[DataField, AutoNetworkedField]
public List<LeashData> Leashed = new();

[DataDefinition, Serializable, NetSerializable]
public sealed partial class LeashData
{
[DataField]
public string JointId = string.Empty;

[DataField]
public NetEntity Pulled = NetEntity.Invalid;

/// <summary>
/// Entity used to visualize the leash. Created dynamically.
/// </summary>
[DataField]
public NetEntity? LeashVisuals = null;

[DataField]
public float Damage = 0f;

[DataField]
public TimeSpan NextDamage = TimeSpan.Zero;

public LeashData(string jointId, NetEntity pulled)
{
JointId = jointId;
Pulled = pulled;
}
};
}
Loading

0 comments on commit cf1bde0

Please sign in to comment.