using Content.Shared._RMC14.Wieldable.Components; using Content.Shared._RMC14.Wieldable.Events; using Content.Shared.Hands; using Content.Shared.Hands.Components; using Content.Shared.Interaction.Events; using Content.Shared.Inventory; using Content.Shared.Inventory.Events; using Content.Shared.Movement.Systems; using Content.Shared.Popups; using Content.Shared.Timing; using Content.Shared.Weapons.Ranged.Events; using Content.Shared.Wieldable; using Content.Shared.Wieldable.Components; using Robust.Shared.Containers; using Robust.Shared.Prototypes; using Robust.Shared.Timing; namespace Content.Shared._RMC14.Wieldable; public sealed class RMCWieldableSystem : EntitySystem { [Dependency] private readonly IGameTiming _timing = default!; [Dependency] private readonly InventorySystem _inventorySystem = default!; [Dependency] private readonly MovementSpeedModifierSystem _movementSpeedModifierSystem = default!; [Dependency] private readonly SharedPopupSystem _popupSystem = default!; [Dependency] private readonly UseDelaySystem _useDelaySystem = default!; [Dependency] private readonly SharedContainerSystem _container = default!; private const string WieldUseDelayID = "RMCWieldDelay"; public override void Initialize() { SubscribeLocalEvent(OnGotEquippedHand); SubscribeLocalEvent(OnGotUnequippedHand); SubscribeLocalEvent>(OnRefreshMovementSpeedModifiers); SubscribeLocalEvent(OnItemUnwielded); SubscribeLocalEvent(OnItemWielded); SubscribeLocalEvent(OnMapInit); SubscribeLocalEvent(OnGotEquipped); SubscribeLocalEvent(OnGotUnequipped); SubscribeLocalEvent(OnGotEquippedHand); SubscribeLocalEvent(OnMapInit); SubscribeLocalEvent(OnUseInHand); SubscribeLocalEvent(OnShotAttempt); SubscribeLocalEvent(OnItemWieldedWithDelay); SubscribeLocalEvent(_inventorySystem.RelayEvent); } private void OnMapInit(Entity wieldable, ref MapInitEvent args) { RefreshSpeedModifiers((wieldable.Owner, wieldable.Comp)); } private void OnMapInit(Entity wieldable, ref MapInitEvent args) { wieldable.Comp.ModifiedDelay = wieldable.Comp.BaseDelay; } #region Wield speed modifiers private void OnGotEquippedHand(Entity wieldable, ref GotEquippedHandEvent args) { _movementSpeedModifierSystem.RefreshMovementSpeedModifiers(args.User); } private void OnGotUnequippedHand(Entity wieldable, ref GotUnequippedHandEvent args) { _movementSpeedModifierSystem.RefreshMovementSpeedModifiers(args.User); } private void OnRefreshMovementSpeedModifiers(Entity wieldable, ref HeldRelayedEvent args) { if (TryComp(wieldable.Owner, out TransformComponent? transformComponent) && transformComponent.ParentUid.Valid && TryComp(transformComponent.ParentUid, out WieldSlowdownCompensationUserComponent? userComponent)) { args.Args.ModifySpeed( Math.Min(wieldable.Comp.ModifiedWalk + userComponent.Walk, 1f), Math.Min(wieldable.Comp.ModifiedSprint + userComponent.Sprint, 1f)); return; } args.Args.ModifySpeed(wieldable.Comp.ModifiedWalk, wieldable.Comp.ModifiedSprint); } public void RefreshSpeedModifiers(Entity wieldable) { wieldable.Comp = EnsureComp(wieldable); var walkSpeed = wieldable.Comp.BaseWalk; var sprintSpeed = wieldable.Comp.BaseSprint; if (!TryComp(wieldable.Owner, out WieldableComponent? wieldableComponent) || !wieldableComponent.Wielded) { walkSpeed = 1f; sprintSpeed = 1f; } var ev = new GetWieldableSpeedModifiersEvent(walkSpeed, sprintSpeed); RaiseLocalEvent(wieldable, ref ev); wieldable.Comp.ModifiedWalk = ev.Walk > 0 ? ev.Walk : 0; wieldable.Comp.ModifiedSprint = ev.Sprint > 0 ? ev.Sprint : 0; RefreshModifiersOnParent(wieldable.Owner); } private void OnItemUnwielded(Entity wieldable, ref ItemUnwieldedEvent args) { RefreshSpeedModifiers((wieldable.Owner, wieldable.Comp)); } private void OnItemWielded(Entity wieldable, ref ItemWieldedEvent args) { RefreshSpeedModifiers((wieldable.Owner, wieldable.Comp)); } private void RefreshModifiersOnParent(EntityUid wieldableUid) { if (!TryComp(wieldableUid, out TransformComponent? transformComponent) || !transformComponent.ParentUid.Valid || !TryComp(transformComponent.ParentUid, out HandsComponent? handsComponent) || handsComponent.ActiveHandEntity != wieldableUid) { return; } _movementSpeedModifierSystem.RefreshMovementSpeedModifiers(transformComponent.ParentUid); } #endregion #region Wield slowdown compensation private void OnGotEquipped(Entity armour, ref GotEquippedEvent args) { EnsureComp(args.Equipee, out WieldSlowdownCompensationUserComponent comp); RefreshWieldSlowdownCompensation((args.Equipee, comp)); } private void OnGotUnequipped(Entity armour, ref GotUnequippedEvent args) { EnsureComp(args.Equipee, out WieldSlowdownCompensationUserComponent comp); RefreshWieldSlowdownCompensation((args.Equipee, comp)); } private void RefreshWieldSlowdownCompensation(Entity user) { var ev = new RefreshWieldSlowdownCompensationEvent(~SlotFlags.POCKET); RaiseLocalEvent(user.Owner, ref ev); user.Comp.Walk = ev.Walk; user.Comp.Walk = ev.Sprint; } private void OnRefreshWieldSlowdownCompensation(Entity armour, ref InventoryRelayedEvent args) { args.Args.Walk += armour.Comp.Walk; args.Args.Sprint += armour.Comp.Sprint; } #endregion #region Wield delay private void OnGotEquippedHand(Entity wieldable, ref GotEquippedHandEvent args) { _useDelaySystem.SetLength(wieldable.Owner, wieldable.Comp.ModifiedDelay, WieldUseDelayID); _useDelaySystem.TryResetDelay(wieldable.Owner, id: WieldUseDelayID); } private void OnUseInHand(Entity wieldable, ref UseInHandEvent args) { if (!TryComp(wieldable.Owner, out UseDelayComponent? useDelayComponent) || !_useDelaySystem.IsDelayed((wieldable.Owner, useDelayComponent), WieldUseDelayID)) { return; } args.Handled = true; if (!_useDelaySystem.TryGetDelayInfo((wieldable.Owner, useDelayComponent), out var info, WieldUseDelayID)) { return; } var time = $"{(info.EndTime - _timing.CurTime).TotalSeconds:F1}"; _popupSystem.PopupClient(Loc.GetString("rmc-wield-use-delay", ("seconds", time), ("wieldable", wieldable.Owner)), args.User, args.User); } public void RefreshWieldDelay(Entity wieldable) { wieldable.Comp = EnsureComp(wieldable); var ev = new GetWieldDelayEvent(wieldable.Comp.BaseDelay); RaiseLocalEvent(wieldable, ref ev); wieldable.Comp.ModifiedDelay = ev.Delay >= TimeSpan.Zero ? ev.Delay : TimeSpan.Zero; } private void OnItemWieldedWithDelay(Entity wieldable, ref ItemWieldedEvent args) { // TODO RMC14 +0.5s if Dazed var skillModifiedDelay = wieldable.Comp.ModifiedDelay; if (_container.TryGetContainingContainer((wieldable, null), out var container)) skillModifiedDelay -= TimeSpan.FromSeconds(0.2) * 1; // ADT ЗАТЫЧКА _useDelaySystem.SetLength(wieldable.Owner, skillModifiedDelay, WieldUseDelayID); _useDelaySystem.TryResetDelay(wieldable.Owner, id: WieldUseDelayID); } public void OnShotAttempt(Entity wieldable, ref ShotAttemptedEvent args) { if (!TryComp(wieldable.Owner, out UseDelayComponent? useDelayComponent) || !_useDelaySystem.IsDelayed((wieldable.Owner, useDelayComponent), WieldUseDelayID) || !_useDelaySystem.TryGetDelayInfo((wieldable.Owner, useDelayComponent), out var info, WieldUseDelayID)) { return; } args.Cancel(); var time = $"{(info.EndTime - _timing.CurTime).TotalSeconds:F1}"; //_popupSystem.PopupClient(Loc.GetString("rmc-shoot-use-delay", ("seconds", time), ("wieldable", wieldable.Owner)), args.User, args.User); // Uncomment when there's a cooldown on popups from a source. } #endregion }