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

fix scram, revert #26429 #31482

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all 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: 6 additions & 0 deletions Content.Server/Implants/Components/ScramImplantComponent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@ 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");
}
108 changes: 28 additions & 80 deletions Content.Server/Implants/SubdermalImplantSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
using Content.Shared.Preferences;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Map;
using Robust.Shared.Maths;
using Robust.Shared.Physics;
using Robust.Shared.Physics.Components;
using Robust.Shared.Random;
Expand All @@ -31,6 +32,7 @@ public sealed class SubdermalImplantSystem : SharedSubdermalImplantSystem
{
[Dependency] private readonly CuffableSystem _cuffable = default!;
[Dependency] private readonly HumanoidAppearanceSystem _humanoidAppearance = default!;
[Dependency] private readonly IMapManager _mapManager = default!;
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly MetaDataSystem _metaData = default!;
[Dependency] private readonly StoreSystem _store = default!;
Expand All @@ -39,11 +41,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;
private HashSet<Entity<MapGridComponent>> _targetGrids = [];

public override void Initialize()
{
Expand Down Expand Up @@ -112,92 +111,41 @@ private void OnScramImplant(EntityUid uid, SubdermalImplantComponent component,
_pullingSystem.TryStopPull(ent, pull);

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

if (targetCoords != null)
// 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++)
{
_xform.SetCoordinates(ent, targetCoords.Value);
_audio.PlayPvs(implant.TeleportSound, ent);
args.Handled = true;
}
}

private EntityCoordinates? SelectRandomTileInRange(TransformComponent userXform, float radius)
{
var userCoords = userXform.Coordinates.ToMap(EntityManager, _xform);
_targetGrids.Clear();
_lookupSystem.GetEntitiesInRange(userCoords, radius, _targetGrids);
Entity<MapGridComponent>? targetGrid = null;

if (_targetGrids.Count == 0)
return null;

// Give preference to the grid the entity is currently on.
// This does not guarantee that if the probability fails that the owner's grid won't be picked.
// In reality the probability is higher and depends on the number of grids.
if (userXform.GridUid != null && TryComp<MapGridComponent>(userXform.GridUid, out var gridComp))
{
var userGrid = new Entity<MapGridComponent>(userXform.GridUid.Value, gridComp);
if (_random.Prob(0.5f))
{
_targetGrids.Remove(userGrid);
targetGrid = userGrid;
}
}

if (targetGrid == null)
targetGrid = _random.GetRandom().PickAndTake(_targetGrids);

EntityCoordinates? targetCoords = null;
var distance = implant.TeleportRadius * MathF.Sqrt(_random.NextFloat()); // to get an uniform distribution
targetCoords = entityCoords.Offset(_random.NextAngle().ToVec() * distance);

do
{
var valid = false;

var range = (float) Math.Sqrt(radius);
var box = Box2.CenteredAround(userCoords.Position, new Vector2(range, range));
var tilesInRange = _mapSystem.GetTilesEnumerator(targetGrid.Value.Owner, targetGrid.Value.Comp, box, false);
var tileList = new ValueList<Vector2i>();
// prefer teleporting to grids
if (!_mapManager.TryFindGridAt(targetCoords, out var gridUid, out var grid))
continue;

while (tilesInRange.MoveNext(out var tile))
// the implant user probably does not want to be in your walls
var valid = true;
foreach (var entity in grid.GetAnchoredEntities(targetCoords))
{
tileList.Add(tile.GridIndices);
}
if (!_physicsQuery.TryGetComponent(entity, out var body))
continue;

while (tileList.Count != 0)
{
var tile = tileList.RemoveSwap(_random.Next(tileList.Count));
valid = true;
foreach (var entity in _mapSystem.GetAnchoredEntities(targetGrid.Value.Owner, targetGrid.Value.Comp,
tile))
{
if (!_physicsQuery.TryGetComponent(entity, out var body))
continue;

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

valid = false;
break;
}

if (valid)
{
targetCoords = new EntityCoordinates(targetGrid.Value.Owner,
_mapSystem.TileCenterToVector(targetGrid.Value, tile));
break;
}
}
if (body.BodyType != BodyType.Static ||
!body.Hard ||
(body.CollisionLayer & (int) CollisionGroup.Impassable) == 0)
continue;

if (valid || _targetGrids.Count == 0) // if we don't do the check here then PickAndTake will blow up on an empty set.
valid = false;
break;
}
if (valid)
break;
}
_xform.SetWorldPosition(ent, targetCoords.Position);
_audio.PlayPvs(implant.TeleportSound, ent);

targetGrid = _random.GetRandom().PickAndTake(_targetGrids);
} while (true);

return targetCoords;
args.Handled = true;
}

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