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