UseDelay + ItemCooldown merge (#22502)

This commit is contained in:
AJCM-git
2024-01-03 21:33:09 -04:00
committed by GitHub
parent 42ec9b2967
commit 9c522c8b19
80 changed files with 324 additions and 589 deletions

View File

@@ -1,9 +1,7 @@
using Content.Client.Clothing;
using Content.Client.Examine;
using Content.Client.Verbs.UI;
using Content.Shared.Clothing.Components;
using Content.Shared.Interaction;
using Content.Shared.Interaction.Events;
using Content.Shared.Inventory;
using Content.Shared.Inventory.Events;
using Content.Shared.Storage;
@@ -48,8 +46,6 @@ namespace Content.Client.Inventory
_equipEventsQueue.Enqueue((comp, args)));
SubscribeLocalEvent<InventorySlotsComponent, DidUnequipEvent>((_, comp, args) =>
_equipEventsQueue.Enqueue((comp, args)));
SubscribeLocalEvent<ClothingComponent, UseInHandEvent>(OnUseInHand);
}
public override void Update(float frameTime)
@@ -74,14 +70,6 @@ namespace Content.Client.Inventory
}
}
private void OnUseInHand(EntityUid uid, ClothingComponent component, UseInHandEvent args)
{
if (args.Handled || !component.QuickEquip)
return;
QuickEquip(uid, component, args);
}
private void OnDidUnequip(InventorySlotsComponent component, DidUnequipEvent args)
{
UpdateSlot(args.Equipee, component, args.Slot);

View File

@@ -3,10 +3,9 @@ using Content.Client.Hands.Systems;
using Content.Client.UserInterface.Controls;
using Content.Client.UserInterface.Systems.Hands.Controls;
using Content.Client.UserInterface.Systems.Hotbar.Widgets;
using Content.Shared.Cooldown;
using Content.Shared.Hands.Components;
using Content.Shared.Input;
using Robust.Client.GameObjects;
using Content.Shared.Timing;
using Robust.Client.Player;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controllers;
@@ -247,7 +246,7 @@ public sealed class HandsUIController : UIController, IOnStateEntered<GameplaySt
if (HandsGui != null &&
_playerHandsComponent != null &&
_player.LocalPlayer?.ControlledEntity is { } playerEntity &&
_player.LocalSession?.AttachedEntity is { } playerEntity &&
_handsSystem.TryGetHand(playerEntity, handName, out var hand, _playerHandsComponent))
{
HandsGui.UpdatePanelEntity(hand.HeldEntity);
@@ -329,7 +328,6 @@ public sealed class HandsUIController : UIController, IOnStateEntered<GameplaySt
private bool RemoveHand(string handName, out HandButton? handButton)
{
handButton = null;
if (!_handLookup.TryGetValue(handName, out handButton))
return false;
if (handButton.Parent is HandsContainer handContainer)
@@ -395,8 +393,9 @@ public sealed class HandsUIController : UIController, IOnStateEntered<GameplaySt
{
foreach (var hand in container.GetButtons())
{
if (!_entities.TryGetComponent(hand.Entity, out ItemCooldownComponent? cooldown) ||
cooldown is not { CooldownStart: { } start, CooldownEnd: { } end})
if (!_entities.TryGetComponent(hand.Entity, out UseDelayComponent? useDelay) ||
useDelay is not { DelayStartTime: var start, DelayEndTime: var end })
{
hand.CooldownDisplay.Visible = false;
return;

View File

@@ -1,6 +1,5 @@
using Content.Server.Administration.Logs;
using Content.Server.Atmos.Components;
using Content.Server.Explosion.EntitySystems;
using Content.Server.IgnitionSource;
using Content.Server.Stunnable;
using Content.Server.Temperature.Components;
@@ -12,7 +11,6 @@ using Content.Shared.Atmos.Components;
using Content.Shared.Damage;
using Content.Shared.Database;
using Content.Shared.Interaction;
using Content.Shared.Interaction.Events;
using Content.Shared.Physics;
using Content.Shared.Popups;
using Content.Shared.Rejuvenate;
@@ -22,7 +20,6 @@ using Content.Shared.Timing;
using Content.Shared.Toggleable;
using Content.Shared.Weapons.Melee.Events;
using Robust.Server.Audio;
using Robust.Server.GameObjects;
using Robust.Shared.Physics.Components;
using Robust.Shared.Physics.Events;
using Robust.Shared.Physics.Systems;
@@ -39,9 +36,7 @@ namespace Content.Server.Atmos.EntitySystems
[Dependency] private readonly IgnitionSourceSystem _ignitionSourceSystem = default!;
[Dependency] private readonly DamageableSystem _damageableSystem = default!;
[Dependency] private readonly AlertsSystem _alertsSystem = default!;
[Dependency] private readonly TransformSystem _transformSystem = default!;
[Dependency] private readonly FixtureSystem _fixture = default!;
[Dependency] private readonly EntityLookupSystem _lookup = default!;
[Dependency] private readonly IAdminLogManager _adminLogger = default!;
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
[Dependency] private readonly SharedPopupSystem _popup = default!;
@@ -59,7 +54,6 @@ namespace Content.Server.Atmos.EntitySystems
private float _timer;
private readonly Dictionary<Entity<FlammableComponent>, float> _fireEvents = new();
private readonly List<EntityUid> _toRemove = new();
public override void Initialize()
{
@@ -157,10 +151,11 @@ namespace Content.Server.Atmos.EntitySystems
args.Handled = true;
if (!_useDelay.BeginDelay(uid))
if (!TryComp(uid, out UseDelayComponent? useDelay) || !_useDelay.TryResetDelay((uid, useDelay), true))
return;
_audio.PlayPvs(component.ExtinguishAttemptSound, uid);
if (_random.Prob(component.Probability))
{
AdjustFireStacks(uid, component.StackDelta, flammable);
@@ -170,6 +165,7 @@ namespace Content.Server.Atmos.EntitySystems
_popup.PopupEntity(Loc.GetString(component.ExtinguishFailed), uid);
}
}
private void OnCollide(EntityUid uid, FlammableComponent flammable, ref StartCollideEvent args)
{
var otherUid = args.OtherEntity;
@@ -364,7 +360,7 @@ namespace Content.Server.Atmos.EntitySystems
// TODO: This needs cleanup to take off the crust from TemperatureComponent and shit.
var query = EntityQueryEnumerator<FlammableComponent, TransformComponent>();
while (query.MoveNext(out var uid, out var flammable, out var transform))
while (query.MoveNext(out var uid, out var flammable, out _))
{
// Slowly dry ourselves off if wet.
if (flammable.FireStacks < 0)

View File

@@ -32,6 +32,7 @@ namespace Content.Server.Bible
[Dependency] private readonly SharedActionsSystem _actionsSystem = default!;
[Dependency] private readonly SharedAudioSystem _audio = default!;
[Dependency] private readonly UseDelaySystem _delay = default!;
[Dependency] private readonly SharedTransformSystem _transform = default!;
public override void Initialize()
{
@@ -68,7 +69,7 @@ namespace Content.Server.Bible
_remQueue.Clear();
var query = EntityQueryEnumerator<SummonableRespawningComponent, SummonableComponent>();
while (query.MoveNext(out var uid, out var respawning, out var summonableComp))
while (query.MoveNext(out var uid, out var _, out var summonableComp))
{
summonableComp.Accumulator += frameTime;
if (summonableComp.Accumulator < summonableComp.RespawnTime)
@@ -82,8 +83,8 @@ namespace Content.Server.Bible
summonableComp.Summon = null;
}
summonableComp.AlreadySummoned = false;
_popupSystem.PopupEntity(Loc.GetString("bible-summon-respawn-ready", ("book", summonableComp.Owner)), summonableComp.Owner, PopupType.Medium);
_audio.PlayPvs("/Audio/Effects/radpulse9.ogg", summonableComp.Owner, AudioParams.Default.WithVolume(-4f));
_popupSystem.PopupEntity(Loc.GetString("bible-summon-respawn-ready", ("book", uid)), uid, PopupType.Medium);
_audio.PlayPvs("/Audio/Effects/radpulse9.ogg", uid, AudioParams.Default.WithVolume(-4f));
// Clean up the accumulator and respawn tracking component
summonableComp.Accumulator = 0;
_remQueue.Enqueue(uid);
@@ -95,9 +96,7 @@ namespace Content.Server.Bible
if (!args.CanReach)
return;
UseDelayComponent? delay = null;
if (_delay.ActiveDelay(uid, delay))
if (!TryComp(uid, out UseDelayComponent? useDelay) || _delay.IsDelayed((uid, useDelay)))
return;
if (args.Target == null || args.Target == args.User || !_mobStateSystem.IsAlive(args.Target.Value))
@@ -111,7 +110,7 @@ namespace Content.Server.Bible
_audio.PlayPvs(component.SizzleSoundPath, args.User);
_damageableSystem.TryChangeDamage(args.User, component.DamageOnUntrainedUse, true, origin: uid);
_delay.BeginDelay(uid, delay);
_delay.TryResetDelay((uid, useDelay));
return;
}
@@ -129,7 +128,7 @@ namespace Content.Server.Bible
_audio.PlayPvs("/Audio/Effects/hit_kick.ogg", args.User);
_damageableSystem.TryChangeDamage(args.Target.Value, component.DamageOnFail, true, origin: uid);
_delay.BeginDelay(uid, delay);
_delay.TryResetDelay((uid, useDelay));
return;
}
}
@@ -152,7 +151,7 @@ namespace Content.Server.Bible
var selfMessage = Loc.GetString(component.LocPrefix + "-heal-success-self", ("target", Identity.Entity(args.Target.Value, EntityManager)), ("bible", uid));
_popupSystem.PopupEntity(selfMessage, args.User, args.User, PopupType.Large);
_audio.PlayPvs(component.HealSoundPath, args.User);
_delay.BeginDelay(uid, delay);
_delay.TryResetDelay((uid, useDelay));
}
}
@@ -168,7 +167,8 @@ namespace Content.Server.Bible
{
Act = () =>
{
if (!TryComp<TransformComponent>(args.User, out var userXform)) return;
if (!TryComp<TransformComponent>(args.User, out var userXform))
return;
AttemptSummon((uid, component), args.User, userXform);
},
@@ -242,7 +242,7 @@ namespace Content.Server.Bible
if (HasComp<GhostRoleMobSpawnerComponent>(familiar))
{
_popupSystem.PopupEntity(Loc.GetString("bible-summon-requested"), user, PopupType.Medium);
Transform(familiar).AttachParent(uid);
_transform.SetParent(familiar, uid);
}
component.AlreadySummoned = true;
_actionsSystem.RemoveAction(user, component.SummonActionEntity);

View File

@@ -4,7 +4,6 @@ using Content.Shared.IdentityManagement;
using Content.Shared.Interaction;
using Content.Shared.Timing;
using Content.Shared.Verbs;
using Robust.Shared.Player;
namespace Content.Server.Cargo.Systems;
@@ -26,11 +25,10 @@ public sealed class PriceGunSystem : EntitySystem
private void OnUtilityVerb(EntityUid uid, PriceGunComponent component, GetVerbsEvent<UtilityVerb> args)
{
if (!args.CanAccess || !args.CanInteract)
if (!args.CanAccess || !args.CanInteract || args.Using == null)
return;
if (TryComp(args.Using, out UseDelayComponent? useDelay) && useDelay.ActiveDelay)
if (!TryComp(uid, out UseDelayComponent? useDelay) || _useDelay.IsDelayed((uid, useDelay)))
return;
var price = _pricingSystem.GetPrice(args.Target);
@@ -40,7 +38,7 @@ public sealed class PriceGunSystem : EntitySystem
Act = () =>
{
_popupSystem.PopupEntity(Loc.GetString("price-gun-pricing-result", ("object", Identity.Entity(args.Target, EntityManager)), ("price", $"{price:F2}")), args.User, args.User);
_useDelay.BeginDelay(uid, useDelay);
_useDelay.TryResetDelay((uid, useDelay));
},
Text = Loc.GetString("price-gun-verb-text"),
Message = Loc.GetString("price-gun-verb-message", ("object", Identity.Entity(args.Target, EntityManager)))
@@ -48,18 +46,19 @@ public sealed class PriceGunSystem : EntitySystem
args.Verbs.Add(verb);
}
private void OnAfterInteract(EntityUid uid, PriceGunComponent component, AfterInteractEvent args)
{
if (!args.CanReach || args.Target == null || args.Handled)
return;
if (TryComp(args.Used, out UseDelayComponent? useDelay) && useDelay.ActiveDelay)
if (!TryComp(uid, out UseDelayComponent? useDelay) || _useDelay.IsDelayed((uid, useDelay)))
return;
var price = _pricingSystem.GetPrice(args.Target.Value);
_popupSystem.PopupEntity(Loc.GetString("price-gun-pricing-result", ("object", Identity.Entity(args.Target.Value, EntityManager)), ("price", $"{price:F2}")), args.User, args.User);
_useDelay.BeginDelay(uid, useDelay);
_useDelay.TryResetDelay((uid, useDelay));
args.Handled = true;
}
}

View File

@@ -79,8 +79,12 @@ namespace Content.Server.Chemistry.EntitySystems
if (!EligibleEntity(target, _entMan, component))
return false;
if (TryComp(uid, out UseDelayComponent? delayComp) && _useDelay.ActiveDelay(uid, delayComp))
if (TryComp(uid, out UseDelayComponent? delayComp))
{
if (_useDelay.IsDelayed((uid, delayComp)))
return false;
}
string? msgFormat = null;
@@ -117,8 +121,8 @@ namespace Content.Server.Chemistry.EntitySystems
// Medipens and such use this system and don't have a delay, requiring extra checks
// BeginDelay function returns if item is already on delay
if (delayComp is not null)
_useDelay.BeginDelay(uid, delayComp);
if (delayComp != null)
_useDelay.TryResetDelay((uid, delayComp));
// Get transfer amount. May be smaller than component.TransferAmount if not enough room
var realTransferAmount = FixedPoint2.Min(component.TransferAmount, targetSolution.AvailableVolume);

View File

@@ -1,32 +0,0 @@
using Content.Shared.Cooldown;
namespace Content.Server.Cooldown
{
public sealed class ItemCooldownSystem : EntitySystem
{
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<ItemCooldownComponent, RefreshItemCooldownEvent>(OnItemCooldownRefreshed);
}
public void OnItemCooldownRefreshed(EntityUid uid, ItemCooldownComponent comp, RefreshItemCooldownEvent args)
{
comp.CooldownStart = args.LastAttackTime;
comp.CooldownEnd = args.CooldownEnd;
}
}
public sealed class RefreshItemCooldownEvent : EntityEventArgs
{
public TimeSpan LastAttackTime { get; }
public TimeSpan CooldownEnd { get; }
public RefreshItemCooldownEvent(TimeSpan lastAttackTime, TimeSpan cooldownEnd)
{
LastAttackTime = lastAttackTime;
CooldownEnd = cooldownEnd;
}
}
}

View File

@@ -5,9 +5,7 @@ using Content.Shared.Examine;
using Content.Shared.Interaction;
using Content.Shared.Popups;
using Content.Shared.Timing;
using Content.Shared.Tools;
using Content.Shared.Tools.Systems;
using Robust.Shared.Audio;
using Robust.Shared.Audio.Systems;
using SignalReceivedEvent = Content.Server.DeviceLinking.Events.SignalReceivedEvent;
@@ -74,7 +72,8 @@ public sealed class LogicGateSystem : EntitySystem
return;
// no sound spamming
if (TryComp<UseDelayComponent>(uid, out var useDelay) && _useDelay.ActiveDelay(uid, useDelay))
if (TryComp<UseDelayComponent>(uid, out var useDelay)
&& !_useDelay.TryResetDelay((uid, useDelay), true))
return;
// cycle through possible gates
@@ -90,8 +89,6 @@ public sealed class LogicGateSystem : EntitySystem
var msg = Loc.GetString("logic-gate-cycle", ("gate", comp.Gate.ToString().ToUpper()));
_popup.PopupEntity(msg, uid, args.User);
_appearance.SetData(uid, LogicGateVisuals.Gate, comp.Gate);
_useDelay.BeginDelay(uid, useDelay);
}
private void OnSignalReceived(EntityUid uid, LogicGateComponent comp, ref SignalReceivedEvent args)

View File

@@ -1,5 +1,4 @@
using Content.Server.DeviceLinking.Components;
using Content.Server.DeviceNetwork;
using Content.Server.NodeContainer;
using Content.Server.Power.EntitySystems;
using Content.Server.Power.Nodes;
@@ -9,10 +8,9 @@ using Content.Shared.Interaction;
using Content.Shared.Popups;
using Content.Shared.Power.Generator;
using Content.Shared.Timing;
using Content.Shared.Tools;
using Content.Shared.Tools.Systems;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Map;
using Robust.Shared.Map.Components;
using Robust.Shared.Timing;
namespace Content.Server.DeviceLinking.Systems;
@@ -21,7 +19,6 @@ public sealed class PowerSensorSystem : EntitySystem
{
[Dependency] private readonly DeviceLinkSystem _deviceLink = default!;
[Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly IMapManager _mapManager = default!;
[Dependency] private readonly PowerNetSystem _powerNet = default!;
[Dependency] private readonly SharedAudioSystem _audio = default!;
[Dependency] private readonly SharedPopupSystem _popup = default!;
@@ -76,7 +73,8 @@ public sealed class PowerSensorSystem : EntitySystem
return;
// no sound spamming
if (TryComp<UseDelayComponent>(uid, out var useDelay) && _useDelay.ActiveDelay(uid, useDelay))
if (TryComp<UseDelayComponent>(uid, out var useDelay)
&& !_useDelay.TryResetDelay((uid, useDelay), true))
return;
// switch between input and output mode.
@@ -89,8 +87,6 @@ public sealed class PowerSensorSystem : EntitySystem
_audio.PlayPvs(comp.SwitchSound, uid);
var msg = Loc.GetString("power-sensor-switch", ("output", comp.Output));
_popup.PopupEntity(msg, uid, args.User);
_useDelay.BeginDelay(uid, useDelay);
}
private void UpdateOutputs(EntityUid uid, PowerSensorComponent comp)
@@ -107,7 +103,9 @@ public sealed class PowerSensorSystem : EntitySystem
// update state based on the power stats retrieved from the selected power network
var xform = _xformQuery.GetComponent(uid);
_mapManager.TryGetGrid(xform.GridUid, out var grid);
if (!TryComp(xform.GridUid, out MapGridComponent? grid))
return;
var cables = deviceNode.GetReachableNodes(xform, _nodeQuery, _xformQuery, grid, EntityManager);
foreach (var node in cables)
{

View File

@@ -39,15 +39,12 @@ public sealed class SignallerSystem : EntitySystem
private void OnTrigger(EntityUid uid, SignallerComponent component, TriggerEvent args)
{
if (!TryComp(uid, out UseDelayComponent? useDelay)
// if on cooldown, do nothing
var hasUseDelay = TryComp<UseDelayComponent>(uid, out var useDelay);
if (hasUseDelay && _useDelay.ActiveDelay(uid, useDelay))
// and set cooldown to prevent clocks
|| !_useDelay.TryResetDelay((uid, useDelay), true))
return;
// set cooldown to prevent clocks
if (hasUseDelay)
_useDelay.BeginDelay(uid, useDelay);
_link.InvokePort(uid, component.Port);
args.Handled = true;
}

View File

@@ -9,7 +9,8 @@ using Content.Shared.Interaction;
using Content.Shared.Timing;
using Content.Shared.Weapons.Melee;
using Robust.Server.Audio;
using Robust.Shared.Map;
using Robust.Server.GameObjects;
using Robust.Shared.Map.Components;
using Robust.Shared.Prototypes;
using Robust.Shared.Utility;
@@ -18,7 +19,6 @@ namespace Content.Server.Fluids.EntitySystems;
/// <inheritdoc/>
public sealed class AbsorbentSystem : SharedAbsorbentSystem
{
[Dependency] private readonly IMapManager _mapManager = default!;
[Dependency] private readonly IPrototypeManager _prototype = default!;
[Dependency] private readonly AudioSystem _audio = default!;
[Dependency] private readonly PopupSystem _popups = default!;
@@ -27,6 +27,7 @@ public sealed class AbsorbentSystem : SharedAbsorbentSystem
[Dependency] private readonly SharedTransformSystem _transform = default!;
[Dependency] private readonly SolutionContainerSystem _solutionContainerSystem = default!;
[Dependency] private readonly UseDelaySystem _useDelay = default!;
[Dependency] private readonly MapSystem _mapSystem = default!;
public override void Initialize()
{
@@ -106,14 +107,15 @@ public sealed class AbsorbentSystem : SharedAbsorbentSystem
if (!_solutionContainerSystem.TryGetSolution(used, AbsorbentComponent.SolutionName, out var absorberSoln))
return;
if (_useDelay.ActiveDelay(used))
if (TryComp<UseDelayComponent>(used, out var useDelay)
&& _useDelay.IsDelayed((used, useDelay)))
return;
// If it's a puddle try to grab from
if (!TryPuddleInteract(user, used, target, component, absorberSoln.Value))
if (!TryPuddleInteract(user, used, target, component, useDelay, absorberSoln.Value))
{
// If it's refillable try to transfer
if (!TryRefillableInteract(user, used, target, component, absorberSoln.Value))
if (!TryRefillableInteract(user, used, target, component, useDelay, absorberSoln.Value))
return;
}
}
@@ -121,7 +123,7 @@ public sealed class AbsorbentSystem : SharedAbsorbentSystem
/// <summary>
/// Logic for an absorbing entity interacting with a refillable.
/// </summary>
private bool TryRefillableInteract(EntityUid user, EntityUid used, EntityUid target, AbsorbentComponent component, Entity<SolutionComponent> absorbentSoln)
private bool TryRefillableInteract(EntityUid user, EntityUid used, EntityUid target, AbsorbentComponent component, UseDelayComponent? useDelay, Entity<SolutionComponent> absorbentSoln)
{
if (!TryComp(target, out RefillableSolutionComponent? refillable))
return false;
@@ -143,7 +145,8 @@ public sealed class AbsorbentSystem : SharedAbsorbentSystem
}
_audio.PlayPvs(component.TransferSound, target);
_useDelay.BeginDelay(used);
if (useDelay != null)
_useDelay.TryResetDelay((used, useDelay));
return true;
}
@@ -264,7 +267,7 @@ public sealed class AbsorbentSystem : SharedAbsorbentSystem
/// <summary>
/// Logic for an absorbing entity interacting with a puddle.
/// </summary>
private bool TryPuddleInteract(EntityUid user, EntityUid used, EntityUid target, AbsorbentComponent absorber, Entity<SolutionComponent> absorberSoln)
private bool TryPuddleInteract(EntityUid user, EntityUid used, EntityUid target, AbsorbentComponent absorber, UseDelayComponent? useDelay, Entity<SolutionComponent> absorberSoln)
{
if (!TryComp(target, out PuddleComponent? puddle))
return false;
@@ -297,17 +300,20 @@ public sealed class AbsorbentSystem : SharedAbsorbentSystem
var absorberSplit = absorberSolution.SplitSolutionWithOnly(puddleSplit.Volume, PuddleSystem.EvaporationReagents);
// Do tile reactions first
var coordinates = Transform(target).Coordinates;
if (_mapManager.TryGetGrid(coordinates.GetGridUid(EntityManager), out var mapGrid))
var transform = Transform(target);
var gridUid = transform.GridUid;
if (TryComp(gridUid, out MapGridComponent? mapGrid))
{
_puddleSystem.DoTileReactions(mapGrid.GetTileRef(coordinates), absorberSplit);
var tileRef = _mapSystem.GetTileRef(gridUid.Value, mapGrid, transform.Coordinates);
_puddleSystem.DoTileReactions(tileRef, absorberSplit);
}
_solutionContainerSystem.AddSolution(puddle.Solution.Value, absorberSplit);
_solutionContainerSystem.AddSolution(absorberSoln, puddleSplit);
_audio.PlayPvs(absorber.PickupSound, target);
_useDelay.BeginDelay(used);
if (useDelay != null)
_useDelay.TryResetDelay((used, useDelay));
var userXform = Transform(user);
var targetPos = _transform.GetWorldPosition(target);

View File

@@ -1,36 +1,34 @@
using Content.Server.Chemistry.Components;
using Content.Server.Chemistry.Containers.EntitySystems;
using Content.Server.Chemistry.EntitySystems;
using Content.Server.Cooldown;
using Content.Server.Extinguisher;
using Content.Server.Fluids.Components;
using Content.Server.Gravity;
using Content.Server.Popups;
using Content.Shared.Cooldown;
using Content.Shared.FixedPoint;
using Content.Shared.Interaction;
using Content.Shared.Timing;
using Content.Shared.Vapor;
using Robust.Server.GameObjects;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Physics.Components;
using Robust.Shared.Prototypes;
using Robust.Shared.Timing;
using System.Numerics;
namespace Content.Server.Fluids.EntitySystems;
public sealed class SpraySystem : EntitySystem
{
[Dependency] private readonly IGameTiming _gameTiming = default!;
[Dependency] private readonly IPrototypeManager _proto = default!;
[Dependency] private readonly GravitySystem _gravity = default!;
[Dependency] private readonly PhysicsSystem _physics = default!;
[Dependency] private readonly UseDelaySystem _useDelay = default!;
[Dependency] private readonly PopupSystem _popupSystem = default!;
[Dependency] private readonly SharedAudioSystem _audio = default!;
[Dependency] private readonly SolutionContainerSystem _solutionContainer = default!;
[Dependency] private readonly VaporSystem _vapor = default!;
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
[Dependency] private readonly TransformSystem _transform = default!;
[Dependency] private readonly SharedTransformSystem _transform = default!;
public override void Initialize()
{
@@ -54,12 +52,9 @@ public sealed class SpraySystem : EntitySystem
if (ev.Cancelled)
return;
var curTime = _gameTiming.CurTime;
if (TryComp<ItemCooldownComponent>(entity, out var cooldown)
&& curTime < cooldown.CooldownEnd)
{
if (!TryComp<UseDelayComponent>(entity, out var useDelay)
|| _useDelay.IsDelayed((entity, useDelay)))
return;
}
if (solution.Volume <= 0)
{
@@ -70,7 +65,7 @@ public sealed class SpraySystem : EntitySystem
var xformQuery = GetEntityQuery<TransformComponent>();
var userXform = xformQuery.GetComponent(args.User);
var userMapPos = userXform.MapPosition;
var userMapPos = _transform.GetMapCoordinates(userXform);
var clickMapPos = args.ClickLocation.ToMap(EntityManager, _transform);
var diffPos = clickMapPos.Position - userMapPos.Position;
@@ -149,7 +144,8 @@ public sealed class SpraySystem : EntitySystem
_audio.PlayPvs(entity.Comp.SpraySound, entity, entity.Comp.SpraySound.Params.WithVariation(0.125f));
RaiseLocalEvent(entity, new RefreshItemCooldownEvent(curTime, curTime + TimeSpan.FromSeconds(cooldownTime)), true);
_useDelay.SetDelay((entity, useDelay), TimeSpan.FromSeconds(cooldownTime));
_useDelay.TryResetDelay((entity, useDelay));
}
}

View File

@@ -1,6 +1,5 @@
using Content.Server.Explosion.EntitySystems;
using Content.Shared.Timing;
using Robust.Shared.Audio;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Timing;
@@ -43,14 +42,13 @@ public sealed class IgniteOnTriggerSystem : EntitySystem
private void OnTrigger(Entity<IgniteOnTriggerComponent> ent, ref TriggerEvent args)
{
// prevent spamming sound and ignition
TryComp<UseDelayComponent>(ent, out var delay);
if (_useDelay.ActiveDelay(ent, delay))
if (!TryComp(ent.Owner, out UseDelayComponent? useDelay) || _useDelay.IsDelayed((ent.Owner, useDelay)))
return;
_source.SetIgnited(ent.Owner);
_audio.PlayPvs(ent.Comp.IgniteSound, ent);
_useDelay.BeginDelay(ent, delay);
_useDelay.TryResetDelay((ent.Owner, useDelay));
ent.Comp.IgnitedUntil = _timing.CurTime + ent.Comp.IgnitedTime;
}
}

View File

@@ -1,7 +1,5 @@
using Content.Server.Storage.EntitySystems;
using Content.Shared.Clothing.Components;
using Content.Shared.Explosion;
using Content.Shared.Interaction.Events;
using Content.Shared.Inventory;
using Content.Shared.Inventory.Events;
using Content.Shared.Storage;
@@ -17,9 +15,6 @@ namespace Content.Server.Inventory
base.Initialize();
SubscribeLocalEvent<InventoryComponent, BeforeExplodeEvent>(OnExploded);
SubscribeLocalEvent<ClothingComponent, UseInHandEvent>(OnUseInHand);
SubscribeNetworkEvent<OpenSlotStorageNetworkMessage>(OnOpenSlotStorage);
}
@@ -34,14 +29,6 @@ namespace Content.Server.Inventory
}
}
private void OnUseInHand(EntityUid uid, ClothingComponent component, UseInHandEvent args)
{
if (args.Handled || !component.QuickEquip)
return;
QuickEquip(uid, component, args);
}
private void OnOpenSlotStorage(OpenSlotStorageNetworkMessage ev, EntitySessionEventArgs args)
{
if (args.SenderSession.AttachedEntity is not { Valid: true } uid)

View File

@@ -66,13 +66,14 @@ public sealed class DefibrillatorSystem : EntitySystem
private void OnUseInHand(EntityUid uid, DefibrillatorComponent component, UseInHandEvent args)
{
if (args.Handled || _useDelay.ActiveDelay(uid))
if (args.Handled || !TryComp(uid, out UseDelayComponent? useDelay) || _useDelay.IsDelayed((uid, useDelay)))
return;
if (!TryToggle(uid, component, args.User))
return;
args.Handled = true;
_useDelay.BeginDelay(uid);
_useDelay.TryResetDelay((uid, useDelay));
}
private void OnPowerCellSlotEmpty(EntityUid uid, DefibrillatorComponent component, ref PowerCellSlotEmptyEvent args)

View File

@@ -11,14 +11,15 @@ public sealed partial class InteractWithOperator : HTNOperator
/// <summary>
/// Key that contains the target entity.
/// </summary>
[DataField("targetKey", required: true)]
[DataField(required: true)]
public string TargetKey = default!;
public override HTNOperatorStatus Update(NPCBlackboard blackboard, float frameTime)
{
var owner = blackboard.GetValue<EntityUid>(NPCBlackboard.Owner);
if (_entManager.System<UseDelaySystem>().ActiveDelay(owner) ||
if (!_entManager.TryGetComponent<UseDelayComponent>(owner, out var useDelay) ||
_entManager.System<UseDelaySystem>().IsDelayed((owner, useDelay)) ||
!blackboard.TryGetValue<EntityUid>(TargetKey, out var moveTarget, _entManager) ||
!_entManager.TryGetComponent<TransformComponent>(moveTarget, out var targetXform))
{

View File

@@ -3,13 +3,12 @@ using Content.Server.Ninja.Events;
using Content.Server.Popups;
using Content.Server.Power.Components;
using Content.Server.PowerCell;
using Content.Shared.Actions;
using Content.Shared.Clothing.EntitySystems;
using Content.Shared.Hands.EntitySystems;
using Content.Shared.Ninja.Components;
using Content.Shared.Ninja.Systems;
using Content.Shared.Popups;
using Content.Shared.PowerCell.Components;
using Content.Shared.Timing;
using Robust.Shared.Containers;
namespace Content.Server.Ninja.Systems;
@@ -94,7 +93,8 @@ public sealed class NinjaSuitSystem : SharedNinjaSuitSystem
// need 1 second of charge to turn on stealth
var chargeNeeded = SuitWattage(uid, comp);
// being attacked while cloaked gives no power message since it overloads the power supply or something
if (!_ninja.GetNinjaBattery(user, out var _, out var battery) || battery.CurrentCharge < chargeNeeded || UseDelay.ActiveDelay(user))
if (!_ninja.GetNinjaBattery(user, out var _, out var battery) || battery.CurrentCharge < chargeNeeded
|| !TryComp(user, out UseDelayComponent? useDelay) || UseDelay.IsDelayed((user, useDelay)))
{
_popup.PopupEntity(Loc.GetString("ninja-no-power"), user, user);
args.Cancel();
@@ -108,7 +108,8 @@ public sealed class NinjaSuitSystem : SharedNinjaSuitSystem
{
args.Handled = true;
var user = args.Performer;
if (!_ninja.TryUseCharge(user, comp.ThrowingStarCharge) || UseDelay.ActiveDelay(user))
if (!_ninja.TryUseCharge(user, comp.ThrowingStarCharge)
|| !TryComp(user, out UseDelayComponent? useDelay) || UseDelay.IsDelayed((user, useDelay)))
{
_popup.PopupEntity(Loc.GetString("ninja-no-power"), user, user);
return;
@@ -130,7 +131,8 @@ public sealed class NinjaSuitSystem : SharedNinjaSuitSystem
var coords = _transform.GetWorldPosition(katana);
var distance = (_transform.GetWorldPosition(user) - coords).Length();
var chargeNeeded = (float) distance * comp.RecallCharge;
if (!_ninja.TryUseCharge(user, chargeNeeded) || UseDelay.ActiveDelay(user))
if (!_ninja.TryUseCharge(user, chargeNeeded)
|| !TryComp(user, out UseDelayComponent? useDelay) || UseDelay.IsDelayed((user, useDelay)))
{
_popup.PopupEntity(Loc.GetString("ninja-no-power"), user, user);
return;
@@ -147,14 +149,15 @@ public sealed class NinjaSuitSystem : SharedNinjaSuitSystem
{
args.Handled = true;
var user = args.Performer;
if (!_ninja.TryUseCharge(user, comp.EmpCharge) || UseDelay.ActiveDelay(user))
if (!_ninja.TryUseCharge(user, comp.EmpCharge)
|| !TryComp(user, out UseDelayComponent? useDelay) || UseDelay.IsDelayed((user, useDelay)))
{
_popup.PopupEntity(Loc.GetString("ninja-no-power"), user, user);
return;
}
// I don't think this affects the suit battery, but if it ever does in the future add a blacklist for it
var coords = Transform(user).MapPosition;
var coords = _transform.GetMapCoordinates(user);
_emp.EmpPulse(coords, comp.EmpRange, comp.EmpConsumption, comp.EmpDuration);
}
}

View File

@@ -70,7 +70,7 @@ public sealed class PowerSwitchableSystem : SharedPowerSwitchableSystem
return;
// no sound spamming
if (TryComp<UseDelayComponent>(uid, out var useDelay) && _useDelay.ActiveDelay(uid))
if (!TryComp(uid, out UseDelayComponent? useDelay) || _useDelay.IsDelayed((uid, useDelay)))
return;
comp.ActiveIndex = NextIndex(uid, comp);
@@ -110,7 +110,7 @@ public sealed class PowerSwitchableSystem : SharedPowerSwitchableSystem
_audio.PlayPvs(comp.SwitchSound, uid);
_useDelay.BeginDelay(uid, useDelay);
_useDelay.TryResetDelay((uid, useDelay));
}
}

View File

@@ -13,32 +13,21 @@ public sealed partial class RadiationCollectorComponent : Component
/// <summary>
/// How much joules will collector generate for each rad.
/// </summary>
[DataField("chargeModifier")]
[DataField]
[ViewVariables(VVAccess.ReadWrite)]
public float ChargeModifier = 30000f;
/// <summary>
/// Cooldown time between users interaction.
/// Is the machine enabled.
/// </summary>
[DataField("cooldown")]
[ViewVariables(VVAccess.ReadWrite)]
public TimeSpan Cooldown = TimeSpan.FromSeconds(0.81f);
/// <summary>
/// Was machine activated by user?
/// </summary>
[ViewVariables(VVAccess.ReadOnly)]
[DataField]
[ViewVariables]
public bool Enabled;
/// <summary>
/// Timestamp when machine can be deactivated again.
/// </summary>
public TimeSpan CoolDownEnd;
/// <summary>
/// List of gases that will react to the radiation passing through the collector
/// </summary>
[DataField("radiationReactiveGases")]
[DataField]
[ViewVariables(VVAccess.ReadWrite)]
public List<RadiationReactiveGas>? RadiationReactiveGases;
}
@@ -52,13 +41,13 @@ public sealed partial class RadiationReactiveGas
/// <summary>
/// The reactant gas
/// </summary>
[DataField("reactantPrototype", required: true)]
public Gas Reactant = Gas.Plasma;
[DataField(required: true)]
public Gas ReactantPrototype;
/// <summary>
/// Multipier for the amount of power produced by the radiation collector when using this gas
/// </summary>
[DataField("powerGenerationEfficiency")]
[DataField]
public float PowerGenerationEfficiency = 1f;
/// <summary>
@@ -67,7 +56,7 @@ public sealed partial class RadiationReactiveGas
/// /// <remarks>
/// Set to zero if the reactant does not deplete
/// </remarks>
[DataField("reactantBreakdownRate")]
[DataField]
public float ReactantBreakdownRate = 1f;
/// <summary>
@@ -76,12 +65,12 @@ public sealed partial class RadiationReactiveGas
/// <remarks>
/// Leave null if the reactant no byproduct gas is to be formed
/// </remarks>
[DataField("byproductPrototype")]
public Gas? Byproduct = null;
[DataField]
public Gas? Byproduct;
/// <summary>
/// The molar ratio of the byproduct gas generated from the reactant gas
/// </summary>
[DataField("molarRatio")]
[DataField]
public float MolarRatio = 1f;
}

View File

@@ -1,16 +1,19 @@
using Content.Server.Singularity.Components;
using Content.Shared.Interaction;
using Content.Shared.Singularity.Components;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using Content.Server.Atmos;
using Content.Server.Atmos.Components;
using Content.Server.Popups;
using Content.Server.Power.Components;
using Content.Shared.Radiation.Events;
using Robust.Shared.Timing;
using Robust.Shared.Containers;
using Content.Server.Atmos.Components;
using Content.Shared.Examine;
using Content.Server.Atmos;
using System.Diagnostics.CodeAnalysis;
using Content.Server.Power.EntitySystems;
using Content.Server.Singularity.Components;
using Content.Shared.Atmos;
using Content.Shared.Examine;
using Content.Shared.Interaction;
using Content.Shared.Radiation.Events;
using Content.Shared.Singularity.Components;
using Content.Shared.Timing;
using Robust.Shared.Containers;
using Robust.Shared.Timing;
namespace Content.Server.Singularity.EntitySystems;
@@ -20,6 +23,10 @@ public sealed class RadiationCollectorSystem : EntitySystem
[Dependency] private readonly PopupSystem _popupSystem = default!;
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
[Dependency] private readonly SharedContainerSystem _containerSystem = default!;
[Dependency] private readonly UseDelaySystem _useDelay = default!;
[Dependency] private readonly BatterySystem _batterySystem = default!;
private const string GasTankContainer = "gas_tank";
public override void Initialize()
{
@@ -36,12 +43,11 @@ public sealed class RadiationCollectorSystem : EntitySystem
private bool TryGetLoadedGasTank(EntityUid uid, [NotNullWhen(true)] out GasTankComponent? gasTankComponent)
{
gasTankComponent = null;
var container = _containerSystem.EnsureContainer<ContainerSlot>(uid, "GasTank");
if (container.ContainedEntity == null)
if (!_containerSystem.TryGetContainer(uid, GasTankContainer, out var container) || container.ContainedEntities.Count == 0)
return false;
if (!EntityManager.TryGetComponent(container.ContainedEntity, out gasTankComponent))
if (!EntityManager.TryGetComponent(container.ContainedEntities.First(), out gasTankComponent))
return false;
return true;
@@ -61,13 +67,10 @@ public sealed class RadiationCollectorSystem : EntitySystem
private void OnInteractHand(EntityUid uid, RadiationCollectorComponent component, InteractHandEvent args)
{
var curTime = _gameTiming.CurTime;
if (curTime < component.CoolDownEnd)
if (TryComp(uid, out UseDelayComponent? useDelay) && !_useDelay.TryResetDelay((uid, useDelay), true))
return;
ToggleCollector(uid, args.User, component);
component.CoolDownEnd = curTime + component.Cooldown;
}
private void OnRadiation(EntityUid uid, RadiationCollectorComponent component, OnIrradiatedEvent args)
@@ -82,7 +85,7 @@ public sealed class RadiationCollectorSystem : EntitySystem
foreach (var gas in component.RadiationReactiveGases)
{
float reactantMol = gasTankComponent.Air.GetMoles(gas.Reactant);
float reactantMol = gasTankComponent.Air.GetMoles(gas.ReactantPrototype);
float delta = args.TotalRads * reactantMol * gas.ReactantBreakdownRate;
// We need to offset the huge power gains possible when using very cold gases
@@ -95,7 +98,7 @@ public sealed class RadiationCollectorSystem : EntitySystem
if (delta > 0)
{
gasTankComponent.Air.AdjustMoles(gas.Reactant, -Math.Min(delta, reactantMol));
gasTankComponent.Air.AdjustMoles(gas.ReactantPrototype, -Math.Min(delta, reactantMol));
}
if (gas.Byproduct != null)
@@ -111,7 +114,7 @@ public sealed class RadiationCollectorSystem : EntitySystem
// This still won't stop things being potentially hilariously unbalanced though.
if (TryComp<BatteryComponent>(uid, out var batteryComponent))
{
batteryComponent.CurrentCharge += charge;
_batterySystem.SetCharge(uid, charge, batteryComponent);
}
// Update appearance

View File

@@ -12,6 +12,7 @@ using Content.Shared.Storage.EntitySystems;
using Content.Shared.Timing;
using Content.Shared.Verbs;
using Robust.Server.GameObjects;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Input.Binding;
using Robust.Shared.Map;
using Robust.Shared.Player;
@@ -26,6 +27,8 @@ public sealed partial class StorageSystem : SharedStorageSystem
[Dependency] private readonly IPrototypeManager _prototype = default!;
[Dependency] private readonly InventorySystem _inventory = default!;
[Dependency] private readonly UserInterfaceSystem _uiSystem = default!;
[Dependency] private readonly SharedAudioSystem _audio = default!;
[Dependency] private readonly UseDelaySystem _useDelay = default!;
public override void Initialize()
{
@@ -123,12 +126,12 @@ public sealed partial class StorageSystem : SharedStorageSystem
return;
// prevent spamming bag open / honkerton honk sound
silent |= TryComp<UseDelayComponent>(uid, out var useDelay) && UseDelay.ActiveDelay(uid, useDelay);
silent |= TryComp<UseDelayComponent>(uid, out var useDelay) && _useDelay.IsDelayed((uid, useDelay));
if (!silent)
{
Audio.PlayPvs(storageComp.StorageOpenSound, uid);
_audio.PlayPvs(storageComp.StorageOpenSound, uid);
if (useDelay != null)
UseDelay.BeginDelay(uid, useDelay);
_useDelay.TryResetDelay((uid, useDelay));
}
Log.Debug($"Storage (UID {uid}) \"used\" by player session (UID {player.PlayerSession.AttachedEntity}).");

View File

@@ -3,7 +3,6 @@ using Content.Server.Xenoarchaeology.Equipment.Components;
using Content.Server.Xenoarchaeology.XenoArtifacts;
using Content.Shared.Interaction;
using Content.Shared.Timing;
using Robust.Shared.Player;
namespace Content.Server.Xenoarchaeology.Equipment.Systems;
@@ -31,7 +30,11 @@ public sealed class NodeScannerSystem : EntitySystem
args.Handled = true;
var target = args.Target.Value;
_useDelay.BeginDelay(uid);
if (TryComp(uid, out UseDelayComponent? useDelay)
&& !_useDelay.TryResetDelay((uid, useDelay), true))
return;
_popupSystem.PopupEntity(Loc.GetString("node-scan-popup",
("id", $"{artifact.CurrentNodeId}")), target);
}

View File

@@ -1,9 +1,13 @@
using Content.Shared.Clothing.Components;
using Content.Shared.Hands.Components;
using Content.Shared.Hands.EntitySystems;
using Content.Shared.Humanoid;
using Content.Shared.Interaction.Events;
using Content.Shared.Inventory;
using Content.Shared.Inventory.Events;
using Content.Shared.Item;
using Content.Shared.Tag;
using Content.Shared.Timing;
using Robust.Shared.GameStates;
namespace Content.Shared.Clothing.EntitySystems;
@@ -13,6 +17,8 @@ public abstract class ClothingSystem : EntitySystem
[Dependency] private readonly SharedItemSystem _itemSys = default!;
[Dependency] private readonly SharedHumanoidAppearanceSystem _humanoidSystem = default!;
[Dependency] private readonly TagSystem _tagSystem = default!;
[Dependency] private readonly InventorySystem _invSystem = default!;
[Dependency] private readonly SharedHandsSystem _handsSystem = default!;
[ValidatePrototypeId<TagPrototype>]
private const string HairTag = "HidesHair";
@@ -21,12 +27,60 @@ public abstract class ClothingSystem : EntitySystem
{
base.Initialize();
SubscribeLocalEvent<ClothingComponent, UseInHandEvent>(OnUseInHand);
SubscribeLocalEvent<ClothingComponent, ComponentGetState>(OnGetState);
SubscribeLocalEvent<ClothingComponent, ComponentHandleState>(OnHandleState);
SubscribeLocalEvent<ClothingComponent, GotEquippedEvent>(OnGotEquipped);
SubscribeLocalEvent<ClothingComponent, GotUnequippedEvent>(OnGotUnequipped);
SubscribeLocalEvent<ClothingComponent, ItemMaskToggledEvent>(OnMaskToggled);
}
private void OnUseInHand(Entity<ClothingComponent> ent, ref UseInHandEvent args)
{
if (args.Handled || !ent.Comp.QuickEquip)
return;
var user = args.User;
if (!TryComp(user, out InventoryComponent? inv) ||
!TryComp(user, out HandsComponent? hands))
return;
QuickEquip(ent, (user, inv, hands));
args.Handled = true;
args.ApplyDelay = false;
}
private void QuickEquip(
Entity<ClothingComponent> toEquipEnt,
Entity<InventoryComponent, HandsComponent> userEnt)
{
foreach (var slotDef in userEnt.Comp1.Slots)
{
if (!_invSystem.CanEquip(userEnt, toEquipEnt, slotDef.Name, out _, slotDef, userEnt, toEquipEnt))
continue;
if (_invSystem.TryGetSlotEntity(userEnt, slotDef.Name, out var slotEntity, userEnt))
{
// Item in slot has to be quick equipable as well
if (TryComp(slotEntity, out ClothingComponent? item) && !item.QuickEquip)
continue;
if (!_invSystem.TryUnequip(userEnt, slotDef.Name, true, inventory: userEnt, clothing: toEquipEnt))
continue;
if (!_invSystem.TryEquip(userEnt, toEquipEnt, slotDef.Name, true, inventory: userEnt, clothing: toEquipEnt))
continue;
_handsSystem.PickupOrDrop(userEnt, slotEntity.Value, handsComp: userEnt);
}
else
{
if (!_invSystem.TryEquip(userEnt, toEquipEnt, slotDef.Name, true, inventory: userEnt, clothing: toEquipEnt))
continue;
}
break;
}
}
protected virtual void OnGotEquipped(EntityUid uid, ClothingComponent component, GotEquippedEvent args)
{
@@ -71,7 +125,7 @@ public abstract class ClothingSystem : EntitySystem
clothing.EquippedPrefix = prefix;
_itemSys.VisualsChanged(uid);
Dirty(clothing);
Dirty(uid, clothing);
}
public void SetSlots(EntityUid uid, SlotFlags slots, ClothingComponent? clothing = null)
@@ -80,7 +134,7 @@ public abstract class ClothingSystem : EntitySystem
return;
clothing.Slots = slots;
Dirty(clothing);
Dirty(uid, clothing);
}
/// <summary>
@@ -97,7 +151,7 @@ public abstract class ClothingSystem : EntitySystem
clothing.FemaleMask = otherClothing.FemaleMask;
_itemSys.VisualsChanged(uid);
Dirty(clothing);
Dirty(uid, clothing);
}
#endregion

View File

@@ -1,26 +0,0 @@
using Robust.Shared.Timing;
namespace Content.Shared.Cooldown
{
/// <summary>
/// Utilities for working with cooldowns.
/// </summary>
public static class Cooldowns
{
/// <param name="gameTiming">game timing to use, otherwise will resolve using IoCManager.</param>
/// <returns>a cooldown interval starting at GameTiming.Curtime and ending at (offset) from CurTime.
/// For example, passing TimeSpan.FromSeconds(5) will create an interval
/// from now to 5 seconds from now.</returns>
public static (TimeSpan start, TimeSpan end) FromNow(TimeSpan offset, IGameTiming? gameTiming = null)
{
var now = (gameTiming ?? IoCManager.Resolve<IGameTiming>()).CurTime;
return (now, now + offset);
}
/// <see cref="FromNow"/>
public static (TimeSpan start, TimeSpan end) SecondsFromNow(double seconds, IGameTiming? gameTiming = null)
{
return FromNow(TimeSpan.FromSeconds(seconds), gameTiming);
}
}
}

View File

@@ -1,51 +0,0 @@
using Robust.Shared.GameStates;
using Robust.Shared.Serialization;
namespace Content.Shared.Cooldown
{
/// <summary>
/// Stores a visual "cooldown" for items, that gets displayed in the hands GUI.
/// </summary>
[RegisterComponent, NetworkedComponent]
[AutoGenerateComponentState]
public sealed partial class ItemCooldownComponent : Component
{
// TODO: access and system setting and dirtying not this funny stuff
private TimeSpan? _cooldownEnd;
private TimeSpan? _cooldownStart;
/// <summary>
/// The time when this cooldown ends.
/// </summary>
/// <remarks>
/// If null, no cooldown is displayed.
/// </remarks>
[ViewVariables, AutoNetworkedField]
public TimeSpan? CooldownEnd
{
get => _cooldownEnd;
set
{
_cooldownEnd = value;
Dirty();
}
}
/// <summary>
/// The time when this cooldown started.
/// </summary>
/// <remarks>
/// If null, no cooldown is displayed.
/// </remarks>
[ViewVariables, AutoNetworkedField]
public TimeSpan? CooldownStart
{
get => _cooldownStart;
set
{
_cooldownStart = value;
Dirty();
}
}
}
}

View File

@@ -1,3 +1,5 @@
using Content.Shared.Clothing.EntitySystems;
using Content.Shared.Timing;
using JetBrains.Annotations;
namespace Content.Shared.Interaction.Events;
@@ -11,7 +13,13 @@ public sealed class UseInHandEvent : HandledEntityEventArgs
/// <summary>
/// Entity holding the item in their hand.
/// </summary>
public EntityUid User { get; }
public EntityUid User;
/// <summary>
/// Whether or not to apply a UseDelay when used.
/// Mostly used by the <see cref="ClothingSystem"/> quick-equip to not apply the delay to entities that have the <see cref="UseDelayComponent"/>.
/// </summary>
public bool ApplyDelay = true;
public UseInHandEvent(EntityUid user)
{

View File

@@ -6,7 +6,6 @@ using Content.Shared.Administration.Logs;
using Content.Shared.Administration.Managers;
using Content.Shared.CombatMode;
using Content.Shared.Database;
using Content.Shared.DragDrop;
using Content.Shared.Hands;
using Content.Shared.Hands.Components;
using Content.Shared.Input;
@@ -21,7 +20,6 @@ using Content.Shared.Popups;
using Content.Shared.Pulling;
using Content.Shared.Pulling.Components;
using Content.Shared.Tag;
using Content.Shared.Throwing;
using Content.Shared.Timing;
using Content.Shared.Verbs;
using Content.Shared.Wall;
@@ -67,8 +65,7 @@ namespace Content.Shared.Interaction
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly TagSystem _tagSystem = default!;
private const CollisionGroup InRangeUnobstructedMask
= CollisionGroup.Impassable | CollisionGroup.InteractImpassable;
private const CollisionGroup InRangeUnobstructedMask = CollisionGroup.Impassable | CollisionGroup.InteractImpassable;
public const float InteractionRange = 1.5f;
public const float InteractionRangeSquared = InteractionRange * InteractionRange;
@@ -170,7 +167,6 @@ namespace Content.Shared.Interaction
QueueDel(uid);
}
private bool HandleTryPullObject(ICommonSession? session, EntityCoordinates coords, EntityUid uid)
{
if (!ValidateClientInput(session, coords, uid, out var userEntity))
@@ -953,7 +949,7 @@ namespace Content.Shared.Interaction
UseDelayComponent? delayComponent = null;
if (checkUseDelay
&& TryComp(used, out delayComponent)
&& delayComponent.ActiveDelay)
&& _useDelay.IsDelayed((used, delayComponent)))
return false;
if (checkCanInteract && !_actionBlockerSystem.CanInteract(user, used))
@@ -977,7 +973,8 @@ namespace Content.Shared.Interaction
return false;
DoContactInteraction(user, used, activateMsg);
_useDelay.BeginDelay(used, delayComponent);
if (delayComponent != null)
_useDelay.TryResetDelay((used, delayComponent));
if (!activateMsg.WasLogged)
_adminLogger.Add(LogType.InteractActivate, LogImpact.Low, $"{ToPrettyString(user):user} activated {ToPrettyString(used):used}");
return true;
@@ -1002,7 +999,7 @@ namespace Content.Shared.Interaction
if (checkUseDelay
&& TryComp(used, out delayComponent)
&& delayComponent.ActiveDelay)
&& _useDelay.IsDelayed((used, delayComponent)))
return true; // if the item is on cooldown, we consider this handled.
if (checkCanInteract && !_actionBlockerSystem.CanInteract(user, used))
@@ -1016,7 +1013,8 @@ namespace Content.Shared.Interaction
if (useMsg.Handled)
{
DoContactInteraction(user, used, useMsg);
_useDelay.BeginDelay(used, delayComponent);
if (delayComponent != null && useMsg.ApplyDelay)
_useDelay.TryResetDelay((used, delayComponent));
return true;
}

View File

@@ -4,18 +4,13 @@ using Content.Shared.Hands;
using Content.Shared.Hands.Components;
using Content.Shared.Hands.EntitySystems;
using Content.Shared.Interaction;
using Content.Shared.Interaction.Events;
using Content.Shared.Inventory.Events;
using Content.Shared.Item;
using Content.Shared.Movement.Systems;
using Content.Shared.Popups;
using Content.Shared.Strip.Components;
using Robust.Shared.Audio;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Containers;
using Robust.Shared.Network;
using Robust.Shared.Player;
using Robust.Shared.Prototypes;
using Robust.Shared.Timing;
using Robust.Shared.Utility;
@@ -31,7 +26,6 @@ public abstract partial class InventorySystem
[Dependency] private readonly SharedContainerSystem _containerSystem = default!;
[Dependency] private readonly SharedHandsSystem _handsSystem = default!;
[Dependency] private readonly IGameTiming _gameTiming = default!;
[Dependency] private readonly INetManager _netMan = default!;
[Dependency] private readonly SharedTransformSystem _transform = default!;
[ValidatePrototypeId<ItemSizePrototype>]
@@ -46,41 +40,6 @@ public abstract partial class InventorySystem
SubscribeAllEvent<UseSlotNetworkMessage>(OnUseSlot);
}
protected void QuickEquip(EntityUid uid, ClothingComponent component, UseInHandEvent args)
{
if (!TryComp(args.User, out InventoryComponent? inv) || !HasComp<HandsComponent>(args.User))
return;
foreach (var slotDef in inv.Slots)
{
if (!CanEquip(args.User, uid, slotDef.Name, out _, slotDef, inv))
continue;
if (TryGetSlotEntity(args.User, slotDef.Name, out var slotEntity, inv))
{
// Item in slot has to be quick equipable as well
if (TryComp(slotEntity, out ClothingComponent? item) && !item.QuickEquip)
continue;
if (!TryUnequip(args.User, slotDef.Name, true, inventory: inv))
continue;
if (!TryEquip(args.User, uid, slotDef.Name, true, inventory: inv))
continue;
_handsSystem.PickupOrDrop(args.User, slotEntity.Value);
}
else
{
if (!TryEquip(args.User, uid, slotDef.Name, true, inventory: inv))
continue;
}
args.Handled = true;
break;
}
}
private void OnEntRemoved(EntityUid uid, InventoryComponent component, EntRemovedFromContainerMessage args)
{
if(!TryGetSlot(uid, args.Container.ID, out var slotDef, inventory: component))

View File

@@ -1,9 +1,6 @@
using Content.Shared.Mech;
using Content.Shared.Mech.Equipment.Components;
using Content.Shared.Mech.Equipment.Systems;
using Content.Shared.Timing;
using Robust.Shared.Audio;
using System.Linq;
using Content.Shared.Mech.Equipment.Components;
using Content.Shared.Timing;
using Robust.Shared.Audio.Systems;
namespace Content.Shared.Mech.Equipment.Systems;
@@ -47,12 +44,11 @@ public sealed class MechSoundboardSystem : EntitySystem
if (msg.Sound >= comp.Sounds.Count)
return;
if (_useDelay.ActiveDelay(uid))
if (TryComp(uid, out UseDelayComponent? useDelay)
&& !_useDelay.TryResetDelay((uid, useDelay), true))
return;
// honk!!!!!
var mech = equipment.EquipmentOwner.Value;
_useDelay.BeginDelay(uid);
_audio.PlayPvs(comp.Sounds[msg.Sound], uid);
}
}

View File

@@ -8,7 +8,6 @@ using Content.Shared.Inventory.Events;
using Content.Shared.Ninja.Components;
using Content.Shared.Popups;
using Content.Shared.Research.Components;
using Content.Shared.Timing;
using Content.Shared.Toggleable;
using Robust.Shared.Timing;
@@ -24,7 +23,6 @@ public abstract class SharedNinjaGlovesSystem : EntitySystem
[Dependency] private readonly SharedCombatModeSystem _combatMode = default!;
[Dependency] protected readonly SharedInteractionSystem Interaction = default!;
[Dependency] protected readonly SharedPopupSystem Popup = default!;
[Dependency] private readonly UseDelaySystem _useDelay = default!;
[Dependency] private readonly ActionContainerSystem _actionContainer = default!;
public override void Initialize()
@@ -110,7 +108,6 @@ public abstract class SharedNinjaGlovesSystem : EntitySystem
target = args.Target;
return _timing.IsFirstTimePredicted
&& !_combatMode.IsInCombatMode(uid)
&& !_useDelay.ActiveDelay(uid)
&& TryComp<HandsComponent>(uid, out var hands)
&& hands.ActiveHandEntity == null
&& Interaction.InRangeUnobstructed(uid, target);

View File

@@ -15,7 +15,7 @@ public abstract class SharedNinjaSuitSystem : EntitySystem
{
[Dependency] private readonly SharedAudioSystem _audio = default!;
[Dependency] private readonly SharedNinjaGlovesSystem _gloves = default!;
[Dependency] protected readonly SharedSpaceNinjaSystem _ninja = default!;
[Dependency] private readonly SharedSpaceNinjaSystem _ninja = default!;
[Dependency] protected readonly StealthClothingSystem StealthClothing = default!;
[Dependency] protected readonly UseDelaySystem UseDelay = default!;
[Dependency] private readonly ActionContainerSystem _actionContainer = default!;
@@ -112,8 +112,8 @@ public abstract class SharedNinjaSuitSystem : EntitySystem
_audio.PlayPredicted(comp.RevealSound, uid, user);
// all abilities check for a usedelay on the ninja
var useDelay = EnsureComp<UseDelayComponent>(user);
useDelay.Delay = comp.DisableTime;
UseDelay.BeginDelay(user, useDelay);
UseDelay.SetDelay((user, useDelay), comp.DisableTime);
UseDelay.TryResetDelay((user, useDelay));
}
// TODO: modify PowerCellDrain

View File

@@ -1,28 +1,36 @@
using Robust.Shared.GameStates;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
namespace Content.Shared.Timing;
/// <summary>
/// Timer that creates a cooldown each time an object is activated/used
/// </summary>
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState(true)]
/// <remarks>
/// Currently it only supports a single delay per entity, this means that for things that have two delay interactions they will share one timer, so this can cause issues. For example, the bible has a delay when opening the storage UI and when applying it's interaction effect, and they share the same delay.
/// </remarks>
[RegisterComponent]
[NetworkedComponent, AutoGenerateComponentState]
[Access(typeof(UseDelaySystem))]
public sealed partial class UseDelayComponent : Component
{
[AutoNetworkedField]
public TimeSpan LastUseTime;
[AutoNetworkedField]
public TimeSpan? DelayEndTime;
[DataField, AutoNetworkedField]
[ViewVariables(VVAccess.ReadWrite)]
public TimeSpan Delay = TimeSpan.FromSeconds(1);
/// <summary>
/// When the delay starts.
/// </summary>
[ViewVariables(VVAccess.ReadWrite), DataField(customTypeSerializer: typeof(TimeOffsetSerializer)), AutoNetworkedField]
public TimeSpan DelayStartTime;
/// <summary>
/// Stores remaining delay pausing (and eventually, serialization).
/// When the delay ends.
/// </summary>
[ViewVariables(VVAccess.ReadWrite), DataField(customTypeSerializer: typeof(TimeOffsetSerializer)), AutoNetworkedField]
public TimeSpan DelayEndTime;
/// <summary>
/// Default delay time
/// </summary>
[DataField]
public TimeSpan? RemainingDelay;
public bool ActiveDelay => DelayEndTime != null;
[ViewVariables(VVAccess.ReadWrite)]
[AutoNetworkedField]
public TimeSpan Delay = TimeSpan.FromSeconds(1);
}

View File

@@ -1,125 +1,64 @@
using Content.Shared.Cooldown;
using Robust.Shared.Timing;
using Robust.Shared.Utility;
namespace Content.Shared.Timing;
public sealed class UseDelaySystem : EntitySystem
{
[Dependency] private readonly IGameTiming _gameTiming = default!;
private HashSet<UseDelayComponent> _activeDelays = new();
[Dependency] private readonly MetaDataSystem _metadata = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<UseDelayComponent, AfterAutoHandleStateEvent>(OnHandleState);
SubscribeLocalEvent<UseDelayComponent, EntityPausedEvent>(OnPaused);
SubscribeLocalEvent<UseDelayComponent, EntityUnpausedEvent>(OnUnpaused);
}
private void OnPaused(EntityUid uid, UseDelayComponent component, ref EntityPausedEvent args)
private void OnUnpaused(Entity<UseDelayComponent> ent, ref EntityUnpausedEvent args)
{
// This entity just got paused, but wasn't before
if (component.DelayEndTime != null)
component.RemainingDelay = _gameTiming.CurTime - component.DelayEndTime;
_activeDelays.Remove(component);
Dirty(component);
// We got unpaused, resume the delay
ent.Comp.DelayStartTime += args.PausedTime;
ent.Comp.DelayEndTime += args.PausedTime;
Dirty(ent);
}
private void OnUnpaused(EntityUid uid, UseDelayComponent component, ref EntityUnpausedEvent args)
public void SetDelay(Entity<UseDelayComponent> ent, TimeSpan delay)
{
if (component.RemainingDelay == null)
if (ent.Comp.Delay == delay)
return;
// We got unpaused, resume the delay/cooldown. Currently this takes for granted that ItemCooldownComponent
// handles the pausing on its own. I'm not even gonna check, because I CBF fixing it if it doesn't.
component.DelayEndTime = _gameTiming.CurTime + component.RemainingDelay;
Dirty(component);
_activeDelays.Add(component);
}
private void OnHandleState(EntityUid uid, UseDelayComponent component, ref AfterAutoHandleStateEvent args)
{
if (component.DelayEndTime == null)
_activeDelays.Remove(component);
else
_activeDelays.Add(component);
}
public override void Update(float frameTime)
{
base.Update(frameTime);
var toRemove = new RemQueue<UseDelayComponent>();
var curTime = _gameTiming.CurTime;
var mQuery = EntityManager.GetEntityQuery<MetaDataComponent>();
// TODO refactor this to use active components
foreach (var delay in _activeDelays)
{
if (delay.DelayEndTime == null ||
curTime > delay.DelayEndTime ||
Deleted(delay.Owner, mQuery))
{
toRemove.Add(delay);
}
}
foreach (var delay in toRemove)
{
delay.DelayEndTime = null;
_activeDelays.Remove(delay);
Dirty(delay);
}
ent.Comp.Delay += delay;
Dirty(ent);
}
/// <summary>
/// Attempts tp start a use-delay for some entity. Returns true unless there is already an active delay.
/// Returns true if the entity has a currently active UseDelay.
/// </summary>
/// <remarks>
/// Note that this will always return true if the entity does not have a use delay component, as in that case there
/// is no reason to block/prevent an interaction.
/// </remarks>
public bool BeginDelay(EntityUid uid, UseDelayComponent? component = null)
public bool IsDelayed(Entity<UseDelayComponent> ent)
{
if (!Resolve(uid, ref component, false))
return true;
return ent.Comp.DelayEndTime >= _gameTiming.CurTime;
}
if (component.ActiveDelay)
/// <summary>
/// Cancels the current delay.
/// </summary>
public void CancelDelay(Entity<UseDelayComponent> ent)
{
ent.Comp.DelayEndTime = _gameTiming.CurTime;
Dirty(ent);
}
/// <summary>
/// Resets the UseDelay entirely for this entity if possible.
/// </summary>
/// <param name="checkDelayed">Check if the entity has an ongoing delay, return false if it does, return true if it does not.</param>
public bool TryResetDelay(Entity<UseDelayComponent> ent, bool checkDelayed = false)
{
if (checkDelayed && IsDelayed(ent))
return false;
DebugTools.Assert(!_activeDelays.Contains(component));
_activeDelays.Add(component);
var currentTime = _gameTiming.CurTime;
component.LastUseTime = currentTime;
component.DelayEndTime = currentTime + component.Delay;
Dirty(uid, component);
var cooldown = EnsureComp<ItemCooldownComponent>(uid);
cooldown.CooldownStart = currentTime;
cooldown.CooldownEnd = component.DelayEndTime;
var curTime = _gameTiming.CurTime;
ent.Comp.DelayStartTime = curTime;
ent.Comp.DelayEndTime = curTime - _metadata.GetPauseTime(ent) + ent.Comp.Delay;
Dirty(ent);
return true;
}
public bool ActiveDelay(EntityUid uid, UseDelayComponent? component = null)
{
return Resolve(uid, ref component, false) && component.ActiveDelay;
}
public void Cancel(UseDelayComponent component)
{
component.DelayEndTime = null;
_activeDelays.Remove(component);
Dirty(component);
if (TryComp<ItemCooldownComponent>(component.Owner, out var cooldown))
{
cooldown.CooldownEnd = _gameTiming.CurTime;
}
}
}

View File

@@ -6,10 +6,8 @@ using Content.Shared.Interaction;
using Content.Shared.Movement.Events;
using Content.Shared.Physics;
using Content.Shared.Projectiles;
using Content.Shared.Timing;
using Content.Shared.Weapons.Ranged.Components;
using Content.Shared.Weapons.Ranged.Systems;
using Robust.Shared.Audio;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Network;
using Robust.Shared.Physics;
@@ -30,7 +28,6 @@ public abstract class SharedGrapplingGunSystem : EntitySystem
[Dependency] private readonly SharedAudioSystem _audio = default!;
[Dependency] private readonly SharedJointSystem _joints = default!;
[Dependency] private readonly SharedPhysicsSystem _physics = default!;
[Dependency] private readonly UseDelaySystem _delay = default!;
public const string GrapplingJoint = "grappling";
@@ -117,10 +114,9 @@ public abstract class SharedGrapplingGunSystem : EntitySystem
private void OnGunActivate(EntityUid uid, GrapplingGunComponent component, ActivateInWorldEvent args)
{
if (!Timing.IsFirstTimePredicted || _delay.ActiveDelay(uid))
if (!Timing.IsFirstTimePredicted || args.Handled)
return;
_delay.BeginDelay(uid);
_audio.PlayPredicted(component.CycleSound, uid, args.User);
TryComp<AppearanceComponent>(uid, out var appearance);
@@ -137,6 +133,8 @@ public abstract class SharedGrapplingGunSystem : EntitySystem
component.Projectile = null;
Dirty(uid, component);
}
args.Handled = true;
}
private void SetReeling(EntityUid uid, GrapplingGunComponent component, bool value, EntityUid? user)

View File

@@ -15,6 +15,7 @@ public sealed class UseDelayOnShootSystem : EntitySystem
private void OnUseShoot(EntityUid uid, UseDelayOnShootComponent component, ref GunShotEvent args)
{
_delay.BeginDelay(uid);
if (TryComp(uid, out UseDelayComponent? useDelay))
_delay.TryResetDelay((uid, useDelay));
}
}

View File

@@ -1,27 +1,24 @@
using Content.Shared.DoAfter;
using Content.Shared.Hands;
using Content.Shared.Hands.Components;
using Content.Shared.Hands.EntitySystems;
using Content.Shared.Interaction.Events;
using Content.Shared.Item;
using Content.Shared.Popups;
using Content.Shared.Timing;
using Content.Shared.Verbs;
using Content.Shared.Weapons.Melee;
using Content.Shared.Weapons.Melee.Events;
using Content.Shared.Weapons.Melee.Components;
using Content.Shared.Weapons.Melee.Events;
using Content.Shared.Weapons.Ranged.Components;
using Content.Shared.Weapons.Ranged.Systems;
using Content.Shared.Wieldable.Components;
using Robust.Shared.Audio;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Player;
using Content.Shared.Timing;
namespace Content.Shared.Wieldable;
public sealed class WieldableSystem : EntitySystem
{
[Dependency] private readonly SharedDoAfterSystem _doAfter = default!;
[Dependency] private readonly SharedHandVirtualItemSystem _virtualItemSystem = default!;
[Dependency] private readonly SharedHandsSystem _handsSystem = default!;
[Dependency] private readonly SharedItemSystem _itemSystem = default!;
@@ -190,7 +187,9 @@ public sealed class WieldableSystem : EntitySystem
_virtualItemSystem.TrySpawnVirtualItemInHand(used, user);
}
_delay.BeginDelay(used);
if (TryComp(used, out UseDelayComponent? useDelay)
&& !_delay.TryResetDelay((used, useDelay), true))
return false;
_popupSystem.PopupClient(Loc.GetString("wieldable-component-successful-wield", ("item", used)), user, user);
_popupSystem.PopupEntity(Loc.GetString("wieldable-component-successful-wield-other", ("user", user), ("item", used)), user, Filter.PvsExcept(user), true);
@@ -224,6 +223,7 @@ public sealed class WieldableSystem : EntitySystem
{
if (args.User == null)
return;
if (!component.Wielded)
return;
@@ -255,6 +255,7 @@ public sealed class WieldableSystem : EntitySystem
{
if (!component.Wielded || uid != args.Unequipped)
return;
RaiseLocalEvent(uid, new ItemUnwieldedEvent(args.User, force: true), true);
}
@@ -268,6 +269,7 @@ public sealed class WieldableSystem : EntitySystem
{
if (!TryComp<WieldableComponent>(uid, out var wield))
return;
if (!wield.Wielded)
return;

View File

@@ -100405,7 +100405,6 @@ entities:
- Pressed: Toggle
1065:
- Pressed: Toggle
- type: ItemCooldown
- uid: 7826
components:
- type: Transform
@@ -100451,7 +100450,6 @@ entities:
- Pressed: Toggle
2822:
- Pressed: Toggle
- type: ItemCooldown
- uid: 8749
components:
- type: Transform
@@ -100550,7 +100548,6 @@ entities:
linkedPorts:
4205:
- Pressed: Toggle
- type: ItemCooldown
- uid: 17649
components:
- type: Transform
@@ -100563,7 +100560,6 @@ entities:
linkedPorts:
3066:
- Pressed: Toggle
- type: ItemCooldown
- proto: SignalButtonBridge
entities:
- uid: 4305

View File

@@ -67091,7 +67091,7 @@ entities:
3218:
- Pressed: Toggle
type: DeviceLinkSource
- type: ItemCooldown
- type: UseDelay
- uid: 5389
components:
- rot: 1.5707963267948966 rad
@@ -67104,7 +67104,7 @@ entities:
3218:
- Pressed: Toggle
type: DeviceLinkSource
- type: ItemCooldown
- type: UseDelay
- uid: 5447
components:
- rot: 3.141592653589793 rad

View File

@@ -74740,7 +74740,7 @@ entities:
1663:
- Pressed: Toggle
type: DeviceLinkSource
- type: ItemCooldown
- type: UseDelay
- uid: 9640
components:
- pos: -20.5,-1.5

View File

@@ -142471,7 +142471,6 @@ entities:
- Pressed: Toggle
20499:
- Pressed: Toggle
- type: ItemCooldown
- uid: 20513
components:
- type: Transform
@@ -142704,7 +142703,6 @@ entities:
- Pressed: Toggle
20423:
- Pressed: Toggle
- type: ItemCooldown
- uid: 20528
components:
- type: Transform

View File

@@ -118234,7 +118234,6 @@ entities:
- Pressed: Toggle
9404:
- Pressed: Toggle
- type: ItemCooldown
- uid: 8610
components:
- type: Transform

View File

@@ -135841,7 +135841,6 @@ entities:
- Pressed: Toggle
19434:
- Pressed: Toggle
- type: ItemCooldown
- uid: 19438
components:
- type: MetaData

View File

@@ -79806,7 +79806,6 @@ entities:
- pos: -46.5,62.5
parent: 2
type: Transform
- type: ItemCooldown
- proto: ClothingBackpackMedical
entities:
- uid: 12350
@@ -163449,7 +163448,6 @@ entities:
- On: Open
- Off: Close
type: DeviceLinkSource
- type: ItemCooldown
- uid: 24195
components:
- rot: -1.5707963267948966 rad
@@ -163481,7 +163479,6 @@ entities:
- On: Open
- Off: Close
type: DeviceLinkSource
- type: ItemCooldown
- uid: 24196
components:
- name: shutters switch
@@ -163514,7 +163511,6 @@ entities:
- On: Open
- Off: Close
type: DeviceLinkSource
- type: ItemCooldown
- uid: 24197
components:
- name: blast door switch
@@ -163528,7 +163524,6 @@ entities:
- On: Open
- Off: Close
type: DeviceLinkSource
- type: ItemCooldown
- uid: 24198
components:
- rot: -1.5707963267948966 rad
@@ -163557,7 +163552,6 @@ entities:
- On: Open
- Off: Close
type: DeviceLinkSource
- type: ItemCooldown
- uid: 24199
components:
- rot: 1.5707963267948966 rad
@@ -163572,7 +163566,6 @@ entities:
- On: Open
- Off: Close
type: DeviceLinkSource
- type: ItemCooldown
- uid: 24200
components:
- rot: 3.141592653589793 rad
@@ -163624,7 +163617,6 @@ entities:
- On: Open
- Off: Close
type: DeviceLinkSource
- type: ItemCooldown
- uid: 24204
components:
- rot: 3.141592653589793 rad
@@ -163671,7 +163663,6 @@ entities:
- On: Open
- Off: Close
type: DeviceLinkSource
- type: ItemCooldown
- uid: 24207
components:
- pos: -52.5,-11.5
@@ -163728,7 +163719,6 @@ entities:
- On: Open
- Off: Close
type: DeviceLinkSource
- type: ItemCooldown
- uid: 24210
components:
- pos: -49.5,24.5
@@ -163793,7 +163783,6 @@ entities:
- On: Open
- Off: Close
type: DeviceLinkSource
- type: ItemCooldown
- uid: 24214
components:
- pos: 58.5,48.5
@@ -164016,7 +164005,6 @@ entities:
- On: Open
- Off: Close
type: DeviceLinkSource
- type: ItemCooldown
- uid: 24228
components:
- pos: 54.5,51.5
@@ -164033,7 +164021,6 @@ entities:
- On: Open
- Off: Close
type: DeviceLinkSource
- type: ItemCooldown
- uid: 24229
components:
- pos: 5.5,49.5
@@ -164229,7 +164216,6 @@ entities:
- On: Open
- Off: Close
type: DeviceLinkSource
- type: ItemCooldown
- uid: 24238
components:
- rot: 3.141592653589793 rad
@@ -164273,7 +164259,6 @@ entities:
- On: Open
- Off: Close
type: DeviceLinkSource
- type: ItemCooldown
- uid: 24239
components:
- name: shutters switch
@@ -164294,7 +164279,6 @@ entities:
- Off: Close
- Status: Toggle
type: DeviceLinkSource
- type: ItemCooldown
- uid: 24240
components:
- pos: -51.5,36.5
@@ -164305,7 +164289,6 @@ entities:
- On: Open
- Off: Close
type: DeviceLinkSource
- type: ItemCooldown
- uid: 24241
components:
- name: shutters switch
@@ -164342,7 +164325,6 @@ entities:
- On: Open
- Off: Close
type: DeviceLinkSource
- type: ItemCooldown
- uid: 24242
components:
- name: visitation switch
@@ -164363,7 +164345,6 @@ entities:
- On: Open
- Off: Close
type: DeviceLinkSource
- type: ItemCooldown
- uid: 24243
components:
- name: shutters switch
@@ -164402,7 +164383,6 @@ entities:
- On: Open
- Off: Close
type: DeviceLinkSource
- type: ItemCooldown
- uid: 24245
components:
- name: shutters switch
@@ -164521,7 +164501,6 @@ entities:
- Off: Close
- Status: Toggle
type: DeviceLinkSource
- type: ItemCooldown
- uid: 24248
components:
- pos: -74.5,-43.5
@@ -175048,7 +175027,6 @@ entities:
- Right: Reverse
- Middle: Off
type: DeviceLinkSource
- type: ItemCooldown
- uid: 25925
components:
- pos: -41.5,17.5
@@ -175351,7 +175329,6 @@ entities:
- Right: Reverse
- Middle: Off
type: DeviceLinkSource
- type: ItemCooldown
- uid: 25933
components:
- pos: 47.5,39.5
@@ -175551,7 +175528,6 @@ entities:
- Right: Forward
- Middle: Off
type: DeviceLinkSource
- type: ItemCooldown
- proto: UnfinishedMachineFrame
entities:
- uid: 25938

View File

@@ -56927,7 +56927,6 @@ entities:
260:
- Pressed: Toggle
type: DeviceLinkSource
- type: ItemCooldown
- uid: 8766
components:
- pos: -13.5,12.5
@@ -56965,7 +56964,6 @@ entities:
7588:
- Pressed: Toggle
type: DeviceLinkSource
- type: ItemCooldown
- uid: 10449
components:
- pos: 51.5,18.5

View File

@@ -53,7 +53,6 @@
qualities:
- Rolling
speed: 0.25 # its small so takes longer to roll the entire dough flat
- type: ItemCooldown
- type: SpaceGarbage
- type: TrashOnSolutionEmpty
solution: drink

View File

@@ -37,7 +37,6 @@
damage:
types:
Blunt: 0
- type: ItemCooldown
- type: entity
parent: DrinkBaseCup

View File

@@ -16,7 +16,6 @@
prototype: MobHumanSyndicateAgent
- type: EmitSoundOnUse
sound: /Audio/Effects/Emotes/parp1.ogg
- type: ItemCooldown
- type: UseDelay
delay: 300

View File

@@ -5,9 +5,7 @@
description: A handy-dandy holographic projector that displays a janitorial sign.
components:
- type: HolosignProjector
- type: ItemCooldown
- type: UseDelay
delay: 1.0
- type: ContainerContainer
containers:
cell_slot: !type:ContainerSlot {}

View File

@@ -14,7 +14,6 @@
sprite: Objects/Fun/bikehorn.rsi
slots: [Belt]
quickEquip: false
- type: ItemCooldown
- type: EmitSoundOnUse
sound:
collection: BikeHorn
@@ -52,7 +51,7 @@
name: broken bike horn
description: A broken horn off of a bicycle.
components:
- type: ItemCooldown
- type: UseDelay
- type: Sprite
sprite: Objects/Fun/cluwnehorn.rsi
state: icon

View File

@@ -42,7 +42,6 @@
- type: Item
size: Tiny
sprite: Objects/Fun/Darts/dart_red.rsi
- type: ItemCooldown
- type: SolutionContainerManager
solutions:
melee:

View File

@@ -4,7 +4,6 @@
id: BaseDice
components:
- type: Dice
- type: ItemCooldown
- type: UseDelay
- type: Sprite
sprite: Objects/Fun/dice.rsi

View File

@@ -9,7 +9,6 @@
state: icon
- type: Item
sprite: Objects/Misc/skub.rsi
- type: ItemCooldown
- type: EmitSoundOnUse
sound:
collection: Skub

View File

@@ -19,7 +19,6 @@
- type: EmitSoundOnLand
sound:
collection: ToyFall
- type: ItemCooldown
- type: UseDelay
delay: 1.0
- type: MeleeWeapon
@@ -709,7 +708,7 @@
size: Small
sprite: Objects/Fun/toys.rsi
heldPrefix: foamblade
- type: ItemCooldown
- type: UseDelay
# MISC
@@ -1020,7 +1019,6 @@
sprite: Objects/Fun/whoopie.rsi
state: icon
quickEquip: false
- type: ItemCooldown
- type: EmitSoundOnUse
sound:
collection: Parp

View File

@@ -20,7 +20,6 @@
- enum.DamageStateVisualLayers.Base:
shard3: ""
- type: SpaceGarbage
- type: ItemCooldown
- type: MeleeWeapon
attackRate: 1.5
damage:

View File

@@ -18,7 +18,6 @@
shard2: ""
- enum.DamageStateVisualLayers.Base:
shard3: ""
- type: ItemCooldown
- type: MeleeWeapon
attackRate: 1.5
damage:

View File

@@ -5,7 +5,6 @@
description: In Space Glasgow this is called a conversation starter.
components:
- type: Sharp
- type: ItemCooldown
- type: MeleeWeapon
attackRate: 1.5
damage:
@@ -27,4 +26,3 @@
materialComposition:
Glass: 50
- type: SpaceGarbage

View File

@@ -32,7 +32,6 @@
params:
variation: 0.03
volume: 3
- type: ItemCooldown
- type: UseDelay
delay: 0.5
- type: MeleeWeapon

View File

@@ -24,7 +24,7 @@
- type: DrainableSolution
solution: spray
- type: SolutionTransfer
- type: ItemCooldown
- type: UseDelay
- type: Spray
transferAmount: 10
pushbackAmount: 60

View File

@@ -287,7 +287,6 @@
- type: Sprite
sprite: Objects/Misc/bureaucracy.rsi
state: overpriced_pen
- type: ItemCooldown
- type: MeleeWeapon
wideAnimationRotation: -45
damage:

View File

@@ -26,7 +26,6 @@
mixMessage: "bible-mixing-success"
reactionTypes:
- Holy
- type: ItemCooldown
- type: Sprite
sprite: Objects/Specific/Chapel/bible.rsi
state: icon

View File

@@ -45,7 +45,6 @@
solution: spray
- type: Spillable
solution: spray
- type: ItemCooldown
- type: Tag
tags:
- Spray

View File

@@ -11,7 +11,6 @@
- type: Sprite
sprite: Objects/Tools/Hydroponics/hoe.rsi
state: icon
- type: ItemCooldown
- type: MeleeWeapon
wideAnimationRotation: 135
swingLeft: true
@@ -33,7 +32,6 @@
- type: Sprite
sprite: Objects/Tools/Hydroponics/clippers.rsi
state: icon
- type: ItemCooldown
- type: MeleeWeapon
wideAnimationRotation: 90
damage:
@@ -53,7 +51,6 @@
- type: Sprite
sprite: Objects/Tools/Hydroponics/scythe.rsi
state: icon
- type: ItemCooldown
- type: MeleeWeapon
wideAnimationRotation: 135
damage:
@@ -81,7 +78,6 @@
- type: Sprite
sprite: Objects/Tools/Hydroponics/hatchet.rsi
state: icon
- type: ItemCooldown
- type: MeleeWeapon
wideAnimationRotation: 135
swingLeft: true
@@ -105,7 +101,6 @@
- type: Sprite
sprite: Objects/Tools/Hydroponics/spade.rsi
state: icon
- type: ItemCooldown
- type: MeleeWeapon
wideAnimationRotation: 45
damage:

View File

@@ -562,7 +562,6 @@
- type: Item
sprite: Objects/Specific/Janitorial/plunger.rsi
heldPrefix: plunger
- type: ItemCooldown
- type: GuideHelp
guides:
- Janitorial

View File

@@ -24,7 +24,7 @@
solution: spray
- type: SolutionTransfer
canChangeTransferAmount: true
- type: ItemCooldown
- type: UseDelay
- type: Spray
transferAmount: 10
sprayVelocity: 2

View File

@@ -29,7 +29,6 @@
False: { visible: false }
- type: Item
size: Large
- type: ItemCooldown
- type: Speech
speechVerb: Robotic
- type: Defibrillator

View File

@@ -22,7 +22,6 @@
state: cautery
- type: Item
sprite: Objects/Specific/Medical/Surgery/cautery.rsi
- type: ItemCooldown
- type: MeleeWeapon
damage:
types:
@@ -43,7 +42,6 @@
state: drill
- type: Item
sprite: Objects/Specific/Medical/Surgery/drill.rsi
- type: ItemCooldown
- type: MeleeWeapon
damage:
types:
@@ -69,7 +67,6 @@
state: scalpel
- type: Item
sprite: Objects/Specific/Medical/Surgery/scalpel.rsi
- type: ItemCooldown
- type: MeleeWeapon
attackRate: 1.5
damage:
@@ -128,7 +125,6 @@
state: retractor
- type: Item
sprite: Objects/Specific/Medical/Surgery/scissors.rsi
- type: ItemCooldown
- type: entity
name: hemostat
@@ -164,7 +160,6 @@
state: saw
- type: Item
sprite: Objects/Specific/Medical/Surgery/saw.rsi
- type: ItemCooldown
- type: Tool
qualities:
- Sawing

View File

@@ -12,7 +12,6 @@
- state: base
- state: green_bit
shader: unshaded
- type: ItemCooldown
- type: MeleeWeapon
damage:
types:

View File

@@ -10,7 +10,6 @@
- type: Sprite
sprite: Objects/Tools/Cowtools/haycutters.rsi
state: haycutters
- type: ItemCooldown
- type: MeleeWeapon
damage:
types:
@@ -36,7 +35,6 @@
state: moodriver
- type: Item
sprite: Objects/Tools/Cowtools/moodriver.rsi
- type: ItemCooldown
- type: MeleeWeapon
attackRate: 1.5
damage:
@@ -60,7 +58,6 @@
state: wronch
- type: Item
sprite: Objects/Tools/Cowtools/wronch.rsi
- type: ItemCooldown
- type: MeleeWeapon
attackRate: 1.5
damage:
@@ -84,7 +81,6 @@
state: cowbar
- type: Item
sprite: Objects/Tools/Cowtools/cowbar.rsi
- type: ItemCooldown
- type: MeleeWeapon
damage:
types:
@@ -185,4 +181,3 @@
- id: Mooltitool
- id: Cowelder
- id: Milkalyzer

View File

@@ -71,7 +71,7 @@
- type: Item
size: Tiny
sprite: Objects/Tools/lighters.rsi
- type: ItemCooldown
- type: UseDelay
- type: RefillableSolution
solution: Welder
- type: SolutionContainerManager

View File

@@ -13,7 +13,6 @@
- 0,0,6,3
- type: Item
size: Ginormous
- type: ItemCooldown
- type: MeleeWeapon
damage:
types:

View File

@@ -17,7 +17,6 @@
- state: cutters
map: [ "enum.DamageStateVisualLayers.Base" ]
- state: cutters-cutty-thingy
- type: ItemCooldown
- type: MeleeWeapon
wideAnimationRotation: -90
damage:
@@ -66,7 +65,6 @@
- type: Item
sprite: Objects/Tools/screwdriver.rsi
storedRotation: -90
- type: ItemCooldown
- type: MeleeWeapon
wideAnimationRotation: -90
attackRate: 1
@@ -110,7 +108,6 @@
storedSprite:
sprite: Objects/Tools/wrench.rsi
state: storage
- type: ItemCooldown
- type: MeleeWeapon
wideAnimationRotation: 135
attackRate: 1.5
@@ -149,7 +146,6 @@
storedSprite:
sprite: Objects/Tools/crowbar.rsi
state: storage
- type: ItemCooldown
- type: MeleeWeapon
wideAnimationRotation: -135
damage:
@@ -351,7 +347,6 @@
maxCharges: 5
charges: 5
- type: UseDelay
delay: 1.0
- type: Sprite
sprite: Objects/Tools/rcd.rsi
state: icon
@@ -500,7 +495,6 @@
- type: Sprite
sprite: Objects/Tools/shovel.rsi
state: icon
- type: ItemCooldown
- type: MeleeWeapon
wideAnimationRotation: -135
damage:
@@ -533,7 +527,6 @@
quickEquip: false
slots:
- Belt
- type: ItemCooldown
- type: MeleeWeapon
wideAnimationRotation: -135
damage:

View File

@@ -64,7 +64,7 @@
right:
- state: inhand-right-flame
shader: unshaded
- type: ItemCooldown
- type: UseDelay
- type: MeleeWeapon
wideAnimationRotation: -90
damage:

View File

@@ -10,7 +10,6 @@
- type: Utensil
types:
- Knife
- type: ItemCooldown
- type: MeleeWeapon
wideAnimationRotation: -135
damage:

View File

@@ -10,7 +10,6 @@
- type: Sprite
sprite: Objects/Weapons/Melee/pickaxe.rsi
state: pickaxe
- type: ItemCooldown
- type: MeleeWeapon
wideAnimationRotation: -135
damage:
@@ -31,7 +30,6 @@
sprite: Objects/Weapons/Melee/pickaxe.rsi
storedRotation: -45
- type: UseDelay
delay: 1
- type: entity
name: mining drill
@@ -45,7 +43,6 @@
- type: Sprite
sprite: Objects/Tools/handdrill.rsi
state: handdrill
- type: ItemCooldown
- type: MeleeWeapon
attackRate: 1.5
damage:

View File

@@ -55,7 +55,6 @@
- type: Construction
graph: Spear
node: spear
- type: ItemCooldown
- type: SolutionContainerManager
solutions:
melee:
@@ -107,7 +106,6 @@
types:
Blunt: 5
- type: UseDelay
delay: 1
- type: Appearance
- type: SolutionContainerVisuals
maxFillLevels: 1

View File

@@ -44,7 +44,7 @@
- type: Battery
maxCharge: 360
startingCharge: 360
- type: ItemCooldown
- type: UseDelay
- type: Item
heldPrefix: off
size: Normal

View File

@@ -46,7 +46,7 @@
- type: Battery
maxCharge: 1000
startingCharge: 1000
- type: ItemCooldown
- type: UseDelay
- type: Item
heldPrefix: off
size: Normal
@@ -142,7 +142,7 @@
- type: Item
size: Small
sprite: Objects/Weapons/Melee/flash.rsi
- type: ItemCooldown
- type: UseDelay
- type: StaticPrice
price: 40
- type: Appearance

View File

@@ -81,14 +81,16 @@
guides: [ Singularity, Power ]
- type: ContainerContainer
containers:
GasTank: !type:ContainerSlot {}
gas_tank: !type:ContainerSlot {}
- type: ItemSlots
slots:
GasTank:
gas_tank:
startingItem: PlasmaTank
whitelist:
components:
- GasTank
- type: UseDelay
delay: 1
- type: entity
id: RadiationCollectorNoTank
@@ -97,7 +99,7 @@
components:
- type: ItemSlots
slots:
GasTank:
gas_tank:
whitelist:
components:
- GasTank
@@ -109,7 +111,7 @@
components:
- type: ItemSlots
slots:
GasTank:
gas_tank:
startingItem: PlasmaTankFilled
whitelist:
components:

View File

@@ -20,7 +20,6 @@
False: { visible: false }
- type: Item
size: Normal
- type: ItemCooldown
- type: EmitSoundOnUse #placeholder for future unical mechanic
sound:
collection: RadiationPulse

View File

@@ -127,7 +127,7 @@
components:
- Item
permanentComponents:
- type: ItemCooldown
- type: UseDelay
- type: MeleeWeapon
damage:
types: