Files
tbd-station-14/Content.Shared/Weapons/Ranged/Upgrades/GunUpgradeSystem.cs
2025-05-07 10:56:20 -07:00

146 lines
5.6 KiB
C#

using System.Linq;
using Content.Shared.Administration.Logs;
using Content.Shared.Database;
using Content.Shared.Examine;
using Content.Shared.Interaction;
using Content.Shared.Popups;
using Content.Shared.Projectiles;
using Content.Shared.Tag;
using Content.Shared.Weapons.Ranged.Events;
using Content.Shared.Weapons.Ranged.Systems;
using Content.Shared.Weapons.Ranged.Upgrades.Components;
using Content.Shared.Whitelist;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Containers;
using Robust.Shared.Prototypes;
namespace Content.Shared.Weapons.Ranged.Upgrades;
public sealed class GunUpgradeSystem : EntitySystem
{
[Dependency] private readonly ISharedAdminLogManager _adminLog = default!;
[Dependency] private readonly SharedAudioSystem _audio = default!;
[Dependency] private readonly SharedContainerSystem _container = default!;
[Dependency] private readonly SharedGunSystem _gun = default!;
[Dependency] private readonly EntityWhitelistSystem _entityWhitelist = default!;
[Dependency] private readonly SharedPopupSystem _popup = default!;
/// <inheritdoc/>
public override void Initialize()
{
SubscribeLocalEvent<UpgradeableGunComponent, ComponentInit>(OnInit);
SubscribeLocalEvent<UpgradeableGunComponent, AfterInteractUsingEvent>(OnAfterInteractUsing);
SubscribeLocalEvent<UpgradeableGunComponent, ExaminedEvent>(OnExamine);
SubscribeLocalEvent<UpgradeableGunComponent, GunRefreshModifiersEvent>(RelayEvent);
SubscribeLocalEvent<UpgradeableGunComponent, GunShotEvent>(RelayEvent);
SubscribeLocalEvent<GunUpgradeFireRateComponent, GunRefreshModifiersEvent>(OnFireRateRefresh);
SubscribeLocalEvent<GunUpgradeSpeedComponent, GunRefreshModifiersEvent>(OnSpeedRefresh);
SubscribeLocalEvent<GunUpgradeDamageComponent, GunShotEvent>(OnDamageGunShot);
}
private void RelayEvent<T>(Entity<UpgradeableGunComponent> ent, ref T args) where T : notnull
{
foreach (var upgrade in GetCurrentUpgrades(ent))
{
RaiseLocalEvent(upgrade, ref args);
}
}
private void OnExamine(Entity<UpgradeableGunComponent> ent, ref ExaminedEvent args)
{
using (args.PushGroup(nameof(UpgradeableGunComponent)))
{
foreach (var upgrade in GetCurrentUpgrades(ent))
{
args.PushMarkup(Loc.GetString(upgrade.Comp.ExamineText));
}
}
}
private void OnInit(Entity<UpgradeableGunComponent> ent, ref ComponentInit args)
{
_container.EnsureContainer<Container>(ent, ent.Comp.UpgradesContainerId);
}
private void OnAfterInteractUsing(Entity<UpgradeableGunComponent> ent, ref AfterInteractUsingEvent args)
{
if (args.Handled || !args.CanReach || !TryComp<GunUpgradeComponent>(args.Used, out var upgradeComponent))
return;
if (GetCurrentUpgrades(ent).Count >= ent.Comp.MaxUpgradeCount)
{
_popup.PopupPredicted(Loc.GetString("upgradeable-gun-popup-upgrade-limit"), ent, args.User);
return;
}
if (_entityWhitelist.IsWhitelistFail(ent.Comp.Whitelist, args.Used))
return;
if (GetCurrentUpgradeTags(ent).ToHashSet().IsSupersetOf(upgradeComponent.Tags))
{
_popup.PopupPredicted(Loc.GetString("upgradeable-gun-popup-already-present"), ent, args.User);
return;
}
_audio.PlayPredicted(ent.Comp.InsertSound, ent, args.User);
_popup.PopupClient(Loc.GetString("gun-upgrade-popup-insert", ("upgrade", args.Used),("gun", ent.Owner)), args.User);
_gun.RefreshModifiers(ent.Owner);
args.Handled = _container.Insert(args.Used, _container.GetContainer(ent, ent.Comp.UpgradesContainerId));
_adminLog.Add(LogType.Action, LogImpact.Low, $"{ToPrettyString(args.User):player} inserted gun upgrade {ToPrettyString(args.Used)} into {ToPrettyString(ent.Owner)}.");
}
private void OnFireRateRefresh(Entity<GunUpgradeFireRateComponent> ent, ref GunRefreshModifiersEvent args)
{
args.FireRate *= ent.Comp.Coefficient;
}
private void OnSpeedRefresh(Entity<GunUpgradeSpeedComponent> ent, ref GunRefreshModifiersEvent args)
{
args.ProjectileSpeed *= ent.Comp.Coefficient;
}
private void OnDamageGunShot(Entity<GunUpgradeDamageComponent> ent, ref GunShotEvent args)
{
foreach (var (ammo, _) in args.Ammo)
{
if (TryComp<ProjectileComponent>(ammo, out var proj))
proj.Damage += ent.Comp.Damage;
}
}
/// <summary>
/// Gets the entities inside the gun's upgrade container.
/// </summary>
public HashSet<Entity<GunUpgradeComponent>> GetCurrentUpgrades(Entity<UpgradeableGunComponent> ent)
{
if (!_container.TryGetContainer(ent, ent.Comp.UpgradesContainerId, out var container))
return new HashSet<Entity<GunUpgradeComponent>>();
var upgrades = new HashSet<Entity<GunUpgradeComponent>>();
foreach (var contained in container.ContainedEntities)
{
if (TryComp<GunUpgradeComponent>(contained, out var upgradeComp))
upgrades.Add((contained, upgradeComp));
}
return upgrades;
}
/// <summary>
/// Gets the tags of the upgrades currently applied.
/// </summary>
public IEnumerable<ProtoId<TagPrototype>> GetCurrentUpgradeTags(Entity<UpgradeableGunComponent> ent)
{
foreach (var upgrade in GetCurrentUpgrades(ent))
{
foreach (var tag in upgrade.Comp.Tags)
{
yield return tag;
}
}
}
}