Salvage dungeons (#14520)

This commit is contained in:
metalgearsloth
2023-03-10 16:41:22 +11:00
committed by GitHub
parent 214ca06997
commit 6157dfa3c0
145 changed files with 24649 additions and 396 deletions

View File

@@ -0,0 +1,11 @@
namespace Content.Shared.Procedural;
public sealed class Dungeon
{
public List<DungeonRoom> Rooms = new();
/// <summary>
/// Hashset of the tiles across all rooms.
/// </summary>
public HashSet<Vector2i> RoomTiles = new();
}

View File

@@ -0,0 +1,21 @@
using Content.Shared.Procedural.DungeonGenerators;
using Content.Shared.Procedural.PostGeneration;
using Robust.Shared.Prototypes;
namespace Content.Shared.Procedural;
[Prototype("dungeonConfig")]
public sealed class DungeonConfigPrototype : IPrototype
{
[IdDataField]
public string ID { get; } = default!;
[DataField("generator", required: true)]
public IDunGen Generator = default!;
/// <summary>
/// Ran after the main dungeon is created.
/// </summary>
[DataField("postGeneration")]
public List<IPostDunGen> PostGeneration = new();
}

View File

@@ -0,0 +1,7 @@
namespace Content.Shared.Procedural.DungeonGenerators;
[ImplicitDataDefinitionForInheritors]
public interface IDunGen
{
}

View File

@@ -0,0 +1,30 @@
using Content.Shared.Maps;
using Content.Shared.Tag;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List;
namespace Content.Shared.Procedural.DungeonGenerators;
/// <summary>
/// Places rooms in pre-selected pack layouts. Chooses rooms from the specified whitelist.
/// </summary>
public sealed class PrefabDunGen : IDunGen
{
/// <summary>
/// Rooms need to match any of these tags
/// </summary>
[DataField("roomWhitelist", customTypeSerializer:typeof(PrototypeIdListSerializer<TagPrototype>))]
public List<string> RoomWhitelist = new();
/// <summary>
/// Room pack presets we can use for this prefab.
/// </summary>
[DataField("presets", required: true, customTypeSerializer:typeof(PrototypeIdListSerializer<DungeonPresetPrototype>))]
public List<string> Presets = new();
/// <summary>
/// Fallback tile.
/// </summary>
[DataField("tile", customTypeSerializer:typeof(PrototypeIdSerializer<ContentTileDefinition>))]
public string Tile = "FloorSteel";
}

View File

@@ -0,0 +1,10 @@
namespace Content.Shared.Procedural;
/// <summary>
/// Connects 2 dungeon rooms.
/// </summary>
public sealed record DungeonPath(string Tile, string Wall, HashSet<Vector2i> Tiles)
{
public string Tile = Tile;
public string Wall = Wall;
}

View File

@@ -0,0 +1,15 @@
using Robust.Shared.Prototypes;
namespace Content.Shared.Procedural;
[Prototype("dungeonPreset")]
public sealed class DungeonPresetPrototype : IPrototype
{
[IdDataField] public string ID { get; } = default!;
/// <summary>
/// The room pack bounds we need to fill.
/// </summary>
[DataField("roomPacks", required: true)]
public List<Box2i> RoomPacks = new();
}

View File

@@ -0,0 +1,3 @@
namespace Content.Shared.Procedural;
public sealed record DungeonRoom(HashSet<Vector2i> Tiles, Vector2 Center);

View File

@@ -0,0 +1,17 @@
using Robust.Shared.Prototypes;
namespace Content.Shared.Procedural;
[Prototype("dungeonRoomPack")]
public sealed class DungeonRoomPackPrototype : IPrototype
{
[IdDataField]
public string ID { get; } = string.Empty;
/// <summary>
/// Used to associate the room pack with other room packs with the same dimensions.
/// </summary>
[DataField("size", required: true)] public Vector2i Size;
[DataField("rooms", required: true)] public List<Box2i> Rooms = new();
}

View File

@@ -0,0 +1,27 @@
using Content.Shared.Tag;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List;
using Robust.Shared.Utility;
namespace Content.Shared.Procedural;
[Prototype("dungeonRoom")]
public sealed class DungeonRoomPrototype : IPrototype
{
[IdDataField] public string ID { get; } = string.Empty;
[ViewVariables(VVAccess.ReadWrite), DataField("tags", customTypeSerializer:typeof(PrototypeIdListSerializer<TagPrototype>))]
public List<string> Tags = new();
[DataField("size", required: true)] public Vector2i Size;
/// <summary>
/// Path to the file to use for the room.
/// </summary>
[DataField("atlas", required: true)] public ResourcePath AtlasPath = default!;
/// <summary>
/// Tile offset into the atlas to use for the room.
/// </summary>
[DataField("offset", required: true)] public Vector2i Offset;
}

View File

@@ -0,0 +1,35 @@
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
namespace Content.Shared.Procedural.Loot;
/// <summary>
/// Spawns loot at points in the specified rooms
/// </summary>
public sealed class ClusterLoot : IDungeonLoot
{
/// <summary>
/// Minimum spawns in a cluster.
/// </summary>
[DataField("minCluster")]
public int MinClusterAmount;
/// <summary>
/// Maximum spawns in a cluster.
/// </summary>
[DataField("maxCluster")] public int MaxClusterAmount;
/// <summary>
/// Amount to spawn for the entire loot.
/// </summary>
[DataField("max")]
public int Amount;
/// <summary>
/// Number of points to spawn.
/// </summary>
[DataField("points")] public int Points;
[DataField("proto", required: true, customTypeSerializer: typeof(PrototypeIdSerializer<EntityPrototype>))]
public string Prototype { get; } = string.Empty;
}

View File

@@ -0,0 +1,7 @@
namespace Content.Shared.Procedural.Loot;
[ImplicitDataDefinitionForInheritors]
public interface IDungeonLoot
{
string Prototype { get; }
}

View File

@@ -0,0 +1,20 @@
using Robust.Shared.Prototypes;
namespace Content.Shared.Procedural.Loot;
/// <summary>
/// Spawned inside of a salvage mission.
/// </summary>
[Prototype("salvageLoot")]
public sealed class SalvageLootPrototype : IPrototype
{
[IdDataField] public string ID { get; } = default!;
[DataField("desc")] public string Description = string.Empty;
/// <summary>
/// All of the loot rules
/// </summary>
[DataField("loots")]
public List<IDungeonLoot> LootRules = new();
}

View File

@@ -0,0 +1,23 @@
using Content.Shared.Maps;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
namespace Content.Shared.Procedural.PostGeneration;
/// <summary>
/// Iterates room edges and places the relevant tiles and walls on any free indices.
/// </summary>
public sealed class BoundaryWallPostGen : IPostDunGen
{
[DataField("tile", customTypeSerializer:typeof(PrototypeIdSerializer<ContentTileDefinition>))]
public string Tile = "FloorSteel";
[DataField("wall", customTypeSerializer:typeof(PrototypeIdSerializer<EntityPrototype>))]
public string Wall = "WallSolid";
/// <summary>
/// Walls to use in corners if applicable.
/// </summary>
[DataField("cornerWall", customTypeSerializer:typeof(PrototypeIdSerializer<EntityPrototype>))]
public string? CornerWall;
}

View File

@@ -0,0 +1,23 @@
using Content.Shared.Maps;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
namespace Content.Shared.Procedural.PostGeneration;
/// <summary>
/// Selects [count] rooms and places external doors to them.
/// </summary>
public sealed class EntrancePostGen : IPostDunGen
{
/// <summary>
/// How many rooms we place doors on.
/// </summary>
[DataField("count")]
public int Count = 1;
[DataField("door", customTypeSerializer:typeof(PrototypeIdSerializer<EntityPrototype>))]
public string Door = "AirlockGlass";
[DataField("tile", customTypeSerializer:typeof(PrototypeIdSerializer<ContentTileDefinition>))]
public string Tile = "FloorSteel";
}

View File

@@ -0,0 +1,22 @@
using Content.Shared.Maps;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List;
namespace Content.Shared.Procedural.PostGeneration;
/// <summary>
/// If external areas are found will try to generate windows.
/// </summary>
public sealed class ExternalWindowPostGen : IPostDunGen
{
[DataField("entities", customTypeSerializer: typeof(PrototypeIdListSerializer<EntityPrototype>))]
public List<string> Entities = new()
{
"Grille",
"Window",
};
[DataField("tile", customTypeSerializer:typeof(PrototypeIdSerializer<ContentTileDefinition>))]
public string Tile = "FloorSteel";
}

View File

@@ -0,0 +1,10 @@
namespace Content.Shared.Procedural.PostGeneration;
/// <summary>
/// Ran after generating dungeon rooms. Can be used for additional loot, contents, etc.
/// </summary>
[ImplicitDataDefinitionForInheritors]
public interface IPostDunGen
{
}

View File

@@ -0,0 +1,22 @@
using Content.Shared.Maps;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List;
namespace Content.Shared.Procedural.PostGeneration;
/// <summary>
/// If internal areas are found will try to generate windows.
/// </summary>
public sealed class InternalWindowPostGen : IPostDunGen
{
[DataField("entities", customTypeSerializer: typeof(PrototypeIdListSerializer<EntityPrototype>))]
public List<string> Entities = new()
{
"Grille",
"Window",
};
[DataField("tile", customTypeSerializer:typeof(PrototypeIdSerializer<ContentTileDefinition>))]
public string Tile = "FloorSteel";
}

View File

@@ -0,0 +1,39 @@
using Content.Shared.Maps;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List;
namespace Content.Shared.Procedural.PostGeneration;
/// <summary>
/// Places the specified entities on the middle connections between rooms
/// </summary>
public sealed class MiddleConnectionPostGen : IPostDunGen
{
/// <summary>
/// How much overlap there needs to be between 2 rooms exactly.
/// </summary>
[DataField("overlapCount")]
public int OverlapCount = -1;
/// <summary>
/// How many connections to spawn between rooms.
/// </summary>
[DataField("count")]
public int Count = 1;
[DataField("tile", customTypeSerializer:typeof(PrototypeIdSerializer<ContentTileDefinition>))]
public string Tile = "FloorSteel";
[DataField("entities", customTypeSerializer: typeof(PrototypeIdListSerializer<EntityPrototype>))]
public List<string> Entities = new()
{
"CableApcExtension",
"AirlockGlass"
};
/// <summary>
/// If overlap > 1 then what should spawn on the edges.
/// </summary>
[DataField("edgeEntities")] public List<string>? EdgeEntities;
}

View File

@@ -0,0 +1,23 @@
using Content.Shared.Maps;
using Content.Shared.Storage;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
namespace Content.Shared.Procedural.PostGeneration;
/// <summary>
/// Spawns on the boundary tiles of rooms.
/// </summary>
public sealed class WallMountPostGen : IPostDunGen
{
[DataField("tile", customTypeSerializer:typeof(PrototypeIdSerializer<ContentTileDefinition>))]
public string Tile = "FloorSteel";
[DataField("spawns")]
public List<EntitySpawnEntry> Spawns = new();
/// <summary>
/// Chance per free tile to spawn a wallmount.
/// </summary>
[DataField("prob")]
public double Prob = 0.1;
}

View File

@@ -0,0 +1,10 @@
namespace Content.Shared.Procedural.Rewards;
/// <summary>
/// Payout to the station's bank account.
/// </summary>
public sealed class BankReward : ISalvageReward
{
[DataField("amount")]
public int Amount = 0;
}

View File

@@ -0,0 +1,7 @@
namespace Content.Shared.Procedural.Rewards;
[ImplicitDataDefinitionForInheritors]
public interface ISalvageReward
{
}

View File

@@ -0,0 +1,14 @@
using Robust.Shared.Prototypes;
namespace Content.Shared.Procedural.Rewards;
/// <summary>
/// Given after successful completion of a salvage mission.
/// </summary>
[Prototype("salvageReward")]
public sealed class SalvageRewardPrototype : IPrototype
{
[IdDataField] public string ID { get; } = string.Empty;
[DataField("reward", required: true)] public ISalvageReward Reward = default!;
}