Skip to content

Commit

Permalink
Footprints (#28)
Browse files Browse the repository at this point in the history
* footprints

* blyat errorki

* errors fixes 2

* oops

* rename

* error fixes

* Renames

* Case files

* fix

* another one

* Fixes

* Apply suggestions from code review

---------

Co-authored-by: FN <[email protected]>
  • Loading branch information
AwareFoxy and FireNameFN authored Nov 9, 2024
1 parent 9933ab1 commit 9031a52
Show file tree
Hide file tree
Showing 40 changed files with 537 additions and 5 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
using Content.Shared._CorvaxNext.Footprints;
using Content.Shared._CorvaxNext.Footprints.Components;
using Robust.Client.GameObjects;
using Robust.Shared.Random;

namespace Content.Client._CorvaxNext.Footprints;

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))
return;

if (!sprite.LayerMapTryGet(FootprintVisualLayers.Print, out var layer))
return;

sprite.RemoveLayer(layer);
}

private void UpdateAppearance(EntityUid uid, FootprintComponent component, SpriteComponent sprite)
{
if (!sprite.LayerMapTryGet(FootprintVisualLayers.Print, out var layer))
return;

if (!TryComp<FootprintVisualizerComponent>(component.FootprintsVisualizer, out var printsComponent))
return;

if (!TryComp<AppearanceComponent>(uid, out var appearance))
return;

if (!_appearance.TryGetData<FootprintVisuals>(uid, FootprintVisualState.State, out var printVisuals, appearance))
return;

sprite.LayerSetState(layer, new(printVisuals switch
{
FootprintVisuals.BareFootprint => printsComponent.RightStep ? printsComponent.RightBarePrint : printsComponent.LeftBarePrint,
FootprintVisuals.ShoesPrint => printsComponent.ShoesPrint,
FootprintVisuals.SuitPrint => printsComponent.SuitPrint,
FootprintVisuals.Dragging => _random.Pick(printsComponent.DraggingPrint),
_ => throw new ArgumentOutOfRangeException($"Unknown {printVisuals} parameter.")
}), printsComponent.RsiPath);

if (_appearance.TryGetData<Color>(uid, FootprintVisualState.Color, out var printColor, appearance))
sprite.LayerSetColor(layer, printColor);
}

protected override void OnAppearanceChange(EntityUid uid, FootprintComponent component, ref AppearanceChangeEvent args)
{
if (args.Sprite is null)
return;

UpdateAppearance(uid, component, args.Sprite);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
using Content.Server.Atmos.Components;
using Content.Shared.Inventory;
using Content.Shared.Mobs;
using Content.Shared.Mobs.Components;
using Content.Shared.Chemistry.Components.SolutionManager;
using Content.Shared.Chemistry.EntitySystems;
using Robust.Shared.Map;
using Robust.Shared.Random;
using Content.Shared._CorvaxNext.Footprints;
using Content.Shared._CorvaxNext.Footprints.Components;

namespace Content.Server._CorvaxNext.Footprints.EntitySystems;

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;

public override void Initialize()
{
_transformQuery = GetEntityQuery<TransformComponent>();
_mobThresholdQuery = GetEntityQuery<MobThresholdsComponent>();
_appearanceQuery = GetEntityQuery<AppearanceComponent>();

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

private void OnStartupComponent(EntityUid uid, FootprintVisualizerComponent component, ComponentStartup args)
{
component.StepSize = Math.Max(0f, component.StepSize + _random.NextFloat(-0.05f, 0.05f));
}

private void OnMove(EntityUid uid, FootprintVisualizerComponent component, ref MoveEvent args)
{
if (component.PrintsColor.A <= 0f)
return;

if (!_transformQuery.TryComp(uid, out var transform))
return;

if (!_mobThresholdQuery.TryComp(uid, out var mobThreshHolds))
return;

if (!_map.TryFindGridAt(_transform.GetMapCoordinates((uid, transform)), out var gridUid, out _))
return;

var dragging = mobThreshHolds.CurrentThresholdState is MobState.Critical or MobState.Dead;
var distance = (transform.LocalPosition - component.StepPos).Length();
var stepSize = dragging ? component.DragSize : component.StepSize;

if (distance <= stepSize)
return;

component.RightStep = !component.RightStep;

var entity = Spawn(component.StepProtoId, CalcCoords(gridUid, component, transform, dragging));
var footPrintComponent = EnsureComp<FootprintComponent>(entity);

footPrintComponent.FootprintsVisualizer = 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, component.PrintsColor, appearance);
}

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

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

component.PrintsColor = component.PrintsColor.WithAlpha(Math.Max(0f, component.PrintsColor.A - component.ColorReduceAlpha));
component.StepPos = transform.LocalPosition;

if (!TryComp<SolutionContainerManagerComponent>(entity, out var solutionContainer))
return;

if (!_solution.ResolveSolution((entity, solutionContainer), footPrintComponent.SolutionName, ref footPrintComponent.Solution, out var solution))
return;

if (string.IsNullOrWhiteSpace(component.ReagentToTransfer) || solution.Volume >= 1)
return;

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

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

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

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

private FootprintVisuals PickState(EntityUid uid, bool dragging)
{
var state = FootprintVisuals.BareFootprint;

if (dragging)
state = FootprintVisuals.Dragging;
else if (_inventory.TryGetSlotEntity(uid, "outerClothing", out var suit) && TryComp<PressureProtectionComponent>(suit, out _))
state = FootprintVisuals.SuitPrint;
else if (_inventory.TryGetSlotEntity(uid, "shoes", out _))
state = FootprintVisuals.ShoesPrint;

return state;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
using System.Linq;
using Content.Shared._CorvaxNext.Footprints.Components;
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._CorvaxNext.Footprints.EntitySystems;

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

public override void Initialize()
{
SubscribeLocalEvent<PuddleFootprintsComponent, EndCollideEvent>(OnStepTrigger);
}

private void OnStepTrigger(EntityUid uid, PuddleFootprintsComponent component, ref EndCollideEvent args)
{
if (!TryComp<AppearanceComponent>(uid, out var appearance))
return;

if (!TryComp<PuddleComponent>(uid, out var puddle))
return;

if (!TryComp<FootprintVisualizerComponent>(args.OtherEntity, out var tripper))
return;

if (!TryComp<SolutionContainerManagerComponent>(uid, out var solutionManager))
return;

if (!_solutionContainer.ResolveSolution((uid, solutionManager), puddle.SolutionName, ref puddle.Solution, out var solutions))
return;

var totalSolutionQuantity = solutions.Contents.Sum(sol => (float)sol.Quantity);
var waterQuantity = (float)solutions.Contents.Where(solution => solution.Reagent.Prototype == "Water").FirstOrDefault().Quantity;

if (waterQuantity / (totalSolutionQuantity / 100f) > component.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 * component.SizeRatio, tripper);

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

private void AddColor(Color col, float quantity, FootprintVisualizerComponent component)
{
component.PrintsColor = component.ColorQuantity == 0 ? col : Color.InterpolateBetween(component.PrintsColor, col, component.ColorInterpolationFactor);
component.ColorQuantity += quantity;
}
}
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._CorvaxNext.Footprints.Components;

/// <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="FootprintVisualizerComponent"/>) of a print (this component).
/// </summary>
[AutoNetworkedField]
public EntityUid FootprintsVisualizer;

[DataField]
public string SolutionName = "step";

[DataField]
public Entity<SolutionComponent>? Solution;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
using System.Numerics;
using Robust.Shared.Prototypes;
using Robust.Shared.Utility;

namespace Content.Shared._CorvaxNext.Footprints.Components;

[RegisterComponent]
public sealed partial class FootprintVisualizerComponent : Component
{
[ViewVariables(VVAccess.ReadOnly), DataField]
public ResPath RsiPath = new("/Textures/_CorvaxNext/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");

/// <summary>
/// The size scaling factor for footprint steps. Must be positive.
/// </summary>
[DataField]
public float StepSize = 0.7f;

/// <summary>
/// The size scaling factor for drag marks. Must be positive.
/// </summary>
[DataField]
public float DragSize = 0.5f;

/// <summary>
/// The amount of color to transfer from the source (e.g., puddle) to the footprint.
/// </summary>
[DataField]
public float ColorQuantity;

/// <summary>
/// The factor by which the alpha channel is reduced in subsequent footprints.
/// </summary>
[DataField]
public float ColorReduceAlpha = 0.1f;

[DataField]
public string? ReagentToTransfer;

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

/// <summary>
/// Tracks which foot should make the next print. True for right foot, false for left.
/// </summary>
public bool RightStep = true;

/// <summary>
/// The position of the last footprint in world coordinates.
/// </summary>
public Vector2 StepPos = Vector2.Zero;

/// <summary>
/// Controls how quickly the footprint color transitions between steps.
/// Value between 0 and 1, where higher values mean faster color changes.
/// </summary>
public float ColorInterpolationFactor = 0.2f;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
namespace Content.Shared._CorvaxNext.Footprints.Components;

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

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

0 comments on commit 9031a52

Please sign in to comment.