Merge remote-tracking branch 'upstream/stable' into ed-25-08-2025-upstream-sync
# Conflicts: # .github/CODEOWNERS # Content.Client/UserInterface/Systems/Actions/Controls/ActionButton.cs # Content.Server/Administration/Systems/AdminVerbSystem.Antags.cs # Content.Server/Chat/Systems/ChatSystem.cs # Content.Server/Explosion/EntitySystems/TriggerSystem.cs # Content.Server/Nutrition/EntitySystems/SliceableFoodSystem.cs # Content.Shared/Lock/LockSystem.cs # Content.Shared/Nutrition/Components/FoodComponent.cs # Content.Shared/Speech/ListenEvent.cs # Resources/Prototypes/Entities/Effects/admin_triggers.yml
This commit is contained in:
72
Content.Shared/Storage/EntitySystems/PickRandomSystem.cs
Normal file
72
Content.Shared/Storage/EntitySystems/PickRandomSystem.cs
Normal file
@@ -0,0 +1,72 @@
|
||||
using System.Linq;
|
||||
using Content.Shared.Database;
|
||||
using Content.Shared.Hands.EntitySystems;
|
||||
using Content.Shared.Storage.Components;
|
||||
using Content.Shared.Verbs;
|
||||
using Content.Shared.Whitelist;
|
||||
using Robust.Shared.Containers;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Random;
|
||||
|
||||
namespace Content.Shared.Storage.EntitySystems;
|
||||
|
||||
public sealed class PickRandomSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly EntityWhitelistSystem _whitelistSystem = default!;
|
||||
[Dependency] private readonly INetManager _net = default!;
|
||||
[Dependency] private readonly IRobustRandom _random = default!;
|
||||
[Dependency] private readonly SharedContainerSystem _container = default!;
|
||||
[Dependency] private readonly SharedHandsSystem _hands = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<PickRandomComponent, GetVerbsEvent<AlternativeVerb>>(OnGetAlternativeVerbs);
|
||||
}
|
||||
|
||||
private void OnGetAlternativeVerbs(EntityUid uid, PickRandomComponent comp, GetVerbsEvent<AlternativeVerb> args)
|
||||
{
|
||||
if (!args.CanAccess || !args.CanInteract || !TryComp<StorageComponent>(uid, out var storage))
|
||||
return;
|
||||
|
||||
var user = args.User;
|
||||
|
||||
var enabled = storage.Container.ContainedEntities.Any(item => _whitelistSystem.IsWhitelistPassOrNull(comp.Whitelist, item));
|
||||
|
||||
// alt-click / alt-z to pick an item
|
||||
args.Verbs.Add(new AlternativeVerb
|
||||
{
|
||||
Act = () =>
|
||||
{
|
||||
TryPick(uid, comp, storage, user);
|
||||
},
|
||||
Impact = LogImpact.Low,
|
||||
Text = Loc.GetString(comp.VerbText),
|
||||
Disabled = !enabled,
|
||||
Message = enabled ? null : Loc.GetString(comp.EmptyText, ("storage", uid))
|
||||
});
|
||||
}
|
||||
|
||||
private void TryPick(EntityUid uid, PickRandomComponent comp, StorageComponent storage, EntityUid user)
|
||||
{
|
||||
// It's hard to predict picking a random entity from a container since the contained entity list will have a different order on the server and client.
|
||||
// One idea might be to sort them by NetEntity ID, but that is expensive if there are a lot of entities.
|
||||
// Another option would be to make this client authorative.
|
||||
if (_net.IsClient)
|
||||
return;
|
||||
|
||||
var entities = storage.Container.ContainedEntities.Where(item => _whitelistSystem.IsWhitelistPassOrNull(comp.Whitelist, item)).ToArray();
|
||||
|
||||
if (entities.Length == 0)
|
||||
return;
|
||||
|
||||
var picked = _random.Pick(entities);
|
||||
|
||||
// if it fails to go into a hand of the user, will be on the storage
|
||||
_container.AttachParentToContainerOrGrid((picked, Transform(picked)));
|
||||
|
||||
// TODO: try to put in hands, failing that put it on the storage
|
||||
_hands.TryPickupAnyHand(user, picked);
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,7 @@ using Content.Shared.Interaction;
|
||||
using Content.Shared.Item;
|
||||
using Content.Shared.Materials;
|
||||
using Content.Shared.Nutrition;
|
||||
using Content.Shared.Nutrition.EntitySystems;
|
||||
using Content.Shared.Popups;
|
||||
using Content.Shared.Storage.Components;
|
||||
using Content.Shared.Tools.EntitySystems;
|
||||
@@ -25,6 +26,7 @@ namespace Content.Shared.Storage.EntitySystems;
|
||||
/// </summary>
|
||||
public sealed class SecretStashSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly IngestionSystem _ingestion = default!;
|
||||
[Dependency] private readonly SharedPopupSystem _popupSystem = default!;
|
||||
[Dependency] private readonly SharedHandsSystem _handsSystem = default!;
|
||||
[Dependency] private readonly SharedContainerSystem _containerSystem = default!;
|
||||
@@ -41,7 +43,7 @@ public sealed class SecretStashSystem : EntitySystem
|
||||
SubscribeLocalEvent<SecretStashComponent, DestructionEventArgs>(OnDestroyed);
|
||||
SubscribeLocalEvent<SecretStashComponent, GotReclaimedEvent>(OnReclaimed);
|
||||
SubscribeLocalEvent<SecretStashComponent, InteractUsingEvent>(OnInteractUsing, after: new[] { typeof(ToolOpenableSystem), typeof(AnchorableSystem) });
|
||||
SubscribeLocalEvent<SecretStashComponent, AfterFullyEatenEvent>(OnEaten);
|
||||
SubscribeLocalEvent<SecretStashComponent, FullyEatenEvent>(OnFullyEaten);
|
||||
SubscribeLocalEvent<SecretStashComponent, InteractHandEvent>(OnInteractHand);
|
||||
SubscribeLocalEvent<SecretStashComponent, GetVerbsEvent<InteractionVerb>>(OnGetVerb);
|
||||
}
|
||||
@@ -61,7 +63,7 @@ public sealed class SecretStashSystem : EntitySystem
|
||||
DropContentsAndAlert(entity, args.ReclaimerCoordinates);
|
||||
}
|
||||
|
||||
private void OnEaten(Entity<SecretStashComponent> entity, ref AfterFullyEatenEvent args)
|
||||
private void OnFullyEaten(Entity<SecretStashComponent> entity, ref FullyEatenEvent args)
|
||||
{
|
||||
// TODO: When newmed is finished should do damage to teeth (Or something like that!)
|
||||
var damage = entity.Comp.DamageEatenItemInside;
|
||||
|
||||
@@ -16,6 +16,7 @@ using Content.Shared.Verbs;
|
||||
using Content.Shared.Wall;
|
||||
using Content.Shared.Whitelist;
|
||||
using Content.Shared.ActionBlocker;
|
||||
using Content.Shared.Mobs.Components;
|
||||
using Robust.Shared.Audio.Systems;
|
||||
using Robust.Shared.Containers;
|
||||
using Robust.Shared.GameStates;
|
||||
@@ -355,7 +356,7 @@ public abstract class SharedEntityStorageSystem : EntitySystem
|
||||
return _whitelistSystem.IsValid(component.Whitelist, toInsert);
|
||||
|
||||
// The inserted entity must be a mob or an item.
|
||||
return HasComp<BodyComponent>(toInsert) || HasComp<ItemComponent>(toInsert);
|
||||
return HasComp<MobStateComponent>(toInsert) || HasComp<ItemComponent>(toInsert);
|
||||
}
|
||||
|
||||
public bool TryOpenStorage(EntityUid user, EntityUid target, bool silent = false)
|
||||
|
||||
@@ -236,7 +236,14 @@ public abstract class SharedStorageSystem : EntitySystem
|
||||
StoredItems = storedItems,
|
||||
SavedLocations = component.SavedLocations,
|
||||
Whitelist = component.Whitelist,
|
||||
Blacklist = component.Blacklist
|
||||
Blacklist = component.Blacklist,
|
||||
QuickInsert = component.QuickInsert,
|
||||
AreaInsert = component.AreaInsert,
|
||||
StorageInsertSound = component.StorageInsertSound,
|
||||
StorageRemoveSound = component.StorageRemoveSound,
|
||||
StorageOpenSound = component.StorageOpenSound,
|
||||
StorageCloseSound = component.StorageCloseSound,
|
||||
DefaultStorageOrientation = component.DefaultStorageOrientation,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -352,6 +359,44 @@ public abstract class SharedStorageSystem : EntitySystem
|
||||
args.Verbs.Add(verb);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copy this component's datafields from one entity to another.
|
||||
/// This can't use CopyComp because we don't want to copy the references to the items inside the storage.
|
||||
/// <summary>
|
||||
public void CopyComponent(Entity<StorageComponent?> source, EntityUid target)
|
||||
{
|
||||
if (!Resolve(source, ref source.Comp))
|
||||
return;
|
||||
|
||||
var targetComp = EnsureComp<StorageComponent>(target);
|
||||
targetComp.Grid = new List<Box2i>(source.Comp.Grid);
|
||||
targetComp.MaxItemSize = source.Comp.MaxItemSize;
|
||||
targetComp.QuickInsert = source.Comp.QuickInsert;
|
||||
targetComp.QuickInsertCooldown = source.Comp.QuickInsertCooldown;
|
||||
targetComp.OpenUiCooldown = source.Comp.OpenUiCooldown;
|
||||
targetComp.ClickInsert = source.Comp.ClickInsert;
|
||||
targetComp.OpenOnActivate = source.Comp.OpenOnActivate;
|
||||
targetComp.AreaInsert = source.Comp.AreaInsert;
|
||||
targetComp.AreaInsertRadius = source.Comp.AreaInsertRadius;
|
||||
targetComp.Whitelist = source.Comp.Whitelist;
|
||||
targetComp.Blacklist = source.Comp.Blacklist;
|
||||
targetComp.StorageInsertSound = source.Comp.StorageInsertSound;
|
||||
targetComp.StorageRemoveSound = source.Comp.StorageRemoveSound;
|
||||
targetComp.StorageOpenSound = source.Comp.StorageOpenSound;
|
||||
targetComp.StorageCloseSound = source.Comp.StorageCloseSound;
|
||||
targetComp.DefaultStorageOrientation = source.Comp.DefaultStorageOrientation;
|
||||
targetComp.HideStackVisualsWhenClosed = source.Comp.HideStackVisualsWhenClosed;
|
||||
targetComp.SilentStorageUserTag = source.Comp.SilentStorageUserTag;
|
||||
targetComp.ShowVerb = source.Comp.ShowVerb;
|
||||
|
||||
UpdateOccupied((target, targetComp));
|
||||
Dirty(target, targetComp);
|
||||
|
||||
var targetUI = EnsureComp<UserInterfaceComponent>(target);
|
||||
|
||||
UI.SetUi((target, targetUI), StorageComponent.StorageUiKey.Key, new InterfaceData("StorageBoundUserInterface"));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to get the storage location of an item.
|
||||
/// </summary>
|
||||
@@ -1303,7 +1348,7 @@ public abstract class SharedStorageSystem : EntitySystem
|
||||
Angle startAngle;
|
||||
if (storageEnt.Comp.DefaultStorageOrientation == null)
|
||||
{
|
||||
startAngle = Angle.FromDegrees(-itemEnt.Comp.StoredRotation);
|
||||
startAngle = Angle.Zero;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1970,15 +2015,17 @@ public abstract class SharedStorageSystem : EntitySystem
|
||||
protected sealed class StorageComponentState : ComponentState
|
||||
{
|
||||
public Dictionary<NetEntity, ItemStorageLocation> StoredItems = new();
|
||||
|
||||
public Dictionary<string, List<ItemStorageLocation>> SavedLocations = new();
|
||||
|
||||
public List<Box2i> Grid = new();
|
||||
|
||||
public ProtoId<ItemSizePrototype>? MaxItemSize;
|
||||
|
||||
public EntityWhitelist? Whitelist;
|
||||
|
||||
public EntityWhitelist? Blacklist;
|
||||
public bool QuickInsert;
|
||||
public bool AreaInsert;
|
||||
public SoundSpecifier? StorageInsertSound;
|
||||
public SoundSpecifier? StorageRemoveSound;
|
||||
public SoundSpecifier? StorageOpenSound;
|
||||
public SoundSpecifier? StorageCloseSound;
|
||||
public StorageDefaultOrientation? DefaultStorageOrientation;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user