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
This commit is contained in:
metalgearsloth
2022-09-09 09:08:14 +10:00
committed by GitHub
parent 7ae1d59ce2
commit 2f07270744
10 changed files with 238 additions and 6 deletions

View File

@@ -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;

View File

@@ -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<MeleeWeaponComponent, HandSelectedEvent>(OnHandSelected);
SubscribeLocalEvent<MeleeWeaponComponent, ClickAttackEvent>(OnClickAttack);
SubscribeLocalEvent<MeleeWeaponComponent, WideAttackEvent>(OnWideAttack);
SubscribeLocalEvent<MeleeWeaponComponent, GetVerbsEvent<ExamineVerb>>(OnMeleeExaminableVerb);
SubscribeLocalEvent<MeleeChemicalInjectorComponent, MeleeHitEvent>(OnChemicalInjectorHit);
}
private void OnMeleeExaminableVerb(EntityUid uid, MeleeWeaponComponent component, GetVerbsEvent<ExamineVerb> 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)
{

View File

@@ -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<HitscanBatteryAmmoProviderComponent, ComponentStartup>(OnBatteryStartup);
SubscribeLocalEvent<HitscanBatteryAmmoProviderComponent, ChargeChangedEvent>(OnBatteryChargeChange);
SubscribeLocalEvent<HitscanBatteryAmmoProviderComponent, GetVerbsEvent<ExamineVerb>>(OnBatteryExaminableVerb);
// Projectile
SubscribeLocalEvent<ProjectileBatteryAmmoProviderComponent, ComponentStartup>(OnBatteryStartup);
SubscribeLocalEvent<ProjectileBatteryAmmoProviderComponent, ChargeChangedEvent>(OnBatteryChargeChange);
SubscribeLocalEvent<ProjectileBatteryAmmoProviderComponent, GetVerbsEvent<ExamineVerb>>(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<ExamineVerb> 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<EntityPrototype>(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<HitscanPrototype>(hitscan.Prototype).Damage;
}
return null;
}
protected override void TakeCharge(EntityUid uid, BatteryAmmoProviderComponent component)
{
if (!TryComp<BatteryComponent>(uid, out var battery)) return;

View File

@@ -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<CartridgeAmmoComponent, ExaminedEvent>(OnCartridgeExamine);
SubscribeLocalEvent<CartridgeAmmoComponent, GetVerbsEvent<ExamineVerb>>(OnCartridgeVerbExamine);
}
private void OnCartridgeVerbExamine(EntityUid uid, CartridgeAmmoComponent component, GetVerbsEvent<ExamineVerb> 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<EntityPrototype>(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"));
}
}
}

View File

@@ -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;

View File

@@ -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<DamageableComponent, OnIrradiatedEvent>(OnIrradiated);
}
/// <summary>
/// Retrieves the damage examine values.
/// </summary>
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;
}
/// <summary>
/// Initialize a damageable component
/// </summary>

View File

@@ -6,7 +6,7 @@ namespace Content.Shared.Weapons.Ranged.Systems;
public abstract partial class SharedGunSystem
{
private void InitializeCartridge()
protected virtual void InitializeCartridge()
{
SubscribeLocalEvent<CartridgeAmmoComponent, ComponentGetState>(OnCartridgeGetState);
SubscribeLocalEvent<CartridgeAmmoComponent, ComponentHandleState>(OnCartridgeHandleState);

View File

@@ -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!;

View File

@@ -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].

View File

@@ -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.