Make pricing system aware of SpawnItemsOnUseComponent (#13626)

* Make appraisal tool aware of SpawnItemsOnUseComponent

* Move to SpawnItemsOnUseSystem
This commit is contained in:
Visne
2023-02-28 16:55:25 +01:00
committed by GitHub
parent 5e6a446c02
commit 7f8860187e
5 changed files with 132 additions and 44 deletions

View File

@@ -1,6 +1,6 @@
using Robust.Shared.Prototypes;
using System.Linq;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
using Robust.Shared.Serialization.Manager;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
namespace Content.Shared.Storage;
@@ -62,7 +62,7 @@ public struct EntitySpawnEntry
public static class EntitySpawnCollection
{
private sealed class OrGroup
public sealed class OrGroup
{
public List<EntitySpawnEntry> Entries { get; set; } = new();
public float CumulativeProbability { get; set; } = 0f;
@@ -84,34 +84,16 @@ public static class EntitySpawnCollection
IoCManager.Resolve(ref random);
var spawned = new List<string?>();
var orGroupedSpawns = new Dictionary<string, OrGroup>();
var ungrouped = CollectOrGroups(entries, out var orGroupedSpawns);
// collect groups together, create singular items that pass probability
foreach (var entry in entries)
foreach (var entry in ungrouped)
{
// Handle "Or" groups
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;
if (entry.SpawnProbability != 1f && !random.Prob(entry.SpawnProbability))
continue;
var amount = entry.Amount;
if (entry.MaxAmount > amount)
amount = random.Next(amount, entry.MaxAmount);
var amount = (int) entry.GetAmount(random);
for (var i = 0; i < amount; i++)
{
@@ -119,25 +101,25 @@ public static class EntitySpawnCollection
}
}
// handle orgroup spawns
foreach (var spawnValue in orGroupedSpawns.Values)
// Handle OrGroup spawns
foreach (var spawnValue in orGroupedSpawns)
{
// For each group use the added cumulative probability to roll a double in that range
double diceRoll = random.NextDouble() * spawnValue.CumulativeProbability;
var 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.
var cumulative = 0.0;
foreach (var entry in spawnValue.Entries)
{
cumulative += entry.SpawnProbability;
if (diceRoll > cumulative) continue;
if (diceRoll > cumulative)
continue;
// Dice roll succeeded, add item and break loop
var amount = (int) entry.GetAmount(random);
var amount = entry.Amount;
if (entry.MaxAmount > amount)
amount = random.Next(amount, entry.MaxAmount);
for (var index = 0; index < amount; index++)
for (var i = 0; i < amount; i++)
{
spawned.Add(entry.PrototypeId);
}
@@ -148,4 +130,58 @@ public static class EntitySpawnCollection
return spawned;
}
/// <summary>
/// Collects all entries that belong together in an OrGroup, and then returns the leftover ungrouped entries.
/// </summary>
/// <param name="entries">A list of entries that will be collected into OrGroups.</param>
/// <param name="orGroups">A list of entries collected into OrGroups.</param>
/// <returns>A list of entries that are not in an OrGroup.</returns>
public static List<EntitySpawnEntry> CollectOrGroups(IEnumerable<EntitySpawnEntry> entries, out List<OrGroup> orGroups)
{
var ungrouped = new List<EntitySpawnEntry>();
var orGroupsDict = new Dictionary<string, OrGroup>();
foreach (var entry in entries)
{
// If the entry is in a group, collect it into an OrGroup. Otherwise just add it to a list of ungrouped
// entries.
if (!string.IsNullOrEmpty(entry.GroupId))
{
// Create a new OrGroup if necessary
if (!orGroupsDict.TryGetValue(entry.GroupId, out var orGroup))
{
orGroup = new OrGroup();
orGroupsDict.Add(entry.GroupId, orGroup);
}
orGroup.Entries.Add(entry);
orGroup.CumulativeProbability += entry.SpawnProbability;
}
else
{
ungrouped.Add(entry);
}
}
// We don't really need the group IDs anymore, so just return the values as a list
orGroups = orGroupsDict.Values.ToList();
return ungrouped;
}
public static double GetAmount(this EntitySpawnEntry entry, IRobustRandom? random = null, bool getAverage = false)
{
// Max amount is less or equal than amount, so just return the amount
if (entry.MaxAmount <= entry.Amount)
return entry.Amount;
// If we want the average, just calculate the expected amount
if (getAverage)
return (entry.Amount + entry.MaxAmount) / 2.0;
// Otherwise get a random value in between
IoCManager.Resolve(ref random);
return random.Next(entry.Amount, entry.MaxAmount);
}
}