(61d00a474) v0.9.7.1

This commit is contained in:
Regalis
2020-03-04 13:04:10 +01:00
parent 3c50efa5c9
commit 3c09ebe02f
5086 changed files with 786063 additions and 295871 deletions
@@ -0,0 +1,281 @@
using Barotrauma.Networking;
using Microsoft.Xna.Framework;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Xml.Linq;
namespace Barotrauma.Items.Components
{
partial class PowerContainer : Powered, IDrawableComponent, IServerSerializable, IClientSerializable
{
//[power/min]
private float capacity;
private float charge;
//private float rechargeVoltage;
//how fast the battery can be recharged
private float maxRechargeSpeed;
//how fast it's currently being recharged (can be changed, so that
//charging can be slowed down or disabled if there's a shortage of power)
private float rechargeSpeed;
private float lastSentCharge;
//charge indicator description
protected Vector2 indicatorPosition, indicatorSize;
protected bool isHorizontal;
public float CurrPowerOutput
{
get;
private set;
}
[Serialize("0,0", true, description: "The position of the progress bar indicating the charge of the item. In pixels as an offset from the upper left corner of the sprite.")]
public Vector2 IndicatorPosition
{
get { return indicatorPosition; }
set { indicatorPosition = value; }
}
[Serialize("0,0", true, description: "The size of the progress bar indicating the charge of the item (in pixels).")]
public Vector2 IndicatorSize
{
get { return indicatorSize; }
set { indicatorSize = value; }
}
[Serialize(false, true, description: "Should the progress bar indicating the charge of the item fill up horizontally or vertically.")]
public bool IsHorizontal
{
get { return isHorizontal; }
set { isHorizontal = value; }
}
[Editable, Serialize(10.0f, true, description: "Maximum output of the device when fully charged (kW).")]
public float MaxOutPut { set; get; }
[Editable, Serialize(10.0f, true, description: "The maximum capacity of the device (kW * min). For example, a value of 1000 means the device can output 100 kilowatts of power for 10 minutes, or 1000 kilowatts for 1 minute.")]
public float Capacity
{
get { return capacity; }
set { capacity = Math.Max(value, 1.0f); }
}
[Editable, Serialize(0.0f, true, description: "The current charge of the device.")]
public float Charge
{
get { return charge; }
set
{
if (!MathUtils.IsValid(value)) return;
charge = MathHelper.Clamp(value, 0.0f, capacity);
//send a network event if the charge has changed by more than 5%
if (Math.Abs(charge - lastSentCharge) / capacity > 0.05f)
{
#if SERVER
if (GameMain.Server != null) item.CreateServerEvent(this);
#endif
lastSentCharge = charge;
}
}
}
public float ChargePercentage => MathUtils.Percentage(Charge, Capacity);
[Editable, Serialize(10.0f, true, description: "How fast the device can be recharged. For example, a recharge speed of 100 kW and a capacity of 1000 kW*min would mean it takes 10 minutes to fully charge the device.")]
public float MaxRechargeSpeed
{
get { return maxRechargeSpeed; }
set { maxRechargeSpeed = Math.Max(value, 1.0f); }
}
[Editable, Serialize(10.0f, true, description: "The current recharge speed of the device.")]
public float RechargeSpeed
{
get { return rechargeSpeed; }
set
{
if (!MathUtils.IsValid(value)) return;
rechargeSpeed = MathHelper.Clamp(value, 0.0f, maxRechargeSpeed);
rechargeSpeed = MathUtils.RoundTowardsClosest(rechargeSpeed, Math.Max(maxRechargeSpeed * 0.1f, 1.0f));
if (isRunning)
{
HasBeenTuned = true;
}
}
}
public float RechargeRatio => RechargeSpeed / MaxRechargeSpeed;
public const float aiRechargeTargetRatio = 0.5f;
private bool isRunning;
public bool HasBeenTuned { get; private set; }
public PowerContainer(Item item, XElement element)
: base(item, element)
{
IsActive = true;
InitProjSpecific();
}
partial void InitProjSpecific();
public override bool Pick(Character picker)
{
return picker != null;
}
public override void Update(float deltaTime, Camera cam)
{
isRunning = true;
float chargeRatio = charge / capacity;
float gridPower = 0.0f;
float gridLoad = 0.0f;
foreach (Connection c in item.Connections)
{
if (!c.IsPower || !c.IsOutput) { continue; }
foreach (Connection c2 in c.Recipients)
{
if (c2.Item.Condition <= 0.0f) { continue; }
PowerTransfer pt = c2.Item.GetComponent<PowerTransfer>();
if (pt == null)
{
foreach (Powered powered in c2.Item.GetComponents<Powered>())
{
if (!powered.IsActive) continue;
gridLoad += powered.CurrPowerConsumption;
}
continue;
}
if (!pt.IsActive || !pt.CanTransfer) { continue; }
gridPower -= pt.CurrPowerConsumption;
gridLoad += pt.PowerLoad;
}
}
if (chargeRatio > 0.0f)
{
ApplyStatusEffects(ActionType.OnActive, deltaTime, null);
}
if (charge >= capacity)
{
//rechargeVoltage = 0.0f;
charge = capacity;
CurrPowerConsumption = 0.0f;
}
else
{
currPowerConsumption = MathHelper.Lerp(currPowerConsumption, rechargeSpeed, 0.05f);
Charge += currPowerConsumption * Math.Min(Voltage, 1.0f) / 3600.0f;
}
if (charge <= 0.0f)
{
CurrPowerOutput = 0.0f;
charge = 0.0f;
return;
}
//output starts dropping when the charge is less than 10%
float maxOutputRatio = 1.0f;
if (chargeRatio < 0.1f)
{
maxOutputRatio = Math.Max(chargeRatio * 10.0f, 0.0f);
}
CurrPowerOutput += (gridLoad - gridPower) * deltaTime;
float maxOutput = Math.Min(MaxOutPut * maxOutputRatio, gridLoad);
CurrPowerOutput = MathHelper.Clamp(CurrPowerOutput, 0.0f, maxOutput);
Charge -= CurrPowerOutput / 3600.0f;
item.SendSignal(0, ((int)Math.Round(Charge)).ToString(), "charge", null);
item.SendSignal(0, ((int)Math.Round((Charge / capacity) * 100)).ToString(), "charge_%", null);
item.SendSignal(0, ((int)Math.Round((RechargeSpeed / maxRechargeSpeed) * 100)).ToString(), "charge_rate", null);
}
public override bool AIOperate(float deltaTime, Character character, AIObjectiveOperateItem objective)
{
if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsClient) { return false; }
if (objective.Override)
{
HasBeenTuned = false;
}
if (HasBeenTuned) { return true; }
if (string.IsNullOrEmpty(objective.Option) || objective.Option.Equals("charge", StringComparison.OrdinalIgnoreCase))
{
if (Math.Abs(rechargeSpeed - maxRechargeSpeed * aiRechargeTargetRatio) > 0.05f)
{
#if SERVER
item.CreateServerEvent(this);
#endif
RechargeSpeed = maxRechargeSpeed * aiRechargeTargetRatio;
#if CLIENT
if (rechargeSpeedSlider != null)
{
rechargeSpeedSlider.BarScroll = RechargeSpeed / Math.Max(maxRechargeSpeed, 1.0f);
}
#endif
character.Speak(TextManager.GetWithVariables("DialogChargeBatteries", new string[2] { "[itemname]", "[rate]" },
new string[2] { item.Name, ((int)(rechargeSpeed / maxRechargeSpeed * 100.0f)).ToString() },
new bool[2] { true, false }), null, 1.0f, "chargebattery", 10.0f);
}
}
else
{
if (rechargeSpeed > 0.0f)
{
#if SERVER
item.CreateServerEvent(this);
#endif
RechargeSpeed = 0.0f;
#if CLIENT
if (rechargeSpeedSlider != null)
{
rechargeSpeedSlider.BarScroll = RechargeSpeed / Math.Max(maxRechargeSpeed, 1.0f);
}
#endif
character.Speak(TextManager.GetWithVariables("DialogStopChargingBatteries", new string[2] { "[itemname]", "[rate]" },
new string[2] { item.Name, ((int)(rechargeSpeed / maxRechargeSpeed * 100.0f)).ToString() },
new bool[2] { true, false }), null, 1.0f, "chargebattery", 10.0f);
}
}
return true;
}
public override void ReceiveSignal(int stepsTaken, string signal, Connection connection, Item source, Character sender, float power, float signalStrength = 1.0f)
{
if (connection.IsPower) { return; }
if (connection.Name == "set_rate")
{
if (float.TryParse(signal, NumberStyles.Any, CultureInfo.InvariantCulture, out float tempSpeed))
{
if (!MathUtils.IsValid(tempSpeed)) { return; }
float rechargeRate = MathHelper.Clamp(tempSpeed / 100.0f, 0.0f, 1.0f);
RechargeSpeed = rechargeRate * MaxRechargeSpeed;
#if CLIENT
if (rechargeSpeedSlider != null)
{
rechargeSpeedSlider.BarScroll = rechargeRate;
}
#endif
}
}
}
}
}
@@ -0,0 +1,335 @@
using Microsoft.Xna.Framework;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
namespace Barotrauma.Items.Components
{
partial class PowerTransfer : Powered
{
public List<Connection> PowerConnections { get; private set; }
private readonly Dictionary<Connection, bool> connectionDirty = new Dictionary<Connection, bool>();
//a list of connections a given connection is connected to, either directly or via other power transfer components
private readonly Dictionary<Connection, HashSet<Connection>> connectedRecipients = new Dictionary<Connection, HashSet<Connection>>();
protected float powerLoad;
protected bool isBroken;
public float PowerLoad
{
get { return powerLoad; }
set { powerLoad = value; }
}
[Editable, Serialize(true, true, description: "Can the item be damaged if too much power is supplied to the power grid.")]
public bool CanBeOverloaded
{
get;
set;
}
[Editable(MinValueFloat = 1.0f), Serialize(2.0f, true, description:
"How much power has to be supplied to the grid relative to the load before item starts taking damage. "
+ "E.g. a value of 2 means that the grid has to be receiving twice as much power as the devices in the grid are consuming.")]
public float OverloadVoltage
{
get;
set;
}
[Serialize(0.15f, true, description: "The probability for a fire to start when the item breaks."), Editable(MinValueFloat = 0.0f, MaxValueFloat = 1.0f)]
public float FireProbability
{
get;
set;
}
[Serialize(false, false, description: "Is the item currently overloaded. Intended to be used by StatusEffect conditionals (setting the value from XML is not recommended).")]
public bool Overload
{
get;
set;
}
//can the component transfer power
private bool canTransfer;
public bool CanTransfer
{
get { return canTransfer; }
set
{
if (canTransfer == value) return;
canTransfer = value;
SetAllConnectionsDirty();
}
}
public override bool IsActive
{
get
{
return base.IsActive;
}
set
{
if (base.IsActive == value) return;
base.IsActive = value;
powerLoad = 0.0f;
currPowerConsumption = 0.0f;
SetAllConnectionsDirty();
if (!base.IsActive)
{
//we need to refresh the connections here because Update won't be called on inactive components
RefreshConnections();
}
}
}
public PowerTransfer(Item item, XElement element)
: base(item, element)
{
IsActive = true;
canTransfer = true;
InitProjectSpecific(element);
}
partial void InitProjectSpecific(XElement element);
public override void UpdateBroken(float deltaTime, Camera cam)
{
base.UpdateBroken(deltaTime, cam);
Overload = false;
if (!isBroken)
{
powerLoad = 0.0f;
currPowerConsumption = 0.0f;
SetAllConnectionsDirty();
RefreshConnections();
isBroken = true;
}
}
public override void Update(float deltaTime, Camera cam)
{
RefreshConnections();
if (!CanTransfer) { return; }
if (isBroken)
{
SetAllConnectionsDirty();
isBroken = false;
}
ApplyStatusEffects(ActionType.OnActive, deltaTime, null);
//if the item can't be fixed, don't allow it to break
if (!item.Repairables.Any() || !CanBeOverloaded) { return; }
float maxOverVoltage = Math.Max(OverloadVoltage, 1.0f);
Overload = -currPowerConsumption > Math.Max(powerLoad, 200.0f) * maxOverVoltage;
if (Overload && (GameMain.NetworkMember == null || GameMain.NetworkMember.IsServer))
{
//damage the item if voltage is too high (except if running as a client)
float prevCondition = item.Condition;
item.Condition -= deltaTime * 10.0f;
if (item.Condition <= 0.0f && prevCondition > 0.0f)
{
#if CLIENT
SoundPlayer.PlaySound("zap", item.WorldPosition, hullGuess: item.CurrentHull);
Vector2 baseVel = Rand.Vector(300.0f);
for (int i = 0; i < 10; i++)
{
var particle = GameMain.ParticleManager.CreateParticle("spark", item.WorldPosition,
baseVel + Rand.Vector(100.0f), 0.0f, item.CurrentHull);
if (particle != null) particle.Size *= Rand.Range(0.5f, 1.0f);
}
#endif
float currentIntensity = GameMain.GameSession?.EventManager != null ?
GameMain.GameSession.EventManager.CurrentIntensity : 0.5f;
//higher probability for fires if the current intensity is low
if (FireProbability > 0.0f &&
Rand.Range(0.0f, 1.0f) < MathHelper.Lerp(FireProbability, FireProbability * 0.1f, currentIntensity))
{
new FireSource(item.WorldPosition);
}
}
}
}
public override bool Pick(Character picker)
{
return picker != null;
}
protected void RefreshConnections()
{
var connections = item.Connections;
foreach (Connection c in connections)
{
if (!connectionDirty.ContainsKey(c))
{
connectionDirty[c] = true;
}
else if (!connectionDirty[c])
{
continue;
}
HashSet<Connection> connected = new HashSet<Connection>();
if (!connectedRecipients.ContainsKey(c))
{
connectedRecipients.Add(c, connected);
}
else
{
//mark all previous recipients as dirty
foreach (Connection recipient in connectedRecipients[c])
{
var pt = recipient.Item.GetComponent<PowerTransfer>();
if (pt != null) pt.connectionDirty[recipient] = true;
}
}
//find all connections that are connected to this one (directly or via another PowerTransfer)
connected.Add(c);
GetConnected(c, connected);
connectedRecipients[c] = connected;
//go through all the PowerTransfers and we're connected to and set their connections to match the ones we just calculated
//(no need to go through the recursive GetConnected method again)
foreach (Connection recipient in connected)
{
var recipientPowerTransfer = recipient.Item.GetComponent<PowerTransfer>();
if (recipientPowerTransfer == null) continue;
if (!connectedRecipients.ContainsKey(recipient))
{
connectedRecipients.Add(recipient, connected);
}
recipientPowerTransfer.connectedRecipients[recipient] = connected;
recipientPowerTransfer.connectionDirty[recipient] = false;
}
}
}
//Finds all the connections that can receive a signal sent into the given connection and stores them in the hashset.
private void GetConnected(Connection c, HashSet<Connection> connected)
{
var recipients = c.Recipients;
foreach (Connection recipient in recipients)
{
if (recipient == null || connected.Contains(recipient)) continue;
Item it = recipient.Item;
if (it == null || it.Condition <= 0.0f) continue;
connected.Add(recipient);
var powerTransfer = it.GetComponent<PowerTransfer>();
if (powerTransfer != null && powerTransfer.CanTransfer && powerTransfer.IsActive)
{
GetConnected(recipient, connected);
}
}
}
public void SetAllConnectionsDirty()
{
if (item.Connections == null) return;
foreach (Connection c in item.Connections)
{
connectionDirty[c] = true;
}
}
public void SetConnectionDirty(Connection connection)
{
var connections = item.Connections;
if (connections == null || !connections.Contains(connection)) return;
connectionDirty[connection] = true;
}
public override void OnItemLoaded()
{
base.OnItemLoaded();
var connections = Item.Connections;
PowerConnections = connections == null ? new List<Connection>() : connections.FindAll(c => c.IsPower);
if (connections == null)
{
IsActive = false;
return;
}
if (!(this is RelayComponent))
{
if (PowerConnections.Any(p => !p.IsOutput) && PowerConnections.Any(p => p.IsOutput))
{
DebugConsole.ThrowError("Error in item \"" + Name + "\" - PowerTransfer components should not have separate power inputs and outputs, but transfer power between wires connected to the same power connection. " +
"If you want power to pass from input to output, change the component to a RelayComponent.");
}
}
SetAllConnectionsDirty();
}
public override void ReceivePowerProbeSignal(Connection connection, Item source, float power)
{
//we've already received this signal
if (lastPowerProbeRecipients.Contains(this)) { return; }
if (item.Condition <= 0.0f) { return; }
lastPowerProbeRecipients.Add(this);
if (power < 0.0f)
{
powerLoad -= power;
}
else
{
currPowerConsumption -= power;
}
powerOut?.SendPowerProbeSignal(source, power);
}
public override void ReceiveSignal(int stepsTaken, string signal, Connection connection, Item source, Character sender, float power, float signalStrength = 1.0f)
{
if (item.Condition <= 0.0f || connection.IsPower) { return; }
if (!connectedRecipients.ContainsKey(connection)) { return; }
if (connection.Name.Length > 5 && connection.Name.Substring(0, 6) == "signal")
{
foreach (Connection recipient in connectedRecipients[connection])
{
if (recipient.Item == item || recipient.Item == source) { continue; }
foreach (ItemComponent ic in recipient.Item.Components)
{
//other junction boxes don't need to receive the signal in the pass-through signal connections
//because we relay it straight to the connected items without going through the whole chain of junction boxes
if (ic is PowerTransfer && !(ic is RelayComponent) && connection.Name.Contains("signal")) { continue; }
ic.ReceiveSignal(stepsTaken, signal, recipient, source, sender, 0.0f, signalStrength);
}
foreach (StatusEffect effect in recipient.Effects)
{
recipient.Item.ApplyStatusEffect(effect, ActionType.OnUse, 1.0f);
}
}
}
}
}
}
@@ -0,0 +1,311 @@
using System;
using System.Xml.Linq;
using Microsoft.Xna.Framework;
using System.Collections.Generic;
#if CLIENT
using Barotrauma.Sounds;
#endif
namespace Barotrauma.Items.Components
{
partial class Powered : ItemComponent
{
private static float updateTimer;
protected static float UpdateInterval = 0.2f;
/// <summary>
/// List of all powered ItemComponents
/// </summary>
private static readonly List<Powered> poweredList = new List<Powered>();
/// <summary>
/// Items that have already received the "probe signal" that's used to distribute power and load across the grid
/// </summary>
protected static HashSet<PowerTransfer> lastPowerProbeRecipients = new HashSet<PowerTransfer>();
/// <summary>
/// The amount of power currently consumed by the item. Negative values mean that the item is providing power to connected items
/// </summary>
protected float currPowerConsumption;
/// <summary>
/// Current voltage of the item (load / power)
/// </summary>
private float voltage;
/// <summary>
/// The minimum voltage required for the item to work
/// </summary>
private float minVoltage;
/// <summary>
/// The maximum amount of power the item can draw from connected items
/// </summary>
protected float powerConsumption;
protected Connection powerIn, powerOut;
[Editable, Serialize(0.5f, true, description: "The minimum voltage required for the device to function. " +
"The voltage is calculated as power / powerconsumption, meaning that a device " +
"with a power consumption of 1000 kW would need at least 500 kW of power to work if the minimum voltage is set to 0.5.")]
public float MinVoltage
{
get { return powerConsumption <= 0.0f ? 0.0f : minVoltage; }
set { minVoltage = value; }
}
[Editable, Serialize(0.0f, true, description: "How much power the device draws (or attempts to draw) from the electrical grid when active.")]
public float PowerConsumption
{
get { return powerConsumption; }
set { powerConsumption = value; }
}
[Serialize(false, true, description: "Is the device currently active. Inactive devices don't consume power.")]
public override bool IsActive
{
get { return base.IsActive; }
set
{
base.IsActive = value;
if (!value)
{
currPowerConsumption = 0.0f;
}
}
}
[Serialize(0.0f, true, description: "The current power consumption of the device. Intended to be used by StatusEffect conditionals (setting the value from XML is not recommended).")]
public float CurrPowerConsumption
{
get {return currPowerConsumption; }
set { currPowerConsumption = value; }
}
[Serialize(0.0f, true, description: "The current voltage of the item (calculated as power consumption / available power). Intended to be used by StatusEffect conditionals (setting the value from XML is not recommended).")]
public float Voltage
{
get { return voltage; }
set { voltage = Math.Max(0.0f, value); }
}
[Editable, Serialize(true, true, description: "Can the item be damaged by electomagnetic pulses.")]
public bool VulnerableToEMP
{
get;
set;
}
public Powered(Item item, XElement element)
: base(item, element)
{
poweredList.Add(this);
InitProjectSpecific(element);
}
partial void InitProjectSpecific(XElement element);
protected void UpdateOnActiveEffects(float deltaTime)
{
if (currPowerConsumption <= 0.0f)
{
//if the item consumes no power, ignore the voltage requirement and
//apply OnActive statuseffects as long as this component is active
if (powerConsumption <= 0.0f)
{
ApplyStatusEffects(ActionType.OnActive, deltaTime, null);
}
return;
}
if (voltage > minVoltage)
{
ApplyStatusEffects(ActionType.OnActive, deltaTime, null);
}
#if CLIENT
if (voltage > minVoltage)
{
if (!powerOnSoundPlayed && powerOnSound != null)
{
SoundPlayer.PlaySound(powerOnSound.Sound, item.WorldPosition, powerOnSound.Volume, powerOnSound.Range, item.CurrentHull);
powerOnSoundPlayed = true;
}
}
else if (voltage < 0.1f)
{
powerOnSoundPlayed = false;
}
#endif
}
public override void Update(float deltaTime, Camera cam)
{
UpdateOnActiveEffects(deltaTime);
}
public override void OnItemLoaded()
{
if (item.Connections == null) { return; }
foreach (Connection c in item.Connections)
{
if (!c.IsPower) { continue; }
if (this is PowerTransfer pt)
{
if (c.Name == "power_in")
{
powerIn = c;
}
else if (c.Name == "power_out")
{
powerOut = c;
}
else if (c.Name == "power")
{
powerIn = powerOut = c;
}
}
else
{
if (c.IsOutput)
{
if (c.Name == "power_in")
{
#if DEBUG
DebugConsole.ThrowError($"Item \"{item.Name}\" has a power output connection called power_in. If the item is supposed to receive power through the connection, change it to an input connection.");
#else
DebugConsole.NewMessage($"Item \"{item.Name}\" has a power output connection called power_in. If the item is supposed to receive power through the connection, change it to an input connection.", Color.Orange);
#endif
}
powerOut = c;
}
else
{
if (c.Name == "power_out")
{
#if DEBUG
DebugConsole.ThrowError($"Item \"{item.Name}\" has a power input connection called power_out. If the item is supposed to output power through the connection, change it to an output connection.");
#else
DebugConsole.NewMessage($"Item \"{item.Name}\" has a power input connection called power_out. If the item is supposed to output power through the connection, change it to an output connection.", Color.Orange);
#endif
}
powerIn = c;
}
}
}
}
public virtual void ReceivePowerProbeSignal(Connection connection, Item source, float power) { }
public static void UpdatePower(float deltaTime)
{
if (updateTimer > 0.0f)
{
updateTimer -= deltaTime;
return;
}
updateTimer = UpdateInterval;
//reset power first
foreach (Powered powered in poweredList)
{
if (powered is PowerTransfer pt)
{
powered.CurrPowerConsumption = 0.0f;
pt.PowerLoad = 0.0f;
if (pt is RelayComponent relay)
{
relay.DisplayLoad = 0.0f;
}
}
//only reset voltage if the item has a power connector
//(other items, such as handheld devices, get power through other means and shouldn't be updated here)
if (powered.powerIn != null || powered.powerOut != null) { powered.voltage = 0.0f; }
}
//go through all the devices that are consuming/providing power
//and send out a "probe signal" which the PowerTransfer components use to add up the grid power/load
foreach (Powered powered in poweredList)
{
if (powered is PowerTransfer) { continue; }
if (powered.currPowerConsumption > 0.0f)
{
//consuming power
lastPowerProbeRecipients.Clear();
powered.powerIn?.SendPowerProbeSignal(powered.item, -powered.currPowerConsumption);
}
}
foreach (Powered powered in poweredList)
{
if (powered is PowerTransfer) { continue; }
else if (powered.currPowerConsumption < 0.0f)
{
//providing power
lastPowerProbeRecipients.Clear();
powered.powerOut?.SendPowerProbeSignal(powered.item, -powered.currPowerConsumption);
}
if (powered is PowerContainer pc)
{
if (pc.CurrPowerOutput <= 0.0f) { continue; }
//providing power
lastPowerProbeRecipients.Clear();
powered.powerOut?.SendPowerProbeSignal(powered.item, pc.CurrPowerOutput);
}
}
//go through powered items and calculate their current voltage
foreach (Powered powered in poweredList)
{
if (powered is PowerTransfer pt1 || (pt1 = powered.Item.GetComponent<PowerTransfer>()) != null)
{
powered.voltage = -pt1.CurrPowerConsumption / Math.Max(pt1.PowerLoad, 1.0f);
continue;
}
if (powered.powerConsumption <= 0.0f && !(powered is PowerContainer))
{
powered.voltage = 1.0f;
continue;
}
if (powered.powerIn == null) { continue; }
foreach (Connection powerSource in powered.powerIn.Recipients)
{
if (!powerSource.IsPower || !powerSource.IsOutput) { continue; }
var pt = powerSource.Item.GetComponent<PowerTransfer>();
if (pt != null)
{
float voltage = -pt.CurrPowerConsumption / Math.Max(pt.PowerLoad, 1.0f);
powered.voltage = Math.Max(powered.voltage, voltage);
continue;
}
var pc = powerSource.Item.GetComponent<PowerContainer>();
if (pc != null)
{
float voltage = pc.CurrPowerOutput / Math.Max(powered.CurrPowerConsumption, 1.0f);
powered.voltage += voltage;
}
}
}
}
/// <summary>
/// Returns the amount of power that can be supplied by batteries directly connected to the item
/// </summary>
protected float GetAvailableBatteryPower()
{
var batteries = item.GetConnectedComponents<PowerContainer>();
float availablePower = 0.0f;
foreach (PowerContainer battery in batteries)
{
float batteryPower = Math.Min(battery.Charge * 3600.0f, battery.MaxOutPut);
availablePower += batteryPower;
}
return availablePower;
}
protected override void RemoveComponentSpecific()
{
poweredList.Remove(this);
}
}
}