Release v0.15.12.0
This commit is contained in:
@@ -11,6 +11,7 @@ using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
using Barotrauma.Extensions;
|
||||
using Barotrauma.MapCreatures.Behavior;
|
||||
using Barotrauma.Abilities;
|
||||
|
||||
#if CLIENT
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
@@ -36,7 +37,6 @@ namespace Barotrauma
|
||||
set
|
||||
{
|
||||
currentHull = value;
|
||||
ParentRuin = currentHull?.ParentRuin;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,14 +97,16 @@ namespace Barotrauma
|
||||
|
||||
private Dictionary<string, Connection> connections;
|
||||
|
||||
private List<Repairable> repairables;
|
||||
private readonly List<Repairable> repairables;
|
||||
|
||||
private Queue<float> impactQueue = new Queue<float>();
|
||||
private Quality qualityComponent;
|
||||
|
||||
private readonly Queue<float> impactQueue = new Queue<float>();
|
||||
|
||||
//a dictionary containing lists of the status effects in all the components of the item
|
||||
private bool[] hasStatusEffectsOfType;
|
||||
private Dictionary<ActionType, List<StatusEffect>> statusEffectLists;
|
||||
|
||||
private readonly bool[] hasStatusEffectsOfType;
|
||||
private readonly Dictionary<ActionType, List<StatusEffect>> statusEffectLists;
|
||||
|
||||
public Dictionary<string, SerializableProperty> SerializableProperties { get; protected set; }
|
||||
|
||||
private bool? hasInGameEditableProperties;
|
||||
@@ -231,7 +233,6 @@ namespace Barotrauma
|
||||
{
|
||||
if (character != null && character.IsOnPlayerTeam)
|
||||
{
|
||||
|
||||
return IsPlayerTeamInteractable;
|
||||
}
|
||||
else
|
||||
@@ -253,6 +254,12 @@ namespace Barotrauma
|
||||
{
|
||||
if (!Prefab.AllowRotatingInEditor) { return; }
|
||||
rotationRad = MathHelper.ToRadians(value);
|
||||
#if CLIENT
|
||||
if (Screen.Selected == GameMain.SubEditorScreen)
|
||||
{
|
||||
SetContainedItemPositions();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -448,7 +455,7 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
public bool IsFullCondition => MathUtils.NearlyEqual(Condition, MaxCondition);
|
||||
public float MaxCondition => Prefab.Health * healthMultiplier;
|
||||
public float MaxCondition => Prefab.Health * healthMultiplier * maxRepairConditionMultiplier * (1.0f + GetQualityModifier(Items.Components.Quality.StatType.Condition));
|
||||
public float ConditionPercentage => MathUtils.Percentage(Condition, MaxCondition);
|
||||
|
||||
private float offsetOnSelectedMultiplier = 1.0f;
|
||||
@@ -466,10 +473,16 @@ namespace Barotrauma
|
||||
public float HealthMultiplier
|
||||
{
|
||||
get => healthMultiplier;
|
||||
set
|
||||
{
|
||||
healthMultiplier = value;
|
||||
}
|
||||
set { healthMultiplier = MathHelper.Clamp(value, 0.0f, float.PositiveInfinity); }
|
||||
}
|
||||
|
||||
private float maxRepairConditionMultiplier = 1.0f;
|
||||
|
||||
[Serialize(1.0f, true)]
|
||||
public float MaxRepairConditionMultiplier
|
||||
{
|
||||
get => maxRepairConditionMultiplier;
|
||||
set { maxRepairConditionMultiplier = MathHelper.Clamp(value, 0.0f, float.PositiveInfinity); }
|
||||
}
|
||||
|
||||
//the default value should be Prefab.Health, but because we can't use it in the attribute,
|
||||
@@ -540,6 +553,12 @@ namespace Barotrauma
|
||||
set => indestructible = value;
|
||||
}
|
||||
|
||||
public bool AllowDeconstruct
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
[Editable, Serialize(false, isSaveable: true, "When enabled will prevent the item from taking damage from all sources")]
|
||||
public bool InvulnerableToDamage { get; set; }
|
||||
|
||||
@@ -613,6 +632,21 @@ namespace Barotrauma
|
||||
get { return Prefab.UseInHealthInterface; }
|
||||
}
|
||||
|
||||
public int Quality
|
||||
{
|
||||
get
|
||||
{
|
||||
return qualityComponent?.QualityLevel ?? 0;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (qualityComponent != null)
|
||||
{
|
||||
qualityComponent.QualityLevel = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool InWater
|
||||
{
|
||||
get
|
||||
@@ -767,6 +801,8 @@ namespace Barotrauma
|
||||
condition = MaxCondition;
|
||||
lastSentCondition = condition;
|
||||
|
||||
AllowDeconstruct = itemPrefab.AllowDeconstruct;
|
||||
|
||||
allPropertyObjects.Add(this);
|
||||
|
||||
XElement element = itemPrefab.ConfigElement;
|
||||
@@ -926,6 +962,8 @@ namespace Barotrauma
|
||||
ownInventory = itemContainer.Inventory;
|
||||
}
|
||||
|
||||
qualityComponent = GetComponent<Quality>();
|
||||
|
||||
InitProjSpecific();
|
||||
|
||||
if (callOnItemLoaded)
|
||||
@@ -943,6 +981,9 @@ namespace Barotrauma
|
||||
|
||||
if (Components.Any(ic => ic is Wire) && Components.All(ic => ic is Wire || ic is Holdable)) { isWire = true; }
|
||||
if (HasTag("logic")) { isLogic = true; }
|
||||
|
||||
ApplyStatusEffects(ActionType.OnSpawn, 1.0f);
|
||||
Components.ForEach(c => c.ApplyStatusEffects(ActionType.OnSpawn, 1.0f));
|
||||
}
|
||||
|
||||
partial void InitProjSpecific();
|
||||
@@ -1115,7 +1156,12 @@ namespace Barotrauma
|
||||
if (!componentsByType.ContainsKey(typeof(T))) { return Enumerable.Empty<T>(); }
|
||||
return components.Where(c => c is T).Cast<T>();
|
||||
}
|
||||
|
||||
|
||||
public float GetQualityModifier(Quality.StatType statType)
|
||||
{
|
||||
return GetComponent<Quality>()?.GetValue(statType) ?? 0.0f;
|
||||
}
|
||||
|
||||
public void RemoveContained(Item contained)
|
||||
{
|
||||
ownInventory?.RemoveItem(contained);
|
||||
@@ -1277,7 +1323,7 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
Submarine = parentInventory.Owner.Submarine;
|
||||
if (body != null) body.Submarine = Submarine;
|
||||
if (body != null) { body.Submarine = Submarine; }
|
||||
|
||||
return CurrentHull;
|
||||
}
|
||||
@@ -1431,7 +1477,7 @@ namespace Barotrauma
|
||||
bool hasTargets = effect.TargetIdentifiers == null;
|
||||
|
||||
targets.Clear();
|
||||
|
||||
|
||||
if (effect.HasTargetType(StatusEffect.TargetType.Contained))
|
||||
{
|
||||
foreach (Item containedItem in ContainedItems)
|
||||
@@ -1443,6 +1489,11 @@ namespace Barotrauma
|
||||
continue;
|
||||
}
|
||||
|
||||
if (effect.TargetSlot > -1)
|
||||
{
|
||||
if (OwnInventory.FindIndex(containedItem) != effect.TargetSlot) { continue; }
|
||||
}
|
||||
|
||||
hasTargets = true;
|
||||
targets.Add(containedItem);
|
||||
}
|
||||
@@ -1500,8 +1551,8 @@ namespace Barotrauma
|
||||
{
|
||||
targets.Add(limb);
|
||||
}
|
||||
|
||||
if (Container != null && effect.HasTargetType(StatusEffect.TargetType.Parent)) targets.Add(Container);
|
||||
|
||||
if (Container != null && effect.HasTargetType(StatusEffect.TargetType.Parent)) { targets.Add(Container); }
|
||||
|
||||
effect.Apply(type, deltaTime, this, targets, worldPosition);
|
||||
}
|
||||
@@ -1561,7 +1612,10 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
aiTarget?.Update(deltaTime);
|
||||
if (aiTarget != null)
|
||||
{
|
||||
aiTarget.Update(deltaTime);
|
||||
}
|
||||
|
||||
if (!isActive) { return; }
|
||||
|
||||
@@ -1679,10 +1733,18 @@ namespace Barotrauma
|
||||
public void UpdateTransform()
|
||||
{
|
||||
if (body == null) { return; }
|
||||
|
||||
Submarine prevSub = Submarine;
|
||||
|
||||
FindHull();
|
||||
var projectile = GetComponent<Projectile>();
|
||||
if (projectile?.StickTarget?.UserData is Limb limb)
|
||||
{
|
||||
Submarine = body.Submarine = limb.character?.Submarine;
|
||||
currentHull = limb.character?.CurrentHull;
|
||||
}
|
||||
else
|
||||
{
|
||||
FindHull();
|
||||
}
|
||||
|
||||
if (Submarine == null && prevSub != null)
|
||||
{
|
||||
@@ -1749,7 +1811,7 @@ namespace Barotrauma
|
||||
|
||||
Vector2 drag = body.LinearVelocity * volume;
|
||||
|
||||
body.ApplyForce((uplift - drag) * 10.0f, maxVelocity: NetConfig.MaxPhysicsBodyVelocity);
|
||||
body.ApplyForce((uplift - drag) * 10.0f);
|
||||
|
||||
//apply simple angular drag
|
||||
body.ApplyTorque(body.AngularVelocity * volume * -0.05f);
|
||||
@@ -1760,6 +1822,12 @@ namespace Barotrauma
|
||||
{
|
||||
if (transformDirty) { return false; }
|
||||
|
||||
var projectile = GetComponent<Projectile>();
|
||||
if (projectile?.IgnoredBodies != null)
|
||||
{
|
||||
if (projectile.IgnoredBodies.Contains(f2.Body)) { return false; }
|
||||
}
|
||||
|
||||
contact.GetWorldManifold(out Vector2 normal, out _);
|
||||
if (contact.FixtureA.Body == f1.Body) { normal = -normal; }
|
||||
float impact = Vector2.Dot(f1.Body.LinearVelocity, -normal);
|
||||
@@ -1819,7 +1887,8 @@ namespace Barotrauma
|
||||
foreach (ItemComponent component in components)
|
||||
{
|
||||
component.FlipX(relativeToSub);
|
||||
}
|
||||
}
|
||||
SetContainedItemPositions();
|
||||
}
|
||||
|
||||
public override void FlipY(bool relativeToSub)
|
||||
@@ -1844,6 +1913,7 @@ namespace Barotrauma
|
||||
{
|
||||
component.FlipY(relativeToSub);
|
||||
}
|
||||
SetContainedItemPositions();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1903,17 +1973,17 @@ namespace Barotrauma
|
||||
|
||||
return connectedComponents;
|
||||
}
|
||||
|
||||
public static readonly Pair<string, string>[] connectionPairs = new Pair<string, string>[]
|
||||
|
||||
public static readonly (string input, string output)[] connectionPairs = new (string input, string output)[]
|
||||
{
|
||||
new Pair<string, string>("power_in", "power_out"),
|
||||
new Pair<string, string>("signal_in1", "signal_out1"),
|
||||
new Pair<string, string>("signal_in2", "signal_out2"),
|
||||
new Pair<string, string>("signal_in3", "signal_out3"),
|
||||
new Pair<string, string>("signal_in4", "signal_out4"),
|
||||
new Pair<string, string>("signal_in", "signal_out"),
|
||||
new Pair<string, string>("signal_in1", "signal_out"),
|
||||
new Pair<string, string>("signal_in2", "signal_out")
|
||||
("power_in", "power_out"),
|
||||
("signal_in1", "signal_out1"),
|
||||
("signal_in2", "signal_out2"),
|
||||
("signal_in3", "signal_out3"),
|
||||
("signal_in4", "signal_out4"),
|
||||
("signal_in", "signal_out"),
|
||||
("signal_in1", "signal_out"),
|
||||
("signal_in2", "signal_out")
|
||||
};
|
||||
|
||||
private void GetConnectedComponentsRecursive<T>(Connection c, HashSet<Connection> alreadySearched, List<T> connectedComponents) where T : ItemComponent
|
||||
@@ -1949,20 +2019,20 @@ namespace Barotrauma
|
||||
recipient.Item.GetConnectedComponentsRecursive(recipient, alreadySearched, connectedComponents);
|
||||
}
|
||||
|
||||
foreach (Pair<string, string> connectionPair in connectionPairs)
|
||||
foreach ((string input, string output) in connectionPairs)
|
||||
{
|
||||
if (connectionPair.First == c.Name)
|
||||
if (input == c.Name)
|
||||
{
|
||||
var pairedConnection = c.Item.Connections.FirstOrDefault(c2 => c2.Name == connectionPair.Second);
|
||||
var pairedConnection = c.Item.Connections.FirstOrDefault(c2 => c2.Name == output);
|
||||
if (pairedConnection != null)
|
||||
{
|
||||
if (alreadySearched.Contains(pairedConnection)) { continue; }
|
||||
GetConnectedComponentsRecursive(pairedConnection, alreadySearched, connectedComponents);
|
||||
}
|
||||
}
|
||||
else if (connectionPair.Second == c.Name)
|
||||
else if (output == c.Name)
|
||||
{
|
||||
var pairedConnection = c.Item.Connections.FirstOrDefault(c2 => c2.Name == connectionPair.First);
|
||||
var pairedConnection = c.Item.Connections.FirstOrDefault(c2 => c2.Name == input);
|
||||
if (pairedConnection != null)
|
||||
{
|
||||
if (alreadySearched.Contains(pairedConnection)) { continue; }
|
||||
@@ -1972,18 +2042,27 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public Controller FindController()
|
||||
public Controller FindController(string[] tags = null)
|
||||
{
|
||||
//try finding the controller with the simpler non-recursive method first
|
||||
var controllers = GetConnectedComponents<Controller>();
|
||||
if (controllers.None()) { controllers = GetConnectedComponents<Controller>(recursive: true); }
|
||||
return controllers.Count < 2 ? controllers.FirstOrDefault() :
|
||||
(controllers.FirstOrDefault(c => c.GetFocusTarget() == this) ?? controllers.FirstOrDefault());
|
||||
bool needsTag = tags != null && tags.Length > 0;
|
||||
if (controllers.None() || (needsTag && controllers.None(c => c.Item.HasTag(tags))))
|
||||
{
|
||||
controllers = GetConnectedComponents<Controller>(recursive: true);
|
||||
}
|
||||
if (needsTag)
|
||||
{
|
||||
controllers.RemoveAll(c => !c.Item.HasTag(tags));
|
||||
}
|
||||
return controllers.Count < 2 ?
|
||||
controllers.FirstOrDefault() :
|
||||
controllers.FirstOrDefault(c => c.GetFocusTarget() == this) ?? controllers.FirstOrDefault();
|
||||
}
|
||||
|
||||
public bool TryFindController(out Controller controller)
|
||||
public bool TryFindController(out Controller controller, string[] tags = null)
|
||||
{
|
||||
controller = FindController();
|
||||
controller = FindController(tags: tags);
|
||||
return controller != null;
|
||||
}
|
||||
|
||||
@@ -2055,8 +2134,6 @@ namespace Barotrauma
|
||||
} while (CoroutineManager.DeltaTime <= 0.0f);
|
||||
|
||||
delayedSignals.Remove((signal, connection));
|
||||
|
||||
signal.source = this;
|
||||
connection.SendSignal(signal);
|
||||
|
||||
yield return CoroutineStatus.Success;
|
||||
@@ -2289,8 +2366,8 @@ namespace Barotrauma
|
||||
public void ApplyTreatment(Character user, Character character, Limb targetLimb)
|
||||
{
|
||||
//can't apply treatment to dead characters
|
||||
if (character.IsDead) return;
|
||||
if (!UseInHealthInterface) return;
|
||||
if (character.IsDead) { return; }
|
||||
if (!UseInHealthInterface) { return; }
|
||||
|
||||
#if CLIENT
|
||||
if (GameMain.Client != null)
|
||||
@@ -2300,10 +2377,12 @@ namespace Barotrauma
|
||||
}
|
||||
#endif
|
||||
|
||||
float applyOnSelfFraction = user?.GetStatValue(StatTypes.ApplyTreatmentsOnSelfFraction) ?? 0.0f;
|
||||
|
||||
bool remove = false;
|
||||
foreach (ItemComponent ic in components)
|
||||
{
|
||||
if (!ic.HasRequiredContainedItems(user, addMessage: user == Character.Controlled)) continue;
|
||||
if (!ic.HasRequiredContainedItems(user, addMessage: user == Character.Controlled)) { continue; }
|
||||
|
||||
bool success = Rand.Range(0.0f, 0.5f) < ic.DegreeOfSuccess(user);
|
||||
ActionType actionType = success ? ActionType.OnUse : ActionType.OnFailure;
|
||||
@@ -2312,7 +2391,19 @@ namespace Barotrauma
|
||||
ic.PlaySound(actionType, user);
|
||||
#endif
|
||||
ic.WasUsed = true;
|
||||
ic.ApplyStatusEffects(actionType, 1.0f, character, targetLimb, user: user);
|
||||
ic.ApplyStatusEffects(actionType, 1.0f, character, targetLimb, user: user, applyOnUserFraction: applyOnSelfFraction);
|
||||
|
||||
if (applyOnSelfFraction > 0.0f)
|
||||
{
|
||||
//hacky af
|
||||
ic.statusEffectLists.TryGetValue(actionType, out var effectList);
|
||||
if (effectList != null)
|
||||
{
|
||||
effectList.ForEach(e => e.AfflictionMultiplier = applyOnSelfFraction);
|
||||
ic.ApplyStatusEffects(actionType, 1.0f, user, targetLimb == null ? null : user.AnimController.GetLimb(targetLimb.type), user: user);
|
||||
effectList.ForEach(e => e.AfflictionMultiplier = 1.0f);
|
||||
}
|
||||
}
|
||||
|
||||
if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsServer)
|
||||
{
|
||||
@@ -2322,9 +2413,18 @@ namespace Barotrauma
|
||||
});
|
||||
}
|
||||
|
||||
if (ic.DeleteOnUse) remove = true;
|
||||
if (ic.DeleteOnUse) { remove = true; }
|
||||
}
|
||||
|
||||
if (user != null)
|
||||
{
|
||||
var abilityItem = new AbilityApplyTreatment(user, character, this);
|
||||
user.CheckTalents(AbilityEffectType.OnApplyTreatment, abilityItem);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (remove) { Spawner?.AddToRemoveQueue(this); }
|
||||
}
|
||||
|
||||
@@ -2390,6 +2490,8 @@ namespace Barotrauma
|
||||
parentInventory.RemoveItem(this);
|
||||
parentInventory = null;
|
||||
}
|
||||
|
||||
SetContainedItemPositions();
|
||||
}
|
||||
|
||||
public void Equip(Character character)
|
||||
@@ -2498,6 +2600,14 @@ namespace Barotrauma
|
||||
{
|
||||
msg.Write((int)value);
|
||||
}
|
||||
else if (value is string[] a)
|
||||
{
|
||||
msg.Write(a.Length);
|
||||
for (int i = 0; i < a.Length; i++)
|
||||
{
|
||||
msg.Write(a[i] ?? "");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotImplementedException("Serializing item properties of the type \"" + value.GetType() + "\" not supported");
|
||||
@@ -2605,6 +2715,19 @@ namespace Barotrauma
|
||||
logValue = XMLExtensions.RectToString(val);
|
||||
if (allowEditing) { property.TrySetValue(parentObject, val); }
|
||||
}
|
||||
else if (type == typeof(string[]))
|
||||
{
|
||||
int arrayLength = msg.ReadInt32();
|
||||
string[] val = new string[arrayLength];
|
||||
for (int i = 0; i < arrayLength; i++)
|
||||
{
|
||||
val[i] = msg.ReadString();
|
||||
}
|
||||
if (allowEditing)
|
||||
{
|
||||
property.TrySetValue(parentObject, val);
|
||||
}
|
||||
}
|
||||
else if (typeof(Enum).IsAssignableFrom(type))
|
||||
{
|
||||
int intVal = msg.ReadInt32();
|
||||
@@ -2640,7 +2763,7 @@ namespace Barotrauma
|
||||
{
|
||||
CoroutineManager.StopCoroutines(logPropertyChangeCoroutine);
|
||||
}
|
||||
logPropertyChangeCoroutine = CoroutineManager.InvokeAfter(() =>
|
||||
logPropertyChangeCoroutine = CoroutineManager.Invoke(() =>
|
||||
{
|
||||
GameServer.Log($"{sender.Character.Name} set the value \"{property.Name}\" of the item \"{Name}\" to \"{logValue}\".", ServerLog.MessageType.ItemInteraction);
|
||||
}, delay: 1.0f);
|
||||
@@ -3029,6 +3152,8 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
connections?.Clear();
|
||||
|
||||
if (parentInventory != null)
|
||||
{
|
||||
if (parentInventory is CharacterInventory characterInventory)
|
||||
@@ -3054,6 +3179,8 @@ namespace Barotrauma
|
||||
body = null;
|
||||
}
|
||||
|
||||
CurrentHull = null;
|
||||
|
||||
if (StaticFixtures != null)
|
||||
{
|
||||
foreach (Fixture fixture in StaticFixtures)
|
||||
|
||||
Reference in New Issue
Block a user