From 2f072707449288869f8897a83f1a32b9393d5017 Mon Sep 17 00:00:00 2001 From: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> Date: Fri, 9 Sep 2022 09:08:14 +1000 Subject: [PATCH] Add examines for damage values (#11090) * Add examines for damage values Even immersive sims still give you values. We should also do this for armour so people don't have to yml dive and so the general public actually know the balance of things. * Slightly better * Cleanup --- .../Weapons/Melee/MeleeWeaponSystem.cs | 1 + .../Weapon/Melee/MeleeWeaponSystem.cs | 45 ++++++++++- .../Ranged/Systems/GunSystem.Battery.cs | 74 ++++++++++++++++++ .../Ranged/Systems/GunSystem.Cartridges.cs | 76 +++++++++++++++++++ .../Weapon/Ranged/Systems/GunSystem.cs | 3 + .../Damage/Systems/DamageableSystem.cs | 26 +++++++ .../Systems/SharedGunSystem.Cartridges.cs | 2 +- .../Weapons/Ranged/Systems/SharedGunSystem.cs | 1 + .../Locale/en-US/damage/damage-examine.ftl | 10 +++ Resources/Locale/en-US/weapons/ranged/gun.ftl | 6 +- 10 files changed, 238 insertions(+), 6 deletions(-) create mode 100644 Content.Server/Weapon/Ranged/Systems/GunSystem.Cartridges.cs create mode 100644 Resources/Locale/en-US/damage/damage-examine.ftl diff --git a/Content.Client/Weapons/Melee/MeleeWeaponSystem.cs b/Content.Client/Weapons/Melee/MeleeWeaponSystem.cs index 8ea211ac9c..f69d62580e 100644 --- a/Content.Client/Weapons/Melee/MeleeWeaponSystem.cs +++ b/Content.Client/Weapons/Melee/MeleeWeaponSystem.cs @@ -1,5 +1,6 @@ using System; using Content.Client.Weapons.Melee.Components; +using Content.Shared.Examine; using Content.Shared.Weapons.Melee; using JetBrains.Annotations; using Robust.Client.GameObjects; diff --git a/Content.Server/Weapon/Melee/MeleeWeaponSystem.cs b/Content.Server/Weapon/Melee/MeleeWeaponSystem.cs index 1e118378a3..017d1f008a 100644 --- a/Content.Server/Weapon/Melee/MeleeWeaponSystem.cs +++ b/Content.Server/Weapon/Melee/MeleeWeaponSystem.cs @@ -7,13 +7,16 @@ using Content.Server.Chemistry.EntitySystems; using Content.Server.Cooldown; using Content.Server.Damage.Components; using Content.Server.Damage.Systems; +using Content.Server.Examine; using Content.Server.Weapon.Melee.Components; using Content.Shared.Damage; using Content.Shared.Audio; using Content.Shared.Database; +using Content.Shared.Examine; using Content.Shared.FixedPoint; using Content.Shared.Hands; using Content.Shared.Physics; +using Content.Shared.Verbs; using Content.Shared.Weapons.Melee; using Robust.Shared.Audio; using Robust.Shared.Containers; @@ -27,12 +30,14 @@ namespace Content.Server.Weapon.Melee { public sealed class MeleeWeaponSystem : EntitySystem { + [Dependency] private readonly IAdminLogManager _adminLogger = default!; [Dependency] private readonly IGameTiming _gameTiming = default!; [Dependency] private readonly IPrototypeManager _protoManager = default!; - [Dependency] private readonly DamageableSystem _damageableSystem = default!; + [Dependency] private readonly DamageableSystem _damageable = default!; + [Dependency] private readonly ExamineSystem _examine = default!; [Dependency] private readonly StaminaSystem _staminaSystem = default!; [Dependency] private readonly SolutionContainerSystem _solutionsSystem = default!; - [Dependency] private readonly IAdminLogManager _adminLogger = default!; + [Dependency] private readonly BloodstreamSystem _bloodstreamSystem = default!; public const float DamagePitchVariation = 0.15f; @@ -44,9 +49,41 @@ namespace Content.Server.Weapon.Melee SubscribeLocalEvent(OnHandSelected); SubscribeLocalEvent(OnClickAttack); SubscribeLocalEvent(OnWideAttack); + SubscribeLocalEvent>(OnMeleeExaminableVerb); SubscribeLocalEvent(OnChemicalInjectorHit); } + private void OnMeleeExaminableVerb(EntityUid uid, MeleeWeaponComponent component, GetVerbsEvent args) + { + if (!args.CanInteract || !args.CanAccess) + return; + + var damageSpec = GetDamage(component); + + if (damageSpec == null) + 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, + IconTexture = "/Textures/Interface/VerbIcons/smite.svg.192dpi.png" + }; + + args.Verbs.Add(verb); + } + + private DamageSpecifier? GetDamage(MeleeWeaponComponent component) + { + return component.Damage.Total > FixedPoint2.Zero ? component.Damage : null; + } + private void OnHandSelected(EntityUid uid, MeleeWeaponComponent comp, HandSelectedEvent args) { var curTime = _gameTiming.CurTime; @@ -100,7 +137,7 @@ namespace Content.Server.Weapon.Melee RaiseLocalEvent(target, new AttackedEvent(args.Used, args.User, args.ClickLocation), true); var modifiedDamage = DamageSpecifier.ApplyModifierSets(comp.Damage + hitEvent.BonusDamage, hitEvent.ModifiersList); - var damageResult = _damageableSystem.TryChangeDamage(target, modifiedDamage); + var damageResult = _damageable.TryChangeDamage(target, modifiedDamage); if (damageResult != null && damageResult.Total > FixedPoint2.Zero) { @@ -196,7 +233,7 @@ namespace Content.Server.Weapon.Melee { RaiseLocalEvent(entity, new AttackedEvent(args.Used, args.User, args.ClickLocation), true); - var damageResult = _damageableSystem.TryChangeDamage(entity, modifiedDamage); + var damageResult = _damageable.TryChangeDamage(entity, modifiedDamage); if (damageResult != null && damageResult.Total > FixedPoint2.Zero) { diff --git a/Content.Server/Weapon/Ranged/Systems/GunSystem.Battery.cs b/Content.Server/Weapon/Ranged/Systems/GunSystem.Battery.cs index 34d089e62a..7767cf40f0 100644 --- a/Content.Server/Weapon/Ranged/Systems/GunSystem.Battery.cs +++ b/Content.Server/Weapon/Ranged/Systems/GunSystem.Battery.cs @@ -1,5 +1,11 @@ using Content.Server.Power.Components; +using Content.Server.Projectiles.Components; +using Content.Shared.Damage; +using Content.Shared.FixedPoint; +using Content.Shared.Verbs; +using Content.Shared.Weapons.Ranged; using Content.Shared.Weapons.Ranged.Components; +using Robust.Shared.Prototypes; namespace Content.Server.Weapon.Ranged.Systems; @@ -12,10 +18,12 @@ public sealed partial class GunSystem // Hitscan SubscribeLocalEvent(OnBatteryStartup); SubscribeLocalEvent(OnBatteryChargeChange); + SubscribeLocalEvent>(OnBatteryExaminableVerb); // Projectile SubscribeLocalEvent(OnBatteryStartup); SubscribeLocalEvent(OnBatteryChargeChange); + SubscribeLocalEvent>(OnBatteryExaminableVerb); } private void OnBatteryStartup(EntityUid uid, BatteryAmmoProviderComponent component, ComponentStartup args) @@ -49,6 +57,72 @@ public sealed partial class GunSystem UpdateBatteryAppearance(component.Owner, component); } + private void OnBatteryExaminableVerb(EntityUid uid, BatteryAmmoProviderComponent component, GetVerbsEvent args) + { + if (!args.CanInteract || !args.CanAccess) + return; + + var damageSpec = GetDamage(component); + + if (damageSpec == null) + return; + + string damageType; + + switch (component) + { + 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, + IconTexture = "/Textures/Interface/VerbIcons/smite.svg.192dpi.png" + }; + + args.Verbs.Add(verb); + } + + private DamageSpecifier? GetDamage(BatteryAmmoProviderComponent component) + { + if (component is ProjectileBatteryAmmoProviderComponent battery) + { + if (ProtoManager.Index(battery.Prototype).Components + .TryGetValue(_factory.GetComponentName(typeof(ProjectileComponent)), out var projectile)) + { + var p = (ProjectileComponent) projectile.Component; + + if (p.Damage.Total > FixedPoint2.Zero) + { + return p.Damage; + } + } + + return null; + } + + if (component is HitscanBatteryAmmoProviderComponent hitscan) + { + return ProtoManager.Index(hitscan.Prototype).Damage; + } + + return null; + } + protected override void TakeCharge(EntityUid uid, BatteryAmmoProviderComponent component) { if (!TryComp(uid, out var battery)) return; diff --git a/Content.Server/Weapon/Ranged/Systems/GunSystem.Cartridges.cs b/Content.Server/Weapon/Ranged/Systems/GunSystem.Cartridges.cs new file mode 100644 index 0000000000..0fc8b5b4d2 --- /dev/null +++ b/Content.Server/Weapon/Ranged/Systems/GunSystem.Cartridges.cs @@ -0,0 +1,76 @@ +using Content.Server.Projectiles.Components; +using Content.Shared.Damage; +using Content.Shared.Examine; +using Content.Shared.FixedPoint; +using Content.Shared.Verbs; +using Content.Shared.Weapons.Ranged.Components; +using Robust.Shared.Prototypes; + +namespace Content.Server.Weapon.Ranged.Systems; + +public sealed partial class GunSystem +{ + protected override void InitializeCartridge() + { + base.InitializeCartridge(); + SubscribeLocalEvent(OnCartridgeExamine); + SubscribeLocalEvent>(OnCartridgeVerbExamine); + } + + private void OnCartridgeVerbExamine(EntityUid uid, CartridgeAmmoComponent component, GetVerbsEvent 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, + IconTexture = "/Textures/Interface/VerbIcons/smite.svg.192dpi.png" + }; + + args.Verbs.Add(verb); + } + + private DamageSpecifier? GetProjectileDamage(string proto) + { + if (!ProtoManager.TryIndex(proto, out var entityProto)) + return null; + + if (entityProto.Components + .TryGetValue(_factory.GetComponentName(typeof(ProjectileComponent)), out var projectile)) + { + var p = (ProjectileComponent) projectile.Component; + + if (p.Damage.Total > FixedPoint2.Zero) + { + return p.Damage; + } + } + + return null; + } + + private void OnCartridgeExamine(EntityUid uid, CartridgeAmmoComponent component, ExaminedEvent args) + { + if (component.Spent) + { + args.PushMarkup(Loc.GetString("gun-cartridge-spent")); + } + else + { + args.PushMarkup(Loc.GetString("gun-cartridge-unspent")); + } + } +} diff --git a/Content.Server/Weapon/Ranged/Systems/GunSystem.cs b/Content.Server/Weapon/Ranged/Systems/GunSystem.cs index 2b2069fdb1..d2e96ef8c3 100644 --- a/Content.Server/Weapon/Ranged/Systems/GunSystem.cs +++ b/Content.Server/Weapon/Ranged/Systems/GunSystem.cs @@ -1,5 +1,6 @@ using System.Linq; using Content.Server.Damage.Systems; +using Content.Server.Examine; using Content.Server.Projectiles.Components; using Content.Server.Weapon.Melee; using Content.Server.Weapon.Ranged.Components; @@ -23,6 +24,8 @@ namespace Content.Server.Weapon.Ranged.Systems; public sealed partial class GunSystem : SharedGunSystem { + [Dependency] private readonly IComponentFactory _factory = default!; + [Dependency] private readonly ExamineSystem _examine = default!; [Dependency] private readonly StaminaSystem _stamina = default!; public const float DamagePitchVariation = MeleeWeaponSystem.DamagePitchVariation; diff --git a/Content.Shared/Damage/Systems/DamageableSystem.cs b/Content.Shared/Damage/Systems/DamageableSystem.cs index 5c7726ddc8..cea2f2f541 100644 --- a/Content.Shared/Damage/Systems/DamageableSystem.cs +++ b/Content.Shared/Damage/Systems/DamageableSystem.cs @@ -7,6 +7,7 @@ using Content.Shared.MobState.Components; using Content.Shared.Radiation.Events; using Robust.Shared.GameStates; using Robust.Shared.Prototypes; +using Robust.Shared.Utility; namespace Content.Shared.Damage { @@ -22,6 +23,31 @@ namespace Content.Shared.Damage SubscribeLocalEvent(OnIrradiated); } + /// + /// 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) + { + msg.PushNewline(); + msg.AddMarkup(Loc.GetString("damage-value", ("type", damage.Key), ("amount", damage.Value))); + } + + return msg; + } + /// /// Initialize a damageable component /// diff --git a/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.Cartridges.cs b/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.Cartridges.cs index e1f7c9da8f..6d2c6163e3 100644 --- a/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.Cartridges.cs +++ b/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.Cartridges.cs @@ -6,7 +6,7 @@ namespace Content.Shared.Weapons.Ranged.Systems; public abstract partial class SharedGunSystem { - private void InitializeCartridge() + protected virtual void InitializeCartridge() { SubscribeLocalEvent(OnCartridgeGetState); SubscribeLocalEvent(OnCartridgeHandleState); diff --git a/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.cs b/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.cs index 59ba754d42..0294e1ca42 100644 --- a/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.cs +++ b/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.cs @@ -42,6 +42,7 @@ public abstract partial class SharedGunSystem : EntitySystem [Dependency] protected readonly SharedAppearanceSystem Appearance = default!; [Dependency] private readonly SharedCombatModeSystem _combatMode = default!; [Dependency] protected readonly SharedContainerSystem Containers = default!; + [Dependency] protected readonly ExamineSystemShared Examine = default!; [Dependency] protected readonly SharedPhysicsSystem Physics = default!; [Dependency] protected readonly SharedPopupSystem PopupSystem = default!; [Dependency] protected readonly ThrowingSystem ThrowingSystem = default!; diff --git a/Resources/Locale/en-US/damage/damage-examine.ftl b/Resources/Locale/en-US/damage/damage-examine.ftl new file mode 100644 index 0000000000..12e885a78a --- /dev/null +++ b/Resources/Locale/en-US/damage/damage-examine.ftl @@ -0,0 +1,10 @@ +# Damage examines +damage-examinable-verb-text = Damage +damage-examinable-verb-message = Examine the damage values. + +damage-hitscan = hitscan +damage-projectile = projectile +damage-melee = melee +damage-examine = It does the following damage: +damage-examine-type = It does the following {$type} damage: +damage-value = - [color=red]{$amount}[/color] units of [color=yellow]{$type}[/color]. diff --git a/Resources/Locale/en-US/weapons/ranged/gun.ftl b/Resources/Locale/en-US/weapons/ranged/gun.ftl index 4f422a357d..d838b2baab 100644 --- a/Resources/Locale/en-US/weapons/ranged/gun.ftl +++ b/Resources/Locale/en-US/weapons/ranged/gun.ftl @@ -15,8 +15,12 @@ gun-ballistic-cycle = Cycle gun-ballistic-cycled = Cycled gun-ballistic-cycled-empty = Cycled (empty) +# CartridgeAmmo +gun-cartridge-spent = It is [color=red]spent[/color]. +gun-cartridge-unspent = It is [color=lime]not spent[/color]. + # BatteryAmmoProvider -gun-battery-examine = It has enough charge for [color={$color}]{$count} shots. +gun-battery-examine = It has enough charge for [color={$color}]{$count}[/color] shots. # MagazineAmmoProvider gun-magazine-examine = It has [color={$color}]{$count}[/color] shots remaining.