]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
Clean up some parts of ExplosionSystem (#40485)
authorLeon Friedrich <60421075+ElectroJr@users.noreply.github.com>
Sun, 28 Sep 2025 16:23:40 +0000 (05:23 +1300)
committerGitHub <noreply@github.com>
Sun, 28 Sep 2025 16:23:40 +0000 (16:23 +0000)
* Clean up some parts of ExplosionSystem

* Update Content.Shared/Damage/DamageSpecifier.cs

Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com>
* Review

---------

Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com>
Content.Server/Atmos/EntitySystems/AirtightSystem.cs
Content.Server/Explosion/EntitySystems/ExplosionSystem.Airtight.cs
Content.Server/Explosion/EntitySystems/ExplosionSystem.GridMap.cs
Content.Server/Explosion/EntitySystems/ExplosionSystem.Processing.cs
Content.Server/Explosion/EntitySystems/ExplosionSystem.TileFill.cs
Content.Server/Explosion/EntitySystems/ExplosionSystem.cs
Content.Shared/Damage/Components/DamageableComponent.cs
Content.Shared/Damage/DamageSpecifier.cs
Content.Shared/Damage/Systems/DamageableSystem.cs
Content.Shared/Explosion/EntitySystems/SharedExplosionSystem.cs

index 4a108b38a4ee88e571eb4c601fc655cfd0c13950..431707c83503831933d37d38a833e5d0e52c02f0 100644 (file)
@@ -123,7 +123,7 @@ namespace Content.Server.Atmos.EntitySystems
         public void InvalidatePosition(Entity<MapGridComponent?> grid, Vector2i pos)
         {
             var query = GetEntityQuery<AirtightComponent>();
-            _explosionSystem.UpdateAirtightMap(grid, pos, grid, query);
+            _explosionSystem.UpdateAirtightMap(grid, pos, grid);
             _atmosphereSystem.InvalidateTile(grid.Owner, pos);
         }
 
index af004e112e95fdf8e7fcd159c4dae31caaaa2a2c..3d55a7e8230659531c9cd1996df488f09c4b0a1b 100644 (file)
@@ -11,8 +11,6 @@ namespace Content.Server.Explosion.EntitySystems;
 
 public sealed partial class ExplosionSystem
 {
-    [Dependency] private readonly DestructibleSystem _destructibleSystem = default!;
-
     private readonly Dictionary<string, int> _explosionTypes = new();
 
     private void InitAirtightMap()
@@ -26,6 +24,8 @@ public sealed partial class ExplosionSystem
         int index = 0;
         foreach (var prototype in _prototypeManager.EnumeratePrototypes<ExplosionPrototype>())
         {
+            // TODO EXPLOSION
+            // just make this a field on the prototype
             _explosionTypes.Add(prototype.ID, index);
             index++;
         }
@@ -42,10 +42,10 @@ public sealed partial class ExplosionSystem
     // indices to this tile-data struct.
     private Dictionary<EntityUid, Dictionary<Vector2i, TileData>> _airtightMap = new();
 
-    public void UpdateAirtightMap(EntityUid gridId, Vector2i tile, MapGridComponent? grid = null, EntityQuery<AirtightComponent>? query = null)
+    public void UpdateAirtightMap(EntityUid gridId, Vector2i tile, MapGridComponent? grid = null)
     {
         if (Resolve(gridId, ref grid, false))
-            UpdateAirtightMap(gridId, grid, tile, query);
+            UpdateAirtightMap(gridId, grid, tile);
     }
 
     /// <summary>
@@ -58,7 +58,7 @@ public sealed partial class ExplosionSystem
     ///     something like a normal and a reinforced windoor on the same tile. But given that this is a pretty rare
     ///     occurrence, I am fine with this.
     /// </remarks>
-    public void UpdateAirtightMap(EntityUid gridId, MapGridComponent grid, Vector2i tile, EntityQuery<AirtightComponent>? query = null)
+    public void UpdateAirtightMap(EntityUid gridId, MapGridComponent grid, Vector2i tile)
     {
         var tolerance = new float[_explosionTypes.Count];
         var blockedDirections = AtmosDirection.Invalid;
@@ -66,18 +66,15 @@ public sealed partial class ExplosionSystem
         if (!_airtightMap.ContainsKey(gridId))
             _airtightMap[gridId] = new();
 
-        query ??= GetEntityQuery<AirtightComponent>();
-        var damageQuery = GetEntityQuery<DamageableComponent>();
-        var destructibleQuery = GetEntityQuery<DestructibleComponent>();
-        var anchoredEnumerator = _mapSystem.GetAnchoredEntitiesEnumerator(gridId, grid, tile);
+        var anchoredEnumerator = _map.GetAnchoredEntitiesEnumerator(gridId, grid, tile);
 
         while (anchoredEnumerator.MoveNext(out var uid))
         {
-            if (!query.Value.TryGetComponent(uid, out var airtight) || !airtight.AirBlocked)
+            if (!_airtightQuery.TryGetComponent(uid, out var airtight) || !airtight.AirBlocked)
                 continue;
 
             blockedDirections |= airtight.AirBlockedDirection;
-            var entityTolerances = GetExplosionTolerance(uid.Value, damageQuery, destructibleQuery);
+            var entityTolerances = GetExplosionTolerance(uid.Value);
             for (var i = 0; i < tolerance.Length; i++)
             {
                 tolerance[i] = Math.Max(tolerance[i], entityTolerances[i]);
@@ -105,28 +102,25 @@ public sealed partial class ExplosionSystem
         if (!TryComp<MapGridComponent>(transform.GridUid, out var grid))
             return;
 
-        UpdateAirtightMap(transform.GridUid.Value, grid, _mapSystem.CoordinatesToTile(transform.GridUid.Value, grid, transform.Coordinates));
+        UpdateAirtightMap(transform.GridUid.Value, grid, _map.CoordinatesToTile(transform.GridUid.Value, grid, transform.Coordinates));
     }
 
     /// <summary>
     ///     Return a dictionary that specifies how intense a given explosion type needs to be in order to destroy an entity.
     /// </summary>
-    public float[] GetExplosionTolerance(
-        EntityUid uid,
-        EntityQuery<DamageableComponent> damageQuery,
-        EntityQuery<DestructibleComponent> destructibleQuery)
+    public float[] GetExplosionTolerance(EntityUid uid)
     {
         // How much total damage is needed to destroy this entity? This also includes "break" behaviors. This ASSUMES
         // that this will result in a non-airtight entity.Entities that ONLY break via construction graph node changes
         // are currently effectively "invincible" as far as this is concerned. This really should be done more rigorously.
         var totalDamageTarget = FixedPoint2.MaxValue;
-        if (destructibleQuery.TryGetComponent(uid, out var destructible))
+        if (_destructibleQuery.TryGetComponent(uid, out var destructible))
         {
             totalDamageTarget = _destructibleSystem.DestroyedAt(uid, destructible);
         }
 
         var explosionTolerance = new float[_explosionTypes.Count];
-        if (totalDamageTarget == FixedPoint2.MaxValue || !damageQuery.TryGetComponent(uid, out var damageable))
+        if (totalDamageTarget == FixedPoint2.MaxValue || !_damageableQuery.TryGetComponent(uid, out var damageable))
         {
             for (var i = 0; i < explosionTolerance.Length; i++)
             {
@@ -139,9 +133,12 @@ public sealed partial class ExplosionSystem
         // does not support entities dynamically changing explosive resistances (e.g. via clothing). But these probably
         // shouldn't be airtight structures anyways....
 
+        var mod = _damageableSystem.UniversalAllDamageModifier * _damageableSystem.UniversalExplosionDamageModifier;
         foreach (var (id, index) in _explosionTypes)
         {
-            if (!_prototypeManager.TryIndex<ExplosionPrototype>(id, out var explosionType))
+            // TODO EXPLOSION SYSTEM
+            // cache explosion type damage.
+            if (!_prototypeManager.Resolve(id, out ExplosionPrototype? explosionType))
                 continue;
 
             // evaluate the damage that this damage type would do to this entity
@@ -151,10 +148,15 @@ public sealed partial class ExplosionSystem
                 if (!damageable.Damage.DamageDict.ContainsKey(type))
                     continue;
 
+                // TODO EXPLOSION SYSTEM
+                // add a variant of the event that gets raised once, instead of once per prototype.
+                // Or better yet, just calculate this manually w/o the event.
+                // The event mainly exists for indirect resistances via things like inventory & clothing
+                // But this shouldn't matter for airtight entities.
                 var ev = new GetExplosionResistanceEvent(explosionType.ID);
                 RaiseLocalEvent(uid, ref ev);
 
-                damagePerIntensity += value * Math.Max(0, ev.DamageCoefficient);
+                damagePerIntensity += value * mod * Math.Max(0, ev.DamageCoefficient);
             }
 
             explosionTolerance[index] = damagePerIntensity > 0
@@ -179,4 +181,16 @@ public sealed partial class ExplosionSystem
         public float[] ExplosionTolerance;
         public AtmosDirection BlockedDirections = AtmosDirection.Invalid;
     }
+
+    public override void ReloadMap()
+    {
+        foreach (var(grid, dict) in _airtightMap)
+        {
+            var comp = Comp<MapGridComponent>(grid);
+            foreach (var index in dict.Keys)
+            {
+                UpdateAirtightMap(grid, comp, index);
+            }
+        }
+    }
 }
index 8515e1af42cfc8efa5c6807f71f7c5a4545e6e77..5c032d5c82e4e4e9c3ce8c8ffb9db638ea8d8bad 100644 (file)
@@ -258,7 +258,7 @@ public sealed partial class ExplosionSystem
                 {
                     var neighbourIndex = change.GridIndices + NeighbourVectors[i];
 
-                    if (_mapSystem.TryGetTileRef(ev.Entity, grid, neighbourIndex, out var neighbourTile) && !neighbourTile.Tile.IsEmpty)
+                    if (_map.TryGetTileRef(ev.Entity, grid, neighbourIndex, out var neighbourTile) && !neighbourTile.Tile.IsEmpty)
                     {
                         var oppositeDirection = (NeighborFlag)(1 << ((i + 4) % 8));
                         edges[neighbourIndex] = edges.GetValueOrDefault(neighbourIndex) | oppositeDirection;
@@ -307,7 +307,7 @@ public sealed partial class ExplosionSystem
         spaceDirections = NeighborFlag.Invalid;
         for (var i = 0; i < NeighbourVectors.Length; i++)
         {
-            if (!_mapSystem.TryGetTileRef(grid, grid.Comp, index + NeighbourVectors[i], out var neighborTile) || neighborTile.Tile.IsEmpty)
+            if (!_map.TryGetTileRef(grid, grid.Comp, index + NeighbourVectors[i], out var neighborTile) || neighborTile.Tile.IsEmpty)
                 spaceDirections |= (NeighborFlag) (1 << i);
         }
 
index b61f78e909a9f75a38739a7a784614969b7c52bf..263fdabf98fc26d6436c6061aac4ff9dc6ce4097 100644 (file)
@@ -27,8 +27,6 @@ namespace Content.Server.Explosion.EntitySystems;
 
 public sealed partial class ExplosionSystem
 {
-    [Dependency] private readonly FlammableSystem _flammableSystem = default!;
-
     /// <summary>
     ///     Used to limit explosion processing time. See <see cref="MaxProcessingTime"/>.
     /// </summary>
@@ -446,7 +444,7 @@ public sealed partial class ExplosionSystem
             GetEntitiesToDamage(uid, originalDamage, id);
             foreach (var (entity, damage) in _toDamage)
             {
-                if (damage.GetTotal() > 0 && TryComp<ActorComponent>(entity, out var actorComponent))
+                if (_actorQuery.HasComp(entity))
                 {
                     // Log damage to player entities only, cause this will create a massive amount of log spam otherwise.
                     if (cause != null)
@@ -461,7 +459,7 @@ public sealed partial class ExplosionSystem
                 }
 
                 // TODO EXPLOSIONS turn explosions into entities, and pass the the entity in as the damage origin.
-                _damageableSystem.TryChangeDamage(entity, damage * _damageableSystem.UniversalExplosionDamageModifier, ignoreResistances: true);
+                _damageableSystem.TryChangeDamage(entity, damage, ignoreResistances: true, ignoreGlobalModifiers: true);
 
             }
         }
@@ -668,6 +666,7 @@ sealed class Explosion
     private readonly IEntityManager _entMan;
     private readonly ExplosionSystem _system;
     private readonly SharedMapSystem _mapSystem;
+    private readonly DamageableSystem _damageable;
 
     public readonly EntityUid VisualEnt;
 
@@ -688,10 +687,10 @@ sealed class Explosion
         int maxTileBreak,
         bool canCreateVacuum,
         IEntityManager entMan,
-        IMapManager mapMan,
         EntityUid visualEnt,
         EntityUid? cause,
-        SharedMapSystem mapSystem)
+        SharedMapSystem mapSystem,
+        DamageableSystem damageable)
     {
         VisualEnt = visualEnt;
         Cause = cause;
@@ -706,6 +705,7 @@ sealed class Explosion
         _maxTileBreak = maxTileBreak;
         _canCreateVacuum = canCreateVacuum;
         _entMan = entMan;
+        _damageable = damageable;
 
         _xformQuery = entMan.GetEntityQuery<TransformComponent>();
         _physicsQuery = entMan.GetEntityQuery<PhysicsComponent>();
@@ -760,8 +760,10 @@ sealed class Explosion
                 _expectedDamage = ExplosionType.DamagePerIntensity * _currentIntensity;
             }
 #endif
-
-            _currentDamage = ExplosionType.DamagePerIntensity * _currentIntensity;
+            var modifier = _currentIntensity
+                           * _damageable.UniversalExplosionDamageModifier
+                           * _damageable.UniversalAllDamageModifier;
+            _currentDamage = ExplosionType.DamagePerIntensity * modifier;
 
             // only throw if either the explosion is small, or if this is the outer ring of a large explosion.
             var doThrow = Area < _system.ThrowLimit || CurrentIteration > _tileSetIntensity.Count - 6;
index cee694886baea10750de2d7d4ccf680a45358e6c..ac539da213d7cfdb1f98bf8e8b8df3b273c1d12a 100644 (file)
@@ -52,7 +52,7 @@ public sealed partial class ExplosionSystem
 
         // get the epicenter tile indices
         if (_mapManager.TryFindGridAt(epicenter, out var gridUid, out var candidateGrid) &&
-            _mapSystem.TryGetTileRef(gridUid, candidateGrid, _mapSystem.WorldToTile(gridUid, candidateGrid, epicenter.Position), out var tileRef) &&
+            _map.TryGetTileRef(gridUid, candidateGrid, _map.WorldToTile(gridUid, candidateGrid, epicenter.Position), out var tileRef) &&
             !tileRef.Tile.IsEmpty)
         {
             epicentreGrid = gridUid;
@@ -62,7 +62,7 @@ public sealed partial class ExplosionSystem
         {
             // reference grid defines coordinate system that the explosion in space will use
             var gridComp = Comp<MapGridComponent>(referenceGrid.Value);
-            initialTile = _mapSystem.WorldToTile(referenceGrid.Value, gridComp, epicenter.Position);
+            initialTile = _map.WorldToTile(referenceGrid.Value, gridComp, epicenter.Position);
         }
         else
         {
index b459f5c70f59c0413f7b1d102d57fe7cf29c93e0..67dbe97b290f009406164a38e7dc12d444cf870b 100644 (file)
@@ -2,6 +2,8 @@ using System.Linq;
 using System.Numerics;
 using Content.Server.Administration.Logs;
 using Content.Server.Atmos.Components;
+using Content.Server.Atmos.EntitySystems;
+using Content.Server.Destructible;
 using Content.Server.NodeContainer.EntitySystems;
 using Content.Server.NPC.Pathfinding;
 using Content.Shared.Atmos.Components;
@@ -16,7 +18,6 @@ using Content.Shared.GameTicking;
 using Content.Shared.Inventory;
 using Content.Shared.Projectiles;
 using Content.Shared.Throwing;
-using Robust.Server.GameObjects;
 using Robust.Server.GameStates;
 using Robust.Server.Player;
 using Robust.Shared.Audio.Systems;
@@ -38,23 +39,28 @@ public sealed partial class ExplosionSystem : SharedExplosionSystem
     [Dependency] private readonly IPrototypeManager _prototypeManager = default!;
     [Dependency] private readonly IConfigurationManager _cfg = default!;
     [Dependency] private readonly IPlayerManager _playerManager = default!;
+    [Dependency] private readonly IAdminLogManager _adminLogger = default!;
 
-    [Dependency] private readonly MapSystem _mapSystem = default!;
     [Dependency] private readonly SharedAppearanceSystem _appearance = default!;
     [Dependency] private readonly DamageableSystem _damageableSystem = default!;
     [Dependency] private readonly NodeGroupSystem _nodeGroupSystem = default!;
     [Dependency] private readonly PathfindingSystem _pathfindingSystem = default!;
     [Dependency] private readonly SharedCameraRecoilSystem _recoilSystem = default!;
-    [Dependency] private readonly IAdminLogManager _adminLogger = default!;
     [Dependency] private readonly ThrowingSystem _throwingSystem = default!;
     [Dependency] private readonly PvsOverrideSystem _pvsSys = default!;
     [Dependency] private readonly SharedAudioSystem _audio = default!;
     [Dependency] private readonly SharedTransformSystem _transformSystem = default!;
     [Dependency] private readonly SharedMapSystem _map = default!;
+    [Dependency] private readonly FlammableSystem _flammableSystem = default!;
+    [Dependency] private readonly DestructibleSystem _destructibleSystem = default!;
 
     private EntityQuery<FlammableComponent> _flammableQuery;
     private EntityQuery<PhysicsComponent> _physicsQuery;
     private EntityQuery<ProjectileComponent> _projectileQuery;
+    private EntityQuery<ActorComponent> _actorQuery;
+    private EntityQuery<DestructibleComponent> _destructibleQuery;
+    private EntityQuery<DamageableComponent> _damageableQuery;
+    private EntityQuery<AirtightComponent> _airtightQuery;
 
     /// <summary>
     ///     "Tile-size" for space when there are no nearby grids to use as a reference.
@@ -93,6 +99,10 @@ public sealed partial class ExplosionSystem : SharedExplosionSystem
         _flammableQuery = GetEntityQuery<FlammableComponent>();
         _physicsQuery = GetEntityQuery<PhysicsComponent>();
         _projectileQuery = GetEntityQuery<ProjectileComponent>();
+        _actorQuery = GetEntityQuery<ActorComponent>();
+        _destructibleQuery = GetEntityQuery<DestructibleComponent>();
+        _damageableQuery = GetEntityQuery<DamageableComponent>();
+        _airtightQuery = GetEntityQuery<AirtightComponent>();
     }
 
     private void OnReset(RoundRestartCleanupEvent ev)
@@ -317,7 +327,7 @@ public sealed partial class ExplosionSystem : SharedExplosionSystem
     private Explosion? SpawnExplosion(QueuedExplosion queued)
     {
         var pos = queued.Epicenter;
-        if (!_mapSystem.MapExists(pos.MapId))
+        if (!_map.MapExists(pos.MapId))
             return null;
 
         var results = GetExplosionTiles(pos, queued.Proto.ID, queued.TotalIntensity, queued.Slope, queued.MaxTileIntensity);
@@ -333,7 +343,7 @@ public sealed partial class ExplosionSystem : SharedExplosionSystem
         CameraShake(iterationIntensity.Count * 4f, pos, queued.TotalIntensity);
 
         //For whatever bloody reason, sound system requires ENTITY coordinates.
-        var mapEntityCoords = _transformSystem.ToCoordinates(_mapSystem.GetMap(pos.MapId), pos);
+        var mapEntityCoords = _transformSystem.ToCoordinates(_map.GetMap(pos.MapId), pos);
 
         // play sound.
         // for the normal audio, we want everyone in pvs range
@@ -376,10 +386,10 @@ public sealed partial class ExplosionSystem : SharedExplosionSystem
             queued.MaxTileBreak,
             queued.CanCreateVacuum,
             EntityManager,
-            _mapManager,
             visualEnt,
             queued.Cause,
-            _map);
+            _map,
+            _damageableSystem);
     }
 
     private void CameraShake(float range, MapCoordinates epicenter, float totalIntensity)
index 9e4e26e4226abece73c0411ad78ba8177e4ee2b6..1d290181ec5451df4d1c96c11a3bd0afecebbcef 100644 (file)
@@ -44,7 +44,7 @@ namespace Content.Shared.Damage
         /// <remarks>
         ///     If this data-field is specified, this allows damageable components to be initialized with non-zero damage.
         /// </remarks>
-        [DataField(readOnly: true)] //todo remove this readonly when implementing writing to damagespecifier
+        [DataField(readOnly: true)] // TODO FULL GAME SAVE
         public DamageSpecifier Damage = new();
 
         /// <summary>
index 00bd416e1f77fdb3b01568d25d88f06b5ed82cd3..7bf921baa2965ed062d5b20e1f23da11a0210af7 100644 (file)
@@ -20,6 +20,11 @@ namespace Content.Shared.Damage
     [DataDefinition, Serializable, NetSerializable]
     public sealed partial class DamageSpecifier : IEquatable<DamageSpecifier>
     {
+        // For the record I regret so many of the decisions i made when rewriting damageable
+        // Why is it just shitting out dictionaries left and right
+        // One day Arrays, stackalloc spans, and SIMD will save the day.
+        // TODO DAMAGEABLE REFACTOR
+
         // These exist solely so the wiki works. Please do not touch them or use them.
         [JsonPropertyName("types")]
         [DataField("types", customTypeSerializer: typeof(PrototypeIdDictionarySerializer<FixedPoint2, DamageTypePrototype>))]
index f3a4f378301955f89e5149b22c30527555d63658..b849227156b56633f896e8b1aa9db963bada52f5 100644 (file)
@@ -2,9 +2,9 @@ using System.Linq;
 using Content.Shared.CCVar;
 using Content.Shared.Chemistry;
 using Content.Shared.Damage.Prototypes;
+using Content.Shared.Explosion.EntitySystems;
 using Content.Shared.FixedPoint;
 using Content.Shared.Inventory;
-using Content.Shared.Mind.Components;
 using Content.Shared.Mobs.Components;
 using Content.Shared.Mobs.Systems;
 using Content.Shared.Radiation.Events;
@@ -25,10 +25,10 @@ namespace Content.Shared.Damage
         [Dependency] private readonly MobThresholdSystem _mobThreshold = default!;
         [Dependency] private readonly IConfigurationManager _config = default!;
         [Dependency] private readonly SharedChemistryGuideDataSystem _chemistryGuideData = default!;
+        [Dependency] private readonly SharedExplosionSystem _explosion = default!;
 
         private EntityQuery<AppearanceComponent> _appearanceQuery;
         private EntityQuery<DamageableComponent> _damageableQuery;
-        private EntityQuery<MindContainerComponent> _mindContainerQuery;
 
         public float UniversalAllDamageModifier { get; private set; } = 1f;
         public float UniversalAllHealModifier { get; private set; } = 1f;
@@ -52,7 +52,6 @@ namespace Content.Shared.Damage
 
             _appearanceQuery = GetEntityQuery<AppearanceComponent>();
             _damageableQuery = GetEntityQuery<DamageableComponent>();
-            _mindContainerQuery = GetEntityQuery<MindContainerComponent>();
 
             // Damage modifier CVars are updated and stored here to be queried in other systems.
             // Note that certain modifiers requires reloading the guidebook.
@@ -60,6 +59,7 @@ namespace Content.Shared.Damage
             {
                 UniversalAllDamageModifier = value;
                 _chemistryGuideData.ReloadAllReagentPrototypes();
+                _explosion.ReloadMap();
             }, true);
             Subs.CVar(_config, CCVars.PlaytestAllHealModifier, value =>
             {
@@ -80,7 +80,11 @@ namespace Content.Shared.Damage
                  UniversalReagentHealModifier = value;
                  _chemistryGuideData.ReloadAllReagentPrototypes();
             }, true);
-            Subs.CVar(_config, CCVars.PlaytestExplosionDamageModifier, value => UniversalExplosionDamageModifier = value, true);
+            Subs.CVar(_config, CCVars.PlaytestExplosionDamageModifier, value =>
+            {
+                UniversalExplosionDamageModifier = value;
+                _explosion.ReloadMap();
+            }, true);
             Subs.CVar(_config, CCVars.PlaytestThrownDamageModifier, value => UniversalThrownDamageModifier = value, true);
             Subs.CVar(_config, CCVars.PlaytestTopicalsHealModifier, value => UniversalTopicalsHealModifier = value, true);
             Subs.CVar(_config, CCVars.PlaytestMobDamageModifier, value => UniversalMobDamageModifier = value, true);
@@ -156,6 +160,9 @@ namespace Content.Shared.Damage
                 var data = new DamageVisualizerGroupData(component.DamagePerGroup.Keys.ToList());
                 _appearance.SetData(uid, DamageVisualizerKeys.DamageUpdateGroups, data, appearance);
             }
+
+            // TODO DAMAGE
+            // byref struct event.
             RaiseLocalEvent(uid, new DamageChangedEvent(component, damageDelta, interruptsDoAfters, origin));
         }
 
@@ -171,12 +178,24 @@ namespace Content.Shared.Damage
         ///     Returns a <see cref="DamageSpecifier"/> with information about the actual damage changes. This will be
         ///     null if the user had no applicable components that can take damage.
         /// </returns>
-        public DamageSpecifier? TryChangeDamage(EntityUid? uid, DamageSpecifier damage, bool ignoreResistances = false,
-            bool interruptsDoAfters = true, DamageableComponent? damageable = null, EntityUid? origin = null)
+        /// <param name="ignoreResistances">If true, this will ignore the entity's damage modifier (<see cref="DamageableComponent.DamageModifierSetId"/> and skip raising a <see cref="DamageModifyEvent"/>.</param>
+        /// <param name="interruptsDoAfters">Whether the damage should cancel any damage sensitive do-afters</param>
+        /// <param name="origin">The entity that is causing this damage</param>
+        /// <param name="ignoreGlobalModifiers">If true, this will skip over applying the universal damage modifiers (see <see cref="ApplyUniversalAllModifiers"/>).</param>
+        /// <returns></returns>
+        public DamageSpecifier? TryChangeDamage(
+            EntityUid? uid,
+            DamageSpecifier damage,
+            bool ignoreResistances = false,
+            bool interruptsDoAfters = true,
+            DamageableComponent? damageable = null,
+            EntityUid? origin = null,
+            bool ignoreGlobalModifiers = false)
         {
             if (!uid.HasValue || !_damageableQuery.Resolve(uid.Value, ref damageable, false))
             {
                 // TODO BODY SYSTEM pass damage onto body system
+                // BOBBY WHEN?
                 return null;
             }
 
@@ -195,13 +214,13 @@ namespace Content.Shared.Damage
             if (!ignoreResistances)
             {
                 if (damageable.DamageModifierSetId != null &&
-                    _prototypeManager.Resolve<DamageModifierSetPrototype>(damageable.DamageModifierSetId, out var modifierSet))
+                    _prototypeManager.Resolve(damageable.DamageModifierSetId, out var modifierSet))
                 {
-                    // TODO DAMAGE PERFORMANCE
-                    // use a local private field instead of creating a new dictionary here..
                     damage = DamageSpecifier.ApplyModifierSet(damage, modifierSet);
                 }
 
+                // TODO DAMAGE
+                // byref struct event.
                 var ev = new DamageModifyEvent(damage, origin);
                 RaiseLocalEvent(uid.Value, ev);
                 damage = ev.Damage;
@@ -212,11 +231,9 @@ namespace Content.Shared.Damage
                 }
             }
 
-            damage = ApplyUniversalAllModifiers(damage);
+            if (!ignoreGlobalModifiers)
+                damage = ApplyUniversalAllModifiers(damage);
 
-            // TODO DAMAGE PERFORMANCE
-            // Consider using a local private field instead of creating a new dictionary here.
-            // Would need to check that nothing ever tries to cache the delta.
             var delta = new DamageSpecifier();
             delta.DamageDict.EnsureCapacity(damage.DamageDict.Count);
 
index d6053c9c3c72a270e7c4c1c2242b9eca50c364c6..ce05cd3eb87ae539036505f588c0fcc01ae2d210 100644 (file)
@@ -69,4 +69,11 @@ public abstract class SharedExplosionSystem : EntitySystem
                                         bool addLog = true)
     {
     }
+
+    /// <summary>
+    /// This forces the explosion system to re-calculate the explosion intensity required to destroy all airtight entities.
+    /// </summary>
+    public virtual void ReloadMap()
+    {
+    }
 }