Merge branch 'master' of https://github.com/Regalis11/Barotrauma.git into Regalis11-master

This commit is contained in:
Evil Factory
2021-10-27 14:41:47 -03:00
450 changed files with 26043 additions and 10457 deletions
@@ -12,6 +12,7 @@ using System.Xml.Linq;
using Barotrauma.Extensions;
using Barotrauma.MapCreatures.Behavior;
using MoonSharp.Interpreter;
using Barotrauma.Abilities;
#if CLIENT
using Microsoft.Xna.Framework.Graphics;
@@ -37,7 +38,6 @@ namespace Barotrauma
set
{
currentHull = value;
ParentRuin = currentHull?.ParentRuin;
}
}
@@ -98,14 +98,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;
@@ -232,7 +234,6 @@ namespace Barotrauma
{
if (character != null && character.IsOnPlayerTeam)
{
return IsPlayerTeamInteractable;
}
else
@@ -254,6 +255,12 @@ namespace Barotrauma
{
if (!Prefab.AllowRotatingInEditor) { return; }
rotationRad = MathHelper.ToRadians(value);
#if CLIENT
if (Screen.Selected == GameMain.SubEditorScreen)
{
SetContainedItemPositions();
}
#endif
}
}
@@ -449,7 +456,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;
@@ -467,10 +474,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,
@@ -541,6 +554,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; }
@@ -614,6 +633,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
@@ -768,6 +802,8 @@ namespace Barotrauma
condition = MaxCondition;
lastSentCondition = condition;
AllowDeconstruct = itemPrefab.AllowDeconstruct;
allPropertyObjects.Add(this);
XElement element = itemPrefab.ConfigElement;
@@ -927,6 +963,8 @@ namespace Barotrauma
ownInventory = itemContainer.Inventory;
}
qualityComponent = GetComponent<Quality>();
InitProjSpecific();
if (callOnItemLoaded)
@@ -944,6 +982,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();
@@ -1116,7 +1157,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);
@@ -1278,7 +1324,7 @@ namespace Barotrauma
}
Submarine = parentInventory.Owner.Submarine;
if (body != null) body.Submarine = Submarine;
if (body != null) { body.Submarine = Submarine; }
return CurrentHull;
}
@@ -1432,7 +1478,7 @@ namespace Barotrauma
bool hasTargets = effect.TargetIdentifiers == null;
targets.Clear();
if (effect.HasTargetType(StatusEffect.TargetType.Contained))
{
foreach (Item containedItem in ContainedItems)
@@ -1444,6 +1490,11 @@ namespace Barotrauma
continue;
}
if (effect.TargetSlot > -1)
{
if (OwnInventory.FindIndex(containedItem) != effect.TargetSlot) { continue; }
}
hasTargets = true;
targets.Add(containedItem);
}
@@ -1501,8 +1552,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);
}
@@ -1562,7 +1613,10 @@ namespace Barotrauma
}
}
aiTarget?.Update(deltaTime);
if (aiTarget != null)
{
aiTarget.Update(deltaTime);
}
GameMain.Lua.hook.Call("itemThink." + prefab.Identifier, new object[] { this, deltaTime });
@@ -1682,10 +1736,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)
{
@@ -1752,7 +1814,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);
@@ -1763,6 +1825,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);
@@ -1822,7 +1890,8 @@ namespace Barotrauma
foreach (ItemComponent component in components)
{
component.FlipX(relativeToSub);
}
}
SetContainedItemPositions();
}
public override void FlipY(bool relativeToSub)
@@ -1847,6 +1916,7 @@ namespace Barotrauma
{
component.FlipY(relativeToSub);
}
SetContainedItemPositions();
}
/// <summary>
@@ -1906,17 +1976,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
@@ -1952,20 +2022,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; }
@@ -1975,18 +2045,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;
}
@@ -2058,8 +2137,6 @@ namespace Barotrauma
} while (CoroutineManager.DeltaTime <= 0.0f);
delayedSignals.Remove((signal, connection));
signal.source = this;
connection.SendSignal(signal);
yield return CoroutineStatus.Success;
@@ -2313,8 +2390,8 @@ namespace Barotrauma
return;
//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)
@@ -2324,10 +2401,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;
@@ -2336,7 +2415,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)
{
@@ -2346,9 +2437,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); }
}
@@ -2424,6 +2524,8 @@ namespace Barotrauma
parentInventory.RemoveItem(this);
parentInventory = null;
}
SetContainedItemPositions();
}
public void Equip(Character character)
@@ -2542,6 +2644,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");
@@ -2649,6 +2759,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();
@@ -2684,7 +2807,7 @@ namespace Barotrauma
{
CoroutineManager.StopCoroutines(logPropertyChangeCoroutine);
}
logPropertyChangeCoroutine = CoroutineManager.InvokeAfter(() =>
logPropertyChangeCoroutine = CoroutineManager.Invoke(() =>
{
if(sender.Character != null)
GameServer.Log($"{sender.Character.Name} set the value \"{property.Name}\" of the item \"{Name}\" to \"{logValue}\".", ServerLog.MessageType.ItemInteraction);
@@ -3074,6 +3197,8 @@ namespace Barotrauma
}
}
connections?.Clear();
if (parentInventory != null)
{
if (parentInventory is CharacterInventory characterInventory)
@@ -3099,6 +3224,8 @@ namespace Barotrauma
body = null;
}
CurrentHull = null;
if (StaticFixtures != null)
{
foreach (Fixture fixture in StaticFixtures)