diff --git a/Content.Server/Storage/EntitySystems/StorageSystem.Fill.cs b/Content.Server/Storage/EntitySystems/StorageSystem.Fill.cs index b02aeb98b2..f42abf5e55 100644 --- a/Content.Server/Storage/EntitySystems/StorageSystem.Fill.cs +++ b/Content.Server/Storage/EntitySystems/StorageSystem.Fill.cs @@ -1,8 +1,6 @@ -using System.Collections.Generic; using Content.Server.Storage.Components; -using Robust.Shared.GameObjects; -using Robust.Shared.Log; using Robust.Shared.Random; +using System.Linq; namespace Content.Server.Storage.EntitySystems; @@ -19,13 +17,26 @@ public sealed partial class StorageSystem } var coordinates = Transform(uid).Coordinates; - var alreadySpawnedGroups = new HashSet(); + var orGroupedSpawns = new Dictionary(); + + // collect groups together, create singular items that pass probability foreach (var entry in component.Contents) { // Handle "Or" groups - if (!string.IsNullOrEmpty(entry.GroupId) && alreadySpawnedGroups.Contains(entry.GroupId)) continue; + if (!string.IsNullOrEmpty(entry.GroupId)) + { + if (!orGroupedSpawns.TryGetValue(entry.GroupId, out OrGroup? orGroup)) + { + orGroup = new(); + orGroupedSpawns.Add(entry.GroupId, orGroup); + } + orGroup.Entries.Add(entry); + orGroup.CumulativeProbability += entry.SpawnProbability; + continue; + } + // else // Check random spawn // ReSharper disable once CompareOfFloatsByEqualityOperator if (entry.SpawnProbability != 1f && !_random.Prob(entry.SpawnProbability)) continue; @@ -39,8 +50,35 @@ public sealed partial class StorageSystem Logger.ErrorS("storage", $"Tried to StorageFill {entry.PrototypeId} inside {uid} but can't."); EntityManager.DeleteEntity(ent); } + } - if (!string.IsNullOrEmpty(entry.GroupId)) alreadySpawnedGroups.Add(entry.GroupId); + // handle orgroup spawns + foreach (var spawnValue in orGroupedSpawns.Values) + { + // For each group use the added cumulative probability to roll a double in that range + double diceRoll = _random.NextDouble() * spawnValue.CumulativeProbability; + // Add the entry's spawn probability to this value, if equals or lower, spawn item, otherwise continue to next item. + double cumulative = 0.0; + foreach (var entry in spawnValue.Entries) + { + cumulative += entry.SpawnProbability; + if (diceRoll > cumulative) continue; + // Dice roll succeeded, spawn item and break loop + for (var index = 0; index < entry.Amount; index++) + { + var ent = EntityManager.SpawnEntity(entry.PrototypeId, coordinates); + if (storage.Insert(ent)) continue; + Logger.ErrorS("storage", $"Tried to StorageFill {entry.PrototypeId} inside {uid} but can't."); + EntityManager.DeleteEntity(ent); + } + break; + } } } + + private sealed class OrGroup + { + public List Entries { get; set; } = new(); + public float CumulativeProbability { get; set; } = 0f; + } } diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Food/Containers/box.yml b/Resources/Prototypes/Entities/Objects/Consumable/Food/Containers/box.yml index 255d820006..61aa71ec15 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Food/Containers/box.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Food/Containers/box.yml @@ -192,7 +192,7 @@ prob: 0.15 orGroup: Pizza - id: FoodPizzaDank - prob: 0.15 + prob: 0.10 orGroup: Pizza - id: FoodPizzaSassysage prob: 0.15 @@ -213,7 +213,7 @@ prob: 0.15 orGroup: Pizza - id: FoodPizzaDonkpocket - prob: 0.15 + prob: 0.10 orGroup: Pizza # Nugget