Explosion refactor fixes pt1 (#7375)

This commit is contained in:
Leon Friedrich
2022-04-05 19:22:35 +12:00
committed by GitHub
parent 722a408c41
commit 311450864c
15 changed files with 239 additions and 78 deletions

View File

@@ -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)

View File

@@ -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))

View File

@@ -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>

View File

@@ -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,

View File

@@ -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);

View File

@@ -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;
}
}

View File

@@ -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;

View File

@@ -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)

View File

@@ -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;

View File

@@ -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();

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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