* Explosions * fix yaml typo and prevent silly UI inputs * oop * Use modified contains() checks And remove IEnumerable * Buff nuke, nerf meteors * optimize the entity lookup stuff a bit * fix tile (0,0) error forgot to do an initial Enumerator.MoveNext(), so the first tile was always the "null" tile. * remove celebration * byte -> int * remove diag edge tile dict * fix one bug but there is another * fix the other bug turns out dividing a ushort leads to rounding errors. Why TF is the grid tile size even a ushort in the first place. * improve edge map * fix minor bug If the initial-explosion tile had an airtight entity on it, the tile was processed twice. * some reviews (transform queries, eye.mapid, and tilesizes in overlays) * Apply suggestions from code review Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> * is map paused * GetAllTiles ignores space by default * WriteLine -> WriteError * First -> FirstOrDefault() * default prototype const string * entity query * misc review changes * grid edge max distance * fix fire texture defn bad use of type serializer and ioc-resolves * Remove ExplosionLaunched And allow nukes to throw items towards the outer part of an explosion * no hot-reload disclaimer * replace prototype id string with int index * optimise damage a tiiiiny bit. * entity queries * comments * misc mirror comments * cvars * admin logs * move intensity-per-state to prototype * update tile event to ECS event * git mv * Tweak rpg & minibomb also fix merge bug * you don't exist anymore go away * Fix build Co-authored-by: moonheart08 <moonheart08@users.noreply.github.com> Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com>
161 lines
5.7 KiB
C#
161 lines
5.7 KiB
C#
using Content.Shared.Atmos;
|
|
using Robust.Shared.Map;
|
|
|
|
namespace Content.Server.Explosion.EntitySystems;
|
|
|
|
public sealed class SpaceExplosion : TileExplosion
|
|
{
|
|
/// <summary>
|
|
/// The keys of this dictionary correspond to space tiles that intersect a grid. The values have information
|
|
/// about what grid (which could be more than one), and in what directions the space-based explosion is allowed
|
|
/// to propagate from this tile.
|
|
/// </summary>
|
|
private Dictionary<Vector2i, BlockedSpaceTile> _gridBlockMap;
|
|
|
|
/// <summary>
|
|
/// After every iteration, this data set will store all the grid-tiles that were reached as a result of the
|
|
/// explosion expanding in space.
|
|
/// </summary>
|
|
public Dictionary<GridId, HashSet<Vector2i>> GridJump = new();
|
|
|
|
public ushort TileSize = ExplosionSystem.DefaultTileSize;
|
|
|
|
public SpaceExplosion(ExplosionSystem system, MapCoordinates epicentre, GridId? referenceGrid, List<GridId> localGrids, float maxDistance)
|
|
{
|
|
(_gridBlockMap, TileSize) = system.TransformGridEdges(epicentre, referenceGrid, localGrids, maxDistance);
|
|
system.GetUnblockedDirections(_gridBlockMap, TileSize);
|
|
}
|
|
|
|
public int AddNewTiles(int iteration, HashSet<Vector2i> inputSpaceTiles)
|
|
{
|
|
NewTiles = new();
|
|
NewBlockedTiles = new();
|
|
NewFreedTiles = new();
|
|
GridJump = new();
|
|
|
|
// Adjacent tiles
|
|
if (TileLists.TryGetValue(iteration - 2, out var adjacent))
|
|
AddNewAdjacentTiles(iteration, adjacent);
|
|
if (FreedTileLists.TryGetValue((iteration - 2) % 3, out var delayedAdjacent))
|
|
AddNewAdjacentTiles(iteration, delayedAdjacent);
|
|
|
|
// Diagonal tiles
|
|
if (TileLists.TryGetValue(iteration - 3, out var diagonal))
|
|
AddNewDiagonalTiles(iteration, diagonal);
|
|
if (FreedTileLists.TryGetValue((iteration - 3) % 3, out var delayedDiagonal))
|
|
AddNewDiagonalTiles(iteration, delayedDiagonal);
|
|
|
|
// Tiles entering space from some grid.
|
|
foreach (var tile in inputSpaceTiles)
|
|
{
|
|
ProcessNewTile(iteration, tile, AtmosDirection.All);
|
|
}
|
|
|
|
// Store new tiles
|
|
if (NewTiles.Count != 0)
|
|
TileLists[iteration] = NewTiles;
|
|
if (NewBlockedTiles.Count != 0)
|
|
BlockedTileLists[iteration] = NewBlockedTiles;
|
|
FreedTileLists[iteration % 3] = NewFreedTiles;
|
|
|
|
// return new tile count
|
|
return NewTiles.Count + NewBlockedTiles.Count;
|
|
}
|
|
|
|
private void JumpToGrid(BlockedSpaceTile blocker)
|
|
{
|
|
foreach (var edge in blocker.BlockingGridEdges)
|
|
{
|
|
if (edge.Grid == null) continue;
|
|
|
|
if (!GridJump.TryGetValue(edge.Grid.Value, out var set))
|
|
{
|
|
set = new();
|
|
GridJump[edge.Grid.Value] = set;
|
|
}
|
|
|
|
set.Add(edge.Tile);
|
|
}
|
|
}
|
|
|
|
private void AddNewAdjacentTiles(int iteration, IEnumerable<Vector2i> tiles)
|
|
{
|
|
foreach (var tile in tiles)
|
|
{
|
|
var unblockedDirections = GetUnblockedDirectionOrAll(tile);
|
|
|
|
if (unblockedDirections == AtmosDirection.Invalid)
|
|
continue;
|
|
|
|
for (var i = 0; i < Atmospherics.Directions; i++)
|
|
{
|
|
var direction = (AtmosDirection) (1 << i);
|
|
|
|
if (!unblockedDirections.IsFlagSet(direction))
|
|
continue; // explosion cannot propagate in this direction. Ever.
|
|
|
|
ProcessNewTile(iteration, tile.Offset(direction), direction.GetOpposite());
|
|
}
|
|
}
|
|
}
|
|
|
|
public override void InitTile(Vector2i initialTile)
|
|
{
|
|
ProcessedTiles.Add(initialTile);
|
|
TileLists[0] = new() { initialTile };
|
|
|
|
// It might be the case that the initial space-explosion tile actually overlaps on a grid. In that case we
|
|
// need to manually add it to the `spaceToGridTiles` dictionary. This would normally be done automatically
|
|
// during the neighbor finding steps.
|
|
if (_gridBlockMap.TryGetValue(initialTile, out var blocker))
|
|
JumpToGrid(blocker);
|
|
}
|
|
|
|
protected override void ProcessNewTile(int iteration, Vector2i tile, AtmosDirection entryDirection)
|
|
{
|
|
if (!_gridBlockMap.TryGetValue(tile, out var blocker))
|
|
{
|
|
// this tile does not intersect any grids. Add it (if its new) and continue.
|
|
if (ProcessedTiles.Add(tile))
|
|
NewTiles.Add(tile);
|
|
return;
|
|
}
|
|
|
|
// Is the entry to this tile blocked?
|
|
if ((blocker.UnblockedDirections & entryDirection) == 0)
|
|
{
|
|
// was this tile already entered from some other direction?
|
|
if (EnteredBlockedTiles.Contains(tile))
|
|
return;
|
|
|
|
// Did the explosion already attempt to enter this tile from some other direction?
|
|
if (!UnenteredBlockedTiles.Add(tile))
|
|
return;
|
|
|
|
// First time the explosion is reaching this tile.
|
|
NewBlockedTiles.Add(tile);
|
|
JumpToGrid(blocker);
|
|
}
|
|
|
|
// Was this tile already entered?
|
|
if (!EnteredBlockedTiles.Add(tile))
|
|
return;
|
|
|
|
// Did the explosion already attempt to enter this tile from some other direction?
|
|
if (UnenteredBlockedTiles.Contains(tile))
|
|
{
|
|
NewFreedTiles.Add(tile);
|
|
return;
|
|
}
|
|
|
|
// This is a completely new tile, and we just so happened to enter it from an unblocked direction.
|
|
NewTiles.Add(tile);
|
|
JumpToGrid(blocker);
|
|
}
|
|
|
|
protected override AtmosDirection GetUnblockedDirectionOrAll(Vector2i tile)
|
|
{
|
|
return _gridBlockMap.TryGetValue(tile, out var blocker) ? blocker.UnblockedDirections : AtmosDirection.All;
|
|
}
|
|
}
|