From 97f995b986229fb99ff75c7808657d5f26c54846 Mon Sep 17 00:00:00 2001 From: TekuNut <13456422+TekuNut@users.noreply.github.com> Date: Tue, 12 Jul 2022 03:37:02 +0100 Subject: [PATCH] Use map coordinates for spraying (#9505) --- .../Chemistry/Components/VaporComponent.cs | 2 +- .../Chemistry/EntitySystems/VaporSystem.cs | 5 +- .../Fluids/EntitySystems/SpraySystem.cs | 60 ++++++++++++------- 3 files changed, 43 insertions(+), 24 deletions(-) diff --git a/Content.Server/Chemistry/Components/VaporComponent.cs b/Content.Server/Chemistry/Components/VaporComponent.cs index a9fe2eb49d..adedfca4a9 100644 --- a/Content.Server/Chemistry/Components/VaporComponent.cs +++ b/Content.Server/Chemistry/Components/VaporComponent.cs @@ -14,7 +14,7 @@ namespace Content.Server.Chemistry.Components internal bool Reached; internal float ReactTimer; internal float Timer; - internal EntityCoordinates Target; + internal MapCoordinates Target; internal bool Active; internal float AliveTime; } diff --git a/Content.Server/Chemistry/EntitySystems/VaporSystem.cs b/Content.Server/Chemistry/EntitySystems/VaporSystem.cs index c217c647e2..3f13b93fc4 100644 --- a/Content.Server/Chemistry/EntitySystems/VaporSystem.cs +++ b/Content.Server/Chemistry/EntitySystems/VaporSystem.cs @@ -43,7 +43,7 @@ namespace Content.Server.Chemistry.EntitySystems } } - public void Start(VaporComponent vapor, Vector2 dir, float speed, EntityCoordinates target, float aliveTime) + public void Start(VaporComponent vapor, Vector2 dir, float speed, MapCoordinates target, float aliveTime) { vapor.Active = true; vapor.Target = target; @@ -112,8 +112,7 @@ namespace Content.Server.Chemistry.EntitySystems // Check if we've reached our target. if (!vapor.Reached && - vapor.Target.TryDistance(EntityManager, xform.Coordinates, out var distance) && - distance <= 0.5f) + (vapor.Target.Position - xform.MapPosition.Position).LengthSquared <= 0.25f) { vapor.Reached = true; } diff --git a/Content.Server/Fluids/EntitySystems/SpraySystem.cs b/Content.Server/Fluids/EntitySystems/SpraySystem.cs index 3177921cad..a654f5e12a 100644 --- a/Content.Server/Fluids/EntitySystems/SpraySystem.cs +++ b/Content.Server/Fluids/EntitySystems/SpraySystem.cs @@ -22,6 +22,7 @@ public sealed class SpraySystem : EntitySystem [Dependency] private readonly SolutionContainerSystem _solutionContainerSystem = default!; [Dependency] private readonly VaporSystem _vaporSystem = default!; [Dependency] private readonly IGameTiming _gameTiming = default!; + [Dependency] private readonly IMapManager _mapManager = default!; public override void Initialize() { @@ -52,48 +53,66 @@ public sealed class SpraySystem : EntitySystem if (solution.CurrentVolume <= 0) { - _popupSystem.PopupEntity( Loc.GetString("spray-component-is-empty-message"),uid, + _popupSystem.PopupEntity(Loc.GetString("spray-component-is-empty-message"), uid, Filter.Entities(args.User)); return; } - var playerPos = Transform(args.User).Coordinates; + var userXform = Transform(args.User); - if (args.ClickLocation.GetGridUid(EntityManager) != playerPos.GetGridUid(EntityManager)) + // The grid/map entity to attach the vapor to. + EntityUid vaporSpawnEntityUid; + if (userXform.GridUid != null) + vaporSpawnEntityUid = userXform.GridUid.Value; + else if (userXform.MapUid != null) + vaporSpawnEntityUid = userXform.MapUid.Value; + else return; - var direction = (args.ClickLocation.Position - playerPos.Position).Normalized; - var threeQuarters = direction * 0.75f; - var quarter = direction * 0.25f; + var gridMapXform = Transform(vaporSpawnEntityUid); + var gridMapInvMatrix = gridMapXform.InvWorldMatrix; + + var userMapPos = userXform.MapPosition; + + var clickMapPos = args.ClickLocation.ToMap(EntityManager); + + var diffPos = clickMapPos.Position - userMapPos.Position; + if (diffPos == Vector2.Zero || diffPos == Vector2.NaN) + return; + + var diffLength = diffPos.Length; + var diffNorm = diffPos.Normalized; + var diffAngle = diffNorm.ToAngle(); + + // Vectors to determine the spawn offset of the vapor clouds. + var threeQuarters = diffNorm * 0.75f; + var quarter = diffNorm * 0.25f; var amount = Math.Max(Math.Min((solution.CurrentVolume / component.TransferAmount).Int(), component.VaporAmount), 1); - var spread = component.VaporSpread / amount; for (var i = 0; i < amount; i++) { - var rotation = new Angle(direction.ToAngle() + Angle.FromDegrees(spread * i) - + var rotation = new Angle(diffAngle + Angle.FromDegrees(spread * i) - Angle.FromDegrees(spread * (amount - 1) / 2)); - var (_, diffPos) = args.ClickLocation - playerPos; - var diffNorm = diffPos.Normalized; - var diffLength = diffPos.Length; - - var target = Transform(args.User).Coordinates + // Calculate the destination for the vapor cloud. Limit to the maximum spray distance. + var target = userMapPos .Offset((diffNorm + rotation.ToVec()).Normalized * diffLength + quarter); - if (target.TryDistance(EntityManager, playerPos, out var distance) && distance > component.SprayDistance) - target = Transform(args.User).Coordinates - .Offset(diffNorm * component.SprayDistance); + var distance = target.Position.Length; + if (distance > component.SprayDistance) + target = userMapPos.Offset(diffNorm * component.SprayDistance); var newSolution = _solutionContainerSystem.SplitSolution(uid, solution, component.TransferAmount); if (newSolution.TotalVolume <= FixedPoint2.Zero) break; - var vapor = Spawn(component.SprayedPrototype, - playerPos.Offset(distance < 1 ? quarter : threeQuarters)); - Transform(vapor).LocalRotation = rotation; + // Spawn the vapor cloud onto the grid/map the user is present on. Offset the start position based on how far the target destination is. + var vaporPos = userMapPos.Offset(distance < 1 ? quarter : threeQuarters).Position; + var vapor = Spawn(component.SprayedPrototype, new EntityCoordinates(vaporSpawnEntityUid, gridMapInvMatrix.Transform(vaporPos))); + Transform(vapor).WorldRotation = rotation; if (TryComp(vapor, out AppearanceComponent? appearance)) { @@ -106,9 +125,10 @@ public sealed class SpraySystem : EntitySystem _vaporSystem.TryAddSolution(vaporComponent, newSolution); // impulse direction is defined in world-coordinates, not local coordinates - var impulseDirection = Transform(vapor).WorldRotation.ToVec(); + var impulseDirection = rotation.ToVec(); _vaporSystem.Start(vaporComponent, impulseDirection, component.SprayVelocity, target, component.SprayAliveTime); + // Apply the reaction force to the user. if (component.Impulse > 0f && TryComp(args.User, out PhysicsComponent? body)) body.ApplyLinearImpulse(-impulseDirection * component.Impulse); }