Fix matryoshka cake slice trick (#44969)

* yml changes

* recursive code

* use the recursive stuff

* fix

* use enum

* remove blank line

Co-authored-by: Pok <113675512+Pok27@users.noreply.github.com>

* remove code

* datafield removed

* add size proto

* rename to Plushie

* rename to cake

* cake size protos

* remove size protos

* ensure size smaller

* use map init and log error

* this is automatic now

* this is automatic now

* send to the client

* upgrade to error again

* update proto to avoid tiny items with secret stash

* ops

* add size to toilet

* update plushie protos to remove secret stash from ian

* ops, forgot to remove these lines

* remove datafield tag

Co-authored-by: Whatstone <166147148+whatston3@users.noreply.github.com>

* use WasModified

Co-authored-by: Whatstone <166147148+whatston3@users.noreply.github.com>

* review

* Update SecretStashComponent.cs

---------

Co-authored-by: Pok <113675512+Pok27@users.noreply.github.com>
Co-authored-by: Whatstone <166147148+whatston3@users.noreply.github.com>
This commit is contained in:
Samuka 2026-09-24 12:39:43 +00:00 • committed by GitHub
parent eefa7073c7
commit 75239a2402
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 199 additions and 94 deletions

View file

@ -16,9 +16,14 @@ public abstract partial class SharedItemSystem : EntitySystem
[Dependency] private SharedHandsSystem _handsSystem = default!;
[Dependency] protected SharedContainerSystem Container = default!;
private readonly List<ItemSizePrototype> _sortedSizes = [];
public override void Initialize()
{
base.Initialize();
ProtoMan.PrototypesReloaded += OnPrototypesReloaded;
SubscribeLocalEvent<ItemComponent, GetVerbsEvent<InteractionVerb>>(AddPickupVerb);
SubscribeLocalEvent<ItemComponent, InteractHandEvent>(OnHandInteract);
SubscribeLocalEvent<ItemComponent, AfterAutoHandleStateEvent>(OnItemAutoState);
@ -26,6 +31,26 @@ public abstract partial class SharedItemSystem : EntitySystem
SubscribeLocalEvent<ItemComponent, ExaminedEvent>(OnExamine);
SubscribeLocalEvent<ItemToggleSizeComponent, ItemToggledEvent>(OnItemToggle);
UpdatePrototypeCache();
}
public override void Shutdown()
{
ProtoMan.PrototypesReloaded -= OnPrototypesReloaded;
}
public void OnPrototypesReloaded(PrototypesReloadedEventArgs args)
{
if (args.WasModified<ItemSizePrototype>())
UpdatePrototypeCache();
}
private void UpdatePrototypeCache()
{
_sortedSizes.Clear();
_sortedSizes.AddRange(ProtoMan.EnumeratePrototypes<ItemSizePrototype>());
_sortedSizes.Sort();
}
private void OnItemAutoState(EntityUid uid, ItemComponent component, ref AfterAutoHandleStateEvent args)
@ -148,6 +173,58 @@ public abstract partial class SharedItemSystem : EntitySystem
return ProtoMan.Index(id);
}
/// <summary>
/// Returns the prototype of the smallest size
/// </summary>
[PublicAPI]
public ItemSizePrototype GetSmallestSize()
{
return _sortedSizes[0];
}
/// <summary>
/// Returns the prototype of the largest size
/// </summary>
[PublicAPI]
public ItemSizePrototype GetLargestSize()
{
return _sortedSizes[^1];
}
/// <summary>
/// Returns a size prototype that is "one" smaller than the size prototype given
/// </summary>
/// <returns>null if the size is the smallest</returns>
[PublicAPI]
public ItemSizePrototype? GetSizeSmaller(ProtoId<ItemSizePrototype> size)
{
var index = _sortedSizes.FindIndex(sizePrototype => sizePrototype.ID == size);
if (index == -1)
{
Log.Error($"Size prototype: {size} not found in _sortedSizes");
return null;
}
return index > 0 ? _sortedSizes[index - 1] : null;
}
/// <summary>
/// Returns a size prototype that is "one" bigger than the size prototype given
/// </summary>
/// <returns>null if the size is the largest</returns>
[PublicAPI]
public ItemSizePrototype? GetSizeBigger(ProtoId<ItemSizePrototype> size)
{
var index = _sortedSizes.FindIndex(sizePrototype => sizePrototype.ID == size);
if (index == -1)
{
Log.Error($"Size prototype: {size} not found in _sortedSizes");
return null;
}
return index < _sortedSizes.Count - 1 ? _sortedSizes[index + 1] : null;
}
/// <summary>
/// Notifies any entity that is holding or wearing this item that they may need to update their sprite.
/// </summary>

View file

@ -24,9 +24,10 @@ namespace Content.Shared.Storage.Components
{
/// <summary>
/// Max item size that can be inserted into secret stash.
/// If null, uses one size smaller than the stash's <see cref="ItemComponent"/> size.
/// </summary>
[DataField("maxItemSize")]
public ProtoId<ItemSizePrototype> MaxItemSize = "Small";
[DataField]
public ProtoId<ItemSizePrototype>? MaxItemSize;
/// <summary>
/// Entity blacklist for secret stashes.

View file

@ -17,6 +17,7 @@ using Robust.Shared.Audio;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Containers;
using Robust.Shared.Map;
using Robust.Shared.Prototypes;
namespace Content.Shared.Storage.EntitySystems;
@ -107,8 +108,26 @@ public sealed partial class SecretStashSystem : EntitySystem
return false;
}
// check if item is too big to fit into secret stash or is in the blacklist
if (_item.GetSizePrototype(itemComp.Size) > _item.GetSizePrototype(entity.Comp.MaxItemSize) ||
// Check if item is too big to fit into secret stash or is in the blacklist.
ProtoId<ItemSizePrototype> maxItemSize;
if (entity.Comp.MaxItemSize != null)
{
maxItemSize = entity.Comp.MaxItemSize.Value;
}
else if (TryComp<ItemComponent>(entity, out var stashItem))
{
var smallerSize = _item.GetSizeSmaller(stashItem.Size);
if (smallerSize == null)
return false;
maxItemSize = smallerSize.ID;
}
else
{
return false;
}
if (_item.GetSizePrototype(itemComp.Size) > _item.GetSizePrototype(maxItemSize) ||
_whitelistSystem.IsWhitelistPass(entity.Comp.Blacklist, itemToHideUid))
{
var msg = Loc.GetString("comp-secret-stash-action-hide-item-too-big",

View file

@ -100,9 +100,6 @@ public abstract partial class SharedStorageSystem : EntitySystem
private readonly List<EntityUid> _entList = new();
private readonly HashSet<EntityUid> _entSet = new();
private readonly List<ItemSizePrototype> _sortedSizes = new();
private FrozenDictionary<string, ItemSizePrototype> _nextSmallest = FrozenDictionary<string, ItemSizePrototype>.Empty;
private const string QuickInsertUseDelayID = "quickInsert";
private const string OpenUiUseDelayID = "storage";
@ -168,8 +165,6 @@ public abstract partial class SharedStorageSystem : EntitySystem
.Register<SharedStorageSystem>();
Subs.CVar(_cfg, CCVars.NestedStorage, OnNestedStorageCvar, true);
UpdatePrototypeCache();
}
private void OnItemSizeChanged(ref ItemSizeChangedEvent ev)
@ -242,30 +237,7 @@ public abstract partial class SharedStorageSystem : EntitySystem
private void OnPrototypesReloaded(PrototypesReloadedEventArgs args)
{
// TODO: This should update all entities in storage as well.
if (args.ByType.ContainsKey(typeof(ItemSizePrototype))
|| (args.Removed?.ContainsKey(typeof(ItemSizePrototype)) ?? false))
{
UpdatePrototypeCache();
}
}
private void UpdatePrototypeCache()
{
_defaultStorageMaxItemSize = ProtoMan.Index(DefaultStorageMaxItemSize);
_sortedSizes.Clear();
_sortedSizes.AddRange(ProtoMan.EnumeratePrototypes<ItemSizePrototype>());
_sortedSizes.Sort();
var nextSmallest = new KeyValuePair<string, ItemSizePrototype>[_sortedSizes.Count];
for (var i = 0; i < _sortedSizes.Count; i++)
{
var k = _sortedSizes[i].ID;
var v = _sortedSizes[Math.Max(i - 1, 0)];
nextSmallest[i] = new(k, v);
}
_nextSmallest = nextSmallest.ToFrozenDictionary();
// TODO: This should update all entities in storage.
}
private void OnComponentInit(EntityUid uid, StorageComponent storageComp, ComponentInit args)
@ -1827,7 +1799,7 @@ public abstract partial class SharedStorageSystem : EntitySystem
// if there is no max item size specified, the value used
// is one below the item size of the storage entity.
return _nextSmallest[item.Size];
return ItemSystem.GetSizeSmaller(item.Size) ?? ItemSystem.GetSmallestSize();
}
/// <summary>

View file

@ -3,7 +3,7 @@
- type: entity
parent: [SolutionNormal, FoodInjectableBase]
id: FoodCakeBase
id: FoodCakeBaseNoSecretStash
abstract: true
components:
- type: FlavorProfile
@ -25,22 +25,14 @@
- type: Tag
tags:
- Cake
- type: SecretStash
maxItemSize: "Normal"
secretStashName: secret-stash-cake
damageEatenItemInside:
types:
Slash: 7.5
- type: ToolOpenable
openToolQualityNeeded: Slicing
closeToolQualityNeeded: Slicing
verbOnly: true
- type: ContainerContainer
containers:
stash: !type:ContainerSlot {}
- type: entity
parent: [SolutionVeryTiny, FoodCakeBase]
abstract: true
parent: [FoodCakeBaseNoSecretStash, BaseStashCake]
id: FoodCakeBase
- type: entity
parent: [SolutionVeryTiny, FoodCakeBaseNoSecretStash] # no secret stash since it's tiny!
id: FoodCakeSliceBase
abstract: true
description: Just a slice of cake, it is enough for everyone.

View file

@ -4,7 +4,7 @@
- type: entity
abstract: true
parent: [SolutionFood, SolutionSmall, BaseItem, BaseStash]
parent: [SolutionFood, SolutionSmall, BaseItem]
id: BasePlushie
components:
- type: EmitSoundOnUse
@ -50,7 +50,39 @@
- ClothMade
- type: entity
parent: BasePlushie
abstract: true
parent: [BasePlushie, BaseStashPlushie]
id: BasePlushieGinormous
components:
- type: Item
size: Ginormous
- type: entity
abstract: true
parent: [BasePlushie, BaseStashPlushie]
id: BasePlushieNormal
components:
- type: Item
size: Normal
- type: entity
abstract: true
parent: [BasePlushie, BaseStashPlushie]
id: BasePlushieSmall
components:
- type: Item
size: Small
- type: entity
abstract: true
parent: BasePlushie # too smoll to fit secret stash
id: BasePlushieTiny
components:
- type: Item
size: Tiny
- type: entity
parent: BasePlushieGinormous
id: PlushieThrongler
name: throngler plushie
description: A stuffed toy to remind cargo techs of what they can no longer have.
@ -62,7 +94,6 @@
wideAnimationRotation: -135
attackRate: 10
- type: Item
size: Ginormous
shape:
- 0,0,3,3
- 1,4,2,6
@ -73,7 +104,7 @@
CottonBurger: ThronglerPlushie
- type: entity
parent: BasePlushie
parent: BasePlushieSmall
id: PlushieGhost
name: ghost soft toy
description: The start of your personal GHOST GANG!
@ -82,7 +113,6 @@
sprite: Mobs/Ghosts/ghost_human.rsi
state: icon
noRot: true
- type: Item
- type: Physics
fixedRotation: true
bodyType: Dynamic
@ -137,7 +167,7 @@
CottonBurger: RevenantPlushie
- type: entity
parent: BasePlushie
parent: BasePlushieNormal
id: PlushieBee
name: bee plushie
description: A cute toy that resembles an even cuter programmer. You'd have to be a monster to grind this up.
@ -146,7 +176,6 @@
sprite: Objects/Fun/Plushies/bee.rsi
state: icon
- type: Item
size: Normal
sprite: Objects/Fun/Plushies/bee.rsi
- type: Extractable
grindableSolutionName: food
@ -167,7 +196,7 @@
CottonBurger: BeePlushie
- type: entity
parent: BasePlushie
parent: BasePlushieSmall
id: PlushieHampter
name: hampter plushie
description: A cute stuffed toy that resembles a hamster. Its face looks squished.
@ -229,7 +258,7 @@
shader: unshaded
- type: entity
parent: BasePlushie
parent: BasePlushieSmall
id: PlushieNuke
name: nukie plushie
description: A stuffed toy that resembles a syndicate nuclear operative. The tag claims operatives to be purely fictitious.
@ -251,7 +280,7 @@
CottonBurger: NukiePlushie
- type: entity
parent: BasePlushie
parent: BasePlushieSmall
id: PlushieRouny
name: rouny plushie
description: Rouny.
@ -273,7 +302,7 @@
CottonBurger: RounyPlushie
- type: entity
parent: BasePlushie
parent: BasePlushieSmall
id: PlushieLamp
name: lamp plushie
description: A light emitting friend!
@ -290,7 +319,7 @@
CottonBurger: LampPlushie
- type: entity
parent: BasePlushie
parent: BasePlushieSmall
id: PlushieArachind
name: arachnid plushie
description: An adorable stuffed toy that resembles an arachnid. It feels silky..
@ -323,7 +352,7 @@
CottonBurger: ArachnidPlushie
- type: entity
parent: BasePlushie
parent: BasePlushieSmall
id: PlushieLizard #Weh!
name: lizard plushie
description: An adorable stuffed toy that resembles a lizardperson. Made by CentComm as a token initiative to combat speciesism in work environments. "Welcome your new colleagues as you do this plush, with open arms!"
@ -384,7 +413,7 @@
Quantity: 10
- type: entity
parent: BasePlushie
parent: BasePlushieSmall
id: PlushieExperiment #Arf!
name: experiment plushie
description: A plushie of a canid of sorts. It yearns to be detonated on a landmine.
@ -568,7 +597,7 @@
CottonBurger: InversedLizardPlushie
- type: entity
parent: BasePlushie
parent: BasePlushieSmall
id: PlushieDiona # TODO Better way of doing the flowering visuals. Probably make it an "AppearanceChangeEntityEffect" on reactive?
name: diona plushie
description: An adorable stuffed toy that resembles a diona. Love water and cuddles. Do not wet!
@ -645,7 +674,7 @@
CottonBurger: DionaPlushie
- type: entity
parent: BasePlushie
parent: BasePlushieSmall
id: PlushieSharkBlue
name: blue shark soft toy
description: Big and safe to have by your side if you want to discover the world below the surface of the ocean.
@ -723,7 +752,7 @@
- ClothMade
- type: entity
parent: BasePlushie
parent: BasePlushieNormal
id: PlushieRatvar
name: ratvar plushie
description: A large stuffed doll of the elder god Ratvar.
@ -732,7 +761,6 @@
sprite: Objects/Fun/Plushies/ratvar.rsi
state: icon
- type: Item
size: Normal
sprite: Objects/Fun/Plushies/ratvar.rsi
- type: MultiHandedItem
- type: Clothing
@ -745,7 +773,7 @@
CottonBurger: RatvarPlushie
- type: entity
parent: BasePlushie
parent: BasePlushieNormal
id: PlushieNar
name: nar'sie plushie
description: A large stuffed doll of the elder goddess Nar'Sie.
@ -754,7 +782,6 @@
sprite: Objects/Fun/Plushies/narsie.rsi
state: icon
- type: Item
size: Normal
sprite: Objects/Fun/Plushies/narsie.rsi
- type: MultiHandedItem
- type: Clothing
@ -767,7 +794,7 @@
CottonBurger: NarPlushie
- type: entity
parent: BasePlushie
parent: BasePlushieSmall
id: PlushieCarp
name: carp plushie
description: An adorable stuffed toy that resembles the monstrous space carp.
@ -875,7 +902,7 @@
- PlushieCarpHolo
- type: entity
parent: BasePlushie
parent: BasePlushieSmall
id: PlushieSlime
name: slime plushie
description: An adorable stuffed toy that resembles a slime. It's basically a hacky sack.
@ -908,7 +935,7 @@
CottonBurger: SlimePlushie
- type: entity
parent: BasePlushie
parent: BasePlushieSmall
id: PlushieSnake
name: snake plushie
description: An adorable stuffed toy that resembles a snake.
@ -946,7 +973,7 @@
CottonBurger: SnakePlushie
- type: entity
parent: BasePlushie
parent: BasePlushieSmall
id: ToyMouse
name: mouse toy
description: A colorful toy mouse!
@ -980,7 +1007,7 @@
CottonBurger: MousePlushie
- type: entity
parent: BasePlushie
parent: BasePlushieSmall
id: PlushieVox
name: vox plushie
description: SKREEEEEEEEEEEE!
@ -1019,7 +1046,7 @@
CottonBurger: VoxPlushie
- type: entity
parent: BasePlushie
parent: BasePlushieSmall
id: PlushieAtmosian
name: atmosian plushie
description: An adorable stuffed toy that resembles a brave atmosian. Unfortunately, he won't fix those depressurizations for you.
@ -1041,7 +1068,7 @@
CottonBurger: AtmosianPlushie
- type: entity
parent: BasePlushie
parent: BasePlushieNormal
id: PlushieXeno
name: xeno plushie
description: An adorable stuffed toy that resembles a scary xenomorf. You're lucky it's just a toy.
@ -1049,8 +1076,6 @@
- type: Sprite
sprite: Objects/Fun/Plushies/xeno.rsi
state: icon
- type: Item
size: Normal
- type: EmitSoundOnUse
sound: &PlushieXenoSound
path: /Audio/Weapons/Xeno/alien_spitacid.ogg
@ -1082,7 +1107,7 @@
CottonBurger: XenoPlushie
- type: entity
parent: BasePlushie
parent: BasePlushieSmall
id: PlushiePenguin
name: penguin plushie
description: I use arch btw!
@ -1100,7 +1125,7 @@
CottonBurger: PenguinPlushie
- type: entity
parent: BasePlushie
parent: BasePlushieSmall
id: PlushieHuman
name: human plushie
description: This is a felt plush of a human. All craftsmanship is of the lowest quality. The human is naked. The human is crying. The human is screaming.
@ -1147,7 +1172,7 @@
CottonBurger: HumanPlushie
- type: entity
parent: BasePlushie
parent: BasePlushieSmall
id: PlushieMoth
name: moth plushie
description: Cute and fluffy moth plushie. Enjoy, bz!
@ -1180,7 +1205,7 @@
CottonBurger: MothPlushie
- type: entity
parent: BasePlushie
parent: BasePlushieSmall
id: PlushieSheep
name: sheep plushie
description: A soft, wooly, stuffed sheep. 100% cotton.
@ -1256,7 +1281,7 @@
soundHit: *PlushieSpaceSheepSound
- type: entity
parent: BasePlushie
parent: BasePlushieSmall
id: PlushieVulp
name: vulpkanin plushie
description: An adorable stuffed toy that resembles a vulpkanin. Yip! Yap!
@ -1297,7 +1322,7 @@
CottonBurger: PlushieVulp
- type: entity
parent: BasePlushie
parent: BasePlushieTiny
id: ToyIan
name: ian toy
description: Unable to eat, but just as fluffy as the real guy!
@ -1314,8 +1339,6 @@
head:
- state: equipped-HELMET
offset: "0, 0.06"
- type: Item
size: Tiny
- type: EmitSoundOnUse
sound: &SoundIan
path: /Audio/Items/Toys/ian.ogg
@ -1336,7 +1359,7 @@
CottonBurger: IanPlushie
- type: entity
parent: BasePlushie
parent: BasePlushieSmall
id: ToyAmongPequeno
name: among pequeño
description: Sus!

View file

@ -261,7 +261,7 @@
- type: entity
abstract: true
parent: [BaseItem, BaseStash]
parent: BaseItem
id: BaseRubberToy
components:
- type: Tag
@ -317,7 +317,7 @@
- ToyRubberDuck
- type: entity
parent: BaseRubberToy
parent: [BaseRubberToy, BaseStashPlushie]
id: RubberChicken
name: rubber chicken
description: A stress inducing parody of nature's most delectable avian.

View file

@ -217,13 +217,9 @@
abstract: true
id: BaseStash
components:
- type: Speech
speechVerb: Default # for pais (In the secret stash)
- type: SecretStash
secretStashName: secret-stash-plushie
blacklist:
components:
- SecretStash # Prevents being able to insert plushies inside each other (infinite plush)!
- NukeDisk # Because a core mechanic of nukies should not be "where in this bag is the fucking disk"
tags:
- QuantumSpinInverter # It will cause issues with the grinder...
@ -231,7 +227,31 @@
- type: ToolOpenable
openToolQualityNeeded: Slicing
closeToolQualityNeeded: Slicing # Should probably be stitching or something if that gets added
name: secret-stash-plushie
- type: ContainerContainer
containers:
stash: !type:ContainerSlot {}
- type: entity
abstract: true
parent: BaseStash
id: BaseStashPlushie
components:
- type: Speech
speechVerb: Default # for pais (In the secret stash)
- type: SecretStash
secretStashName: secret-stash-plushie
- type: ToolOpenable
name: secret-stash-plushie
- type: entity
abstract: true
parent: BaseStash
id: BaseStashCake
components:
- type: SecretStash
secretStashName: secret-stash-cake
damageEatenItemInside:
types:
Slash: 7.5
- type: ToolOpenable
verbOnly: true

View file

@ -84,6 +84,7 @@
- type: Appearance
- type: SecretStash
secretStashName: secret-stash-toilet
maxItemSize: Small
- type: ToolOpenable
openToolQualityNeeded: Prying
closeToolQualityNeeded: Prying