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

Replace the teleportation logic on the SCRAM implant! #26429

Merged
merged 6 commits into from
Apr 1, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
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
6 changes: 0 additions & 6 deletions Content.Server/Implants/Components/ScramImplantComponent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,6 @@ public sealed partial class ScramImplantComponent : Component
[DataField, ViewVariables(VVAccess.ReadWrite)]
public float TeleportRadius = 100f;

/// <summary>
/// How many times to check for a valid tile to teleport to
/// </summary>
[DataField, ViewVariables(VVAccess.ReadOnly)]
public int TeleportAttempts = 20;

[DataField, ViewVariables(VVAccess.ReadWrite)]
public SoundSpecifier TeleportSound = new SoundPathSpecifier("/Audio/Effects/teleport_arrival.ogg");
}
96 changes: 71 additions & 25 deletions Content.Server/Implants/SubdermalImplantSystem.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Content.Server.Cuffs;
using System.Linq;
using Content.Server.Cuffs;
using Content.Server.Forensics;
using Content.Server.Humanoid;
using Content.Server.Implants.Components;
Expand All @@ -21,6 +22,7 @@
using System.Numerics;
using Content.Shared.Movement.Pulling.Components;
using Content.Shared.Movement.Pulling.Systems;
using Robust.Shared.Map.Components;

namespace Content.Server.Implants;

Expand All @@ -37,6 +39,8 @@ public sealed class SubdermalImplantSystem : SharedSubdermalImplantSystem
[Dependency] private readonly SharedTransformSystem _xform = default!;
[Dependency] private readonly ForensicsSystem _forensicsSystem = default!;
[Dependency] private readonly PullingSystem _pullingSystem = default!;
[Dependency] private readonly EntityLookupSystem _lookupSystem = default!;
[Dependency] private readonly SharedMapSystem _mapSystem = default!;

private EntityQuery<PhysicsComponent> _physicsQuery;

Expand Down Expand Up @@ -107,42 +111,84 @@ private void OnScramImplant(EntityUid uid, SubdermalImplantComponent component,
_pullingSystem.TryStopPull(ent, pull);

var xform = Transform(ent);
var entityCoords = xform.Coordinates.ToMap(EntityManager, _xform);
var targetCoords = SelectRandomTileInRange(xform, implant.TeleportRadius);

// try to find a valid position to teleport to, teleport to whatever works if we can't
var targetCoords = new MapCoordinates();
for (var i = 0; i < implant.TeleportAttempts; i++)
if (targetCoords != null)
{
var distance = implant.TeleportRadius * MathF.Sqrt(_random.NextFloat()); // to get an uniform distribution
targetCoords = entityCoords.Offset(_random.NextAngle().ToVec() * distance);
_xform.SetWorldPosition(ent, targetCoords.Value.Position);
_xform.AttachToGridOrMap(ent, xform);
_audio.PlayPvs(implant.TeleportSound, ent);
nikthechampiongr marked this conversation as resolved.
Show resolved Hide resolved
args.Handled = true;
}
}

// prefer teleporting to grids
if (!_mapManager.TryFindGridAt(targetCoords, out var gridUid, out var grid))
continue;
private MapCoordinates? SelectRandomTileInRange(TransformComponent userXform, float radius)
{
var userCoords = userXform.Coordinates.ToMap(EntityManager, _xform);
var grids = _lookupSystem.GetEntitiesInRange<MapGridComponent>(userCoords, radius).ToList();
_random.Shuffle(grids);

// the implant user probably does not want to be in your walls
var valid = true;
foreach (var entity in grid.GetAnchoredEntities(targetCoords))
// Give preference to the grid the entity is currently on.
var idx = grids.FindIndex(grid => grid.Owner == userXform.GridUid);
nikthechampiongr marked this conversation as resolved.
Show resolved Hide resolved
if (idx != -1)
{
if (_random.Prob(0.66f))
{
(grids[0], grids[idx]) = (grids[idx], grids[0]);
}
else
{
if (!_physicsQuery.TryGetComponent(entity, out var body))
continue;
(grids[^1], grids[idx]) = (grids[idx], grids[^1]);
}
}

if (body.BodyType != BodyType.Static ||
!body.Hard ||
(body.CollisionLayer & (int) CollisionGroup.Impassable) == 0)
continue;
MapCoordinates? targetCoords = null;

valid = false;
break;
foreach (var grid in grids)
{
var valid = false;

var range = (float) Math.Sqrt(radius);
var box = Box2.CenteredAround(userCoords.Position, new Vector2(range, range));
var tilesInRange = _mapSystem.GetTilesEnumerator(grid.Owner, grid.Comp, box, false);
var tileList = new List<TileRef>();

nikthechampiongr marked this conversation as resolved.
Show resolved Hide resolved
while (tilesInRange.MoveNext(out var tile))
{
tileList.Add(tile);
}

_random.Shuffle(tileList);

foreach (var tile in tileList)
nikthechampiongr marked this conversation as resolved.
Show resolved Hide resolved
{
valid = true;
foreach(var entity in _mapSystem.GetAnchoredEntities(grid.Owner, grid.Comp, tile.GridIndices))
{
if (!_physicsQuery.TryGetComponent(entity, out var body))
continue;

if (body.BodyType != BodyType.Static ||
!body.Hard ||
(body.CollisionLayer & (int) CollisionGroup.Impassable) == 0)
continue;

valid = false;
nikthechampiongr marked this conversation as resolved.
Show resolved Hide resolved
break;
}

if (valid)
{
targetCoords = _mapSystem.GridTileToWorld(grid.Owner, grid.Comp, tile.GridIndices);
break;
}
}

if (valid)
break;
}
_xform.SetWorldPosition(ent, targetCoords.Position);
_xform.AttachToGridOrMap(ent, xform);
_audio.PlayPvs(implant.TeleportSound, ent);

args.Handled = true;
return targetCoords;
}

private void OnDnaScramblerImplant(EntityUid uid, SubdermalImplantComponent component, UseDnaScramblerImplantEvent args)
Expand Down
Loading