using Microsoft.Xna.Framework; using System; using System.Globalization; using System.Xml.Linq; namespace Barotrauma.Items.Components { abstract class ArithmeticComponent : ItemComponent { //an array to keep track of how long ago a signal was received on both inputs protected float[] timeSinceReceived; protected float[] receivedSignal; //the output is sent if both inputs have received a signal within the timeframe protected float timeFrame; 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 { get; set; } [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 { get; set; } [InGameEditable(DecimalCount = 2), 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; } set { if (value > timeFrame) { timeSinceReceived[0] = timeSinceReceived[1] = Math.Max(value * 2.0f, 0.1f); } timeFrame = Math.Max(0.0f, value); } } 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) }; receivedSignal = new float[2]; } sealed public override void Update(float deltaTime, Camera cam) { bool deactivate = true; bool earlyReturn = false; for (int i = 0; i < timeSinceReceived.Length; i++) { 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)) { item.SendSignal(new Signal(MathHelper.Clamp(output, ClampMin, ClampMax).ToString("G", CultureInfo.InvariantCulture), sender: signalSender[0] ?? signalSender[1]), "signal_out"); } } protected abstract float Calculate(float signal1, float signal2); public override void ReceiveSignal(Signal signal, Connection connection) { switch (connection.Name) { 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; } } } }