Salvage dungeons (#14520)
This commit is contained in:
@@ -0,0 +1,21 @@
|
||||
namespace Content.Shared.Salvage.Expeditions.Extraction;
|
||||
|
||||
public sealed class SalvageExtraction : ISalvageMission
|
||||
{
|
||||
/// <summary>
|
||||
/// Minimum weight to be used for a wave.
|
||||
/// </summary>
|
||||
[DataField("minWaveWeight")] public float MinWaveWeight = 5;
|
||||
|
||||
/// <summary>
|
||||
/// Minimum time between 2 waves. Roughly the end of one to the start of another.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite), DataField("waveCooldown")]
|
||||
public TimeSpan WaveCooldown = TimeSpan.FromSeconds(60);
|
||||
|
||||
/// <summary>
|
||||
/// How much weight accumulates per second while the expedition is active.
|
||||
/// </summary>
|
||||
[DataField("weightAccumulator")]
|
||||
public float WeightAccumulator = 0.1f;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace Content.Shared.Salvage.Expeditions;
|
||||
|
||||
|
||||
public interface IFactionExpeditionConfig
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.Dictionary;
|
||||
|
||||
namespace Content.Shared.Salvage.Expeditions;
|
||||
|
||||
[Prototype("salvageFaction")]
|
||||
public sealed class SalvageFactionPrototype : IPrototype
|
||||
{
|
||||
[IdDataField] public string ID { get; } = default!;
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite), DataField("groups", required: true)]
|
||||
public List<SalvageMobGroup> MobGroups = default!;
|
||||
|
||||
/// <summary>
|
||||
/// Per expedition type data for this faction.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite), DataField("configs", customTypeSerializer: typeof(PrototypeIdDictionarySerializer<IFactionExpeditionConfig, SalvageExpeditionPrototype>))]
|
||||
public Dictionary<string, IFactionExpeditionConfig> Configs = new();
|
||||
}
|
||||
18
Content.Shared/Salvage/Expeditions/SalvageMobGroup.cs
Normal file
18
Content.Shared/Salvage/Expeditions/SalvageMobGroup.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
using Content.Shared.Storage;
|
||||
|
||||
namespace Content.Shared.Salvage.Expeditions;
|
||||
|
||||
[DataDefinition]
|
||||
public record struct SalvageMobGroup()
|
||||
{
|
||||
// A mob may be cheap but rare or expensive but frequent.
|
||||
|
||||
/// <summary>
|
||||
/// Probability to spawn this group. Summed with everything else for the faction.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite), DataField("prob")]
|
||||
public float Prob = 1f;
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite), DataField("entries", required: true)]
|
||||
public List<EntitySpawnEntry> Entries = new();
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
namespace Content.Shared.Salvage.Expeditions.Structure;
|
||||
|
||||
/// <summary>
|
||||
/// Destroy the specified number of structures to finish the expedition.
|
||||
/// </summary>
|
||||
[DataDefinition]
|
||||
public sealed class SalvageStructure : ISalvageMission
|
||||
{
|
||||
[DataField("desc")]
|
||||
public string Description = string.Empty;
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite), DataField("minStructures")]
|
||||
public int MinStructures = 3;
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite), DataField("maxStructures")]
|
||||
public int MaxStructures = 5;
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
||||
|
||||
namespace Content.Shared.Salvage.Expeditions.Structure;
|
||||
|
||||
/// <summary>
|
||||
/// Per-faction config for Salvage Structure expeditions.
|
||||
/// </summary>
|
||||
[DataDefinition]
|
||||
public sealed class SalvageStructureFaction : IFactionExpeditionConfig
|
||||
{
|
||||
/// <summary>
|
||||
/// Entity prototype of the structures to destroy.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite), DataField("spawn", required: true, customTypeSerializer: typeof(PrototypeIdSerializer<EntityPrototype>))]
|
||||
public string Spawn = default!;
|
||||
|
||||
/// <summary>
|
||||
/// How many groups of mobs to spawn.
|
||||
/// </summary>
|
||||
[DataField("groupCount")]
|
||||
public int Groups = 5;
|
||||
}
|
||||
3
Content.Shared/Salvage/ISalvageMission.cs
Normal file
3
Content.Shared/Salvage/ISalvageMission.cs
Normal file
@@ -0,0 +1,3 @@
|
||||
namespace Content.Shared.Salvage;
|
||||
|
||||
public interface ISalvageMission {}
|
||||
89
Content.Shared/Salvage/SalvageExpeditionPrototype.cs
Normal file
89
Content.Shared/Salvage/SalvageExpeditionPrototype.cs
Normal file
@@ -0,0 +1,89 @@
|
||||
using Content.Shared.Dataset;
|
||||
using Content.Shared.Parallax.Biomes;
|
||||
using Content.Shared.Procedural;
|
||||
using Content.Shared.Procedural.Loot;
|
||||
using Content.Shared.Procedural.Rewards;
|
||||
using Content.Shared.Random;
|
||||
using Content.Shared.Salvage.Expeditions;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List;
|
||||
|
||||
namespace Content.Shared.Salvage;
|
||||
|
||||
[Prototype("salvageExpedition")]
|
||||
public sealed class SalvageExpeditionPrototype : IPrototype
|
||||
{
|
||||
[IdDataField] public string ID { get; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// Naming scheme for the FTL marker.
|
||||
/// </summary>
|
||||
[DataField("nameProto", customTypeSerializer:typeof(PrototypeIdSerializer<DatasetPrototype>))]
|
||||
public string NameProto = "names_borer";
|
||||
|
||||
/// <summary>
|
||||
/// Biome to generate the dungeon.
|
||||
/// </summary>
|
||||
[DataField("biome", required: true, customTypeSerializer: typeof(PrototypeIdSerializer<BiomePrototype>))]
|
||||
public string Biome = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Player-friendly description for the console.
|
||||
/// </summary>
|
||||
[DataField("desc")]
|
||||
public string Description = string.Empty;
|
||||
|
||||
[DataField("difficultyRating")]
|
||||
public DifficultyRating DifficultyRating = DifficultyRating.Minor;
|
||||
|
||||
// TODO: Make these modifiers but also add difficulty modifiers.
|
||||
[DataField("light")]
|
||||
public Color Light = Color.Black;
|
||||
|
||||
[DataField("temperature")]
|
||||
public float Temperature = 293.15f;
|
||||
|
||||
[DataField("expedition", required: true)]
|
||||
public ISalvageMission Mission = default!;
|
||||
|
||||
[DataField("minDuration")]
|
||||
public TimeSpan MinDuration = TimeSpan.FromSeconds(9 * 60);
|
||||
|
||||
[DataField("maxDuration")]
|
||||
public TimeSpan MaxDuration = TimeSpan.FromSeconds(12 * 60);
|
||||
|
||||
/// <summary>
|
||||
/// Available factions for selection for this mission prototype.
|
||||
/// </summary>
|
||||
[DataField("factions", customTypeSerializer:typeof(PrototypeIdListSerializer<SalvageFactionPrototype>))]
|
||||
public List<string> Factions = new();
|
||||
|
||||
[DataField("dungeonConfig", required: true, customTypeSerializer: typeof(PrototypeIdSerializer<DungeonConfigPrototype>))]
|
||||
public string DungeonConfigPrototype = string.Empty;
|
||||
|
||||
[DataField("reward", customTypeSerializer: typeof(PrototypeIdSerializer<WeightedRandomPrototype>))]
|
||||
public string Reward = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Possible loot prototypes available for this expedition.
|
||||
/// This spawns during the mission and is not tied to completion.
|
||||
/// </summary>
|
||||
[DataField("loot", customTypeSerializer: typeof(PrototypeIdListSerializer<WeightedRandomPrototype>))]
|
||||
public List<string> Loots = new();
|
||||
|
||||
[DataField("dungeonPosition")]
|
||||
public Vector2i DungeonPosition = new(80, -25);
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public enum DifficultyRating : byte
|
||||
{
|
||||
None,
|
||||
Minor,
|
||||
Moderate,
|
||||
Hazardous,
|
||||
Extreme,
|
||||
}
|
||||
|
||||
91
Content.Shared/Salvage/SalvageExpeditions.cs
Normal file
91
Content.Shared/Salvage/SalvageExpeditions.cs
Normal file
@@ -0,0 +1,91 @@
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
||||
|
||||
namespace Content.Shared.Salvage;
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class SalvageExpeditionConsoleState : BoundUserInterfaceState
|
||||
{
|
||||
public TimeSpan NextOffer;
|
||||
public bool Claimed;
|
||||
public ushort ActiveMission;
|
||||
public List<SalvageMission> Missions;
|
||||
|
||||
public SalvageExpeditionConsoleState(TimeSpan nextOffer, bool claimed, ushort activeMission, List<SalvageMission> missions)
|
||||
{
|
||||
NextOffer = nextOffer;
|
||||
Claimed = claimed;
|
||||
ActiveMission = activeMission;
|
||||
Missions = missions;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used to interact with salvage expeditions and claim them.
|
||||
/// </summary>
|
||||
[RegisterComponent, NetworkedComponent]
|
||||
public sealed class SalvageExpeditionConsoleComponent : Component
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class ClaimSalvageMessage : BoundUserInterfaceMessage
|
||||
{
|
||||
public ushort Index;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Added per station to store data on their available salvage missions.
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
public sealed class SalvageExpeditionDataComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// Is there an active salvage expedition.
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
public bool Claimed => ActiveMission != 0;
|
||||
|
||||
/// <summary>
|
||||
/// Nexy time salvage missions are offered.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite), DataField("nextOffer", customTypeSerializer:typeof(TimeOffsetSerializer))]
|
||||
public TimeSpan NextOffer;
|
||||
|
||||
[ViewVariables]
|
||||
public readonly Dictionary<ushort, SalvageMission> Missions = new();
|
||||
|
||||
[ViewVariables] public ushort ActiveMission;
|
||||
|
||||
public ushort NextIndex = 1;
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed record SalvageMission
|
||||
{
|
||||
[ViewVariables]
|
||||
public ushort Index;
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite), DataField("config", required: true, customTypeSerializer:typeof(SalvageExpeditionPrototype))]
|
||||
public string Config = default!;
|
||||
|
||||
[ViewVariables] public TimeSpan Duration;
|
||||
|
||||
[ViewVariables] public int Seed;
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public enum SalvageEnvironment : byte
|
||||
{
|
||||
Invalid = 0,
|
||||
Caves,
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public enum SalvageConsoleUiKey : byte
|
||||
{
|
||||
Expedition,
|
||||
}
|
||||
77
Content.Shared/Salvage/SharedSalvageSystem.cs
Normal file
77
Content.Shared/Salvage/SharedSalvageSystem.cs
Normal file
@@ -0,0 +1,77 @@
|
||||
using Content.Shared.Dataset;
|
||||
using Content.Shared.Procedural.Loot;
|
||||
using Content.Shared.Procedural.Rewards;
|
||||
using Content.Shared.Random;
|
||||
using Content.Shared.Random.Helpers;
|
||||
using Content.Shared.Salvage.Expeditions.Structure;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared.Salvage;
|
||||
|
||||
public abstract class SharedSalvageSystem : EntitySystem
|
||||
{
|
||||
public static readonly TimeSpan MissionCooldown = TimeSpan.FromMinutes(5);
|
||||
public static readonly TimeSpan MissionFailedCooldown = TimeSpan.FromMinutes(10);
|
||||
|
||||
public static float GetDifficultyModifier(DifficultyRating difficulty)
|
||||
{
|
||||
// These should reflect how many salvage staff are expected to be required for the mission.
|
||||
switch (difficulty)
|
||||
{
|
||||
case DifficultyRating.None:
|
||||
return 1f;
|
||||
case DifficultyRating.Minor:
|
||||
return 1.5f;
|
||||
case DifficultyRating.Moderate:
|
||||
return 3f;
|
||||
case DifficultyRating.Hazardous:
|
||||
return 6f;
|
||||
case DifficultyRating.Extreme:
|
||||
return 10f;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(difficulty), difficulty, null);
|
||||
}
|
||||
}
|
||||
|
||||
public static string GetFTLName(DatasetPrototype dataset, int seed)
|
||||
{
|
||||
var random = new System.Random(seed);
|
||||
return $"{dataset.Values[random.Next(dataset.Values.Count)]}-{random.Next(10, 100)}-{(char) (65 + random.Next(26))}";
|
||||
}
|
||||
|
||||
public static string GetFaction(List<string> factions, int seed)
|
||||
{
|
||||
var adjustedSeed = new System.Random(seed + 1);
|
||||
return factions[adjustedSeed.Next(factions.Count)];
|
||||
}
|
||||
|
||||
public static IEnumerable<SalvageLootPrototype> GetLoot(List<string> loots, int seed, IPrototypeManager protoManager)
|
||||
{
|
||||
var adjustedSeed = new System.Random(seed + 2);
|
||||
|
||||
for (var i = 0; i < loots.Count; i++)
|
||||
{
|
||||
var loot = loots[i];
|
||||
var a = protoManager.Index<WeightedRandomPrototype>(loot);
|
||||
var lootConfig = a.Pick(adjustedSeed);
|
||||
yield return protoManager.Index<SalvageLootPrototype>(lootConfig);
|
||||
}
|
||||
}
|
||||
|
||||
public static ISalvageReward GetReward(WeightedRandomPrototype proto, int seed, IPrototypeManager protoManager)
|
||||
{
|
||||
var adjustedSeed = new System.Random(seed + 3);
|
||||
var rewardProto = proto.Pick(adjustedSeed);
|
||||
return protoManager.Index<SalvageRewardPrototype>(rewardProto).Reward;
|
||||
}
|
||||
|
||||
#region Structure
|
||||
|
||||
public static int GetStructureCount(SalvageStructure structure, int seed)
|
||||
{
|
||||
var adjustedSeed = new System.Random(seed + 4);
|
||||
return adjustedSeed.Next(structure.MinStructures, structure.MaxStructures + 1);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
Reference in New Issue
Block a user