Delta-v/Content.Server/_DV/Footprints/Systems/FootPrintsSystem.cs

125 lines
4.9 KiB
C#

using System.Numerics;
using Content.Server._DV.Footprints.Components;
using Content.Server.Decals;
using Content.Shared._EE.Flight;
using Content.Shared.Inventory;
using Content.Shared.Mobs;
using Content.Shared.Mobs.Components;
using Content.Shared.Standing;
using Robust.Shared.Map;
using Robust.Shared.Random;
namespace Content.Server._DV.Footprints.Systems;
// TODO: If upstream ever adds prediction to SharedDecalSystem, move this to Shared and implement footprint prediction
public sealed partial class FootPrintsSystem : EntitySystem
{
[Dependency] private readonly IMapManager _map = default!;
[Dependency] private readonly DecalSystem _decalSystem = default!;
[Dependency] private readonly SharedFlightSystem _flight = default!;
[Dependency] private readonly SharedTransformSystem _transform = default!;
[Dependency] private readonly StandingStateSystem _standing = default!;
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly InventorySystem _inventory = default!;
private EntityQuery<FlightComponent> _flightQuery;
private EntityQuery<TransformComponent> _transformQuery;
private EntityQuery<StandingStateComponent> _standingQuery;
private EntityQuery<MobThresholdsComponent> _mobThresholdQuery;
// CrayonSystem uses a hardcoded offset of [-0.5, -0.5] for clicks
private static readonly Vector2 BaseDecalOffset = new(-0.5f, -0.5f);
public override void Initialize()
{
base.Initialize();
_flightQuery = GetEntityQuery<FlightComponent>();
_transformQuery = GetEntityQuery<TransformComponent>();
_standingQuery = GetEntityQuery<StandingStateComponent>();
_mobThresholdQuery = GetEntityQuery<MobThresholdsComponent>();
SubscribeLocalEvent<FootPrintsComponent, MoveEvent>(OnMove);
}
private void OnMove(Entity<FootPrintsComponent> ent, ref MoveEvent args)
{
if (ent.Comp.PrintsColor.A <= 0f)
{
ent.Comp.ColorQuantity = 0;
return;
}
if (_flightQuery.TryComp(ent, out var flight) && _flight.IsFlying((ent, flight)))
return;
if (!_transformQuery.TryComp(ent, out var transform))
return;
if (!_mobThresholdQuery.TryComp(ent, out var mobThresholds))
return;
var isCrit = mobThresholds.CurrentThresholdState is MobState.Critical or MobState.Dead;
var isDowned = isCrit || _standingQuery.TryComp(ent, out var standingComp) && _standing.IsDown((ent, standingComp));
var distance = (transform.LocalPosition - ent.Comp.LastPrintPosition).Length();
var stepSize = isDowned ? ent.Comp.DragSize : ent.Comp.StepSize;
if (distance <= stepSize)
return;
// Need to be on a grid to leave footprints
if (!_map.TryFindGridAt(_transform.GetMapCoordinates((ent, transform)), out var gridUid, out _))
return;
// Calculate spawn coordinates
var coords = CalcCoords(gridUid, ent.Comp, transform, isDowned);
var angle = isDowned
? (transform.LocalPosition - ent.Comp.LastPrintPosition).ToAngle() + Angle.FromDegrees(-90f)
: transform.LocalRotation + Angle.FromDegrees(180f);
string decal;
if (isDowned)
{
decal = _random.Pick(ent.Comp.DraggingDecals);
}
else if (!_inventory.GetSlotEnumerator(ent.Owner, SlotFlags.FEET).NextItem(out var item) // This assumes there can only be 1 feet slot.
|| item == EntityUid.Invalid)
{
decal = ent.Comp.RightStep ? ent.Comp.BareDecalRight : ent.Comp.BareDecalLeft;
}
else
{
decal = ent.Comp.RightStep ? ent.Comp.BootDecalRight : ent.Comp.BootDecalLeft;
}
if (!_decalSystem.TryAddDecal(decal, coords, out _, color: ent.Comp.PrintsColor, rotation: angle, cleanable: true))
return;
ent.Comp.LastPrintPosition = transform.LocalPosition;
// Alternate feet
ent.Comp.RightStep = !ent.Comp.RightStep;
ent.Comp.PrintsColor = ent.Comp.PrintsColor.WithAlpha(
Math.Max(0f, ent.Comp.PrintsColor.A - ent.Comp.ColorReduceAlpha));
}
private EntityCoordinates CalcCoords(EntityUid gridUid,
FootPrintsComponent footPrints,
TransformComponent transform,
bool dragging)
{
// For dragging, place footprint at center
if (dragging)
return new EntityCoordinates(gridUid, transform.LocalPosition + BaseDecalOffset);
// For walking, offset left or right based on which foot
var footOffset = footPrints.RightStep
? new Angle(Angle.FromDegrees(180f) + transform.LocalRotation).RotateVec(footPrints.OffsetPrint)
: new Angle(transform.LocalRotation).RotateVec(footPrints.OffsetPrint);
return new EntityCoordinates(gridUid, transform.LocalPosition + BaseDecalOffset + footOffset);
}
}