v0.11.0.9
This commit is contained in:
@@ -37,18 +37,23 @@ namespace Barotrauma
|
||||
|
||||
public bool NeedsNetworkSyncing
|
||||
{
|
||||
get { return Triggers.Any(t => t.NeedsNetworkSyncing); }
|
||||
set { Triggers.ForEach(t => t.NeedsNetworkSyncing = false); }
|
||||
get { return Triggers != null && Triggers.Any(t => t.NeedsNetworkSyncing); }
|
||||
set
|
||||
{
|
||||
if (Triggers == null) { return; }
|
||||
Triggers.ForEach(t => t.NeedsNetworkSyncing = false);
|
||||
}
|
||||
}
|
||||
|
||||
public bool NeedsUpdate
|
||||
{
|
||||
get; private set;
|
||||
}
|
||||
|
||||
public Sprite Sprite
|
||||
{
|
||||
get { return spriteIndex < 0 || Prefab.Sprites.Count == 0 ? null : Prefab.Sprites[spriteIndex % Prefab.Sprites.Count]; }
|
||||
}
|
||||
public Sprite SpecularSprite
|
||||
{
|
||||
get { return spriteIndex < 0 || Prefab.SpecularSprites.Count == 0 ? null : Prefab.SpecularSprites[spriteIndex % Prefab.SpecularSprites.Count]; }
|
||||
}
|
||||
|
||||
Vector2 ISpatialEntity.Position => new Vector2(Position.X, Position.Y);
|
||||
|
||||
@@ -60,8 +65,6 @@ namespace Barotrauma
|
||||
|
||||
public LevelObject(LevelObjectPrefab prefab, Vector3 position, float scale, float rotation = 0.0f)
|
||||
{
|
||||
Triggers = new List<LevelTrigger>();
|
||||
|
||||
ActivePrefab = Prefab = prefab;
|
||||
Position = position;
|
||||
Scale = scale;
|
||||
@@ -69,13 +72,26 @@ namespace Barotrauma
|
||||
|
||||
spriteIndex = ActivePrefab.Sprites.Any() ? Rand.Int(ActivePrefab.Sprites.Count, Rand.RandSync.Server) : -1;
|
||||
|
||||
if (prefab.PhysicsBodyElement != null)
|
||||
if (Sprite != null && prefab.SpriteSpecificPhysicsBodyElements.ContainsKey(Sprite))
|
||||
{
|
||||
PhysicsBody = new PhysicsBody(prefab.SpriteSpecificPhysicsBodyElements[Sprite], ConvertUnits.ToSimUnits(new Vector2(position.X, position.Y)), Scale);
|
||||
}
|
||||
else if (prefab.PhysicsBodyElement != null)
|
||||
{
|
||||
PhysicsBody = new PhysicsBody(prefab.PhysicsBodyElement, ConvertUnits.ToSimUnits(new Vector2(position.X, position.Y)), Scale);
|
||||
}
|
||||
|
||||
if (PhysicsBody != null)
|
||||
{
|
||||
PhysicsBody.SetTransformIgnoreContacts(PhysicsBody.SimPosition, -Rotation);
|
||||
PhysicsBody.BodyType = BodyType.Static;
|
||||
PhysicsBody.CollisionCategories = Physics.CollisionLevel;
|
||||
PhysicsBody.CollidesWith = Physics.CollisionWall | Physics.CollisionCharacter;
|
||||
}
|
||||
|
||||
foreach (XElement triggerElement in prefab.LevelTriggerElements)
|
||||
{
|
||||
Triggers ??= new List<LevelTrigger>();
|
||||
Vector2 triggerPosition = triggerElement.GetAttributeVector2("position", Vector2.Zero) * scale;
|
||||
|
||||
if (rotation != 0.0f)
|
||||
@@ -90,10 +106,12 @@ namespace Barotrauma
|
||||
|
||||
var newTrigger = new LevelTrigger(triggerElement, new Vector2(position.X, position.Y) + triggerPosition, -rotation, scale, prefab.Name);
|
||||
int parentTriggerIndex = prefab.LevelTriggerElements.IndexOf(triggerElement.Parent);
|
||||
if (parentTriggerIndex > -1) newTrigger.ParentTrigger = Triggers[parentTriggerIndex];
|
||||
if (parentTriggerIndex > -1) { newTrigger.ParentTrigger = Triggers[parentTriggerIndex]; }
|
||||
Triggers.Add(newTrigger);
|
||||
}
|
||||
|
||||
NeedsUpdate = NeedsNetworkSyncing || (Triggers != null && Triggers.Any()) || Prefab.PhysicsBodyTriggerIndex > -1;
|
||||
|
||||
InitProjSpecific();
|
||||
}
|
||||
|
||||
@@ -131,9 +149,10 @@ namespace Barotrauma
|
||||
|
||||
public void ServerWrite(IWriteMessage msg, Client c)
|
||||
{
|
||||
if (Triggers == null) { return; }
|
||||
for (int j = 0; j < Triggers.Count; j++)
|
||||
{
|
||||
if (!Triggers[j].UseNetworkSyncing) continue;
|
||||
if (!Triggers[j].UseNetworkSyncing) { continue; }
|
||||
Triggers[j].ServerWrite(msg, c);
|
||||
}
|
||||
}
|
||||
|
||||
+191
-93
@@ -9,6 +9,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
using Voronoi2;
|
||||
using Barotrauma.Extensions;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
@@ -17,9 +18,10 @@ namespace Barotrauma
|
||||
const int GridSize = 2000;
|
||||
|
||||
private List<LevelObject> objects;
|
||||
private List<LevelObject> updateableObjects;
|
||||
private List<LevelObject>[,] objectGrid;
|
||||
|
||||
public LevelObjectManager() : base(null)
|
||||
public LevelObjectManager() : base(null, Entity.NullEntityID)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -27,20 +29,36 @@ namespace Barotrauma
|
||||
{
|
||||
public readonly GraphEdge GraphEdge;
|
||||
public readonly Vector2 Normal;
|
||||
public readonly LevelObjectPrefab.SpawnPosType SpawnPosType;
|
||||
public readonly List<LevelObjectPrefab.SpawnPosType> SpawnPosTypes = new List<LevelObjectPrefab.SpawnPosType>();
|
||||
public readonly Alignment Alignment;
|
||||
public readonly float Length;
|
||||
|
||||
private readonly float noiseVal;
|
||||
|
||||
|
||||
public SpawnPosition(GraphEdge graphEdge, Vector2 normal, LevelObjectPrefab.SpawnPosType spawnPosType, Alignment alignment)
|
||||
: this(graphEdge, normal, spawnPosType.ToEnumerable(), alignment)
|
||||
{ }
|
||||
|
||||
public SpawnPosition(GraphEdge graphEdge, Vector2 normal, IEnumerable<LevelObjectPrefab.SpawnPosType> spawnPosTypes, Alignment alignment)
|
||||
{
|
||||
GraphEdge = graphEdge;
|
||||
Normal = normal;
|
||||
SpawnPosType = spawnPosType;
|
||||
Alignment = alignment;
|
||||
|
||||
Length = Vector2.Distance(graphEdge.Point1, graphEdge.Point2);
|
||||
Normal = normal.NearlyEquals(Vector2.Zero) ? Vector2.UnitY : Vector2.Normalize(normal);
|
||||
SpawnPosTypes.AddRange(spawnPosTypes);
|
||||
|
||||
if (spawnPosTypes.Contains(LevelObjectPrefab.SpawnPosType.MainPath) ||
|
||||
spawnPosTypes.Contains(LevelObjectPrefab.SpawnPosType.LevelStart) ||
|
||||
spawnPosTypes.Contains(LevelObjectPrefab.SpawnPosType.LevelEnd))
|
||||
{
|
||||
Length = 1000.0f;
|
||||
Normal = Vector2.Zero;
|
||||
Alignment = Alignment.Any;
|
||||
}
|
||||
else
|
||||
{
|
||||
Alignment = alignment;
|
||||
Length = Vector2.Distance(graphEdge.Point1, graphEdge.Point2);
|
||||
}
|
||||
|
||||
noiseVal =
|
||||
(float)(PerlinNoise.CalculatePerlin(GraphEdge.Point1.X / 10000.0f, GraphEdge.Point1.Y / 10000.0f, 0.5f) +
|
||||
@@ -83,7 +101,7 @@ namespace Barotrauma
|
||||
|
||||
foreach (var posOfInterest in level.PositionsOfInterest)
|
||||
{
|
||||
if (posOfInterest.PositionType != Level.PositionType.MainPath) continue;
|
||||
if (posOfInterest.PositionType != Level.PositionType.MainPath && posOfInterest.PositionType != Level.PositionType.SidePath) { continue; }
|
||||
|
||||
availableSpawnPositions.Add(new SpawnPosition(
|
||||
new GraphEdge(posOfInterest.Position.ToVector2(), posOfInterest.Position.ToVector2() + Vector2.UnitX),
|
||||
@@ -101,49 +119,29 @@ namespace Barotrauma
|
||||
|
||||
var availablePrefabs = new List<LevelObjectPrefab>(LevelObjectPrefab.List);
|
||||
objects = new List<LevelObject>();
|
||||
updateableObjects = new List<LevelObject>();
|
||||
|
||||
Dictionary<LevelObjectPrefab, List<SpawnPosition>> suitableSpawnPositions = new Dictionary<LevelObjectPrefab, List<SpawnPosition>>();
|
||||
Dictionary<LevelObjectPrefab, List<float>> spawnPositionWeights = new Dictionary<LevelObjectPrefab, List<float>>();
|
||||
for (int i = 0; i < amount; i++)
|
||||
{
|
||||
//get a random prefab and find a place to spawn it
|
||||
LevelObjectPrefab prefab = GetRandomPrefab(level.GenerationParams.Identifier, availablePrefabs);
|
||||
LevelObjectPrefab prefab = GetRandomPrefab(level.GenerationParams, availablePrefabs);
|
||||
if (prefab == null) { continue; }
|
||||
if (!suitableSpawnPositions.ContainsKey(prefab))
|
||||
{
|
||||
suitableSpawnPositions.Add(prefab, availableSpawnPositions.Where(sp =>
|
||||
prefab.SpawnPos.HasFlag(sp.SpawnPosType) && (sp.Length >= prefab.MinSurfaceWidth && prefab.Alignment.HasFlag(sp.Alignment) || sp.SpawnPosType == LevelObjectPrefab.SpawnPosType.LevelEnd || sp.SpawnPosType == LevelObjectPrefab.SpawnPosType.LevelStart)).ToList());
|
||||
suitableSpawnPositions.Add(prefab,
|
||||
availableSpawnPositions.Where(sp =>
|
||||
sp.SpawnPosTypes.Any(type => prefab.SpawnPos.HasFlag(type)) &&
|
||||
sp.Length >= prefab.MinSurfaceWidth &&
|
||||
(sp.Alignment == Alignment.Any || prefab.Alignment.HasFlag(sp.Alignment))).ToList());
|
||||
spawnPositionWeights.Add(prefab,
|
||||
suitableSpawnPositions[prefab].Select(sp => sp.GetSpawnProbability(prefab)).ToList());
|
||||
}
|
||||
|
||||
SpawnPosition spawnPosition = ToolBox.SelectWeightedRandom(suitableSpawnPositions[prefab], spawnPositionWeights[prefab], Rand.RandSync.Server);
|
||||
if (spawnPosition == null && prefab.SpawnPos != LevelObjectPrefab.SpawnPosType.None) { continue; }
|
||||
|
||||
float rotation = 0.0f;
|
||||
if (prefab.AlignWithSurface && spawnPosition != null)
|
||||
{
|
||||
rotation = MathUtils.VectorToAngle(new Vector2(spawnPosition.Normal.Y, spawnPosition.Normal.X));
|
||||
}
|
||||
rotation += Rand.Range(prefab.RandomRotationRad.X, prefab.RandomRotationRad.Y, Rand.RandSync.Server);
|
||||
|
||||
Vector2 position = Vector2.Zero;
|
||||
Vector2 edgeDir = Vector2.UnitX;
|
||||
if (spawnPosition == null)
|
||||
{
|
||||
position = new Vector2(
|
||||
Rand.Range(0.0f, level.Size.X, Rand.RandSync.Server),
|
||||
Rand.Range(0.0f, level.Size.Y, Rand.RandSync.Server));
|
||||
}
|
||||
else
|
||||
{
|
||||
edgeDir = (spawnPosition.GraphEdge.Point1 - spawnPosition.GraphEdge.Point2) / spawnPosition.Length;
|
||||
position = spawnPosition.GraphEdge.Point2 + edgeDir * Rand.Range(prefab.MinSurfaceWidth / 2.0f, spawnPosition.Length - prefab.MinSurfaceWidth / 2.0f, Rand.RandSync.Server);
|
||||
}
|
||||
|
||||
var newObject = new LevelObject(prefab,
|
||||
new Vector3(position, Rand.Range(prefab.DepthRange.X, prefab.DepthRange.Y, Rand.RandSync.Server)), Rand.Range(prefab.MinSize, prefab.MaxSize, Rand.RandSync.Server), rotation);
|
||||
AddObject(newObject, level);
|
||||
PlaceObject(prefab, spawnPosition, level);
|
||||
if (prefab.MaxCount < amount)
|
||||
{
|
||||
if (objects.Count(o => o.Prefab == prefab) >= prefab.MaxCount)
|
||||
@@ -151,38 +149,119 @@ namespace Barotrauma
|
||||
availablePrefabs.Remove(prefab);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (LevelObjectPrefab.ChildObject child in prefab.ChildObjects)
|
||||
foreach (Level.Cave cave in level.Caves)
|
||||
{
|
||||
availablePrefabs = new List<LevelObjectPrefab>(LevelObjectPrefab.List.FindAll(p => p.SpawnPos.HasFlag(LevelObjectPrefab.SpawnPosType.CaveWall)));
|
||||
availableSpawnPositions.Clear();
|
||||
suitableSpawnPositions.Clear();
|
||||
spawnPositionWeights.Clear();
|
||||
|
||||
var caveCells = cave.Tunnels.SelectMany(t => t.Cells);
|
||||
List<VoronoiCell> caveWallCells = new List<VoronoiCell>();
|
||||
foreach (var edge in caveCells.SelectMany(c => c.Edges))
|
||||
{
|
||||
int childCount = Rand.Range(child.MinCount, child.MaxCount, Rand.RandSync.Server);
|
||||
for (int j = 0; j < childCount; j++)
|
||||
{
|
||||
var matchingPrefabs = LevelObjectPrefab.List.Where(p => child.AllowedNames.Contains(p.Name));
|
||||
int prefabCount = matchingPrefabs.Count();
|
||||
var childPrefab = prefabCount == 0 ? null : matchingPrefabs.ElementAt(Rand.Range(0, prefabCount, Rand.RandSync.Server));
|
||||
if (childPrefab == null) continue;
|
||||
|
||||
Vector2 childPos = position + edgeDir * Rand.Range(-0.5f, 0.5f, Rand.RandSync.Server) * prefab.MinSurfaceWidth;
|
||||
|
||||
var childObject = new LevelObject(childPrefab,
|
||||
new Vector3(childPos, Rand.Range(childPrefab.DepthRange.X, childPrefab.DepthRange.Y, Rand.RandSync.Server)),
|
||||
Rand.Range(childPrefab.MinSize, childPrefab.MaxSize, Rand.RandSync.Server),
|
||||
rotation + Rand.Range(childPrefab.RandomRotationRad.X, childPrefab.RandomRotationRad.Y, Rand.RandSync.Server));
|
||||
|
||||
AddObject(childObject, level);
|
||||
}
|
||||
if (!edge.NextToCave) { continue; }
|
||||
if (edge.Cell1?.CellType == CellType.Solid) { caveWallCells.Add(edge.Cell1); }
|
||||
if (edge.Cell2?.CellType == CellType.Solid) { caveWallCells.Add(edge.Cell2); }
|
||||
}
|
||||
}
|
||||
availableSpawnPositions.AddRange(GetAvailableSpawnPositions(caveWallCells.Distinct(), LevelObjectPrefab.SpawnPosType.CaveWall));
|
||||
|
||||
for (int i = 0; i < cave.CaveGenerationParams.LevelObjectAmount; i++)
|
||||
{
|
||||
//get a random prefab and find a place to spawn it
|
||||
LevelObjectPrefab prefab = GetRandomPrefab(cave.CaveGenerationParams, availablePrefabs);
|
||||
if (prefab == null) { continue; }
|
||||
if (!suitableSpawnPositions.ContainsKey(prefab))
|
||||
{
|
||||
suitableSpawnPositions.Add(prefab,
|
||||
availableSpawnPositions.Where(sp =>
|
||||
sp.Length >= prefab.MinSurfaceWidth &&
|
||||
(sp.Alignment == Alignment.Any || prefab.Alignment.HasFlag(sp.Alignment))).ToList());
|
||||
spawnPositionWeights.Add(prefab,
|
||||
suitableSpawnPositions[prefab].Select(sp => sp.GetSpawnProbability(prefab)).ToList());
|
||||
}
|
||||
SpawnPosition spawnPosition = ToolBox.SelectWeightedRandom(suitableSpawnPositions[prefab], spawnPositionWeights[prefab], Rand.RandSync.Server);
|
||||
if (spawnPosition == null && prefab.SpawnPos != LevelObjectPrefab.SpawnPosType.None) { continue; }
|
||||
PlaceObject(prefab, spawnPosition, level);
|
||||
if (prefab.MaxCount < amount)
|
||||
{
|
||||
if (objects.Count(o => o.Prefab == prefab) >= prefab.MaxCount)
|
||||
{
|
||||
availablePrefabs.Remove(prefab);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void PlaceObject(LevelObjectPrefab prefab, SpawnPosition spawnPosition, Level level)
|
||||
{
|
||||
float rotation = 0.0f;
|
||||
if (prefab.AlignWithSurface && spawnPosition.Normal.LengthSquared() > 0.001f && spawnPosition != null)
|
||||
{
|
||||
rotation = MathUtils.VectorToAngle(new Vector2(spawnPosition.Normal.Y, spawnPosition.Normal.X));
|
||||
}
|
||||
rotation += Rand.Range(prefab.RandomRotationRad.X, prefab.RandomRotationRad.Y, Rand.RandSync.Server);
|
||||
|
||||
Vector2 position = Vector2.Zero;
|
||||
Vector2 edgeDir = Vector2.UnitX;
|
||||
if (spawnPosition == null)
|
||||
{
|
||||
position = new Vector2(
|
||||
Rand.Range(0.0f, level.Size.X, Rand.RandSync.Server),
|
||||
Rand.Range(0.0f, level.Size.Y, Rand.RandSync.Server));
|
||||
}
|
||||
else
|
||||
{
|
||||
edgeDir = (spawnPosition.GraphEdge.Point1 - spawnPosition.GraphEdge.Point2) / spawnPosition.Length;
|
||||
position = spawnPosition.GraphEdge.Point2 + edgeDir * Rand.Range(prefab.MinSurfaceWidth / 2.0f, spawnPosition.Length - prefab.MinSurfaceWidth / 2.0f, Rand.RandSync.Server);
|
||||
}
|
||||
|
||||
if (!MathUtils.NearlyEqual(prefab.RandomOffset.X, 0.0f) || !MathUtils.NearlyEqual(prefab.RandomOffset.Y, 0.0f))
|
||||
{
|
||||
Vector2 offsetDir = spawnPosition.Normal.LengthSquared() > 0.001f ? spawnPosition.Normal : Rand.Vector(1.0f, Rand.RandSync.Server);
|
||||
position += offsetDir * Rand.Range(prefab.RandomOffset.X, prefab.RandomOffset.Y, Rand.RandSync.Server);
|
||||
}
|
||||
|
||||
var newObject = new LevelObject(prefab,
|
||||
new Vector3(position, Rand.Range(prefab.DepthRange.X, prefab.DepthRange.Y, Rand.RandSync.Server)), Rand.Range(prefab.MinSize, prefab.MaxSize, Rand.RandSync.Server), rotation);
|
||||
AddObject(newObject, level);
|
||||
|
||||
foreach (LevelObjectPrefab.ChildObject child in prefab.ChildObjects)
|
||||
{
|
||||
int childCount = Rand.Range(child.MinCount, child.MaxCount, Rand.RandSync.Server);
|
||||
for (int j = 0; j < childCount; j++)
|
||||
{
|
||||
var matchingPrefabs = LevelObjectPrefab.List.Where(p => child.AllowedNames.Contains(p.Name));
|
||||
int prefabCount = matchingPrefabs.Count();
|
||||
var childPrefab = prefabCount == 0 ? null : matchingPrefabs.ElementAt(Rand.Range(0, prefabCount, Rand.RandSync.Server));
|
||||
if (childPrefab == null) continue;
|
||||
|
||||
Vector2 childPos = position + edgeDir * Rand.Range(-0.5f, 0.5f, Rand.RandSync.Server) * prefab.MinSurfaceWidth;
|
||||
|
||||
var childObject = new LevelObject(childPrefab,
|
||||
new Vector3(childPos, Rand.Range(childPrefab.DepthRange.X, childPrefab.DepthRange.Y, Rand.RandSync.Server)),
|
||||
Rand.Range(childPrefab.MinSize, childPrefab.MaxSize, Rand.RandSync.Server),
|
||||
rotation + Rand.Range(childPrefab.RandomRotationRad.X, childPrefab.RandomRotationRad.Y, Rand.RandSync.Server));
|
||||
|
||||
AddObject(childObject, level);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void AddObject(LevelObject newObject, Level level)
|
||||
{
|
||||
foreach (LevelTrigger trigger in newObject.Triggers)
|
||||
{
|
||||
trigger.OnTriggered += (levelTrigger, obj) =>
|
||||
if (newObject.Triggers != null)
|
||||
{
|
||||
foreach (LevelTrigger trigger in newObject.Triggers)
|
||||
{
|
||||
OnObjectTriggered(newObject, levelTrigger, obj);
|
||||
};
|
||||
trigger.OnTriggered += (levelTrigger, obj) =>
|
||||
{
|
||||
OnObjectTriggered(newObject, levelTrigger, obj);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
var spriteCorners = new List<Vector2>
|
||||
@@ -223,22 +302,24 @@ namespace Barotrauma
|
||||
float minY = spriteCorners.Min(c => c.Y) - newObject.Position.Z - level.BottomPos;
|
||||
float maxY = spriteCorners.Max(c => c.Y) + newObject.Position.Z - level.BottomPos;
|
||||
|
||||
foreach (LevelTrigger trigger in newObject.Triggers)
|
||||
if (newObject.Triggers != null)
|
||||
{
|
||||
if (trigger.PhysicsBody == null) continue;
|
||||
for (int i = 0; i < trigger.PhysicsBody.FarseerBody.FixtureList.Count; i++)
|
||||
foreach (LevelTrigger trigger in newObject.Triggers)
|
||||
{
|
||||
trigger.PhysicsBody.FarseerBody.GetTransform(out FarseerPhysics.Common.Transform transform);
|
||||
trigger.PhysicsBody.FarseerBody.FixtureList[i].Shape.ComputeAABB(out FarseerPhysics.Collision.AABB aabb, ref transform, i);
|
||||
if (trigger.PhysicsBody == null) { continue; }
|
||||
for (int i = 0; i < trigger.PhysicsBody.FarseerBody.FixtureList.Count; i++)
|
||||
{
|
||||
trigger.PhysicsBody.FarseerBody.GetTransform(out FarseerPhysics.Common.Transform transform);
|
||||
trigger.PhysicsBody.FarseerBody.FixtureList[i].Shape.ComputeAABB(out FarseerPhysics.Collision.AABB aabb, ref transform, i);
|
||||
|
||||
minX = Math.Min(minX, ConvertUnits.ToDisplayUnits(aabb.LowerBound.X));
|
||||
maxX = Math.Max(maxX, ConvertUnits.ToDisplayUnits(aabb.UpperBound.X));
|
||||
minY = Math.Min(minY, ConvertUnits.ToDisplayUnits(aabb.LowerBound.Y) - level.BottomPos);
|
||||
maxY = Math.Max(maxY, ConvertUnits.ToDisplayUnits(aabb.UpperBound.Y) - level.BottomPos);
|
||||
minX = Math.Min(minX, ConvertUnits.ToDisplayUnits(aabb.LowerBound.X));
|
||||
maxX = Math.Max(maxX, ConvertUnits.ToDisplayUnits(aabb.UpperBound.X));
|
||||
minY = Math.Min(minY, ConvertUnits.ToDisplayUnits(aabb.LowerBound.Y) - level.BottomPos);
|
||||
maxY = Math.Max(maxY, ConvertUnits.ToDisplayUnits(aabb.UpperBound.Y) - level.BottomPos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#if CLIENT
|
||||
if (newObject.ParticleEmitters != null)
|
||||
{
|
||||
@@ -253,6 +334,7 @@ namespace Barotrauma
|
||||
}
|
||||
#endif
|
||||
objects.Add(newObject);
|
||||
if (newObject.NeedsUpdate) { updateableObjects.Add(newObject); }
|
||||
newObject.Position.Z += (minX + minY) % 100.0f * 0.00001f;
|
||||
|
||||
int xStart = (int)Math.Floor(minX / GridSize);
|
||||
@@ -290,7 +372,7 @@ namespace Barotrauma
|
||||
return objects;
|
||||
}
|
||||
|
||||
private readonly static List<LevelObject> objectsInRange = new List<LevelObject>();
|
||||
private readonly static HashSet<LevelObject> objectsInRange = new HashSet<LevelObject>();
|
||||
public IEnumerable<LevelObject> GetAllObjects(Vector2 worldPosition, float radius)
|
||||
{
|
||||
var minIndices = GetGridIndices(worldPosition - Vector2.One * radius);
|
||||
@@ -309,10 +391,10 @@ namespace Barotrauma
|
||||
{
|
||||
for (int y = minIndices.Y; y <= maxIndices.Y; y++)
|
||||
{
|
||||
if (objectGrid[x, y] == null) continue;
|
||||
if (objectGrid[x, y] == null) { continue; }
|
||||
foreach (LevelObject obj in objectGrid[x, y])
|
||||
{
|
||||
if (!objectsInRange.Contains(obj)) objectsInRange.Add(obj);
|
||||
objectsInRange.Add(obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -322,12 +404,14 @@ namespace Barotrauma
|
||||
|
||||
private List<SpawnPosition> GetAvailableSpawnPositions(IEnumerable<VoronoiCell> cells, LevelObjectPrefab.SpawnPosType spawnPosType)
|
||||
{
|
||||
List<LevelObjectPrefab.SpawnPosType> spawnPosTypes = new List<LevelObjectPrefab.SpawnPosType>(4);
|
||||
List<SpawnPosition> availableSpawnPositions = new List<SpawnPosition>();
|
||||
foreach (var cell in cells)
|
||||
{
|
||||
foreach (var edge in cell.Edges)
|
||||
{
|
||||
if (!edge.IsSolid || edge.OutsideLevel) continue;
|
||||
if (!edge.IsSolid || edge.OutsideLevel) { continue; }
|
||||
if (spawnPosType != LevelObjectPrefab.SpawnPosType.CaveWall && edge.NextToCave) { continue; }
|
||||
Vector2 normal = edge.GetNormal(cell);
|
||||
|
||||
Alignment edgeAlignment = 0;
|
||||
@@ -340,7 +424,13 @@ namespace Barotrauma
|
||||
else if(normal.X > 0.5f)
|
||||
edgeAlignment |= Alignment.Right;
|
||||
|
||||
availableSpawnPositions.Add(new SpawnPosition(edge, normal, spawnPosType, edgeAlignment));
|
||||
spawnPosTypes.Clear();
|
||||
spawnPosTypes.Add(spawnPosType);
|
||||
if (spawnPosType.HasFlag(LevelObjectPrefab.SpawnPosType.MainPathWall) && edge.NextToMainPath) { spawnPosTypes.Add(LevelObjectPrefab.SpawnPosType.MainPathWall); }
|
||||
if (spawnPosType.HasFlag(LevelObjectPrefab.SpawnPosType.SidePathWall) && edge.NextToSidePath) { spawnPosTypes.Add(LevelObjectPrefab.SpawnPosType.SidePathWall); }
|
||||
if (spawnPosType.HasFlag(LevelObjectPrefab.SpawnPosType.CaveWall) && edge.NextToCave) { spawnPosTypes.Add(LevelObjectPrefab.SpawnPosType.CaveWall); }
|
||||
|
||||
availableSpawnPositions.Add(new SpawnPosition(edge, normal, spawnPosTypes, edgeAlignment));
|
||||
}
|
||||
}
|
||||
return availableSpawnPositions;
|
||||
@@ -348,7 +438,7 @@ namespace Barotrauma
|
||||
|
||||
public void Update(float deltaTime)
|
||||
{
|
||||
foreach (LevelObject obj in objects)
|
||||
foreach (LevelObject obj in updateableObjects)
|
||||
{
|
||||
if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsServer)
|
||||
{
|
||||
@@ -361,21 +451,24 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
obj.ActivePrefab = obj.Prefab;
|
||||
for (int i = 0; i < obj.Triggers.Count; i++)
|
||||
if (obj.Triggers != null)
|
||||
{
|
||||
obj.Triggers[i].Update(deltaTime);
|
||||
if (obj.Triggers[i].IsTriggered && obj.Prefab.OverrideProperties[i] != null)
|
||||
obj.ActivePrefab = obj.Prefab;
|
||||
for (int i = 0; i < obj.Triggers.Count; i++)
|
||||
{
|
||||
obj.ActivePrefab = obj.Prefab.OverrideProperties[i];
|
||||
obj.Triggers[i].Update(deltaTime);
|
||||
if (obj.Triggers[i].IsTriggered && obj.Prefab.OverrideProperties[i] != null)
|
||||
{
|
||||
obj.ActivePrefab = obj.Prefab.OverrideProperties[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (obj.PhysicsBody != null)
|
||||
{
|
||||
if (obj.Prefab.PhysicsBodyTriggerIndex > -1) obj.PhysicsBody.Enabled = obj.Triggers[obj.Prefab.PhysicsBodyTriggerIndex].IsTriggered;
|
||||
obj.Position = new Vector3(obj.PhysicsBody.Position, obj.Position.Z);
|
||||
obj.Rotation = obj.PhysicsBody.Rotation;
|
||||
if (obj.Prefab.PhysicsBodyTriggerIndex > -1) { obj.PhysicsBody.Enabled = obj.Triggers[obj.Prefab.PhysicsBodyTriggerIndex].IsTriggered; }
|
||||
/*obj.Position = new Vector3(obj.PhysicsBody.Position, obj.Position.Z);
|
||||
obj.Rotation = -obj.PhysicsBody.Rotation;*/
|
||||
}
|
||||
}
|
||||
|
||||
@@ -386,10 +479,10 @@ namespace Barotrauma
|
||||
|
||||
private void OnObjectTriggered(LevelObject triggeredObject, LevelTrigger trigger, Entity triggerer)
|
||||
{
|
||||
if (trigger.TriggerOthersDistance <= 0.0f) return;
|
||||
if (trigger.TriggerOthersDistance <= 0.0f) { return; }
|
||||
foreach (LevelObject obj in objects)
|
||||
{
|
||||
if (obj == triggeredObject) continue;
|
||||
if (obj == triggeredObject || obj.Triggers == null) { continue; }
|
||||
foreach (LevelTrigger otherTrigger in obj.Triggers)
|
||||
{
|
||||
otherTrigger.OtherTriggered(triggeredObject, trigger);
|
||||
@@ -397,16 +490,20 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
private LevelObjectPrefab GetRandomPrefab(string levelType)
|
||||
{
|
||||
return GetRandomPrefab(levelType, LevelObjectPrefab.List);
|
||||
}
|
||||
|
||||
private LevelObjectPrefab GetRandomPrefab(string levelType, IList<LevelObjectPrefab> availablePrefabs)
|
||||
private LevelObjectPrefab GetRandomPrefab(LevelGenerationParams generationParams, IList<LevelObjectPrefab> availablePrefabs)
|
||||
{
|
||||
if (availablePrefabs.Sum(p => p.GetCommonness(generationParams)) <= 0.0f) { return null; }
|
||||
return ToolBox.SelectWeightedRandom(
|
||||
availablePrefabs,
|
||||
availablePrefabs.Select(p => p.GetCommonness(levelType)).ToList(), Rand.RandSync.Server);
|
||||
availablePrefabs.Select(p => p.GetCommonness(generationParams)).ToList(), Rand.RandSync.Server);
|
||||
}
|
||||
|
||||
private LevelObjectPrefab GetRandomPrefab(CaveGenerationParams caveParams, IList<LevelObjectPrefab> availablePrefabs)
|
||||
{
|
||||
if (availablePrefabs.Sum(p => p.GetCommonness(caveParams)) <= 0.0f) { return null; }
|
||||
return ToolBox.SelectWeightedRandom(
|
||||
availablePrefabs,
|
||||
availablePrefabs.Select(p => p.GetCommonness(caveParams)).ToList(), Rand.RandSync.Server);
|
||||
}
|
||||
|
||||
public override void Remove()
|
||||
@@ -418,6 +515,7 @@ namespace Barotrauma
|
||||
obj.Remove();
|
||||
}
|
||||
objects.Clear();
|
||||
updateableObjects.Clear();
|
||||
}
|
||||
RemoveProjSpecific();
|
||||
|
||||
|
||||
+98
-39
@@ -8,11 +8,7 @@ namespace Barotrauma
|
||||
{
|
||||
partial class LevelObjectPrefab : ISerializableEntity
|
||||
{
|
||||
private static List<LevelObjectPrefab> list = new List<LevelObjectPrefab>();
|
||||
public static List<LevelObjectPrefab> List
|
||||
{
|
||||
get { return list; }
|
||||
}
|
||||
public static List<LevelObjectPrefab> List { get; } = new List<LevelObjectPrefab>();
|
||||
|
||||
public class ChildObject
|
||||
{
|
||||
@@ -38,12 +34,15 @@ namespace Barotrauma
|
||||
public enum SpawnPosType
|
||||
{
|
||||
None = 0,
|
||||
Wall = 1,
|
||||
RuinWall = 2,
|
||||
SeaFloor = 4,
|
||||
MainPath = 8,
|
||||
LevelStart = 16,
|
||||
LevelEnd = 32,
|
||||
MainPathWall = 1,
|
||||
SidePathWall = 2,
|
||||
CaveWall = 4,
|
||||
RuinWall = 8,
|
||||
SeaFloor = 16,
|
||||
MainPath = 32,
|
||||
LevelStart = 64,
|
||||
LevelEnd = 128,
|
||||
Wall = MainPathWall | SidePathWall | CaveWall,
|
||||
}
|
||||
|
||||
public List<Sprite> Sprites
|
||||
@@ -52,12 +51,6 @@ namespace Barotrauma
|
||||
private set;
|
||||
} = new List<Sprite>();
|
||||
|
||||
public List<Sprite> SpecularSprites
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
} = new List<Sprite>();
|
||||
|
||||
public DeformableSprite DeformableSprite
|
||||
{
|
||||
get;
|
||||
@@ -117,7 +110,13 @@ namespace Barotrauma
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
} = -1;
|
||||
|
||||
public Dictionary<Sprite, XElement> SpriteSpecificPhysicsBodyElements
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
} = new Dictionary<Sprite, XElement>();
|
||||
|
||||
|
||||
[Serialize(10000, false, description: "Maximum number of this specific object per level."), Editable(MinValueFloat = 0.01f, MaxValueFloat = 10.0f)]
|
||||
@@ -162,6 +161,13 @@ namespace Barotrauma
|
||||
private set;
|
||||
}
|
||||
|
||||
[Editable, Serialize("0,0", true, description: "Random offset from the surface the object spawns on.")]
|
||||
public Vector2 RandomOffset
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
[Editable, Serialize(false, true, description: "Should the object be rotated to align it with the wall surface it spawns on.")]
|
||||
public bool AlignWithSurface
|
||||
{
|
||||
@@ -243,12 +249,18 @@ namespace Barotrauma
|
||||
private set;
|
||||
}
|
||||
|
||||
public string Name
|
||||
public string Identifier
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
|
||||
public string Name
|
||||
{
|
||||
get { return Identifier; }
|
||||
}
|
||||
|
||||
public List<ChildObject> ChildObjects
|
||||
{
|
||||
get;
|
||||
@@ -272,12 +284,12 @@ namespace Barotrauma
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return "LevelObjectPrefab (" + Name + ")";
|
||||
return "LevelObjectPrefab (" + Identifier + ")";
|
||||
}
|
||||
|
||||
public static void LoadAll()
|
||||
{
|
||||
list.Clear();
|
||||
List.Clear();
|
||||
var files = GameMain.Instance.GetFilesOfType(ContentType.LevelObjectPrefabs);
|
||||
if (files.Count() > 0)
|
||||
{
|
||||
@@ -303,35 +315,62 @@ namespace Barotrauma
|
||||
{
|
||||
mainElement = doc.Root.FirstElement();
|
||||
DebugConsole.NewMessage($"Overriding all level object prefabs with '{configPath}'", Color.Yellow);
|
||||
list.Clear();
|
||||
List.Clear();
|
||||
}
|
||||
else if (list.Any())
|
||||
else if (List.Any())
|
||||
{
|
||||
DebugConsole.NewMessage($"Loading additional level object prefabs from file '{configPath}'");
|
||||
DebugConsole.Log($"Loading additional level object prefabs from file '{configPath}'");
|
||||
}
|
||||
foreach (XElement element in mainElement.Elements())
|
||||
foreach (XElement subElement in mainElement.Elements())
|
||||
{
|
||||
list.Add(new LevelObjectPrefab(element));
|
||||
var element = subElement.IsOverride() ? subElement.FirstElement() : subElement;
|
||||
string identifier = element.GetAttributeString("identifier", "");
|
||||
var existingPrefab = List.Find(p => p.Identifier.Equals(identifier, StringComparison.OrdinalIgnoreCase));
|
||||
if (existingPrefab != null)
|
||||
{
|
||||
if (subElement.IsOverride())
|
||||
{
|
||||
DebugConsole.NewMessage($"Overriding the existing level object prefab '{identifier}' using the file '{configPath}'", Color.Yellow);
|
||||
List.Remove(existingPrefab);
|
||||
}
|
||||
else
|
||||
{
|
||||
DebugConsole.ThrowError($"Error in '{configPath}': Duplicate level object prefab '{identifier}' found in '{configPath}'! Each level object prefab must have a unique identifier. " +
|
||||
"Use <override></override> tags to override prefabs.");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
List.Add(new LevelObjectPrefab(element));
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
DebugConsole.ThrowError(String.Format("Failed to load LevelObject prefabs from {0}", configPath), e);
|
||||
DebugConsole.ThrowError(string.Format("Failed to load LevelObject prefabs from {0}", configPath), e);
|
||||
}
|
||||
}
|
||||
|
||||
public LevelObjectPrefab(XElement element)
|
||||
public LevelObjectPrefab(XElement element, string identifier = null)
|
||||
{
|
||||
ChildObjects = new List<ChildObject>();
|
||||
LevelTriggerElements = new List<XElement>();
|
||||
OverrideProperties = new List<LevelObjectPrefab>();
|
||||
OverrideCommonness = new Dictionary<string, float>();
|
||||
|
||||
Identifier = null;
|
||||
SerializableProperties = SerializableProperty.DeserializeProperties(this, element);
|
||||
if (element != null)
|
||||
{
|
||||
Config = element;
|
||||
Name = element.Name.ToString();
|
||||
Identifier = element.GetAttributeString("identifier", null) ?? identifier;
|
||||
if (string.IsNullOrEmpty(Identifier))
|
||||
{
|
||||
#if DEBUG
|
||||
DebugConsole.ThrowError($"Level object prefab \"{element.Name}\" has no identifier! Using the name as the identifier instead...");
|
||||
#else
|
||||
DebugConsole.AddWarning($"Level object prefab \"{element.Name}\" has no identifier! Using the name as the identifier instead...");
|
||||
#endif
|
||||
Identifier = element.Name.ToString();
|
||||
}
|
||||
LoadElements(element, -1);
|
||||
InitProjSpecific(element);
|
||||
}
|
||||
@@ -346,21 +385,27 @@ namespace Barotrauma
|
||||
|
||||
private void LoadElements(XElement element, int parentTriggerIndex)
|
||||
{
|
||||
int propertyOverrideCount = 0;
|
||||
foreach (XElement subElement in element.Elements())
|
||||
{
|
||||
switch (subElement.Name.ToString().ToLowerInvariant())
|
||||
{
|
||||
case "sprite":
|
||||
Sprites.Add( new Sprite(subElement, lazyLoad: true));
|
||||
break;
|
||||
case "specularsprite":
|
||||
SpecularSprites.Add(new Sprite(subElement, lazyLoad: true));
|
||||
var newSprite = new Sprite(subElement, lazyLoad: true);
|
||||
Sprites.Add(newSprite);
|
||||
var spriteSpecificPhysicsBodyElement =
|
||||
subElement.Element("PhysicsBody") ?? subElement.Element("Body") ??
|
||||
subElement.Element("physicsbody") ?? subElement.Element("body");
|
||||
if (spriteSpecificPhysicsBodyElement != null)
|
||||
{
|
||||
SpriteSpecificPhysicsBodyElements.Add(newSprite, spriteSpecificPhysicsBodyElement);
|
||||
}
|
||||
break;
|
||||
case "deformablesprite":
|
||||
DeformableSprite = new DeformableSprite(subElement, lazyLoad: true);
|
||||
break;
|
||||
case "overridecommonness":
|
||||
string levelType = subElement.GetAttributeString("leveltype", "");
|
||||
string levelType = subElement.GetAttributeString("leveltype", "").ToLowerInvariant();
|
||||
if (!OverrideCommonness.ContainsKey(levelType))
|
||||
{
|
||||
OverrideCommonness.Add(levelType, subElement.GetAttributeFloat("commonness", 1.0f));
|
||||
@@ -376,13 +421,14 @@ namespace Barotrauma
|
||||
ChildObjects.Add(new ChildObject(subElement));
|
||||
break;
|
||||
case "overrideproperties":
|
||||
var propertyOverride = new LevelObjectPrefab(subElement);
|
||||
var propertyOverride = new LevelObjectPrefab(subElement, identifier: Identifier + "-" + propertyOverrideCount);
|
||||
OverrideProperties[OverrideProperties.Count - 1] = propertyOverride;
|
||||
if (!propertyOverride.Sprites.Any() && propertyOverride.DeformableSprite == null)
|
||||
{
|
||||
propertyOverride.Sprites = Sprites;
|
||||
propertyOverride.DeformableSprite = DeformableSprite;
|
||||
}
|
||||
propertyOverrideCount++;
|
||||
break;
|
||||
case "body":
|
||||
case "physicsbody":
|
||||
@@ -395,13 +441,26 @@ namespace Barotrauma
|
||||
|
||||
partial void InitProjSpecific(XElement element);
|
||||
|
||||
public float GetCommonness(string levelType)
|
||||
|
||||
public float GetCommonness(CaveGenerationParams generationParams)
|
||||
{
|
||||
if (!OverrideCommonness.TryGetValue(levelType, out float commonness))
|
||||
if (generationParams?.Identifier != null &&
|
||||
OverrideCommonness.TryGetValue(generationParams.Identifier, out float commonness))
|
||||
{
|
||||
return Commonness;
|
||||
return commonness;
|
||||
}
|
||||
return commonness;
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
public float GetCommonness(LevelGenerationParams generationParams)
|
||||
{
|
||||
if (generationParams?.Identifier != null &&
|
||||
(OverrideCommonness.TryGetValue(generationParams.Identifier, out float commonness) ||
|
||||
(generationParams.OldIdentifier != null && OverrideCommonness.TryGetValue(generationParams.OldIdentifier, out commonness))))
|
||||
{
|
||||
return commonness;
|
||||
}
|
||||
return Commonness;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -186,6 +186,18 @@ namespace Barotrauma
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public string InfectIdentifier
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public float InfectionChance
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public LevelTrigger(XElement element, Vector2 position, float rotation, float scale = 1.0f, string parentDebugName = "")
|
||||
{
|
||||
@@ -211,6 +223,9 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
cameraShake = element.GetAttributeFloat("camerashake", 0.0f);
|
||||
|
||||
InfectIdentifier = element.GetAttributeString("infectidentifier", null);
|
||||
InfectionChance = element.GetAttributeFloat("infectionchance", 0.05f);
|
||||
|
||||
stayTriggeredDelay = element.GetAttributeFloat("staytriggereddelay", 0.0f);
|
||||
randomTriggerInterval = element.GetAttributeFloat("randomtriggerinterval", 0.0f);
|
||||
@@ -513,9 +528,14 @@ namespace Barotrauma
|
||||
float structureDamage = attack.GetStructureDamage(deltaTime);
|
||||
if (structureDamage > 0.0f)
|
||||
{
|
||||
Explosion.RangedStructureDamage(worldPosition, attack.DamageRange, structureDamage);
|
||||
Explosion.RangedStructureDamage(worldPosition, attack.DamageRange, structureDamage, levelWallDamage: 0.0f);
|
||||
}
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(InfectIdentifier))
|
||||
{
|
||||
submarine.AttemptBallastFloraInfection(InfectIdentifier, deltaTime, InfectionChance);
|
||||
}
|
||||
}
|
||||
|
||||
if (Force.LengthSquared() > 0.01f)
|
||||
@@ -598,7 +618,7 @@ namespace Barotrauma
|
||||
|
||||
public Vector2 GetWaterFlowVelocity()
|
||||
{
|
||||
if (Force == Vector2.Zero) return Vector2.Zero;
|
||||
if (Force == Vector2.Zero || ForceMode == TriggerForceMode.LimitVelocity) { return Vector2.Zero; }
|
||||
|
||||
Vector2 vel = Force;
|
||||
if (ForceMode == TriggerForceMode.Acceleration)
|
||||
|
||||
Reference in New Issue
Block a user