diff --git a/Content.Server/Damage/Systems/DamageOtherOnHitSystem.cs b/Content.Server/Damage/Systems/DamageOtherOnHitSystem.cs index 406cce8bb5..615caed2d8 100644 --- a/Content.Server/Damage/Systems/DamageOtherOnHitSystem.cs +++ b/Content.Server/Damage/Systems/DamageOtherOnHitSystem.cs @@ -3,6 +3,8 @@ using Content.Server.Damage.Components; using Content.Server.Weapons.Ranged.Systems; using Content.Shared.Camera; using Content.Shared.Damage; +using Content.Shared.Damage.Events; +using Content.Shared.Damage.Systems; using Content.Shared.Database; using Content.Shared.Effects; using Content.Shared.Mobs.Components; @@ -15,21 +17,23 @@ namespace Content.Server.Damage.Systems { public sealed class DamageOtherOnHitSystem : EntitySystem { - [Dependency] private readonly DamageableSystem _damageableSystem = default!; [Dependency] private readonly IAdminLogManager _adminLogger = default!; [Dependency] private readonly GunSystem _guns = default!; [Dependency] private readonly SharedCameraRecoilSystem _sharedCameraRecoil = default!; [Dependency] private readonly ThrownItemSystem _thrownItem = default!; [Dependency] private readonly SharedPhysicsSystem _physics = default!; + [Dependency] private readonly DamageableSystem _damageable = default!; + [Dependency] private readonly DamageExamineSystem _damageExamine = default!; public override void Initialize() { SubscribeLocalEvent(OnDoHit); + SubscribeLocalEvent(OnDamageExamine); } private void OnDoHit(EntityUid uid, DamageOtherOnHitComponent component, ThrowDoHitEvent args) { - var dmg = _damageableSystem.TryChangeDamage(args.Target, component.Damage, component.IgnoreResistances, origin: args.Component.Thrower); + var dmg = _damageable.TryChangeDamage(args.Target, component.Damage, component.IgnoreResistances, origin: args.Component.Thrower); // 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(args.Target)) @@ -49,5 +53,10 @@ namespace Content.Server.Damage.Systems _physics.ResetDynamics(physics); } } + + private void OnDamageExamine(EntityUid uid, DamageOtherOnHitComponent component, ref DamageExamineEvent args) + { + _damageExamine.AddDamageExamine(args.Message, component.Damage, Loc.GetString("damage-throw")); + } } } diff --git a/Content.Server/Weapons/Melee/MeleeWeaponSystem.cs b/Content.Server/Weapons/Melee/MeleeWeaponSystem.cs index 9714112895..39c97f4749 100644 --- a/Content.Server/Weapons/Melee/MeleeWeaponSystem.cs +++ b/Content.Server/Weapons/Melee/MeleeWeaponSystem.cs @@ -7,11 +7,11 @@ using Content.Server.Chemistry.Components; using Content.Server.Chemistry.EntitySystems; using Content.Server.CombatMode.Disarm; using Content.Server.Contests; -using Content.Server.Examine; using Content.Server.Movement.Systems; using Content.Shared.Administration.Components; using Content.Shared.Actions.Events; using Content.Shared.CombatMode; +using Content.Shared.Damage.Events; using Content.Shared.Database; using Content.Shared.FixedPoint; using Content.Shared.Hands.Components; @@ -21,7 +21,6 @@ using Content.Shared.Popups; using Content.Shared.Speech.Components; using Content.Shared.StatusEffect; using Content.Shared.Tag; -using Content.Shared.Verbs; using Content.Shared.Weapons.Melee; using Content.Shared.Weapons.Melee.Events; using Robust.Server.Player; @@ -30,8 +29,8 @@ using Robust.Shared.Map; using Robust.Shared.Player; using Robust.Shared.Players; using Robust.Shared.Random; -using Robust.Shared.Utility; using Content.Shared.Effects; +using Content.Shared.Damage.Systems; namespace Content.Server.Weapons.Melee; @@ -40,24 +39,24 @@ public sealed class MeleeWeaponSystem : SharedMeleeWeaponSystem [Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly BloodstreamSystem _bloodstream = default!; [Dependency] private readonly ContestsSystem _contests = default!; - [Dependency] private readonly ExamineSystem _examine = default!; [Dependency] private readonly InventorySystem _inventory = default!; [Dependency] private readonly LagCompensationSystem _lag = default!; [Dependency] private readonly SolutionContainerSystem _solutions = default!; [Dependency] private readonly TagSystem _tag = default!; [Dependency] private readonly ChatSystem _chat = default!; + [Dependency] private readonly DamageExamineSystem _damageExamine = default!; public override void Initialize() { base.Initialize(); SubscribeLocalEvent(OnChemicalInjectorHit); SubscribeLocalEvent(OnSpeechHit); - SubscribeLocalEvent>(OnMeleeExaminableVerb); + SubscribeLocalEvent(OnMeleeExamineDamage); } - private void OnMeleeExaminableVerb(EntityUid uid, MeleeWeaponComponent component, GetVerbsEvent args) + private void OnMeleeExamineDamage(EntityUid uid, MeleeWeaponComponent component, ref DamageExamineEvent args) { - if (!args.CanInteract || !args.CanAccess || component.HideFromExamine) + if (component.HideFromExamine) return; var damageSpec = GetDamage(uid, args.User, component); @@ -65,20 +64,7 @@ public sealed class MeleeWeaponSystem : SharedMeleeWeaponSystem if (damageSpec.Total == FixedPoint2.Zero) return; - var verb = new ExamineVerb() - { - Act = () => - { - var markup = Damageable.GetDamageExamine(damageSpec, Loc.GetString("damage-melee")); - _examine.SendExamineTooltip(args.User, uid, markup, false, false); - }, - Text = Loc.GetString("damage-examinable-verb-text"), - Message = Loc.GetString("damage-examinable-verb-message"), - Category = VerbCategory.Examine, - Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/VerbIcons/smite.svg.192dpi.png")), - }; - - args.Verbs.Add(verb); + _damageExamine.AddDamageExamine(args.Message, damageSpec, Loc.GetString("damage-melee")); } protected override bool ArcRaySuccessful(EntityUid targetUid, Vector2 position, Angle angle, Angle arcWidth, float range, MapId mapId, diff --git a/Content.Server/Weapons/Ranged/Systems/GunSystem.Battery.cs b/Content.Server/Weapons/Ranged/Systems/GunSystem.Battery.cs index fa34dcaf58..ab2553e31b 100644 --- a/Content.Server/Weapons/Ranged/Systems/GunSystem.Battery.cs +++ b/Content.Server/Weapons/Ranged/Systems/GunSystem.Battery.cs @@ -1,12 +1,11 @@ using Content.Server.Power.Components; using Content.Shared.Damage; +using Content.Shared.Damage.Events; using Content.Shared.FixedPoint; using Content.Shared.Projectiles; -using Content.Shared.Verbs; using Content.Shared.Weapons.Ranged; using Content.Shared.Weapons.Ranged.Components; using Robust.Shared.Prototypes; -using Robust.Shared.Utility; namespace Content.Server.Weapons.Ranged.Systems; @@ -19,12 +18,12 @@ public sealed partial class GunSystem // Hitscan SubscribeLocalEvent(OnBatteryStartup); SubscribeLocalEvent(OnBatteryChargeChange); - SubscribeLocalEvent>(OnBatteryExaminableVerb); + SubscribeLocalEvent(OnBatteryDamageExamine); // Projectile SubscribeLocalEvent(OnBatteryStartup); SubscribeLocalEvent(OnBatteryChargeChange); - SubscribeLocalEvent>(OnBatteryExaminableVerb); + SubscribeLocalEvent(OnBatteryDamageExamine); } private void OnBatteryStartup(EntityUid uid, BatteryAmmoProviderComponent component, ComponentStartup args) @@ -60,44 +59,21 @@ public sealed partial class GunSystem UpdateBatteryAppearance(uid, component); } - private void OnBatteryExaminableVerb(EntityUid uid, BatteryAmmoProviderComponent component, GetVerbsEvent args) + private void OnBatteryDamageExamine(EntityUid uid, BatteryAmmoProviderComponent component, ref DamageExamineEvent args) { - if (!args.CanInteract || !args.CanAccess) - return; - var damageSpec = GetDamage(component); if (damageSpec == null) return; - string damageType; - - switch (component) + var damageType = component switch { - case HitscanBatteryAmmoProviderComponent: - damageType = Loc.GetString("damage-hitscan"); - break; - case ProjectileBatteryAmmoProviderComponent: - damageType = Loc.GetString("damage-projectile"); - break; - default: - throw new ArgumentOutOfRangeException(); - } - - var verb = new ExamineVerb() - { - Act = () => - { - var markup = Damageable.GetDamageExamine(damageSpec, damageType); - Examine.SendExamineTooltip(args.User, uid, markup, false, false); - }, - Text = Loc.GetString("damage-examinable-verb-text"), - Message = Loc.GetString("damage-examinable-verb-message"), - Category = VerbCategory.Examine, - Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/VerbIcons/smite.svg.192dpi.png")), + HitscanBatteryAmmoProviderComponent => Loc.GetString("damage-hitscan"), + ProjectileBatteryAmmoProviderComponent => Loc.GetString("damage-projectile"), + _ => throw new ArgumentOutOfRangeException(), }; - args.Verbs.Add(verb); + _damageExamine.AddDamageExamine(args.Message, damageSpec, damageType); } private DamageSpecifier? GetDamage(BatteryAmmoProviderComponent component) diff --git a/Content.Server/Weapons/Ranged/Systems/GunSystem.Cartridges.cs b/Content.Server/Weapons/Ranged/Systems/GunSystem.Cartridges.cs index 497e66901c..6a5dd2d02d 100644 --- a/Content.Server/Weapons/Ranged/Systems/GunSystem.Cartridges.cs +++ b/Content.Server/Weapons/Ranged/Systems/GunSystem.Cartridges.cs @@ -1,11 +1,10 @@ using Content.Shared.Damage; +using Content.Shared.Damage.Events; using Content.Shared.Examine; using Content.Shared.FixedPoint; using Content.Shared.Projectiles; -using Content.Shared.Verbs; using Content.Shared.Weapons.Ranged.Components; using Robust.Shared.Prototypes; -using Robust.Shared.Utility; namespace Content.Server.Weapons.Ranged.Systems; @@ -15,33 +14,17 @@ public sealed partial class GunSystem { base.InitializeCartridge(); SubscribeLocalEvent(OnCartridgeExamine); - SubscribeLocalEvent>(OnCartridgeVerbExamine); + SubscribeLocalEvent(OnCartridgeDamageExamine); } - private void OnCartridgeVerbExamine(EntityUid uid, CartridgeAmmoComponent component, GetVerbsEvent args) + private void OnCartridgeDamageExamine(EntityUid uid, CartridgeAmmoComponent component, ref DamageExamineEvent args) { - if (!args.CanInteract || !args.CanAccess) - return; - var damageSpec = GetProjectileDamage(component.Prototype); if (damageSpec == null) return; - var verb = new ExamineVerb() - { - Act = () => - { - var markup = Damageable.GetDamageExamine(damageSpec, Loc.GetString("damage-projectile")); - _examine.SendExamineTooltip(args.User, uid, markup, false, false); - }, - Text = Loc.GetString("damage-examinable-verb-text"), - Message = Loc.GetString("damage-examinable-verb-message"), - Category = VerbCategory.Examine, - Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/VerbIcons/smite.svg.192dpi.png")), - }; - - args.Verbs.Add(verb); + _damageExamine.AddDamageExamine(args.Message, damageSpec, Loc.GetString("damage-projectile")); } private DamageSpecifier? GetProjectileDamage(string proto) diff --git a/Content.Server/Weapons/Ranged/Systems/GunSystem.cs b/Content.Server/Weapons/Ranged/Systems/GunSystem.cs index 00bbcc92a1..43c9f09464 100644 --- a/Content.Server/Weapons/Ranged/Systems/GunSystem.cs +++ b/Content.Server/Weapons/Ranged/Systems/GunSystem.cs @@ -2,7 +2,6 @@ using System.Linq; using System.Numerics; using Content.Server.Administration.Logs; using Content.Server.Cargo.Systems; -using Content.Server.Examine; using Content.Server.Interaction; using Content.Server.Power.EntitySystems; using Content.Server.Stunnable; @@ -35,13 +34,13 @@ public sealed partial class GunSystem : SharedGunSystem { [Dependency] private readonly IAdminLogManager _adminLogger = default!; [Dependency] private readonly IComponentFactory _factory = default!; - [Dependency] private readonly ExamineSystem _examine = default!; [Dependency] private readonly InteractionSystem _interaction = default!; [Dependency] private readonly PricingSystem _pricing = default!; [Dependency] private readonly StaminaSystem _stamina = default!; [Dependency] private readonly StunSystem _stun = default!; [Dependency] private readonly SharedTransformSystem _transform = default!; [Dependency] private readonly BatterySystem _battery = default!; + [Dependency] private readonly DamageExamineSystem _damageExamine = default!; public const float DamagePitchVariation = SharedMeleeWeaponSystem.DamagePitchVariation; public const float GunClumsyChance = 0.5f; diff --git a/Content.Shared/Damage/Components/DamageExaminableComponent.cs b/Content.Shared/Damage/Components/DamageExaminableComponent.cs new file mode 100644 index 0000000000..4bd019deaf --- /dev/null +++ b/Content.Shared/Damage/Components/DamageExaminableComponent.cs @@ -0,0 +1,8 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared.Damage.Components; + +[RegisterComponent, NetworkedComponent] +public sealed class DamageExaminableComponent : Component +{ +} diff --git a/Content.Shared/Damage/Events/DamageExamineEvent.cs b/Content.Shared/Damage/Events/DamageExamineEvent.cs new file mode 100644 index 0000000000..d3e6175f49 --- /dev/null +++ b/Content.Shared/Damage/Events/DamageExamineEvent.cs @@ -0,0 +1,6 @@ +using Robust.Shared.Utility; + +namespace Content.Shared.Damage.Events; + +[ByRefEvent] +public readonly record struct DamageExamineEvent(FormattedMessage Message, EntityUid User); diff --git a/Content.Shared/Damage/Systems/DamageExamineSystem.cs b/Content.Shared/Damage/Systems/DamageExamineSystem.cs new file mode 100644 index 0000000000..8273719110 --- /dev/null +++ b/Content.Shared/Damage/Systems/DamageExamineSystem.cs @@ -0,0 +1,75 @@ +using Content.Shared.Damage.Components; +using Content.Shared.Damage.Events; +using Content.Shared.Examine; +using Content.Shared.FixedPoint; +using Content.Shared.Verbs; +using Robust.Shared.Utility; + +namespace Content.Shared.Damage.Systems; + +public sealed class DamageExamineSystem : EntitySystem +{ + [Dependency] private readonly ExamineSystemShared _examine = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent>(OnGetExamineVerbs); + } + + private void OnGetExamineVerbs(EntityUid uid, DamageExaminableComponent component, GetVerbsEvent args) + { + if (!args.CanInteract || !args.CanAccess) + return; + + var ev = new DamageExamineEvent(new FormattedMessage(), args.User); + RaiseLocalEvent(uid, ref ev); + if (!ev.Message.IsEmpty) + { + _examine.AddDetailedExamineVerb(args, component, ev.Message, + Loc.GetString("damage-examinable-verb-text"), + "/Textures/Interface/VerbIcons/smite.svg.192dpi.png", + Loc.GetString("damage-examinable-verb-message") + ); + } + } + + public void AddDamageExamine(FormattedMessage message, DamageSpecifier damageSpecifier, string? type = null) + { + var markup = GetDamageExamine(damageSpecifier, type); + if (!message.IsEmpty) + { + message.PushNewline(); + } + message.AddMessage(markup); + } + + /// + /// Retrieves the damage examine values. + /// + private FormattedMessage GetDamageExamine(DamageSpecifier damageSpecifier, string? type = null) + { + var msg = new FormattedMessage(); + + if (string.IsNullOrEmpty(type)) + { + msg.AddMarkup(Loc.GetString("damage-examine")); + } + else + { + msg.AddMarkup(Loc.GetString("damage-examine-type", ("type", type))); + } + + foreach (var damage in damageSpecifier.DamageDict) + { + if (damage.Value != FixedPoint2.Zero) + { + msg.PushNewline(); + msg.AddMarkup(Loc.GetString("damage-value", ("type", damage.Key), ("amount", damage.Value))); + } + } + + return msg; + } +} diff --git a/Content.Shared/Damage/Systems/DamageableSystem.cs b/Content.Shared/Damage/Systems/DamageableSystem.cs index 53923207b2..2e25d66586 100644 --- a/Content.Shared/Damage/Systems/DamageableSystem.cs +++ b/Content.Shared/Damage/Systems/DamageableSystem.cs @@ -29,34 +29,6 @@ namespace Content.Shared.Damage SubscribeLocalEvent(OnRejuvenate); } - /// - /// Retrieves the damage examine values. - /// - public FormattedMessage GetDamageExamine(DamageSpecifier damageSpecifier, string? type = null) - { - var msg = new FormattedMessage(); - - if (string.IsNullOrEmpty(type)) - { - msg.AddMarkup(Loc.GetString("damage-examine")); - } - else - { - msg.AddMarkup(Loc.GetString("damage-examine-type", ("type", type))); - } - - foreach (var damage in damageSpecifier.DamageDict) - { - if (damage.Value != FixedPoint2.Zero) - { - msg.PushNewline(); - msg.AddMarkup(Loc.GetString("damage-value", ("type", damage.Key), ("amount", damage.Value))); - } - } - - return msg; - } - /// /// Initialize a damageable component /// diff --git a/Resources/Locale/en-US/damage/damage-examine.ftl b/Resources/Locale/en-US/damage/damage-examine.ftl index 12e885a78a..974b8fa965 100644 --- a/Resources/Locale/en-US/damage/damage-examine.ftl +++ b/Resources/Locale/en-US/damage/damage-examine.ftl @@ -5,6 +5,8 @@ damage-examinable-verb-message = Examine the damage values. damage-hitscan = hitscan damage-projectile = projectile damage-melee = melee +damage-throw = throw + damage-examine = It does the following damage: -damage-examine-type = It does the following {$type} damage: +damage-examine-type = It does the following [color=cyan]{$type}[/color] damage: damage-value = - [color=red]{$amount}[/color] units of [color=yellow]{$type}[/color]. diff --git a/Resources/Prototypes/Entities/Objects/base_item.yml b/Resources/Prototypes/Entities/Objects/base_item.yml index 0a1fe41198..32325603c1 100644 --- a/Resources/Prototypes/Entities/Objects/base_item.yml +++ b/Resources/Prototypes/Entities/Objects/base_item.yml @@ -43,6 +43,7 @@ drawdepth: Items noRot: false - type: Pullable + - type: DamageExaminable - type: entity name: "storage item"