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
@@ -8,7 +8,7 @@ using System.Xml.Linq;
namespace Barotrauma
{
partial class LevelObject : ISpatialEntity
partial class LevelObject : ISpatialEntity, IDamageable, ISerializableEntity
{
public readonly LevelObjectPrefab Prefab;
public Vector3 Position;
@@ -21,6 +21,8 @@ namespace Barotrauma
private int spriteIndex;
protected bool tookDamage;
public LevelObjectPrefab ActivePrefab;
public PhysicsBody PhysicsBody
@@ -37,11 +39,15 @@ namespace Barotrauma
public bool NeedsNetworkSyncing
{
get { return Triggers != null && Triggers.Any(t => t.NeedsNetworkSyncing); }
get
{
return tookDamage || (Triggers != null && Triggers.Any(t => t.NeedsNetworkSyncing));
}
set
{
if (Triggers == null) { return; }
Triggers.ForEach(t => t.NeedsNetworkSyncing = false);
Triggers.ForEach(t => t.NeedsNetworkSyncing = false);
tookDamage = false;
}
}
@@ -50,6 +56,12 @@ namespace Barotrauma
get; private set;
}
public float Health
{
get;
private set;
}
public Sprite Sprite
{
get
@@ -67,6 +79,10 @@ namespace Barotrauma
public Submarine Submarine => null;
public string Name => Prefab?.Name ?? "LevelObject (null)";
public Dictionary<string, SerializableProperty> SerializableProperties { get; } = new Dictionary<string, SerializableProperty>();
public Level.Cave ParentCave;
public LevelObject(LevelObjectPrefab prefab, Vector3 position, float scale, float rotation = 0.0f)
@@ -75,6 +91,7 @@ namespace Barotrauma
Position = position;
Scale = scale;
Rotation = rotation;
Health = prefab.Health;
spriteIndex = ActivePrefab.Sprites.Any() ? Rand.Int(ActivePrefab.Sprites.Count, Rand.RandSync.Server) : -1;
@@ -89,10 +106,13 @@ namespace Barotrauma
if (PhysicsBody != null)
{
PhysicsBody.UserData = this;
PhysicsBody.SetTransformIgnoreContacts(PhysicsBody.SimPosition, -Rotation);
PhysicsBody.BodyType = BodyType.Static;
PhysicsBody.CollisionCategories = Physics.CollisionLevel;
PhysicsBody.CollidesWith = Physics.CollisionWall | Physics.CollisionCharacter;
PhysicsBody.CollidesWith = Prefab.TakeLevelWallDamage?
Physics.CollisionWall | Physics.CollisionCharacter | Physics.CollisionProjectile :
Physics.CollisionWall | Physics.CollisionCharacter;
}
foreach (XElement triggerElement in prefab.LevelTriggerElements)
@@ -111,6 +131,10 @@ namespace Barotrauma
}
var newTrigger = new LevelTrigger(triggerElement, new Vector2(position.X, position.Y) + triggerPosition, -rotation, scale, prefab.Name);
if (newTrigger.PhysicsBody != null)
{
newTrigger.PhysicsBody.UserData = this;
}
int parentTriggerIndex = prefab.LevelTriggerElements.IndexOf(triggerElement.Parent);
if (parentTriggerIndex > -1) { newTrigger.ParentTrigger = Triggers[parentTriggerIndex]; }
Triggers.Add(newTrigger);
@@ -135,7 +159,54 @@ namespace Barotrauma
}
partial void InitProjSpecific();
public AttackResult AddDamage(Character attacker, Vector2 worldPosition, Attack attack, float deltaTime, bool playSound = true)
{
if (Health <= 0.0f) { return new AttackResult(0.0f); }
float damage = 0.0f;
if (Prefab.TakeLevelWallDamage)
{
damage += attack.GetLevelWallDamage(deltaTime);
}
damage = Math.Max(Health, damage);
AddDamage(damage, deltaTime, attacker);
return new AttackResult(damage);
}
public void AddDamage(float damage, float deltaTime, Entity attacker, bool isNetworkEvent = false)
{
if (Health <= 0.0f) { return; }
if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsClient && !isNetworkEvent)
{
return;
}
tookDamage |= !MathUtils.NearlyEqual(damage, 0.0f);
Health -= damage;
if (Health <= 0.0f)
{
#if CLIENT
if (GameMain.GameSession?.Level?.LevelObjectManager != null)
{
GameMain.GameSession.Level.LevelObjectManager.ForceRefreshVisibleObjects = true;
}
#endif
if (PhysicsBody != null)
{
PhysicsBody.Enabled = false;
}
foreach (LevelTrigger trigger in Triggers)
{
trigger.PhysicsBody.Enabled = false;
foreach (StatusEffect effect in trigger.StatusEffects)
{
if (effect.type != ActionType.OnBroken) { continue; }
effect.Apply(effect.type, deltaTime, attacker, this, worldPosition: WorldPosition);
}
}
}
}
public Vector2 LocalToWorld(Vector2 localPosition, float swingState = 0.0f)
{
Vector2 emitterPos = localPosition * Scale;
@@ -169,6 +240,10 @@ namespace Barotrauma
public void ServerWrite(IWriteMessage msg, Client c)
{
if (Triggers == null) { return; }
if (Prefab.TakeLevelWallDamage)
{
msg.WriteRangedSingle(MathHelper.Clamp(Health, 0.0f, Prefab.Health), 0.0f, Prefab.Health, 8);
}
for (int j = 0; j < Triggers.Count; j++)
{
if (!Triggers[j].UseNetworkSyncing) { continue; }
@@ -21,6 +21,12 @@ namespace Barotrauma
private List<LevelObject> updateableObjects;
private List<LevelObject>[,] objectGrid;
public float GlobalForceDecreaseTimer
{
get;
private set;
}
public LevelObjectManager() : base(null, Entity.NullEntityID)
{
}
@@ -130,11 +136,16 @@ namespace Barotrauma
if (prefab == null) { continue; }
if (!suitableSpawnPositions.ContainsKey(prefab))
{
float minDistance = level.Size.X * 0.2f;
suitableSpawnPositions.Add(prefab,
availableSpawnPositions.Where(sp =>
sp.SpawnPosTypes.Any(type => prefab.SpawnPos.HasFlag(type)) &&
sp.Length >= prefab.MinSurfaceWidth &&
sp.Length >= prefab.MinSurfaceWidth &&
(prefab.AllowAtStart || !level.IsCloseToStart(sp.GraphEdge.Center, minDistance)) &&
(prefab.AllowAtEnd || !level.IsCloseToEnd(sp.GraphEdge.Center, minDistance)) &&
(sp.Alignment == Alignment.Any || prefab.Alignment.HasFlag(sp.Alignment))).ToList());
spawnPositionWeights.Add(prefab,
suitableSpawnPositions[prefab].Select(sp => sp.GetSpawnProbability(prefab)).ToList());
}
@@ -422,10 +433,10 @@ namespace Barotrauma
public IEnumerable<LevelObject> GetAllObjects(Vector2 worldPosition, float radius)
{
var minIndices = GetGridIndices(worldPosition - Vector2.One * radius);
if (minIndices.X >= objectGrid.GetLength(0) || minIndices.Y >= objectGrid.GetLength(1)) return Enumerable.Empty<LevelObject>();
if (minIndices.X >= objectGrid.GetLength(0) || minIndices.Y >= objectGrid.GetLength(1)) { return Enumerable.Empty<LevelObject>(); }
var maxIndices = GetGridIndices(worldPosition + Vector2.One * radius);
if (maxIndices.X < 0 || maxIndices.Y < 0) return Enumerable.Empty<LevelObject>();
if (maxIndices.X < 0 || maxIndices.Y < 0) { return Enumerable.Empty<LevelObject>(); }
minIndices.X = Math.Max(0, minIndices.X);
minIndices.Y = Math.Max(0, minIndices.Y);
@@ -440,6 +451,7 @@ namespace Barotrauma
if (objectGrid[x, y] == null) { continue; }
foreach (LevelObject obj in objectGrid[x, y])
{
if (obj.Prefab.HideWhenBroken && obj.Health <= 0.0f) { continue; }
objectsInRange.Add(obj);
}
}
@@ -484,6 +496,12 @@ namespace Barotrauma
public void Update(float deltaTime)
{
GlobalForceDecreaseTimer += deltaTime;
if (GlobalForceDecreaseTimer > 1000000.0f)
{
GlobalForceDecreaseTimer = 0.0f;
}
foreach (LevelObject obj in updateableObjects)
{
if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsServer)
@@ -496,6 +514,7 @@ namespace Barotrauma
obj.NetworkUpdateTimer = NetConfig.LevelObjectUpdateInterval;
}
}
if (obj.Prefab.HideWhenBroken && obj.Health <= 0.0f) { continue; }
if (obj.Triggers != null)
{
@@ -176,6 +176,20 @@ namespace Barotrauma
private set;
}
[Editable, Serialize(true, true, description: "Can the object be placed near the start of the level.")]
public bool AllowAtStart
{
get;
private set;
}
[Editable, Serialize(true, true, description: "Can the object be placed near the end of the level.")]
public bool AllowAtEnd
{
get;
private set;
}
[Serialize(0.0f, true, description: "Minimum length of a graph edge the object can spawn on."), Editable(MinValueFloat = 0.0f, MaxValueFloat = 1000.0f)]
/// <summary>
/// Minimum length of a graph edge the object can spawn on.
@@ -250,6 +264,27 @@ namespace Barotrauma
private set;
}
[Serialize(false, true, description: "Can the object take damage from weapons/attacks that damage level walls."), Editable]
public bool TakeLevelWallDamage
{
get;
private set;
}
[Serialize(false, true), Editable]
public bool HideWhenBroken
{
get;
private set;
}
[Serialize(100.0f, true), Editable]
public float Health
{
get;
private set;
}
public string Identifier
{
get;
@@ -38,6 +38,10 @@ namespace Barotrauma
/// Effects applied to entities that are inside the trigger
/// </summary>
private readonly List<StatusEffect> statusEffects = new List<StatusEffect>();
public IEnumerable<StatusEffect> StatusEffects
{
get { return statusEffects; }
}
/// <summary>
/// Attacks applied to entities that are inside the trigger
@@ -140,6 +144,11 @@ namespace Barotrauma
get;
private set;
}
public float GlobalForceDecreaseInterval
{
get;
private set;
}
private readonly TriggerForceMode forceMode;
public TriggerForceMode ForceMode
@@ -200,7 +209,7 @@ namespace Barotrauma
PhysicsBody = new PhysicsBody(element, scale)
{
CollisionCategories = Physics.CollisionLevel,
CollidesWith = Physics.CollisionCharacter | Physics.CollisionItem | Physics.CollisionProjectile | Physics.CollisionWall
CollidesWith = Physics.CollisionCharacter | Physics.CollisionItem | Physics.CollisionProjectile | Physics.CollisionWall,
};
PhysicsBody.FarseerBody.OnCollision += PhysicsBody_OnCollision;
PhysicsBody.FarseerBody.OnSeparation += PhysicsBody_OnSeparation;
@@ -234,6 +243,7 @@ namespace Barotrauma
ForceFluctuationInterval = element.GetAttributeFloat("forcefluctuationinterval", 0.01f);
ForceFluctuationStrength = Math.Max(element.GetAttributeFloat("forcefluctuationstrength", 0.0f), 0.0f);
ForceFalloff = element.GetAttributeBool("forcefalloff", true);
GlobalForceDecreaseInterval = element.GetAttributeFloat("globalforcedecreaseinterval", 0.0f);
ForceVelocityLimit = ConvertUnits.ToSimUnits(element.GetAttributeFloat("forcevelocitylimit", float.MaxValue));
string forceModeStr = element.GetAttributeString("forcemode", "Force");
@@ -434,6 +444,8 @@ namespace Barotrauma
}
}
private readonly List<ISerializableEntity> targets = new List<ISerializableEntity>();
public void Update(float deltaTime)
{
if (ParentTrigger != null && !ParentTrigger.IsTriggered) { return; }
@@ -457,7 +469,13 @@ namespace Barotrauma
if (!UseNetworkSyncing || isNotClient)
{
if (ForceFluctuationStrength > 0.0f)
if (GlobalForceDecreaseInterval > 0.0f && Level.Loaded?.LevelObjectManager != null &&
Level.Loaded.LevelObjectManager.GlobalForceDecreaseTimer % (GlobalForceDecreaseInterval * 2) < GlobalForceDecreaseInterval)
{
NeedsNetworkSyncing |= currentForceFluctuation > 0.0f;
currentForceFluctuation = 0.0f;
}
else if (ForceFluctuationStrength > 0.0f)
{
//no need for force fluctuation (or network updates) if the trigger limits velocity and there are no triggerers
if (forceMode != TriggerForceMode.LimitVelocity || triggerers.Any())
@@ -509,6 +527,7 @@ namespace Barotrauma
{
foreach (StatusEffect effect in statusEffects)
{
if (effect.type == ActionType.OnBroken) { continue; }
Vector2? position = null;
if (effect.HasTargetType(StatusEffect.TargetType.This)) { position = WorldPosition; }
if (triggerer is Character character)
@@ -533,8 +552,8 @@ namespace Barotrauma
if (effect.HasTargetType(StatusEffect.TargetType.NearbyItems) ||
effect.HasTargetType(StatusEffect.TargetType.NearbyCharacters))
{
var targets = new List<ISerializableEntity>();
effect.GetNearbyTargets(worldPosition, targets);
targets.Clear();
targets.AddRange(effect.GetNearbyTargets(worldPosition, targets));
effect.Apply(effect.type, deltaTime, triggerer, targets);
}
}