Merge branch 'dev' of https://github.com/Regalis11/Barotrauma.git into unstable-tests

This commit is contained in:
Evil Factory
2022-04-08 12:52:28 -03:00
990 changed files with 44338 additions and 38589 deletions
@@ -4,7 +4,7 @@ namespace Barotrauma.Items.Components
{
class AdderComponent : ArithmeticComponent
{
public AdderComponent(Item item, XElement element)
public AdderComponent(Item item, ContentXElement element)
: base(item, element)
{
}
@@ -15,7 +15,7 @@ namespace Barotrauma.Items.Components
protected readonly Character[] signalSender = new Character[2];
[InGameEditable(DecimalCount = 2), Serialize(0.0f, true, description: "The item sends the output if both inputs have received a non-zero signal within the timeframe. If set to 0, the inputs must receive a signal at the same time.", alwaysUseInstanceValues: true)]
[InGameEditable(DecimalCount = 2), Serialize(0.0f, IsPropertySaveable.Yes, description: "The item sends the output if both inputs have received a non-zero signal within the timeframe. If set to 0, the inputs must receive a signal at the same time.", alwaysUseInstanceValues: true)]
public float TimeFrame
{
get { return timeFrame; }
@@ -30,7 +30,7 @@ namespace Barotrauma.Items.Components
}
private int maxOutputLength;
[Editable, Serialize(200, false, description: "The maximum length of the output strings. Warning: Large values can lead to large memory usage or networking issues.")]
[Editable, Serialize(200, IsPropertySaveable.No, description: "The maximum length of the output strings. Warning: Large values can lead to large memory usage or networking issues.")]
public int MaxOutputLength
{
get { return maxOutputLength; }
@@ -40,7 +40,7 @@ namespace Barotrauma.Items.Components
}
}
[InGameEditable, Serialize("1", true, description: "The signal sent when the condition is met.", alwaysUseInstanceValues: true)]
[InGameEditable, Serialize("1", IsPropertySaveable.Yes, description: "The signal sent when the condition is met.", alwaysUseInstanceValues: true)]
public string Output
{
get { return output; }
@@ -55,7 +55,7 @@ namespace Barotrauma.Items.Components
}
}
[InGameEditable, Serialize("", true, description: "The signal sent when the condition is met (if empty, no signal is sent).", alwaysUseInstanceValues: true)]
[InGameEditable, Serialize("", IsPropertySaveable.Yes, description: "The signal sent when the condition is met (if empty, no signal is sent).", alwaysUseInstanceValues: true)]
public string FalseOutput
{
get { return falseOutput; }
@@ -70,7 +70,7 @@ namespace Barotrauma.Items.Components
}
}
public AndComponent(Item item, XElement element)
public AndComponent(Item item, ContentXElement element)
: base(item, element)
{
timeSinceReceived = new float[] { Math.Max(timeFrame * 2.0f, 0.1f), Math.Max(timeFrame * 2.0f, 0.1f) };
@@ -15,7 +15,9 @@ namespace Barotrauma.Items.Components
//the output is sent if both inputs have received a signal within the timeframe
protected float timeFrame;
[Serialize(999999.0f, true, description: "The output of the item is restricted below this value.", alwaysUseInstanceValues: true),
protected readonly Character[] signalSender = new Character[2];
[Serialize(999999.0f, IsPropertySaveable.Yes, description: "The output of the item is restricted below this value.", alwaysUseInstanceValues: true),
InGameEditable(MinValueFloat = -999999.0f, MaxValueFloat = 999999.0f)]
public float ClampMax
{
@@ -23,7 +25,7 @@ namespace Barotrauma.Items.Components
set;
}
[Serialize(-999999.0f, true, description: "The output of the item is restricted above this value.", alwaysUseInstanceValues: true),
[Serialize(-999999.0f, IsPropertySaveable.Yes, description: "The output of the item is restricted above this value.", alwaysUseInstanceValues: true),
InGameEditable(MinValueFloat = -999999.0f, MaxValueFloat = 999999.0f)]
public float ClampMin
{
@@ -32,8 +34,8 @@ namespace Barotrauma.Items.Components
}
[InGameEditable(DecimalCount = 2),
Serialize(0.0f, true, description: "The item must have received signals to both inputs within this timeframe to output the result." +
" If set to 0, the inputs must be received at the same time.", alwaysUseInstanceValues: true)]
Serialize(0.0f, IsPropertySaveable.Yes, description: "The item must have received signals to both inputs within this timeframe to output the result." +
" If set to 0, the inputs must be received at the same time.", alwaysUseInstanceValues: true, translationTextTag: "sp.")]
public float TimeFrame
{
get { return timeFrame; }
@@ -47,7 +49,7 @@ namespace Barotrauma.Items.Components
}
}
public ArithmeticComponent(Item item, XElement element)
public ArithmeticComponent(Item item, ContentXElement element)
: base(item, element)
{
timeSinceReceived = new float[] { Math.Max(timeFrame * 2.0f, 0.1f), Math.Max(timeFrame * 2.0f, 0.1f) };
@@ -71,7 +73,7 @@ namespace Barotrauma.Items.Components
float output = Calculate(receivedSignal[0], receivedSignal[1]);
if (MathUtils.IsValid(output))
{
item.SendSignal(MathHelper.Clamp(output, ClampMin, ClampMax).ToString("G", CultureInfo.InvariantCulture), "signal_out");
item.SendSignal(new Signal(MathHelper.Clamp(output, ClampMin, ClampMax).ToString("G", CultureInfo.InvariantCulture), sender: signalSender[0] ?? signalSender[1]), "signal_out");
}
}
@@ -83,11 +85,13 @@ namespace Barotrauma.Items.Components
{
case "signal_in1":
float.TryParse(signal.value, NumberStyles.Float, CultureInfo.InvariantCulture, out receivedSignal[0]);
signalSender[0] = signal.sender;
timeSinceReceived[0] = 0.0f;
IsActive = true;
break;
case "signal_in2":
float.TryParse(signal.value, NumberStyles.Float, CultureInfo.InvariantCulture, out receivedSignal[1]);
signalSender[1] = signal.sender;
timeSinceReceived[1] = 0.0f;
IsActive = true;
break;
@@ -9,9 +9,9 @@ namespace Barotrauma.Items.Components
{
partial class ButtonTerminal : ItemComponent
{
[Editable, Serialize(new string[0], true, description: "Signals sent when the corresponding buttons are pressed.", alwaysUseInstanceValues: true)]
[Editable, Serialize(new string[0], IsPropertySaveable.Yes, description: "Signals sent when the corresponding buttons are pressed.", alwaysUseInstanceValues: true)]
public string[] Signals { get; set; }
[Editable, Serialize("", true, description: "Identifiers or tags of items that, when contained, allow the terminal buttons to be used. Multiple ones should be separated by commas.", alwaysUseInstanceValues: true)]
[Editable, Serialize("", IsPropertySaveable.Yes, description: "Identifiers or tags of items that, when contained, allow the terminal buttons to be used. Multiple ones should be separated by commas.", alwaysUseInstanceValues: true)]
public string ActivatingItems { get; set; }
private int RequiredSignalCount { get; set; }
@@ -21,7 +21,7 @@ namespace Barotrauma.Items.Components
private bool AllowUsingButtons => ActivatingItemPrefabs.None() || (Container != null && Container.Inventory.AllItems.Any(i => i != null && ActivatingItemPrefabs.Any(p => p == i.Prefab)));
public ButtonTerminal(Item item, XElement element) : base(item, element)
public ButtonTerminal(Item item, ContentXElement element) : base(item, element)
{
RequiredSignalCount = element.GetChildElements("TerminalButton").Count(c => c.GetAttribute("style") != null);
if (RequiredSignalCount < 1)
@@ -31,7 +31,7 @@ namespace Barotrauma.Items.Components
InitProjSpecific(element);
}
partial void InitProjSpecific(XElement element);
partial void InitProjSpecific(ContentXElement element);
public override void OnItemLoaded()
{
@@ -77,7 +77,7 @@ namespace Barotrauma.Items.Components
}
else
{
ItemPrefab.Prefabs.Where(p => p.Tags.Any(t => t.Equals(activatingItem, StringComparison.OrdinalIgnoreCase)))
ItemPrefab.Prefabs.Where(p => p.Tags.Any(t => t == activatingItem))
.ForEach(p => ActivatingItemPrefabs.Add(p));
}
}
@@ -109,10 +109,23 @@ namespace Barotrauma.Items.Components
return true;
}
private void Write(IWriteMessage msg, object[] extraData)
private readonly struct EventData : IEventData
{
if (extraData == null || extraData.Length < 3) { return; }
msg.WriteRangedInteger((int)extraData[2], 0, Signals.Length - 1);
public readonly int SignalIndex;
public EventData(int signalIndex)
{
SignalIndex = signalIndex;
}
}
public override bool ValidateEventData(NetEntityEvent.IData data)
=> TryExtractEventData<EventData>(data, out _);
private void Write(IWriteMessage msg, NetEntityEvent.IData extraData)
{
var eventData = ExtractEventData<EventData>(extraData);
msg.WriteRangedInteger(eventData.SignalIndex, 0, Signals.Length - 1);
}
}
}
@@ -11,10 +11,10 @@ namespace Barotrauma.Items.Components
private string output = "0,0,0,0";
[InGameEditable, Serialize(false, true, description: "When enabled makes the component translate the signal from HSV into RGB where red is the hue between 0 and 360, green is the saturation between 0 and 1 and blue is the value between 0 and 1.", alwaysUseInstanceValues: true)]
[InGameEditable, Serialize(false, IsPropertySaveable.Yes, description: "When enabled makes the component translate the signal from HSV into RGB where red is the hue between 0 and 360, green is the saturation between 0 and 1 and blue is the value between 0 and 1.", alwaysUseInstanceValues: true)]
public bool UseHSV { get; set; }
public ColorComponent(Item item, XElement element)
public ColorComponent(Item item, ContentXElement element)
: base(item, element)
{
receivedSignal = new float[4];
@@ -7,7 +7,7 @@ namespace Barotrauma.Items.Components
{
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.")]
[Editable, Serialize(256, IsPropertySaveable.No, 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; }
@@ -17,14 +17,14 @@ namespace Barotrauma.Items.Components
}
}
[Editable, Serialize("", false)]
[InGameEditable, Serialize("", IsPropertySaveable.No)]
public string Separator
{
get;
set;
}
public ConcatComponent(Item item, XElement element)
public ConcatComponent(Item item, ContentXElement element)
: base(item, element)
{
}
@@ -17,7 +17,7 @@ namespace Barotrauma.Items.Components
public readonly int MaxWires = 5;
public readonly string Name;
public readonly string DisplayName;
public readonly LocalizedString DisplayName;
private readonly Wire[] wires;
public IEnumerable<Wire> Wires
@@ -33,6 +33,12 @@ namespace Barotrauma.Items.Components
public readonly ushort[] wireId;
//The grid the connection is a part of
public GridInfo Grid;
//Priority in which power output will be handled - load is unaffected
public PowerPriority Priority = PowerPriority.Default;
public bool IsPower
{
get;
@@ -40,7 +46,7 @@ namespace Barotrauma.Items.Components
}
private bool recipientsDirty = true;
private List<Connection> recipients = new List<Connection>();
private readonly List<Connection> recipients = new List<Connection>();
public List<Connection> Recipients
{
get
@@ -66,17 +72,17 @@ namespace Barotrauma.Items.Components
return "Connection (" + item.Name + ", " + Name + ")";
}
public Connection(XElement element, ConnectionPanel connectionPanel, IdRemap idRemap)
public Connection(ContentXElement element, ConnectionPanel connectionPanel, IdRemap idRemap)
{
#if CLIENT
if (connector == null)
{
connector = GUI.Style.GetComponentStyle("ConnectionPanelConnector").GetDefaultSprite();
wireVertical = GUI.Style.GetComponentStyle("ConnectionPanelWire").GetDefaultSprite();
connectionSprite = GUI.Style.GetComponentStyle("ConnectionPanelConnection").GetDefaultSprite();
connectionSpriteHighlight = GUI.Style.GetComponentStyle("ConnectionPanelConnection").GetSprite(GUIComponent.ComponentState.Hover);
screwSprites = GUI.Style.GetComponentStyle("ConnectionPanelScrew").Sprites[GUIComponent.ComponentState.None].Select(s => s.Sprite).ToList();
connector = GUIStyle.GetComponentStyle("ConnectionPanelConnector").GetDefaultSprite();
wireVertical = GUIStyle.GetComponentStyle("ConnectionPanelWire").GetDefaultSprite();
connectionSprite = GUIStyle.GetComponentStyle("ConnectionPanelConnection").GetDefaultSprite();
connectionSpriteHighlight = GUIStyle.GetComponentStyle("ConnectionPanelConnection").GetSprite(GUIComponent.ComponentState.Hover);
screwSprites = GUIStyle.GetComponentStyle("ConnectionPanelScrew").Sprites[GUIComponent.ComponentState.None].Select(s => s.Sprite).ToList();
}
#endif
ConnectionPanel = connectionPanel;
@@ -93,9 +99,9 @@ namespace Barotrauma.Items.Components
string displayNameTag = "", fallbackTag = "";
//if displayname is not present, attempt to find it from the prefab
if (element.Attribute("displayname") == null)
if (element.GetAttribute("displayname") == null)
{
foreach (XElement subElement in item.Prefab.ConfigElement.Elements())
foreach (var subElement in item.Prefab.ConfigElement.Elements())
{
if (!subElement.Name.ToString().Equals("connectionpanel", StringComparison.OrdinalIgnoreCase)) { continue; }
@@ -132,7 +138,7 @@ namespace Barotrauma.Items.Components
}
}
if (string.IsNullOrEmpty(DisplayName))
if (DisplayName.IsNullOrEmpty())
{
#if DEBUG
DebugConsole.ThrowError("Missing display name in connection " + item.Name + ": " + Name);
@@ -145,7 +151,7 @@ namespace Barotrauma.Items.Components
wireId = new ushort[MaxWires];
foreach (XElement subElement in element.Elements())
foreach (var subElement in element.Elements())
{
switch (subElement.Name.ToString().ToLowerInvariant())
{
@@ -236,6 +242,34 @@ namespace Barotrauma.Items.Components
var otherConnection = previousWire.OtherConnection(this);
if (otherConnection != null)
{
//Change the connection grids or flag them for updating
if (IsPower && otherConnection.IsPower && Grid != null)
{
//Check if both connections belong to a larger grid
if (otherConnection.recipients.Count > 1 && recipients.Count > 1)
{
Powered.ChangedConnections.Add(otherConnection);
Powered.ChangedConnections.Add(this);
}
else if (recipients.Count > 1)
{
//This wire was the only one at the other grid
otherConnection.Grid?.RemoveConnection(otherConnection);
otherConnection.Grid = null;
}
else if (otherConnection.recipients.Count > 1)
{
Grid?.RemoveConnection(this);
Grid = null;
}
else if (Grid.Connections.Count == 2)
{
//Delete the grid as these were the only 2 devices
Powered.Grids.Remove(Grid.ID);
Grid = null;
otherConnection.Grid = null;
}
}
otherConnection.recipientsDirty = true;
}
}
@@ -244,10 +278,32 @@ namespace Barotrauma.Items.Components
recipientsDirty = true;
if (wire != null)
{
ConnectionPanel.DisconnectedWires.Remove(wire);
var otherConnection = wire.OtherConnection(this);
if (otherConnection != null)
{
//Set the other connection grid if a grid exists already
if (Powered.ValidPowerConnection(this, otherConnection))
{
if (Grid == null && otherConnection.Grid != null)
{
otherConnection.Grid.AddConnection(this);
Grid = otherConnection.Grid;
}
else if (Grid != null && otherConnection.Grid == null)
{
Grid.AddConnection(otherConnection);
otherConnection.Grid = Grid;
}
else
{
//Flag change so that proper grids can be formed
Powered.ChangedConnections.Add(this);
Powered.ChangedConnections.Add(otherConnection);
}
}
otherConnection.recipientsDirty = true;
}
}
@@ -286,20 +342,17 @@ namespace Barotrauma.Items.Components
}
}
public void SendPowerProbeSignal(Item source, float power)
{
for (int i = 0; i < MaxWires; i++)
{
if (wires[i] == null) { continue; }
Connection recipient = wires[i].OtherConnection(this);
if (recipient == null || !recipient.IsPower) { continue; }
recipient.item.GetComponent<Powered>()?.ReceivePowerProbeSignal(recipient, source, power);
}
}
public void ClearConnections()
{
if (IsPower && Grid != null)
{
Powered.ChangedConnections.Add(this);
foreach (Connection c in recipients)
{
Powered.ChangedConnections.Add(c);
}
}
for (int i = 0; i < MaxWires; i++)
{
if (wires[i] == null) continue;
@@ -1,4 +1,5 @@
using Barotrauma.Networking;
using System;
using Barotrauma.Networking;
using Microsoft.Xna.Framework;
using System.Collections.Generic;
using System.Linq;
@@ -39,7 +40,7 @@ namespace Barotrauma.Items.Components
}
}
[Editable, Serialize(false, true, description: "Locked connection panels cannot be rewired in-game.", alwaysUseInstanceValues: true)]
[Editable, Serialize(false, IsPropertySaveable.Yes, description: "Locked connection panels cannot be rewired in-game.", alwaysUseInstanceValues: true)]
public bool Locked
{
get;
@@ -63,12 +64,12 @@ namespace Barotrauma.Items.Components
get { return user; }
}
public ConnectionPanel(Item item, XElement element)
public ConnectionPanel(Item item, ContentXElement element)
: base(item, element)
{
Connections = new List<Connection>();
foreach (XElement subElement in element.Elements())
foreach (var subElement in element.Elements())
{
switch (subElement.Name.ToString())
{
@@ -264,13 +265,13 @@ namespace Barotrauma.Items.Components
return false;
}
public override void Load(XElement element, bool usePrefabValues, IdRemap idRemap)
public override void Load(ContentXElement element, bool usePrefabValues, IdRemap idRemap)
{
base.Load(element, usePrefabValues, idRemap);
List<Connection> loadedConnections = new List<Connection>();
foreach (XElement subElement in element.Elements())
foreach (var subElement in element.Elements())
{
switch (subElement.Name.ToString())
{
@@ -306,7 +307,7 @@ namespace Barotrauma.Items.Components
}
}
disconnectedWireIds = element.GetAttributeUshortArray("disconnectedwires", new ushort[0]).ToList();
disconnectedWireIds = element.GetAttributeUshortArray("disconnectedwires", Array.Empty<ushort>()).ToList();
for (int i = 0; i < disconnectedWireIds.Count; i++)
{
disconnectedWireIds[i] = idRemap.GetOffsetId(disconnectedWireIds[i]);
@@ -399,7 +400,7 @@ namespace Barotrauma.Items.Components
}
public void ClientWrite(IWriteMessage msg, object[] extraData = null)
public void ClientEventWrite(IWriteMessage msg, NetEntityEvent.IData extraData = null)
{
#if CLIENT
TriggerRewiringSound();
@@ -1,4 +1,5 @@
using Barotrauma.Networking;
using System;
using Barotrauma.Networking;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
@@ -7,20 +8,30 @@ namespace Barotrauma.Items.Components
{
partial class CustomInterface : ItemComponent, IClientSerializable, IServerSerializable
{
public class CustomInterfaceElement : ISerializableEntity
private readonly struct EventData : IEventData
{
public readonly CustomInterfaceElement BtnElement;
public EventData(CustomInterfaceElement btnElement)
{
BtnElement = btnElement;
}
}
class CustomInterfaceElement : ISerializableEntity
{
public bool ContinuousSignal;
public bool State;
public string ConnectionName;
public Connection Connection;
[Serialize("", false, translationTextTag: "Label.", description: "The text displayed on this button/tickbox."), Editable]
[Serialize("", IsPropertySaveable.No, 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]
[Serialize("1", IsPropertySaveable.No, 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 Identifier PropertyName { get; }
public bool TargetOnlyParentProperty { get; }
public int NumberInputMin { get; }
@@ -35,7 +46,7 @@ namespace Barotrauma.Items.Components
public string Name => "CustomInterfaceElement";
public Dictionary<string, SerializableProperty> SerializableProperties { get; set; }
public Dictionary<Identifier, SerializableProperty> SerializableProperties { get; set; }
public List<StatusEffect> StatusEffects = new List<StatusEffect>();
@@ -43,19 +54,19 @@ namespace Barotrauma.Items.Components
/// 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)
public CustomInterfaceElement(Item item, ContentXElement element, CustomInterface parent)
{
Label = element.GetAttributeString("text", "");
ConnectionName = element.GetAttributeString("connection", "");
PropertyName = element.GetAttributeString("propertyname", "").ToLowerInvariant();
PropertyName = element.GetAttributeIdentifier("propertyname", "");
TargetOnlyParentProperty = element.GetAttributeBool("targetonlyparentproperty", false);
NumberInputMin = element.GetAttributeInt("min", DefaultNumberInputMin);
NumberInputMax = element.GetAttributeInt("max", DefaultNumberInputMax);
MaxTextLength = element.GetAttributeInt("maxtextlength", int.MaxValue);
HasPropertyName = !string.IsNullOrEmpty(PropertyName);
HasPropertyName = !PropertyName.IsEmpty;
IsIntegerInput = HasPropertyName && element.Name.ToString().ToLowerInvariant() == "integerinput";
if (element.Attribute("signal") is XAttribute attribute)
if (element.GetAttribute("signal") is XAttribute attribute)
{
Signal = attribute.Value;
ShouldSetProperty = HasPropertyName;
@@ -84,7 +95,7 @@ namespace Barotrauma.Items.Components
Signal = "1";
}
foreach (XElement subElement in element.Elements())
foreach (var subElement in element.Elements())
{
if (subElement.Name.ToString().Equals("statuseffect", System.StringComparison.OrdinalIgnoreCase))
{
@@ -95,7 +106,7 @@ namespace Barotrauma.Items.Components
}
private string[] labels;
[Serialize("", true, description: "The texts displayed on the buttons/tickboxes, separated by commas.", alwaysUseInstanceValues: true)]
[Serialize("", IsPropertySaveable.Yes, description: "The texts displayed on the buttons/tickboxes, separated by commas.", alwaysUseInstanceValues: true)]
public string Labels
{
get { return string.Join(",", labels); }
@@ -104,14 +115,14 @@ namespace Barotrauma.Items.Components
if (value == null) { return; }
if (customInterfaceElementList.Count > 0)
{
string[] splitValues = value == "" ? new string[0] : value.Split(',');
string[] splitValues = value == "" ? Array.Empty<string>() : 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.", alwaysUseInstanceValues: true)]
[Serialize("", IsPropertySaveable.Yes, description: "The signals sent when the buttons are pressed or the tickboxes checked, separated by commas.", alwaysUseInstanceValues: true)]
public string Signals
{
//use semicolon as a separator because comma may be needed in the signals (for color or vector values for example)
@@ -122,7 +133,7 @@ namespace Barotrauma.Items.Components
if (value == null) { return; }
if (customInterfaceElementList.Count > 0)
{
string[] splitValues = value == "" ? new string[0] : value.Split(';');
string[] splitValues = value == "" ? Array.Empty<string>() : value.Split(';');
UpdateSignals(splitValues);
}
}
@@ -132,17 +143,17 @@ namespace Barotrauma.Items.Components
public readonly List<CustomInterfaceElement> customInterfaceElementList = new List<CustomInterfaceElement>();
public CustomInterface(Item item, XElement element)
public CustomInterface(Item item, ContentXElement element)
: base(item, element)
{
foreach (XElement subElement in element.Elements())
foreach (var subElement in element.Elements())
{
switch (subElement.Name.ToString().ToLowerInvariant())
{
case "button":
case "textbox":
case "integerinput":
var button = new CustomInterfaceElement(subElement, this)
var button = new CustomInterfaceElement(item, subElement, this)
{
ContinuousSignal = false
};
@@ -153,7 +164,7 @@ namespace Barotrauma.Items.Components
customInterfaceElementList.Add(button);
break;
case "tickbox":
var tickBox = new CustomInterfaceElement(subElement, this)
var tickBox = new CustomInterfaceElement(item, subElement, this)
{
ContinuousSignal = true
};
@@ -179,7 +190,7 @@ namespace Barotrauma.Items.Components
labels[i] = i < newLabels.Length ? newLabels[i] : customInterfaceElementList[i].Label;
if (Screen.Selected != GameMain.SubEditorScreen)
{
customInterfaceElementList[i].Label = TextManager.Get(labels[i], returnNull: true) ?? labels[i];
customInterfaceElementList[i].Label = TextManager.Get(labels[i]).Fallback(labels[i]).Value;
}
else
{
@@ -30,7 +30,7 @@ namespace Barotrauma.Items.Components
private DelayedSignal prevQueuedSignal;
private float delay;
[InGameEditable(MinValueFloat = 0.0f, MaxValueFloat = 60.0f, DecimalCount = 2), Serialize(1.0f, true, description: "How long the item delays the signals (in seconds).", alwaysUseInstanceValues: true)]
[InGameEditable(MinValueFloat = 0.0f, MaxValueFloat = 60.0f, DecimalCount = 2), Serialize(1.0f, IsPropertySaveable.Yes, description: "How long the item delays the signals (in seconds).", alwaysUseInstanceValues: true)]
public float Delay
{
get { return delay; }
@@ -44,21 +44,21 @@ namespace Barotrauma.Items.Components
}
}
[InGameEditable, Serialize(false, true, description: "Should the component discard previously received signals when a new one is received.", alwaysUseInstanceValues: true)]
[InGameEditable, Serialize(false, IsPropertySaveable.Yes, description: "Should the component discard previously received signals when a new one is received.", alwaysUseInstanceValues: true)]
public bool ResetWhenSignalReceived
{
get;
set;
}
[InGameEditable, Serialize(false, true, description: "Should the component discard previously received signals when the incoming signal changes.", alwaysUseInstanceValues: true)]
[InGameEditable, Serialize(false, IsPropertySaveable.Yes, description: "Should the component discard previously received signals when the incoming signal changes.", alwaysUseInstanceValues: true)]
public bool ResetWhenDifferentSignalReceived
{
get;
set;
}
public DelayComponent(Item item, XElement element)
public DelayComponent(Item item, ContentXElement element)
: base (item, element)
{
IsActive = true;
@@ -4,7 +4,7 @@ namespace Barotrauma.Items.Components
{
class DivideComponent : ArithmeticComponent
{
public DivideComponent(Item item, XElement element)
public DivideComponent(Item item, ContentXElement element)
: base(item, element)
{
}
@@ -18,7 +18,7 @@ namespace Barotrauma.Items.Components
protected float timeFrame;
private int maxOutputLength;
[Editable, Serialize(200, false, description: "The maximum length of the output strings. Warning: Large values can lead to large memory usage or networking issues.")]
[Editable, Serialize(200, IsPropertySaveable.No, description: "The maximum length of the output strings. Warning: Large values can lead to large memory usage or networking issues.")]
public int MaxOutputLength
{
get { return maxOutputLength; }
@@ -28,7 +28,7 @@ namespace Barotrauma.Items.Components
}
}
[InGameEditable, Serialize("1", true, description: "The signal sent when the condition is met.", alwaysUseInstanceValues: true)]
[InGameEditable, Serialize("1", IsPropertySaveable.Yes, description: "The signal sent when the condition is met.", alwaysUseInstanceValues: true)]
public string Output
{
get { return output; }
@@ -43,7 +43,7 @@ namespace Barotrauma.Items.Components
}
}
[InGameEditable, Serialize("", true, description: "The signal sent when the condition is met (if empty, no signal is sent).", alwaysUseInstanceValues: true)]
[InGameEditable, Serialize("", IsPropertySaveable.Yes, description: "The signal sent when the condition is met (if empty, no signal is sent).", alwaysUseInstanceValues: true)]
public string FalseOutput
{
get { return falseOutput; }
@@ -58,7 +58,7 @@ namespace Barotrauma.Items.Components
}
}
[InGameEditable(DecimalCount = 2), Serialize(0.0f, true, description: "The maximum amount of time between the received signals. If set to 0, the signals must be received at the same time.", alwaysUseInstanceValues: true)]
[InGameEditable(DecimalCount = 2), Serialize(0.0f, IsPropertySaveable.Yes, description: "The maximum amount of time between the received signals. If set to 0, the signals must be received at the same time.", alwaysUseInstanceValues: true)]
public float TimeFrame
{
get { return timeFrame; }
@@ -72,7 +72,7 @@ namespace Barotrauma.Items.Components
}
}
public EqualsComponent(Item item, XElement element)
public EqualsComponent(Item item, ContentXElement element)
: base(item, element)
{
timeSinceReceived = new float[] { Math.Max(timeFrame * 2.0f, 0.1f), Math.Max(timeFrame * 2.0f, 0.1f) };
@@ -6,7 +6,7 @@ namespace Barotrauma.Items.Components
class ExponentiationComponent : ItemComponent
{
private float exponent;
[InGameEditable, Serialize(1.0f, false, description: "The exponent of the operation.", alwaysUseInstanceValues: true)]
[InGameEditable, Serialize(1.0f, IsPropertySaveable.No, description: "The exponent of the operation.", alwaysUseInstanceValues: true)]
public float Exponent
{
get
@@ -19,7 +19,7 @@ namespace Barotrauma.Items.Components
}
}
public ExponentiationComponent(Item item, XElement element)
public ExponentiationComponent(Item item, ContentXElement element)
: base(item, element)
{
IsActive = true;
@@ -16,13 +16,13 @@ namespace Barotrauma.Items.Components
SquareRoot
}
[Serialize(FunctionType.Round, false, description: "Which kind of function to run the input through.", alwaysUseInstanceValues: true)]
[Serialize(FunctionType.Round, IsPropertySaveable.No, description: "Which kind of function to run the input through.", alwaysUseInstanceValues: true)]
public FunctionType Function
{
get; set;
}
public FunctionComponent(Item item, XElement element)
public FunctionComponent(Item item, ContentXElement element)
: base(item, element)
{
IsActive = true;
@@ -7,7 +7,7 @@ namespace Barotrauma.Items.Components
{
private float val1, val2;
public GreaterComponent(Item item, XElement element)
public GreaterComponent(Item item, ContentXElement element)
: base(item, element)
{
IsActive = true;
@@ -30,7 +30,7 @@ namespace Barotrauma.Items.Components
private Turret turret;
[Serialize(100.0f, true, description: "The range of the emitted light. Higher values are more performance-intensive.", alwaysUseInstanceValues: true),
[Serialize(100.0f, IsPropertySaveable.Yes, 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
{
@@ -56,8 +56,8 @@ namespace Barotrauma.Items.Components
}
}
[Editable, Serialize(true, true, description: "Should structures cast shadows when light from this light source hits them. " +
"Disabling shadows increases the performance of the game, and is recommended for lights with a short range.", alwaysUseInstanceValues: true)]
[Editable, Serialize(true, IsPropertySaveable.Yes, description: "Should structures cast shadows when light from this light source hits them. " +
"Disabling shadows increases the performance of the game, and is recommended for lights with a short range. Lights that are set to be drawn behind subs don't cast shadows, regardless of this setting.", alwaysUseInstanceValues: true)]
public bool CastShadows
{
get { return castShadows; }
@@ -70,7 +70,7 @@ namespace Barotrauma.Items.Components
}
}
[Editable, Serialize(false, true, description: "Lights drawn behind submarines don't cast any shadows and are much faster to draw than shadow-casting lights. " +
[Editable, Serialize(false, IsPropertySaveable.Yes, description: "Lights drawn behind submarines don't cast any shadows and are much faster to draw than shadow-casting lights. " +
"It's recommended to enable this on decorative lights outside the submarine's hull.", alwaysUseInstanceValues: true)]
public bool DrawBehindSubs
{
@@ -84,7 +84,7 @@ namespace Barotrauma.Items.Components
}
}
[Editable, Serialize(false, true, description: "Is the light currently on.", alwaysUseInstanceValues: true)]
[Editable, Serialize(false, IsPropertySaveable.Yes, description: "Is the light currently on.", alwaysUseInstanceValues: true)]
public bool IsOn
{
get { return isOn; }
@@ -98,7 +98,7 @@ namespace Barotrauma.Items.Components
}
}
[Editable, Serialize(0.0f, false, description: "How heavily the light flickers. 0 = no flickering, 1 = the light will alternate between completely dark and full brightness.")]
[Editable, Serialize(0.0f, IsPropertySaveable.No, description: "How heavily the light flickers. 0 = no flickering, 1 = the light will alternate between completely dark and full brightness.")]
public float Flicker
{
get { return flicker; }
@@ -111,7 +111,7 @@ namespace Barotrauma.Items.Components
}
}
[Editable, Serialize(1.0f, false, description: "How fast the light flickers.")]
[Editable, Serialize(1.0f, IsPropertySaveable.No, description: "How fast the light flickers.")]
public float FlickerSpeed
{
get { return flickerSpeed; }
@@ -124,7 +124,7 @@ namespace Barotrauma.Items.Components
}
}
[Editable, Serialize(0.0f, true, description: "How rapidly the light pulsates (in Hz). 0 = no blinking.")]
[Editable, Serialize(0.0f, IsPropertySaveable.Yes, description: "How rapidly the light pulsates (in Hz). 0 = no blinking.")]
public float PulseFrequency
{
get { return pulseFrequency; }
@@ -137,7 +137,7 @@ namespace Barotrauma.Items.Components
}
}
[Editable(MinValueFloat = 0.0f, MaxValueFloat = 1.0f, DecimalCount = 2), Serialize(0.0f, true, description: "How much light pulsates (in Hz). 0 = not at all, 1 = alternates between full brightness and off.")]
[Editable(MinValueFloat = 0.0f, MaxValueFloat = 1.0f, DecimalCount = 2), Serialize(0.0f, IsPropertySaveable.Yes, description: "How much light pulsates (in Hz). 0 = not at all, 1 = alternates between full brightness and off.")]
public float PulseAmount
{
get { return pulseAmount; }
@@ -150,7 +150,7 @@ namespace Barotrauma.Items.Components
}
}
[Editable, Serialize(0.0f, true, description: "How rapidly the light blinks on and off (in Hz). 0 = no blinking.")]
[Editable, Serialize(0.0f, IsPropertySaveable.Yes, description: "How rapidly the light blinks on and off (in Hz). 0 = no blinking.")]
public float BlinkFrequency
{
get { return blinkFrequency; }
@@ -163,7 +163,7 @@ namespace Barotrauma.Items.Components
}
}
[InGameEditable(FallBackTextTag = "connection.setcolor"), Serialize("255,255,255,255", true, description: "The color of the emitted light (R,G,B,A).", alwaysUseInstanceValues: true)]
[InGameEditable(FallBackTextTag = "connection.setcolor"), Serialize("255,255,255,255", IsPropertySaveable.Yes, description: "The color of the emitted light (R,G,B,A).", alwaysUseInstanceValues: true)]
public Color LightColor
{
get { return lightColor; }
@@ -179,7 +179,7 @@ namespace Barotrauma.Items.Components
}
}
[Serialize(false, false, description: "If enabled, the component will ignore continuous signals received in the toggle input (i.e. a continuous signal will only toggle it once).")]
[Serialize(false, IsPropertySaveable.No, description: "If enabled, the component will ignore continuous signals received in the toggle input (i.e. a continuous signal will only toggle it once).")]
public bool IgnoreContinuousToggle
{
get;
@@ -208,7 +208,7 @@ namespace Barotrauma.Items.Components
}
}
public LightComponent(Item item, XElement element)
public LightComponent(Item item, ContentXElement element)
: base(item, element)
{
#if CLIENT
@@ -264,8 +264,6 @@ namespace Barotrauma.Items.Components
}
UpdateOnActiveEffects(deltaTime);
if (powerIn == null && powerConsumption > 0.0f) { Voltage -= deltaTime; }
#if CLIENT
Light.ParentSub = item.Submarine;
#endif
@@ -284,7 +282,7 @@ namespace Barotrauma.Items.Components
return;
}
currPowerConsumption = powerConsumption;
//currPowerConsumption = powerConsumption;
if (Rand.Range(0.0f, 1.0f) < 0.05f && Voltage < Rand.Range(0.0f, MinVoltage))
{
#if CLIENT
@@ -7,7 +7,7 @@ namespace Barotrauma.Items.Components
partial class MemoryComponent : ItemComponent, IServerSerializable
{
private int maxValueLength;
[Editable, Serialize(200, false, description: "The maximum length of the stored value. Warning: Large values can lead to large memory usage or networking issues.")]
[Editable, Serialize(200, IsPropertySaveable.No, description: "The maximum length of the stored value. Warning: Large values can lead to large memory usage or networking issues.")]
public int MaxValueLength
{
get { return maxValueLength; }
@@ -19,7 +19,7 @@ namespace Barotrauma.Items.Components
private string value;
[InGameEditable, Serialize("", true, description: "The currently stored signal the item outputs.", alwaysUseInstanceValues: true)]
[InGameEditable, Serialize("", IsPropertySaveable.Yes, description: "The currently stored signal the item outputs.", alwaysUseInstanceValues: true)]
public string Value
{
get { return value; }
@@ -34,14 +34,14 @@ namespace Barotrauma.Items.Components
}
}
[Editable, Serialize(true, true, description: "Can the value stored in the memory component be changed via signals.", alwaysUseInstanceValues: true)]
[Editable, Serialize(true, IsPropertySaveable.Yes, description: "Can the value stored in the memory component be changed via signals.", alwaysUseInstanceValues: true)]
public bool Writeable
{
get;
set;
}
public MemoryComponent(Item item, XElement element)
public MemoryComponent(Item item, ContentXElement element)
: base(item, element)
{
IsActive = true;
@@ -6,7 +6,7 @@ namespace Barotrauma.Items.Components
class ModuloComponent : ItemComponent
{
private float modulus;
[InGameEditable, Serialize(1.0f, false, description: "The modulus of the operation. Must be non-zero.", alwaysUseInstanceValues: true)]
[InGameEditable, Serialize(1.0f, IsPropertySaveable.No, description: "The modulus of the operation. Must be non-zero.", alwaysUseInstanceValues: true)]
public float Modulus
{
get { return modulus; }
@@ -16,7 +16,7 @@ namespace Barotrauma.Items.Components
}
}
public ModuloComponent(Item item, XElement element) : base(item, element)
public ModuloComponent(Item item, ContentXElement element) : base(item, element)
{
IsActive = true;
}
@@ -1,7 +1,6 @@
using FarseerPhysics;
using Microsoft.Xna.Framework;
using System;
using System.Linq;
using System.Xml.Linq;
namespace Barotrauma.Items.Components
@@ -22,17 +21,17 @@ namespace Barotrauma.Items.Components
Wall
}
[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).")]
[Serialize(false, IsPropertySaveable.No, 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; }
[InGameEditable, Serialize(TargetType.Any, true, description: "Which kind of targets can trigger the sensor?", alwaysUseInstanceValues: true)]
[InGameEditable, Serialize(TargetType.Any, IsPropertySaveable.Yes, description: "Which kind of targets can trigger the sensor?", alwaysUseInstanceValues: true)]
public TargetType Target
{
get;
set;
}
[InGameEditable, Serialize(false, true, description: "Should the sensor ignore the bodies of dead characters?", alwaysUseInstanceValues: true)]
[InGameEditable, Serialize(false, IsPropertySaveable.Yes, description: "Should the sensor ignore the bodies of dead characters?", alwaysUseInstanceValues: true)]
public bool IgnoreDead
{
get;
@@ -40,7 +39,7 @@ namespace Barotrauma.Items.Components
}
[InGameEditable, Serialize(0.0f, true, description: "Horizontal detection range.", alwaysUseInstanceValues: true)]
[InGameEditable, Serialize(0.0f, IsPropertySaveable.Yes, description: "Horizontal detection range.", alwaysUseInstanceValues: true)]
public float RangeX
{
get { return rangeX; }
@@ -52,7 +51,7 @@ namespace Barotrauma.Items.Components
#endif
}
}
[InGameEditable, Serialize(0.0f, true, description: "Vertical movement detection range.", alwaysUseInstanceValues: true)]
[InGameEditable, Serialize(0.0f, IsPropertySaveable.Yes, description: "Vertical movement detection range.", alwaysUseInstanceValues: true)]
public float RangeY
{
get { return rangeY; }
@@ -62,7 +61,7 @@ namespace Barotrauma.Items.Components
}
}
[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.")]
[InGameEditable, Serialize("0,0", IsPropertySaveable.Yes, 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; }
@@ -85,7 +84,7 @@ namespace Barotrauma.Items.Components
}
}
[Editable(MinValueFloat = 0.1f, MaxValueFloat = 100.0f, DecimalCount = 2), Serialize(0.1f, true, description: "How often the sensor checks if there's something moving near it. Higher values are better for performance.", alwaysUseInstanceValues: true)]
[Editable(MinValueFloat = 0.1f, MaxValueFloat = 100.0f, DecimalCount = 2), Serialize(0.1f, IsPropertySaveable.Yes, description: "How often the sensor checks if there's something moving near it. Higher values are better for performance.", alwaysUseInstanceValues: true)]
public float UpdateInterval
{
get;
@@ -93,7 +92,7 @@ namespace Barotrauma.Items.Components
}
private int maxOutputLength;
[Editable, Serialize(200, false, description: "The maximum length of the output strings. Warning: Large values can lead to large memory usage or networking issues.")]
[Editable, Serialize(200, IsPropertySaveable.No, description: "The maximum length of the output strings. Warning: Large values can lead to large memory usage or networking issues.")]
public int MaxOutputLength
{
get { return maxOutputLength; }
@@ -104,7 +103,7 @@ namespace Barotrauma.Items.Components
}
private string output;
[InGameEditable, Serialize("1", true, description: "The signal the item outputs when it has detected movement.", alwaysUseInstanceValues: true)]
[InGameEditable, Serialize("1", IsPropertySaveable.Yes, description: "The signal the item outputs when it has detected movement.", alwaysUseInstanceValues: true)]
public string Output
{
get { return output; }
@@ -120,7 +119,7 @@ namespace Barotrauma.Items.Components
}
private string falseOutput;
[InGameEditable, Serialize("", true, description: "The signal the item outputs when it has not detected movement.", alwaysUseInstanceValues: true)]
[InGameEditable, Serialize("", IsPropertySaveable.Yes, description: "The signal the item outputs when it has not detected movement.", alwaysUseInstanceValues: true)]
public string FalseOutput
{
get { return falseOutput; }
@@ -135,27 +134,27 @@ namespace Barotrauma.Items.Components
}
}
[Editable(DecimalCount = 3), Serialize(0.01f, true, description: "How fast the objects within the detector's range have to be moving (in m/s).", alwaysUseInstanceValues: true)]
[Editable(DecimalCount = 3), Serialize(0.01f, IsPropertySaveable.Yes, description: "How fast the objects within the detector's range have to be moving (in m/s).", alwaysUseInstanceValues: true)]
public float MinimumVelocity
{
get;
set;
}
[Serialize(true, true, description: "Should the sensor trigger when the item itself moves.")]
[Serialize(true, IsPropertySaveable.Yes, description: "Should the sensor trigger when the item itself moves.")]
public bool DetectOwnMotion
{
get;
set;
}
public MotionSensor(Item item, XElement element)
public MotionSensor(Item item, ContentXElement element)
: base(item, element)
{
IsActive = true;
//backwards compatibility
if (element.Attribute("range") != null)
if (element.GetAttribute("range") != null)
{
rangeX = rangeY = element.GetAttributeFloat("range", 0.0f);
}
@@ -164,7 +163,7 @@ namespace Barotrauma.Items.Components
updateTimer = Rand.Range(0.0f, UpdateInterval);
}
public override void Load(XElement componentElement, bool usePrefabValues, IdRemap idRemap)
public override void Load(ContentXElement componentElement, bool usePrefabValues, IdRemap idRemap)
{
base.Load(componentElement, usePrefabValues, idRemap);
//backwards compatibility
@@ -4,7 +4,7 @@ namespace Barotrauma.Items.Components
{
class MultiplyComponent : ArithmeticComponent
{
public MultiplyComponent(Item item, XElement element)
public MultiplyComponent(Item item, ContentXElement element)
: base(item, element)
{
}
@@ -1,20 +1,18 @@
using System.Xml.Linq;
namespace Barotrauma.Items.Components
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)]
[InGameEditable, Serialize(false, IsPropertySaveable.Yes, 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)
public NotComponent(Item item, ContentXElement element)
: base (item, element)
{
}
@@ -4,7 +4,7 @@ namespace Barotrauma.Items.Components
{
class OrComponent : AndComponent
{
public OrComponent(Item item, XElement element)
public OrComponent(Item item, ContentXElement element)
: base(item, element)
{
IsActive = true;
@@ -22,7 +22,7 @@ namespace Barotrauma.Items.Components
private float phase;
[InGameEditable, Serialize(WaveType.Pulse, true, description: "What kind of a signal the item outputs." +
[InGameEditable, Serialize(WaveType.Pulse, IsPropertySaveable.Yes, description: "What kind of a signal the item outputs." +
" Pulse: periodically sends out a signal of 1." +
" Sawtooth: sends out a periodic wave that increases linearly from 0 to 1." +
" Sine: sends out a sine wave oscillating between -1 and 1." +
@@ -35,7 +35,7 @@ namespace Barotrauma.Items.Components
set;
}
[InGameEditable(DecimalCount = 2), Serialize(1.0f, true, description: "How fast the signal oscillates, or how fast the pulses are sent (in Hz).", alwaysUseInstanceValues: true)]
[InGameEditable(DecimalCount = 2), Serialize(1.0f, IsPropertySaveable.Yes, description: "How fast the signal oscillates, or how fast the pulses are sent (in Hz).", alwaysUseInstanceValues: true)]
public float Frequency
{
get { return frequency; }
@@ -47,7 +47,7 @@ namespace Barotrauma.Items.Components
}
}
public OscillatorComponent(Item item, XElement element) :
public OscillatorComponent(Item item, ContentXElement element) :
base(item, element)
{
IsActive = true;
@@ -4,10 +4,12 @@ namespace Barotrauma.Items.Components
{
class OxygenDetector : ItemComponent
{
public const int LowOxygenPercentage = 35;
private int prevSentOxygenValue;
private string oxygenSignal;
public OxygenDetector(Item item, XElement element)
public OxygenDetector(Item item, ContentXElement element)
: base (item, element)
{
IsActive = true;
@@ -17,13 +19,15 @@ namespace Barotrauma.Items.Components
{
if (item.CurrentHull == null) { return; }
if (prevSentOxygenValue != (int)item.CurrentHull.OxygenPercentage || oxygenSignal == null)
int currOxygenPercentage = (int)item.CurrentHull.OxygenPercentage;
if (prevSentOxygenValue != currOxygenPercentage || oxygenSignal == null)
{
prevSentOxygenValue = (int)item.CurrentHull.OxygenPercentage;
prevSentOxygenValue = currOxygenPercentage;
oxygenSignal = prevSentOxygenValue.ToString();
}
item.SendSignal(oxygenSignal, "signal_out");
item.SendSignal(oxygenSignal, "signal_out");
item.SendSignal(currOxygenPercentage <= LowOxygenPercentage ? "1" : "0", "low_oxygen");
}
}
@@ -21,7 +21,7 @@ namespace Barotrauma.Items.Components
private bool nonContinuousOutputSent;
private int maxOutputLength;
[Editable, Serialize(200, false, description: "The maximum length of the output string. Warning: Large values can lead to large memory usage or networking issues.")]
[Editable, Serialize(200, IsPropertySaveable.No, description: "The maximum length of the output string. Warning: Large values can lead to large memory usage or networking issues.")]
public int MaxOutputLength
{
get { return maxOutputLength; }
@@ -33,7 +33,7 @@ namespace Barotrauma.Items.Components
private string output;
[InGameEditable, Serialize("1", true, description: "The signal this item outputs when the received signal matches the regular expression.", alwaysUseInstanceValues: true)]
[InGameEditable, Serialize("1", IsPropertySaveable.Yes, description: "The signal this item outputs when the received signal matches the regular expression.", alwaysUseInstanceValues: true)]
public string Output
{
get { return output; }
@@ -48,16 +48,16 @@ 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)]
[InGameEditable, Serialize(false, IsPropertySaveable.Yes, description: "Should the component output a value of a capture group instead of a constant signal.", alwaysUseInstanceValues: true)]
public bool UseCaptureGroup { get; set; }
[InGameEditable, Serialize("0", true, description: "The signal this item outputs when the received signal does not match the regular expression.", alwaysUseInstanceValues: true)]
[InGameEditable, Serialize("0", IsPropertySaveable.Yes, 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)]
[InGameEditable, Serialize(true, IsPropertySaveable.Yes, 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)]
public bool ContinuousOutput { get; set; }
[InGameEditable, Serialize("", true, description: "The regular expression used to check the incoming signals.", alwaysUseInstanceValues: true)]
[InGameEditable, Serialize("", IsPropertySaveable.Yes, description: "The regular expression used to check the incoming signals.", alwaysUseInstanceValues: true)]
public string Expression
{
get { return expression; }
@@ -82,7 +82,7 @@ namespace Barotrauma.Items.Components
}
}
public RegExFindComponent(Item item, XElement element)
public RegExFindComponent(Item item, ContentXElement element)
: base(item, element)
{
nonContinuousOutputSent = true;
@@ -13,7 +13,23 @@ namespace Barotrauma.Items.Components
private bool isOn;
private float throttlePowerOutput;
private float prevVoltage;
private float? newVoltage = null;
//internal load buffer that's used to isolate the input and output sides from each other
private float internalLoadBuffer = 0;
//previous load (used to smooth changes in the load to prevent oscillations)
private float prevInternalLoad = 0;
//previous load on the output side
private float prevExternalLoad = 0;
//difference between the internal load buffer and external load
private float bufferDiff = 0;
private float thirdInverseMax = 0, loadEqnConstant = 0;
private static readonly Dictionary<string, string> connectionPairs = new Dictionary<string, string>
{
@@ -25,19 +41,36 @@ namespace Barotrauma.Items.Components
{ "signal_in4", "signal_out4" },
{ "signal_in5", "signal_out5" }
};
public float DisplayLoad { get; set; }
[Editable, Serialize(1000.0f, true, description: "The maximum amount of power that can pass through the item.")]
protected override PowerPriority Priority { get { return PowerPriority.Relay; } }
public float DisplayLoad
{
get
{
if (powerOut != null && powerOut.Grid != null)
{
return powerOut.Grid.Load;
}
else
{
return 0;
}
}
}
[Editable, Serialize(1000.0f, IsPropertySaveable.Yes, description: "The maximum amount of power that can pass through the item.")]
public float MaxPower
{
get { return maxPower; }
set
{
maxPower = Math.Max(0.0f, value);
SetLoadFormulaValues();
}
}
[Editable, Serialize(true, true, description: "Can the relay currently pass power and signals through it.", alwaysUseInstanceValues: true)]
[Editable, Serialize(true, IsPropertySaveable.Yes, description: "Can the relay currently pass power and signals through it.", alwaysUseInstanceValues: true)]
public bool IsOn
{
get
@@ -55,13 +88,23 @@ namespace Barotrauma.Items.Components
}
}
public RelayComponent(Item item, XElement element)
public RelayComponent(Item item, ContentXElement element)
: base(item, element)
{
IsActive = true;
throttlePowerOutput = MaxPower;
prevVoltage = 0;
SetLoadFormulaValues();
}
private void SetLoadFormulaValues()
{
internalLoadBuffer = MaxPower * 2;
// Set constants for load Formula to reduce calculation time
thirdInverseMax = 1 / (3 * maxPower);
loadEqnConstant = (8 * maxPower) / 3;
}
public override void OnItemLoaded()
{
base.OnItemLoaded();
@@ -87,8 +130,8 @@ namespace Barotrauma.Items.Components
RefreshConnections();
item.SendSignal(IsOn ? "1" : "0", "state_out");
if (!CanTransfer) { Voltage = 0.0f; return; }
item.SendSignal(((int)Math.Round(-PowerLoad)).ToString(), "power_value_out");
item.SendSignal(((int)Math.Round(DisplayLoad)).ToString(), "load_value_out");
if (isBroken)
{
@@ -98,75 +141,199 @@ namespace Barotrauma.Items.Components
ApplyStatusEffects(ActionType.OnActive, deltaTime, null);
if (powerOut != null)
{
bool overloaded = false;
foreach (Connection recipient in powerOut.Recipients)
{
var pt = recipient.Item.GetComponent<PowerTransfer>();
if (pt != null)
{
float overload = -pt.CurrPowerConsumption - pt.PowerLoad;
throttlePowerOutput += overload * deltaTime * 0.5f;
overloaded = overload > 1.0f;
}
}
throttlePowerOutput = overloaded ?
MathHelper.Clamp(throttlePowerOutput, 0.0f, MaxPower):
Math.Max(throttlePowerOutput - MaxPower * 0.1f * deltaTime, 0.0f);
}
if (Math.Min(-currPowerConsumption, PowerLoad) > maxPower && CanBeOverloaded)
if (Voltage > OverloadVoltage && CanBeOverloaded)
{
item.Condition = 0.0f;
}
}
public override void ReceivePowerProbeSignal(Connection connection, Item source, float power)
/// <summary>
/// Relay power consumption. Load consumption is based on the internal buffer.
/// This allows for the relay to react to demand and find equilibrium in loop configurations.
/// </summary>
public override float GetCurrentPowerConsumption(Connection connection = null)
{
if (!IsOn || item.Condition <= 0.0f) { return; }
//we've already received this signal
if (lastPowerProbeRecipients.Contains(this)) { return; }
lastPowerProbeRecipients.Add(this);
if (power < 0.0f)
//Can't output or draw if broken
if (isBroken)
{
if (!connection.IsOutput || powerIn == null) { return; }
return 0;
}
//power being drawn from the power_out connection
DisplayLoad -= Math.Min(power, 0.0f);
powerLoad -= Math.Min(power + throttlePowerOutput, 0.0f);
if (connection == powerIn)
{
float currentLoad = MaxPower;
if (internalLoadBuffer > MaxPower)
{
//Buffer load charging curve - special relay sauce
// Original formula (buffer - 3 * maxPower)^2 / (3 * maxPower) - (maxPower / 3)
//loadDraw = MathHelper.Clamp((float)Math.Pow(internalBuffer - 3 * MaxPower, 2) / (3 * MaxPower) - MaxPower / 3, 1, MaxPower);
//Optimised formula 0.2% error from original
currentLoad = MathHelper.Clamp(internalLoadBuffer * internalLoadBuffer * thirdInverseMax - 2 * internalLoadBuffer + loadEqnConstant, 0.001f, MaxPower);
//pass the load to items connected to the input
powerIn.SendPowerProbeSignal(source, Math.Max(power, -MaxPower));
//Slight smoothing to load to minimise relay jank
currentLoad = MathHelper.Clamp((currentLoad + prevInternalLoad * 0.1f) / 1.1f, 0.001f, MaxPower);
prevInternalLoad = currentLoad;
}
//Add on extra load after calculation
currentLoad += ExtraLoad;
return currentLoad;
}
else
{
if (connection.IsOutput || powerOut == null) { return; }
//power being supplied to the power_in connection
if (currPowerConsumption - power < -MaxPower)
//Flag output as power out
return -1;
}
}
private bool RelayCanOutput()
{
//Only allow output if device is on, buffers have charge and the connected grids aren't short circuited
return isOn && powerIn != null && powerIn.Grid != null && internalLoadBuffer > 0 && powerOut != null && powerOut.Grid != null && powerIn.Grid != powerOut.Grid;
}
/// <summary>
/// Minimum and maximum power out for the relay.
/// Max out is adjusted to allow for other relays to compensate if this relay is undervolted.
/// </summary>
public override PowerRange MinMaxPowerOut(Connection connection, float load = 0)
{
if (connection == powerOut)
{
if (RelayCanOutput())
{
power += MaxPower + (currPowerConsumption - power);
}
//Determine output limits from buffer and voltage
float bufferDraw = MathHelper.Min(internalLoadBuffer, MaxPower);
float voltageLimit = MathHelper.Min(MaxPower, load) * prevVoltage;
currPowerConsumption -= power;
//If undervolted adjust max output so that other relays can compensate
if (prevVoltage < 1)
{
voltageLimit *= prevVoltage;
}
foreach (Connection recipient in powerOut.Recipients)
{
if (!recipient.IsPower) { continue; }
var powered = recipient.Item.GetComponent<Powered>();
if (powered == null) { continue; }
float load = powered.CurrPowerConsumption;
var powerTransfer = powered as PowerTransfer;
if (powerTransfer != null) { load = powerTransfer.PowerLoad; }
float powerOut = power * (load / Math.Max(powerLoad + throttlePowerOutput, 0.01f));
powered.ReceivePowerProbeSignal(recipient, source, Math.Min(powerOut, power));
float maxOutput = MathHelper.Min(voltageLimit, bufferDraw);
return new PowerRange(0.0f, maxOutput);
}
}
return PowerRange.Zero;
}
/// <summary>
/// Power out for the relay connection.
/// Relay will output the necessary power to the grid based on maximum power output of other
/// relays and will undervolt and overvolt the grid following its supply grid.
/// </summary>
/// <returns>Power outputted to the grid</returns>
public override float GetConnectionPowerOut(Connection connection, float power, PowerRange minMaxPower, float load)
{
if (connection == powerIn)
{
return 0.0f;
}
else if (RelayCanOutput())
{
//Determine output limits of the relay
float bufferDraw = MathHelper.Min(internalLoadBuffer, MaxPower);
float voltageLimit = MathHelper.Min(MaxPower, load) * prevVoltage;
float maxOut = MathHelper.Min(voltageLimit, bufferDraw);
//Don't output negative power to the grid
if (maxOut < 0)
{
PowerLoad = 0;
return 0;
}
prevExternalLoad = load;
//Calculate power out
PowerLoad = MathHelper.Clamp((load * prevVoltage - power) / MathHelper.Max(minMaxPower.Max, 1E-20f) * -maxOut, -maxOut, 0);
return -PowerLoad;
}
//Else relay isn't outputting
PowerLoad = 0;
return 0;
}
/// <summary>
/// Connection's grid resolved, determine the difference to be added to the buffer.
/// Ensure the prevVoltage voltage is updated once both grids are resolved.
/// </summary>
public override void GridResolved(Connection conn)
{
if (conn == powerIn)
{
if (powerIn != null && powerIn.Grid != null)
{
float addToBuffer = powerIn.Grid.Voltage * (CurrPowerConsumption - ExtraLoad);
//Limit power input to the previous voltage to prevent wild oscillations in overload
if (powerIn.Grid.Voltage > 1)
{
addToBuffer = prevVoltage * (CurrPowerConsumption - ExtraLoad);
}
//Cap the max power input
if (addToBuffer > MaxPower)
{
addToBuffer = MaxPower;
}
//To prevent problems with grid order, only update voltage and buffer after input and output grids have been resolved
if (newVoltage == null)
{
//temporarily store the new voltage and also indicates that the input connection side has been updated
newVoltage = powerIn.Grid.Voltage;
bufferDiff = addToBuffer;
}
else
{
UpdateBuffer(addToBuffer, powerIn.Grid.Voltage);
}
}
}
else
{
//To prevent problems with grid order, only update voltage and buffer after input and output grids have been resolved
if (newVoltage == null)
{
//Flag that output connection has been updated already
newVoltage = -1;
bufferDiff = PowerLoad;
}
else
{
UpdateBuffer(PowerLoad, (float)newVoltage);
}
}
}
private void UpdateBuffer(float addToBuffer, float newVoltage)
{
//Update buffer and voltage
float limit = MaxPower * 2;
//Clamp the buffer to have a constant load in a severe overload event, otherwise wild oscillation will occur
if (RelayCanOutput() && powerIn.Grid.Voltage > 2)
{
limit = MathHelper.Min(limit, 3 * MaxPower - (float)Math.Sqrt((3 * prevExternalLoad + MaxPower) * MaxPower));
}
//Add to the internal buffer
internalLoadBuffer = MathHelper.Clamp(internalLoadBuffer + bufferDiff + addToBuffer, 0, limit);
//Decay overvoltage slightly, helps resolve large chain loops to a grid
if (newVoltage > 1)
{
newVoltage = MathHelper.Max(newVoltage - 0.0005f, 1);
}
prevVoltage = newVoltage;
this.newVoltage = null;
bufferDiff = 0;
}
public override void ReceiveSignal(Signal signal, Connection connection)
@@ -192,7 +359,7 @@ namespace Barotrauma.Items.Components
public void SetState(bool on, bool isNetworkMessage)
{
#if CLIENT
if (GameMain.Client != null && !isNetworkMessage) return;
if (GameMain.Client != null && !isNetworkMessage) { return; }
#endif
#if SERVER
@@ -205,12 +372,12 @@ namespace Barotrauma.Items.Components
IsOn = on;
}
public void ServerWrite(IWriteMessage msg, Client c, object[] extraData = null)
public void ServerEventWrite(IWriteMessage msg, Client c, NetEntityEvent.IData extraData = null)
{
msg.Write(isOn);
}
public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
public void ClientEventRead(IReadMessage msg, float sendingTime)
{
SetState(msg.ReadBoolean(), true);
}
@@ -6,7 +6,7 @@ namespace Barotrauma.Items.Components
class SignalCheckComponent : ItemComponent
{
private int maxOutputLength;
[Editable, Serialize(200, false, description: "The maximum length of the output strings. Warning: Large values can lead to large memory usage or networking issues.")]
[Editable, Serialize(200, IsPropertySaveable.No, description: "The maximum length of the output strings. Warning: Large values can lead to large memory usage or networking issues.")]
public int MaxOutputLength
{
get { return maxOutputLength; }
@@ -17,7 +17,7 @@ namespace Barotrauma.Items.Components
}
private string output;
[InGameEditable, Serialize("1", true, description: "The signal this item outputs when the received signal matches the target signal.", alwaysUseInstanceValues: true)]
[InGameEditable, Serialize("1", IsPropertySaveable.Yes, description: "The signal this item outputs when the received signal matches the target signal.", alwaysUseInstanceValues: true)]
public string Output
{
get { return output; }
@@ -33,7 +33,7 @@ namespace Barotrauma.Items.Components
}
private string falseOutput;
[InGameEditable, Serialize("0", true, description: "The signal this item outputs when the received signal does not match the target signal.", alwaysUseInstanceValues: true)]
[InGameEditable, Serialize("0", IsPropertySaveable.Yes, description: "The signal this item outputs when the received signal does not match the target signal.", alwaysUseInstanceValues: true)]
public string FalseOutput
{
get { return falseOutput; }
@@ -48,10 +48,10 @@ namespace Barotrauma.Items.Components
}
}
[InGameEditable, Serialize("", true, description: "The value to compare the received signals against.", alwaysUseInstanceValues: true)]
[InGameEditable, Serialize("", IsPropertySaveable.Yes, description: "The value to compare the received signals against.", alwaysUseInstanceValues: true)]
public string TargetSignal { get; set; }
public SignalCheckComponent(Item item, XElement element)
public SignalCheckComponent(Item item, ContentXElement element)
: base(item, element)
{
}
@@ -11,7 +11,7 @@ namespace Barotrauma.Items.Components
private bool fireInRange;
private int maxOutputLength;
[Editable, Serialize(200, false, description: "The maximum length of the output strings. Warning: Large values can lead to large memory usage or networking issues.")]
[Editable, Serialize(200, IsPropertySaveable.No, description: "The maximum length of the output strings. Warning: Large values can lead to large memory usage or networking issues.")]
public int MaxOutputLength
{
get { return maxOutputLength; }
@@ -22,7 +22,7 @@ namespace Barotrauma.Items.Components
}
private string output;
[InGameEditable, Serialize("1", true, description: "The signal the item outputs when it has detected a fire.", alwaysUseInstanceValues: true)]
[InGameEditable, Serialize("1", IsPropertySaveable.Yes, description: "The signal the item outputs when it has detected a fire.", alwaysUseInstanceValues: true)]
public string Output
{
get { return output; }
@@ -38,7 +38,7 @@ namespace Barotrauma.Items.Components
}
private string falseOutput;
[InGameEditable, Serialize("0", true, description: "The signal the item outputs when it has not detected a fire.", alwaysUseInstanceValues: true)]
[InGameEditable, Serialize("0", IsPropertySaveable.Yes, description: "The signal the item outputs when it has not detected a fire.", alwaysUseInstanceValues: true)]
public string FalseOutput
{
get { return falseOutput; }
@@ -53,7 +53,7 @@ namespace Barotrauma.Items.Components
}
}
public SmokeDetector(Item item, XElement element)
public SmokeDetector(Item item, ContentXElement element)
: base(item, element)
{
IsActive = true;
@@ -68,7 +68,7 @@ namespace Barotrauma.Items.Components
{
foreach (FireSource fireSource in hull.FireSources)
{
if (fireSource.IsInDamageRange(item.WorldPosition, fireSource.DamageRange * 2.0f)) { return true; }
if (fireSource.IsInDamageRange(item.WorldPosition, Math.Max(fireSource.DamageRange * 2.0f, 500.0f))) { return true; }
}
}
@@ -1,7 +1,4 @@
using Microsoft.Xna.Framework;
using System;
using System.Globalization;
using System.Xml.Linq;
using System;
namespace Barotrauma.Items.Components
{
@@ -17,7 +14,7 @@ namespace Barotrauma.Items.Components
[InGameEditable(DecimalCount = 2),
Serialize(0.0f, true, description: "The item must have received signals to both inputs within this timeframe to output the result." +
Serialize(0.0f, IsPropertySaveable.Yes, description: "The item must have received signals to both inputs within this timeframe to output the result." +
" If set to 0, the inputs must be received at the same time.", alwaysUseInstanceValues: true)]
public float TimeFrame
{
@@ -32,7 +29,7 @@ namespace Barotrauma.Items.Components
}
}
public StringComponent(Item item, XElement element)
public StringComponent(Item item, ContentXElement element)
: base(item, element)
{
timeSinceReceived = new float[] { Math.Max(timeFrame * 2.0f, 0.1f), Math.Max(timeFrame * 2.0f, 0.1f) };
@@ -4,7 +4,7 @@ namespace Barotrauma.Items.Components
{
class SubtractComponent : ArithmeticComponent
{
public SubtractComponent(Item item, XElement element)
public SubtractComponent(Item item, ContentXElement element)
: base(item, element)
{
}
@@ -32,14 +32,14 @@ namespace Barotrauma.Items.Components
private List<TerminalMessage> messageHistory = new List<TerminalMessage>(MaxMessages);
public string DisplayedWelcomeMessage
public LocalizedString DisplayedWelcomeMessage
{
get;
private set;
}
private string welcomeMessage;
[InGameEditable, Serialize("", true, "Message to be displayed on the terminal display when it is first opened.", translationTextTag = "terminalwelcomemsg.", AlwaysUseInstanceValues = true)]
[InGameEditable, Serialize("", IsPropertySaveable.Yes, "Message to be displayed on the terminal display when it is first opened.", translationTextTag: "terminalwelcomemsg.", alwaysUseInstanceValues: true)]
public string WelcomeMessage
{
get { return welcomeMessage; }
@@ -47,7 +47,7 @@ namespace Barotrauma.Items.Components
{
if (welcomeMessage == value) { return; }
welcomeMessage = value;
DisplayedWelcomeMessage = TextManager.Get(welcomeMessage, returnNull: true) ?? welcomeMessage.Replace("\\n", "\n");
DisplayedWelcomeMessage = TextManager.Get(welcomeMessage).Fallback(welcomeMessage.Replace("\\n", "\n"));
}
}
@@ -64,12 +64,12 @@ namespace Barotrauma.Items.Components
}
}
[Editable, Serialize(false, true, description: "The terminal will use a monospace font if this box is ticked.", alwaysUseInstanceValues: true)]
[Editable, Serialize(false, IsPropertySaveable.Yes, description: "The terminal will use a monospace font if this box is ticked.", alwaysUseInstanceValues: true)]
public bool UseMonospaceFont { get; set; }
private Color textColor = Color.LimeGreen;
[Editable, Serialize("50,205,50,255", true, description: "Color of the terminal text.", alwaysUseInstanceValues: true)]
[Editable, Serialize("50,205,50,255", IsPropertySaveable.Yes, description: "Color of the terminal text.", alwaysUseInstanceValues: true)]
public Color TextColor
{
get => textColor;
@@ -89,7 +89,7 @@ namespace Barotrauma.Items.Components
private string prevColorSignal;
public Terminal(Item item, XElement element)
public Terminal(Item item, ContentXElement element)
: base(item, element)
{
IsActive = true;
@@ -143,9 +143,9 @@ namespace Barotrauma.Items.Components
#endif
base.OnItemLoaded();
if (!string.IsNullOrEmpty(DisplayedWelcomeMessage))
if (!DisplayedWelcomeMessage.IsNullOrEmpty())
{
ShowOnDisplay(DisplayedWelcomeMessage, addToHistory: !isSubEditor, TextColor);
ShowOnDisplay(DisplayedWelcomeMessage.Value, addToHistory: !isSubEditor, TextColor);
DisplayedWelcomeMessage = "";
//remove welcome message if a game session is running so it doesn't reappear on successive rounds
if (GameMain.GameSession != null && !isSubEditor)
@@ -166,7 +166,7 @@ namespace Barotrauma.Items.Components
return componentElement;
}
public override void Load(XElement componentElement, bool usePrefabValues, IdRemap idRemap)
public override void Load(ContentXElement componentElement, bool usePrefabValues, IdRemap idRemap)
{
base.Load(componentElement, usePrefabValues, idRemap);
for (int i = 0; i < MaxMessages; i++)
@@ -20,21 +20,23 @@ namespace Barotrauma.Items.Components
private readonly float[] receivedSignal = new float[2];
private readonly float[] timeSinceReceived = new float[2];
[Serialize(FunctionType.Sin, false, description: "Which kind of function to run the input through.", alwaysUseInstanceValues: true)]
protected Character signalSender;
[Serialize(FunctionType.Sin, IsPropertySaveable.No, description: "Which kind of function to run the input through.", alwaysUseInstanceValues: true)]
public FunctionType Function
{
get; set;
}
[InGameEditable, Serialize(false, true, description: "If set to true, the trigonometric function uses radians instead of degrees.", alwaysUseInstanceValues: true)]
[InGameEditable, Serialize(false, IsPropertySaveable.Yes, description: "If set to true, the trigonometric function uses radians instead of degrees.", alwaysUseInstanceValues: true)]
public bool UseRadians
{
get; set;
}
public TrigonometricFunctionComponent(Item item, XElement element)
public TrigonometricFunctionComponent(Item item, ContentXElement element)
: base(item, element)
{
IsActive = true;
@@ -56,7 +58,7 @@ namespace Barotrauma.Items.Components
{
float angle = (float)Math.Atan2(receivedSignal[1], receivedSignal[0]);
if (!UseRadians) { angle = MathHelper.ToDegrees(angle); }
item.SendSignal(angle.ToString("G", CultureInfo.InvariantCulture), "signal_out");
item.SendSignal(new Signal(angle.ToString("G", CultureInfo.InvariantCulture), sender: signalSender), "signal_out");
}
}
}
@@ -65,6 +67,7 @@ namespace Barotrauma.Items.Components
{
float.TryParse(signal.value, NumberStyles.Float, CultureInfo.InvariantCulture, out float value);
bool sendOutputImmediately = true;
signalSender = signal.sender;
switch (Function)
{
case FunctionType.Sin:
@@ -16,7 +16,7 @@ namespace Barotrauma.Items.Components
private float stateSwitchDelay;
private int maxOutputLength;
[Editable, Serialize(200, false, description: "The maximum length of the output strings. Warning: Large values can lead to large memory usage or networking issues.")]
[Editable, Serialize(200, IsPropertySaveable.No, description: "The maximum length of the output strings. Warning: Large values can lead to large memory usage or networking issues.")]
public int MaxOutputLength
{
get { return maxOutputLength; }
@@ -27,7 +27,7 @@ namespace Barotrauma.Items.Components
}
private string output;
[InGameEditable, Serialize("1", true, description: "The signal the item sends out when it's underwater.", alwaysUseInstanceValues: true)]
[InGameEditable, Serialize("1", IsPropertySaveable.Yes, description: "The signal the item sends out when it's underwater.", alwaysUseInstanceValues: true)]
public string Output
{
get { return output; }
@@ -43,7 +43,7 @@ namespace Barotrauma.Items.Components
}
private string falseOutput;
[InGameEditable, Serialize("0", true, description: "The signal the item sends out when it's not underwater.", alwaysUseInstanceValues: true)]
[InGameEditable, Serialize("0", IsPropertySaveable.Yes, description: "The signal the item sends out when it's not underwater.", alwaysUseInstanceValues: true)]
public string FalseOutput
{
get { return falseOutput; }
@@ -58,7 +58,7 @@ namespace Barotrauma.Items.Components
}
}
public WaterDetector(Item item, XElement element)
public WaterDetector(Item item, ContentXElement element)
: base(item, element)
{
IsActive = true;
@@ -30,10 +30,10 @@ namespace Barotrauma.Items.Components
private Connection signalInConnection;
private Connection signalOutConnection;
[Serialize(CharacterTeamType.None, true, description: "WiFi components can only communicate with components that have the same Team ID.", alwaysUseInstanceValues: true)]
[Serialize(CharacterTeamType.None, IsPropertySaveable.Yes, 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)]
[Editable, Serialize(20000.0f, IsPropertySaveable.No, description: "How close the recipient has to be to receive a signal from this WiFi component.", alwaysUseInstanceValues: true)]
public float Range
{
get { return range; }
@@ -46,7 +46,7 @@ namespace Barotrauma.Items.Components
}
}
[InGameEditable, Serialize(0, true, description: "WiFi components can only communicate with components that use the same channel.", alwaysUseInstanceValues: true)]
[InGameEditable, Serialize(0, IsPropertySaveable.Yes, description: "WiFi components can only communicate with components that use the same channel.", alwaysUseInstanceValues: true)]
public int Channel
{
get { return channel; }
@@ -57,7 +57,7 @@ namespace Barotrauma.Items.Components
}
[Editable, Serialize(false, true, description: "Can the component communicate with wifi components in another team's submarine (e.g. enemy sub in Combat missions, respawn shuttle). Needs to be enabled on both the component transmitting the signal and the component receiving it.", alwaysUseInstanceValues: true)]
[Editable, Serialize(false, IsPropertySaveable.Yes, description: "Can the component communicate with wifi components in another team's submarine (e.g. enemy sub in Combat missions, respawn shuttle). Needs to be enabled on both the component transmitting the signal and the component receiving it.", alwaysUseInstanceValues: true)]
public bool AllowCrossTeamCommunication
{
get;
@@ -67,7 +67,7 @@ namespace Barotrauma.Items.Components
private bool linkToChat = false;
[ConditionallyEditable(ConditionallyEditable.ConditionType.AllowLinkingWifiToChat)]
[Serialize(false, false, description: "If enabled, any signals received from another chat-linked wifi component are displayed " +
[Serialize(false, IsPropertySaveable.No, description: "If enabled, any signals received from another chat-linked wifi component are displayed " +
"as chat messages in the chatbox of the player holding the item.", alwaysUseInstanceValues: true)]
public bool LinkToChat
{
@@ -88,7 +88,7 @@ namespace Barotrauma.Items.Components
#endif
}
[Editable, Serialize(1.0f, true, description: "How many seconds have to pass between signals for a message to be displayed in the chatbox. " +
[Editable, Serialize(1.0f, IsPropertySaveable.Yes, description: "How many seconds have to pass between signals for a message to be displayed in the chatbox. " +
"Setting this to a very low value is not recommended, because it may cause an excessive amount of chat messages to be created " +
"if there are chat-linked wifi components that transmit a continuous signal.")]
public float MinChatMessageInterval
@@ -97,15 +97,15 @@ namespace Barotrauma.Items.Components
set;
}
[Editable, Serialize(false, true, description: "If set to true, the component will only create chat messages when the received signal changes.")]
[Editable, Serialize(false, IsPropertySaveable.Yes, description: "If set to true, the component will only create chat messages when the received signal changes.")]
public bool DiscardDuplicateChatMessages
{
get;
set;
}
public WifiComponent(Item item, XElement element)
: base(item, element)
public WifiComponent(Item item, ContentXElement element)
: base (item, element)
{
list.Add(this);
IsActive = true;
@@ -214,8 +214,6 @@ namespace Barotrauma.Items.Components
{
item.LastSentSignalRecipients.Clear();
}
var senderComponent = signal.source?.GetComponent<WifiComponent>();
if (senderComponent != null && !CanReceive(senderComponent)) { return; }
bool chatMsgSent = false;
@@ -267,7 +265,7 @@ namespace Barotrauma.Items.Components
wifiComp.item.ParentInventory.Owner != null)
{
string chatMsg = signal.value;
if (senderComponent != null)
if (sentSignalStrength <= 1.0f)
{
chatMsg = ChatMessage.ApplyDistanceEffect(chatMsg, 1.0f - sentSignalStrength);
}
@@ -81,35 +81,35 @@ namespace Barotrauma.Items.Components
get { return connections; }
}
[Serialize(5000.0f, false, description: "The maximum distance the wire can extend (in pixels).")]
[Serialize(5000.0f, IsPropertySaveable.No, description: "The maximum distance the wire can extend (in pixels).")]
public float MaxLength
{
get;
set;
}
[Serialize(false, false, description: "If enabled, the wire will not be visible in connection panels outside the submarine editor.")]
[Serialize(false, IsPropertySaveable.No, description: "If enabled, the wire will not be visible in connection panels outside the submarine editor.")]
public bool HiddenInGame
{
get;
set;
}
[Editable, Serialize(false, true, "If enabled, this wire will be ignored by the \"Lock all default wires\" setting.", alwaysUseInstanceValues: true)]
[Editable, Serialize(false, IsPropertySaveable.Yes, "If enabled, this wire will be ignored by the \"Lock all default wires\" setting.", alwaysUseInstanceValues: true)]
public bool NoAutoLock
{
get;
set;
}
[Editable, Serialize(false, true, "If enabled, this wire will use the sprite depth instead of a constant depth.")]
[Editable, Serialize(false, IsPropertySaveable.Yes, "If enabled, this wire will use the sprite depth instead of a constant depth.")]
public bool UseSpriteDepth
{
get;
set;
}
public Wire(Item item, XElement element)
public Wire(Item item, ContentXElement element)
: base(item, element)
{
nodes = new List<Vector2>();
@@ -121,7 +121,7 @@ namespace Barotrauma.Items.Components
InitProjSpecific(element);
}
partial void InitProjSpecific(XElement element);
partial void InitProjSpecific(ContentXElement element);
public Connection OtherConnection(Connection connection)
{
@@ -455,12 +455,7 @@ namespace Barotrauma.Items.Components
#if CLIENT
if (GameMain.NetworkMember != null)
{
GameMain.Client.CreateEntityEvent(item, new object[]
{
NetEntityEvent.Type.ComponentState,
item.GetComponentIndex(this),
nodes.Count
});
item.CreateClientEvent(this, new ClientEventData(nodes.Count));
}
#endif
}
@@ -482,12 +477,7 @@ namespace Barotrauma.Items.Components
#if CLIENT
if (GameMain.NetworkMember != null)
{
GameMain.Client.CreateEntityEvent(item, new object[]
{
NetEntityEvent.Type.ComponentState,
item.GetComponentIndex(this),
nodes.Count
});
item.CreateClientEvent(this, new ClientEventData(nodes.Count));
}
#endif
}
@@ -785,7 +775,7 @@ namespace Barotrauma.Items.Components
UpdateSections();
}
public override void Load(XElement componentElement, bool usePrefabValues, IdRemap idRemap)
public override void Load(ContentXElement componentElement, bool usePrefabValues, IdRemap idRemap)
{
base.Load(componentElement, usePrefabValues, idRemap);
@@ -4,7 +4,7 @@ namespace Barotrauma.Items.Components
{
class XorComponent : AndComponent
{
public XorComponent(Item item, XElement element)
public XorComponent(Item item, ContentXElement element)
: base(item, element)
{
IsActive = true;