using System.Linq; using Content.Shared.CCVar; using Content.Shared.Dataset; using Content.Shared.Procedural; using Content.Shared.Procedural.Loot; using Content.Shared.Random; using Content.Shared.Random.Helpers; using Content.Shared.Salvage.Expeditions; using Content.Shared.Salvage.Expeditions.Modifiers; using Robust.Shared.Configuration; using Robust.Shared.Prototypes; using Robust.Shared.Random; using Robust.Shared.Serialization; using Robust.Shared.Utility; namespace Content.Shared.Salvage; public abstract partial class SharedSalvageSystem : EntitySystem { [Dependency] protected readonly IConfigurationManager CfgManager = default!; [Dependency] private readonly IPrototypeManager _proto = default!; /// /// Main loot table for salvage expeditions. /// public static readonly ProtoId ExpeditionsLootProto = "SalvageLoot"; public string GetFTLName(LocalizedDatasetPrototype dataset, int seed) { var random = new System.Random(seed); return $"{Loc.GetString(dataset.Values[random.Next(dataset.Values.Count)])}-{random.Next(10, 100)}-{(char) (65 + random.Next(26))}"; } public SalvageMission GetMission(SalvageDifficultyPrototype difficulty, int seed) { // This is on shared to ensure the client display for missions and what the server generates are consistent var modifierBudget = difficulty.ModifierBudget; var rand = new System.Random(seed); // Run budget in order of priority // - Biome // - Lighting // - Atmos var biome = GetMod(rand, ref modifierBudget); var light = GetBiomeMod(biome.ID, rand, ref modifierBudget); var temp = GetBiomeMod(biome.ID, rand, ref modifierBudget); var air = GetBiomeMod(biome.ID, rand, ref modifierBudget); var dungeon = GetBiomeMod(biome.ID, rand, ref modifierBudget); var factionProtos = _proto.EnumeratePrototypes().ToList(); factionProtos.Sort((x, y) => string.Compare(x.ID, y.ID, StringComparison.Ordinal)); var faction = factionProtos[rand.Next(factionProtos.Count)]; var mods = new List(); if (air.Description != string.Empty) { mods.Add(Loc.GetString(air.Description)); } // only show the description if there is an atmosphere since wont matter otherwise if (temp.Description != string.Empty && !air.Space) { mods.Add(Loc.GetString(temp.Description)); } if (light.Description != string.Empty) { mods.Add(Loc.GetString(light.Description)); } var duration = TimeSpan.FromSeconds(CfgManager.GetCVar(CCVars.SalvageExpeditionDuration)); return new SalvageMission(seed, dungeon.ID, faction.ID, biome.ID, air.ID, temp.Temperature, light.Color, duration, mods); } public T GetBiomeMod(string biome, System.Random rand, ref float rating) where T : class, IPrototype, IBiomeSpecificMod { var mods = _proto.EnumeratePrototypes().ToList(); mods.Sort((x, y) => string.Compare(x.ID, y.ID, StringComparison.Ordinal)); rand.Shuffle(mods); foreach (var mod in mods) { if (mod.Cost > rating || (mod.Biomes != null && !mod.Biomes.Contains(biome))) continue; rating -= mod.Cost; return mod; } throw new InvalidOperationException(); } public T GetMod(System.Random rand, ref float rating) where T : class, IPrototype, ISalvageMod { var mods = _proto.EnumeratePrototypes().ToList(); mods.Sort((x, y) => string.Compare(x.ID, y.ID, StringComparison.Ordinal)); rand.Shuffle(mods); foreach (var mod in mods) { if (mod.Cost > rating) continue; rating -= mod.Cost; return mod; } throw new InvalidOperationException(); } }