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!;
///
public override void Initialize()
{
SubscribeLocalEvent(OnInit);
SubscribeLocalEvent(OnAfterInteractUsing);
SubscribeLocalEvent(OnExamine);
SubscribeLocalEvent(RelayEvent);
SubscribeLocalEvent(RelayEvent);
SubscribeLocalEvent(OnFireRateRefresh);
SubscribeLocalEvent(OnSpeedRefresh);
SubscribeLocalEvent(OnDamageGunShot);
}
private void RelayEvent(Entity ent, ref T args) where T : notnull
{
foreach (var upgrade in GetCurrentUpgrades(ent))
{
RaiseLocalEvent(upgrade, ref args);
}
}
private void OnExamine(Entity 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 ent, ref ComponentInit args)
{
_container.EnsureContainer(ent, ent.Comp.UpgradesContainerId);
}
private void OnAfterInteractUsing(Entity ent, ref AfterInteractUsingEvent args)
{
if (args.Handled || !args.CanReach || !TryComp(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 ent, ref GunRefreshModifiersEvent args)
{
args.FireRate *= ent.Comp.Coefficient;
}
private void OnSpeedRefresh(Entity ent, ref GunRefreshModifiersEvent args)
{
args.ProjectileSpeed *= ent.Comp.Coefficient;
}
private void OnDamageGunShot(Entity ent, ref GunShotEvent args)
{
foreach (var (ammo, _) in args.Ammo)
{
if (TryComp(ammo, out var proj))
proj.Damage += ent.Comp.Damage;
}
}
///
/// Gets the entities inside the gun's upgrade container.
///
public HashSet> GetCurrentUpgrades(Entity ent)
{
if (!_container.TryGetContainer(ent, ent.Comp.UpgradesContainerId, out var container))
return new HashSet>();
var upgrades = new HashSet>();
foreach (var contained in container.ContainedEntities)
{
if (TryComp(contained, out var upgradeComp))
upgrades.Add((contained, upgradeComp));
}
return upgrades;
}
///
/// Gets the tags of the upgrades currently applied.
///
public IEnumerable> GetCurrentUpgradeTags(Entity ent)
{
foreach (var upgrade in GetCurrentUpgrades(ent))
{
foreach (var tag in upgrade.Comp.Tags)
{
yield return tag;
}
}
}
}