v0.14.6.0

This commit is contained in:
Joonas Rikkonen
2021-06-17 17:54:52 +03:00
parent 3f324b14e8
commit c27e2ea5ab
348 changed files with 13156 additions and 4266 deletions
@@ -50,7 +50,7 @@ namespace Barotrauma
private float calculateDistanceTraveledTimer;
private float distanceTraveled;
private float avgCrewHealth, avgHullIntegrity, floodingAmount, fireAmount, enemyDanger;
private float avgCrewHealth, avgHullIntegrity, floodingAmount, fireAmount, enemyDanger, monsterTotalStrength;
private float roundDuration;
@@ -107,7 +107,7 @@ namespace Barotrauma
totalPathLength = 0.0f;
if (level != null)
{
var steeringPath = pathFinder.FindPath(ConvertUnits.ToSimUnits(Level.Loaded.StartPosition), ConvertUnits.ToSimUnits(Level.Loaded.EndPosition));
var steeringPath = pathFinder.FindPath(ConvertUnits.ToSimUnits(level.StartPosition), ConvertUnits.ToSimUnits(level.EndPosition));
totalPathLength = steeringPath.TotalLength;
}
@@ -124,7 +124,7 @@ namespace Barotrauma
}
MTRandom rand = new MTRandom(seed);
var initialEventSet = SelectRandomEvents(EventSet.List);
var initialEventSet = SelectRandomEvents(EventSet.List, rand);
if (initialEventSet != null)
{
pendingEventSets.Add(initialEventSet);
@@ -168,7 +168,7 @@ namespace Barotrauma
if (eventSet == null) { return; }
if (eventSet.OncePerOutpost)
{
foreach (EventPrefab ep in eventSet.EventPrefabs.Select(e => e.First))
foreach (EventPrefab ep in eventSet.EventPrefabs.Select(e => e.prefab))
{
if (!level.LevelData.NonRepeatableEvents.Contains(ep))
{
@@ -374,11 +374,11 @@ namespace Barotrauma
preloadedSprites.Clear();
}
private float CalculateCommonness(Pair<EventPrefab, float> eventPrefab)
private float CalculateCommonness(EventPrefab eventPrefab, float baseCommonness)
{
if (level.LevelData.NonRepeatableEvents.Contains(eventPrefab.First)) { return 0.0f; }
float retVal = eventPrefab.Second;
if (level.LevelData.EventHistory.Contains(eventPrefab.First)) { retVal *= 0.1f; }
if (level.LevelData.NonRepeatableEvents.Contains(eventPrefab)) { return 0.0f; }
float retVal = baseCommonness;
if (level.LevelData.EventHistory.Contains(eventPrefab)) { retVal *= 0.1f; }
return retVal;
}
@@ -386,21 +386,25 @@ namespace Barotrauma
{
if (level == null) { return; }
if (level.LevelData.HasHuntingGrounds && eventSet.DisableInHuntingGrounds) { return; }
#if DEBUG
DebugConsole.NewMessage($"Loading event set {eventSet.DebugIdentifier}", Color.LightBlue);
#else
DebugConsole.Log($"Loading event set {eventSet.DebugIdentifier}");
#endif
int applyCount = 1;
List<Func<Level.InterestingPosition, bool>> spawnPosFilter = new List<Func<Level.InterestingPosition, bool>>();
if (eventSet.PerRuin)
{
applyCount = Level.Loaded.Ruins.Count();
foreach (var ruin in Level.Loaded.Ruins)
applyCount = level.Ruins.Count();
foreach (var ruin in level.Ruins)
{
spawnPosFilter.Add((Level.InterestingPosition pos) => { return pos.Ruin == ruin; });
}
}
else if (eventSet.PerCave)
{
applyCount = Level.Loaded.Caves.Count();
foreach (var cave in Level.Loaded.Caves)
applyCount = level.Caves.Count();
foreach (var cave in level.Caves)
{
spawnPosFilter.Add((Level.InterestingPosition pos) => { return pos.Cave == cave; });
}
@@ -416,49 +420,62 @@ namespace Barotrauma
}
var suitablePrefabs = eventSet.EventPrefabs.FindAll(e =>
string.IsNullOrEmpty(e.First.BiomeIdentifier) ||
e.First.BiomeIdentifier.Equals(Level.Loaded.LevelData?.Biome?.Identifier, StringComparison.OrdinalIgnoreCase));
string.IsNullOrEmpty(e.prefab.BiomeIdentifier) ||
e.prefab.BiomeIdentifier.Equals(level.LevelData?.Biome?.Identifier, StringComparison.OrdinalIgnoreCase));
for (int i = 0; i < applyCount; i++)
{
if (eventSet.ChooseRandom)
{
if (suitablePrefabs.Count > 0)
{
List<Pair<EventPrefab, float>> unusedEvents = new List<Pair<EventPrefab, float>>(suitablePrefabs);
var unusedEvents = new List<(EventPrefab prefab, float commonness, float probability)>(suitablePrefabs);
for (int j = 0; j < eventSet.EventCount; j++)
{
if (unusedEvents.All(e => CalculateCommonness(e) <= 0.0f)) { break; }
var eventPrefab = ToolBox.SelectWeightedRandom(unusedEvents, unusedEvents.Select(e => CalculateCommonness(e)).ToList(), rand);
if (eventPrefab != null)
if (unusedEvents.All(e => CalculateCommonness(e.prefab, e.commonness) <= 0.0f)) { break; }
(EventPrefab eventPrefab, float commonness, float probability) = ToolBox.SelectWeightedRandom(unusedEvents, unusedEvents.Select(e => CalculateCommonness(e.prefab, e.commonness)).ToList(), rand);
if (eventPrefab != null && rand.NextDouble() <= probability)
{
var newEvent = eventPrefab.First.CreateInstance();
var newEvent = eventPrefab.CreateInstance();
if (newEvent == null) { continue; }
newEvent.Init(true);
if (i < spawnPosFilter.Count) { newEvent.SpawnPosFilter = spawnPosFilter[i]; }
DebugConsole.Log("Initialized event " + newEvent.ToString());
#if DEBUG
DebugConsole.NewMessage($"Initialized event {newEvent}");
#else
DebugConsole.Log($"Initialized event {newEvent}");
#endif
if (!selectedEvents.ContainsKey(eventSet))
{
selectedEvents.Add(eventSet, new List<Event>());
}
selectedEvents[eventSet].Add(newEvent);
unusedEvents.Remove(eventPrefab);
unusedEvents.Remove((eventPrefab, commonness, probability));
}
}
}
if (eventSet.ChildSets.Count > 0)
{
var newEventSet = SelectRandomEvents(eventSet.ChildSets);
if (newEventSet != null) { CreateEvents(newEventSet, rand); }
var newEventSet = SelectRandomEvents(eventSet.ChildSets, rand);
if (newEventSet != null)
{
CreateEvents(newEventSet, rand);
}
}
}
else
{
foreach (Pair<EventPrefab, float> eventPrefab in suitablePrefabs)
foreach ((EventPrefab eventPrefab, float commonness, float probability) in suitablePrefabs)
{
var newEvent = eventPrefab.First.CreateInstance();
if (rand.NextDouble() > probability) { continue; }
var newEvent = eventPrefab.CreateInstance();
if (newEvent == null) { continue; }
newEvent.Init(true);
DebugConsole.Log("Initialized event " + newEvent.ToString());
#if DEBUG
DebugConsole.NewMessage($"Initialized event {newEvent}");
#else
DebugConsole.Log($"Initialized event {newEvent}");
#endif
if (!selectedEvents.ContainsKey(eventSet))
{
selectedEvents.Add(eventSet, new List<Event>());
@@ -474,10 +491,10 @@ namespace Barotrauma
}
}
private EventSet SelectRandomEvents(List<EventSet> eventSets)
private EventSet SelectRandomEvents(List<EventSet> eventSets, Random random = null)
{
if (level == null) { return null; }
MTRandom rand = new MTRandom(ToolBox.StringToInt(level.Seed));
Random rand = random ?? new MTRandom(ToolBox.StringToInt(level.Seed));
var allowedEventSets =
eventSets.Where(es =>
@@ -496,7 +513,8 @@ namespace Barotrauma
}
float totalCommonness = allowedEventSets.Sum(e => e.GetCommonness(level));
float randomNumber = (float)rand.NextDouble() * totalCommonness;
float randomNumber = (float)rand.NextDouble();
randomNumber *= totalCommonness;
foreach (EventSet eventSet in allowedEventSets)
{
float commonness = eventSet.GetCommonness(level);
@@ -694,47 +712,103 @@ namespace Barotrauma
// enemy amount --------------------------------------------------------
enemyDanger = 0.0f;
monsterTotalStrength = 0;
foreach (Character character in Character.CharacterList)
{
if (character.IsDead || character.IsIncapacitated || !character.Enabled || character.IsPet || character.Params.CompareGroup("human")) { continue; }
if (character.IsIncapacitated || !character.Enabled || character.IsPet || character.Params.CompareGroup("human")) { continue; }
if (!(character.AIController is EnemyAIController enemyAI)) { continue; }
if (!enemyAI.AIParams.StayInAbyss)
{
// Ignore abyss monsters because they can stay active for quite great distances. They'll be taken into account when they target the sub.
monsterTotalStrength += enemyAI.CombatStrength;
}
// Example combat strengths:
// Hammerheadspawn 1
// Moloch Pupa 1
// Terminal cell 20
// Leucocyte 40
// Husk 90
// Crawler 100
// Unarmored Mudraptor 140
// Spineling 150
// Tigerthresher 200
// Armored Mudraptor 210
// Watcher 400
// Golden Hammerhead 400
// Hammerhead 500
// Hammerhead Matriarch 550
// Bonethresher 600
// Moloch 1250
// Black Moloch 1500
// Endworm 10000
if (character.CurrentHull?.Submarine != null &&
(character.CurrentHull.Submarine == Submarine.MainSub || Submarine.MainSub.DockedTo.Contains(character.CurrentHull.Submarine)))
{
//crawler inside the sub adds 0.1f to enemy danger, mantis 0.25f
enemyDanger += enemyAI.CombatStrength / 100.0f;
// Enemy onboard -> Crawler inside the sub adds 0.2 to enemy danger, Mudraptor 0.42
enemyDanger += enemyAI.CombatStrength / 500.0f;
}
else if (enemyAI.SelectedAiTarget?.Entity?.Submarine != null)
{
//enemy outside and targeting the sub or something in it
//moloch adds 0.24 to enemy danger, a crawler 0.02
enemyDanger += enemyAI.CombatStrength / 1000.0f;
// Enemy outside targeting the sub or something in it
// -> One Crawler adds 0.02, a Mudraptor 0.042, a Hammerhead 0.1, and a Moloch 0.25.
enemyDanger += enemyAI.CombatStrength / 5000.0f;
}
}
// Add a portion of the total strength of active monsters to the enemy danger so that we don't spawn too many monsters around the sub.
// On top of the existing value, so if 10 crawlers are targeting the sub simultaneously from outside, the final value would be: 0.02 x 10 + 0.2 = 0.4.
// And if they get inside, we add 0.1 per crawler on that.
// So, in practice the danger per enemy that is attacking the sub is half of what it would be when the enemy is not targeting the sub.
// 10 Crawlers -> +0.2 (0.4 in total if all target the sub from outside).
// 5 Mudraptors -> +0.21 (0.42 in total, before they get inside).
// 3 Hammerheads -> +0.3 (0.6 in total, if they all target the sub).
// 2 Molochs -> +0.5 (1.0 in total, if both target the sub).
enemyDanger += monsterTotalStrength / 5000f;
enemyDanger = MathHelper.Clamp(enemyDanger, 0.0f, 1.0f);
// The definitions above aim for that we never spawn more monsters that the player (and the performance) can handle.
// Some examples that result in the max intensity even when the creatures would just idle around.
// The values are theoretical, because in practice many of the monsters are targeting the sub, which will double the danger of those monster and effectively halve the max monster count.
// In practice we don't use the max intensity. For example on level 50 we use max intensity 50, which would mean that we'd halve the numbers below.
// There's no hard cap for the monster count, but if the amount of monsters is higher than this, we don't spawn more monsters from the events:
// 50 Crawlers (We shouldn't actually ever spawn that many. 12 is the max per event, but theoretically 25 crawlers would result in max intensity).
// 25 Tigerthreshers (Max 9 per event. 12 targeting the sub at the same time results in max intensity).
// 10 Hammerheads (Max 3 per event. 5 targeting the sub at the same time results in max intensity).
// 4 Molochs (Max 2 per event and 2 targeting the sub at the same time results in max intensity).
// hull status (gaps, flooding, fire) --------------------------------------------------------
float holeCount = 0.0f;
float waterAmount = 0.0f;
float totalHullVolume = 0.0f;
float dryHullVolume = 0.0f;
foreach (Hull hull in Hull.hullList)
{
if (hull.Submarine == null || hull.Submarine.Info.Type != SubmarineType.Player) { continue; }
if (hull.RoomName != null && hull.RoomName.Contains("ballast", StringComparison.OrdinalIgnoreCase)) { continue; }
if (hull.Submarine == null || hull.Submarine.Info.Type != SubmarineType.Player) { continue; }
if (GameMain.GameSession?.GameMode is PvPMode)
{
if (hull.Submarine.TeamID != CharacterTeamType.Team1 && hull.Submarine.TeamID != CharacterTeamType.Team2) { continue; }
}
else
{
if (hull.Submarine.TeamID != CharacterTeamType.Team1) { continue; }
}
fireAmount += hull.FireSources.Sum(fs => fs.Size.X);
if (hull.IsWetRoom) { continue; }
foreach (Gap gap in hull.ConnectedGaps)
{
if (!gap.IsRoomToRoom) holeCount += gap.Open;
if (!gap.IsRoomToRoom)
{
holeCount += gap.Open;
}
}
waterAmount += hull.WaterVolume;
totalHullVolume += hull.Volume;
fireAmount += hull.FireSources.Sum(fs => fs.Size.X);
dryHullVolume += hull.Volume;
}
if (totalHullVolume > 0)
if (dryHullVolume > 0)
{
floodingAmount = waterAmount / totalHullVolume;
floodingAmount = waterAmount / dryHullVolume;
}
//hull integrity at 0.0 if there are 10 or more wide-open holes
@@ -779,7 +853,7 @@ namespace Barotrauma
{
if (level == null) { return 0.0f; }
var refEntity = GetRefEntity();
Vector2 target = ConvertUnits.ToSimUnits(Level.Loaded.EndPosition);
Vector2 target = ConvertUnits.ToSimUnits(level.EndPosition);
var steeringPath = pathFinder.FindPath(ConvertUnits.ToSimUnits(refEntity.WorldPosition), target);
if (steeringPath.Unreachable || float.IsPositiveInfinity(totalPathLength))
{
@@ -897,15 +971,15 @@ namespace Barotrauma
const int maxDist = 1000;
if (Level.Loaded != null)
if (level != null)
{
foreach (var ruin in Level.Loaded.Ruins)
foreach (var ruin in level.Ruins)
{
Rectangle area = ruin.Area;
area.Inflate(maxDist, maxDist);
if (area.Contains(character.WorldPosition)) { return true; }
}
foreach (var cave in Level.Loaded.Caves)
foreach (var cave in level.Caves)
{
Rectangle area = cave.Area;
area.Inflate(maxDist, maxDist);