]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
Predict damage examine (#40168)
authorslarticodefast <161409025+slarticodefast@users.noreply.github.com>
Fri, 10 Oct 2025 23:23:26 +0000 (01:23 +0200)
committerGitHub <noreply@github.com>
Fri, 10 Oct 2025 23:23:26 +0000 (23:23 +0000)
* predict damage examine

* .

* required true

* nits

---------

Co-authored-by: ArtisticRoomba <145879011+ArtisticRoomba@users.noreply.github.com>
Content.Client/Damage/Systems/DamageOtherOnHitSystem.cs [new file with mode: 0644]
Content.Server/Damage/Components/DamageOtherOnHitComponent.cs [deleted file]
Content.Server/Damage/Systems/DamageOtherOnHitSystem.cs
Content.Server/Weapons/Melee/MeleeWeaponSystem.cs
Content.Server/Weapons/Ranged/Systems/GunSystem.Battery.cs
Content.Shared/Damage/Components/DamageExaminableComponent.cs
Content.Shared/Damage/Components/DamageOtherOnHitComponent.cs [new file with mode: 0644]
Content.Shared/Damage/Events/DamageExamineEvent.cs
Content.Shared/Damage/Systems/SharedDamageOtherOnHitSystem.cs [new file with mode: 0644]
Content.Shared/Weapons/Melee/SharedMeleeWeaponSystem.cs
Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.Battery.cs

diff --git a/Content.Client/Damage/Systems/DamageOtherOnHitSystem.cs b/Content.Client/Damage/Systems/DamageOtherOnHitSystem.cs
new file mode 100644 (file)
index 0000000..a78603c
--- /dev/null
@@ -0,0 +1,5 @@
+using Content.Shared.Damage.Systems;
+
+namespace Content.Client.Damage.Systems;
+
+public sealed class DamageOtherOnHitSystem : SharedDamageOtherOnHitSystem;
diff --git a/Content.Server/Damage/Components/DamageOtherOnHitComponent.cs b/Content.Server/Damage/Components/DamageOtherOnHitComponent.cs
deleted file mode 100644 (file)
index 3123e25..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-using Content.Server.Damage.Systems;
-using Content.Shared.Damage;
-
-namespace Content.Server.Damage.Components
-{
-    [Access(typeof(DamageOtherOnHitSystem))]
-    [RegisterComponent]
-    public sealed partial class DamageOtherOnHitComponent : Component
-    {
-        [DataField("ignoreResistances")]
-        [ViewVariables(VVAccess.ReadWrite)]
-        public bool IgnoreResistances = false;
-
-        [DataField("damage", required: true)]
-        [ViewVariables(VVAccess.ReadWrite)]
-        public DamageSpecifier Damage = default!;
-
-    }
-}
index b1f5365b016eacddd3b2730157c4f6a3c620c67f..10930ca5c9e5c1f177838144be2debfeb1567bd6 100644 (file)
@@ -1,72 +1,54 @@
 using Content.Server.Administration.Logs;
-using Content.Server.Damage.Components;
 using Content.Server.Weapons.Ranged.Systems;
-using Content.Shared.CombatMode.Pacification;
 using Content.Shared.Camera;
 using Content.Shared.Damage;
-using Content.Shared.Damage.Events;
+using Content.Shared.Damage.Components;
 using Content.Shared.Damage.Systems;
 using Content.Shared.Database;
 using Content.Shared.Effects;
 using Content.Shared.Mobs.Components;
 using Content.Shared.Throwing;
-using Content.Shared.Wires;
 using Robust.Shared.Physics.Components;
 using Robust.Shared.Player;
 
-namespace Content.Server.Damage.Systems
-{
-    public sealed class DamageOtherOnHitSystem : EntitySystem
-    {
-        [Dependency] private readonly IAdminLogManager _adminLogger = default!;
-        [Dependency] private readonly GunSystem _guns = default!;
-        [Dependency] private readonly DamageableSystem _damageable = default!;
-        [Dependency] private readonly DamageExamineSystem _damageExamine = default!;
-        [Dependency] private readonly SharedCameraRecoilSystem _sharedCameraRecoil = default!;
-        [Dependency] private readonly SharedColorFlashEffectSystem _color = default!;
+namespace Content.Server.Damage.Systems;
 
-        public override void Initialize()
-        {
-            SubscribeLocalEvent<DamageOtherOnHitComponent, ThrowDoHitEvent>(OnDoHit);
-            SubscribeLocalEvent<DamageOtherOnHitComponent, DamageExamineEvent>(OnDamageExamine);
-            SubscribeLocalEvent<DamageOtherOnHitComponent, AttemptPacifiedThrowEvent>(OnAttemptPacifiedThrow);
-        }
+public sealed class DamageOtherOnHitSystem : SharedDamageOtherOnHitSystem
+{
+    [Dependency] private readonly IAdminLogManager _adminLogger = default!;
+    [Dependency] private readonly GunSystem _guns = default!;
+    [Dependency] private readonly DamageableSystem _damageable = default!;
+    [Dependency] private readonly SharedCameraRecoilSystem _sharedCameraRecoil = default!;
+    [Dependency] private readonly SharedColorFlashEffectSystem _color = default!;
 
-        private void OnDoHit(EntityUid uid, DamageOtherOnHitComponent component, ThrowDoHitEvent args)
-        {
-            if (TerminatingOrDeleted(args.Target))
-                return;
+    public override void Initialize()
+    {
+        base.Initialize();
 
-            var dmg = _damageable.TryChangeDamage(args.Target, component.Damage * _damageable.UniversalThrownDamageModifier, component.IgnoreResistances, origin: args.Component.Thrower);
+        SubscribeLocalEvent<DamageOtherOnHitComponent, ThrowDoHitEvent>(OnDoHit);
+    }
 
-            // Log damage only for mobs. Useful for when people throw spears at each other, but also avoids log-spam when explosions send glass shards flying.
-            if (dmg != null && HasComp<MobStateComponent>(args.Target))
-                _adminLogger.Add(LogType.ThrowHit, $"{ToPrettyString(args.Target):target} received {dmg.GetTotal():damage} damage from collision");
+    private void OnDoHit(EntityUid uid, DamageOtherOnHitComponent component, ThrowDoHitEvent args)
+    {
+        if (TerminatingOrDeleted(args.Target))
+            return;
 
-            if (dmg is { Empty: false })
-            {
-                _color.RaiseEffect(Color.Red, new List<EntityUid>() { args.Target }, Filter.Pvs(args.Target, entityManager: EntityManager));
-            }
+        var dmg = _damageable.TryChangeDamage(args.Target, component.Damage * _damageable.UniversalThrownDamageModifier, component.IgnoreResistances, origin: args.Component.Thrower);
 
-            _guns.PlayImpactSound(args.Target, dmg, null, false);
-            if (TryComp<PhysicsComponent>(uid, out var body) && body.LinearVelocity.LengthSquared() > 0f)
-            {
-                var direction = body.LinearVelocity.Normalized();
-                _sharedCameraRecoil.KickCamera(args.Target, direction);
-            }
-        }
+        // Log damage only for mobs. Useful for when people throw spears at each other, but also avoids log-spam when explosions send glass shards flying.
+        if (dmg != null && HasComp<MobStateComponent>(args.Target))
+            _adminLogger.Add(LogType.ThrowHit, $"{ToPrettyString(args.Target):target} received {dmg.GetTotal():damage} damage from collision");
 
-        private void OnDamageExamine(EntityUid uid, DamageOtherOnHitComponent component, ref DamageExamineEvent args)
+        if (dmg is { Empty: false })
         {
-            _damageExamine.AddDamageExamine(args.Message, _damageable.ApplyUniversalAllModifiers(component.Damage * _damageable.UniversalThrownDamageModifier), Loc.GetString("damage-throw"));
+            _color.RaiseEffect(Color.Red, [args.Target], Filter.Pvs(args.Target, entityManager: EntityManager));
         }
 
-        /// <summary>
-        /// Prevent players with the Pacified status effect from throwing things that deal damage.
-        /// </summary>
-        private void OnAttemptPacifiedThrow(Entity<DamageOtherOnHitComponent> ent, ref AttemptPacifiedThrowEvent args)
+        _guns.PlayImpactSound(args.Target, dmg, null, false);
+        if (TryComp<PhysicsComponent>(uid, out var body) && body.LinearVelocity.LengthSquared() > 0f)
         {
-            args.Cancel("pacified-cannot-throw");
+            var direction = body.LinearVelocity.Normalized();
+            _sharedCameraRecoil.KickCamera(args.Target, direction);
         }
     }
 }
index 1e8f3334ac5cbb972d761553746fab6031245094..31d289217c4cdd7fc697524831fb62aa4298c0f5 100644 (file)
@@ -1,7 +1,5 @@
 using Content.Server.Chat.Systems;
 using Content.Server.Movement.Systems;
-using Content.Shared.Damage.Events;
-using Content.Shared.Damage.Systems;
 using Content.Shared.Effects;
 using Content.Shared.Speech.Components;
 using Content.Shared.Weapons.Melee;
@@ -16,28 +14,14 @@ namespace Content.Server.Weapons.Melee;
 public sealed class MeleeWeaponSystem : SharedMeleeWeaponSystem
 {
     [Dependency] private readonly ChatSystem _chat = default!;
-    [Dependency] private readonly DamageExamineSystem _damageExamine = default!;
     [Dependency] private readonly LagCompensationSystem _lag = default!;
     [Dependency] private readonly SharedColorFlashEffectSystem _color = default!;
 
     public override void Initialize()
     {
         base.Initialize();
-        SubscribeLocalEvent<MeleeSpeechComponent, MeleeHitEvent>(OnSpeechHit);
-        SubscribeLocalEvent<MeleeWeaponComponent, DamageExamineEvent>(OnMeleeExamineDamage);
-    }
-
-    private void OnMeleeExamineDamage(EntityUid uid, MeleeWeaponComponent component, ref DamageExamineEvent args)
-    {
-        if (component.Hidden)
-            return;
 
-        var damageSpec = GetDamage(uid, args.User, component);
-
-        if (damageSpec.Empty)
-            return;
-
-        _damageExamine.AddDamageExamine(args.Message, Damageable.ApplyUniversalAllModifiers(damageSpec), Loc.GetString("damage-melee"));
+        SubscribeLocalEvent<MeleeSpeechComponent, MeleeHitEvent>(OnSpeechHit);
     }
 
     protected override bool ArcRaySuccessful(EntityUid targetUid,
index d697e2bef18d4440e4f8c8e9e944efc40ff93a9e..700a15e1b0132c0a21ade33258a7e7e825485ab7 100644 (file)
@@ -1,12 +1,7 @@
-using Content.Shared.Damage;
-using Content.Shared.Damage.Events;
 using Content.Shared.Power;
 using Content.Shared.PowerCell.Components;
-using Content.Shared.Projectiles;
-using Content.Shared.Weapons.Ranged;
 using Content.Shared.Weapons.Ranged.Components;
 using Content.Shared.Weapons.Ranged.Events;
-using Robust.Shared.Prototypes;
 
 namespace Content.Server.Weapons.Ranged.Systems;
 
@@ -19,13 +14,11 @@ public sealed partial class GunSystem
         // Hitscan
         SubscribeLocalEvent<HitscanBatteryAmmoProviderComponent, ComponentStartup>(OnBatteryStartup);
         SubscribeLocalEvent<HitscanBatteryAmmoProviderComponent, ChargeChangedEvent>(OnBatteryChargeChange);
-        SubscribeLocalEvent<HitscanBatteryAmmoProviderComponent, DamageExamineEvent>(OnBatteryDamageExamine);
         SubscribeLocalEvent<HitscanBatteryAmmoProviderComponent, PowerCellChangedEvent>(OnPowerCellChanged);
 
         // Projectile
         SubscribeLocalEvent<ProjectileBatteryAmmoProviderComponent, ComponentStartup>(OnBatteryStartup);
         SubscribeLocalEvent<ProjectileBatteryAmmoProviderComponent, ChargeChangedEvent>(OnBatteryChargeChange);
-        SubscribeLocalEvent<ProjectileBatteryAmmoProviderComponent, DamageExamineEvent>(OnBatteryDamageExamine);
         SubscribeLocalEvent<ProjectileBatteryAmmoProviderComponent, PowerCellChangedEvent>(OnPowerCellChanged);
     }
 
@@ -73,50 +66,6 @@ public sealed partial class GunSystem
         RaiseLocalEvent(uid, ref updateAmmoEv);
     }
 
-    private void OnBatteryDamageExamine<T>(Entity<T> entity, ref DamageExamineEvent args) where T : BatteryAmmoProviderComponent
-    {
-        var damageSpec = GetDamage(entity.Comp);
-
-        if (damageSpec == null)
-            return;
-
-        var damageType = entity.Comp switch
-        {
-            HitscanBatteryAmmoProviderComponent => Loc.GetString("damage-hitscan"),
-            ProjectileBatteryAmmoProviderComponent => Loc.GetString("damage-projectile"),
-            _ => throw new ArgumentOutOfRangeException(),
-        };
-
-        _damageExamine.AddDamageExamine(args.Message, Damageable.ApplyUniversalAllModifiers(damageSpec), damageType);
-    }
-
-    private DamageSpecifier? GetDamage(BatteryAmmoProviderComponent component)
-    {
-        if (component is ProjectileBatteryAmmoProviderComponent battery)
-        {
-            if (ProtoManager.Index<EntityPrototype>(battery.Prototype).Components
-                .TryGetValue(Factory.GetComponentName<ProjectileComponent>(), out var projectile))
-            {
-                var p = (ProjectileComponent) projectile.Component;
-
-                if (!p.Damage.Empty)
-                {
-                    return p.Damage * Damageable.UniversalProjectileDamageModifier;
-                }
-            }
-
-            return null;
-        }
-
-        if (component is HitscanBatteryAmmoProviderComponent hitscan)
-        {
-            var dmg = ProtoManager.Index<HitscanPrototype>(hitscan.Prototype).Damage;
-            return dmg == null ? dmg : dmg * Damageable.UniversalHitscanDamageModifier;
-        }
-
-        return null;
-    }
-
     protected override void TakeCharge(Entity<BatteryAmmoProviderComponent> entity)
     {
         var ev = new ChangeChargeEvent(-entity.Comp.FireCost);
index a9fa833070b63e3ec7b040dda8d41954f7bc7459..0ac9435bb6717c5b168d91fd95919dafc5f2ebcf 100644 (file)
@@ -2,7 +2,8 @@ using Robust.Shared.GameStates;
 
 namespace Content.Shared.Damage.Components;
 
+/// <summary>
+/// Shows a detailed examine window with this entity's damage stats when examined.
+/// </summary>
 [RegisterComponent, NetworkedComponent]
-public sealed partial class DamageExaminableComponent : Component
-{
-}
+public sealed partial class DamageExaminableComponent : Component;
diff --git a/Content.Shared/Damage/Components/DamageOtherOnHitComponent.cs b/Content.Shared/Damage/Components/DamageOtherOnHitComponent.cs
new file mode 100644 (file)
index 0000000..7728bcf
--- /dev/null
@@ -0,0 +1,24 @@
+using Content.Shared.Damage.Systems;
+
+namespace Content.Shared.Damage.Components;
+
+/// <summary>
+/// Makes this entity deal damage when thrown at something.
+/// </summary>
+[RegisterComponent]
+[Access(typeof(SharedDamageOtherOnHitSystem))]
+public sealed partial class DamageOtherOnHitComponent : Component
+{
+    /// <summary>
+    /// Whether to ignore damage modifiers.
+    /// </summary>
+    [DataField]
+    public bool IgnoreResistances = false;
+
+    /// <summary>
+    /// The damage amount to deal on hit.
+    /// </summary>
+    [DataField(required: true)]
+    public DamageSpecifier Damage = default!;
+
+}
index d3e6175f496fa3d70b3ba5c8d0ee2416ba3daab1..33949cc05257734b3b704727baa964dff2bc8124 100644 (file)
@@ -1,6 +1,10 @@
+using Content.Shared.Damage.Components;
 using Robust.Shared.Utility;
 
 namespace Content.Shared.Damage.Events;
 
+/// <summary>
+/// Raised on an entity with <see cref="DamageExaminableComponent"/> when examined to get the damage values displayed in the examine window.
+/// </summary>
 [ByRefEvent]
 public readonly record struct DamageExamineEvent(FormattedMessage Message, EntityUid User);
diff --git a/Content.Shared/Damage/Systems/SharedDamageOtherOnHitSystem.cs b/Content.Shared/Damage/Systems/SharedDamageOtherOnHitSystem.cs
new file mode 100644 (file)
index 0000000..f17a919
--- /dev/null
@@ -0,0 +1,32 @@
+using Content.Shared.CombatMode.Pacification;
+using Content.Shared.Damage.Components;
+using Content.Shared.Damage.Events;
+
+namespace Content.Shared.Damage.Systems;
+
+public abstract class SharedDamageOtherOnHitSystem : EntitySystem
+{
+    [Dependency] private readonly DamageableSystem _damageable = default!;
+    [Dependency] private readonly DamageExamineSystem _damageExamine = default!;
+
+    public override void Initialize()
+    {
+        base.Initialize();
+
+        SubscribeLocalEvent<DamageOtherOnHitComponent, DamageExamineEvent>(OnDamageExamine);
+        SubscribeLocalEvent<DamageOtherOnHitComponent, AttemptPacifiedThrowEvent>(OnAttemptPacifiedThrow);
+    }
+
+    private void OnDamageExamine(Entity<DamageOtherOnHitComponent> ent, ref DamageExamineEvent args)
+    {
+        _damageExamine.AddDamageExamine(args.Message, _damageable.ApplyUniversalAllModifiers(ent.Comp.Damage * _damageable.UniversalThrownDamageModifier), Loc.GetString("damage-throw"));
+    }
+
+    /// <summary>
+    /// Prevent players with the Pacified status effect from throwing things that deal damage.
+    /// </summary>
+    private void OnAttemptPacifiedThrow(Entity<DamageOtherOnHitComponent> ent, ref AttemptPacifiedThrowEvent args)
+    {
+        args.Cancel("pacified-cannot-throw");
+    }
+}
index 7d0d7577a4b062484dc96f52b11484d1264a8f0e..9bc0b845aee72bfcca4f287b16505228024024b7 100644 (file)
@@ -7,6 +7,7 @@ using Content.Shared.Administration.Components;
 using Content.Shared.Administration.Logs;
 using Content.Shared.CombatMode;
 using Content.Shared.Damage;
+using Content.Shared.Damage.Events;
 using Content.Shared.Damage.Systems;
 using Content.Shared.Database;
 using Content.Shared.FixedPoint;
@@ -63,6 +64,7 @@ public abstract class SharedMeleeWeaponSystem : EntitySystem
     [Dependency] protected readonly SharedPopupSystem PopupSystem = default!;
     [Dependency] protected readonly SharedTransformSystem TransformSystem = default!;
     [Dependency] private   readonly SharedStaminaSystem _stamina = default!;
+    [Dependency] private   readonly DamageExamineSystem _damageExamine = default!;
 
     private const int AttackMask = (int) (CollisionGroup.MobMask | CollisionGroup.Opaque);
 
@@ -83,6 +85,7 @@ public abstract class SharedMeleeWeaponSystem : EntitySystem
         SubscribeLocalEvent<MeleeWeaponComponent, HandSelectedEvent>(OnMeleeSelected);
         SubscribeLocalEvent<MeleeWeaponComponent, ShotAttemptedEvent>(OnMeleeShotAttempted);
         SubscribeLocalEvent<MeleeWeaponComponent, GunShotEvent>(OnMeleeShot);
+        SubscribeLocalEvent<MeleeWeaponComponent, DamageExamineEvent>(OnMeleeExamineDamage);
         SubscribeLocalEvent<BonusMeleeDamageComponent, GetMeleeDamageEvent>(OnGetBonusMeleeDamage);
         SubscribeLocalEvent<BonusMeleeDamageComponent, GetHeavyDamageModifierEvent>(OnGetBonusHeavyDamageModifier);
         SubscribeLocalEvent<BonusMeleeAttackRateComponent, GetMeleeAttackRateEvent>(OnGetBonusMeleeAttackRate);
@@ -95,8 +98,7 @@ public abstract class SharedMeleeWeaponSystem : EntitySystem
         SubscribeAllEvent<StopAttackEvent>(OnStopAttack);
 
 #if DEBUG
-        SubscribeLocalEvent<MeleeWeaponComponent,
-                            MapInitEvent>                   (OnMapInit);
+        SubscribeLocalEvent<MeleeWeaponComponent, MapInitEvent>(OnMapInit);
     }
 
     private void OnMapInit(EntityUid uid, MeleeWeaponComponent component, MapInitEvent args)
@@ -124,6 +126,18 @@ public abstract class SharedMeleeWeaponSystem : EntitySystem
         }
     }
 
+    private void OnMeleeExamineDamage(EntityUid uid, MeleeWeaponComponent component, ref DamageExamineEvent args)
+    {
+        if (component.Hidden)
+            return;
+
+        var damageSpec = GetDamage(uid, args.User, component);
+
+        if (damageSpec.Empty)
+            return;
+
+        _damageExamine.AddDamageExamine(args.Message, Damageable.ApplyUniversalAllModifiers(damageSpec), Loc.GetString("damage-melee"));
+    }
     private void OnMeleeSelected(EntityUid uid, MeleeWeaponComponent component, HandSelectedEvent args)
     {
         var attackRate = GetAttackRate(uid, args.User, component);
index ea865fced663a9ab04ea35c812cdc995ed67da66..cb4e42f3cf0c717cca768ea9d1b955e3fd2ca4c1 100644 (file)
@@ -1,8 +1,12 @@
+using Content.Shared.Damage;
+using Content.Shared.Damage.Events;
 using Content.Shared.Examine;
+using Content.Shared.Projectiles;
 using Content.Shared.Weapons.Ranged.Components;
 using Content.Shared.Weapons.Ranged.Events;
 using Robust.Shared.GameStates;
 using Robust.Shared.Map;
+using Robust.Shared.Prototypes;
 using Robust.Shared.Serialization;
 
 namespace Content.Shared.Weapons.Ranged.Systems;
@@ -18,6 +22,7 @@ public abstract partial class SharedGunSystem
         SubscribeLocalEvent<HitscanBatteryAmmoProviderComponent, TakeAmmoEvent>(OnBatteryTakeAmmo);
         SubscribeLocalEvent<HitscanBatteryAmmoProviderComponent, GetAmmoCountEvent>(OnBatteryAmmoCount);
         SubscribeLocalEvent<HitscanBatteryAmmoProviderComponent, ExaminedEvent>(OnBatteryExamine);
+        SubscribeLocalEvent<HitscanBatteryAmmoProviderComponent, DamageExamineEvent>(OnBatteryDamageExamine);
 
         // Projectile
         SubscribeLocalEvent<ProjectileBatteryAmmoProviderComponent, ComponentGetState>(OnBatteryGetState);
@@ -25,6 +30,7 @@ public abstract partial class SharedGunSystem
         SubscribeLocalEvent<ProjectileBatteryAmmoProviderComponent, TakeAmmoEvent>(OnBatteryTakeAmmo);
         SubscribeLocalEvent<ProjectileBatteryAmmoProviderComponent, GetAmmoCountEvent>(OnBatteryAmmoCount);
         SubscribeLocalEvent<ProjectileBatteryAmmoProviderComponent, ExaminedEvent>(OnBatteryExamine);
+        SubscribeLocalEvent<ProjectileBatteryAmmoProviderComponent, DamageExamineEvent>(OnBatteryDamageExamine);
     }
 
     private void OnBatteryHandleState(EntityUid uid, BatteryAmmoProviderComponent component, ref ComponentHandleState args)
@@ -53,6 +59,51 @@ public abstract partial class SharedGunSystem
         args.PushMarkup(Loc.GetString("gun-battery-examine", ("color", AmmoExamineColor), ("count", component.Shots)));
     }
 
+    private void OnBatteryDamageExamine<T>(Entity<T> entity, ref DamageExamineEvent args) where T : BatteryAmmoProviderComponent
+    {
+        var damageSpec = GetDamage(entity.Comp);
+
+        if (damageSpec == null)
+            return;
+
+        var damageType = entity.Comp switch
+        {
+            HitscanBatteryAmmoProviderComponent => Loc.GetString("damage-hitscan"),
+            ProjectileBatteryAmmoProviderComponent => Loc.GetString("damage-projectile"),
+            _ => throw new ArgumentOutOfRangeException(),
+        };
+
+        _damageExamine.AddDamageExamine(args.Message, Damageable.ApplyUniversalAllModifiers(damageSpec), damageType);
+    }
+
+    private DamageSpecifier? GetDamage(BatteryAmmoProviderComponent component)
+    {
+        if (component is ProjectileBatteryAmmoProviderComponent battery)
+        {
+            if (ProtoManager.Index<EntityPrototype>(battery.Prototype)
+                .Components
+                .TryGetValue(Factory.GetComponentName<ProjectileComponent>(), out var projectile))
+            {
+                var p = (ProjectileComponent)projectile.Component;
+
+                if (!p.Damage.Empty)
+                {
+                    return p.Damage * Damageable.UniversalProjectileDamageModifier;
+                }
+            }
+
+            return null;
+        }
+
+        if (component is HitscanBatteryAmmoProviderComponent hitscan)
+        {
+            var dmg = ProtoManager.Index<HitscanPrototype>(hitscan.Prototype).Damage;
+            return dmg == null ? dmg : dmg * Damageable.UniversalHitscanDamageModifier;
+        }
+
+        return null;
+    }
+
     private void OnBatteryTakeAmmo(EntityUid uid, BatteryAmmoProviderComponent component, TakeAmmoEvent args)
     {
         var shots = Math.Min(args.Shots, component.Shots);