Unstable v0.19.1.0

This commit is contained in:
Juan Pablo Arce
2022-08-19 13:59:08 -03:00
parent 6b55adcdd9
commit 1219615d64
192 changed files with 3875 additions and 2648 deletions
@@ -8,6 +8,7 @@ using Microsoft.Xna.Framework;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using Voronoi2;
@@ -24,6 +25,22 @@ namespace Barotrauma
//all entities are disabled after they reach this depth
public const int MaxEntityDepth = -1000000;
public const float ShaftHeight = 1000.0f;
/// <summary>
/// How far outside the boundaries of the level the water current that pushes subs towards the level starts
/// </summary>
public const float OutsideBoundsCurrentMargin = 30000.0f;
/// <summary>
/// How far outside the boundaries of the level the strength of the current starts to increase exponentially
/// </summary>
public const float OutsideBoundsCurrentMarginExponential = 150000.0f;
/// <summary>
/// How far outside the boundaries of the level the current stops submarines entirely
/// </summary>
public const float OutsideBoundsCurrentHardLimit = 200000.0f;
/// <summary>
/// The level generator won't try to adjust the width of the main path above this limit.
/// </summary>
@@ -2437,16 +2454,27 @@ namespace Barotrauma
public List<ClusterLocation> ClusterLocations { get; }
public TunnelType TunnelType { get; }
public PathPoint(string id, Vector2 position, bool shouldContainResources, TunnelType tunnelType)
private PathPoint(string id, Vector2 position, bool shouldContainResources, TunnelType tunnelType, List<Identifier> resourceTags, List<Identifier> resourceIds, List<ClusterLocation> clusterLocations)
{
Id = id;
Id = id;
Position = position;
ShouldContainResources = shouldContainResources;
ResourceTags = new List<Identifier>();
ResourceIds = new List<Identifier>();
ClusterLocations = new List<ClusterLocation>();
ResourceTags = resourceTags;
ResourceIds = resourceIds;
ClusterLocations = clusterLocations;
TunnelType = tunnelType;
}
public PathPoint(string id, Vector2 position, bool shouldContainResources, TunnelType tunnelType)
: this(id, position, shouldContainResources, tunnelType, new List<Identifier>(), new List<Identifier>(), new List<ClusterLocation>())
{
}
public PathPoint WithResources(bool containsResources)
{
return new PathPoint(Id, Position, containsResources, TunnelType, ResourceTags, ResourceIds, ClusterLocations);
}
}
public List<ClusterLocation> AbyssResources { get; } = new List<ClusterLocation>();
@@ -2485,22 +2513,26 @@ namespace Barotrauma
// Such as the exploding crystals in The Great Sea
private void GenerateItems()
{
Identifier levelName = GenerationParams.Identifier;
float minCommonness = float.MaxValue, maxCommonness = float.MinValue;
List<(ItemPrefab itemPrefab, float commonness)> levelResources = new List<(ItemPrefab itemPrefab, float commonness)>();
var levelResources = new List<(ItemPrefab itemPrefab, ItemPrefab.CommonnessInfo commonnessInfo)>();
var fixedResources = new List<(ItemPrefab itemPrefab, ItemPrefab.FixedQuantityResourceInfo resourceInfo)>();
Vector2 commonnessRange = new Vector2(float.MaxValue, float.MinValue), caveCommonnessRange = new Vector2(float.MaxValue, float.MinValue);
foreach (ItemPrefab itemPrefab in ItemPrefab.Prefabs.OrderBy(p => p.UintIdentifier))
{
if (itemPrefab.LevelCommonness.TryGetValue(levelName, out float commonness) ||
itemPrefab.LevelCommonness.TryGetValue(LevelData.Biome.Identifier, out commonness) ||
itemPrefab.LevelCommonness.TryGetValue(Identifier.Empty, out commonness))
if (itemPrefab.GetCommonnessInfo(this) is { CanAppear: true } commonnessInfo)
{
if (commonness <= 0.0f) { continue; }
if (commonness < minCommonness) { minCommonness = commonness; }
if (commonness > maxCommonness) { maxCommonness = commonness; }
levelResources.Add((itemPrefab, commonness));
if (commonnessInfo.Commonness > 0.0)
{
if (commonnessInfo.Commonness < commonnessRange.X) { commonnessRange.X = commonnessInfo.Commonness; }
if (commonnessInfo.Commonness > commonnessRange.Y) { commonnessRange.Y = commonnessInfo.Commonness; }
}
if (commonnessInfo.CaveCommonness > 0.0)
{
if (commonnessInfo.CaveCommonness < caveCommonnessRange.X) { caveCommonnessRange.X = commonnessInfo.CaveCommonness; }
if (commonnessInfo.CaveCommonness > caveCommonnessRange.Y) { caveCommonnessRange.Y = commonnessInfo.CaveCommonness; }
}
levelResources.Add((itemPrefab, commonnessInfo));
}
else if (itemPrefab.LevelQuantity.TryGetValue(levelName, out var fixedQuantityResourceInfo) ||
else if (itemPrefab.LevelQuantity.TryGetValue(GenerationParams.Identifier, out var fixedQuantityResourceInfo) ||
itemPrefab.LevelQuantity.TryGetValue(Identifier.Empty, out fixedQuantityResourceInfo))
{
fixedResources.Add((itemPrefab, fixedQuantityResourceInfo));
@@ -2533,18 +2565,18 @@ namespace Barotrauma
}
}
//place some of the least common resources in the abyss
// Abyss Resources
AbyssResources.Clear();
int abyssClusterCount = (int)MathHelper.Lerp(GenerationParams.AbyssResourceClustersMin, GenerationParams.AbyssResourceClustersMax, Difficulty / 100.0f);
var abyssResourcePrefabs = levelResources.Where(r => r.commonnessInfo.AbyssCommonness > 0.0f);
int abyssClusterCount = (int)MathHelper.Lerp(GenerationParams.AbyssResourceClustersMin, GenerationParams.AbyssResourceClustersMax, MathUtils.InverseLerp(LevelData.Biome.MinDifficulty, LevelData.Biome.AdjustedMaxDifficulty, Difficulty));
for (int i = 0; i < abyssClusterCount; i++)
{
//use inverse commonness to select the abyss resources (the rarest ones are the most common in the abyss)
var selectedPrefab = ToolBox.SelectWeightedRandom(
levelResources.Select(it => it.itemPrefab).ToList(),
levelResources.Select(it => it.commonness <= 0.0f ? 0.0f : 1.0f / it.commonness).ToList(),
abyssResourcePrefabs.Select(r => r.itemPrefab).ToList(),
abyssResourcePrefabs.Select(r => r.commonnessInfo.AbyssCommonness).ToList(),
Rand.RandSync.ServerAndClient);
var location = allValidLocations.GetRandom(l =>
{
if (l.Cell == null || l.Edge == null) { return false; }
@@ -2554,14 +2586,16 @@ namespace Barotrauma
}, randSync: Rand.RandSync.ServerAndClient);
if (location.Cell == null || location.Edge == null) { break; }
int clusterSize = Rand.Range(GenerationParams.ResourceClusterSizeRange.X, GenerationParams.ResourceClusterSizeRange.Y + 1, Rand.RandSync.ServerAndClient);
PlaceResources(selectedPrefab, clusterSize, location, out var abyssResources);
PlaceResources(selectedPrefab, clusterSize, location, out var placedResources, maxResourceOverlap: 0);
var abyssClusterLocation = new ClusterLocation(location.Cell, location.Edge, initializeResourceList: true);
abyssClusterLocation.Resources.AddRange(abyssResources);
abyssClusterLocation.Resources.AddRange(placedResources);
AbyssResources.Add(abyssClusterLocation);
var locationIndex = allValidLocations.FindIndex(l => l.Equals(location));
allValidLocations.RemoveAt(locationIndex);
}
}
PathPoints.Clear();
nextPathPointId = 0;
@@ -2618,17 +2652,25 @@ namespace Barotrauma
int itemCount = 0;
Identifier[] exclusiveResourceTags = new Identifier[2] { "ore".ToIdentifier(), "plant".ToIdentifier() };
var disabledPathPoints = new List<string>();
// Create first cluster for each spawn point
foreach (var pathPoint in PathPoints.Where(p => p.ShouldContainResources))
foreach (var pathPoint in PathPoints)
{
if (itemCount >= GenerationParams.ItemCount) { break; }
if (!pathPoint.ShouldContainResources) { continue; }
GenerateFirstCluster(pathPoint);
if (pathPoint.ClusterLocations.Count > 0) { continue; }
disabledPathPoints.Add(pathPoint.Id);
}
// Don't try to spawn more resource clusters for points for which the initial cluster could not be spawned
foreach (string pathPointId in disabledPathPoints)
{
if (PathPoints.FirstOrNull(p => p.Id == pathPointId) is PathPoint pathPoint)
{
PathPoints.RemoveAll(p => p.Id == pathPointId);
PathPoints.Add(pathPoint.WithResources(false));
}
}
// Don't try to spawn more resource clusters for points
// for which the initial cluster could not be spawned
PathPoints.Where(p => p.ShouldContainResources && p.ClusterLocations.Count == 0)
.ForEach(p => p.ShouldContainResources = false);
var excludedPathPointIds = new List<string>();
while (itemCount < GenerationParams.ItemCount)
@@ -2647,35 +2689,16 @@ namespace Barotrauma
GenerateAdditionalCluster(pathPoint);
}
// If none of the point set to contain resources can take more resources,
// but we still haven't reached the item count set in the generation parameters...
while (itemCount < GenerationParams.ItemCount)
{
// We need to start filling some of the path points previously set to not contain resources
Func<PathPoint, bool> availablePathPoints = p => !excludedPathPointIds.Contains(p.Id) && p.ClusterLocations.None();
if (PathPoints.None(availablePathPoints)) { break; }
var pathPoint = PathPoints.GetRandom(availablePathPoints, randSync: Rand.RandSync.ServerAndClient);
if (!GenerateFirstCluster(pathPoint))
{
excludedPathPointIds.Add(pathPoint.Id);
continue;
}
while (pathPoint.NextClusterProbability > 0)
{
if (!GenerateAdditionalCluster(pathPoint)) { break; }
}
pathPoint.ShouldContainResources = pathPoint.ClusterLocations.Any();
}
#if DEBUG
DebugConsole.NewMessage("Level resources spawned: " + itemCount + "\n" +
" Spawn points containing resources: " + PathPoints.Where(p => p.ClusterLocations.Any()).Count() + "/" + PathPoints.Count + "\n" +
" Total value: " + PathPoints.Sum(p => p.ClusterLocations.Sum(c => c.Resources.Sum(r => r.Prefab.DefaultPrice?.Price ?? 0))) + " mk");
int spawnPointsContainingResources = PathPoints.Where(p => p.ClusterLocations.Any()).Count();
string percentage = string.Format(CultureInfo.InvariantCulture, "{0:P2}", (float)spawnPointsContainingResources / PathPoints.Count);
DebugConsole.NewMessage($"Level resources spawned: {itemCount}\n" +
$" Spawn points containing resources: {spawnPointsContainingResources} ({percentage})\n" +
$" Total value: {PathPoints.Sum(p => p.ClusterLocations.Sum(c => c.Resources.Sum(r => r.Prefab.DefaultPrice?.Price ?? 0)))} mk");
if (AbyssResources.Count > 0)
{
DebugConsole.NewMessage("Abyss resources spawned: " + AbyssResources.Sum(a => a.Resources.Count) + "\n" +
" Total value: " + AbyssResources.Sum(c => c.Resources.Sum(r => r.Prefab.DefaultPrice?.Price ?? 0)) + " mk");
DebugConsole.NewMessage($"Abyss resources spawned: {AbyssResources.Sum(a => a.Resources.Count)}\n" +
$" Total value: {AbyssResources.Sum(c => c.Resources.Sum(r => r.Prefab.DefaultPrice?.Price ?? 0))} mk");
}
#endif
@@ -2842,7 +2865,7 @@ namespace Barotrauma
{
selectedPrefab = ToolBox.SelectWeightedRandom(
levelResources.Select(it => it.itemPrefab).ToList(),
levelResources.Select(it => it.commonness).ToList(),
levelResources.Select(it => it.commonnessInfo.GetCommonness(pathPoint.TunnelType)).ToList(),
Rand.RandSync.ServerAndClient);
selectedPrefab.Tags.ForEach(t =>
{
@@ -2854,20 +2877,21 @@ namespace Barotrauma
}
else
{
var filteredResources = levelResources.Where(it =>
!pathPoint.ResourceIds.Contains(it.itemPrefab.Identifier) &&
pathPoint.ResourceTags.Any() && it.itemPrefab.Tags.Any(t => pathPoint.ResourceTags.Contains(t)));
selectedPrefab = ToolBox.SelectWeightedRandom(
var filteredResources = pathPoint.ResourceTags.None() ? levelResources :
levelResources.Where(it => it.itemPrefab.Tags.Any(t => pathPoint.ResourceTags.Contains(t)));
selectedPrefab = ToolBox.SelectWeightedRandom(
filteredResources.Select(it => it.itemPrefab).ToList(),
filteredResources.Select(it => it.commonness).ToList(),
filteredResources.Select(it => it.commonnessInfo.GetCommonness(pathPoint.TunnelType)).ToList(),
Rand.RandSync.ServerAndClient);
}
if (selectedPrefab == null) { return false; }
// Create resources for the cluster
var commonness = levelResources.First(r => r.itemPrefab == selectedPrefab).commonness;
var lerpAmount = MathUtils.InverseLerp(minCommonness, maxCommonness, commonness);
float commonness = levelResources.First(r => r.itemPrefab == selectedPrefab).commonnessInfo.GetCommonness(pathPoint.TunnelType);
float lerpAmount = pathPoint.TunnelType != TunnelType.Cave ?
MathUtils.InverseLerp(commonnessRange.X, commonnessRange.Y, commonness) :
MathUtils.InverseLerp(caveCommonnessRange.X, caveCommonnessRange.Y, commonness);
var maxClusterSize = (int)MathHelper.Lerp(GenerationParams.ResourceClusterSizeRange.X, GenerationParams.ResourceClusterSizeRange.Y, lerpAmount);
var maxFitOnEdge = GetMaxResourcesOnEdge(selectedPrefab, location, out var edgeLength);
maxClusterSize = Math.Min(maxClusterSize, maxFitOnEdge);
@@ -2898,6 +2922,7 @@ namespace Barotrauma
edgeLength = 0.0f;
if (location.Cell == null || location.Edge == null) { return 0; }
edgeLength = Vector2.Distance(location.Edge.Point1, location.Edge.Point2);
if (resourcePrefab == null) { return 0; }
return (int)Math.Floor(edgeLength / ((1.0f - maxResourceOverlap) * resourcePrefab.Size.X));
}
}
@@ -3041,15 +3066,19 @@ namespace Barotrauma
{
edgeLength ??= Vector2.Distance(location.Edge.Point1, location.Edge.Point2);
Vector2 edgeDir = (location.Edge.Point2 - location.Edge.Point1) / edgeLength.Value;
if (!MathUtils.IsValid(edgeDir))
{
edgeDir = Vector2.Zero;
}
var minResourceOverlap = -((edgeLength.Value - (resourceCount * resourcePrefab.Size.X)) / (resourceCount * resourcePrefab.Size.X));
minResourceOverlap = Math.Max(minResourceOverlap, 0.0f);
minResourceOverlap = Math.Clamp(minResourceOverlap, 0, maxResourceOverlap);
var lerpAmounts = new float[resourceCount];
lerpAmounts[0] = 0.0f;
var lerpAmount = 0.0f;
for (int i = 1; i < resourceCount; i++)
{
var overlap = Rand.Range(minResourceOverlap, maxResourceOverlap, sync: Rand.RandSync.ServerAndClient);
lerpAmount += ((1.0f - overlap) * resourcePrefab.Size.X) / edgeLength.Value;
lerpAmount += (1.0f - overlap) * resourcePrefab.Size.X / edgeLength.Value;
lerpAmounts[i] = Math.Clamp(lerpAmount, 0.0f, 1.0f);
}
var startOffset = Rand.Range(0.0f, 1.0f - lerpAmount, sync: Rand.RandSync.ServerAndClient);