Explosion refactor fixes pt1 (#7375)
This commit is contained in:
@@ -33,6 +33,7 @@ public sealed class ExplosionOverlaySystem : EntitySystem
|
||||
|
||||
SubscribeNetworkEvent<ExplosionEvent>(OnExplosion);
|
||||
SubscribeNetworkEvent<ExplosionOverlayUpdateEvent>(HandleExplosionUpdate);
|
||||
SubscribeLocalEvent<MapChangedEvent>(OnMapChanged);
|
||||
|
||||
_cfg.OnValueChanged(CCVars.ExplosionPersistence, SetExplosionPersistence, true);
|
||||
|
||||
@@ -42,6 +43,17 @@ public sealed class ExplosionOverlaySystem : EntitySystem
|
||||
overlayManager.AddOverlay(_overlay);
|
||||
}
|
||||
|
||||
private void OnMapChanged(MapChangedEvent ev)
|
||||
{
|
||||
if (ev.Created)
|
||||
return;
|
||||
|
||||
if (_overlay.ActiveExplosion?.Map == ev.Map)
|
||||
_overlay.ActiveExplosion = null;
|
||||
|
||||
_overlay.CompletedExplosions.RemoveAll(exp => exp.Map == ev.Map);
|
||||
}
|
||||
|
||||
private void SetExplosionPersistence(float value) => ExplosionPersistence = value;
|
||||
|
||||
public override void FrameUpdate(float frameTime)
|
||||
|
||||
@@ -153,7 +153,7 @@ namespace Content.Server.Administration
|
||||
{
|
||||
var coords = Transform(args.Target).MapPosition;
|
||||
Timer.Spawn(_gameTiming.TickPeriod,
|
||||
() => _explosionSystem.QueueExplosion(coords, ExplosionSystem.DefaultExplosionPrototypeId, 30, 4, 8),
|
||||
() => _explosionSystem.QueueExplosion(coords, ExplosionSystem.DefaultExplosionPrototypeId, 4, 1, 2, maxTileBreak: 0), // it gibs, damage doesn't need to be high.
|
||||
CancellationToken.None);
|
||||
|
||||
if (TryComp(args.Target, out SharedBodyComponent? body))
|
||||
|
||||
@@ -51,6 +51,22 @@ public sealed class ExplosiveComponent : Component
|
||||
[DataField("totalIntensity")]
|
||||
public float TotalIntensity = 10;
|
||||
|
||||
/// <summary>
|
||||
/// Factor used to scale the explosion intensity when calculating tile break chances. Allows for stronger
|
||||
/// explosives that don't space tiles, without having to create a new explosion-type prototype.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField("tileBreakScale")]
|
||||
public float TileBreakScale = 1f;
|
||||
|
||||
/// <summary>
|
||||
/// Maximum number of times that an explosive can break a tile. Currently, for normal space ships breaking a
|
||||
/// tile twice will result in a vacuum.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField("maxTileBreak")]
|
||||
public int MaxTileBreak = int.MaxValue;
|
||||
|
||||
/// <summary>
|
||||
/// Avoid somehow double-triggering this explosion (e.g. by damaging this entity from its own explosion.
|
||||
/// </summary>
|
||||
|
||||
@@ -4,7 +4,10 @@ using static Content.Server.Explosion.EntitySystems.ExplosionSystem;
|
||||
|
||||
namespace Content.Server.Explosion.EntitySystems;
|
||||
|
||||
public sealed class GridExplosion : TileExplosion
|
||||
/// <summary>
|
||||
/// See <see cref="ExplosionTileFlood"/>. Each instance of this class corresponds to a seperate grid.
|
||||
/// </summary>
|
||||
public sealed class ExplosionGridTileFlood : ExplosionTileFlood
|
||||
{
|
||||
public IMapGrid Grid;
|
||||
private bool _needToTransform = false;
|
||||
@@ -31,7 +34,7 @@ public sealed class GridExplosion : TileExplosion
|
||||
|
||||
private Dictionary<Vector2i, NeighborFlag> _edgeTiles;
|
||||
|
||||
public GridExplosion(
|
||||
public ExplosionGridTileFlood(
|
||||
IMapGrid grid,
|
||||
Dictionary<Vector2i, TileData> airtightMap,
|
||||
float maxIntensity,
|
||||
@@ -3,7 +3,10 @@ using Robust.Shared.Map;
|
||||
|
||||
namespace Content.Server.Explosion.EntitySystems;
|
||||
|
||||
public sealed class SpaceExplosion : TileExplosion
|
||||
/// <summary>
|
||||
/// See <see cref="ExplosionTileFlood"/>.
|
||||
/// </summary>
|
||||
public sealed class ExplosionSpaceTileFlood : ExplosionTileFlood
|
||||
{
|
||||
/// <summary>
|
||||
/// The keys of this dictionary correspond to space tiles that intersect a grid. The values have information
|
||||
@@ -20,7 +23,7 @@ public sealed class SpaceExplosion : TileExplosion
|
||||
|
||||
public ushort TileSize = ExplosionSystem.DefaultTileSize;
|
||||
|
||||
public SpaceExplosion(ExplosionSystem system, MapCoordinates epicentre, GridId? referenceGrid, List<GridId> localGrids, float maxDistance)
|
||||
public ExplosionSpaceTileFlood(ExplosionSystem system, MapCoordinates epicentre, GridId? referenceGrid, List<GridId> localGrids, float maxDistance)
|
||||
{
|
||||
(_gridBlockMap, TileSize) = system.TransformGridEdges(epicentre, referenceGrid, localGrids, maxDistance);
|
||||
system.GetUnblockedDirections(_gridBlockMap, TileSize);
|
||||
@@ -163,13 +163,12 @@ public sealed partial class ExplosionSystem : EntitySystem
|
||||
|
||||
return explosionTolerance;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Data struct that describes the explosion-blocking airtight entities on a tile.
|
||||
/// </summary>
|
||||
public struct TileData
|
||||
{
|
||||
/// <summary>
|
||||
/// Data struct that describes the explosion-blocking airtight entities on a tile.
|
||||
/// </summary>
|
||||
public struct TileData
|
||||
{
|
||||
public TileData(float[] explosionTolerance, AtmosDirection blockedDirections)
|
||||
{
|
||||
ExplosionTolerance = explosionTolerance;
|
||||
@@ -178,4 +177,5 @@ public struct TileData
|
||||
|
||||
public float[] ExplosionTolerance;
|
||||
public AtmosDirection BlockedDirections = AtmosDirection.Invalid;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
using System.Linq;
|
||||
using Content.Server.Explosion.Components;
|
||||
using Content.Server.Throwing;
|
||||
using Content.Shared.Damage;
|
||||
using Content.Shared.Explosion;
|
||||
using Content.Shared.Maps;
|
||||
@@ -9,7 +7,6 @@ using Robust.Shared.Map;
|
||||
using Robust.Shared.Physics;
|
||||
using Robust.Shared.Random;
|
||||
using Robust.Shared.Timing;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Server.Explosion.EntitySystems;
|
||||
|
||||
@@ -54,6 +51,19 @@ public sealed partial class ExplosionSystem : EntitySystem
|
||||
/// </summary>
|
||||
private int _previousTileIteration;
|
||||
|
||||
private void OnMapChanged(MapChangedEvent ev)
|
||||
{
|
||||
// If a map was deleted, check the explosion currently being processed belongs to that map.
|
||||
if (ev.Created)
|
||||
return;
|
||||
|
||||
if (_activeExplosion?.Epicenter.MapId != ev.Map)
|
||||
return;
|
||||
|
||||
_activeExplosion = null;
|
||||
_nodeGroupSystem.Snoozing = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Process the explosion queue.
|
||||
/// </summary>
|
||||
@@ -287,8 +297,11 @@ public sealed partial class ExplosionSystem : EntitySystem
|
||||
if (_containerSystem.IsEntityInContainer(uid, meta))
|
||||
return;
|
||||
|
||||
// "worldPos" should be the space/map local position.
|
||||
var worldPos = _transformSystem.GetWorldPosition(xform, xformQuery);
|
||||
|
||||
// finally check if it intersects our tile
|
||||
if (gridBox.Contains(invSpaceMatrix.Transform(xform.LocalPosition)))
|
||||
if (gridBox.Contains(invSpaceMatrix.Transform(worldPos)))
|
||||
list.Add((uid, xform));
|
||||
};
|
||||
|
||||
@@ -365,15 +378,18 @@ public sealed partial class ExplosionSystem : EntitySystem
|
||||
/// grid tile.
|
||||
/// </summary>
|
||||
public void DamageFloorTile(TileRef tileRef,
|
||||
float intensity,
|
||||
float effectiveIntensity,
|
||||
int maxTileBreak,
|
||||
List<(Vector2i GridIndices, Tile Tile)> damagedTiles,
|
||||
ExplosionPrototype type)
|
||||
{
|
||||
var tileDef = _tileDefinitionManager[tileRef.Tile.TypeId];
|
||||
|
||||
while (_robustRandom.Prob(type.TileBreakChance(intensity)))
|
||||
int tileBreakages = 0;
|
||||
while (maxTileBreak > tileBreakages && _robustRandom.Prob(type.TileBreakChance(effectiveIntensity)))
|
||||
{
|
||||
intensity -= type.TileBreakRerollReduction;
|
||||
tileBreakages++;
|
||||
effectiveIntensity -= type.TileBreakRerollReduction;
|
||||
|
||||
if (tileDef is not ContentTileDefinition contentTileDef)
|
||||
break;
|
||||
@@ -397,19 +413,41 @@ public sealed partial class ExplosionSystem : EntitySystem
|
||||
/// cref="ExplosionSystem"/>.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is basically the output of <see cref="ExplosionSystem.GetExplosionTiles()"/>, but wrapped in an enumerator
|
||||
/// to iterate over the tiles, along with the ability to keep track of what entities have already been damaged by
|
||||
/// This is basically the output of <see cref="ExplosionSystem.GetExplosionTiles()"/>, but with some utility functions for
|
||||
/// iterating over the tiles, along with the ability to keep track of what entities have already been damaged by
|
||||
/// this explosion.
|
||||
/// </remarks>
|
||||
sealed class Explosion
|
||||
{
|
||||
/// <summary>
|
||||
/// For every grid (+ space) that the explosion reached, this data struct stores information about the tiles and
|
||||
/// caches the entity-lookup component so that it doesn't have to be re-fetched for every tile.
|
||||
/// </summary>
|
||||
struct ExplosionData
|
||||
{
|
||||
public EntityLookupComponent Lookup;
|
||||
/// <summary>
|
||||
/// The tiles that the explosion damaged, grouped by the iteration (can be thought of as the distance from the epicenter)
|
||||
/// </summary>
|
||||
public Dictionary<int, List<Vector2i>> TileLists;
|
||||
|
||||
/// <summary>
|
||||
/// Lookup component for this grid (or space/map).
|
||||
/// </summary>
|
||||
public EntityLookupComponent Lookup;
|
||||
|
||||
/// <summary>
|
||||
/// The actual grid that this corresponds to. If null, this implies space.
|
||||
/// </summary>
|
||||
public IMapGrid? MapGrid;
|
||||
}
|
||||
|
||||
private readonly List<ExplosionData> _explosionData = new();
|
||||
|
||||
/// <summary>
|
||||
/// The explosion intensity associated with each tile iteration.
|
||||
/// </summary>
|
||||
private readonly List<float> _tileSetIntensity;
|
||||
|
||||
/// <summary>
|
||||
/// Used to avoid applying explosion effects repeatedly to the same entity. Particularly important if the
|
||||
/// explosion throws this entity, as then it will be moving while the explosion is happening.
|
||||
@@ -421,17 +459,32 @@ sealed class Explosion
|
||||
/// </summary>
|
||||
public int CurrentIteration { get; private set; } = 0;
|
||||
|
||||
/// <summary>
|
||||
/// The prototype for this explosion. Determines tile break chance, damage, etc.
|
||||
/// </summary>
|
||||
public readonly ExplosionPrototype ExplosionType;
|
||||
|
||||
/// <summary>
|
||||
/// The center of the explosion. Used for physics throwing. Also used to identify the map on which the explosion is happening.
|
||||
/// </summary>
|
||||
public readonly MapCoordinates Epicenter;
|
||||
|
||||
/// <summary>
|
||||
/// The matrix that defines the referance frame for the explosion in space.
|
||||
/// </summary>
|
||||
private readonly Matrix3 _spaceMatrix;
|
||||
|
||||
/// <summary>
|
||||
/// Inverse of <see cref="_spaceMatrix"/>
|
||||
/// </summary>
|
||||
private readonly Matrix3 _invSpaceMatrix;
|
||||
|
||||
private readonly List<ExplosionData> _explosionData = new();
|
||||
private readonly List<float> _tileSetIntensity;
|
||||
|
||||
/// <summary>
|
||||
/// Have all the tiles on all the grids been processed?
|
||||
/// </summary>
|
||||
public bool FinishedProcessing;
|
||||
|
||||
// shitty enumerator implementation
|
||||
// Variables used for enumerating over tiles, grids, etc
|
||||
private DamageSpecifier _currentDamage = default!;
|
||||
private EntityLookupComponent _currentLookup = default!;
|
||||
private IMapGrid? _currentGrid;
|
||||
@@ -439,25 +492,50 @@ sealed class Explosion
|
||||
private float _currentThrowForce;
|
||||
private List<Vector2i>.Enumerator _currentEnumerator;
|
||||
private int _currentDataIndex;
|
||||
private Dictionary<IMapGrid, List<(Vector2i, Tile)>> _tileUpdateDict = new();
|
||||
|
||||
private EntityQuery<TransformComponent> _xformQuery;
|
||||
private EntityQuery<PhysicsComponent> _physicsQuery;
|
||||
private EntityQuery<DamageableComponent> _damageQuery;
|
||||
private EntityQuery<MetaDataComponent> _metaQuery;
|
||||
/// <summary>
|
||||
/// The set of tiles that need to be updated when the explosion has finished processing. Used to avoid having
|
||||
/// the explosion trigger chunk regeneration & shuttle-system processing every tick.
|
||||
/// </summary>
|
||||
private readonly Dictionary<IMapGrid, List<(Vector2i, Tile)>> _tileUpdateDict = new();
|
||||
|
||||
public int Area;
|
||||
// Entity Queries
|
||||
private readonly EntityQuery<TransformComponent> _xformQuery;
|
||||
private readonly EntityQuery<PhysicsComponent> _physicsQuery;
|
||||
private readonly EntityQuery<DamageableComponent> _damageQuery;
|
||||
private readonly EntityQuery<MetaDataComponent> _metaQuery;
|
||||
|
||||
/// <summary>
|
||||
/// Total area that the explosion covers.
|
||||
/// </summary>
|
||||
public readonly int Area;
|
||||
|
||||
/// <summary>
|
||||
/// factor used to scale the tile break chances.
|
||||
/// </summary>
|
||||
private readonly float _tileBreakScale;
|
||||
|
||||
/// <summary>
|
||||
/// Maximum number of times that an explosion will break a single tile.
|
||||
/// </summary>
|
||||
private readonly int _maxTileBreak;
|
||||
|
||||
private readonly IEntityManager _entMan;
|
||||
private readonly ExplosionSystem _system;
|
||||
|
||||
/// <summary>
|
||||
/// Initialize a new instance for processing
|
||||
/// </summary>
|
||||
public Explosion(ExplosionSystem system,
|
||||
ExplosionPrototype explosionType,
|
||||
SpaceExplosion? spaceData,
|
||||
List<GridExplosion> gridData,
|
||||
ExplosionSpaceTileFlood? spaceData,
|
||||
List<ExplosionGridTileFlood> gridData,
|
||||
List<float> tileSetIntensity,
|
||||
MapCoordinates epicenter,
|
||||
Matrix3 spaceMatrix,
|
||||
int area,
|
||||
float tileBreakScale,
|
||||
int maxTileBreak,
|
||||
IEntityManager entMan,
|
||||
IMapManager mapMan)
|
||||
{
|
||||
@@ -467,6 +545,10 @@ sealed class Explosion
|
||||
Epicenter = epicenter;
|
||||
Area = area;
|
||||
|
||||
_tileBreakScale = tileBreakScale;
|
||||
_maxTileBreak = maxTileBreak;
|
||||
_entMan = entMan;
|
||||
|
||||
_xformQuery = entMan.GetEntityQuery<TransformComponent>();
|
||||
_physicsQuery = entMan.GetEntityQuery<PhysicsComponent>();
|
||||
_damageQuery = entMan.GetEntityQuery<DamageableComponent>();
|
||||
@@ -501,6 +583,10 @@ sealed class Explosion
|
||||
MoveNext();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Find the next tile-enumerator. This either means retrieving a set of tiles on the next grid, or incrementing
|
||||
/// the tile iteration by one and moving back to the first grid. This will also update the current damage, current entity-lookup, etc.
|
||||
/// </summary>
|
||||
private bool TryGetNextTileEnumerator()
|
||||
{
|
||||
while (CurrentIteration < _tileSetIntensity.Count)
|
||||
@@ -526,21 +612,29 @@ sealed class Explosion
|
||||
_currentEnumerator = tileList.GetEnumerator();
|
||||
_currentLookup = _explosionData[_currentDataIndex].Lookup;
|
||||
_currentGrid = _explosionData[_currentDataIndex].MapGrid;
|
||||
|
||||
_currentDataIndex++;
|
||||
|
||||
// sanity checks, in case something changed while the explosion was being processed over several ticks.
|
||||
if (_currentLookup.Deleted || _currentGrid != null && !_entMan.EntityExists(_currentGrid.GridEntityId))
|
||||
continue;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// this explosion intensity has been fully processed, move to the next one
|
||||
// All the tiles belonging to this explosion iteration have been processed. Move onto the next iteration and
|
||||
// reset the grid counter.
|
||||
CurrentIteration++;
|
||||
_currentDataIndex = 0;
|
||||
}
|
||||
|
||||
// no more explosion data to process
|
||||
// No more explosion tiles to process
|
||||
FinishedProcessing = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the next tile that needs processing
|
||||
/// </summary>
|
||||
private bool MoveNext()
|
||||
{
|
||||
if (FinishedProcessing)
|
||||
@@ -557,6 +651,9 @@ sealed class Explosion
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempt to process (i.e., damage entities) some number of grid tiles.
|
||||
/// </summary>
|
||||
public int Process(int processingTarget)
|
||||
{
|
||||
// In case the explosion terminated early last tick due to exceeding the allocated processing time, use this
|
||||
@@ -572,6 +669,7 @@ sealed class Explosion
|
||||
break;
|
||||
}
|
||||
|
||||
// Is the current tile on a grid (instead of in space)?
|
||||
if (_currentGrid != null &&
|
||||
_currentGrid.TryGetTileRef(_currentEnumerator.Current, out var tileRef) &&
|
||||
!tileRef.Tile.IsEmpty)
|
||||
@@ -582,6 +680,8 @@ sealed class Explosion
|
||||
_tileUpdateDict[_currentGrid] = tileUpdateList;
|
||||
}
|
||||
|
||||
// damage entities on the tile. Also figures out whether there are any solid entities blocking the floor
|
||||
// from being destroyed.
|
||||
var canDamageFloor = _system.ExplodeTile(_currentLookup,
|
||||
_currentGrid,
|
||||
_currentEnumerator.Current,
|
||||
@@ -595,12 +695,13 @@ sealed class Explosion
|
||||
_physicsQuery,
|
||||
_metaQuery);
|
||||
|
||||
// was there a blocking entity on the tile that was not destroyed by the explosion?
|
||||
// If the floor is not blocked by some dense object, damage the floor tiles.
|
||||
if (canDamageFloor)
|
||||
_system.DamageFloorTile(tileRef, _currentIntensity, tileUpdateList, ExplosionType);
|
||||
_system.DamageFloorTile(tileRef, _currentIntensity * _tileBreakScale, _maxTileBreak, tileUpdateList, ExplosionType);
|
||||
}
|
||||
else
|
||||
{
|
||||
// The current "tile" is in space. Damage any entities in that region
|
||||
_system.ExplodeSpace(_currentLookup,
|
||||
_spaceMatrix,
|
||||
_invSpaceMatrix,
|
||||
@@ -620,12 +721,16 @@ sealed class Explosion
|
||||
break;
|
||||
}
|
||||
|
||||
// Update damaged/broken tiles on the grid.
|
||||
SetTiles();
|
||||
return processed;
|
||||
}
|
||||
|
||||
private void SetTiles()
|
||||
{
|
||||
// Updating the grid can result in chunk collision regeneration & slow processing by the shuttle system.
|
||||
// Therefore, tile breaking may be configure to only happen at the end of an explosion, rather than during every
|
||||
// tick.
|
||||
if (!_system.IncrementalTileBreaking && !FinishedProcessing)
|
||||
return;
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ public sealed partial class ExplosionSystem : EntitySystem
|
||||
/// <param name="maxIntensity">The maximum intensity that the explosion can have at any given tile. This
|
||||
/// effectively caps the damage that this explosion can do.</param>
|
||||
/// <returns>A list of tile-sets and a list of intensity values which describe the explosion.</returns>
|
||||
private (int, List<float>, SpaceExplosion?, Dictionary<GridId, GridExplosion>, Matrix3)? GetExplosionTiles(
|
||||
private (int, List<float>, ExplosionSpaceTileFlood?, Dictionary<GridId, ExplosionGridTileFlood>, Matrix3)? GetExplosionTiles(
|
||||
MapCoordinates epicenter,
|
||||
string typeID,
|
||||
float totalIntensity,
|
||||
@@ -64,8 +64,8 @@ public sealed partial class ExplosionSystem : EntitySystem
|
||||
}
|
||||
|
||||
// Main data for the exploding tiles in space and on various grids
|
||||
Dictionary<GridId, GridExplosion> gridData = new();
|
||||
SpaceExplosion? spaceData = null;
|
||||
Dictionary<GridId, ExplosionGridTileFlood> gridData = new();
|
||||
ExplosionSpaceTileFlood? spaceData = null;
|
||||
|
||||
// The intensity slope is how much the intensity drop over a one-tile distance. The actual algorithm step-size is half of thhat.
|
||||
var stepSize = slope / 2;
|
||||
@@ -98,7 +98,7 @@ public sealed partial class ExplosionSystem : EntitySystem
|
||||
if (!_airtightMap.TryGetValue(epicentreGrid.Value, out var airtightMap))
|
||||
airtightMap = new();
|
||||
|
||||
var initialGridData = new GridExplosion(
|
||||
var initialGridData = new ExplosionGridTileFlood(
|
||||
_mapManager.GetGrid(epicentreGrid.Value),
|
||||
airtightMap,
|
||||
maxIntensity,
|
||||
@@ -116,7 +116,7 @@ public sealed partial class ExplosionSystem : EntitySystem
|
||||
else
|
||||
{
|
||||
// set up the space explosion data
|
||||
spaceData = new SpaceExplosion(this, epicenter, referenceGrid, localGrids, maxDistance);
|
||||
spaceData = new ExplosionSpaceTileFlood(this, epicenter, referenceGrid, localGrids, maxDistance);
|
||||
spaceData.InitTile(initialTile);
|
||||
}
|
||||
|
||||
@@ -187,7 +187,7 @@ public sealed partial class ExplosionSystem : EntitySystem
|
||||
if (!_airtightMap.TryGetValue(grid, out var airtightMap))
|
||||
airtightMap = new();
|
||||
|
||||
data = new GridExplosion(
|
||||
data = new ExplosionGridTileFlood(
|
||||
_mapManager.GetGrid(grid),
|
||||
airtightMap,
|
||||
maxIntensity,
|
||||
@@ -208,7 +208,7 @@ public sealed partial class ExplosionSystem : EntitySystem
|
||||
|
||||
// if space-data is null, but some grid-based explosion reached space, we need to initialize it.
|
||||
if (spaceData == null && previousSpaceJump.Count != 0)
|
||||
spaceData = new SpaceExplosion(this, epicenter, referenceGrid, localGrids, maxDistance);
|
||||
spaceData = new ExplosionSpaceTileFlood(this, epicenter, referenceGrid, localGrids, maxDistance);
|
||||
|
||||
// If the explosion has reached space, do that neighbors finding step as well.
|
||||
if (spaceData != null)
|
||||
|
||||
@@ -16,7 +16,6 @@ using Robust.Shared.Map;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Random;
|
||||
using Robust.Shared.Timing;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Server.Explosion.EntitySystems;
|
||||
@@ -29,7 +28,6 @@ public sealed partial class ExplosionSystem : EntitySystem
|
||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||
[Dependency] private readonly IConfigurationManager _cfg = default!;
|
||||
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
||||
|
||||
[Dependency] private readonly DamageableSystem _damageableSystem = default!;
|
||||
[Dependency] private readonly ContainerSystem _containerSystem = default!;
|
||||
@@ -38,6 +36,7 @@ public sealed partial class ExplosionSystem : EntitySystem
|
||||
[Dependency] private readonly EntityLookupSystem _entityLookup = default!;
|
||||
[Dependency] private readonly AdminLogSystem _logsSystem = default!;
|
||||
[Dependency] private readonly ThrowingSystem _throwingSystem = default!;
|
||||
[Dependency] private readonly SharedTransformSystem _transformSystem = default!;
|
||||
|
||||
/// <summary>
|
||||
/// "Tile-size" for space when there are no nearby grids to use as a reference.
|
||||
@@ -62,12 +61,15 @@ public sealed partial class ExplosionSystem : EntitySystem
|
||||
|
||||
DebugTools.Assert(_prototypeManager.HasIndex<ExplosionPrototype>(DefaultExplosionPrototypeId));
|
||||
|
||||
// handled in ExplosionSystemGridMap.cs
|
||||
// handled in ExplosionSystem.GridMap.cs
|
||||
SubscribeLocalEvent<GridRemovalEvent>(OnGridRemoved);
|
||||
SubscribeLocalEvent<GridStartupEvent>(OnGridStartup);
|
||||
SubscribeLocalEvent<ExplosionResistanceComponent, GetExplosionResistanceEvent>(OnGetResistance);
|
||||
SubscribeLocalEvent<TileChangedEvent>(OnTileChanged);
|
||||
|
||||
// Handled by ExplosionSystem.Processing.cs
|
||||
SubscribeLocalEvent<MapChangedEvent>(OnMapChanged);
|
||||
|
||||
// handled in ExplosionSystemAirtight.cs
|
||||
SubscribeLocalEvent<AirtightComponent, DamageChangedEvent>(OnAirtightDamaged);
|
||||
SubscribeCvars();
|
||||
@@ -118,6 +120,8 @@ public sealed partial class ExplosionSystem : EntitySystem
|
||||
(float) totalIntensity,
|
||||
explosive.IntensitySlope,
|
||||
explosive.MaxIntensity,
|
||||
explosive.TileBreakScale,
|
||||
explosive.MaxTileBreak,
|
||||
user);
|
||||
|
||||
if (delete)
|
||||
@@ -184,13 +188,15 @@ public sealed partial class ExplosionSystem : EntitySystem
|
||||
float totalIntensity,
|
||||
float slope,
|
||||
float maxTileIntensity,
|
||||
float tileBreakScale = 1f,
|
||||
int maxTileBreak = int.MaxValue,
|
||||
EntityUid? user = null,
|
||||
bool addLog = false)
|
||||
{
|
||||
var pos = Transform(uid).MapPosition;
|
||||
|
||||
|
||||
QueueExplosion(pos, typeId, totalIntensity, slope, maxTileIntensity, addLog: false);
|
||||
QueueExplosion(pos, typeId, totalIntensity, slope, maxTileIntensity, tileBreakScale, maxTileBreak, addLog: false);
|
||||
|
||||
if (!addLog)
|
||||
return;
|
||||
@@ -211,6 +217,8 @@ public sealed partial class ExplosionSystem : EntitySystem
|
||||
float totalIntensity,
|
||||
float slope,
|
||||
float maxTileIntensity,
|
||||
float tileBreakScale = 1f,
|
||||
int maxTileBreak = int.MaxValue,
|
||||
bool addLog = false)
|
||||
{
|
||||
if (totalIntensity <= 0 || slope <= 0)
|
||||
@@ -226,7 +234,7 @@ public sealed partial class ExplosionSystem : EntitySystem
|
||||
_logsSystem.Add(LogType.Explosion, LogImpact.High, $"Explosion spawned at {epicenter:coordinates} with intensity {totalIntensity} slope {slope}");
|
||||
|
||||
_explosionQueue.Enqueue(() => SpawnExplosion(epicenter, type, totalIntensity,
|
||||
slope, maxTileIntensity));
|
||||
slope, maxTileIntensity, tileBreakScale, maxTileBreak));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -238,8 +246,13 @@ public sealed partial class ExplosionSystem : EntitySystem
|
||||
ExplosionPrototype type,
|
||||
float totalIntensity,
|
||||
float slope,
|
||||
float maxTileIntensity)
|
||||
float maxTileIntensity,
|
||||
float tileBreakScale,
|
||||
int maxTileBreak)
|
||||
{
|
||||
if (!_mapManager.MapExists(epicenter.MapId))
|
||||
return null;
|
||||
|
||||
var results = GetExplosionTiles(epicenter, type.ID, totalIntensity, slope, maxTileIntensity);
|
||||
|
||||
if (results == null)
|
||||
@@ -268,6 +281,8 @@ public sealed partial class ExplosionSystem : EntitySystem
|
||||
epicenter,
|
||||
spaceMatrix,
|
||||
area,
|
||||
tileBreakScale,
|
||||
maxTileBreak,
|
||||
EntityManager,
|
||||
_mapManager);
|
||||
}
|
||||
@@ -275,7 +290,7 @@ public sealed partial class ExplosionSystem : EntitySystem
|
||||
/// <summary>
|
||||
/// Constructor for the shared <see cref="ExplosionEvent"/> using the server-exclusive explosion classes.
|
||||
/// </summary>
|
||||
internal ExplosionEvent GetExplosionEvent(MapCoordinates epicenter, string id, Matrix3 spaceMatrix, SpaceExplosion? spaceData, IEnumerable<GridExplosion> gridData, List<float> iterationIntensity)
|
||||
internal ExplosionEvent GetExplosionEvent(MapCoordinates epicenter, string id, Matrix3 spaceMatrix, ExplosionSpaceTileFlood? spaceData, IEnumerable<ExplosionGridTileFlood> gridData, List<float> iterationIntensity)
|
||||
{
|
||||
var spaceTiles = spaceData?.TileLists;
|
||||
|
||||
|
||||
@@ -4,9 +4,16 @@ using System.Runtime.CompilerServices;
|
||||
namespace Content.Server.Explosion.EntitySystems;
|
||||
|
||||
/// <summary>
|
||||
/// This is the base class for <see cref="SpaceExplosion"/> and <see cref="GridExplosion"/>. It just exists to avoid some code duplication, because those classes are generally quite distinct.
|
||||
/// This class exists to facilitate the iterative neighbor-finding / flooding algorithm used by explosions in <see
|
||||
/// cref="ExplosionSystem.GetExplosionTiles"/>. This is the base class for <see cref="ExplosionSpaceTileFlood"/> and
|
||||
/// <see cref="ExplosionGridTileFlood"/>, each of which contains additional code fro logic specific to grids or space.
|
||||
/// </summary>
|
||||
public abstract class TileExplosion
|
||||
/// <remarks>
|
||||
/// The class stores information about the tiles that the explosion has currently reached, and provides functions to
|
||||
/// perform a neighbor-finding iteration to expand the explosion area. It also has some functionality that allows
|
||||
/// tiles to move between grids/space.
|
||||
/// </remarks>
|
||||
public abstract class ExplosionTileFlood
|
||||
{
|
||||
// Main tile data sets, mapping iterations onto tile lists
|
||||
public Dictionary<int, List<Vector2i>> TileLists = new();
|
||||
@@ -1004,10 +1004,9 @@
|
||||
beepInterval: 1
|
||||
- type: Explosive
|
||||
explosionType: Default
|
||||
devastationRange: 1
|
||||
heavyImpactRange: 2
|
||||
lightImpactRange: 3
|
||||
flashRange: 6
|
||||
maxIntensity: 15
|
||||
intensitySlope: 5
|
||||
totalIntensity: 120
|
||||
- type: ExplodeOnTrigger
|
||||
|
||||
- type: entity
|
||||
|
||||
@@ -30,9 +30,10 @@
|
||||
state: payload-explosive-armed
|
||||
- type: Explosive
|
||||
explosionType: Default
|
||||
devastationRange: 0
|
||||
heavyImpactRange: 2
|
||||
lightImpactRange: 4
|
||||
# same as the standard grenade, but those numbers were also just picked out of a hat.
|
||||
maxIntensity: 10
|
||||
intensitySlope: 3
|
||||
totalIntensity: 120 # about a ~4 tile radius
|
||||
flashRange: 7
|
||||
- type: ExplodeOnTrigger
|
||||
- type: Destructible
|
||||
|
||||
@@ -191,6 +191,7 @@
|
||||
maxIntensity: 40
|
||||
intensitySlope: 6
|
||||
totalIntensity: 200
|
||||
maxTileBreak: 1
|
||||
- type: PointLight
|
||||
radius: 3.5
|
||||
color: orange
|
||||
@@ -209,10 +210,10 @@
|
||||
- type: ExplodeOnTrigger
|
||||
- type: Explosive
|
||||
explosionType: Default
|
||||
devastationRange: 0
|
||||
heavyImpactRange: 0
|
||||
lightImpactRange: 1
|
||||
flashRange: 10
|
||||
maxIntensity: 2 # max 30 per tile
|
||||
intensitySlope: 1
|
||||
totalIntensity: 4 # 60 total damage to distribute over tiles
|
||||
maxTileBreak: 1
|
||||
- type: PointLight
|
||||
radius: 3.5
|
||||
color: orange
|
||||
|
||||
@@ -96,10 +96,9 @@
|
||||
- type: Explosive
|
||||
explosionType: Default
|
||||
# About a 3-3.5 tile radius, strong enough to break reinforced walls near centre.
|
||||
# Currently a big spacing hazzard.
|
||||
totalIntensity: 800
|
||||
intensitySlope: 15
|
||||
maxIntensity: 45
|
||||
maxTileBreak: 1 # for destroying walls, not spacing the hallway
|
||||
- type: ExplodeOnTrigger
|
||||
- type: Damageable
|
||||
damageContainer: Inorganic
|
||||
|
||||
@@ -63,10 +63,10 @@
|
||||
- !type:ExplodeBehavior
|
||||
- type: Explosive
|
||||
explosionType: Default
|
||||
devastationRange: 1
|
||||
heavyImpactRange: 3
|
||||
lightImpactRange: 5
|
||||
flashRange: 6
|
||||
# Same as AME, but numbers still picked from a hat.
|
||||
maxIntensity: 100
|
||||
intensitySlope: 2
|
||||
totalIntensity: 200
|
||||
|
||||
# Base Wallmount Generator
|
||||
|
||||
|
||||
Reference in New Issue
Block a user