diff --git a/Content.Client/Salvage/UI/SalvageExpeditionWindow.xaml.cs b/Content.Client/Salvage/UI/SalvageExpeditionWindow.xaml.cs index 03184ae715..fcc8f7af0d 100644 --- a/Content.Client/Salvage/UI/SalvageExpeditionWindow.xaml.cs +++ b/Content.Client/Salvage/UI/SalvageExpeditionWindow.xaml.cs @@ -4,7 +4,6 @@ using Content.Client.Stylesheets; using Content.Client.UserInterface.Controls; using Content.Shared.CCVar; using Content.Shared.Parallax.Biomes; -using Content.Shared.Procedural.Loot; using Content.Shared.Salvage; using Content.Shared.Salvage.Expeditions.Modifiers; using Content.Shared.Shuttles.BUIStates; @@ -191,29 +190,17 @@ public sealed partial class SalvageExpeditionWindow : FancyWindow, lBox.AddChild(new Label() { - Text = Loc.GetString("salvage-expedition-window-loot") + Text = Loc.GetString("salvage-expedition-window-rewards") }); - if (mission.Loot.Count == 0) + // there will always be 3 rewards so no need for 0 check + lBox.AddChild(new Label() { - lBox.AddChild(new Label() - { - Text = Loc.GetString("salvage-expedition-window-none"), - FontColorOverride = StyleNano.ConcerningOrangeFore, - HorizontalAlignment = HAlignment.Left, - Margin = new Thickness(0f, 0f, 0f, 5f), - }); - } - else - { - lBox.AddChild(new Label() - { - Text = string.Join("\n", mission.Loot.Select(o => "- " + _prototype.Index(o.Key).Description + (o.Value > 1 ? $" x {o.Value}" : ""))).TrimEnd(), - FontColorOverride = StyleNano.ConcerningOrangeFore, - HorizontalAlignment = HAlignment.Left, - Margin = new Thickness(0f, 0f, 0f, 5f), - }); - } + Text = string.Join("\n", mission.Rewards.Select(id => "- " + _prototype.Index(id).Name)), + FontColorOverride = StyleNano.ConcerningOrangeFore, + HorizontalAlignment = HAlignment.Left, + Margin = new Thickness(0f, 0f, 0f, 5f) + }); // Claim var claimButton = new Button() diff --git a/Content.Server/Salvage/Expeditions/SalvageExpeditionComponent.cs b/Content.Server/Salvage/Expeditions/SalvageExpeditionComponent.cs index 9c4fd05a20..1fcc4c3003 100644 --- a/Content.Server/Salvage/Expeditions/SalvageExpeditionComponent.cs +++ b/Content.Server/Salvage/Expeditions/SalvageExpeditionComponent.cs @@ -1,8 +1,10 @@ using Content.Shared.Random; using Content.Shared.Salvage; using Robust.Shared.Audio; +using Robust.Shared.Prototypes; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List; namespace Content.Server.Salvage.Expeditions; @@ -56,6 +58,12 @@ public sealed class SalvageExpeditionComponent : Component /// [ViewVariables(VVAccess.ReadWrite), DataField("difficulty")] public DifficultyRating Difficulty; + + /// + /// List of items to order on mission completion + /// + [ViewVariables(VVAccess.ReadWrite), DataField("rewards", customTypeSerializer: typeof(PrototypeIdListSerializer))] + public List Rewards = default!; } public enum ExpeditionStage : byte diff --git a/Content.Server/Salvage/SalvageSystem.Expeditions.cs b/Content.Server/Salvage/SalvageSystem.Expeditions.cs index 6fb8897a0a..7269c571e6 100644 --- a/Content.Server/Salvage/SalvageSystem.Expeditions.cs +++ b/Content.Server/Salvage/SalvageSystem.Expeditions.cs @@ -286,42 +286,12 @@ public sealed partial class SalvageSystem return; } - var ids = RewardsForDifficulty(comp.Difficulty); - foreach (var id in ids) + foreach (var reward in comp.Rewards) { - // pick a random reward to give - var rewards = _prototypeManager.Index(id); - var reward = rewards.Pick(_random); - var sender = Loc.GetString("cargo-gift-default-sender"); var desc = Loc.GetString("salvage-expedition-reward-description"); var dest = Loc.GetString("cargo-gift-default-dest"); _cargo.AddAndApproveOrder(cargoDb, reward, 0, 1, sender, desc, dest); } } - - /// - /// Get a list of WeightedRandomPrototype IDs with the rewards for a certain difficulty. - /// - private string[] RewardsForDifficulty(DifficultyRating rating) - { - var common = "SalvageRewardCommon"; - var rare = "SalvageRewardRare"; - var epic = "SalvageRewardEpic"; - switch (rating) - { - case DifficultyRating.Minimal: - return new string[] { common, common, common }; - case DifficultyRating.Minor: - return new string[] { common, common, rare }; - case DifficultyRating.Moderate: - return new string[] { common, rare, rare }; - case DifficultyRating.Hazardous: - return new string[] { rare, rare, epic }; - case DifficultyRating.Extreme: - return new string[] { rare, epic, epic }; - default: - throw new NotImplementedException(); - } - } } diff --git a/Content.Server/Salvage/SpawnSalvageMissionJob.cs b/Content.Server/Salvage/SpawnSalvageMissionJob.cs index caeaf6c7bc..533e1db61a 100644 --- a/Content.Server/Salvage/SpawnSalvageMissionJob.cs +++ b/Content.Server/Salvage/SpawnSalvageMissionJob.cs @@ -135,6 +135,7 @@ public sealed class SpawnSalvageMissionJob : Job expedition.EndTime = _timing.CurTime + mission.Duration; expedition.MissionParams = _missionParams; expedition.Difficulty = _missionParams.Difficulty; + expedition.Rewards = mission.Rewards; // Don't want consoles to have the incorrect name until refreshed. var ftlUid = _entManager.CreateEntityUninitialized("FTLPoint", new EntityCoordinates(mapUid, Vector2.Zero)); @@ -216,14 +217,6 @@ public sealed class SpawnSalvageMissionJob : Job await SpawnDungeonLoot(dungeon, lootProto, mapUid, grid, random, reservedTiles); } - foreach (var (loot, count) in mission.Loot) - { - for (var i = 0; i < count; i++) - { - var lootProto = _prototypeManager.Index(loot); - await SpawnDungeonLoot(dungeon, lootProto, mapUid, grid, random, reservedTiles); - } - } return true; } @@ -251,62 +244,10 @@ public sealed class SpawnSalvageMissionJob : Job } } break; - // Spawns a cluster (like an ore vein) nearby. - case DungeonClusterLoot clusterLoot: - await SpawnDungeonClusterLoot(dungeon!, clusterLoot, grid, random, reservedTiles); - break; } } } - #region Loot - - private async Task SpawnDungeonClusterLoot( - Dungeon dungeon, - DungeonClusterLoot loot, - MapGridComponent grid, - Random random, - List reservedTiles) - { - var spawnTiles = new HashSet(); - - for (var i = 0; i < loot.Points; i++) - { - var room = dungeon.Rooms[random.Next(dungeon.Rooms.Count)]; - var clusterAmount = loot.ClusterAmount; - var spots = room.Tiles.ToList(); - random.Shuffle(spots); - - foreach (var spot in spots) - { - if (reservedTiles.Contains(spot)) - continue; - - var anchored = grid.GetAnchoredEntitiesEnumerator(spot); - - if (anchored.MoveNext(out _)) - { - continue; - } - - clusterAmount--; - spawnTiles.Add(spot); - - if (clusterAmount == 0) - break; - } - } - - foreach (var tile in spawnTiles) - { - await SuspendIfOutOfTime(); - var proto = _prototypeManager.Index(loot.Prototype).Pick(random); - _entManager.SpawnEntity(proto, grid.GridTileToLocal(tile)); - } - } - - #endregion - #region Mission Specific private async Task SetupMining( diff --git a/Content.Shared/Procedural/Loot/DungeonClusterLoot.cs b/Content.Shared/Procedural/Loot/DungeonClusterLoot.cs deleted file mode 100644 index f1f46079c2..0000000000 --- a/Content.Shared/Procedural/Loot/DungeonClusterLoot.cs +++ /dev/null @@ -1,24 +0,0 @@ -using Content.Shared.Random; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; - -namespace Content.Shared.Procedural.Loot; - -/// -/// Spawns loot at points in the specified area inside of a dungeon room. -/// -public sealed class DungeonClusterLoot : IDungeonLoot -{ - /// - /// Spawns in a cluster. - /// - [DataField("clusterAmount")] - public int ClusterAmount = 1; - - /// - /// Number of clusters to spawn. - /// - [DataField("clusters")] public int Points = 1; - - [DataField("lootTable", required: true, customTypeSerializer: typeof(PrototypeIdSerializer))] - public string Prototype { get; } = string.Empty; -} diff --git a/Content.Shared/Salvage/SalvageExpeditions.cs b/Content.Shared/Salvage/SalvageExpeditions.cs index 18a41eb30a..bac0819d57 100644 --- a/Content.Shared/Salvage/SalvageExpeditions.cs +++ b/Content.Shared/Salvage/SalvageExpeditions.cs @@ -103,7 +103,7 @@ public sealed record SalvageMission( string Air, Color? Color, TimeSpan Duration, - Dictionary Loot, + List Rewards, List Modifiers) { /// @@ -151,7 +151,10 @@ public sealed record SalvageMission( /// public TimeSpan Duration = Duration; - public Dictionary Loot = Loot; + /// + /// The list of items to order on mission completion. + /// + public List Rewards = Rewards; /// /// Modifiers (outside of the above) applied to the mission. diff --git a/Content.Shared/Salvage/SharedSalvageSystem.cs b/Content.Shared/Salvage/SharedSalvageSystem.cs index 50c8af9771..7a5a7c32e9 100644 --- a/Content.Shared/Salvage/SharedSalvageSystem.cs +++ b/Content.Shared/Salvage/SharedSalvageSystem.cs @@ -1,6 +1,5 @@ using System.Linq; using Content.Shared.Dataset; -using Content.Shared.Procedural.Loot; using Content.Shared.Random; using Content.Shared.Random.Helpers; using Content.Shared.Salvage.Expeditions; @@ -124,8 +123,8 @@ public abstract class SharedSalvageSystem : EntitySystem mods.Add(time.Description); } - var loots = GetLoot(config, _proto.EnumeratePrototypes().Where(o => !o.Guaranteed).ToList(), GetDifficulty(difficulty), seed); - return new SalvageMission(seed, difficulty, dungeon.ID, faction.ID, config, biome.ID, air.ID, light.Color, duration, loots, mods); + var rewards = GetRewards(difficulty, rand); + return new SalvageMission(seed, difficulty, dungeon.ID, faction.ID, config, biome.ID, air.ID, light.Color, duration, rewards, mods); } // TODO: probably worth putting the biome whitelist thing in a common thing then having a getmod overload for it @@ -208,28 +207,43 @@ public abstract class SharedSalvageSystem : EntitySystem throw new InvalidOperationException(); } - private Dictionary GetLoot(SalvageMissionType mission, List loots, int count, int seed) + private List GetRewards(DifficultyRating difficulty, System.Random rand) { - var results = new Dictionary(); - var adjustedSeed = new System.Random(seed + 2); - - for (var i = 0; i < count; i++) + var rewards = new List(3); + var ids = RewardsForDifficulty(difficulty); + foreach (var id in ids) { - adjustedSeed.Shuffle(loots); - - foreach (var loot in loots) - { - if (loot.Blacklist.Contains(mission)) - continue; - - var weh = results.GetOrNew(loot.ID); - weh++; - results[loot.ID] = weh; - break; - } + // pick a random reward to give + var weights = _proto.Index(id); + rewards.Add(weights.Pick(rand)); } - return results; + return rewards; + } + + /// + /// Get a list of WeightedRandomPrototype IDs with the rewards for a certain difficulty. + /// + private string[] RewardsForDifficulty(DifficultyRating rating) + { + var common = "SalvageRewardCommon"; + var rare = "SalvageRewardRare"; + var epic = "SalvageRewardEpic"; + switch (rating) + { + case DifficultyRating.Minimal: + return new string[] { common, common, common }; + case DifficultyRating.Minor: + return new string[] { common, common, rare }; + case DifficultyRating.Moderate: + return new string[] { common, rare, rare }; + case DifficultyRating.Hazardous: + return new string[] { rare, rare, epic }; + case DifficultyRating.Extreme: + return new string[] { rare, epic, epic }; + default: + throw new NotImplementedException(); + } } } diff --git a/Resources/Locale/en-US/procedural/expeditions.ftl b/Resources/Locale/en-US/procedural/expeditions.ftl index cb29c5ab8c..a0192fabd3 100644 --- a/Resources/Locale/en-US/procedural/expeditions.ftl +++ b/Resources/Locale/en-US/procedural/expeditions.ftl @@ -13,8 +13,7 @@ salvage-expedition-window-hostiles = Hostiles: salvage-expedition-window-duration = Duration: salvage-expedition-window-biome = Biome: salvage-expedition-window-modifiers = Modifiers: -salvage-expedition-window-loot = Loot: -salvage-expedition-window-none = N/A +salvage-expedition-window-rewards = Rewards: salvage-expedition-window-claimed = Claimed salvage-expedition-window-claim = Claim diff --git a/Resources/Prototypes/Catalog/Fills/Crates/salvage.yml b/Resources/Prototypes/Catalog/Fills/Crates/salvage.yml index 2b33df0427..9e83e1eec0 100644 --- a/Resources/Prototypes/Catalog/Fills/Crates/salvage.yml +++ b/Resources/Prototypes/Catalog/Fills/Crates/salvage.yml @@ -114,3 +114,35 @@ - id: WeaponRevolverMateba prob: 0.0001 +- type: entity + parent: CrateGenericSteel + id: CratePartsT3 + name: tier 3 parts crate + description: Contains 5 random tier 3 parts for upgrading machines. + components: + - type: StorageFill + contents: + - id: SalvagePartsT3Spawner + amount: 5 + +- type: entity + parent: CrateGenericSteel + id: CratePartsT3T4 + name: tier 3/4 parts crate + description: Contains 5 random tier 3 or 4 parts for upgrading machines. + components: + - type: StorageFill + contents: + - id: SalvagePartsT3T4Spawner + amount: 5 + +- type: entity + parent: CrateGenericSteel + id: CratePartsT4 + name: tier 4 parts crate + description: Contains 5 random tier 4 parts for upgrading machines. + components: + - type: StorageFill + contents: + - id: SalvagePartsT4Spawner + amount: 5 diff --git a/Resources/Prototypes/Procedural/salvage_loot.yml b/Resources/Prototypes/Procedural/salvage_loot.yml index 3b2519b63b..9d46018de5 100644 --- a/Resources/Prototypes/Procedural/salvage_loot.yml +++ b/Resources/Prototypes/Procedural/salvage_loot.yml @@ -1,55 +1,3 @@ -# Loot tables -#- type: weightedRandom -# id: SalvageLowValue -# weights: - # Common -# CrateSalvageAssortedGoodies: 1.0 - # Uncommon - # TODO: - # Rare - -- type: weightedRandom - id: SalvageHighValue - weights: - # Common - CrateMaterialPlasteel: 1.0 - CrateMaterialWood: 1.0 - CrateMaterialPlastic: 1.0 - CrateSalvageEquipment: 1.0 - CrateMaterialSteel: 1.0 - CrateMaterialGlass: 1.0 - # Uncommon - SuperCapacitorStockPart: 0.25 - PicoManipulatorStockPart: 0.25 - SuperMatterBinStockPart: 0.25 - # Rare - QuadraticCapacitorStockPart: 0.10 - FemtoManipulatorStockPart: 0.10 - BluespaceMatterBinStockPart: 0.10 - -# Crates -#- type: salvageLoot -# id: LowValue -# desc: Commodities -# blacklist: -# - Mining -# loots: -# - !type:DungeonClusterLoot -# lootTable: SalvageLowValue -# clusters: 3 -# clusterAmount: 3 - -- type: salvageLoot - id: HighValue - desc: High-value commodities - blacklist: - - Mining - loots: - - !type:DungeonClusterLoot - lootTable: SalvageHighValue - clusters: 5 - clusterAmount: 1 - # Ores # - Low value - type: salvageLoot diff --git a/Resources/Prototypes/Procedural/salvage_rewards.yml b/Resources/Prototypes/Procedural/salvage_rewards.yml index 9d5ea6cc96..d0b27167ac 100644 --- a/Resources/Prototypes/Procedural/salvage_rewards.yml +++ b/Resources/Prototypes/Procedural/salvage_rewards.yml @@ -25,8 +25,8 @@ IngotSilver: 1.0 SheetPlasma: 1.0 SheetUranium: 1.0 - SalvagePartsT3Spawner: 1.0 - SalvagePartsT3T4Spawner: 1.0 + CratePartsT3: 1.0 + CratePartsT3T4: 0.5 # things the expedition team might want CrateEmergencyBruteKit: 0.5 CrateMedicalSupplies: 0.5 @@ -48,7 +48,7 @@ # rare machinery SecurityTechFabCircuitboard: 1.0 ResearchAndDevelopmentServerMachineCircuitboard: 1.0 - SalvagePartsT4Spawner: 1.0 + CratePartsT4: 1.0 # rare weapons WeaponAdvancedLaser: 1.0 WeaponLaserCannon: 1.0