Unstable v0.1300.0.0 (February 19th 2021)

This commit is contained in:
Joonas Rikkonen
2021-02-25 13:44:23 +02:00
parent b772654326
commit 24cbef485a
441 changed files with 21343 additions and 8562 deletions
@@ -52,15 +52,18 @@ namespace Barotrauma.Items.Components
sealed public override void Update(float deltaTime, Camera cam)
{
bool deactivate = true;
bool earlyReturn = false;
for (int i = 0; i < timeSinceReceived.Length; i++)
{
if (timeSinceReceived[i] > timeFrame)
{
IsActive = false;
return;
}
deactivate &= timeSinceReceived[i] > timeFrame;
earlyReturn |= timeSinceReceived[i] > timeFrame;
timeSinceReceived[i] += deltaTime;
}
// only stop Update() if both signals timed-out. if IsActive == false, then the component stops updating.
IsActive = !deactivate;
// early return if either of the signal timed-out
if (earlyReturn) { return; }
float output = Calculate(receivedSignal[0], receivedSignal[1]);
if (MathUtils.IsValid(output))
{
@@ -1,9 +1,23 @@
using System.Xml.Linq;
using System;
namespace Barotrauma.Items.Components
{
class ConcatComponent : StringComponent
{
private int maxOutputLength;
[Editable, Serialize(256, false, description: "The maximum length of the output string. Warning: Large values can lead to large memory usage or networking load.")]
public int MaxOutputLength
{
get { return maxOutputLength; }
set
{
maxOutputLength = Math.Max(value, 0);
}
}
public ConcatComponent(Item item, XElement element)
: base(item, element)
{
@@ -11,7 +25,8 @@ namespace Barotrauma.Items.Components
protected override string Calculate(string signal1, string signal2)
{
return signal1 + signal2;
string output = signal1 + signal2;
return output.Length <= maxOutputLength ? output : output.Substring(0, MaxOutputLength);
}
}
}
@@ -8,13 +8,16 @@ namespace Barotrauma.Items.Components
{
partial class Connection
{
//how many wires can be linked to a single connector
public const int MaxLinked = 5;
//how many wires can be linked to connectors by default
private const int DefaultMaxWires = 5;
//how many wires can be linked to this connection
public readonly int MaxWires = 5;
public readonly string Name;
public readonly string DisplayName;
private Wire[] wires;
private readonly Wire[] wires;
public IEnumerable<Wire> Wires
{
get { return wires; }
@@ -77,7 +80,8 @@ namespace Barotrauma.Items.Components
ConnectionPanel = connectionPanel;
item = connectionPanel.Item;
wires = new Wire[MaxLinked];
MaxWires = element.GetAttributeInt("maxwires", DefaultMaxWires);
wires = new Wire[MaxWires];
IsOutput = element.Name.ToString() == "output";
Name = element.GetAttributeString("name", IsOutput ? "output" : "input");
@@ -135,7 +139,7 @@ namespace Barotrauma.Items.Components
Effects = new List<StatusEffect>();
wireId = new ushort[MaxLinked];
wireId = new ushort[MaxWires];
foreach (XElement subElement in element.Elements())
{
@@ -143,7 +147,7 @@ namespace Barotrauma.Items.Components
{
case "link":
int index = -1;
for (int i = 0; i < MaxLinked; i++)
for (int i = 0; i < MaxWires; i++)
{
if (wireId[i] < 1) index = i;
}
@@ -173,7 +177,7 @@ namespace Barotrauma.Items.Components
private void RefreshRecipients()
{
recipients.Clear();
for (int i = 0; i < MaxLinked; i++)
for (int i = 0; i < MaxWires; i++)
{
if (wires[i] == null) continue;
Connection recipient = wires[i].OtherConnection(this);
@@ -184,7 +188,7 @@ namespace Barotrauma.Items.Components
public int FindEmptyIndex()
{
for (int i = 0; i < MaxLinked; i++)
for (int i = 0; i < MaxWires; i++)
{
if (wires[i] == null) return i;
}
@@ -193,7 +197,7 @@ namespace Barotrauma.Items.Components
public int FindWireIndex(Wire wire)
{
for (int i = 0; i < MaxLinked; i++)
for (int i = 0; i < MaxWires; i++)
{
if (wires[i] == wire) return i;
}
@@ -202,7 +206,7 @@ namespace Barotrauma.Items.Components
public int FindWireIndex(Item wireItem)
{
for (int i = 0; i < MaxLinked; i++)
for (int i = 0; i < MaxWires; i++)
{
if (wires[i] == null && wireItem == null) return i;
if (wires[i] != null && wires[i].Item == wireItem) return i;
@@ -212,7 +216,7 @@ namespace Barotrauma.Items.Components
public bool TryAddLink(Wire wire)
{
for (int i = 0; i < MaxLinked; i++)
for (int i = 0; i < MaxWires; i++)
{
if (wires[i] == null)
{
@@ -250,7 +254,7 @@ namespace Barotrauma.Items.Components
public void SendSignal(int stepsTaken, string signal, Item source, Character sender, float power, float signalStrength = 1.0f)
{
for (int i = 0; i < MaxLinked; i++)
for (int i = 0; i < MaxWires; i++)
{
if (wires[i] == null) { continue; }
@@ -265,16 +269,19 @@ namespace Barotrauma.Items.Components
ic.ReceiveSignal(stepsTaken, signal, recipient, source, sender, power, signalStrength);
}
foreach (StatusEffect effect in recipient.Effects)
if (signal != "0")
{
recipient.Item.ApplyStatusEffect(effect, ActionType.OnUse, (float)Timing.Step);
foreach (StatusEffect effect in recipient.Effects)
{
recipient.Item.ApplyStatusEffect(effect, ActionType.OnUse, (float)Timing.Step);
}
}
}
}
public void SendPowerProbeSignal(Item source, float power)
{
for (int i = 0; i < MaxLinked; i++)
for (int i = 0; i < MaxWires; i++)
{
if (wires[i] == null) { continue; }
@@ -286,7 +293,7 @@ namespace Barotrauma.Items.Components
}
public void ClearConnections()
{
for (int i = 0; i < MaxLinked; i++)
for (int i = 0; i < MaxWires; i++)
{
if (wires[i] == null) continue;
@@ -300,7 +307,7 @@ namespace Barotrauma.Items.Components
{
if (wireId == null) return;
for (int i = 0; i < MaxLinked; i++)
for (int i = 0; i < MaxWires; i++)
{
if (wireId[i] == 0) { continue; }
@@ -329,7 +336,7 @@ namespace Barotrauma.Items.Components
return wire1.Item.ID.CompareTo(wire2.Item.ID);
});
for (int i = 0; i < MaxLinked; i++)
for (int i = 0; i < MaxWires; i++)
{
if (wires[i] == null) continue;
@@ -1,7 +1,5 @@
using Barotrauma.Networking;
using FarseerPhysics;
using Microsoft.Xna.Framework;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
@@ -21,6 +19,14 @@ namespace Barotrauma.Items.Components
private List<ushort> disconnectedWireIds;
/// <summary>
/// Allows rewiring the connection panel despite rewiring being disabled on a server
/// </summary>
public bool AlwaysAllowRewiring
{
get { return item.Submarine?.Info.Type == SubmarineType.BeaconStation; }
}
[Editable, Serialize(false, true, description: "Locked connection panels cannot be rewired in-game.", alwaysUseInstanceValues: true)]
public bool Locked
{
@@ -103,7 +109,7 @@ namespace Barotrauma.Items.Components
public override void OnItemLoaded()
{
if (item.body != null)
if (item.body != null && item.body.BodyType == FarseerPhysics.BodyType.Dynamic)
{
var holdable = item.GetComponent<Holdable>();
if (holdable == null || !holdable.Attachable)
@@ -122,12 +128,12 @@ namespace Barotrauma.Items.Components
{
foreach (Wire wire in c.Wires)
{
if (wire == null) continue;
if (wire == null) { continue; }
#if CLIENT
if (wire.Item.IsSelected) continue;
if (wire.Item.IsSelected) { continue; }
#endif
var wireNodes = wire.GetNodes();
if (wireNodes.Count == 0) continue;
if (wireNodes.Count == 0) { continue; }
if (Submarine.RectContains(item.Rect, wireNodes[0] + wireNodeOffset))
{
@@ -176,7 +182,7 @@ namespace Barotrauma.Items.Components
{
//attaching wires to items with a body is not allowed
//(signal items remove their bodies when attached to a wall)
if (item.body != null)
if (item.body != null && item.body.BodyType == FarseerPhysics.BodyType.Dynamic)
{
return false;
}
@@ -239,10 +245,32 @@ namespace Barotrauma.Items.Components
for (int i = 0; i < loadedConnections.Count && i < Connections.Count; i++)
{
loadedConnections[i].wireId.CopyTo(Connections[i].wireId, 0);
if (loadedConnections[i].wireId.Length == Connections[i].wireId.Length)
{
loadedConnections[i].wireId.CopyTo(Connections[i].wireId, 0);
}
else
{
//backwards compatibility when maximum number of wires has changed
foreach (ushort id in loadedConnections[i].wireId)
{
for (int j = 0; j < Connections[i].wireId.Length; j++)
{
if (Connections[i].wireId[j] == 0)
{
Connections[i].wireId[j] = id;
break;
}
}
}
}
}
disconnectedWireIds = element.GetAttributeUshortArray("disconnectedwires", new ushort[0]).ToList();
for (int i = 0; i < disconnectedWireIds.Count; i++)
{
disconnectedWireIds[i] = idRemap.GetOffsetId(disconnectedWireIds[i]);
}
}
public override XElement Save(XElement parentElement)
@@ -12,25 +12,72 @@ namespace Barotrauma.Items.Components
public bool ContinuousSignal;
public bool State;
public string ConnectionName;
public string PropertyName;
public Connection Connection;
[Serialize("", false, translationTextTag: "Label.", description: "The text displayed on this button/tickbox."), Editable]
public string Label { get; set; }
[Serialize("1", false, description: "The signal sent out when this button is pressed or this tickbox checked."), Editable]
public string Signal { get; set; }
public string PropertyName { get; }
public bool TargetOnlyParentProperty { get; }
public int NumberInputMin { get; }
public int NumberInputMax { get; }
public const int DefaultNumberInputMin = 0, DefaultNumberInputMax = 99;
public bool IsIntegerInput { get; }
public bool HasPropertyName { get; }
public bool ShouldSetProperty { get; set; }
public string Name => "CustomInterfaceElement";
public Dictionary<string, SerializableProperty> SerializableProperties { get; set; }
public List<StatusEffect> StatusEffects = new List<StatusEffect>();
public CustomInterfaceElement(XElement element)
/// <summary>
/// Pass the parent component to the constructor to access the serializable properties
/// for elements which change property values.
/// </summary>
public CustomInterfaceElement(XElement element, CustomInterface parent)
{
Label = element.GetAttributeString("text", "");
ConnectionName = element.GetAttributeString("connection", "");
PropertyName = element.GetAttributeString("propertyname", "").ToLowerInvariant();
Signal = element.GetAttributeString("signal", "1");
TargetOnlyParentProperty = element.GetAttributeBool("targetonlyparentproperty", false);
NumberInputMin = element.GetAttributeInt("min", DefaultNumberInputMin);
NumberInputMax = element.GetAttributeInt("max", DefaultNumberInputMax);
HasPropertyName = !string.IsNullOrEmpty(PropertyName);
IsIntegerInput = HasPropertyName && element.Name.ToString().ToLowerInvariant() == "integerinput";
if (element.Attribute("signal") is XAttribute attribute)
{
Signal = attribute.Value;
ShouldSetProperty = HasPropertyName;
}
else if (HasPropertyName && parent != null)
{
if (TargetOnlyParentProperty)
{
if (parent.SerializableProperties.ContainsKey(PropertyName))
{
Signal = parent.SerializableProperties[PropertyName].GetValue(parent) as string;
}
}
else
{
foreach (ISerializableEntity e in parent.item.AllPropertyObjects)
{
if (!e.SerializableProperties.ContainsKey(PropertyName)) { continue; }
Signal = e.SerializableProperties[PropertyName].GetValue(e) as string;
break;
}
}
}
else
{
Signal = "1";
}
foreach (XElement subElement in element.Elements())
{
@@ -50,13 +97,14 @@ namespace Barotrauma.Items.Components
set
{
if (value == null) { return; }
string[] splitValues = value == "" ? new string[0] : value.Split(',');
if (customInterfaceElementList.Count > 0)
{
string[] splitValues = value == "" ? new string[0] : value.Split(',');
UpdateLabels(splitValues);
}
}
}
private string[] signals;
[Serialize("", true, description: "The signals sent when the buttons are pressed or the tickboxes checked, separated by commas.")]
public string Signals
@@ -67,34 +115,29 @@ namespace Barotrauma.Items.Components
set
{
if (value == null) { return; }
string[] splitValues = value == "" ? new string[0] : value.Split(';');
if (customInterfaceElementList.Count > 0)
{
signals = new string[customInterfaceElementList.Count];
for (int i = 0; i < customInterfaceElementList.Count; i++)
{
signals[i] = i < splitValues.Length ? splitValues[i] : customInterfaceElementList[i].Signal;
customInterfaceElementList[i].Signal = signals[i];
}
string[] splitValues = value == "" ? new string[0] : value.Split(';');
UpdateSignals(splitValues);
}
}
}
public override bool RecreateGUIOnResolutionChange => true;
private List<CustomInterfaceElement> customInterfaceElementList = new List<CustomInterfaceElement>();
private readonly List<CustomInterfaceElement> customInterfaceElementList = new List<CustomInterfaceElement>();
public CustomInterface(Item item, XElement element)
: base(item, element)
{
int i = 0;
foreach (XElement subElement in element.Elements())
{
switch (subElement.Name.ToString().ToLowerInvariant())
{
case "button":
case "textbox":
var button = new CustomInterfaceElement(subElement)
case "integerinput":
var button = new CustomInterfaceElement(subElement, this)
{
ContinuousSignal = false
};
@@ -105,7 +148,7 @@ namespace Barotrauma.Items.Components
customInterfaceElementList.Add(button);
break;
case "tickbox":
var tickBox = new CustomInterfaceElement(subElement)
var tickBox = new CustomInterfaceElement(subElement, this)
{
ContinuousSignal = true
};
@@ -116,10 +159,9 @@ namespace Barotrauma.Items.Components
customInterfaceElementList.Add(tickBox);
break;
}
i++;
}
IsActive = true;
InitProjSpecific(element);
InitProjSpecific();
Labels = element.GetAttributeString("labels", "");
Signals = element.GetAttributeString("signals", "");
}
@@ -142,6 +184,47 @@ namespace Barotrauma.Items.Components
UpdateLabelsProjSpecific();
}
private void UpdateSignals(string[] newSignals)
{
signals = new string[customInterfaceElementList.Count];
for (int i = 0; i < customInterfaceElementList.Count; i++)
{
var element = customInterfaceElementList[i];
if (i < newSignals.Length)
{
var newSignal = newSignals[i];
signals[i] = newSignal;
element.ShouldSetProperty = element.Signal != newSignal;
element.Signal = newSignal;
}
else
{
signals[i] = element.Signal;
}
if (element.HasPropertyName && element.ShouldSetProperty)
{
if (element.TargetOnlyParentProperty)
{
if (SerializableProperties.ContainsKey(element.PropertyName))
{
SerializableProperties[element.PropertyName].TrySetValue(this, element.Signal);
}
}
else
{
foreach (var po in item.AllPropertyObjects)
{
if (!po.SerializableProperties.ContainsKey(element.PropertyName)) { continue; }
po.SerializableProperties[element.PropertyName].TrySetValue(po, element.Signal);
}
}
customInterfaceElementList[i].ShouldSetProperty = false;
}
}
UpdateSignalsProjSpecific();
}
public override void OnItemLoaded()
{
foreach (CustomInterfaceElement ciElement in customInterfaceElementList)
@@ -152,7 +235,9 @@ namespace Barotrauma.Items.Components
partial void UpdateLabelsProjSpecific();
partial void InitProjSpecific(XElement element);
partial void UpdateSignalsProjSpecific();
partial void InitProjSpecific();
private void ButtonClicked(CustomInterfaceElement btnElement)
{
@@ -175,14 +260,38 @@ namespace Barotrauma.Items.Components
private void TextChanged(CustomInterfaceElement textElement, string text)
{
if (textElement == null) { return; }
textElement.Signal = text;
foreach (ISerializableEntity e in item.AllPropertyObjects)
if (!textElement.TargetOnlyParentProperty)
{
if (e.SerializableProperties.ContainsKey(textElement.PropertyName))
foreach (ISerializableEntity e in item.AllPropertyObjects)
{
if (!e.SerializableProperties.ContainsKey(textElement.PropertyName)) { continue; }
e.SerializableProperties[textElement.PropertyName].TrySetValue(e, text);
}
}
}
else if (SerializableProperties.ContainsKey(textElement.PropertyName))
{
SerializableProperties[textElement.PropertyName].TrySetValue(this, text);
}
}
private void ValueChanged(CustomInterfaceElement numberInputElement, int value)
{
if (numberInputElement == null) { return; }
numberInputElement.Signal = value.ToString();
if (!numberInputElement.TargetOnlyParentProperty)
{
foreach (ISerializableEntity e in item.AllPropertyObjects)
{
if (!e.SerializableProperties.ContainsKey(numberInputElement.PropertyName)) { continue; }
e.SerializableProperties[numberInputElement.PropertyName].TrySetValue(e, value);
}
}
else if (SerializableProperties.ContainsKey(numberInputElement.PropertyName))
{
SerializableProperties[numberInputElement.PropertyName].TrySetValue(this, value);
}
}
public override void Update(float deltaTime, Camera cam)
@@ -35,7 +35,7 @@ namespace Barotrauma.Items.Components
break;
case "signal_in":
float.TryParse(signal, NumberStyles.Float, CultureInfo.InvariantCulture, out float value);
item.SendSignal(0, MathUtils.Pow(value, Exponent).ToString("G", CultureInfo.InvariantCulture), "signal_out", null);
item.SendSignal(stepsTaken, MathUtils.Pow(value, Exponent).ToString("G", CultureInfo.InvariantCulture), "signal_out", sender, source: source);
break;
}
}
@@ -31,17 +31,17 @@ namespace Barotrauma.Items.Components
public override void ReceiveSignal(int stepsTaken, string signal, Connection connection, Item source, Character sender, float power = 0, float signalStrength = 1)
{
if (connection.Name != "signal_in") return;
if (!float.TryParse(signal, NumberStyles.Float, CultureInfo.InvariantCulture, out float value)) return;
if (!float.TryParse(signal, NumberStyles.Float, CultureInfo.InvariantCulture, out float value)) { return; }
switch (Function)
{
case FunctionType.Round:
item.SendSignal(0, Math.Round(value).ToString("G", CultureInfo.InvariantCulture), "signal_out", null);
item.SendSignal(stepsTaken, Math.Round(value).ToString("G", CultureInfo.InvariantCulture), "signal_out", sender, source: source);
break;
case FunctionType.Ceil:
item.SendSignal(0, Math.Ceiling(value).ToString("G", CultureInfo.InvariantCulture), "signal_out", null);
item.SendSignal(stepsTaken, Math.Ceiling(value).ToString("G", CultureInfo.InvariantCulture), "signal_out", sender, source: source);
break;
case FunctionType.Floor:
item.SendSignal(0, Math.Floor(value).ToString("G", CultureInfo.InvariantCulture), "signal_out", null);
item.SendSignal(stepsTaken, Math.Floor(value).ToString("G", CultureInfo.InvariantCulture), "signal_out", sender, source: source);
break;
case FunctionType.Factorial:
int intVal = (int)Math.Min(value, 20);
@@ -50,15 +50,15 @@ namespace Barotrauma.Items.Components
{
factorial *= (ulong)i;
}
item.SendSignal(0, factorial.ToString(), "signal_out", null);
item.SendSignal(stepsTaken, factorial.ToString(), "signal_out", sender, source: source);
break;
case FunctionType.AbsoluteValue:
item.SendSignal(0, Math.Abs(value).ToString("G", CultureInfo.InvariantCulture), "signal_out", null);
item.SendSignal(stepsTaken, Math.Abs(value).ToString("G", CultureInfo.InvariantCulture), "signal_out", sender, source: source);
break;
case FunctionType.SquareRoot:
if (value > 0)
{
item.SendSignal(0, Math.Sqrt(value).ToString("G", CultureInfo.InvariantCulture), "signal_out", null);
item.SendSignal(stepsTaken, Math.Sqrt(value).ToString("G", CultureInfo.InvariantCulture), "signal_out", sender, source: source);
}
break;
default:
@@ -25,6 +25,8 @@ namespace Barotrauma.Items.Components
public PhysicsBody ParentBody;
private Turret turret;
[Serialize(100.0f, true, description: "The range of the emitted light. Higher values are more performance-intensive.", alwaysUseInstanceValues: true),
Editable(MinValueFloat = 0.0f, MaxValueFloat = 2048.0f)]
public float Range
@@ -214,7 +216,14 @@ namespace Barotrauma.Items.Components
IsActive = IsOn;
item.AddTag("light");
}
public override void OnItemLoaded()
{
base.OnItemLoaded();
SetLightSourceState(IsActive, lightBrightness);
turret = item.GetComponent<Turret>();
}
public override void Update(float deltaTime, Camera cam)
{
if (item.AiTarget != null)
@@ -232,9 +241,19 @@ namespace Barotrauma.Items.Components
return;
}
#if CLIENT
light.Position = ParentBody != null ? ParentBody.Position : item.Position;
if (ParentBody != null)
{
light.Position = ParentBody.Position;
}
else if (turret != null)
{
light.Position = new Vector2(item.Rect.X + turret.TransformedBarrelPos.X, item.Rect.Y - turret.TransformedBarrelPos.Y);
}
else
{
light.Position = item.Position;
}
#endif
PhysicsBody body = ParentBody ?? item.body;
if (body != null)
{
@@ -49,6 +49,7 @@ namespace Barotrauma.Items.Components
}
break;
case "signal_store":
case "lock_state":
writeable = signal == "1";
break;
}
@@ -32,7 +32,7 @@ namespace Barotrauma.Items.Components
break;
case "signal_in":
float.TryParse(signal, NumberStyles.Float, CultureInfo.InvariantCulture, out float value);
item.SendSignal(0, (value % modulus).ToString("G", CultureInfo.InvariantCulture), "signal_out", null);
item.SendSignal(stepsTaken, (value % modulus).ToString("G", CultureInfo.InvariantCulture), "signal_out", sender, source: source);
break;
}
@@ -15,17 +15,24 @@ namespace Barotrauma.Items.Components
private float updateTimer;
public enum TargetType
{
Any,
Human,
Monster
}
[Serialize(false, false, description: "Has the item currently detected movement. Intended to be used by StatusEffect conditionals (setting this value in XML has no effect).")]
public bool MotionDetected { get; set; }
[Editable, Serialize(false, true, description: "Should the sensor only detect the movement of humans?", alwaysUseInstanceValues: true)]
public bool OnlyHumans
[InGameEditable, Serialize(TargetType.Any, true, description: "Which kind of targets can trigger the sensor?", alwaysUseInstanceValues: true)]
public TargetType Target
{
get;
set;
}
[Editable, Serialize(false, true, description: "Should the sensor ignore the bodies of dead characters?", alwaysUseInstanceValues: true)]
[InGameEditable, Serialize(false, true, description: "Should the sensor ignore the bodies of dead characters?", alwaysUseInstanceValues: true)]
public bool IgnoreDead
{
get;
@@ -55,7 +62,7 @@ namespace Barotrauma.Items.Components
}
}
[Editable, Serialize("0,0", true, description: "The position to detect the movement at relative to the item. For example, 0,100 would detect movement 100 units above the item.")]
[InGameEditable, Serialize("0,0", true, description: "The position to detect the movement at relative to the item. For example, 0,100 would detect movement 100 units above the item.")]
public Vector2 DetectOffset
{
get { return detectOffset; }
@@ -80,7 +87,6 @@ namespace Barotrauma.Items.Components
set;
}
public MotionSensor(Item item, XElement element)
: base(item, element)
{
@@ -93,6 +99,16 @@ namespace Barotrauma.Items.Components
}
}
public override void Load(XElement componentElement, bool usePrefabValues, IdRemap idRemap)
{
base.Load(componentElement, usePrefabValues, idRemap);
//backwards compatibility
if (componentElement.GetAttributeBool("onlyhumans", false))
{
Target = TargetType.Human;
}
}
public override void Update(float deltaTime, Camera cam)
{
string signalOut = MotionDetected ? Output : FalseOutput;
@@ -121,7 +137,20 @@ namespace Barotrauma.Items.Components
foreach (Character c in Character.CharacterList)
{
if (IgnoreDead && c.IsDead) { continue; }
if (OnlyHumans && !c.IsHuman) { continue; }
//ignore characters that have spawned a second or less ago
//makes it possible to detect when a spawned character moves without triggering the detector immediately as the ragdoll spawns and drops to the ground
if (c.SpawnTime > Timing.TotalTime - 1.0) { continue; }
switch (Target)
{
case TargetType.Human:
if (!c.IsHuman) { continue; }
break;
case TargetType.Monster:
if (c.IsHuman || c.IsPet) { continue; }
break;
}
//do a rough check based on the position of the character's collider first
//before the more accurate limb-based check
@@ -4,16 +4,36 @@ namespace Barotrauma.Items.Components
{
class NotComponent : ItemComponent
{
private bool signalReceived;
private bool continuousOutput;
[Editable, Serialize(false, true, description: "When enabled, the component continuously outputs \"1\" when it's not receiving a signal.", alwaysUseInstanceValues: true)]
public bool ContinuousOutput
{
get { return continuousOutput; }
set { continuousOutput = IsActive = value; }
}
public NotComponent(Item item, XElement element)
: base (item, element)
{
}
public override void Update(float deltaTime, Camera cam)
{
base.Update(deltaTime, cam);
if (!signalReceived)
{
item.SendSignal(0, "1", "signal_out", null, 0.0f);
}
signalReceived = false;
}
public override void ReceiveSignal(int stepsTaken, string signal, Connection connection, Item source, Character sender, float power = 0.0f, float signalStrength = 1.0f)
{
if (connection.Name != "signal_in") return;
item.SendSignal(stepsTaken, signal == "0" ? "1" : "0", "signal_out", sender, 0.0f, source, signalStrength);
if (connection.Name != "signal_in") { return; }
item.SendSignal(stepsTaken, signal == "0" || signal == string.Empty ? "1" : "0", "signal_out", sender, 0.0f, source, signalStrength);
signalReceived = true;
}
}
}
@@ -23,7 +23,7 @@ namespace Barotrauma.Items.Components
[InGameEditable, Serialize(false, true, description: "Should the component output a value of a capture group instead of a constant signal.", alwaysUseInstanceValues: true)]
public bool UseCaptureGroup { get; set; }
[Serialize("0", true, description: "The signal this item outputs when the received signal does not match the regular expression.", alwaysUseInstanceValues: true)]
[InGameEditable, Serialize("0", true, description: "The signal this item outputs when the received signal does not match the regular expression.", alwaysUseInstanceValues: true)]
public string FalseOutput { get; set; }
[InGameEditable, Serialize(true, true, description: "Should the component keep sending the output even after it stops receiving a signal, or only send an output when it receives a signal.", alwaysUseInstanceValues: true)]
@@ -180,6 +180,7 @@ namespace Barotrauma.Items.Components
}
else if (connection.Name == "toggle")
{
if (signal == "0") { return; }
SetState(!IsOn, false);
}
else if (connection.Name == "set_state")
@@ -25,7 +25,7 @@ namespace Barotrauma.Items.Components
string signalOut = (signal == TargetSignal) ? Output : FalseOutput;
if (string.IsNullOrWhiteSpace(signalOut)) return;
item.SendSignal(stepsTaken, signalOut, "signal_out", sender, signalStrength);
item.SendSignal(stepsTaken, signalOut, "signal_out", sender, signalStrength, source);
break;
case "set_output":
@@ -68,18 +68,18 @@ namespace Barotrauma.Items.Components
{
case FunctionType.Sin:
if (!UseRadians) { value = MathHelper.ToRadians(value); }
item.SendSignal(0, ((float)Math.Sin(value)).ToString("G", CultureInfo.InvariantCulture), "signal_out", null);
item.SendSignal(stepsTaken, ((float)Math.Sin(value)).ToString("G", CultureInfo.InvariantCulture), "signal_out", sender, source: source);
break;
case FunctionType.Cos:
if (!UseRadians) { value = MathHelper.ToRadians(value); }
item.SendSignal(0, ((float)Math.Cos(value)).ToString("G", CultureInfo.InvariantCulture), "signal_out", null);
item.SendSignal(stepsTaken, ((float)Math.Cos(value)).ToString("G", CultureInfo.InvariantCulture), "signal_out", sender, source: source);
break;
case FunctionType.Tan:
if (!UseRadians) { value = MathHelper.ToRadians(value); }
//tan is undefined if the value is (π / 2) + πk, where k is any integer
if (!MathUtils.NearlyEqual(value % MathHelper.Pi, MathHelper.PiOver2))
{
item.SendSignal(0, ((float)Math.Tan(value)).ToString("G", CultureInfo.InvariantCulture), "signal_out", null);
item.SendSignal(stepsTaken, ((float)Math.Tan(value)).ToString("G", CultureInfo.InvariantCulture), "signal_out", sender, source: source);
}
break;
case FunctionType.Asin:
@@ -88,7 +88,7 @@ namespace Barotrauma.Items.Components
{
float angle = (float)Math.Asin(value);
if (!UseRadians) { angle = MathHelper.ToDegrees(angle); }
item.SendSignal(0, angle.ToString("G", CultureInfo.InvariantCulture), "signal_out", null);
item.SendSignal(stepsTaken, angle.ToString("G", CultureInfo.InvariantCulture), "signal_out", sender, source: source);
}
break;
case FunctionType.Acos:
@@ -97,7 +97,7 @@ namespace Barotrauma.Items.Components
{
float angle = (float)Math.Acos(value);
if (!UseRadians) { angle = MathHelper.ToDegrees(angle); }
item.SendSignal(0, angle.ToString("G", CultureInfo.InvariantCulture), "signal_out", null);
item.SendSignal(stepsTaken, angle.ToString("G", CultureInfo.InvariantCulture), "signal_out", sender, source: source);
}
break;
case FunctionType.Atan:
@@ -115,7 +115,7 @@ namespace Barotrauma.Items.Components
{
float angle = (float)Math.Atan(value);
if (!UseRadians) { angle = MathHelper.ToDegrees(angle); }
item.SendSignal(0, angle.ToString("G", CultureInfo.InvariantCulture), "signal_out", null);
item.SendSignal(stepsTaken, angle.ToString("G", CultureInfo.InvariantCulture), "signal_out", sender, source: source);
}
break;
default:
@@ -24,8 +24,8 @@ namespace Barotrauma.Items.Components
private int[] channelMemory = new int[ChannelMemorySize];
[Serialize(Character.TeamType.None, true, description: "WiFi components can only communicate with components that have the same Team ID.", alwaysUseInstanceValues: true)]
public Character.TeamType TeamID { get; set; }
[Serialize(CharacterTeamType.None, true, description: "WiFi components can only communicate with components that have the same Team ID.", alwaysUseInstanceValues: true)]
public CharacterTeamType TeamID { get; set; }
[Editable, Serialize(20000.0f, false, description: "How close the recipient has to be to receive a signal from this WiFi component.", alwaysUseInstanceValues: true)]
public float Range
@@ -152,7 +152,7 @@ namespace Barotrauma.Items.Components
channelMemory[index] = MathHelper.Clamp(value, 0, 10000);
}
public void TransmitSignal(int stepsTaken, string signal, Item source, Character sender, bool sendToChat, float signalStrength = 1.0f)
public void TransmitSignal(int stepsTaken, string signal, Item source, Character sender, bool sentFromChat, float signalStrength = 1.0f)
{
var senderComponent = source?.GetComponent<WifiComponent>();
if (senderComponent != null && !CanReceive(senderComponent)) { return; }
@@ -162,6 +162,8 @@ namespace Barotrauma.Items.Components
var receivers = GetReceiversInRange();
foreach (WifiComponent wifiComp in receivers)
{
if (sentFromChat && !wifiComp.LinkToChat) { continue; }
//signal strength diminishes by distance
float sentSignalStrength = signalStrength *
MathHelper.Clamp(1.0f - (Vector2.Distance(item.WorldPosition, wifiComp.item.WorldPosition) / wifiComp.range), 0.0f, 1.0f);
@@ -176,11 +178,12 @@ namespace Barotrauma.Items.Components
source.LastSentSignalRecipients.Add(receiverItem);
}
}
}
}
if (DiscardDuplicateChatMessages && signal == prevSignal) continue;
if (DiscardDuplicateChatMessages && signal == prevSignal) { continue; }
if (LinkToChat && wifiComp.LinkToChat && chatMsgCooldown <= 0.0f && sendToChat)
//create a chat message
if (LinkToChat && wifiComp.LinkToChat && chatMsgCooldown <= 0.0f && !sentFromChat)
{
if (wifiComp.item.ParentInventory != null &&
wifiComp.item.ParentInventory.Owner != null)
@@ -232,7 +235,7 @@ namespace Barotrauma.Items.Components
switch (connection.Name)
{
case "signal_in":
TransmitSignal(stepsTaken, signal, source, sender, true, signalStrength);
TransmitSignal(stepsTaken, signal, source, sender, false, signalStrength);
break;
case "set_channel":
if (int.TryParse(signal, out int newChannel))
@@ -37,6 +37,11 @@ namespace Barotrauma.Items.Components
angle = MathUtils.VectorToAngle(end - start);
length = Vector2.Distance(start, end);
if (length > 5000.0f)
{
int akjsdnfkjsadf = 1;
}
}
}
@@ -183,8 +188,12 @@ namespace Barotrauma.Items.Components
if (refSub == null)
{
Structure attachTarget = Structure.GetAttachTarget(newConnection.Item.WorldPosition);
if (attachTarget == null) { continue; }
refSub = attachTarget.Submarine;
if (attachTarget == null && !(newConnection.Item.GetComponent<Holdable>()?.Attached ?? false))
{
connections[i] = null;
continue;
}
refSub = attachTarget?.Submarine;
}
Vector2 nodePos = refSub == null ?
@@ -238,18 +247,18 @@ namespace Barotrauma.Items.Components
{
foreach (ItemComponent ic in item.Components)
{
if (ic == this) continue;
if (ic == this) { continue; }
ic.Drop(null);
}
if (item.Container != null) item.Container.RemoveContained(this.item);
if (item.body != null) item.body.Enabled = false;
if (item.Container != null) { item.Container.RemoveContained(this.item); }
if (item.body != null) { item.body.Enabled = false; }
IsActive = false;
CleanNodes();
}
if (item.body != null) item.Submarine = newConnection.Item.Submarine;
if (item.body != null) { item.Submarine = newConnection.Item.Submarine; }
if (sendNetworkEvent)
{
@@ -735,6 +744,11 @@ namespace Barotrauma.Items.Components
public override void FlipX(bool relativeToSub)
{
if (item.ParentInventory != null) { return; }
#if CLIENT
if (!relativeToSub && Screen.Selected != GameMain.SubEditorScreen) { return; }
#else
if (!relativeToSub) { return; }
#endif
Vector2 refPos = item.Submarine == null ?
Vector2.Zero :