v0.14.6.0
This commit is contained in:
@@ -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; }
|
||||
|
||||
+22
-3
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user