Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Port] Footsteps / Следы #110

Merged
merged 3 commits into from
Oct 31, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 84 additions & 0 deletions Content.Client/_White/FootPrint/FootPrintsVisualizerSystem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
using Content.Shared._White.FootPrint;
using Robust.Client.GameObjects;
using Robust.Client.Graphics;
using Robust.Shared.Random;

namespace Content.Client._White.FootPrint;

public sealed class FootPrintsVisualizerSystem : VisualizerSystem<FootPrintComponent>
{
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
[Dependency] private readonly IRobustRandom _random = default!;

public override void Initialize()
{
base.Initialize();

SubscribeLocalEvent<FootPrintComponent, ComponentInit>(OnInitialized);
SubscribeLocalEvent<FootPrintComponent, ComponentShutdown>(OnShutdown);
}

private void OnInitialized(EntityUid uid, FootPrintComponent comp, ComponentInit args)
{
if (!TryComp<SpriteComponent>(uid, out var sprite))
return;

sprite.LayerMapReserveBlank(FootPrintVisualLayers.Print);
UpdateAppearance(uid, comp, sprite);
}

private void OnShutdown(EntityUid uid, FootPrintComponent comp, ComponentShutdown args)
{
if (TryComp<SpriteComponent>(uid, out var sprite) &&
sprite.LayerMapTryGet(FootPrintVisualLayers.Print, out var layer))
{
sprite.RemoveLayer(layer);
}
}

private void UpdateAppearance(EntityUid uid, FootPrintComponent component, SpriteComponent sprite)
{
if (!sprite.LayerMapTryGet(FootPrintVisualLayers.Print, out var layer)
|| !TryComp<FootPrintsComponent>(component.PrintOwner, out var printsComponent)
|| !TryComp<AppearanceComponent>(uid, out var appearance))
return;

if (_appearance.TryGetData<FootPrintVisuals>(uid, FootPrintVisualState.State, out var printVisuals, appearance))
{
switch (printVisuals)
{
case FootPrintVisuals.BareFootPrint:
sprite.LayerSetState(layer,
printsComponent.RightStep
? new RSI.StateId(printsComponent.RightBarePrint)
: new RSI.StateId(printsComponent.LeftBarePrint),
printsComponent.RsiPath);
break;
case FootPrintVisuals.ShoesPrint:
sprite.LayerSetState(layer, new RSI.StateId(printsComponent.ShoesPrint), printsComponent.RsiPath);
break;
case FootPrintVisuals.SuitPrint:
sprite.LayerSetState(layer, new RSI.StateId(printsComponent.SuitPrint), printsComponent.RsiPath);
break;
case FootPrintVisuals.Dragging:
sprite.LayerSetState(layer, new RSI.StateId(_random.Pick(printsComponent.DraggingPrint)), printsComponent.RsiPath);
break;
default:
throw new ArgumentOutOfRangeException($"Unknown {printVisuals} parameter.");
}
}

if (!_appearance.TryGetData<Color>(uid, FootPrintVisualState.Color, out var printColor, appearance))
return;

sprite.LayerSetColor(layer, printColor);
}

protected override void OnAppearanceChange (EntityUid uid, FootPrintComponent component, ref AppearanceChangeEvent args)
{
if (args.Sprite is not { } sprite)
return;

UpdateAppearance(uid, component, sprite);
}
}
131 changes: 131 additions & 0 deletions Content.Server/_White/FootPrint/FootPrintsSystem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
using Content.Server.Atmos.Components;
using Content.Shared.Inventory;
using Content.Shared.Mobs;
using Content.Shared.Mobs.Components;
using Content.Shared._White.FootPrint;
using Content.Shared.Standing;
using Content.Shared.Chemistry.Components.SolutionManager;
using Content.Shared.Chemistry.EntitySystems;
using Robust.Shared.Map;
using Robust.Shared.Random;

namespace Content.Server._White.FootPrint;

public sealed class FootPrintsSystem : EntitySystem
{
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly InventorySystem _inventory = default!;
[Dependency] private readonly IMapManager _map = default!;

[Dependency] private readonly SharedSolutionContainerSystem _solution = default!;
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
[Dependency] private readonly SharedTransformSystem _transform = default!;

private EntityQuery<TransformComponent> _transformQuery;
private EntityQuery<MobThresholdsComponent> _mobThresholdQuery;
private EntityQuery<AppearanceComponent> _appearanceQuery;
private EntityQuery<LayingDownComponent> _layingQuery;

public override void Initialize()
{
base.Initialize();

_transformQuery = GetEntityQuery<TransformComponent>();
_mobThresholdQuery = GetEntityQuery<MobThresholdsComponent>();
_appearanceQuery = GetEntityQuery<AppearanceComponent>();
_layingQuery = GetEntityQuery<LayingDownComponent>();

SubscribeLocalEvent<FootPrintsComponent, ComponentStartup>(OnStartupComponent);
SubscribeLocalEvent<FootPrintsComponent, MoveEvent>(OnMove);
}

private void OnStartupComponent(EntityUid uid, FootPrintsComponent comp, ComponentStartup args)
{
comp.StepSize += _random.NextFloat(-0.05f, 0.05f);
}

private void OnMove(EntityUid uid, FootPrintsComponent comp, ref MoveEvent args)
{
if (comp.PrintsColor.A <= 0f
|| !_transformQuery.TryComp(uid, out var transform)
|| !_mobThresholdQuery.TryComp(uid, out var mobThreshHolds)
|| !_map.TryFindGridAt(_transform.GetMapCoordinates((uid, transform)), out var gridUid, out _))
return;

var dragging = mobThreshHolds.CurrentThresholdState is MobState.Critical or MobState.Dead || _layingQuery.TryComp(uid, out var laying) && laying.IsCrawlingUnder;
var distance = (transform.LocalPosition - comp.StepPos).Length();
var stepSize = dragging ? comp.DragSize : comp.StepSize;

if (!(distance > stepSize))
return;

comp.RightStep = !comp.RightStep;

var entity = Spawn(comp.StepProtoId, CalcCoords(gridUid, comp, transform, dragging));
var footPrintComponent = Comp<FootPrintComponent>(entity); // There's NO way there's no footprint commponent in a FOOTPRINT

footPrintComponent.PrintOwner = uid;
Dirty(entity, footPrintComponent);

if (_appearanceQuery.TryComp(entity, out var appearance))
{
_appearance.SetData(entity, FootPrintVisualState.State, PickState(uid, dragging), appearance);
_appearance.SetData(entity, FootPrintVisualState.Color, comp.PrintsColor, appearance);
}

if (!_transformQuery.TryComp(entity, out var stepTransform))
return;

stepTransform.LocalRotation = dragging
? (transform.LocalPosition - comp.StepPos).ToAngle() + Angle.FromDegrees(-90f)
: transform.LocalRotation + Angle.FromDegrees(180f);

comp.PrintsColor = comp.PrintsColor.WithAlpha(ReduceAlpha(comp.PrintsColor.A, comp.ColorReduceAlpha));
comp.StepPos = transform.LocalPosition;

if (!TryComp<SolutionContainerManagerComponent>(entity, out var solutionContainer)
|| !_solution.ResolveSolution((entity, solutionContainer), footPrintComponent.SolutionName, ref footPrintComponent.Solution, out var solution)
|| string.IsNullOrWhiteSpace(comp.ReagentToTransfer) || solution.Volume >= 1)
return;

_solution.TryAddReagent(footPrintComponent.Solution.Value, comp.ReagentToTransfer, 1, out _);
}

private EntityCoordinates CalcCoords(EntityUid uid, FootPrintsComponent comp, TransformComponent transform, bool state)
{
if (state)
return new EntityCoordinates(uid, transform.LocalPosition);

var offset = comp.RightStep
? new Angle(Angle.FromDegrees(180f) + transform.LocalRotation).RotateVec(comp.OffsetPrint)
: new Angle(transform.LocalRotation).RotateVec(comp.OffsetPrint);

return new EntityCoordinates(uid, transform.LocalPosition + offset);
}

private FootPrintVisuals PickState(EntityUid uid, bool dragging)
{
var state = FootPrintVisuals.BareFootPrint;

if (_inventory.TryGetSlotEntity(uid, "shoes", out _))
state = FootPrintVisuals.ShoesPrint;

if (_inventory.TryGetSlotEntity(uid, "outerClothing", out var suit) && TryComp<PressureProtectionComponent>(suit, out _))
state = FootPrintVisuals.SuitPrint;

if (dragging)
state = FootPrintVisuals.Dragging;

return state;
}

private float ReduceAlpha(float alpha, float reductionAmount)
{
if (alpha - reductionAmount > 0f)
alpha -= reductionAmount;
else
alpha = 0f;

return alpha;
}
}
53 changes: 53 additions & 0 deletions Content.Server/_White/FootPrint/PuddleFootPrintsSystem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
using System.Linq;
using Content.Shared._White.FootPrint;
using Content.Shared.Chemistry.Components.SolutionManager;
using Content.Shared.Chemistry.EntitySystems;
using Content.Shared.Fluids;
using Content.Shared.Fluids.Components;
using Robust.Shared.Physics.Events;

namespace Content.Server._White.FootPrint;

public sealed class PuddleFootPrintsSystem : EntitySystem
{
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
[Dependency] private readonly SharedSolutionContainerSystem _solutionContainer = default!;

public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<PuddleFootPrintsComponent, EndCollideEvent>(OnStepTrigger);
}

private void OnStepTrigger(EntityUid uid, PuddleFootPrintsComponent comp, ref EndCollideEvent args)
{
if (!TryComp<AppearanceComponent>(uid, out var appearance)
|| !TryComp<PuddleComponent>(uid, out var puddle)
|| !TryComp<FootPrintsComponent>(args.OtherEntity, out var tripper)
|| !TryComp<SolutionContainerManagerComponent>(uid, out var solutionManager)
||!_solutionContainer.ResolveSolution((uid, solutionManager), puddle.SolutionName, ref puddle.Solution, out var solutions))
return;

// alles gut!
var totalSolutionQuantity = solutions.Contents.Sum(sol => (float)sol.Quantity);
var waterQuantity = (from sol in solutions.Contents where sol.Reagent.Prototype == "Water" select (float) sol.Quantity).FirstOrDefault();

if (waterQuantity / (totalSolutionQuantity / 100f) > comp.OffPercent || solutions.Contents.Count <= 0)
return;

tripper.ReagentToTransfer =
solutions.Contents.Aggregate((l, r) => l.Quantity > r.Quantity ? l : r).Reagent.Prototype;

if (_appearance.TryGetData(uid, PuddleVisuals.SolutionColor, out var color, appearance)
&& _appearance.TryGetData(uid, PuddleVisuals.CurrentVolume, out var volume, appearance))
AddColor((Color)color, (float)volume * comp.SizeRatio, tripper);

_solutionContainer.RemoveEachReagent(puddle.Solution.Value, 1);
}

private void AddColor(Color col, float quantity, FootPrintsComponent comp)
{
comp.PrintsColor = comp.ColorQuantity == 0f ? col : Color.InterpolateBetween(comp.PrintsColor, col, 0.2f);
comp.ColorQuantity += quantity;
}
}
23 changes: 23 additions & 0 deletions Content.Shared/_White/Footprint/FootPrintComponent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using Content.Shared.Chemistry.Components;
using Robust.Shared.GameStates;

namespace Content.Shared._White.FootPrint;

/// <summary>
/// This is used for marking footsteps, handling footprint drawing.
/// </summary>
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
public sealed partial class FootPrintComponent : Component
{
/// <summary>
/// Owner (with <see cref="FootPrintsComponent"/>) of a print (this component).
/// </summary>
[AutoNetworkedField]
public EntityUid PrintOwner;

[DataField]
public string SolutionName = "step";

[DataField]
public Entity<SolutionComponent>? Solution;
}
25 changes: 25 additions & 0 deletions Content.Shared/_White/Footprint/FootPrintVisuals.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using Robust.Shared.Serialization;

namespace Content.Shared._White.FootPrint;

[Serializable, NetSerializable]
public enum FootPrintVisuals : byte
{
BareFootPrint,
ShoesPrint,
SuitPrint,
Dragging
}

[Serializable, NetSerializable]
public enum FootPrintVisualState : byte
{
State,
Color
}

[Serializable, NetSerializable]
public enum FootPrintVisualLayers : byte
{
Print
}
64 changes: 64 additions & 0 deletions Content.Shared/_White/Footprint/FootPrintsComponent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
using System.Numerics;
using Robust.Shared.Prototypes;
using Robust.Shared.Utility;

namespace Content.Shared._White.FootPrint;

[RegisterComponent]
public sealed partial class FootPrintsComponent : Component
{
[ViewVariables(VVAccess.ReadOnly), DataField]
public ResPath RsiPath = new("/Textures/_White/Effects/footprints.rsi");

// all of those are set as a layer
[ViewVariables(VVAccess.ReadOnly), DataField]
public string LeftBarePrint = "footprint-left-bare-human";

[ViewVariables(VVAccess.ReadOnly), DataField]
public string RightBarePrint = "footprint-right-bare-human";

[ViewVariables(VVAccess.ReadOnly), DataField]
public string ShoesPrint = "footprint-shoes";

[ViewVariables(VVAccess.ReadOnly), DataField]
public string SuitPrint = "footprint-suit";

[ViewVariables(VVAccess.ReadOnly), DataField]
public string[] DraggingPrint =
[
"dragging-1",
"dragging-2",
"dragging-3",
"dragging-4",
"dragging-5",
];
// yea, those

[ViewVariables(VVAccess.ReadOnly), DataField]
public EntProtoId<FootPrintComponent> StepProtoId = "Footstep";

[ViewVariables(VVAccess.ReadOnly), DataField]
public Color PrintsColor = Color.FromHex("#00000000");

[DataField]
public float StepSize = 0.7f;

[DataField]
public float DragSize = 0.5f;

[DataField]
public float ColorQuantity;

[DataField]
public float ColorReduceAlpha = 0.1f;

[DataField]
public string? ReagentToTransfer;

[DataField]
public Vector2 OffsetPrint = new(0.1f, 0f);

public bool RightStep = true;

public Vector2 StepPos = Vector2.Zero;
}
11 changes: 11 additions & 0 deletions Content.Shared/_White/Footprint/PuddleFootPrintsComponent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
namespace Content.Shared._White.FootPrint;

[RegisterComponent]
public sealed partial class PuddleFootPrintsComponent : Component
{
[ViewVariables(VVAccess.ReadWrite)]
public float SizeRatio = 0.2f;

[ViewVariables(VVAccess.ReadWrite)]
public float OffPercent = 80f;
}
Loading
Loading