Unstable 0.17.0.0
This commit is contained in:
@@ -18,45 +18,72 @@ namespace Barotrauma.MapCreatures.Behavior
|
||||
public readonly BallastFloraBehavior? ParentBallastFlora;
|
||||
public int ID = -1;
|
||||
|
||||
public Item ClaimedItem;
|
||||
public Item? ClaimedItem;
|
||||
public int ClaimedItemId = -1;
|
||||
|
||||
public float MaxHealth = 100f;
|
||||
public float Health = 100f;
|
||||
|
||||
private float health = 100;
|
||||
public float Health
|
||||
{
|
||||
get { return health; }
|
||||
set { health = MathHelper.Clamp(value, 0.0f, MaxHealth); }
|
||||
}
|
||||
|
||||
public float RemoveTimer = 60.0f;
|
||||
|
||||
public bool SpawningItem;
|
||||
public Item? AttackItem;
|
||||
|
||||
public bool IsRoot;
|
||||
/// <summary>
|
||||
/// Decorative branches that grow around the root
|
||||
/// </summary>
|
||||
public bool IsRootGrowth;
|
||||
public bool Removed;
|
||||
|
||||
public bool DisconnectedFromRoot;
|
||||
|
||||
public Hull? CurrentHull;
|
||||
|
||||
public float Pulse = 1.0f;
|
||||
private bool inflate;
|
||||
private float pulseDelay = Rand.Range(0f, 3f);
|
||||
|
||||
public readonly BallastFloraBranch? ParentBranch;
|
||||
/// <summary>
|
||||
/// How far from the root this branch is
|
||||
/// </summary>
|
||||
public readonly int BranchDepth;
|
||||
|
||||
public float AccumulatedDamage;
|
||||
public float DamageVisualizationTimer;
|
||||
public Vector2 ShakeAmount;
|
||||
|
||||
// Adjacent tiles, used to free up sides when this branch gets removed
|
||||
public readonly Dictionary<TileSide, BallastFloraBranch> Connections = new Dictionary<TileSide, BallastFloraBranch>();
|
||||
|
||||
public BallastFloraBranch(BallastFloraBehavior? parent, Vector2 position, VineTileType type, FoliageConfig? flowerConfig = null, FoliageConfig? leafConfig = null, Rectangle? rect = null)
|
||||
public BallastFloraBranch(BallastFloraBehavior? parent, BallastFloraBranch? parentBranch, Vector2 position, VineTileType type, FoliageConfig? flowerConfig = null, FoliageConfig? leafConfig = null, Rectangle? rect = null)
|
||||
: base(null, position, type, flowerConfig, leafConfig, rect)
|
||||
{
|
||||
ParentBranch = parentBranch;
|
||||
ParentBallastFlora = parent;
|
||||
if (parentBranch != null)
|
||||
{
|
||||
BranchDepth = parentBranch.BranchDepth + 1;
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateHealth()
|
||||
{
|
||||
if (MaxHealth <= Health) { return; }
|
||||
Color healthColor = Color.White * (1.0f - Health / MaxHealth);
|
||||
HealthColor = healthColor;
|
||||
HealthColor = Color.Lerp(HealthColor, healthColor, 0.05f);
|
||||
}
|
||||
|
||||
public void UpdatePulse(float deltaTime, float inflateSpeed, float deflateSpeed, float delay)
|
||||
{
|
||||
if (ParentBallastFlora == null) { return; }
|
||||
if (ParentBallastFlora == null || DisconnectedFromRoot) { return; }
|
||||
|
||||
if (pulseDelay > 0)
|
||||
{
|
||||
@@ -91,7 +118,7 @@ namespace Barotrauma.MapCreatures.Behavior
|
||||
public List<Tuple<Vector2, Vector2>> debugSearchLines = new List<Tuple<Vector2, Vector2>>();
|
||||
#endif
|
||||
|
||||
private static List<BallastFloraBehavior> _entityList = new List<BallastFloraBehavior>();
|
||||
private readonly static List<BallastFloraBehavior> _entityList = new List<BallastFloraBehavior>();
|
||||
public static IEnumerable<BallastFloraBehavior> EntityList => _entityList;
|
||||
|
||||
public enum NetworkHeader
|
||||
@@ -101,119 +128,126 @@ namespace Barotrauma.MapCreatures.Behavior
|
||||
BranchCreate,
|
||||
BranchRemove,
|
||||
BranchDamage,
|
||||
Infect
|
||||
Infect,
|
||||
Remove
|
||||
}
|
||||
|
||||
public enum AttackType
|
||||
{
|
||||
Fire,
|
||||
Explosives,
|
||||
Other
|
||||
Other,
|
||||
CutFromRoot
|
||||
}
|
||||
|
||||
public struct AITarget
|
||||
{
|
||||
public string[] Tags;
|
||||
public Identifier[] Tags;
|
||||
public int Priority;
|
||||
|
||||
public AITarget(XElement element)
|
||||
public AITarget(ContentXElement element)
|
||||
{
|
||||
Tags = element.GetAttributeStringArray("tags", new string[0]);
|
||||
Tags = element.GetAttributeIdentifierArray("tags", Array.Empty<Identifier>())!;
|
||||
Priority = element.GetAttributeInt("priority", 0);
|
||||
}
|
||||
|
||||
public bool Matches(Item item)
|
||||
{
|
||||
foreach (string tag in item.GetTags())
|
||||
{
|
||||
foreach (Identifier targetTag in Tags)
|
||||
{
|
||||
foreach (string targetTag in Tags)
|
||||
{
|
||||
if (tag == targetTag) { return true; }
|
||||
}
|
||||
if (item.HasTag(targetTag)) { return true; }
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
[Serialize(0.25f, true, "Scale of the branches")]
|
||||
[Serialize(0.25f, IsPropertySaveable.Yes, "Scale of the branches.")]
|
||||
public float BaseBranchScale { get; set; }
|
||||
|
||||
[Serialize(0.25f, true, "Scale of the flowers")]
|
||||
[Serialize(0.25f, IsPropertySaveable.Yes, "Scale of the flowers.")]
|
||||
public float BaseFlowerScale { get; set; }
|
||||
|
||||
[Serialize(0.5f, true, "Scale of the leaves")]
|
||||
[Serialize(0.5f, IsPropertySaveable.Yes, "Scale of the leaves.")]
|
||||
public float BaseLeafScale { get; set; }
|
||||
|
||||
[Serialize(0.33f, true, "Chance for a flower to appear on the branch")]
|
||||
[Serialize(0.33f, IsPropertySaveable.Yes, "Chance for a flower to appear on a branch.")]
|
||||
public float FlowerProbability { get; set; }
|
||||
|
||||
[Serialize(0.7f, true, "Change for leaves to appear for the branch")]
|
||||
[Serialize(0.7f, IsPropertySaveable.Yes, "Chance for leaves to appear on a branch.")]
|
||||
public float LeafProbability { get; set; }
|
||||
|
||||
[Serialize(3f, true, "Delay between pulses")]
|
||||
[Serialize(3f, IsPropertySaveable.Yes, "Delay between pulses.")]
|
||||
public float PulseDelay { get; set; }
|
||||
|
||||
[Serialize(3f, true, "How fast the flower inflates during a pulse")]
|
||||
[Serialize(3f, IsPropertySaveable.Yes, "How fast the flower inflates during a pulse.")]
|
||||
public float PulseInflateSpeed { get; set; }
|
||||
|
||||
[Serialize(1f, true, "How fast the flower deflates")]
|
||||
[Serialize(1f, IsPropertySaveable.Yes, "How fast the flower deflates.")]
|
||||
public float PulseDeflateSpeed { get; set; }
|
||||
|
||||
[Serialize(32, true, "How many vines must grow before the plant breaks thru the wall")]
|
||||
[Serialize(32, IsPropertySaveable.Yes, "How many vines must grow before the plant breaks through the wall.")]
|
||||
public int BreakthroughPoint { get; set; }
|
||||
|
||||
[Serialize(false, true, "Has the plant grown large enough to expose itself")]
|
||||
[Serialize(false, IsPropertySaveable.Yes, "Has the plant grown large enough to expose itself.")]
|
||||
public bool HasBrokenThrough { get; set; }
|
||||
|
||||
[Serialize(300, true, "How far the ballast flora can detect items")]
|
||||
[Serialize(300, IsPropertySaveable.Yes, "How far the ballast flora can detect items from.")]
|
||||
public int Sight { get; set; }
|
||||
|
||||
[Serialize(100, true, "How much health the branches have")]
|
||||
[Serialize(100, IsPropertySaveable.Yes, "How much health the branches have.")]
|
||||
public int BranchHealth { get; set; }
|
||||
|
||||
[Serialize(400, true, "How much health the stem has")]
|
||||
public int StemHealth { get; set; }
|
||||
[Serialize(400, IsPropertySaveable.Yes, "How much health the root has.")]
|
||||
public int RootHealth { get; set; }
|
||||
|
||||
[Serialize(300f, true, "How much power the ballast flora takes from junction boxes")]
|
||||
[Serialize(0.0005f, IsPropertySaveable.Yes, "How fast the root's health regenerates per each grown branch.")]
|
||||
public float HealthRegenPerBranch { get; set; }
|
||||
|
||||
[Serialize(30, IsPropertySaveable.Yes, "How far away from the root branches can regenerate health (in number of branches). The amount of regen decreases lineary further from the root.")]
|
||||
public int MaxBranchHealthRegenDistance { get; set; }
|
||||
|
||||
[Serialize("255,255,255,255", IsPropertySaveable.Yes)]
|
||||
public Color RootColor { get; set; }
|
||||
|
||||
[Serialize(300f, IsPropertySaveable.Yes, "How much power the ballast flora takes from junction boxes.")]
|
||||
public float PowerConsumptionMin { get; set; }
|
||||
|
||||
[Serialize(3000f, true, "How much the power drain spikes")]
|
||||
[Serialize(3000f, IsPropertySaveable.Yes, "How much the power drain spikes.")]
|
||||
public float PowerConsumptionMax { get; set; }
|
||||
|
||||
[Serialize(10f, true, "How long it takes for power drain to wind down")]
|
||||
[Serialize(10f, IsPropertySaveable.Yes, "How long it takes for power drain to wind down.")]
|
||||
public float PowerConsumptionDuration { get; set; }
|
||||
|
||||
[Serialize(250f, true, "How much power does it take to accelerate growth")]
|
||||
[Serialize(250f, IsPropertySaveable.Yes, "How much power does it take to accelerate growth.")]
|
||||
public float PowerRequirement { get; set; }
|
||||
|
||||
[Serialize(5f, true, "Maximum anger, anger increases when the plant gets damaged and increases growth speed")]
|
||||
[Serialize(5f, IsPropertySaveable.Yes, "Maximum anger, anger increases when the plant gets damaged and increases growth speed.")]
|
||||
public float MaxAnger { get; set; }
|
||||
|
||||
[Serialize(10000f, true, "Maximum power buffer")]
|
||||
[Serialize(10000f, IsPropertySaveable.Yes, "Maximum power buffer.")]
|
||||
public float MaxPowerCapacity { get; set; }
|
||||
|
||||
[Serialize("", true, "Item prefab that is spawned when threatened")]
|
||||
public string AttackItemPrefab { get; set; } = "";
|
||||
[Serialize("", IsPropertySaveable.Yes, "Item prefab that is spawned when threatened.")]
|
||||
public Identifier AttackItemPrefab { get; set; } = Identifier.Empty;
|
||||
|
||||
[Serialize(0.8f, true, "How resistant the ballast flora is to exlposives before it blooms")]
|
||||
[Serialize(0.8f, IsPropertySaveable.Yes, "How resistant the ballast flora is to explosives before it blooms.")]
|
||||
public float ExplosionResistance { get; set; }
|
||||
|
||||
[Serialize(5f, true, "How much damage is taken from open fires")]
|
||||
[Serialize(5f, IsPropertySaveable.Yes, "How much damage is taken from open fires.")]
|
||||
public float FireVulnerability { get; set; }
|
||||
|
||||
[Serialize(0.5f, true, "How much resistance against fire is gained while submerged.")]
|
||||
[Serialize(0.5f, IsPropertySaveable.Yes, "How much resistance against fire is gained while submerged.")]
|
||||
public float SubmergedWaterResistance { get; set; }
|
||||
|
||||
[Serialize(0.8f, true, "What depth the branches will be drawn on")]
|
||||
[Serialize(0.8f, IsPropertySaveable.Yes, "What depth the branches will be drawn on.")]
|
||||
public float BranchDepth { get; set; }
|
||||
|
||||
[Serialize("", true, "What sound to play when the ballast flora bursts thru walls")]
|
||||
[Serialize("", IsPropertySaveable.Yes, "What sound to play when the ballast flora bursts through walls.")]
|
||||
public string BurstSound { get; set; } = "";
|
||||
|
||||
private float availablePower;
|
||||
|
||||
[Serialize(0f, true, "How much power the ballast flora has stored.")]
|
||||
[Serialize(0f, IsPropertySaveable.Yes, "How much power the ballast flora has stored.")]
|
||||
public float AvailablePower
|
||||
{
|
||||
get => availablePower;
|
||||
@@ -222,7 +256,7 @@ namespace Barotrauma.MapCreatures.Behavior
|
||||
|
||||
private float anger;
|
||||
|
||||
[Serialize(1f, true, "How enraged the flora is, affects how fast it grows.")]
|
||||
[Serialize(1f, IsPropertySaveable.Yes, "How enraged the flora is, affects how fast it grows.")]
|
||||
public float Anger
|
||||
{
|
||||
get => anger;
|
||||
@@ -235,13 +269,13 @@ namespace Barotrauma.MapCreatures.Behavior
|
||||
|
||||
public BallastFloraPrefab Prefab { get; private set; }
|
||||
|
||||
public Dictionary<string, SerializableProperty> SerializableProperties { get; private set; }
|
||||
public Dictionary<Identifier, SerializableProperty> SerializableProperties { get; private set; }
|
||||
|
||||
public Vector2 Offset;
|
||||
|
||||
public readonly List<Item> ClaimedTargets = new List<Item>();
|
||||
public readonly List<PowerTransfer> ClaimedJunctionBoxes = new List<PowerTransfer>();
|
||||
public readonly List<PowerContainer> ClaimedBatteries = new List<PowerContainer>();
|
||||
public readonly HashSet<Item> ClaimedTargets = new HashSet<Item>();
|
||||
public readonly HashSet<PowerTransfer> ClaimedJunctionBoxes = new HashSet<PowerTransfer>();
|
||||
public readonly HashSet<PowerContainer> ClaimedBatteries = new HashSet<PowerContainer>();
|
||||
public readonly Dictionary<Item, int> IgnoredTargets = new Dictionary<Item, int>();
|
||||
|
||||
private readonly List<Tuple<UInt16, int>> tempClaimedTargets = new List<Tuple<ushort, int>>();
|
||||
@@ -252,11 +286,12 @@ namespace Barotrauma.MapCreatures.Behavior
|
||||
public float PowerConsumptionTimer;
|
||||
|
||||
private float defenseCooldown, toxinsCooldown, fireCheckCooldown;
|
||||
private float damageIndicatorTimer, selfDamageTimer, toxinsTimer;
|
||||
private float selfDamageTimer, toxinsTimer;
|
||||
|
||||
private readonly List<BallastFloraBranch> branchesVulnerableToFire = new List<BallastFloraBranch>();
|
||||
|
||||
public readonly List<BallastFloraBranch> Branches = new List<BallastFloraBranch>();
|
||||
private BallastFloraBranch? root;
|
||||
private readonly List<Body> bodies = new List<Body>();
|
||||
|
||||
public readonly BallastFloraStateMachine StateMachine;
|
||||
@@ -319,15 +354,15 @@ namespace Barotrauma.MapCreatures.Behavior
|
||||
SerializableProperties = SerializableProperty.DeserializeProperties(this, prefab.Element);
|
||||
LoadPrefab(prefab.Element);
|
||||
StateMachine = new BallastFloraStateMachine(this);
|
||||
if (firstGrowth) { GenerateStem(); }
|
||||
if (firstGrowth) { GenerateRoot(); }
|
||||
_entityList.Add(this);
|
||||
}
|
||||
|
||||
partial void LoadPrefab(XElement element);
|
||||
partial void LoadPrefab(ContentXElement element);
|
||||
|
||||
public void LoadTargets(XElement element)
|
||||
public void LoadTargets(ContentXElement element)
|
||||
{
|
||||
foreach (XElement subElement in element.Elements())
|
||||
foreach (var subElement in element.Elements())
|
||||
{
|
||||
Targets.Add(new AITarget(subElement));
|
||||
}
|
||||
@@ -358,6 +393,10 @@ namespace Barotrauma.MapCreatures.Behavior
|
||||
{
|
||||
be.Add(new XAttribute("claimed", (int)(branch.ClaimedItem?.ID ?? -1)));
|
||||
}
|
||||
if (branch.ParentBranch != null)
|
||||
{
|
||||
be.Add(new XAttribute("parentbranch", (int)(branch.ParentBranch?.ID ?? -1)));
|
||||
}
|
||||
|
||||
saveElement.Add(be);
|
||||
}
|
||||
@@ -382,7 +421,7 @@ namespace Barotrauma.MapCreatures.Behavior
|
||||
{
|
||||
SerializableProperties = SerializableProperty.DeserializeProperties(this, element);
|
||||
Offset = element.GetAttributeVector2("offset", Vector2.Zero);
|
||||
foreach (XElement subElement in element.Elements())
|
||||
foreach (var subElement in element.Elements())
|
||||
{
|
||||
switch (subElement.Name.ToString().ToLowerInvariant())
|
||||
{
|
||||
@@ -412,8 +451,15 @@ namespace Barotrauma.MapCreatures.Behavior
|
||||
int sides = getInt("sides");
|
||||
int blockedSides = getInt("blockedsides");
|
||||
int claimedId = branchElement.GetAttributeInt("claimed", -1);
|
||||
int parentBranchId = branchElement.GetAttributeInt("parentbranch", -1);
|
||||
|
||||
BallastFloraBranch newBranch = new BallastFloraBranch(this, pos, VineTileType.CrossJunction, FoliageConfig.Deserialize(flowerConfig), FoliageConfig.Deserialize(leafconfig))
|
||||
BallastFloraBranch? parentBranch = null;
|
||||
if (parentBranchId > -1)
|
||||
{
|
||||
parentBranch = Branches[parentBranchId];
|
||||
}
|
||||
|
||||
BallastFloraBranch newBranch = new BallastFloraBranch(this, parentBranch, pos, VineTileType.CrossJunction, FoliageConfig.Deserialize(flowerConfig), FoliageConfig.Deserialize(leafconfig))
|
||||
{
|
||||
ID = id,
|
||||
Health = health,
|
||||
@@ -422,6 +468,7 @@ namespace Barotrauma.MapCreatures.Behavior
|
||||
BlockedSides = (TileSide) blockedSides,
|
||||
IsRoot = isRoot
|
||||
};
|
||||
if (newBranch.IsRoot) { root = newBranch; }
|
||||
|
||||
if (claimedId > -1)
|
||||
{
|
||||
@@ -437,6 +484,15 @@ namespace Barotrauma.MapCreatures.Behavior
|
||||
|
||||
public void Update(float deltaTime)
|
||||
{
|
||||
if (GameMain.NetworkMember == null || !GameMain.NetworkMember.IsClient)
|
||||
{
|
||||
if (Branches.Count == 0)
|
||||
{
|
||||
Remove();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (BallastFloraBranch branch in Branches)
|
||||
{
|
||||
branch.UpdateScale(deltaTime);
|
||||
@@ -446,38 +502,25 @@ namespace Barotrauma.MapCreatures.Behavior
|
||||
#endif
|
||||
}
|
||||
|
||||
if (damageIndicatorTimer <= 0)
|
||||
{
|
||||
foreach (BallastFloraBranch branch in Branches)
|
||||
{
|
||||
if (branch.AccumulatedDamage > 0)
|
||||
{
|
||||
|
||||
#if CLIENT
|
||||
CreateDamageParticle(branch, branch.AccumulatedDamage);
|
||||
|
||||
if (GameMain.DebugDraw)
|
||||
{
|
||||
var pos = (Parent?.Position ?? Vector2.Zero) + Offset + branch.Position;
|
||||
GUI.AddMessage($"{(int)branch.AccumulatedDamage}", GUI.Style.Red, pos, Vector2.UnitY * 10.0f, 3f, playSound: false, subId: Parent?.Submarine?.ID ?? -1);
|
||||
}
|
||||
#elif SERVER
|
||||
SendNetworkMessage(this, NetworkHeader.BranchDamage, branch, branch.AccumulatedDamage);
|
||||
#endif
|
||||
}
|
||||
|
||||
branch.AccumulatedDamage = 0f;
|
||||
}
|
||||
|
||||
damageIndicatorTimer = 1f;
|
||||
}
|
||||
|
||||
damageIndicatorTimer -= deltaTime;
|
||||
UpdateDamage(deltaTime);
|
||||
|
||||
UpdatePowerDrain(deltaTime);
|
||||
|
||||
if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsClient) { return; }
|
||||
|
||||
if (root != null && HealthRegenPerBranch > 0.0f)
|
||||
{
|
||||
float healAmount = Branches.Count(b => !b.IsRoot && !b.IsRootGrowth && !b.DisconnectedFromRoot) * HealthRegenPerBranch;
|
||||
|
||||
foreach (BallastFloraBranch branch in Branches)
|
||||
{
|
||||
if (branch.Health > branch.MaxHealth * 0.9f || branch.DisconnectedFromRoot) { continue; }
|
||||
float branchHealAmount = (float)(MaxBranchHealthRegenDistance - branch.BranchDepth) / MaxBranchHealthRegenDistance * healAmount;
|
||||
if (branchHealAmount <= 0.0f) { continue; }
|
||||
branch.Health += branchHealAmount;
|
||||
branch.AccumulatedDamage -= branchHealAmount;
|
||||
}
|
||||
}
|
||||
StateMachine.Update(deltaTime);
|
||||
|
||||
if (HasBrokenThrough)
|
||||
@@ -512,12 +555,12 @@ namespace Barotrauma.MapCreatures.Behavior
|
||||
// This entire scope is probably very heavy for GC, need to experiment
|
||||
if (toxinsTimer > 0.1f)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(AttackItemPrefab))
|
||||
if (!AttackItemPrefab.IsEmpty)
|
||||
{
|
||||
Dictionary<Hull, List<BallastFloraBranch>> branches = new Dictionary<Hull, List<BallastFloraBranch>>();
|
||||
foreach (BallastFloraBranch branch in Branches)
|
||||
{
|
||||
if (branch.CurrentHull == null || branch.FlowerConfig.Variant < 0) { continue; }
|
||||
if (branch.CurrentHull == null || branch.FlowerConfig.Variant < 0 || branch.DisconnectedFromRoot) { continue; }
|
||||
|
||||
if (branches.TryGetValue(branch.CurrentHull, out List<BallastFloraBranch>? list))
|
||||
{
|
||||
@@ -534,11 +577,12 @@ namespace Barotrauma.MapCreatures.Behavior
|
||||
List<BallastFloraBranch> list = branches[hull];
|
||||
if (!list.Any(HasAcidEmitter))
|
||||
{
|
||||
BallastFloraBranch randomBranch = branches[hull].GetRandom();
|
||||
BallastFloraBranch randomBranch = branches[hull].GetRandomUnsynced();
|
||||
randomBranch.SpawningItem = true;
|
||||
|
||||
ItemPrefab prefab = ItemPrefab.Find(null, AttackItemPrefab);
|
||||
Entity.Spawner?.AddToSpawnQueue(prefab, Parent.Position + Offset + randomBranch.Position, Parent.Submarine, onSpawned: item =>
|
||||
#warning TODO: Parent needs a nullability sanity check
|
||||
Entity.Spawner?.AddItemToSpawnQueue(prefab, Parent!.Position + Offset + randomBranch.Position, Parent.Submarine, onSpawned: item =>
|
||||
{
|
||||
randomBranch.AttackItem = item;
|
||||
randomBranch.SpawningItem = false;
|
||||
@@ -563,38 +607,49 @@ namespace Barotrauma.MapCreatures.Behavior
|
||||
}
|
||||
}
|
||||
|
||||
partial void UpdateDamage(float deltaTime);
|
||||
|
||||
private readonly List<BallastFloraBranch> toBeRemoved = new List<BallastFloraBranch>();
|
||||
private void UpdateSelfDamage(float deltaTime)
|
||||
{
|
||||
if (selfDamageTimer <= 0)
|
||||
{
|
||||
bool hasRoot = false;
|
||||
foreach (BallastFloraBranch branch in Branches)
|
||||
{
|
||||
if (branch.IsRoot)
|
||||
{
|
||||
hasRoot = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasRoot)
|
||||
{
|
||||
Kill();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!HasBrokenThrough && !CanGrowMore())
|
||||
{
|
||||
Branches.ForEachMod(branch =>
|
||||
{
|
||||
float maxHealth = branch.IsRoot ? StemHealth : BranchHealth;
|
||||
float maxHealth = branch.IsRoot ? RootHealth : BranchHealth;
|
||||
DamageBranch(branch, Rand.Range(1f, maxHealth), AttackType.Other);
|
||||
});
|
||||
}
|
||||
|
||||
selfDamageTimer = 1f;
|
||||
}
|
||||
toBeRemoved.Clear();
|
||||
foreach (BallastFloraBranch branch in Branches)
|
||||
{
|
||||
if (branch.ParentBranch != null && (branch.ParentBranch.DisconnectedFromRoot || branch.ParentBranch.Health <= 0.0f))
|
||||
{
|
||||
DamageBranch(branch, deltaTime * MathHelper.Lerp(10.0f, 0.01f, branch.ParentBranch.Health / branch.ParentBranch.MaxHealth), AttackType.CutFromRoot);
|
||||
}
|
||||
if (branch.Health <= 0.0f)
|
||||
{
|
||||
if (branch.ClaimedItem != null)
|
||||
{
|
||||
RemoveClaim(branch.ClaimedItem);
|
||||
branch.ClaimedItem = null;
|
||||
}
|
||||
|
||||
branch.RemoveTimer -= deltaTime;
|
||||
if (branch.RemoveTimer <= 0.0f)
|
||||
{
|
||||
toBeRemoved.Add(branch);
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach (BallastFloraBranch branch in toBeRemoved)
|
||||
{
|
||||
RemoveBranch(branch);
|
||||
}
|
||||
selfDamageTimer -= deltaTime;
|
||||
}
|
||||
|
||||
@@ -675,20 +730,25 @@ namespace Barotrauma.MapCreatures.Behavior
|
||||
branch.CurrentHull = Hull.FindHull(GetWorldPosition() + branch.Position, Parent, true);
|
||||
}
|
||||
|
||||
private void GenerateStem()
|
||||
private void GenerateRoot()
|
||||
{
|
||||
BallastFloraBranch stem = new BallastFloraBranch(this, Vector2.Zero, VineTileType.Stem, FoliageConfig.EmptyConfig, FoliageConfig.EmptyConfig)
|
||||
if (root != null)
|
||||
{
|
||||
DebugConsole.ThrowError("Error in ballast flora: tried to grow a root even though root has already been created.\n" + Environment.StackTrace);
|
||||
}
|
||||
|
||||
root = new BallastFloraBranch(this, null, Vector2.Zero, VineTileType.Stem, FoliageConfig.EmptyConfig, FoliageConfig.EmptyConfig)
|
||||
{
|
||||
BlockedSides = TileSide.Bottom | TileSide.Left | TileSide.Right,
|
||||
GrowthStep = 1f,
|
||||
Health = StemHealth,
|
||||
MaxHealth = StemHealth,
|
||||
MaxHealth = RootHealth,
|
||||
Health = RootHealth,
|
||||
IsRoot = true,
|
||||
CurrentHull = Parent
|
||||
};
|
||||
|
||||
Branches.Add(stem);
|
||||
CreateBody(stem);
|
||||
|
||||
Branches.Add(root);
|
||||
CreateBody(root);
|
||||
}
|
||||
|
||||
public float GetGrowthSpeed(float deltaTime)
|
||||
@@ -704,19 +764,19 @@ namespace Barotrauma.MapCreatures.Behavior
|
||||
return deltaTime;
|
||||
}
|
||||
|
||||
public bool TryGrowBranch(BallastFloraBranch parent, TileSide side, out List<BallastFloraBranch> result)
|
||||
public bool TryGrowBranch(BallastFloraBranch parent, TileSide side, out List<BallastFloraBranch> result, bool isRootGrowth = false, Vector2? forcePosition = null)
|
||||
{
|
||||
result = new List<BallastFloraBranch>();
|
||||
if (parent.IsSideBlocked(side)) { return false; }
|
||||
if (!isRootGrowth && parent.IsSideBlocked(side)) { return false; }
|
||||
|
||||
Vector2 pos = parent.AdjacentPositions[side];
|
||||
Vector2 pos = forcePosition ?? parent.AdjacentPositions[side];
|
||||
Rectangle rect = VineTile.CreatePlantRect(pos);
|
||||
|
||||
if (CollidesWithWorld(rect))
|
||||
if (CollidesWithWorld(rect, checkOtherBranches: !isRootGrowth))
|
||||
{
|
||||
parent.BlockedSides |= side;
|
||||
parent.FailedGrowthAttempts++;
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
FoliageConfig flowerConfig = FoliageConfig.EmptyConfig;
|
||||
@@ -732,21 +792,22 @@ namespace Barotrauma.MapCreatures.Behavior
|
||||
leafConfig = FoliageConfig.CreateRandomConfig(leafVariants, 0.5f, 1.0f);
|
||||
}
|
||||
|
||||
BallastFloraBranch newBranch = new BallastFloraBranch(this, pos, VineTileType.CrossJunction, flowerConfig, leafConfig, rect)
|
||||
BallastFloraBranch newBranch = new BallastFloraBranch(this, parent, pos, VineTileType.CrossJunction, flowerConfig, leafConfig, rect)
|
||||
{
|
||||
ID = CreateID(),
|
||||
MaxHealth = BranchHealth,
|
||||
Health = BranchHealth,
|
||||
MaxHealth = BranchHealth
|
||||
IsRootGrowth = isRootGrowth
|
||||
};
|
||||
|
||||
SetHull(newBranch);
|
||||
|
||||
if (newBranch.CurrentHull == null || newBranch.CurrentHull.Submarine != Parent.Submarine)
|
||||
{
|
||||
parent.BlockedSides |= side;
|
||||
if (!isRootGrowth) { parent.BlockedSides |= side; }
|
||||
parent.FailedGrowthAttempts++;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
UpdateConnections(newBranch, parent);
|
||||
|
||||
@@ -760,12 +821,28 @@ namespace Barotrauma.MapCreatures.Behavior
|
||||
GrowthWarps--;
|
||||
}
|
||||
|
||||
int rootGrowthCount = Branches.Count(b => b.IsRootGrowth);
|
||||
if (rootGrowthCount < GetDesiredRootGrowthAmount())
|
||||
{
|
||||
if (root != null)
|
||||
{
|
||||
Vector2 rootGrowthPos = Rand.Vector(rootGrowthCount * Rand.Range(3.0f, 5.0f));
|
||||
TryGrowBranch(root, TileSide.None, out List<BallastFloraBranch> newRootGrowth, isRootGrowth: true, forcePosition: rootGrowthPos);
|
||||
}
|
||||
}
|
||||
|
||||
#if SERVER
|
||||
SendNetworkMessage(this, NetworkHeader.BranchCreate, newBranch, parent.ID);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
private int GetDesiredRootGrowthAmount()
|
||||
{
|
||||
if (root == null) { return 0; }
|
||||
return MathHelper.Clamp(Branches.Count(b => !b.IsRootGrowth && b.Health > 0) / 20, 3, 30);
|
||||
}
|
||||
|
||||
public bool BranchContainsTarget(BallastFloraBranch branch, Item target)
|
||||
{
|
||||
Rectangle worldRect = branch.Rect;
|
||||
@@ -894,6 +971,14 @@ namespace Barotrauma.MapCreatures.Behavior
|
||||
public void DamageBranch(BallastFloraBranch branch, float amount, AttackType type, Character? attacker = null)
|
||||
{
|
||||
float damage = amount;
|
||||
|
||||
if (type != AttackType.Other && type != AttackType.CutFromRoot)
|
||||
{
|
||||
branch.DamageVisualizationTimer = 1.0f;
|
||||
}
|
||||
|
||||
if (branch.IsRootGrowth && root != null && root.Health > 0.0f) { return; }
|
||||
|
||||
// damage is handled server side currently
|
||||
if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsClient) { return; }
|
||||
|
||||
@@ -922,12 +1007,10 @@ namespace Barotrauma.MapCreatures.Behavior
|
||||
}
|
||||
}
|
||||
|
||||
branch.AccumulatedDamage += damage;
|
||||
|
||||
branch.Health -= damage;
|
||||
|
||||
if (type != AttackType.Other)
|
||||
if (type != AttackType.Other && type != AttackType.CutFromRoot)
|
||||
{
|
||||
branch.AccumulatedDamage += damage;
|
||||
Anger += damage * 0.001f;
|
||||
}
|
||||
|
||||
@@ -935,30 +1018,13 @@ namespace Barotrauma.MapCreatures.Behavior
|
||||
GameMain.Server?.KarmaManager?.OnBallastFloraDamaged(attacker, damage);
|
||||
#endif
|
||||
|
||||
if (branch.Health < 0)
|
||||
if (branch.Health <= 0 && type != AttackType.CutFromRoot)
|
||||
{
|
||||
RemoveBranch(branch);
|
||||
if (branch.IsRoot) { Kill(); }
|
||||
}
|
||||
}
|
||||
|
||||
public void Remove()
|
||||
{
|
||||
foreach (Body body in bodies)
|
||||
{
|
||||
GameMain.World.Remove(body);
|
||||
}
|
||||
|
||||
Parent.BallastFlora = null;
|
||||
Branches.Clear();
|
||||
|
||||
foreach (Item target in ClaimedTargets)
|
||||
{
|
||||
target.Infector = null;
|
||||
}
|
||||
|
||||
_entityList.Remove(this);
|
||||
}
|
||||
|
||||
public void RemoveBranch(BallastFloraBranch branch)
|
||||
{
|
||||
bool isClient = GameMain.NetworkMember != null && GameMain.NetworkMember.IsClient;
|
||||
@@ -969,6 +1035,21 @@ namespace Barotrauma.MapCreatures.Behavior
|
||||
Branches.Remove(branch);
|
||||
branch.Removed = true;
|
||||
|
||||
bool foundDisconnected = false;
|
||||
do
|
||||
{
|
||||
foundDisconnected = false;
|
||||
foreach (BallastFloraBranch otherBranch in Branches)
|
||||
{
|
||||
if (otherBranch.ParentBranch == null || otherBranch.DisconnectedFromRoot) { continue; }
|
||||
if (otherBranch.ParentBranch.Removed || otherBranch.ParentBranch.DisconnectedFromRoot)
|
||||
{
|
||||
otherBranch.DisconnectedFromRoot = true;
|
||||
foundDisconnected = true;
|
||||
}
|
||||
}
|
||||
} while (foundDisconnected);
|
||||
|
||||
bodies.ForEachMod(body =>
|
||||
{
|
||||
if (body.UserData == branch)
|
||||
@@ -995,11 +1076,21 @@ namespace Barotrauma.MapCreatures.Behavior
|
||||
});
|
||||
|
||||
#if CLIENT
|
||||
CreateDeathParticle(branch);
|
||||
CreateDeathParticle(branch, 1.0f);
|
||||
#endif
|
||||
|
||||
if (isClient) { return; }
|
||||
|
||||
int rootGrowthCount = Branches.Count(b => b.IsRootGrowth);
|
||||
if (rootGrowthCount > GetDesiredRootGrowthAmount())
|
||||
{
|
||||
var rootGrowth = Branches.LastOrDefault(b => b.IsRootGrowth);
|
||||
if (rootGrowth != null)
|
||||
{
|
||||
RemoveBranch(rootGrowth);
|
||||
}
|
||||
}
|
||||
|
||||
if (branch.ClaimedItem != null)
|
||||
{
|
||||
RemoveClaim(branch.ClaimedItem);
|
||||
@@ -1050,8 +1141,10 @@ namespace Barotrauma.MapCreatures.Behavior
|
||||
|
||||
public void Kill()
|
||||
{
|
||||
Branches.ForEachMod(RemoveBranch);
|
||||
Parent.BallastFlora = null;
|
||||
foreach (var branch in Branches)
|
||||
{
|
||||
branch.DisconnectedFromRoot = true;
|
||||
}
|
||||
|
||||
foreach (Item target in ClaimedTargets)
|
||||
{
|
||||
@@ -1059,6 +1152,19 @@ namespace Barotrauma.MapCreatures.Behavior
|
||||
}
|
||||
|
||||
StateMachine?.State?.Exit();
|
||||
#if SERVER
|
||||
SendNetworkMessage(this, NetworkHeader.Kill);
|
||||
#endif
|
||||
}
|
||||
|
||||
public void Remove()
|
||||
{
|
||||
Kill();
|
||||
|
||||
Branches.ForEachMod(RemoveBranch);
|
||||
Branches.Clear();
|
||||
toBeRemoved.Clear();
|
||||
Parent.BallastFlora = null;
|
||||
|
||||
// clean up leftover (can probably be removed)
|
||||
foreach (Body body in bodies)
|
||||
@@ -1067,8 +1173,9 @@ namespace Barotrauma.MapCreatures.Behavior
|
||||
GameMain.World.Remove(body);
|
||||
}
|
||||
|
||||
_entityList.Remove(this);
|
||||
#if SERVER
|
||||
SendNetworkMessage(this, NetworkHeader.Kill);
|
||||
SendNetworkMessage(this, NetworkHeader.Remove);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1093,9 +1200,9 @@ namespace Barotrauma.MapCreatures.Behavior
|
||||
|
||||
private bool CanGrowMore() => Branches.Any(b => b.CanGrowMore());
|
||||
|
||||
private bool CollidesWithWorld(Rectangle rect)
|
||||
private bool CollidesWithWorld(Rectangle rect, bool checkOtherBranches = true)
|
||||
{
|
||||
if (Branches.Any(g => g.Rect.Contains(rect))) { return true; }
|
||||
if (checkOtherBranches && Branches.Any(g => g.Rect.Contains(rect))) { return true; }
|
||||
|
||||
Rectangle worldRect = rect;
|
||||
worldRect.Location = (Parent.Position + Offset).ToPoint() + worldRect.Location;
|
||||
|
||||
@@ -4,125 +4,28 @@ using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
class BallastFloraPrefab : IPrefab, IDisposable
|
||||
class BallastFloraPrefab : Prefab
|
||||
{
|
||||
public string OriginalName { get; }
|
||||
public string Identifier { get; }
|
||||
public string FilePath { get; }
|
||||
public XElement Element { get; }
|
||||
|
||||
public ContentPackage ContentPackage { get; private set; }
|
||||
public LocalizedString DisplayName { get; }
|
||||
public ContentXElement Element { get; }
|
||||
|
||||
public bool Disposed;
|
||||
|
||||
public static readonly PrefabCollection<BallastFloraPrefab> Prefabs = new PrefabCollection<BallastFloraPrefab>();
|
||||
|
||||
private BallastFloraPrefab(XElement element, string filePath, bool isOverride)
|
||||
public BallastFloraPrefab(ContentXElement element, BallastFloraFile file) : base(file, element.GetAttributeIdentifier("identifier", ""))
|
||||
{
|
||||
Identifier = element.GetAttributeString("identifier", "");
|
||||
OriginalName = element.GetAttributeString("name", "");
|
||||
DisplayName = TextManager.Get(Identifier).Fallback(OriginalName);
|
||||
Element = element;
|
||||
FilePath = filePath;
|
||||
Prefabs.Add(this, isOverride);
|
||||
}
|
||||
|
||||
public static BallastFloraPrefab Find(string idenfitier)
|
||||
public static BallastFloraPrefab Find(Identifier identifier)
|
||||
{
|
||||
return !string.IsNullOrWhiteSpace(idenfitier) ? Prefabs.Find(prefab => prefab.Identifier == idenfitier) : null;
|
||||
return Prefabs.ContainsKey(identifier) ? Prefabs[identifier] : null;
|
||||
}
|
||||
|
||||
public static void LoadAll(IEnumerable files)
|
||||
{
|
||||
DebugConsole.Log("Loading map creature prefabs: ");
|
||||
|
||||
foreach (ContentFile file in files) { LoadFromFile(file); }
|
||||
}
|
||||
|
||||
public static void LoadFromFile(ContentFile file)
|
||||
{
|
||||
XDocument doc = XMLExtensions.TryLoadXml(file.Path);
|
||||
|
||||
var rootElement = doc?.Root;
|
||||
if (rootElement == null) { return; }
|
||||
|
||||
switch (rootElement.Name.ToString().ToLowerInvariant())
|
||||
{
|
||||
case "ballastflorabehavior":
|
||||
{
|
||||
new BallastFloraPrefab(rootElement, file.Path, false) { ContentPackage = file.ContentPackage };
|
||||
break;
|
||||
}
|
||||
case "ballastflorabehaviors":
|
||||
{
|
||||
foreach (var element in rootElement.Elements())
|
||||
{
|
||||
if (element.IsOverride())
|
||||
{
|
||||
XElement upgradeElement = element.GetChildElement("mapcreature");
|
||||
if (upgradeElement != null)
|
||||
{
|
||||
new BallastFloraPrefab(upgradeElement, file.Path, true) { ContentPackage = file.ContentPackage };
|
||||
}
|
||||
else
|
||||
{
|
||||
DebugConsole.ThrowError($"Cannot find a map creature element from the children of the override element defined in {file.Path}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (element.Name.ToString().Equals("mapcreature", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
new BallastFloraPrefab(element, file.Path, false) { ContentPackage = file.ContentPackage };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case "override":
|
||||
{
|
||||
XElement mapCreatures = rootElement.GetChildElement("ballastflorabehaviors");
|
||||
if (mapCreatures != null)
|
||||
{
|
||||
foreach (XElement element in mapCreatures.Elements())
|
||||
{
|
||||
new BallastFloraPrefab(element, file.Path, true) { ContentPackage = file.ContentPackage };
|
||||
}
|
||||
}
|
||||
|
||||
foreach (XElement element in rootElement.GetChildElements("ballastflorabehavior"))
|
||||
{
|
||||
new BallastFloraPrefab(element, file.Path, true) { ContentPackage = file.ContentPackage };
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
DebugConsole.ThrowError($"Invalid XML root element: '{rootElement.Name}' in {file.Path}\n " +
|
||||
"Valid elements are: \"MapCreature\", \"MapCreatures\" and \"Override\".");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void Dispose(bool disposing)
|
||||
{
|
||||
if (!Disposed)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
Prefabs.Remove(this);
|
||||
}
|
||||
}
|
||||
|
||||
Disposed = true;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
public override void Dispose() { }
|
||||
}
|
||||
}
|
||||
@@ -18,7 +18,7 @@ namespace Barotrauma.MapCreatures.Behavior
|
||||
private bool tryDrown;
|
||||
private readonly Character attacker;
|
||||
|
||||
public DefendWithPumpState(BallastFloraBranch branch, List<Item> items, Character attacker)
|
||||
public DefendWithPumpState(BallastFloraBranch branch, IEnumerable<Item> items, Character attacker)
|
||||
{
|
||||
targetBranch = branch;
|
||||
this.attacker = attacker;
|
||||
|
||||
@@ -59,11 +59,14 @@ namespace Barotrauma.MapCreatures.Behavior
|
||||
|
||||
protected virtual void Grow()
|
||||
{
|
||||
List<BallastFloraBranch> newTiles = GrowRandomly();
|
||||
List<BallastFloraBranch> newBranches = GrowRandomly();
|
||||
#if DEBUG
|
||||
Behavior.debugSearchLines.Clear();
|
||||
#endif
|
||||
if (newTiles.Any(TryScanTargets)) { return; }
|
||||
foreach (var branch in newBranches)
|
||||
{
|
||||
TryScanTargets(branch);
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateIgnoredTargets()
|
||||
@@ -85,23 +88,20 @@ namespace Barotrauma.MapCreatures.Behavior
|
||||
|
||||
private List<BallastFloraBranch> GrowRandomly()
|
||||
{
|
||||
List<BallastFloraBranch> newBranches = new List<BallastFloraBranch>();
|
||||
List<BallastFloraBranch> newList = new List<BallastFloraBranch>(Behavior.Branches);
|
||||
foreach (BallastFloraBranch branch in newList)
|
||||
{
|
||||
if (branch.FailedGrowthAttempts > 8 || !branch.CanGrowMore()) { continue; }
|
||||
List<BallastFloraBranch> availableBranches = Behavior.Branches.Where(b => !b.DisconnectedFromRoot && b.FailedGrowthAttempts <= 8 && b.CanGrowMore()).ToList();
|
||||
if (availableBranches.Count == 0) { return availableBranches; }
|
||||
|
||||
if (Rand.Range(0, Behavior.Branches.Count(tile => tile.CanGrowMore())) != 0) { continue; }
|
||||
//prefer growing from the branches furthest from the root (ones with the largest branch depth)
|
||||
var branch = ToolBox.SelectWeightedRandom(availableBranches, b => (float)b.BranchDepth, Rand.RandSync.Unsynced);
|
||||
|
||||
TileSide side = branch.GetRandomFreeSide();
|
||||
TileSide side = branch.GetRandomFreeSide();
|
||||
if (side == TileSide.None) { return availableBranches; }
|
||||
|
||||
if (side == TileSide.None) { continue; }
|
||||
Behavior.TryGrowBranch(branch, side, out List<BallastFloraBranch> result);
|
||||
availableBranches.Clear();
|
||||
availableBranches.Add(branch);
|
||||
|
||||
Behavior.TryGrowBranch(branch, side, out List<BallastFloraBranch> result);
|
||||
newBranches.AddRange(result);
|
||||
}
|
||||
|
||||
return newBranches;
|
||||
return availableBranches;
|
||||
}
|
||||
|
||||
private Item? ScanForTargets(VineTile branch)
|
||||
@@ -117,22 +117,22 @@ namespace Barotrauma.MapCreatures.Behavior
|
||||
int highestPriority = 0;
|
||||
Item? currentItem = null;
|
||||
|
||||
foreach (Item item in Item.ItemList.Where(it => !Behavior.ClaimedTargets.Contains(it)))
|
||||
foreach (Item item in Item.ItemList)
|
||||
{
|
||||
if (item.Submarine != parent.Submarine || Vector2.DistanceSquared(worldPos, item.WorldPosition) > Behavior.Sight * Behavior.Sight) { continue; }
|
||||
if (Behavior.ClaimedTargets.Contains(item)) { continue; }
|
||||
if (Behavior.IgnoredTargets.ContainsKey(item)) { continue; }
|
||||
|
||||
int priority = 0;
|
||||
foreach (BallastFloraBehavior.AITarget target in Behavior.Targets)
|
||||
{
|
||||
if (!target.Matches(item) || target.Priority <= highestPriority) { continue; }
|
||||
if (target.Priority <= highestPriority || !target.Matches(item)) { continue; }
|
||||
priority = target.Priority;
|
||||
break;
|
||||
}
|
||||
|
||||
if (priority == 0) { continue; }
|
||||
|
||||
if (item.Submarine != parent.Submarine || Vector2.Distance(worldPos, item.WorldPosition) > Behavior.Sight) { continue; }
|
||||
|
||||
Vector2 itemSimPos = ConvertUnits.ToSimUnits(item.Position);
|
||||
|
||||
#if DEBUG
|
||||
@@ -156,6 +156,7 @@ namespace Barotrauma.MapCreatures.Behavior
|
||||
{
|
||||
foreach (BallastFloraBranch existingBranch in Behavior.Branches)
|
||||
{
|
||||
if (existingBranch.Health <= 0 || existingBranch.IsRootGrowth) { continue; }
|
||||
if (Behavior.BranchContainsTarget(existingBranch, currentItem))
|
||||
{
|
||||
Behavior.ClaimTarget(currentItem, existingBranch);
|
||||
|
||||
@@ -53,7 +53,7 @@ namespace Barotrauma.MapCreatures.Behavior
|
||||
List<BallastFloraBranch> newList = new List<BallastFloraBranch>(TargetBranches);
|
||||
foreach (BallastFloraBranch branch in newList)
|
||||
{
|
||||
if (branch.FailedGrowthAttempts > 8 || !branch.CanGrowMore()) { continue; }
|
||||
if (branch.FailedGrowthAttempts > 8 || branch.DisconnectedFromRoot || !branch.CanGrowMore()) { continue; }
|
||||
|
||||
// Get what side gets us closest to the target
|
||||
TileSide side = GetClosestSide(branch, Target.WorldPosition);
|
||||
|
||||
Reference in New Issue
Block a user