--- /dev/null
+using Content.Shared.Damage.Systems;
+
+namespace Content.Client.Damage.Systems;
+
+public sealed class DamageOtherOnHitSystem : SharedDamageOtherOnHitSystem;
+++ /dev/null
-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!;
-
- }
-}
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);
}
}
}
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;
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,
-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;
// 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);
}
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);
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;
--- /dev/null
+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!;
+
+}
+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);
--- /dev/null
+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");
+ }
+}
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;
[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);
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);
SubscribeAllEvent<StopAttackEvent>(OnStopAttack);
#if DEBUG
- SubscribeLocalEvent<MeleeWeaponComponent,
- MapInitEvent> (OnMapInit);
+ SubscribeLocalEvent<MeleeWeaponComponent, MapInitEvent>(OnMapInit);
}
private void OnMapInit(EntityUid uid, MeleeWeaponComponent component, MapInitEvent args)
}
}
+ 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);
+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;
SubscribeLocalEvent<HitscanBatteryAmmoProviderComponent, TakeAmmoEvent>(OnBatteryTakeAmmo);
SubscribeLocalEvent<HitscanBatteryAmmoProviderComponent, GetAmmoCountEvent>(OnBatteryAmmoCount);
SubscribeLocalEvent<HitscanBatteryAmmoProviderComponent, ExaminedEvent>(OnBatteryExamine);
+ SubscribeLocalEvent<HitscanBatteryAmmoProviderComponent, DamageExamineEvent>(OnBatteryDamageExamine);
// Projectile
SubscribeLocalEvent<ProjectileBatteryAmmoProviderComponent, ComponentGetState>(OnBatteryGetState);
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)
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);