v0.13.0.11
This commit is contained in:
@@ -38,13 +38,15 @@ namespace Barotrauma.Items.Components
|
||||
private Fixture outsideBlocker;
|
||||
private Body doorBody;
|
||||
|
||||
private float dockingCooldown;
|
||||
|
||||
private bool docked;
|
||||
private bool obstructedWayPointsDisabled;
|
||||
|
||||
private float forceLockTimer;
|
||||
//if the submarine isn't in the correct position to lock within this time after docking has been activated,
|
||||
//force the sub to the correct position
|
||||
const float ForceLockDelay = 1.0f;
|
||||
const float ForceLockDelay = 1.0f;
|
||||
|
||||
public int DockingDir { get; set; }
|
||||
|
||||
@@ -147,20 +149,12 @@ namespace Barotrauma.Items.Components
|
||||
DockingDir = GetDir(DockingTarget);
|
||||
DockingTarget.DockingDir = -DockingDir;
|
||||
}
|
||||
if (joint != null)
|
||||
{
|
||||
CreateJoint(joint is WeldJoint);
|
||||
LinkHullsToGaps();
|
||||
}
|
||||
else if (DockingTarget.joint != null)
|
||||
{
|
||||
if (!GameMain.World.BodyList.Contains(DockingTarget.joint.BodyA) ||
|
||||
!GameMain.World.BodyList.Contains(DockingTarget.joint.BodyB))
|
||||
{
|
||||
DockingTarget.CreateJoint(DockingTarget.joint is WeldJoint);
|
||||
}
|
||||
DockingTarget.LinkHullsToGaps();
|
||||
}
|
||||
|
||||
//undock and redock to recreate the hulls, gaps and physics bodies
|
||||
var prevDockingTarget = DockingTarget;
|
||||
Undock(applyEffects: false);
|
||||
Dock(prevDockingTarget);
|
||||
Lock(isNetworkMessage: true, applyEffects: false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -187,15 +181,15 @@ namespace Barotrauma.Items.Components
|
||||
private void AttemptDock()
|
||||
{
|
||||
var adjacentPort = FindAdjacentPort();
|
||||
|
||||
if (adjacentPort != null) Dock(adjacentPort);
|
||||
if (adjacentPort != null) { Dock(adjacentPort); }
|
||||
}
|
||||
|
||||
public void Dock(DockingPort target)
|
||||
{
|
||||
if (item.Submarine.DockedTo.Contains(target.item.Submarine)) return;
|
||||
if (item.Submarine.DockedTo.Contains(target.item.Submarine)) { return; }
|
||||
|
||||
forceLockTimer = 0.0f;
|
||||
dockingCooldown = 0.1f;
|
||||
|
||||
if (DockingTarget != null)
|
||||
{
|
||||
@@ -237,7 +231,6 @@ namespace Barotrauma.Items.Components
|
||||
#if SERVER
|
||||
if (GameMain.Server != null && (!item.Submarine?.Loading ?? true))
|
||||
{
|
||||
originalDockingTargetID = DockingTarget.item.ID;
|
||||
item.CreateServerEvent(this);
|
||||
}
|
||||
#endif
|
||||
@@ -246,8 +239,7 @@ namespace Barotrauma.Items.Components
|
||||
OnDocked = null;
|
||||
}
|
||||
|
||||
|
||||
public void Lock(bool isNetworkMessage, bool forcePosition = false)
|
||||
public void Lock(bool isNetworkMessage, bool applyEffects = true)
|
||||
{
|
||||
#if CLIENT
|
||||
if (GameMain.Client != null && !isNetworkMessage) { return; }
|
||||
@@ -264,7 +256,10 @@ namespace Barotrauma.Items.Components
|
||||
DockingDir = GetDir(DockingTarget);
|
||||
DockingTarget.DockingDir = -DockingDir;
|
||||
|
||||
ApplyStatusEffects(ActionType.OnUse, 1.0f);
|
||||
if (applyEffects)
|
||||
{
|
||||
ApplyStatusEffects(ActionType.OnUse, 1.0f);
|
||||
}
|
||||
|
||||
Vector2 jointDiff = joint.WorldAnchorB - joint.WorldAnchorA;
|
||||
if (item.Submarine.PhysicsBody.Mass < DockingTarget.item.Submarine.PhysicsBody.Mass ||
|
||||
@@ -284,7 +279,6 @@ namespace Barotrauma.Items.Components
|
||||
#if SERVER
|
||||
if (GameMain.Server != null && (!item.Submarine?.Loading ?? true))
|
||||
{
|
||||
originalDockingTargetID = DockingTarget.item.ID;
|
||||
item.CreateServerEvent(this);
|
||||
}
|
||||
#else
|
||||
@@ -846,13 +840,17 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
public void Undock()
|
||||
public void Undock(bool applyEffects = true)
|
||||
{
|
||||
if (DockingTarget == null || !docked) return;
|
||||
if (DockingTarget == null || !docked) { return; }
|
||||
|
||||
forceLockTimer = 0.0f;
|
||||
dockingCooldown = 0.1f;
|
||||
|
||||
ApplyStatusEffects(ActionType.OnSecondaryUse, 1.0f);
|
||||
if (applyEffects)
|
||||
{
|
||||
ApplyStatusEffects(ActionType.OnSecondaryUse, 1.0f);
|
||||
}
|
||||
|
||||
DockingTarget.item.Submarine.ConnectedDockingPorts.Remove(item.Submarine);
|
||||
item.Submarine.ConnectedDockingPorts.Remove(DockingTarget.item.Submarine);
|
||||
@@ -877,6 +875,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
Item.Submarine.EnableObstructedWaypoints(DockingTarget.Item.Submarine);
|
||||
obstructedWayPointsDisabled = false;
|
||||
Item.Submarine.RefreshOutdoorNodes();
|
||||
|
||||
DockingTarget.Undock();
|
||||
DockingTarget = null;
|
||||
@@ -924,7 +923,6 @@ namespace Barotrauma.Items.Components
|
||||
#if SERVER
|
||||
if (GameMain.Server != null && (!item.Submarine?.Loading ?? true))
|
||||
{
|
||||
originalDockingTargetID = Entity.NullEntityID;
|
||||
item.CreateServerEvent(this);
|
||||
}
|
||||
#endif
|
||||
@@ -934,14 +932,13 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
public override void Update(float deltaTime, Camera cam)
|
||||
{
|
||||
dockingCooldown -= deltaTime;
|
||||
if (DockingTarget == null)
|
||||
{
|
||||
dockingState = MathHelper.Lerp(dockingState, 0.0f, deltaTime * 10.0f);
|
||||
if (dockingState < 0.01f) docked = false;
|
||||
|
||||
item.SendSignal(0, "0", "state_out", null);
|
||||
item.SendSignal(0, (FindAdjacentPort() != null) ? "1" : "0", "proximity_sensor", null);
|
||||
|
||||
if (dockingState < 0.01f) { docked = false; }
|
||||
item.SendSignal("0", "state_out");
|
||||
item.SendSignal((FindAdjacentPort() != null) ? "1" : "0", "proximity_sensor");
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -987,7 +984,7 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
else
|
||||
{
|
||||
Lock(isNetworkMessage: false, forcePosition: true);
|
||||
Lock(isNetworkMessage: false);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -999,11 +996,12 @@ namespace Barotrauma.Items.Components
|
||||
dockingState = MathHelper.Lerp(dockingState, 1.0f, deltaTime * 10.0f);
|
||||
}
|
||||
|
||||
item.SendSignal(0, IsLocked ? "1" : "0", "state_out", null);
|
||||
item.SendSignal(IsLocked ? "1" : "0", "state_out");
|
||||
}
|
||||
if (!obstructedWayPointsDisabled && dockingState >= 0.99f)
|
||||
{
|
||||
Item.Submarine.DisableObstructedWayPoints(DockingTarget?.Item.Submarine);
|
||||
Item.Submarine.RefreshOutdoorNodes();
|
||||
obstructedWayPointsDisabled = true;
|
||||
}
|
||||
}
|
||||
@@ -1104,39 +1102,41 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
public override void ReceiveSignal(int stepsTaken, string signal, Connection connection, Item source, Character sender, float power = 0.0f, float signalStrength = 1.0f)
|
||||
public override void ReceiveSignal(Signal signal, Connection connection)
|
||||
{
|
||||
if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsClient) { return; }
|
||||
|
||||
if (dockingCooldown > 0.0f) { return; }
|
||||
|
||||
bool wasDocked = docked;
|
||||
DockingPort prevDockingTarget = DockingTarget;
|
||||
|
||||
switch (connection.Name)
|
||||
{
|
||||
case "toggle":
|
||||
if (signal != "0")
|
||||
if (signal.value != "0")
|
||||
{
|
||||
Docked = !docked;
|
||||
}
|
||||
break;
|
||||
case "set_active":
|
||||
case "set_state":
|
||||
Docked = signal != "0";
|
||||
Docked = signal.value != "0";
|
||||
break;
|
||||
}
|
||||
|
||||
#if SERVER
|
||||
if (sender != null && docked != wasDocked)
|
||||
if (signal.sender != null && docked != wasDocked)
|
||||
{
|
||||
if (docked)
|
||||
{
|
||||
if (item.Submarine != null && DockingTarget?.item?.Submarine != null)
|
||||
GameServer.Log(GameServer.CharacterLogName(sender) + " docked " + item.Submarine.Info.Name + " to " + DockingTarget.item.Submarine.Info.Name, ServerLog.MessageType.ItemInteraction);
|
||||
GameServer.Log(GameServer.CharacterLogName(signal.sender) + " docked " + item.Submarine.Info.Name + " to " + DockingTarget.item.Submarine.Info.Name, ServerLog.MessageType.ItemInteraction);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (item.Submarine != null && prevDockingTarget?.item?.Submarine != null)
|
||||
GameServer.Log(GameServer.CharacterLogName(sender) + " undocked " + item.Submarine.Info.Name + " from " + prevDockingTarget.item.Submarine.Info.Name, ServerLog.MessageType.ItemInteraction);
|
||||
GameServer.Log(GameServer.CharacterLogName(signal.sender) + " undocked " + item.Submarine.Info.Name + " from " + prevDockingTarget.item.Submarine.Info.Name, ServerLog.MessageType.ItemInteraction);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -305,9 +305,21 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
private void ToggleState(ActionType actionType, Character user)
|
||||
{
|
||||
if (toggleCooldownTimer > 0.0f && user != lastUser) { OnFailedToOpen(); return; }
|
||||
if (toggleCooldownTimer > 0.0f && user != lastUser)
|
||||
{
|
||||
OnFailedToOpen();
|
||||
return;
|
||||
}
|
||||
toggleCooldownTimer = ToggleCoolDown;
|
||||
if (IsStuck || IsJammed) { toggleCooldownTimer = 1.0f; OnFailedToOpen(); return; }
|
||||
if (IsStuck || IsJammed)
|
||||
{
|
||||
#if CLIENT
|
||||
if (IsStuck) { HintManager.OnTryOpenStuckDoor(user); }
|
||||
#endif
|
||||
toggleCooldownTimer = 1.0f;
|
||||
OnFailedToOpen();
|
||||
return;
|
||||
}
|
||||
lastUser = user;
|
||||
SetState(PredictedState == null ? !isOpen : !PredictedState.Value, false, true, forcedOpen: actionType == ActionType.OnPicked);
|
||||
}
|
||||
@@ -395,7 +407,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
//don't use the predicted state here, because it might set
|
||||
//other items to an incorrect state if the prediction is wrong
|
||||
item.SendSignal(0, isOpen ? "1" : "0", "state_out", null);
|
||||
item.SendSignal(isOpen ? "1" : "0", "state_out");
|
||||
}
|
||||
|
||||
partial void UpdateProjSpecific(float deltaTime);
|
||||
@@ -651,7 +663,7 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
public override void ReceiveSignal(int stepsTaken, string signal, Connection connection, Item source, Character sender, float power = 0.0f, float signalStrength = 1.0f)
|
||||
public override void ReceiveSignal(Signal signal, Connection connection)
|
||||
{
|
||||
if (IsStuck || IsJammed) { return; }
|
||||
|
||||
@@ -659,24 +671,24 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
if (connection.Name == "toggle")
|
||||
{
|
||||
if (signal == "0") { return; }
|
||||
if (toggleCooldownTimer > 0.0f && sender != lastUser) { OnFailedToOpen(); return; }
|
||||
if (signal.value == "0") { return; }
|
||||
if (toggleCooldownTimer > 0.0f && signal.sender != lastUser) { OnFailedToOpen(); return; }
|
||||
if (IsStuck) { toggleCooldownTimer = 1.0f; OnFailedToOpen(); return; }
|
||||
toggleCooldownTimer = ToggleCoolDown;
|
||||
lastUser = sender;
|
||||
lastUser = signal.sender;
|
||||
SetState(!wasOpen, false, true, forcedOpen: false);
|
||||
}
|
||||
else if (connection.Name == "set_state")
|
||||
{
|
||||
bool signalOpen = signal != "0";
|
||||
bool signalOpen = signal.value != "0";
|
||||
if (IsStuck && signalOpen != wasOpen) { toggleCooldownTimer = 1.0f; OnFailedToOpen(); return; }
|
||||
SetState(signalOpen, false, true, forcedOpen: false);
|
||||
}
|
||||
|
||||
#if SERVER
|
||||
if (sender != null && wasOpen != isOpen)
|
||||
if (signal.sender != null && wasOpen != isOpen)
|
||||
{
|
||||
GameServer.Log(GameServer.CharacterLogName(sender) + (isOpen ? " opened " : " closed ") + item.Name, ServerLog.MessageType.ItemInteraction);
|
||||
GameServer.Log(GameServer.CharacterLogName(signal.sender) + (isOpen ? " opened " : " closed ") + item.Name, ServerLog.MessageType.ItemInteraction);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -39,6 +39,12 @@ namespace Barotrauma.Items.Components
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
[Serialize(true, true, description: "Is the item currently able to push characters around? True by default. Only valid if blocksplayers is set to true.")]
|
||||
public bool CanPush
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
//the angle in which the Character holds the item
|
||||
protected float holdAngle;
|
||||
@@ -208,6 +214,7 @@ namespace Barotrauma.Items.Components
|
||||
if (other.Body.UserData is Character character)
|
||||
{
|
||||
if (!IsActive) { return false; }
|
||||
if (!CanPush) { return false; }
|
||||
return character != picker;
|
||||
}
|
||||
else
|
||||
@@ -436,6 +443,7 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
//not attached -> pick the item instantly, ignoring picking time
|
||||
return OnPicked(picker);
|
||||
}
|
||||
@@ -443,6 +451,10 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
public override bool OnPicked(Character picker)
|
||||
{
|
||||
if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsClient)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (base.OnPicked(picker))
|
||||
{
|
||||
DeattachFromWall();
|
||||
|
||||
@@ -62,6 +62,7 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
if (!subElement.Name.ToString().Equals("attack", StringComparison.OrdinalIgnoreCase)) { continue; }
|
||||
Attack = new Attack(subElement, item.Name + ", MeleeWeapon");
|
||||
Attack.DamageRange = item.body == null ? 10.0f : ConvertUnits.ToDisplayUnits(item.body.GetMaxExtent());
|
||||
}
|
||||
item.IsShootable = true;
|
||||
// TODO: should define this in xml if we have melee weapons that don't require aim to use
|
||||
|
||||
@@ -41,25 +41,25 @@ namespace Barotrauma.Items.Components
|
||||
public override bool Use(float deltaTime, Character character = null)
|
||||
{
|
||||
if (character == null || character.Removed) return false;
|
||||
if (!character.IsKeyDown(InputType.Aim) || character.Stun > 0.0f) return false;
|
||||
if (!character.IsKeyDown(InputType.Aim) || character.Stun > 0.0f) { return false; }
|
||||
|
||||
IsActive = true;
|
||||
useState = 0.1f;
|
||||
|
||||
if (character.AnimController.InWater)
|
||||
{
|
||||
if (UsableIn == UseEnvironment.Air) return true;
|
||||
if (UsableIn == UseEnvironment.Air) { return true; }
|
||||
}
|
||||
else
|
||||
{
|
||||
if (UsableIn == UseEnvironment.Water) return true;
|
||||
if (UsableIn == UseEnvironment.Water) { return true; }
|
||||
}
|
||||
|
||||
Vector2 dir = Vector2.Normalize(character.CursorPosition - character.Position);
|
||||
//move upwards if the cursor is at the position of the character
|
||||
if (!MathUtils.IsValid(dir)) dir = Vector2.UnitY;
|
||||
|
||||
Vector2 propulsion = dir * Force;
|
||||
Vector2 propulsion = dir * Force * character.PropulsionSpeedMultiplier;
|
||||
|
||||
if (character.AnimController.InWater) character.AnimController.TargetMovement = dir;
|
||||
|
||||
|
||||
@@ -12,7 +12,8 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
partial class RangedWeapon : ItemComponent
|
||||
{
|
||||
private float reload, reloadTimer;
|
||||
private float reload;
|
||||
public float ReloadTimer { get; private set; }
|
||||
|
||||
private Vector2 barrelPos;
|
||||
|
||||
@@ -75,17 +76,17 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
public override void Equip(Character character)
|
||||
{
|
||||
reloadTimer = Math.Min(reload, 1.0f);
|
||||
ReloadTimer = Math.Min(reload, 1.0f);
|
||||
IsActive = true;
|
||||
}
|
||||
|
||||
public override void Update(float deltaTime, Camera cam)
|
||||
{
|
||||
reloadTimer -= deltaTime;
|
||||
ReloadTimer -= deltaTime;
|
||||
|
||||
if (reloadTimer < 0.0f)
|
||||
if (ReloadTimer < 0.0f)
|
||||
{
|
||||
reloadTimer = 0.0f;
|
||||
ReloadTimer = 0.0f;
|
||||
IsActive = false;
|
||||
}
|
||||
}
|
||||
@@ -101,10 +102,10 @@ namespace Barotrauma.Items.Components
|
||||
public override bool Use(float deltaTime, Character character = null)
|
||||
{
|
||||
if (character == null || character.Removed) { return false; }
|
||||
if ((item.RequireAimToUse && !character.IsKeyDown(InputType.Aim)) || reloadTimer > 0.0f) { return false; }
|
||||
if ((item.RequireAimToUse && !character.IsKeyDown(InputType.Aim)) || ReloadTimer > 0.0f) { return false; }
|
||||
|
||||
IsActive = true;
|
||||
reloadTimer = reload;
|
||||
ReloadTimer = reload;
|
||||
|
||||
if (item.AiTarget != null)
|
||||
{
|
||||
|
||||
@@ -796,7 +796,7 @@ namespace Barotrauma.Items.Components
|
||||
bool leakFixed = (leak.Open <= 0.0f || leak.Removed) &&
|
||||
(leak.ConnectedWall == null || leak.ConnectedWall.Sections.Average(s => s.damage) < 1);
|
||||
|
||||
if (leakFixed && leak.FlowTargetHull?.DisplayName != null)
|
||||
if (leakFixed && leak.FlowTargetHull?.DisplayName != null && character.IsOnPlayerTeam)
|
||||
{
|
||||
if (!leak.FlowTargetHull.ConnectedGaps.Any(g => !g.IsRoomToRoom && g.Open > 0.0f))
|
||||
{
|
||||
@@ -854,9 +854,11 @@ namespace Barotrauma.Items.Components
|
||||
object value = property.GetValue(target);
|
||||
if (door.Stuck > 0)
|
||||
{
|
||||
bool isCutting = effect.propertyEffects[i].GetType() == typeof(float) && (float)effect.propertyEffects[i] < 0;
|
||||
var progressBar = user.UpdateHUDProgressBar(door, door.Item.WorldPosition, door.Stuck / 100, Color.DarkGray * 0.5f, Color.White,
|
||||
effect.propertyEffects[i].GetType() == typeof(float) && (float)effect.propertyEffects[i] < 0 ? "progressbar.cutting" : "progressbar.welding");
|
||||
textTag: isCutting ? "progressbar.cutting" : "progressbar.welding");
|
||||
if (progressBar != null) { progressBar.Size = new Vector2(60.0f, 20.0f); }
|
||||
if (!isCutting) { HintManager.OnWeldingDoor(user, door); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -432,27 +432,27 @@ namespace Barotrauma.Items.Components
|
||||
//called then the item is dropped or dragged out of a "limbslot"
|
||||
public virtual void Unequip(Character character) { }
|
||||
|
||||
public virtual void ReceiveSignal(int stepsTaken, string signal, Connection connection, Item source, Character sender, float power = 0.0f, float signalStrength = 1.0f)
|
||||
public virtual void ReceiveSignal(Signal signal, Connection connection)
|
||||
{
|
||||
switch (connection.Name)
|
||||
{
|
||||
case "activate":
|
||||
case "use":
|
||||
case "trigger_in":
|
||||
if (signal != "0")
|
||||
if (signal.value != "0")
|
||||
{
|
||||
item.Use(1.0f, sender);
|
||||
item.Use(1.0f, signal.sender);
|
||||
}
|
||||
break;
|
||||
case "toggle":
|
||||
if (signal != "0")
|
||||
if (signal.value != "0")
|
||||
{
|
||||
IsActive = !isActive;
|
||||
}
|
||||
break;
|
||||
case "set_active":
|
||||
case "set_state":
|
||||
IsActive = signal != "0";
|
||||
IsActive = signal.value != "0";
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -771,6 +771,10 @@ namespace Barotrauma.Items.Components
|
||||
brokenEffects.ForEach(e => e.SetUser(user));
|
||||
}
|
||||
}
|
||||
|
||||
#if CLIENT
|
||||
HintManager.OnStatusEffectApplied(this, type, character);
|
||||
#endif
|
||||
}
|
||||
|
||||
public virtual void Load(XElement componentElement, bool usePrefabValues, IdRemap idRemap)
|
||||
@@ -952,26 +956,6 @@ namespace Barotrauma.Items.Components
|
||||
#region AI related
|
||||
protected const float AIUpdateInterval = 0.2f;
|
||||
protected float aiUpdateTimer;
|
||||
private int itemIndex;
|
||||
private Character previousUser;
|
||||
protected bool FindSuitableContainer(Character character, Func<Item, float> priority, out Item suitableContainer)
|
||||
{
|
||||
suitableContainer = null;
|
||||
if (character.AIController is HumanAIController aiController)
|
||||
{
|
||||
if (previousUser != character)
|
||||
{
|
||||
previousUser = character;
|
||||
itemIndex = 0;
|
||||
}
|
||||
if (character.FindItem(ref itemIndex, out Item targetContainer, ignoredItems: aiController.IgnoredItems, customPriorityFunction: priority, positionalReference: Item))
|
||||
{
|
||||
suitableContainer = targetContainer;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected AIObjectiveContainItem AIContainItems<T>(ItemContainer container, Character character, AIObjective currentObjective, int itemCount, bool equip, bool removeEmpty, bool spawnItemIfNotFound = false, bool dropItemOnDeselected = false) where T : ItemComponent
|
||||
{
|
||||
@@ -1014,83 +998,6 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
return containObjective;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true when done seeking the suitable container.
|
||||
/// </summary>
|
||||
protected bool AIDecontainEmptyItems(Character character, AIObjective objective, bool equip, ItemContainer sourceContainer = null)
|
||||
{
|
||||
if (character.AIController is HumanAIController aiController)
|
||||
{
|
||||
ItemContainer sourceC = sourceContainer ?? (item.OwnInventory?.Owner is Item it ? it.GetComponent<ItemContainer>() : null);
|
||||
var containedItems = sourceContainer != null ? sourceContainer.Inventory.AllItems : item.OwnInventory.AllItems;
|
||||
foreach (Item containedItem in containedItems)
|
||||
{
|
||||
if (containedItem != null && containedItem.Condition <= 0.0f)
|
||||
{
|
||||
if (FindSuitableContainer(character,
|
||||
i =>
|
||||
{
|
||||
if (i.IsThisOrAnyContainerIgnoredByAI()) { return 0; }
|
||||
var container = i.GetComponent<ItemContainer>();
|
||||
if (container == null) { return 0; }
|
||||
if (!container.Inventory.CanBePut(containedItem)) { return 0; }
|
||||
// Ignore containers that are identical to the source container
|
||||
if (sourceC != null && container.Item.Prefab == sourceC.Item.Prefab) { return 0; }
|
||||
if (container.ShouldBeContained(containedItem, out bool isRestrictionsDefined))
|
||||
{
|
||||
if (isRestrictionsDefined)
|
||||
{
|
||||
return 10;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (containedItem.IsContainerPreferred(container, out bool isPreferencesDefined, out bool isSecondary))
|
||||
{
|
||||
return isPreferencesDefined ? isSecondary ? 2 : 5 : 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return isPreferencesDefined ? 0 : 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}, out Item targetContainer))
|
||||
{
|
||||
var decontainObjective = new AIObjectiveDecontainItem(character, containedItem, objective.objectiveManager, sourceC, targetContainer?.GetComponent<ItemContainer>())
|
||||
{
|
||||
Equip = equip
|
||||
};
|
||||
decontainObjective.Abandoned += () =>
|
||||
{
|
||||
itemIndex = 0;
|
||||
if (targetContainer != null)
|
||||
{
|
||||
aiController.IgnoredItems.Add(targetContainer);
|
||||
}
|
||||
};
|
||||
decontainObjective.Completed += () =>
|
||||
{
|
||||
if (targetContainer == null)
|
||||
{
|
||||
itemIndex = 0;
|
||||
}
|
||||
};
|
||||
objective.AddSubObjectiveInQueue(decontainObjective);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,13 +13,13 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
partial void OnStateChanged();
|
||||
|
||||
public override void ReceiveSignal(int stepsTaken, string signal, Connection connection, Item source, Character sender, float power = 0, float signalStrength = 1)
|
||||
public override void ReceiveSignal(Signal signal, Connection connection)
|
||||
{
|
||||
switch (connection.Name)
|
||||
{
|
||||
case "set_text":
|
||||
if (Text == signal) { return; }
|
||||
Text = signal;
|
||||
if (Text == signal.value) { return; }
|
||||
Text = signal.value;
|
||||
OnStateChanged();
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -152,7 +152,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
if (IsToggle)
|
||||
{
|
||||
item.SendSignal(0, State ? "1" : "0", "signal_out", sender: null);
|
||||
item.SendSignal(State ? "1" : "0", "signal_out");
|
||||
}
|
||||
|
||||
if (user == null
|
||||
@@ -277,7 +277,7 @@ namespace Barotrauma.Items.Components
|
||||
return false;
|
||||
}
|
||||
|
||||
item.SendSignal(0, "1", "trigger_out", user);
|
||||
item.SendSignal(new Signal("1", sender: user), "trigger_out");
|
||||
|
||||
ApplyStatusEffects(ActionType.OnUse, 1.0f, activator);
|
||||
|
||||
@@ -343,14 +343,14 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
public Item GetFocusTarget()
|
||||
{
|
||||
item.SendSignal(0, MathHelper.ToDegrees(targetRotation).ToString("G", CultureInfo.InvariantCulture), "position_out", user);
|
||||
item.SendSignal(new Signal(MathHelper.ToDegrees(targetRotation).ToString("G", CultureInfo.InvariantCulture), sender: user), "position_out");
|
||||
|
||||
for (int i = item.LastSentSignalRecipients.Count - 1; i >= 0; i--)
|
||||
{
|
||||
if (item.LastSentSignalRecipients[i].Condition <= 0.0f) continue;
|
||||
if (item.LastSentSignalRecipients[i].Prefab.FocusOnSelected)
|
||||
if (item.LastSentSignalRecipients[i].Item.Condition <= 0.0f) { continue; }
|
||||
if (item.LastSentSignalRecipients[i].Item.Prefab.FocusOnSelected)
|
||||
{
|
||||
return item.LastSentSignalRecipients[i];
|
||||
return item.LastSentSignalRecipients[i].Item;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -374,7 +374,7 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
else
|
||||
{
|
||||
item.SendSignal(0, "1", "signal_out", picker);
|
||||
item.SendSignal(new Signal("1", sender: picker), "signal_out");
|
||||
}
|
||||
#if CLIENT
|
||||
PlaySound(ActionType.OnUse, picker);
|
||||
@@ -442,7 +442,7 @@ namespace Barotrauma.Items.Components
|
||||
#if SERVER
|
||||
item.CreateServerEvent(this);
|
||||
#endif
|
||||
item.SendSignal(0, "1", "signal_out", user);
|
||||
item.SendSignal(new Signal("1", sender: user), "signal_out");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -175,7 +175,7 @@ namespace Barotrauma.Items.Components
|
||||
Vector2 propellerWorldPos = item.WorldPosition + PropellerPos * item.Scale;
|
||||
foreach (Character character in Character.CharacterList)
|
||||
{
|
||||
if (character.Submarine != null || !character.Enabled || character.Removed) { continue; }
|
||||
if (!character.Enabled || character.Removed) { continue; }
|
||||
float distSqr = Vector2.DistanceSquared(character.WorldPosition, propellerWorldPos);
|
||||
if (distSqr > scaledDamageRange * scaledDamageRange) { continue; }
|
||||
character.LastDamageSource = item;
|
||||
@@ -201,17 +201,17 @@ namespace Barotrauma.Items.Components
|
||||
PropellerPos = new Vector2(PropellerPos.X, -PropellerPos.Y);
|
||||
}
|
||||
|
||||
public override void ReceiveSignal(int stepsTaken, string signal, Connection connection, Item source, Character sender, float power = 0.0f, float signalStrength = 1.0f)
|
||||
public override void ReceiveSignal(Signal signal, Connection connection)
|
||||
{
|
||||
base.ReceiveSignal(stepsTaken, signal, connection, source, sender, power, signalStrength);
|
||||
base.ReceiveSignal(signal, connection);
|
||||
|
||||
if (connection.Name == "set_force")
|
||||
{
|
||||
if (float.TryParse(signal, NumberStyles.Float, CultureInfo.InvariantCulture, out float tempForce))
|
||||
if (float.TryParse(signal.value, NumberStyles.Float, CultureInfo.InvariantCulture, out float tempForce))
|
||||
{
|
||||
controlLockTimer = 0.1f;
|
||||
targetForce = MathHelper.Clamp(tempForce, -100.0f, 100.0f);
|
||||
User = sender;
|
||||
User = signal.sender;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma.Items.Components
|
||||
@@ -96,6 +97,12 @@ namespace Barotrauma.Items.Components
|
||||
fabricationRecipes.Add(recipe);
|
||||
}
|
||||
}
|
||||
fabricationRecipes.Sort((r1, r2) =>
|
||||
{
|
||||
int hash1 = (int)r1.TargetItem.UIntIdentifier;
|
||||
int hash2 = (int)r2.TargetItem.UIntIdentifier;
|
||||
return hash1 - hash2;
|
||||
});
|
||||
|
||||
state = FabricatorState.Stopped;
|
||||
|
||||
@@ -114,11 +121,10 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
inputContainer = containers[0];
|
||||
outputContainer = containers[1];
|
||||
|
||||
|
||||
foreach (var recipe in fabricationRecipes)
|
||||
{
|
||||
int ingredientCount = recipe.RequiredItems.Sum(it => it.Amount);
|
||||
if (ingredientCount > inputContainer.Capacity)
|
||||
if (recipe.RequiredItems.Count > inputContainer.Capacity)
|
||||
{
|
||||
DebugConsole.ThrowError("Error in item \"" + item.Name + "\": There's not enough room in the input inventory for the ingredients of \"" + recipe.TargetItem.Name + "\"!");
|
||||
}
|
||||
@@ -205,6 +211,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
progressState = 0.0f;
|
||||
timeUntilReady = 0.0f;
|
||||
UpdateRequiredTimeProjSpecific();
|
||||
inputContainer.Inventory.Locked = false;
|
||||
outputContainer.Inventory.Locked = false;
|
||||
|
||||
@@ -272,6 +279,7 @@ namespace Barotrauma.Items.Components
|
||||
if (powerConsumption <= 0) { Voltage = 1.0f; }
|
||||
|
||||
timeUntilReady -= deltaTime * Math.Min(Voltage, 1.0f);
|
||||
UpdateRequiredTimeProjSpecific();
|
||||
|
||||
if (timeUntilReady > 0.0f) { return; }
|
||||
|
||||
@@ -353,6 +361,8 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
partial void UpdateRequiredTimeProjSpecific();
|
||||
|
||||
private bool CanBeFabricated(FabricationRecipe fabricableItem)
|
||||
{
|
||||
if (fabricableItem == null) { return false; }
|
||||
|
||||
@@ -87,8 +87,9 @@ namespace Barotrauma.Items.Components
|
||||
return picker != null;
|
||||
}
|
||||
|
||||
public override void ReceiveSignal(int stepsTaken, string signal, Connection connection, Item source, Character sender, float power = 0, float signalStrength = 1.0f)
|
||||
public override void ReceiveSignal(Signal signal, Connection connection)
|
||||
{
|
||||
Item source = signal.source;
|
||||
if (source == null || source.CurrentHull == null) { return; }
|
||||
|
||||
Hull sourceHull = source.CurrentHull;
|
||||
@@ -116,7 +117,7 @@ namespace Barotrauma.Items.Components
|
||||
case "oxygen_data_in":
|
||||
float oxy;
|
||||
|
||||
if (!float.TryParse(signal, System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out oxy))
|
||||
if (!float.TryParse(signal.value, System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out oxy))
|
||||
{
|
||||
oxy = Rand.Range(0.0f, 100.0f);
|
||||
}
|
||||
|
||||
@@ -142,7 +142,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
partial void UpdateProjSpecific(float deltaTime);
|
||||
|
||||
public override void ReceiveSignal(int stepsTaken, string signal, Connection connection, Item source, Character sender, float power = 0.0f, float signalStrength = 1.0f)
|
||||
public override void ReceiveSignal(Signal signal, Connection connection)
|
||||
{
|
||||
if (Hijacked) { return; }
|
||||
|
||||
@@ -153,12 +153,12 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
else if (connection.Name == "set_active")
|
||||
{
|
||||
IsActive = signal != "0";
|
||||
IsActive = signal.value != "0";
|
||||
isActiveLockTimer = 0.1f;
|
||||
}
|
||||
else if (connection.Name == "set_speed")
|
||||
{
|
||||
if (float.TryParse(signal, NumberStyles.Any, CultureInfo.InvariantCulture, out float tempSpeed))
|
||||
if (float.TryParse(signal.value, NumberStyles.Any, CultureInfo.InvariantCulture, out float tempSpeed))
|
||||
{
|
||||
flowPercentage = MathHelper.Clamp(tempSpeed, -100.0f, 100.0f);
|
||||
TargetLevel = null;
|
||||
@@ -167,9 +167,9 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
else if (connection.Name == "set_targetlevel")
|
||||
{
|
||||
if (float.TryParse(signal, NumberStyles.Any, CultureInfo.InvariantCulture, out float tempTarget))
|
||||
if (float.TryParse(signal.value, NumberStyles.Any, CultureInfo.InvariantCulture, out float tempTarget))
|
||||
{
|
||||
TargetLevel = MathHelper.Clamp(tempTarget + 50.0f, 0.0f, 100.0f);
|
||||
TargetLevel = MathUtils.InverseLerp(-100.0f, 100.0f, tempTarget) * 100.0f;
|
||||
pumpSpeedLockTimer = 0.1f;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -221,6 +221,13 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
#if CLIENT
|
||||
if(PowerOn && AvailableFuel < 1)
|
||||
{
|
||||
HintManager.OnReactorOutOfFuel(this);
|
||||
}
|
||||
#endif
|
||||
|
||||
prevAvailableFuel = AvailableFuel;
|
||||
ApplyStatusEffects(ActionType.OnActive, deltaTime, null);
|
||||
|
||||
@@ -326,7 +333,7 @@ namespace Barotrauma.Items.Components
|
||||
if (item.CurrentHull != null)
|
||||
{
|
||||
var aiTarget = item.CurrentHull.AiTarget;
|
||||
if (aiTarget != null)
|
||||
if (aiTarget != null && MaxPowerOutput > 0)
|
||||
{
|
||||
float range = Math.Abs(currPowerConsumption) / MaxPowerOutput;
|
||||
float noise = MathHelper.Lerp(aiTarget.MinSoundRange, aiTarget.MaxSoundRange, range);
|
||||
@@ -334,7 +341,7 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
if (item.AiTarget != null)
|
||||
if (item.AiTarget != null && MaxPowerOutput > 0)
|
||||
{
|
||||
var aiTarget = item.AiTarget;
|
||||
float range = Math.Abs(currPowerConsumption) / MaxPowerOutput;
|
||||
@@ -342,10 +349,10 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
item.SendSignal(0, ((int)(temperature * 100.0f)).ToString(), "temperature_out", null);
|
||||
item.SendSignal(0, ((int)-CurrPowerConsumption).ToString(), "power_value_out", null);
|
||||
item.SendSignal(0, ((int)load).ToString(), "load_value_out", null);
|
||||
item.SendSignal(0, ((int)AvailableFuel).ToString(), "fuel_out", null);
|
||||
item.SendSignal(((int)(temperature * 100.0f)).ToString(), "temperature_out");
|
||||
item.SendSignal(((int)-CurrPowerConsumption).ToString(), "power_value_out");
|
||||
item.SendSignal(((int)load).ToString(), "load_value_out");
|
||||
item.SendSignal(((int)AvailableFuel).ToString(), "fuel_out");
|
||||
|
||||
UpdateFailures(deltaTime);
|
||||
#if CLIENT
|
||||
@@ -427,7 +434,7 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
if (temperature > allowedTemperature.Y)
|
||||
{
|
||||
item.SendSignal(0, "1", "meltdown_warning", null);
|
||||
item.SendSignal("1", "meltdown_warning");
|
||||
//faster meltdown if the item is in a bad condition
|
||||
meltDownTimer += MathHelper.Lerp(deltaTime * 2.0f, deltaTime, item.Condition / item.MaxCondition);
|
||||
|
||||
@@ -439,7 +446,7 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
else
|
||||
{
|
||||
item.SendSignal(0, "0", "meltdown_warning", null);
|
||||
item.SendSignal("0", "meltdown_warning");
|
||||
meltDownTimer = Math.Max(0.0f, meltDownTimer - deltaTime);
|
||||
}
|
||||
|
||||
@@ -509,7 +516,7 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
base.UpdateBroken(deltaTime, cam);
|
||||
|
||||
item.SendSignal(0, ((int)(temperature * 100.0f)).ToString(), "temperature_out", null);
|
||||
item.SendSignal(((int)(temperature * 100.0f)).ToString(), "temperature_out");
|
||||
|
||||
currPowerConsumption = 0.0f;
|
||||
Temperature -= deltaTime * 1000.0f;
|
||||
@@ -568,49 +575,53 @@ namespace Barotrauma.Items.Components
|
||||
//characters with insufficient skill levels don't refuel the reactor
|
||||
if (degreeOfSuccess > refuelLimit)
|
||||
{
|
||||
if (objective.SubObjectives.None())
|
||||
{
|
||||
if (!AIDecontainEmptyItems(character, objective, equip: false))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (aiUpdateTimer > 0.0f)
|
||||
{
|
||||
aiUpdateTimer -= deltaTime;
|
||||
return false;
|
||||
}
|
||||
aiUpdateTimer = AIUpdateInterval;
|
||||
|
||||
// load more fuel if the current maximum output is only 50% of the current load
|
||||
// or if the fuel rod is (almost) deplenished
|
||||
float minCondition = fuelConsumptionRate * MathUtils.Pow((degreeOfSuccess - refuelLimit) * 2, 2);
|
||||
float minCondition = fuelConsumptionRate * MathUtils.Pow2((degreeOfSuccess - refuelLimit) * 2);
|
||||
if (NeedMoreFuel(minimumOutputRatio: 0.5f, minCondition: minCondition))
|
||||
{
|
||||
bool outOfFuel = false;
|
||||
var container = item.GetComponent<ItemContainer>();
|
||||
if (objective.SubObjectives.None())
|
||||
{
|
||||
int itemCount = item.ContainedItems.Count(i => i != null && container.ContainableItems.Any(ri => ri.MatchesItem(i))) + 1;
|
||||
AIContainItems<Reactor>(container, character, objective, itemCount, equip: false, removeEmpty: true, spawnItemIfNotFound: character.TeamID == CharacterTeamType.FriendlyNPC, dropItemOnDeselected: true);
|
||||
var containObjective = AIContainItems<Reactor>(container, character, objective, itemCount: 1, equip: true, removeEmpty: true, spawnItemIfNotFound: character.TeamID == CharacterTeamType.FriendlyNPC, dropItemOnDeselected: true);
|
||||
containObjective.Completed += ReportFuelRodCount;
|
||||
containObjective.Abandoned += ReportFuelRodCount;
|
||||
character.Speak(TextManager.Get("DialogReactorFuel"), null, 0.0f, "reactorfuel", 30.0f);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
else if (TooMuchFuel())
|
||||
{
|
||||
if (item.OwnInventory?.AllItems != null)
|
||||
{
|
||||
var container = item.GetComponent<ItemContainer>();
|
||||
foreach (Item item in item.OwnInventory.AllItemsMod)
|
||||
|
||||
void ReportFuelRodCount()
|
||||
{
|
||||
if (container.ContainableItems.Any(ri => ri.MatchesItem(item)))
|
||||
if (!character.IsOnPlayerTeam) { return; }
|
||||
int remainingFuelRods = Submarine.MainSub.GetItems(false).Count(i => i.HasTag("reactorfuel") && i.Condition > 1);
|
||||
if (remainingFuelRods == 0)
|
||||
{
|
||||
item.Drop(character);
|
||||
break;
|
||||
character.Speak(TextManager.Get("DialogOutOfFuelRods"), null, 0.0f, "outoffuelrods", 30.0f);
|
||||
outOfFuel = true;
|
||||
}
|
||||
else if (remainingFuelRods < 3)
|
||||
{
|
||||
character.Speak(TextManager.Get("DialogLowOnFuelRods"), null, 0.0f, "lowonfuelrods", 30.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
return outOfFuel;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (TooMuchFuel())
|
||||
{
|
||||
DropFuel(minCondition: 0.1f, maxCondition: 100);
|
||||
}
|
||||
else
|
||||
{
|
||||
DropFuel(minCondition: 0, maxCondition: 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -619,7 +630,7 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
if (lastUser != null && lastUser != character && lastUser != LastAIUser)
|
||||
{
|
||||
if (lastUser.SelectedConstruction == item)
|
||||
if (lastUser.SelectedConstruction == item && character.IsOnPlayerTeam)
|
||||
{
|
||||
character.Speak(TextManager.Get("DialogReactorTaken"), null, 0.0f, "reactortaken", 10.0f);
|
||||
}
|
||||
@@ -676,6 +687,23 @@ namespace Barotrauma.Items.Components
|
||||
aiUpdateTimer = AIUpdateInterval;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void DropFuel(float minCondition, float maxCondition)
|
||||
{
|
||||
if (item.OwnInventory?.AllItems != null)
|
||||
{
|
||||
var container = item.GetComponent<ItemContainer>();
|
||||
foreach (Item item in item.OwnInventory.AllItemsMod)
|
||||
{
|
||||
if (item.ConditionPercentage <= maxCondition && item.ConditionPercentage >= minCondition)
|
||||
{
|
||||
item.Drop(character);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnMapLoaded()
|
||||
@@ -683,7 +711,7 @@ namespace Barotrauma.Items.Components
|
||||
prevAvailableFuel = AvailableFuel;
|
||||
}
|
||||
|
||||
public override void ReceiveSignal(int stepsTaken, string signal, Connection connection, Item source, Character sender, float power, float signalStrength = 1.0f)
|
||||
public override void ReceiveSignal(Signal signal, Connection connection)
|
||||
{
|
||||
switch (connection.Name)
|
||||
{
|
||||
@@ -698,7 +726,7 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
break;
|
||||
case "set_fissionrate":
|
||||
if (PowerOn && float.TryParse(signal, NumberStyles.Float, CultureInfo.InvariantCulture, out float newFissionRate))
|
||||
if (PowerOn && float.TryParse(signal.value, NumberStyles.Float, CultureInfo.InvariantCulture, out float newFissionRate))
|
||||
{
|
||||
targetFissionRate = newFissionRate;
|
||||
if (GameMain.NetworkMember?.IsServer ?? false) { unsentChanges = true; }
|
||||
@@ -708,7 +736,7 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
break;
|
||||
case "set_turbineoutput":
|
||||
if (PowerOn && float.TryParse(signal, NumberStyles.Float, CultureInfo.InvariantCulture, out float newTurbineOutput))
|
||||
if (PowerOn && float.TryParse(signal.value, NumberStyles.Float, CultureInfo.InvariantCulture, out float newTurbineOutput))
|
||||
{
|
||||
targetTurbineOutput = newTurbineOutput;
|
||||
if (GameMain.NetworkMember?.IsServer ?? false) { unsentChanges = true; }
|
||||
@@ -719,6 +747,5 @@ namespace Barotrauma.Items.Components
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -150,7 +150,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
public override void Update(float deltaTime, Camera cam)
|
||||
{
|
||||
currPowerConsumption = powerConsumption;
|
||||
currPowerConsumption = (currentMode == Mode.Active) ? powerConsumption : powerConsumption * 0.1f;
|
||||
|
||||
UpdateOnActiveEffects(deltaTime);
|
||||
|
||||
@@ -252,9 +252,10 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
foreach (Character c in Character.CharacterList)
|
||||
{
|
||||
if (c.AnimController.CurrentHull != null || !c.Enabled) continue;
|
||||
if (DetectSubmarineWalls && c.AnimController.CurrentHull == null && item.CurrentHull != null) continue;
|
||||
if (Vector2.DistanceSquared(c.WorldPosition, item.WorldPosition) > range * range) continue;
|
||||
if (c.IsDead || c.Removed || !c.Enabled) { continue; }
|
||||
if (c.AnimController.CurrentHull != null || c.Params.HideInSonar) { continue; }
|
||||
if (DetectSubmarineWalls && c.AnimController.CurrentHull == null && item.CurrentHull != null) { continue; }
|
||||
if (Vector2.DistanceSquared(c.WorldPosition, item.WorldPosition) > range * range) { continue; }
|
||||
|
||||
string directionName = GetDirectionName(c.WorldPosition - item.WorldPosition);
|
||||
if (!targetGroups.ContainsKey(directionName))
|
||||
@@ -277,9 +278,12 @@ namespace Barotrauma.Items.Components
|
||||
dialogTag = "DialogSonarTargetLarge";
|
||||
}
|
||||
|
||||
character.Speak(TextManager.GetWithVariables(dialogTag, new string[2] { "[direction]", "[count]" },
|
||||
new string[2] { targetGroup.Key.ToString(), targetGroup.Value.Count.ToString() },
|
||||
new bool[2] { true, false }), null, 0, "sonartarget" + targetGroup.Value[0].ID, 60);
|
||||
if (character.IsOnPlayerTeam)
|
||||
{
|
||||
character.Speak(TextManager.GetWithVariables(dialogTag, new string[2] { "[direction]", "[count]" },
|
||||
new string[2] { targetGroup.Key.ToString(), targetGroup.Value.Count.ToString() },
|
||||
new bool[2] { true, false }), null, 0, "sonartarget" + targetGroup.Value[0].ID, 60);
|
||||
}
|
||||
|
||||
//prevent the character from reporting other targets in the group
|
||||
for (int i = 1; i < targetGroup.Value.Count; i++)
|
||||
@@ -321,23 +325,23 @@ namespace Barotrauma.Items.Components
|
||||
return transducerPosSum / connectedTransducers.Count;
|
||||
}
|
||||
|
||||
public override void ReceiveSignal(int stepsTaken, string signal, Connection connection, Item source, Character sender, float power = 0, float signalStrength = 1.0f)
|
||||
public override void ReceiveSignal(Signal signal, Connection connection)
|
||||
{
|
||||
base.ReceiveSignal(stepsTaken, signal, connection, source, sender, power, signalStrength);
|
||||
base.ReceiveSignal(signal, connection);
|
||||
|
||||
if (connection.Name == "transducer_in")
|
||||
{
|
||||
var transducer = source.GetComponent<SonarTransducer>();
|
||||
var transducer = signal.source.GetComponent<SonarTransducer>();
|
||||
if (transducer == null) return;
|
||||
|
||||
var connectedTransducer = connectedTransducers.Find(t => t.Transducer == transducer);
|
||||
if (connectedTransducer == null)
|
||||
{
|
||||
connectedTransducers.Add(new ConnectedTransducer(transducer, signalStrength, 1.0f));
|
||||
connectedTransducers.Add(new ConnectedTransducer(transducer, signal.strength, 1.0f));
|
||||
}
|
||||
else
|
||||
{
|
||||
connectedTransducer.SignalStrength = signalStrength;
|
||||
connectedTransducer.SignalStrength = signal.strength;
|
||||
connectedTransducer.DisconnectTimer = 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -24,7 +24,7 @@ namespace Barotrauma.Items.Components
|
||||
sendSignalTimer += deltaTime;
|
||||
if (sendSignalTimer > SendSignalInterval)
|
||||
{
|
||||
item.SendSignal(0, "0101101101101011010", "data_out", sender: null);
|
||||
item.SendSignal("0101101101101011010", "data_out");
|
||||
sendSignalTimer = SendSignalInterval;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,16 +12,21 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
partial class Steering : Powered, IServerSerializable, IClientSerializable
|
||||
{
|
||||
public const float AutopilotMinDistToPathNode = 30.0f;
|
||||
|
||||
private const float AutopilotRayCastInterval = 0.5f;
|
||||
private const float RecalculatePathInterval = 5.0f;
|
||||
|
||||
private const float AutopilotMinDistToPathNode = 30.0f;
|
||||
|
||||
private const float AutoPilotSteeringLerp = 0.1f;
|
||||
|
||||
private const float AutoPilotMaxSpeed = 0.5f;
|
||||
private const float AIPilotMaxSpeed = 1.0f;
|
||||
|
||||
/// <summary>
|
||||
/// How fast the steering vector adjusts when the nav terminal is operated by something else than a character (= signals)
|
||||
/// </summary>
|
||||
const float DefaultSteeringAdjustSpeed = 0.2f;
|
||||
|
||||
private Vector2 targetVelocity;
|
||||
|
||||
private Vector2 steeringInput;
|
||||
@@ -333,13 +338,12 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
float targetLevel = targetVelocity.X;
|
||||
if (controlledSub != null && controlledSub.FlippedX) { targetLevel *= -1; }
|
||||
item.SendSignal(0, targetLevel.ToString(CultureInfo.InvariantCulture), "velocity_x_out", user);
|
||||
float velX = targetVelocity.X;
|
||||
if (controlledSub != null && controlledSub.FlippedX) { velX *= -1; }
|
||||
item.SendSignal(new Signal(velX.ToString(CultureInfo.InvariantCulture), sender: user), "velocity_x_out");
|
||||
|
||||
targetLevel = -targetVelocity.Y;
|
||||
targetLevel += (neutralBallastLevel - 0.5f) * 100.0f;
|
||||
item.SendSignal(0, targetLevel.ToString(CultureInfo.InvariantCulture), "velocity_y_out", user);
|
||||
float velY = MathHelper.Lerp((neutralBallastLevel * 100 - 50) * 2, -100 * Math.Sign(targetVelocity.Y), Math.Abs(targetVelocity.Y) / 100.0f);
|
||||
item.SendSignal(new Signal(velY.ToString(CultureInfo.InvariantCulture), sender: user), "velocity_y_out");
|
||||
}
|
||||
|
||||
private void IncreaseSkillLevel(Character user, float deltaTime)
|
||||
@@ -543,6 +547,10 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
TargetVelocity *= 100.0f / velMagnitude;
|
||||
}
|
||||
|
||||
#if CLIENT
|
||||
HintManager.OnAutoPilotPathUpdated(this);
|
||||
#endif
|
||||
}
|
||||
|
||||
private float? GetNodePenalty(PathNode node, PathNode nextNode)
|
||||
@@ -626,7 +634,7 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
if (objective.Override)
|
||||
{
|
||||
if (user != character && user != null && user.SelectedConstruction == item)
|
||||
if (user != character && user != null && user.SelectedConstruction == item && character.IsOnPlayerTeam)
|
||||
{
|
||||
character.Speak(TextManager.Get("DialogSteeringTaken"), null, 0.0f, "steeringtaken", 10.0f);
|
||||
}
|
||||
@@ -661,7 +669,7 @@ namespace Barotrauma.Items.Components
|
||||
if (Level.IsLoadedOutpost) { break; }
|
||||
if (DockingSources.Any(d => d.Docked))
|
||||
{
|
||||
item.SendSignal(0, "1", "toggle_docking", sender: null);
|
||||
item.SendSignal("1", "toggle_docking");
|
||||
}
|
||||
if (objective.Override)
|
||||
{
|
||||
@@ -676,7 +684,7 @@ namespace Barotrauma.Items.Components
|
||||
if (Level.IsLoadedOutpost) { break; }
|
||||
if (DockingSources.Any(d => d.Docked))
|
||||
{
|
||||
item.SendSignal(0, "1", "toggle_docking", sender: null);
|
||||
item.SendSignal("1", "toggle_docking");
|
||||
}
|
||||
if (objective.Override)
|
||||
{
|
||||
@@ -689,22 +697,25 @@ namespace Barotrauma.Items.Components
|
||||
break;
|
||||
}
|
||||
sonar?.AIOperate(deltaTime, character, objective);
|
||||
if (!MaintainPos && showIceSpireWarning)
|
||||
if (!MaintainPos && showIceSpireWarning && character.IsOnPlayerTeam)
|
||||
{
|
||||
character.Speak(TextManager.Get("dialogicespirespottedsonar"), null, 0.0f, "icespirespottedsonar", 60.0f);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public override void ReceiveSignal(int stepsTaken, string signal, Connection connection, Item source, Character sender, float power = 0.0f, float signalStrength = 1.0f)
|
||||
public override void ReceiveSignal(Signal signal, Connection connection)
|
||||
{
|
||||
if (connection.Name == "velocity_in")
|
||||
{
|
||||
TargetVelocity = XMLExtensions.ParseVector2(signal, errorMessages: false);
|
||||
steeringAdjustSpeed = DefaultSteeringAdjustSpeed;
|
||||
steeringInput = XMLExtensions.ParseVector2(signal.value, errorMessages: false);
|
||||
steeringInput.X = MathHelper.Clamp(steeringInput.X, -100.0f, 100.0f);
|
||||
steeringInput.Y = MathHelper.Clamp(-steeringInput.Y, -100.0f, 100.0f);
|
||||
}
|
||||
else
|
||||
{
|
||||
base.ReceiveSignal(stepsTaken, signal, connection, source, sender, power, signalStrength);
|
||||
base.ReceiveSignal(signal, connection);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -199,9 +199,9 @@ namespace Barotrauma.Items.Components
|
||||
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);
|
||||
item.SendSignal(((int)Math.Round(Charge)).ToString(), "charge");
|
||||
item.SendSignal(((int)Math.Round(Charge / capacity * 100)).ToString(), "charge_%");
|
||||
item.SendSignal(((int)Math.Round(RechargeSpeed / maxRechargeSpeed * 100)).ToString(), "charge_rate");
|
||||
}
|
||||
|
||||
public override bool AIOperate(float deltaTime, Character character, AIObjectiveOperateItem objective)
|
||||
@@ -228,11 +228,13 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
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);
|
||||
#endif
|
||||
if (character.IsOnPlayerTeam)
|
||||
{
|
||||
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
|
||||
@@ -249,22 +251,25 @@ namespace Barotrauma.Items.Components
|
||||
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);
|
||||
if (character.IsOnPlayerTeam)
|
||||
{
|
||||
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)
|
||||
public override void ReceiveSignal(Signal signal, Connection connection)
|
||||
{
|
||||
if (connection.IsPower) { return; }
|
||||
|
||||
if (connection.Name == "set_rate")
|
||||
{
|
||||
if (float.TryParse(signal, NumberStyles.Any, CultureInfo.InvariantCulture, out float tempSpeed))
|
||||
if (float.TryParse(signal.value, NumberStyles.Any, CultureInfo.InvariantCulture, out float tempSpeed))
|
||||
{
|
||||
if (!MathUtils.IsValid(tempSpeed)) { return; }
|
||||
|
||||
|
||||
@@ -342,7 +342,7 @@ namespace Barotrauma.Items.Components
|
||||
powerOut?.SendPowerProbeSignal(source, power);
|
||||
}
|
||||
|
||||
public override void ReceiveSignal(int stepsTaken, string signal, Connection connection, Item source, Character sender, float power, float signalStrength = 1.0f)
|
||||
public override void ReceiveSignal(Signal signal, Connection connection)
|
||||
{
|
||||
if (item.Condition <= 0.0f || connection.IsPower) { return; }
|
||||
if (!connectedRecipients.ContainsKey(connection)) { return; }
|
||||
@@ -351,16 +351,16 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
foreach (Connection recipient in connectedRecipients[connection])
|
||||
{
|
||||
if (recipient.Item == item || recipient.Item == source) { continue; }
|
||||
if (recipient.Item == item || recipient.Item == signal.source) { continue; }
|
||||
|
||||
source?.LastSentSignalRecipients.Add(recipient.Item);
|
||||
signal.source?.LastSentSignalRecipients.Add(recipient);
|
||||
|
||||
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);
|
||||
ic.ReceiveSignal(signal, recipient);
|
||||
}
|
||||
|
||||
foreach (StatusEffect effect in recipient.Effects)
|
||||
|
||||
@@ -481,7 +481,7 @@ namespace Barotrauma.Items.Components
|
||||
character.AnimController.UpdateUseItem(false, item.WorldPosition + new Vector2(0.0f, 100.0f) * ((item.Condition / item.MaxCondition) % 0.1f));
|
||||
}
|
||||
|
||||
public override void ReceiveSignal(int stepsTaken, string signal, Connection connection, Item source, Character sender, float power = 0, float signalStrength = 1)
|
||||
public override void ReceiveSignal(Signal signal, Connection connection)
|
||||
{
|
||||
//do nothing
|
||||
//Repairables should always stay active, so we don't want to use the default behavior
|
||||
|
||||
@@ -4,7 +4,7 @@ using System.Xml.Linq;
|
||||
namespace Barotrauma.Items.Components
|
||||
{
|
||||
class AndComponent : ItemComponent
|
||||
{
|
||||
{
|
||||
protected string output, falseOutput;
|
||||
|
||||
//an array to keep track of how long ago a non-zero signal was received on both inputs
|
||||
@@ -27,14 +27,41 @@ namespace Barotrauma.Items.Components
|
||||
public string Output
|
||||
{
|
||||
get { return output; }
|
||||
set { output = value; }
|
||||
set
|
||||
{
|
||||
if (value == null) { return; }
|
||||
output = value;
|
||||
if (output.Length > MaxOutputLength && (item.Submarine == null || !item.Submarine.Loading))
|
||||
{
|
||||
output = output.Substring(0, MaxOutputLength);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[InGameEditable, Serialize("", true, description: "The signal sent when the condition is met (if empty, no signal is sent).", alwaysUseInstanceValues: true)]
|
||||
public string FalseOutput
|
||||
{
|
||||
get { return falseOutput; }
|
||||
set { falseOutput = value; }
|
||||
set
|
||||
{
|
||||
if (value == null) { return; }
|
||||
falseOutput = value;
|
||||
if (falseOutput.Length > MaxOutputLength && (item.Submarine == null || !item.Submarine.Loading))
|
||||
{
|
||||
falseOutput = falseOutput.Substring(0, MaxOutputLength);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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.")]
|
||||
public int MaxOutputLength
|
||||
{
|
||||
get { return maxOutputLength; }
|
||||
set
|
||||
{
|
||||
maxOutputLength = Math.Max(value, 0);
|
||||
}
|
||||
}
|
||||
|
||||
public AndComponent(Item item, XElement element)
|
||||
@@ -56,23 +83,23 @@ namespace Barotrauma.Items.Components
|
||||
string signalOut = sendOutput ? output : falseOutput;
|
||||
if (string.IsNullOrEmpty(signalOut)) return;
|
||||
|
||||
item.SendSignal(0, signalOut, "signal_out", null);
|
||||
item.SendSignal(signalOut, "signal_out");
|
||||
}
|
||||
|
||||
public override void ReceiveSignal(int stepsTaken, string signal, Connection connection, Item source, Character sender, float power = 0.0f, float signalStrength = 1.0f)
|
||||
public override void ReceiveSignal(Signal signal, Connection connection)
|
||||
{
|
||||
switch (connection.Name)
|
||||
{
|
||||
case "signal_in1":
|
||||
if (signal == "0") return;
|
||||
if (signal.value == "0") return;
|
||||
timeSinceReceived[0] = 0.0f;
|
||||
break;
|
||||
case "signal_in2":
|
||||
if (signal == "0") return;
|
||||
if (signal.value == "0") return;
|
||||
timeSinceReceived[1] = 0.0f;
|
||||
break;
|
||||
case "set_output":
|
||||
output = signal;
|
||||
output = signal.value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
+4
-4
@@ -67,23 +67,23 @@ namespace Barotrauma.Items.Components
|
||||
float output = Calculate(receivedSignal[0], receivedSignal[1]);
|
||||
if (MathUtils.IsValid(output))
|
||||
{
|
||||
item.SendSignal(0, MathHelper.Clamp(output, ClampMin, ClampMax).ToString("G", CultureInfo.InvariantCulture), "signal_out", null);
|
||||
item.SendSignal(MathHelper.Clamp(output, ClampMin, ClampMax).ToString("G", CultureInfo.InvariantCulture), "signal_out");
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract float Calculate(float signal1, float signal2);
|
||||
|
||||
public override void ReceiveSignal(int stepsTaken, string signal, Connection connection, Item source, Character sender, float power = 0.0f, float signalStrength = 1.0f)
|
||||
public override void ReceiveSignal(Signal signal, Connection connection)
|
||||
{
|
||||
switch (connection.Name)
|
||||
{
|
||||
case "signal_in1":
|
||||
float.TryParse(signal, NumberStyles.Float, CultureInfo.InvariantCulture, out receivedSignal[0]);
|
||||
float.TryParse(signal.value, NumberStyles.Float, CultureInfo.InvariantCulture, out receivedSignal[0]);
|
||||
timeSinceReceived[0] = 0.0f;
|
||||
IsActive = true;
|
||||
break;
|
||||
case "signal_in2":
|
||||
float.TryParse(signal, NumberStyles.Float, CultureInfo.InvariantCulture, out receivedSignal[1]);
|
||||
float.TryParse(signal.value, NumberStyles.Float, CultureInfo.InvariantCulture, out receivedSignal[1]);
|
||||
timeSinceReceived[1] = 0.0f;
|
||||
IsActive = true;
|
||||
break;
|
||||
|
||||
+27
-10
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Xml.Linq;
|
||||
using Microsoft.Xna.Framework;
|
||||
|
||||
namespace Barotrauma.Items.Components
|
||||
{
|
||||
@@ -10,6 +11,9 @@ 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)]
|
||||
public bool UseHSV { get; set; }
|
||||
|
||||
public ColorComponent(Item item, XElement element)
|
||||
: base(item, element)
|
||||
{
|
||||
@@ -19,35 +23,48 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
public override void Update(float deltaTime, Camera cam)
|
||||
{
|
||||
item.SendSignal(0, output, "signal_out", null);
|
||||
item.SendSignal(output, "signal_out");
|
||||
}
|
||||
|
||||
private void UpdateOutput()
|
||||
{
|
||||
output = receivedSignal[0].ToString("G", CultureInfo.InvariantCulture);
|
||||
output += "," + receivedSignal[1].ToString("G", CultureInfo.InvariantCulture);
|
||||
output += "," + receivedSignal[2].ToString("G", CultureInfo.InvariantCulture);
|
||||
output += "," + receivedSignal[3].ToString("G", CultureInfo.InvariantCulture);
|
||||
float signalR = receivedSignal[0],
|
||||
signalG = receivedSignal[1],
|
||||
signalB = receivedSignal[2],
|
||||
signalA = receivedSignal[3];
|
||||
|
||||
if (UseHSV)
|
||||
{
|
||||
Color hsvColor = ToolBox.HSVToRGB(signalR, signalG, signalB);
|
||||
signalR = hsvColor.R / (float) byte.MaxValue;
|
||||
signalG = hsvColor.G / (float) byte.MaxValue;
|
||||
signalB = hsvColor.B / (float) byte.MaxValue;
|
||||
}
|
||||
|
||||
output = signalR.ToString("G", CultureInfo.InvariantCulture);
|
||||
output += "," + signalG.ToString("G", CultureInfo.InvariantCulture);
|
||||
output += "," + signalB.ToString("G", CultureInfo.InvariantCulture);
|
||||
output += "," + signalA.ToString("G", CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
public override void ReceiveSignal(int stepsTaken, string signal, Connection connection, Item source, Character sender, float power = 0.0f, float signalStrength = 1.0f)
|
||||
public override void ReceiveSignal(Signal signal, Connection connection)
|
||||
{
|
||||
switch (connection.Name)
|
||||
{
|
||||
case "signal_r":
|
||||
float.TryParse(signal, NumberStyles.Float, CultureInfo.InvariantCulture, out receivedSignal[0]);
|
||||
float.TryParse(signal.value, NumberStyles.Float, CultureInfo.InvariantCulture, out receivedSignal[0]);
|
||||
UpdateOutput();
|
||||
break;
|
||||
case "signal_g":
|
||||
float.TryParse(signal, NumberStyles.Float, CultureInfo.InvariantCulture, out receivedSignal[1]);
|
||||
float.TryParse(signal.value, NumberStyles.Float, CultureInfo.InvariantCulture, out receivedSignal[1]);
|
||||
UpdateOutput();
|
||||
break;
|
||||
case "signal_b":
|
||||
float.TryParse(signal, NumberStyles.Float, CultureInfo.InvariantCulture, out receivedSignal[2]);
|
||||
float.TryParse(signal.value, NumberStyles.Float, CultureInfo.InvariantCulture, out receivedSignal[2]);
|
||||
UpdateOutput();
|
||||
break;
|
||||
case "signal_a":
|
||||
float.TryParse(signal, NumberStyles.Float, CultureInfo.InvariantCulture, out receivedSignal[3]);
|
||||
float.TryParse(signal.value, NumberStyles.Float, CultureInfo.InvariantCulture, out receivedSignal[3]);
|
||||
UpdateOutput();
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
@@ -11,7 +10,10 @@ namespace Barotrauma.Items.Components
|
||||
//how many wires can be linked to connectors by default
|
||||
private const int DefaultMaxWires = 5;
|
||||
|
||||
//how many wires can be linked to this connection
|
||||
//how many wires a player can link to this connection
|
||||
public readonly int MaxPlayerConnectableWires = 5;
|
||||
|
||||
//how many wires can be linked to this connection in total
|
||||
public readonly int MaxWires = 5;
|
||||
|
||||
public readonly string Name;
|
||||
@@ -81,6 +83,9 @@ namespace Barotrauma.Items.Components
|
||||
item = connectionPanel.Item;
|
||||
|
||||
MaxWires = element.GetAttributeInt("maxwires", DefaultMaxWires);
|
||||
MaxWires = Math.Max(element.Elements().Count(e => e.Name.ToString().Equals("link", StringComparison.OrdinalIgnoreCase)), MaxWires);
|
||||
|
||||
MaxPlayerConnectableWires = element.GetAttributeInt("maxplayerconnectablewires", MaxWires);
|
||||
wires = new Wire[MaxWires];
|
||||
|
||||
IsOutput = element.Name.ToString() == "output";
|
||||
@@ -149,19 +154,15 @@ namespace Barotrauma.Items.Components
|
||||
int index = -1;
|
||||
for (int i = 0; i < MaxWires; i++)
|
||||
{
|
||||
if (wireId[i] < 1) index = i;
|
||||
if (wireId[i] < 1) { index = i; }
|
||||
}
|
||||
if (index == -1) break;
|
||||
if (index == -1) { break; }
|
||||
|
||||
int id = subElement.GetAttributeInt("w", 0);
|
||||
if (id < 0)
|
||||
{
|
||||
id = 0;
|
||||
}
|
||||
if (id < 0) { id = 0; }
|
||||
wireId[index] = idRemap.GetOffsetId(id);
|
||||
|
||||
break;
|
||||
|
||||
case "statuseffect":
|
||||
Effects.Add(StatusEffect.Load(subElement, item.Name + ", connection " + Name));
|
||||
break;
|
||||
@@ -251,8 +252,8 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void SendSignal(int stepsTaken, string signal, Item source, Character sender, float power, float signalStrength = 1.0f)
|
||||
|
||||
public void SendSignal(Signal signal)
|
||||
{
|
||||
for (int i = 0; i < MaxWires; i++)
|
||||
{
|
||||
@@ -260,22 +261,27 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
Connection recipient = wires[i].OtherConnection(this);
|
||||
if (recipient == null) { continue; }
|
||||
if (recipient.item == this.item || recipient.item == source) { continue; }
|
||||
if (recipient.item == this.item || signal.source?.LastSentSignalRecipients.LastOrDefault() == recipient) { continue; }
|
||||
|
||||
source?.LastSentSignalRecipients.Add(recipient.item);
|
||||
signal.source?.LastSentSignalRecipients.Add(recipient);
|
||||
|
||||
Connection connection = recipient;
|
||||
|
||||
foreach (ItemComponent ic in recipient.item.Components)
|
||||
{
|
||||
ic.ReceiveSignal(stepsTaken, signal, recipient, source, sender, power, signalStrength);
|
||||
ic.ReceiveSignal(signal, connection);
|
||||
}
|
||||
|
||||
foreach (StatusEffect effect in recipient.Effects)
|
||||
if (signal.value != "0")
|
||||
{
|
||||
recipient.Item.ApplyStatusEffect(effect, ActionType.OnUse, (float)Timing.Step);
|
||||
foreach (StatusEffect effect in recipient.Effects)
|
||||
{
|
||||
recipient.Item.ApplyStatusEffect(effect, ActionType.OnUse, (float)Timing.Step);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void SendPowerProbeSignal(Item source, float power)
|
||||
{
|
||||
for (int i = 0; i < MaxWires; i++)
|
||||
|
||||
@@ -65,10 +65,10 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
|
||||
base.IsActive = true;
|
||||
InitProjSpecific(element);
|
||||
InitProjSpecific();
|
||||
}
|
||||
|
||||
partial void InitProjSpecific(XElement element);
|
||||
partial void InitProjSpecific();
|
||||
|
||||
private bool linksInitialized;
|
||||
public override void OnMapLoaded()
|
||||
@@ -352,7 +352,7 @@ namespace Barotrauma.Items.Components
|
||||
#endif
|
||||
}
|
||||
|
||||
public override void ReceiveSignal(int stepsTaken, string signal, Connection connection, Item source, Character sender, float power = 0, float signalStrength = 1)
|
||||
public override void ReceiveSignal(Signal signal, Connection connection)
|
||||
{
|
||||
//do nothing
|
||||
}
|
||||
|
||||
@@ -16,13 +16,18 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
[Serialize("", false, translationTextTag: "Label.", description: "The text displayed on this button/tickbox."), Editable]
|
||||
public string Label { get; set; }
|
||||
|
||||
[Serialize("1", false, description: "The signal sent out when this button is pressed or this tickbox checked."), Editable]
|
||||
public string Signal { get; set; }
|
||||
|
||||
public string PropertyName { get; }
|
||||
public bool TargetOnlyParentProperty { get; }
|
||||
|
||||
public int NumberInputMin { get; }
|
||||
public int NumberInputMax { get; }
|
||||
|
||||
public int MaxTextLength { get; }
|
||||
|
||||
public const int DefaultNumberInputMin = 0, DefaultNumberInputMax = 99;
|
||||
public bool IsIntegerInput { get; }
|
||||
public bool HasPropertyName { get; }
|
||||
@@ -46,7 +51,7 @@ namespace Barotrauma.Items.Components
|
||||
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);
|
||||
IsIntegerInput = HasPropertyName && element.Name.ToString().ToLowerInvariant() == "integerinput";
|
||||
|
||||
@@ -244,7 +249,7 @@ namespace Barotrauma.Items.Components
|
||||
if (btnElement == null) return;
|
||||
if (btnElement.Connection != null)
|
||||
{
|
||||
item.SendSignal(0, btnElement.Signal, btnElement.Connection, sender: null, source: item);
|
||||
item.SendSignal(new Signal(btnElement.Signal, 0, null, item), btnElement.Connection);
|
||||
}
|
||||
foreach (StatusEffect effect in btnElement.StatusEffects)
|
||||
{
|
||||
@@ -303,7 +308,7 @@ namespace Barotrauma.Items.Components
|
||||
//TODO: allow changing output when a tickbox is not selected
|
||||
if (!string.IsNullOrEmpty(ciElement.Signal) && ciElement.Connection != null)
|
||||
{
|
||||
item.SendSignal(0, ciElement.State ? ciElement.Signal : "0", ciElement.Connection, sender: null, source: item);
|
||||
item.SendSignal(new Signal(ciElement.State ? ciElement.Signal : "0", source: item), ciElement.Connection);
|
||||
}
|
||||
|
||||
foreach (StatusEffect effect in ciElement.StatusEffects)
|
||||
|
||||
@@ -7,17 +7,15 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
class DelayedSignal
|
||||
{
|
||||
public readonly string Signal;
|
||||
public readonly float SignalStrength;
|
||||
public readonly Signal Signal;
|
||||
//in number of frames
|
||||
public int SendTimer;
|
||||
//in number of frames
|
||||
public int SendDuration;
|
||||
|
||||
public DelayedSignal(string signal, float signalStrength, int sendTimer)
|
||||
public DelayedSignal(Signal signal, int sendTimer)
|
||||
{
|
||||
Signal = signal;
|
||||
SignalStrength = signalStrength;
|
||||
SendTimer = sendTimer;
|
||||
}
|
||||
}
|
||||
@@ -75,34 +73,34 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
var signalOut = signalQueue.Peek();
|
||||
signalOut.SendDuration -= 1;
|
||||
item.SendSignal(0, signalOut.Signal, "signal_out", null, signalStrength: signalOut.SignalStrength);
|
||||
item.SendSignal(new Signal(signalOut.Signal.value, strength: signalOut.Signal.strength), "signal_out");
|
||||
if (signalOut.SendDuration <= 0) { signalQueue.Dequeue(); } else { break; }
|
||||
}
|
||||
}
|
||||
|
||||
public override void ReceiveSignal(int stepsTaken, string signal, Connection connection, Item source, Character sender, float power = 0.0f, float signalStrength = 1.0f)
|
||||
public override void ReceiveSignal(Signal signal, Connection connection)
|
||||
{
|
||||
switch (connection.Name)
|
||||
{
|
||||
case "signal_in":
|
||||
if (signalQueue.Count >= signalQueueSize) { return; }
|
||||
if (ResetWhenSignalReceived) { prevQueuedSignal = null; signalQueue.Clear(); }
|
||||
if (ResetWhenDifferentSignalReceived && signalQueue.Count > 0 && signalQueue.Peek().Signal != signal)
|
||||
if (ResetWhenDifferentSignalReceived && signalQueue.Count > 0 && signalQueue.Peek().Signal.value != signal.value)
|
||||
{
|
||||
prevQueuedSignal = null;
|
||||
signalQueue.Clear();
|
||||
}
|
||||
|
||||
if (prevQueuedSignal != null &&
|
||||
prevQueuedSignal.Signal == signal &&
|
||||
MathUtils.NearlyEqual(prevQueuedSignal.SignalStrength, signalStrength) &&
|
||||
prevQueuedSignal.Signal.value == signal.value &&
|
||||
MathUtils.NearlyEqual(prevQueuedSignal.Signal.strength, signal.strength) &&
|
||||
((prevQueuedSignal.SendTimer + prevQueuedSignal.SendDuration == delayTicks) || (prevQueuedSignal.SendTimer <= 0 && prevQueuedSignal.SendDuration > 0)))
|
||||
{
|
||||
prevQueuedSignal.SendDuration += 1;
|
||||
return;
|
||||
}
|
||||
|
||||
prevQueuedSignal = new DelayedSignal(signal, signalStrength, delayTicks)
|
||||
prevQueuedSignal = new DelayedSignal(signal, delayTicks)
|
||||
{
|
||||
SendDuration = 1
|
||||
};
|
||||
|
||||
+35
-8
@@ -15,18 +15,45 @@ namespace Barotrauma.Items.Components
|
||||
//the output is sent if both inputs have received a signal within the timeframe
|
||||
protected float timeFrame;
|
||||
|
||||
[InGameEditable, Serialize("1", true, description: "The signal this item outputs when the condition is met.", alwaysUseInstanceValues: true)]
|
||||
[InGameEditable, Serialize("1", true, description: "The signal sent when the condition is met.", alwaysUseInstanceValues: true)]
|
||||
public string Output
|
||||
{
|
||||
get { return output; }
|
||||
set { output = value; }
|
||||
set
|
||||
{
|
||||
if (value == null) { return; }
|
||||
output = value;
|
||||
if (output.Length > MaxOutputLength && (item.Submarine == null || !item.Submarine.Loading))
|
||||
{
|
||||
output = output.Substring(0, MaxOutputLength);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[InGameEditable, Serialize("", true, description: "The signal this item outputs when the condition is not met.", alwaysUseInstanceValues: true)]
|
||||
[InGameEditable, Serialize("", true, description: "The signal sent when the condition is met (if empty, no signal is sent).", alwaysUseInstanceValues: true)]
|
||||
public string FalseOutput
|
||||
{
|
||||
get { return falseOutput; }
|
||||
set { falseOutput = value; }
|
||||
set
|
||||
{
|
||||
if (value == null) { return; }
|
||||
falseOutput = value;
|
||||
if (falseOutput.Length > MaxOutputLength && (item.Submarine == null || !item.Submarine.Loading))
|
||||
{
|
||||
falseOutput = falseOutput.Substring(0, MaxOutputLength);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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.")]
|
||||
public int MaxOutputLength
|
||||
{
|
||||
get { return maxOutputLength; }
|
||||
set
|
||||
{
|
||||
maxOutputLength = Math.Max(value, 0);
|
||||
}
|
||||
}
|
||||
|
||||
[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)]
|
||||
@@ -61,20 +88,20 @@ namespace Barotrauma.Items.Components
|
||||
string signalOut = receivedSignal[0] == receivedSignal[1] ? output : falseOutput;
|
||||
if (string.IsNullOrEmpty(signalOut)) return;
|
||||
|
||||
item.SendSignal(0, signalOut, "signal_out", null);
|
||||
item.SendSignal(signalOut, "signal_out");
|
||||
}
|
||||
}
|
||||
|
||||
public override void ReceiveSignal(int stepsTaken, string signal, Connection connection, Item source, Character sender, float power = 0.0f, float signalStrength = 1.0f)
|
||||
public override void ReceiveSignal(Signal signal, Connection connection)
|
||||
{
|
||||
switch (connection.Name)
|
||||
{
|
||||
case "signal_in1":
|
||||
receivedSignal[0] = signal;
|
||||
receivedSignal[0] = signal.value;
|
||||
timeSinceReceived[0] = 0.0f;
|
||||
break;
|
||||
case "signal_in2":
|
||||
receivedSignal[1] = signal;
|
||||
receivedSignal[1] = signal.value;
|
||||
timeSinceReceived[1] = 0.0f;
|
||||
break;
|
||||
}
|
||||
|
||||
+5
-4
@@ -25,17 +25,18 @@ namespace Barotrauma.Items.Components
|
||||
IsActive = true;
|
||||
}
|
||||
|
||||
public override void ReceiveSignal(int stepsTaken, string signal, Connection connection, Item source, Character sender, float power = 0, float signalStrength = 1)
|
||||
public override void ReceiveSignal(Signal signal, Connection connection)
|
||||
{
|
||||
switch (connection.Name)
|
||||
{
|
||||
case "set_exponent":
|
||||
case "exponent":
|
||||
float.TryParse(signal, NumberStyles.Float, CultureInfo.InvariantCulture, out exponent);
|
||||
float.TryParse(signal.value, NumberStyles.Float, CultureInfo.InvariantCulture, out exponent);
|
||||
break;
|
||||
case "signal_in":
|
||||
float.TryParse(signal, NumberStyles.Float, CultureInfo.InvariantCulture, out float value);
|
||||
item.SendSignal(0, MathUtils.Pow(value, Exponent).ToString("G", CultureInfo.InvariantCulture), "signal_out", null);
|
||||
float.TryParse(signal.value, NumberStyles.Float, CultureInfo.InvariantCulture, out float value);
|
||||
signal.value = MathUtils.Pow(value, Exponent).ToString("G", CultureInfo.InvariantCulture);
|
||||
item.SendSignal(signal, "signal_out");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
+14
-10
@@ -28,20 +28,20 @@ namespace Barotrauma.Items.Components
|
||||
IsActive = true;
|
||||
}
|
||||
|
||||
public override void ReceiveSignal(int stepsTaken, string signal, Connection connection, Item source, Character sender, float power = 0, float signalStrength = 1)
|
||||
public override void ReceiveSignal(Signal signal, Connection connection)
|
||||
{
|
||||
if (connection.Name != "signal_in") return;
|
||||
if (!float.TryParse(signal, NumberStyles.Float, CultureInfo.InvariantCulture, out float value)) return;
|
||||
if (connection.Name != "signal_in") { return; }
|
||||
if (!float.TryParse(signal.value, NumberStyles.Float, CultureInfo.InvariantCulture, out float value)) { return; }
|
||||
switch (Function)
|
||||
{
|
||||
case FunctionType.Round:
|
||||
item.SendSignal(0, Math.Round(value).ToString("G", CultureInfo.InvariantCulture), "signal_out", null);
|
||||
value = MathF.Round(value);
|
||||
break;
|
||||
case FunctionType.Ceil:
|
||||
item.SendSignal(0, Math.Ceiling(value).ToString("G", CultureInfo.InvariantCulture), "signal_out", null);
|
||||
value = MathF.Ceiling(value);
|
||||
break;
|
||||
case FunctionType.Floor:
|
||||
item.SendSignal(0, Math.Floor(value).ToString("G", CultureInfo.InvariantCulture), "signal_out", null);
|
||||
value = MathF.Floor(value);
|
||||
break;
|
||||
case FunctionType.Factorial:
|
||||
int intVal = (int)Math.Min(value, 20);
|
||||
@@ -50,20 +50,24 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
factorial *= (ulong)i;
|
||||
}
|
||||
item.SendSignal(0, factorial.ToString(), "signal_out", null);
|
||||
value = factorial;
|
||||
break;
|
||||
case FunctionType.AbsoluteValue:
|
||||
item.SendSignal(0, Math.Abs(value).ToString("G", CultureInfo.InvariantCulture), "signal_out", null);
|
||||
value = MathF.Abs(value);
|
||||
break;
|
||||
case FunctionType.SquareRoot:
|
||||
if (value > 0)
|
||||
if (value < 0)
|
||||
{
|
||||
item.SendSignal(0, Math.Sqrt(value).ToString("G", CultureInfo.InvariantCulture), "signal_out", null);
|
||||
return;
|
||||
}
|
||||
value = MathF.Sqrt(value);
|
||||
break;
|
||||
default:
|
||||
throw new NotImplementedException($"Function {Function} has not been implemented.");
|
||||
}
|
||||
|
||||
signal.value = value.ToString("G", CultureInfo.InvariantCulture);
|
||||
item.SendSignal(signal, "signal_out");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+3
-3
@@ -27,13 +27,13 @@ namespace Barotrauma.Items.Components
|
||||
string signalOut = val1 > val2 ? output : falseOutput;
|
||||
if (string.IsNullOrEmpty(signalOut)) return;
|
||||
|
||||
item.SendSignal(0, signalOut, "signal_out", null);
|
||||
item.SendSignal(signalOut, "signal_out");
|
||||
}
|
||||
}
|
||||
|
||||
public override void ReceiveSignal(int stepsTaken, string signal, Connection connection, Item source, Character sender, float power = 0.0f, float signalStrength = 1.0f)
|
||||
public override void ReceiveSignal(Signal signal, Connection connection)
|
||||
{
|
||||
base.ReceiveSignal(stepsTaken, signal, connection, source, sender, power, signalStrength);
|
||||
base.ReceiveSignal(signal, connection);
|
||||
float.TryParse(receivedSignal[0], NumberStyles.Float, CultureInfo.InvariantCulture, out val1);
|
||||
float.TryParse(receivedSignal[1], NumberStyles.Float, CultureInfo.InvariantCulture, out val2);
|
||||
}
|
||||
|
||||
@@ -308,12 +308,12 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
partial void OnStateChanged();
|
||||
|
||||
public override void ReceiveSignal(int stepsTaken, string signal, Connection connection, Item source, Character sender, float power = 0.0f, float signalStrength = 1.0f)
|
||||
public override void ReceiveSignal(Signal signal, Connection connection)
|
||||
{
|
||||
switch (connection.Name)
|
||||
{
|
||||
case "toggle":
|
||||
if (signal != "0")
|
||||
if (signal.value != "0")
|
||||
{
|
||||
if (!IgnoreContinuousToggle || lastToggleSignalTime < Timing.TotalTime - 0.1)
|
||||
{
|
||||
@@ -323,10 +323,10 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
break;
|
||||
case "set_state":
|
||||
IsOn = signal != "0";
|
||||
IsOn = signal.value != "0";
|
||||
break;
|
||||
case "set_color":
|
||||
LightColor = XMLExtensions.ParseColor(signal, false);
|
||||
LightColor = XMLExtensions.ParseColor(signal.value, false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
+27
-11
@@ -1,13 +1,11 @@
|
||||
using Barotrauma.Networking;
|
||||
using System;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma.Items.Components
|
||||
{
|
||||
partial class MemoryComponent : ItemComponent, IServerSerializable
|
||||
{
|
||||
const int MaxValueLength = ChatMessage.MaxLength;
|
||||
|
||||
|
||||
private string value;
|
||||
|
||||
[InGameEditable, Serialize("", true, description: "The currently stored signal the item outputs.", alwaysUseInstanceValues: true)]
|
||||
@@ -17,10 +15,25 @@ namespace Barotrauma.Items.Components
|
||||
set
|
||||
{
|
||||
if (value == null) { return; }
|
||||
this.value = value.Length <= MaxValueLength ? value : value.Substring(0, MaxValueLength);
|
||||
this.value = value;
|
||||
if (this.value.Length > MaxValueLength && (item.Submarine == null || !item.Submarine.Loading))
|
||||
{
|
||||
this.value = this.value.Substring(0, MaxValueLength);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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.")]
|
||||
public int MaxValueLength
|
||||
{
|
||||
get { return maxValueLength; }
|
||||
set
|
||||
{
|
||||
maxValueLength = Math.Max(value, 0);
|
||||
}
|
||||
}
|
||||
|
||||
protected bool writeable = true;
|
||||
|
||||
public MemoryComponent(Item item, XElement element)
|
||||
@@ -31,26 +44,29 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
public override void Update(float deltaTime, Camera cam)
|
||||
{
|
||||
item.SendSignal(0, Value, "signal_out", null);
|
||||
item.SendSignal(Value, "signal_out");
|
||||
}
|
||||
|
||||
partial void OnStateChanged();
|
||||
|
||||
public override void ReceiveSignal(int stepsTaken, string signal, Connection connection, Item source, Character sender, float power = 0.0f, float signalStrength = 1.0f)
|
||||
public override void ReceiveSignal(Signal signal, Connection connection)
|
||||
{
|
||||
switch (connection.Name)
|
||||
{
|
||||
case "signal_in":
|
||||
if (writeable)
|
||||
{
|
||||
if (Value == signal) { return; }
|
||||
Value = signal;
|
||||
OnStateChanged();
|
||||
string prevValue = Value;
|
||||
Value = signal.value;
|
||||
if (Value != prevValue)
|
||||
{
|
||||
OnStateChanged();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "signal_store":
|
||||
case "lock_state":
|
||||
writeable = signal == "1";
|
||||
writeable = signal.value == "1";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,18 +21,19 @@ namespace Barotrauma.Items.Components
|
||||
IsActive = true;
|
||||
}
|
||||
|
||||
public override void ReceiveSignal(int stepsTaken, string signal, Connection connection, Item source, Character sender, float power = 0, float signalStrength = 1)
|
||||
public override void ReceiveSignal(Signal signal, Connection connection)
|
||||
{
|
||||
switch (connection.Name)
|
||||
{
|
||||
case "set_modulus":
|
||||
case "modulus":
|
||||
float.TryParse(signal, NumberStyles.Float, CultureInfo.InvariantCulture, out float newModulus);
|
||||
float.TryParse(signal.value, NumberStyles.Float, CultureInfo.InvariantCulture, out float newModulus);
|
||||
Modulus = newModulus;
|
||||
break;
|
||||
case "signal_in":
|
||||
float.TryParse(signal, NumberStyles.Float, CultureInfo.InvariantCulture, out float value);
|
||||
item.SendSignal(0, (value % modulus).ToString("G", CultureInfo.InvariantCulture), "signal_out", null);
|
||||
float.TryParse(signal.value, NumberStyles.Float, CultureInfo.InvariantCulture, out float value);
|
||||
signal.value = (value % modulus).ToString("G", CultureInfo.InvariantCulture);
|
||||
item.SendSignal(signal, "signal_out");
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -74,11 +74,48 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
private string output;
|
||||
[InGameEditable, Serialize("1", true, description: "The signal the item outputs when it has detected movement.", alwaysUseInstanceValues: true)]
|
||||
public string Output { get; set; }
|
||||
public string Output
|
||||
{
|
||||
get { return output; }
|
||||
set
|
||||
{
|
||||
if (value == null) { return; }
|
||||
output = value;
|
||||
if (output.Length > MaxOutputLength && (item.Submarine == null || !item.Submarine.Loading))
|
||||
{
|
||||
output = output.Substring(0, MaxOutputLength);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private string falseOutput;
|
||||
[InGameEditable, Serialize("", true, description: "The signal the item outputs when it has not detected movement.", alwaysUseInstanceValues: true)]
|
||||
public string FalseOutput { get; set; }
|
||||
public string FalseOutput
|
||||
{
|
||||
get { return falseOutput; }
|
||||
set
|
||||
{
|
||||
if (value == null) { return; }
|
||||
falseOutput = value;
|
||||
if (falseOutput.Length > MaxOutputLength && (item.Submarine == null || !item.Submarine.Loading))
|
||||
{
|
||||
falseOutput = falseOutput.Substring(0, MaxOutputLength);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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.")]
|
||||
public int MaxOutputLength
|
||||
{
|
||||
get { return maxOutputLength; }
|
||||
set
|
||||
{
|
||||
maxOutputLength = Math.Max(value, 0);
|
||||
}
|
||||
}
|
||||
|
||||
[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)]
|
||||
public float MinimumVelocity
|
||||
@@ -113,7 +150,7 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
string signalOut = MotionDetected ? Output : FalseOutput;
|
||||
|
||||
if (!string.IsNullOrEmpty(signalOut)) item.SendSignal(1, signalOut, "state_out", null);
|
||||
if (!string.IsNullOrEmpty(signalOut)) { item.SendSignal(new Signal(signalOut, 1), "state_out"); }
|
||||
|
||||
updateTimer -= deltaTime;
|
||||
if (updateTimer > 0.0f) return;
|
||||
@@ -138,6 +175,10 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
if (IgnoreDead && c.IsDead) { continue; }
|
||||
|
||||
//ignore characters that have spawned a second or less ago
|
||||
//makes it possible to detect when a spawned character moves without triggering the detector immediately as the ragdoll spawns and drops to the ground
|
||||
if (c.SpawnTime > Timing.TotalTime - 1.0) { continue; }
|
||||
|
||||
switch (Target)
|
||||
{
|
||||
case TargetType.Human:
|
||||
|
||||
@@ -24,15 +24,18 @@ namespace Barotrauma.Items.Components
|
||||
base.Update(deltaTime, cam);
|
||||
if (!signalReceived)
|
||||
{
|
||||
item.SendSignal(0, "1", "signal_out", null, 0.0f);
|
||||
item.SendSignal("1", "signal_out");
|
||||
}
|
||||
signalReceived = false;
|
||||
}
|
||||
|
||||
public override void ReceiveSignal(int stepsTaken, string signal, Connection connection, Item source, Character sender, float power = 0.0f, float signalStrength = 1.0f)
|
||||
public override void ReceiveSignal(Signal signal, Connection connection)
|
||||
{
|
||||
if (connection.Name != "signal_in") { return; }
|
||||
item.SendSignal(stepsTaken, signal == "0" || signal == string.Empty ? "1" : "0", "signal_out", sender, 0.0f, source, signalStrength);
|
||||
|
||||
signal.value = signal.value == "0" || string.IsNullOrEmpty(signal.value) ? "1" : "0";
|
||||
signal.power = 0.0f;
|
||||
item.SendSignal(signal, "signal_out");
|
||||
signalReceived = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ namespace Barotrauma.Items.Components
|
||||
string signalOut = sendOutput ? output : falseOutput;
|
||||
if (string.IsNullOrEmpty(signalOut)) return;
|
||||
|
||||
item.SendSignal(0, signalOut, "signal_out", null);
|
||||
item.SendSignal(signalOut, "signal_out");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+6
-6
@@ -59,29 +59,29 @@ namespace Barotrauma.Items.Components
|
||||
float pulseInterval = 1.0f / frequency;
|
||||
while (phase >= pulseInterval)
|
||||
{
|
||||
item.SendSignal(0, "1", "signal_out", null);
|
||||
item.SendSignal("1", "signal_out");
|
||||
phase -= pulseInterval;
|
||||
}
|
||||
break;
|
||||
case WaveType.Square:
|
||||
phase = (phase + deltaTime * frequency) % 1.0f;
|
||||
item.SendSignal(0, phase < 0.5f ? "0" : "1", "signal_out", null);
|
||||
item.SendSignal(phase < 0.5f ? "0" : "1", "signal_out");
|
||||
break;
|
||||
case WaveType.Sine:
|
||||
phase = (phase + deltaTime * frequency) % 1.0f;
|
||||
item.SendSignal(0, Math.Sin(phase * MathHelper.TwoPi).ToString(CultureInfo.InvariantCulture), "signal_out", null);
|
||||
item.SendSignal(Math.Sin(phase * MathHelper.TwoPi).ToString(CultureInfo.InvariantCulture), "signal_out");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public override void ReceiveSignal(int stepsTaken, string signal, Connection connection, Item source, Character sender, float power = 0.0f, float signalStrength = 1.0f)
|
||||
public override void ReceiveSignal(Signal signal, Connection connection)
|
||||
{
|
||||
switch (connection.Name)
|
||||
{
|
||||
case "set_frequency":
|
||||
case "frequency_in":
|
||||
float newFrequency;
|
||||
if (float.TryParse(signal, NumberStyles.Float, CultureInfo.InvariantCulture, out newFrequency))
|
||||
if (float.TryParse(signal.value, NumberStyles.Float, CultureInfo.InvariantCulture, out newFrequency))
|
||||
{
|
||||
Frequency = newFrequency;
|
||||
}
|
||||
@@ -90,7 +90,7 @@ namespace Barotrauma.Items.Components
|
||||
case "set_outputtype":
|
||||
case "set_wavetype":
|
||||
WaveType newOutputType;
|
||||
if (Enum.TryParse(signal, out newOutputType))
|
||||
if (Enum.TryParse(signal.value, out newOutputType))
|
||||
{
|
||||
OutputType = newOutputType;
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
if (item.CurrentHull == null) return;
|
||||
|
||||
item.SendSignal(0, ((int)item.CurrentHull.OxygenPercentage).ToString(), "signal_out", null);
|
||||
item.SendSignal(((int)item.CurrentHull.OxygenPercentage).ToString(), "signal_out");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+35
-9
@@ -1,4 +1,5 @@
|
||||
using System.Text.RegularExpressions;
|
||||
using System;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma.Items.Components
|
||||
@@ -17,8 +18,22 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
private bool nonContinuousOutputSent;
|
||||
|
||||
private string output;
|
||||
|
||||
[InGameEditable, Serialize("1", true, description: "The signal this item outputs when the received signal matches the regular expression.", alwaysUseInstanceValues: true)]
|
||||
public string Output { get; set; }
|
||||
public string Output
|
||||
{
|
||||
get { return output; }
|
||||
set
|
||||
{
|
||||
if (value == null) { return; }
|
||||
output = value;
|
||||
if (output.Length > MaxOutputLength && (item.Submarine == null || !item.Submarine.Loading))
|
||||
{
|
||||
output = output.Substring(0, MaxOutputLength);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[InGameEditable, Serialize(false, true, description: "Should the component output a value of a capture group instead of a constant signal.", alwaysUseInstanceValues: true)]
|
||||
public bool UseCaptureGroup { get; set; }
|
||||
@@ -46,12 +61,23 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
catch
|
||||
{
|
||||
item.SendSignal(0, "ERROR", "signal_out", null);
|
||||
item.SendSignal("ERROR", "signal_out");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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.")]
|
||||
public int MaxOutputLength
|
||||
{
|
||||
get { return maxOutputLength; }
|
||||
set
|
||||
{
|
||||
maxOutputLength = Math.Max(value, 0);
|
||||
}
|
||||
}
|
||||
|
||||
public RegExFindComponent(Item item, XElement element)
|
||||
: base(item, element)
|
||||
{
|
||||
@@ -74,7 +100,7 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
catch
|
||||
{
|
||||
item.SendSignal(0, "ERROR", "signal_out", null);
|
||||
item.SendSignal("ERROR", "signal_out");
|
||||
previousResult = false;
|
||||
return;
|
||||
}
|
||||
@@ -106,25 +132,25 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
if (ContinuousOutput)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(signalOut)) { item.SendSignal(0, signalOut, "signal_out", null); }
|
||||
if (!string.IsNullOrEmpty(signalOut)) { item.SendSignal(signalOut, "signal_out"); }
|
||||
}
|
||||
else if (!nonContinuousOutputSent)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(signalOut)) { item.SendSignal(0, signalOut, "signal_out", null); }
|
||||
if (!string.IsNullOrEmpty(signalOut)) { item.SendSignal(signalOut, "signal_out"); }
|
||||
nonContinuousOutputSent = true;
|
||||
}
|
||||
}
|
||||
|
||||
public override void ReceiveSignal(int stepsTaken, string signal, Connection connection, Item source, Character sender, float power = 0.0f, float signalStrength = 1.0f)
|
||||
public override void ReceiveSignal(Signal signal, Connection connection)
|
||||
{
|
||||
switch (connection.Name)
|
||||
{
|
||||
case "signal_in":
|
||||
receivedSignal = signal;
|
||||
receivedSignal = signal.value;
|
||||
nonContinuousOutputSent = false;
|
||||
break;
|
||||
case "set_output":
|
||||
Output = signal;
|
||||
Output = signal.value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,7 +86,7 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
RefreshConnections();
|
||||
|
||||
item.SendSignal(0, IsOn ? "1" : "0", "state_out", null);
|
||||
item.SendSignal(IsOn ? "1" : "0", "state_out");
|
||||
|
||||
if (!CanTransfer) { Voltage = 0.0f; return; }
|
||||
|
||||
@@ -169,23 +169,23 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
}
|
||||
|
||||
public override void ReceiveSignal(int stepsTaken, string signal, Connection connection, Item source, Character sender, float power = 0.0f, float signalStrength = 1.0f)
|
||||
public override void ReceiveSignal(Signal signal, Connection connection)
|
||||
{
|
||||
if (item.Condition <= 0.0f || connection.IsPower) { return; }
|
||||
|
||||
if (connectionPairs.TryGetValue(connection.Name, out string outConnection))
|
||||
{
|
||||
if (!IsOn) { return; }
|
||||
item.SendSignal(stepsTaken, signal, outConnection, sender, power, source, signalStrength);
|
||||
item.SendSignal(signal, outConnection);
|
||||
}
|
||||
else if (connection.Name == "toggle")
|
||||
{
|
||||
if (signal == "0") { return; }
|
||||
if (signal.value == "0") { return; }
|
||||
SetState(!IsOn, false);
|
||||
}
|
||||
else if (connection.Name == "set_state")
|
||||
{
|
||||
SetState(signal != "0", false);
|
||||
SetState(signal.value != "0", false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
namespace Barotrauma.Items.Components
|
||||
{
|
||||
public struct Signal
|
||||
{
|
||||
internal string value;
|
||||
internal int stepsTaken;
|
||||
internal Character sender;
|
||||
internal Item source;
|
||||
internal float power;
|
||||
internal float strength;
|
||||
|
||||
internal Signal(string value, int stepsTaken = 0, Character sender = null,
|
||||
Item source = null, float power = 0.0f, float strength = 1.0f)
|
||||
{
|
||||
this.value = value;
|
||||
this.stepsTaken = stepsTaken;
|
||||
this.sender = sender;
|
||||
this.source = source;
|
||||
this.power = power;
|
||||
this.strength = strength;
|
||||
}
|
||||
}
|
||||
}
|
||||
+49
-11
@@ -1,38 +1,76 @@
|
||||
using System.Xml.Linq;
|
||||
using System;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma.Items.Components
|
||||
{
|
||||
class SignalCheckComponent : ItemComponent
|
||||
{
|
||||
private string output;
|
||||
[InGameEditable, Serialize("1", true, description: "The signal this item outputs when the received signal matches the target signal.", alwaysUseInstanceValues: true)]
|
||||
public string Output { get; set; }
|
||||
public string Output
|
||||
{
|
||||
get { return output; }
|
||||
set
|
||||
{
|
||||
if (value == null) { return; }
|
||||
output = value;
|
||||
if (output.Length > MaxOutputLength && (item.Submarine == null || !item.Submarine.Loading))
|
||||
{
|
||||
output = output.Substring(0, MaxOutputLength);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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)]
|
||||
public string FalseOutput { get; set; }
|
||||
public string FalseOutput
|
||||
{
|
||||
get { return falseOutput; }
|
||||
set
|
||||
{
|
||||
if (value == null) { return; }
|
||||
falseOutput = value;
|
||||
if (falseOutput.Length > MaxOutputLength && (item.Submarine == null || !item.Submarine.Loading))
|
||||
{
|
||||
falseOutput = falseOutput.Substring(0, MaxOutputLength);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[InGameEditable, Serialize("", true, description: "The value to compare the received signals against.", alwaysUseInstanceValues: true)]
|
||||
public string TargetSignal { get; set; }
|
||||
|
||||
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.")]
|
||||
public int MaxOutputLength
|
||||
{
|
||||
get { return maxOutputLength; }
|
||||
set
|
||||
{
|
||||
maxOutputLength = Math.Max(value, 0);
|
||||
}
|
||||
}
|
||||
|
||||
public SignalCheckComponent(Item item, XElement element)
|
||||
: base(item, element)
|
||||
{
|
||||
}
|
||||
|
||||
public override void ReceiveSignal(int stepsTaken, string signal, Connection connection, Item source, Character sender, float power = 0.0f, float signalStrength = 1.0f)
|
||||
public override void ReceiveSignal(Signal signal, Connection connection)
|
||||
{
|
||||
switch (connection.Name)
|
||||
{
|
||||
case "signal_in":
|
||||
string signalOut = (signal == TargetSignal) ? Output : FalseOutput;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(signalOut)) return;
|
||||
item.SendSignal(stepsTaken, signalOut, "signal_out", sender, signalStrength);
|
||||
|
||||
string signalOut = (signal.value == TargetSignal) ? Output : FalseOutput;
|
||||
if (string.IsNullOrEmpty(signalOut)) { return; }
|
||||
signal.value = signalOut;
|
||||
item.SendSignal(signal, "signal_out");
|
||||
break;
|
||||
case "set_output":
|
||||
Output = signal;
|
||||
Output = signal.value;
|
||||
break;
|
||||
case "set_targetsignal":
|
||||
TargetSignal = signal;
|
||||
TargetSignal = signal.value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Xml.Linq;
|
||||
using System;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma.Items.Components
|
||||
{
|
||||
@@ -9,11 +10,48 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
private bool fireInRange;
|
||||
|
||||
[InGameEditable, Serialize("1", true, description: "The signal the item outputs when it has detected movement.", alwaysUseInstanceValues: true)]
|
||||
public string Output { get; set; }
|
||||
private string output;
|
||||
[InGameEditable, Serialize("1", true, description: "The signal the item outputs when it has detected a fire.", alwaysUseInstanceValues: true)]
|
||||
public string Output
|
||||
{
|
||||
get { return output; }
|
||||
set
|
||||
{
|
||||
if (value == null) { return; }
|
||||
output = value;
|
||||
if (output.Length > MaxOutputLength && (item.Submarine == null || !item.Submarine.Loading))
|
||||
{
|
||||
output = output.Substring(0, MaxOutputLength);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[InGameEditable, Serialize("0", true, description: "The signal the item outputs when it has not detected movement.", alwaysUseInstanceValues: true)]
|
||||
public string FalseOutput { get; set; }
|
||||
private string falseOutput;
|
||||
[InGameEditable, Serialize("0", true, description: "The signal the item outputs when it has not detected a fire.", alwaysUseInstanceValues: true)]
|
||||
public string FalseOutput
|
||||
{
|
||||
get { return falseOutput; }
|
||||
set
|
||||
{
|
||||
if (value == null) { return; }
|
||||
falseOutput = value;
|
||||
if (falseOutput.Length > MaxOutputLength && (item.Submarine == null || !item.Submarine.Loading))
|
||||
{
|
||||
falseOutput = falseOutput.Substring(0, MaxOutputLength);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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.")]
|
||||
public int MaxOutputLength
|
||||
{
|
||||
get { return maxOutputLength; }
|
||||
set
|
||||
{
|
||||
maxOutputLength = Math.Max(value, 0);
|
||||
}
|
||||
}
|
||||
|
||||
public SmokeDetector(Item item, XElement element)
|
||||
: base(item, element)
|
||||
@@ -45,7 +83,8 @@ namespace Barotrauma.Items.Components
|
||||
fireInRange = IsFireInRange();
|
||||
fireCheckTimer = FireCheckInterval;
|
||||
}
|
||||
item.SendSignal(0, fireInRange ? Output : FalseOutput, "signal_out", null);
|
||||
string signalOut = fireInRange ? Output : FalseOutput;
|
||||
if (!string.IsNullOrEmpty(signalOut)) { item.SendSignal(signalOut, "signal_out"); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+12
-9
@@ -37,32 +37,35 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
sealed public override void Update(float deltaTime, Camera cam)
|
||||
{
|
||||
bool deactivate = true;
|
||||
bool earlyReturn = false;
|
||||
for (int i = 0; i < timeSinceReceived.Length; i++)
|
||||
{
|
||||
if (timeSinceReceived[i] > timeFrame)
|
||||
{
|
||||
IsActive = false;
|
||||
return;
|
||||
}
|
||||
deactivate &= timeSinceReceived[i] > timeFrame;
|
||||
earlyReturn |= timeSinceReceived[i] > timeFrame;
|
||||
timeSinceReceived[i] += deltaTime;
|
||||
}
|
||||
// only stop Update() if both signals timed-out. if IsActive == false, then the component stops updating.
|
||||
IsActive = !deactivate;
|
||||
// early return if either of the signal timed-out
|
||||
if (earlyReturn) { return; }
|
||||
string output = Calculate(receivedSignal[0], receivedSignal[1]);
|
||||
item.SendSignal(0, output, "signal_out", null);
|
||||
item.SendSignal(output, "signal_out");
|
||||
}
|
||||
|
||||
protected abstract string Calculate(string signal1, string signal2);
|
||||
|
||||
public override void ReceiveSignal(int stepsTaken, string signal, Connection connection, Item source, Character sender, float power = 0.0f, float signalStrength = 1.0f)
|
||||
public override void ReceiveSignal(Signal signal, Connection connection)
|
||||
{
|
||||
switch (connection.Name)
|
||||
{
|
||||
case "signal_in1":
|
||||
receivedSignal[0] = signal;
|
||||
receivedSignal[0] = signal.value;
|
||||
timeSinceReceived[0] = 0.0f;
|
||||
IsActive = true;
|
||||
break;
|
||||
case "signal_in2":
|
||||
receivedSignal[1] = signal;
|
||||
receivedSignal[1] = signal.value;
|
||||
timeSinceReceived[1] = 0.0f;
|
||||
IsActive = true;
|
||||
break;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Barotrauma.Networking;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma.Items.Components
|
||||
@@ -31,6 +32,19 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Can be used to display messages on the terminal via status effects
|
||||
/// </summary>
|
||||
public string ShowMessage
|
||||
{
|
||||
get { return messageHistory.Count == 0 ? string.Empty : messageHistory.Last(); }
|
||||
set
|
||||
{
|
||||
if (string.IsNullOrEmpty(value)) { return; }
|
||||
ShowOnDisplay(value);
|
||||
}
|
||||
}
|
||||
|
||||
private string OutputValue { get; set; }
|
||||
|
||||
public Terminal(Item item, XElement element)
|
||||
@@ -42,29 +56,34 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
partial void InitProjSpecific(XElement element);
|
||||
|
||||
partial void ShowOnDisplay(string input);
|
||||
partial void ShowOnDisplay(string input, bool addToHistory = true);
|
||||
|
||||
public override void ReceiveSignal(int stepsTaken, string signal, Connection connection, Item source, Character sender, float power = 0, float signalStrength = 1)
|
||||
public override void ReceiveSignal(Signal signal, Connection connection)
|
||||
{
|
||||
if (connection.Name != "signal_in") { return; }
|
||||
if (signal.Length > MaxMessageLength)
|
||||
if (signal.value.Length > MaxMessageLength)
|
||||
{
|
||||
signal = signal.Substring(0, MaxMessageLength);
|
||||
signal.value = signal.value.Substring(0, MaxMessageLength);
|
||||
}
|
||||
|
||||
string inputSignal = signal.Replace("\\n", "\n");
|
||||
string inputSignal = signal.value.Replace("\\n", "\n");
|
||||
ShowOnDisplay(inputSignal);
|
||||
}
|
||||
|
||||
public override void OnItemLoaded()
|
||||
{
|
||||
bool isSubEditor = false;
|
||||
#if CLIENT
|
||||
isSubEditor = Screen.Selected != GameMain.SubEditorScreen || GameMain.GameSession?.GameMode is TestGameMode;
|
||||
#endif
|
||||
|
||||
base.OnItemLoaded();
|
||||
if (!string.IsNullOrEmpty(DisplayedWelcomeMessage))
|
||||
{
|
||||
ShowOnDisplay(DisplayedWelcomeMessage);
|
||||
ShowOnDisplay(DisplayedWelcomeMessage, addToHistory: !isSubEditor);
|
||||
DisplayedWelcomeMessage = "";
|
||||
//remove welcome message if a game session is running so it doesn't reappear on successive rounds
|
||||
if (GameMain.GameSession != null)
|
||||
if (GameMain.GameSession != null && !isSubEditor)
|
||||
{
|
||||
welcomeMessage = null;
|
||||
}
|
||||
|
||||
+17
-14
@@ -56,71 +56,74 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
float angle = (float)Math.Atan2(receivedSignal[1], receivedSignal[0]);
|
||||
if (!UseRadians) { angle = MathHelper.ToDegrees(angle); }
|
||||
item.SendSignal(0, angle.ToString("G", CultureInfo.InvariantCulture), "signal_out", null);
|
||||
item.SendSignal(angle.ToString("G", CultureInfo.InvariantCulture), "signal_out");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void ReceiveSignal(int stepsTaken, string signal, Connection connection, Item source, Character sender, float power = 0, float signalStrength = 1)
|
||||
public override void ReceiveSignal(Signal signal, Connection connection)
|
||||
{
|
||||
float.TryParse(signal, NumberStyles.Float, CultureInfo.InvariantCulture, out float value);
|
||||
float.TryParse(signal.value, NumberStyles.Float, CultureInfo.InvariantCulture, out float value);
|
||||
switch (Function)
|
||||
{
|
||||
case FunctionType.Sin:
|
||||
if (!UseRadians) { value = MathHelper.ToRadians(value); }
|
||||
item.SendSignal(0, ((float)Math.Sin(value)).ToString("G", CultureInfo.InvariantCulture), "signal_out", null);
|
||||
value = MathF.Sin(value);
|
||||
break;
|
||||
case FunctionType.Cos:
|
||||
if (!UseRadians) { value = MathHelper.ToRadians(value); }
|
||||
item.SendSignal(0, ((float)Math.Cos(value)).ToString("G", CultureInfo.InvariantCulture), "signal_out", null);
|
||||
value = MathF.Cos(value);
|
||||
break;
|
||||
case FunctionType.Tan:
|
||||
if (!UseRadians) { value = MathHelper.ToRadians(value); }
|
||||
//tan is undefined if the value is (π / 2) + πk, where k is any integer
|
||||
if (!MathUtils.NearlyEqual(value % MathHelper.Pi, MathHelper.PiOver2))
|
||||
{
|
||||
item.SendSignal(0, ((float)Math.Tan(value)).ToString("G", CultureInfo.InvariantCulture), "signal_out", null);
|
||||
value = MathF.Tan(value);
|
||||
}
|
||||
break;
|
||||
case FunctionType.Asin:
|
||||
//asin is only defined in the range [-1,1]
|
||||
if (value >= -1.0f && value <= 1.0f)
|
||||
{
|
||||
float angle = (float)Math.Asin(value);
|
||||
float angle = MathF.Asin(value);
|
||||
if (!UseRadians) { angle = MathHelper.ToDegrees(angle); }
|
||||
item.SendSignal(0, angle.ToString("G", CultureInfo.InvariantCulture), "signal_out", null);
|
||||
value = angle;
|
||||
}
|
||||
break;
|
||||
case FunctionType.Acos:
|
||||
//acos is only defined in the range [-1,1]
|
||||
if (value >= -1.0f && value <= 1.0f)
|
||||
{
|
||||
float angle = (float)Math.Acos(value);
|
||||
float angle = MathF.Acos(value);
|
||||
if (!UseRadians) { angle = MathHelper.ToDegrees(angle); }
|
||||
item.SendSignal(0, angle.ToString("G", CultureInfo.InvariantCulture), "signal_out", null);
|
||||
value = angle;
|
||||
}
|
||||
break;
|
||||
case FunctionType.Atan:
|
||||
if (connection.Name == "signal_in_x")
|
||||
{
|
||||
timeSinceReceived[0] = 0.0f;
|
||||
float.TryParse(signal, NumberStyles.Float, CultureInfo.InvariantCulture, out receivedSignal[0]);
|
||||
float.TryParse(signal.value, NumberStyles.Float, CultureInfo.InvariantCulture, out receivedSignal[0]);
|
||||
}
|
||||
else if (connection.Name == "signal_in_y")
|
||||
{
|
||||
timeSinceReceived[1] = 0.0f;
|
||||
float.TryParse(signal, NumberStyles.Float, CultureInfo.InvariantCulture, out receivedSignal[1]);
|
||||
float.TryParse(signal.value, NumberStyles.Float, CultureInfo.InvariantCulture, out receivedSignal[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
float angle = (float)Math.Atan(value);
|
||||
float angle = MathF.Atan(value);
|
||||
if (!UseRadians) { angle = MathHelper.ToDegrees(angle); }
|
||||
item.SendSignal(0, angle.ToString("G", CultureInfo.InvariantCulture), "signal_out", null);
|
||||
value = angle;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new NotImplementedException($"Function {Function} has not been implemented.");
|
||||
}
|
||||
|
||||
signal.value = value.ToString("G", CultureInfo.InvariantCulture);
|
||||
item.SendSignal(signal, "signal_out");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,11 +12,48 @@ namespace Barotrauma.Items.Components
|
||||
private bool isInWater;
|
||||
private float stateSwitchDelay;
|
||||
|
||||
private string output;
|
||||
[InGameEditable, Serialize("1", true, description: "The signal the item sends out when it's underwater.", alwaysUseInstanceValues: true)]
|
||||
public string Output { get; set; }
|
||||
public string Output
|
||||
{
|
||||
get { return output; }
|
||||
set
|
||||
{
|
||||
if (value == null) { return; }
|
||||
output = value;
|
||||
if (output.Length > MaxOutputLength && (item.Submarine == null || !item.Submarine.Loading))
|
||||
{
|
||||
output = output.Substring(0, MaxOutputLength);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private string falseOutput;
|
||||
[InGameEditable, Serialize("0", true, description: "The signal the item sends out when it's not underwater.", alwaysUseInstanceValues: true)]
|
||||
public string FalseOutput { get; set; }
|
||||
public string FalseOutput
|
||||
{
|
||||
get { return falseOutput; }
|
||||
set
|
||||
{
|
||||
if (value == null) { return; }
|
||||
falseOutput = value;
|
||||
if (falseOutput.Length > MaxOutputLength && (item.Submarine == null || !item.Submarine.Loading))
|
||||
{
|
||||
falseOutput = falseOutput.Substring(0, MaxOutputLength);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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.")]
|
||||
public int MaxOutputLength
|
||||
{
|
||||
get { return maxOutputLength; }
|
||||
set
|
||||
{
|
||||
maxOutputLength = Math.Max(value, 0);
|
||||
}
|
||||
}
|
||||
|
||||
public WaterDetector(Item item, XElement element)
|
||||
: base(item, element)
|
||||
@@ -59,13 +96,13 @@ namespace Barotrauma.Items.Components
|
||||
string signalOut = isInWater ? Output : FalseOutput;
|
||||
if (!string.IsNullOrEmpty(signalOut))
|
||||
{
|
||||
item.SendSignal(0, signalOut, "signal_out", null);
|
||||
item.SendSignal(signalOut, "signal_out");
|
||||
}
|
||||
|
||||
if (item.CurrentHull != null)
|
||||
{
|
||||
int waterPercentage = MathHelper.Clamp((int)Math.Round(item.CurrentHull.WaterPercentage), 0, 100);
|
||||
item.SendSignal(0, waterPercentage.ToString(), "water_%", null);
|
||||
item.SendSignal(waterPercentage.ToString(), "water_%");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -152,9 +152,9 @@ namespace Barotrauma.Items.Components
|
||||
channelMemory[index] = MathHelper.Clamp(value, 0, 10000);
|
||||
}
|
||||
|
||||
public void TransmitSignal(int stepsTaken, string signal, Item source, Character sender, bool sentFromChat, float signalStrength = 1.0f)
|
||||
public void TransmitSignal(Signal signal, bool sentFromChat)
|
||||
{
|
||||
var senderComponent = source?.GetComponent<WifiComponent>();
|
||||
var senderComponent = signal.source?.GetComponent<WifiComponent>();
|
||||
if (senderComponent != null && !CanReceive(senderComponent)) { return; }
|
||||
|
||||
bool chatMsgSent = false;
|
||||
@@ -165,22 +165,24 @@ namespace Barotrauma.Items.Components
|
||||
if (sentFromChat && !wifiComp.LinkToChat) { continue; }
|
||||
|
||||
//signal strength diminishes by distance
|
||||
float sentSignalStrength = signalStrength *
|
||||
float sentSignalStrength = signal.strength *
|
||||
MathHelper.Clamp(1.0f - (Vector2.Distance(item.WorldPosition, wifiComp.item.WorldPosition) / wifiComp.range), 0.0f, 1.0f);
|
||||
wifiComp.item.SendSignal(stepsTaken, signal, "signal_out", sender, 0, source, sentSignalStrength);
|
||||
Signal s = new Signal(signal.value, signal.stepsTaken, sender: signal.sender, source: signal.source,
|
||||
power: 0.0f, strength: sentSignalStrength);
|
||||
wifiComp.item.SendSignal(s, "signal_out");
|
||||
|
||||
if (source != null)
|
||||
if (signal.source != null)
|
||||
{
|
||||
foreach (Item receiverItem in wifiComp.item.LastSentSignalRecipients)
|
||||
foreach (Connection receiver in wifiComp.item.LastSentSignalRecipients)
|
||||
{
|
||||
if (!source.LastSentSignalRecipients.Contains(receiverItem))
|
||||
if (!signal.source.LastSentSignalRecipients.Contains(receiver))
|
||||
{
|
||||
source.LastSentSignalRecipients.Add(receiverItem);
|
||||
signal.source.LastSentSignalRecipients.Add(receiver);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (DiscardDuplicateChatMessages && signal == prevSignal) { continue; }
|
||||
if (DiscardDuplicateChatMessages && signal.value == prevSignal) { continue; }
|
||||
|
||||
//create a chat message
|
||||
if (LinkToChat && wifiComp.LinkToChat && chatMsgCooldown <= 0.0f && !sentFromChat)
|
||||
@@ -188,7 +190,7 @@ namespace Barotrauma.Items.Components
|
||||
if (wifiComp.item.ParentInventory != null &&
|
||||
wifiComp.item.ParentInventory.Owner != null)
|
||||
{
|
||||
string chatMsg = signal;
|
||||
string chatMsg = signal.value;
|
||||
if (senderComponent != null)
|
||||
{
|
||||
chatMsg = ChatMessage.ApplyDistanceEffect(chatMsg, 1.0f - sentSignalStrength);
|
||||
@@ -201,7 +203,7 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
if (GameMain.Client == null)
|
||||
{
|
||||
GameMain.GameSession?.CrewManager?.AddSinglePlayerChatMessage(source?.Name ?? "", signal, ChatMessageType.Radio, sender: null);
|
||||
GameMain.GameSession?.CrewManager?.AddSinglePlayerChatMessage(signal.source?.Name ?? "", signal.value, ChatMessageType.Radio, sender: null);
|
||||
}
|
||||
}
|
||||
#elif SERVER
|
||||
@@ -211,7 +213,7 @@ namespace Barotrauma.Items.Components
|
||||
if (recipientClient != null)
|
||||
{
|
||||
GameMain.Server.SendDirectChatMessage(
|
||||
ChatMessage.Create(source?.Name ?? "", chatMsg, ChatMessageType.Radio, null), recipientClient);
|
||||
ChatMessage.Create(signal.source?.Name ?? "", chatMsg, ChatMessageType.Radio, null), recipientClient);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -225,26 +227,26 @@ namespace Barotrauma.Items.Components
|
||||
IsActive = true;
|
||||
}
|
||||
|
||||
prevSignal = signal;
|
||||
prevSignal = signal.value;
|
||||
}
|
||||
|
||||
public override void ReceiveSignal(int stepsTaken, string signal, Connection connection, Item source, Character sender, float power = 0.0f, float signalStrength = 1.0f)
|
||||
public override void ReceiveSignal(Signal signal, Connection connection)
|
||||
{
|
||||
if (connection == null) { return; }
|
||||
|
||||
switch (connection.Name)
|
||||
{
|
||||
case "signal_in":
|
||||
TransmitSignal(stepsTaken, signal, source, sender, false, signalStrength);
|
||||
TransmitSignal(signal, false);
|
||||
break;
|
||||
case "set_channel":
|
||||
if (int.TryParse(signal, out int newChannel))
|
||||
if (int.TryParse(signal.value, out int newChannel))
|
||||
{
|
||||
Channel = newChannel;
|
||||
}
|
||||
break;
|
||||
case "set_range":
|
||||
if (float.TryParse(signal, NumberStyles.Float, CultureInfo.InvariantCulture, out float newRange))
|
||||
if (float.TryParse(signal.value, NumberStyles.Float, CultureInfo.InvariantCulture, out float newRange))
|
||||
{
|
||||
Range = newRange;
|
||||
}
|
||||
|
||||
@@ -37,11 +37,6 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
angle = MathUtils.VectorToAngle(end - start);
|
||||
length = Vector2.Distance(start, end);
|
||||
|
||||
if (length > 5000.0f)
|
||||
{
|
||||
int akjsdnfkjsadf = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,6 +95,20 @@ namespace Barotrauma.Items.Components
|
||||
set;
|
||||
}
|
||||
|
||||
[Editable, Serialize(false, true, "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.")]
|
||||
public bool UseSpriteDepth
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public Wire(Item item, XElement element)
|
||||
: base(item, element)
|
||||
{
|
||||
@@ -309,6 +318,8 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
if (Screen.Selected != GameMain.SubEditorScreen)
|
||||
{
|
||||
if (user != null) { NoAutoLock = true; }
|
||||
|
||||
//cannot run wires from sub to another
|
||||
if (item.Submarine != sub && sub != null && item.Submarine != null)
|
||||
{
|
||||
|
||||
@@ -22,7 +22,7 @@ namespace Barotrauma.Items.Components
|
||||
string signalOut = sendOutput == 1 ? output : falseOutput;
|
||||
if (string.IsNullOrEmpty(signalOut)) return;
|
||||
|
||||
item.SendSignal(0, signalOut, "signal_out", null);
|
||||
item.SendSignal(signalOut, "signal_out");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -251,7 +251,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
private void UpdateTransformedBarrelPos()
|
||||
{
|
||||
transformedBarrelPos = MathUtils.RotatePointAroundTarget(barrelPos * item.Scale, new Vector2(item.Rect.Width / 2, item.Rect.Height / 2), item.Rotation);
|
||||
transformedBarrelPos = MathUtils.RotatePointAroundTarget(barrelPos * item.Scale, new Vector2(item.Rect.Width / 2, item.Rect.Height / 2), MathHelper.ToRadians(item.Rotation));
|
||||
#if CLIENT
|
||||
item.ResetCachedVisibleSize();
|
||||
#endif
|
||||
@@ -436,23 +436,28 @@ namespace Barotrauma.Items.Components
|
||||
Projectile launchedProjectile = null;
|
||||
for (int i = 0; i < ProjectileCount; i++)
|
||||
{
|
||||
foreach (MapEntity e in item.linkedTo)
|
||||
var projectiles = GetLoadedProjectiles(true);
|
||||
if (projectiles.Any())
|
||||
{
|
||||
//use linked projectile containers in case they have to react to the turret being launched somehow
|
||||
//(play a sound, spawn more projectiles)
|
||||
if (!(e is Item linkedItem)) { continue; }
|
||||
ItemContainer projectileContainer = linkedItem.GetComponent<ItemContainer>();
|
||||
if (projectileContainer != null)
|
||||
ItemContainer projectileContainer = projectiles.First().Item.Container?.GetComponent<ItemContainer>();
|
||||
if (projectileContainer?.Item != item) { projectileContainer?.Item.Use(deltaTime, null); }
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (MapEntity e in item.linkedTo)
|
||||
{
|
||||
linkedItem.Use(deltaTime, null);
|
||||
var repairable = linkedItem.GetComponent<Repairable>();
|
||||
if (repairable != null && failedLaunchAttempts < 2)
|
||||
//use linked projectile containers in case they have to react to the turret being launched somehow
|
||||
//(play a sound, spawn more projectiles)
|
||||
if (!(e is Item linkedItem)) { continue; }
|
||||
ItemContainer projectileContainer = linkedItem.GetComponent<ItemContainer>();
|
||||
if (projectileContainer != null)
|
||||
{
|
||||
repairable.LastActiveTime = (float)Timing.TotalTime + 1.0f;
|
||||
linkedItem.Use(deltaTime, null);
|
||||
projectiles = GetLoadedProjectiles(true);
|
||||
if (projectiles.Any()) { break; }
|
||||
}
|
||||
}
|
||||
}
|
||||
var projectiles = GetLoadedProjectiles(true);
|
||||
if (projectiles.Count == 0 && !LaunchWithoutProjectile)
|
||||
{
|
||||
//coilguns spawns ammo in the ammo boxes with the OnUse statuseffect when the turret is launched,
|
||||
@@ -471,7 +476,6 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
failedLaunchAttempts = 0;
|
||||
launchedProjectile = projectiles.FirstOrDefault();
|
||||
|
||||
if (!ignorePower)
|
||||
{
|
||||
var batteries = item.GetConnectedComponents<PowerContainer>();
|
||||
@@ -492,6 +496,15 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
if (launchedProjectile?.Item.Container != null)
|
||||
{
|
||||
var repairable = launchedProjectile?.Item.Container.GetComponent<Repairable>();
|
||||
if (repairable != null)
|
||||
{
|
||||
repairable.LastActiveTime = (float)Timing.TotalTime + 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
if (launchedProjectile != null || LaunchWithoutProjectile)
|
||||
{
|
||||
Launch(launchedProjectile?.Item, character);
|
||||
@@ -709,10 +722,7 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
else
|
||||
{
|
||||
float midRotation = (minRotation + maxRotation) / 2.0f;
|
||||
while (midRotation - angle < -MathHelper.Pi) { angle -= MathHelper.TwoPi; }
|
||||
while (midRotation - angle > MathHelper.Pi) { angle += MathHelper.TwoPi; }
|
||||
if (angle < minRotation || angle > maxRotation) { return; }
|
||||
if (!CheckTurretAngle(angle)) { return; }
|
||||
float enemyAngle = MathUtils.VectorToAngle(target.WorldPosition - item.WorldPosition);
|
||||
float turretAngle = -rotation;
|
||||
if (Math.Abs(MathUtils.GetShortestAngle(enemyAngle, turretAngle)) > 0.15f) { return; }
|
||||
@@ -770,6 +780,7 @@ namespace Barotrauma.Items.Components
|
||||
TryLaunch(deltaTime, ignorePower: true);
|
||||
}
|
||||
|
||||
private bool outOfAmmo;
|
||||
public override bool AIOperate(float deltaTime, Character character, AIObjectiveOperateItem objective)
|
||||
{
|
||||
if (character.AIController.SelectedAiTarget?.Entity is Character previousTarget &&
|
||||
@@ -836,32 +847,37 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
if (container == null || container.ContainableItems.Count == 0)
|
||||
{
|
||||
character.Speak(TextManager.GetWithVariable("DialogCannotLoadTurret", "[itemname]", item.Name, true), null, 0.0f, "cannotloadturret", 30.0f);
|
||||
if (character.IsOnPlayerTeam)
|
||||
{
|
||||
character.Speak(TextManager.GetWithVariable("DialogCannotLoadTurret", "[itemname]", item.Name, true), null, 0.0f, "cannotloadturret", 30.0f);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (objective.SubObjectives.None())
|
||||
{
|
||||
if (!AIDecontainEmptyItems(character, objective, equip: true, sourceContainer: container))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (objective.SubObjectives.None())
|
||||
{
|
||||
var loadItemsObjective = AIContainItems<Turret>(container, character, objective, usableProjectileCount + 1, equip: true, removeEmpty: true, dropItemOnDeselected: true);
|
||||
if (loadItemsObjective == null)
|
||||
loadItemsObjective.ignoredContainerIdentifiers = new string[] { containerItem.prefab.Identifier };
|
||||
if (character.IsOnPlayerTeam)
|
||||
{
|
||||
if (usableProjectileCount == 0)
|
||||
{
|
||||
character.Speak(TextManager.GetWithVariable("DialogCannotLoadTurret", "[itemname]", item.Name, true), null, 0.0f, "cannotloadturret", 30.0f);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
loadItemsObjective.ignoredContainerIdentifiers = new string[] { containerItem.prefab.Identifier };
|
||||
character.Speak(TextManager.GetWithVariable("DialogLoadTurret", "[itemname]", item.Name, true), null, 0.0f, "loadturret", 30.0f);
|
||||
return false;
|
||||
}
|
||||
loadItemsObjective.Abandoned += CheckRemainingAmmo;
|
||||
loadItemsObjective.Completed += CheckRemainingAmmo;
|
||||
return false;
|
||||
|
||||
void CheckRemainingAmmo()
|
||||
{
|
||||
if (!character.IsOnPlayerTeam) { return; }
|
||||
string ammoType = container.Item.HasTag("railgunammosource") ? "railgunammo" : container.Item.HasTag("coilgunammosource") ? "coilgunammo" : "turretammo";
|
||||
int remainingAmmo = Submarine.MainSub.GetItems(false).Count(i => i.HasTag(ammoType) && i.Condition > 1);
|
||||
if (remainingAmmo == 0)
|
||||
{
|
||||
character.Speak(TextManager.Get($"DialogOutOf{ammoType}"), null, 0.0f, "outofammo", 30.0f);
|
||||
}
|
||||
else if (remainingAmmo < 3)
|
||||
{
|
||||
character.Speak(TextManager.Get($"DialogLowOn{ammoType}"), null, 0.0f, "outofammo", 30.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (objective.SubObjectives.Any())
|
||||
@@ -873,23 +889,51 @@ namespace Barotrauma.Items.Components
|
||||
//enough shells and power
|
||||
Character closestEnemy = null;
|
||||
Vector2? targetPos = null;
|
||||
float maxDistance = 10000;
|
||||
float shootDistance = AIRange * item.OffsetOnSelectedMultiplier;
|
||||
float closestDistance = shootDistance * shootDistance;
|
||||
float closestDistance = maxDistance * maxDistance;
|
||||
foreach (Character enemy in Character.CharacterList)
|
||||
{
|
||||
// Ignore dead, friendly, and those that are inside the same sub
|
||||
if (enemy.IsDead || !enemy.Enabled || enemy.Submarine == character.Submarine) { continue; }
|
||||
// Don't aim monsters that are inside a submarine.
|
||||
if (!enemy.IsHuman && enemy.CurrentHull != null) { continue; }
|
||||
if (HumanAIController.IsFriendly(character, enemy)) { continue; }
|
||||
float dist = Vector2.DistanceSquared(enemy.WorldPosition, item.WorldPosition);
|
||||
if (dist > closestDistance) { continue; }
|
||||
if (!CheckTurretAngle(enemy.WorldPosition)) { continue; }
|
||||
if (dist < shootDistance * shootDistance)
|
||||
{
|
||||
// Only check the angle to targets that are close enough to be shot at
|
||||
// We shouldn't check the angle when a long creature is traveling outside of the shooting range, because doing so would not allow us to shoot the limbs that might be close enough to shoot at.
|
||||
if (!CheckTurretAngle(enemy.WorldPosition)) { continue; }
|
||||
}
|
||||
closestEnemy = enemy;
|
||||
closestDistance = dist;
|
||||
}
|
||||
|
||||
if (closestEnemy != null)
|
||||
{
|
||||
// Target the closest limb. Doesn't make much difference with smaller creatures, but enables the bots to shoot longer abyss creatures like the endworm. Otherwise they just target the main body = head.
|
||||
targetPos = closestEnemy.WorldPosition;
|
||||
float closestDist = closestDistance;
|
||||
foreach (Limb limb in closestEnemy.AnimController.Limbs)
|
||||
{
|
||||
if (limb.IsSevered) { continue; }
|
||||
if (limb.Hidden) { continue; }
|
||||
if (!CheckTurretAngle(limb.WorldPosition)) { continue; }
|
||||
float dist = Vector2.DistanceSquared(limb.WorldPosition, item.WorldPosition);
|
||||
if (dist < closestDist)
|
||||
{
|
||||
closestDist = dist;
|
||||
targetPos = limb.WorldPosition;
|
||||
}
|
||||
}
|
||||
if (closestDist > shootDistance * shootDistance)
|
||||
{
|
||||
// Not close enough to shoot
|
||||
closestEnemy = null;
|
||||
targetPos = null;
|
||||
}
|
||||
}
|
||||
else if (item.Submarine != null && Level.Loaded != null)
|
||||
{
|
||||
@@ -949,29 +993,32 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
if (closestEnemy != null && character.AIController.SelectedAiTarget != closestEnemy.AiTarget)
|
||||
{
|
||||
if (character.AIController.SelectedAiTarget == null)
|
||||
if (character.IsOnPlayerTeam)
|
||||
{
|
||||
if (GameMain.Config.RecentlyEncounteredCreatures.Contains(closestEnemy.SpeciesName))
|
||||
if (character.AIController.SelectedAiTarget == null)
|
||||
{
|
||||
character.Speak(TextManager.Get("DialogNewTargetSpotted"), null, 0.0f, "newtargetspotted", 30.0f);
|
||||
if (GameMain.Config.RecentlyEncounteredCreatures.Contains(closestEnemy.SpeciesName))
|
||||
{
|
||||
character.Speak(TextManager.Get("DialogNewTargetSpotted"), null, 0.0f, "newtargetspotted", 30.0f);
|
||||
}
|
||||
else if (GameMain.Config.EncounteredCreatures.Any(name => name.Equals(closestEnemy.SpeciesName, StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
character.Speak(TextManager.GetWithVariable("DialogIdentifiedTargetSpotted", "[speciesname]", closestEnemy.DisplayName), null, 0.0f, "identifiedtargetspotted", 30.0f);
|
||||
}
|
||||
else
|
||||
{
|
||||
character.Speak(TextManager.Get("DialogUnidentifiedTargetSpotted"), null, 0.0f, "unidentifiedtargetspotted", 5.0f);
|
||||
}
|
||||
}
|
||||
else if (GameMain.Config.EncounteredCreatures.Any(name => name.Equals(closestEnemy.SpeciesName, StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
character.Speak(TextManager.GetWithVariable("DialogIdentifiedTargetSpotted", "[speciesname]", closestEnemy.DisplayName), null, 0.0f, "identifiedtargetspotted", 30.0f);
|
||||
}
|
||||
else
|
||||
else if (GameMain.Config.EncounteredCreatures.None(name => name.Equals(closestEnemy.SpeciesName, StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
character.Speak(TextManager.Get("DialogUnidentifiedTargetSpotted"), null, 0.0f, "unidentifiedtargetspotted", 5.0f);
|
||||
}
|
||||
character.AddEncounter(closestEnemy);
|
||||
}
|
||||
else if (GameMain.Config.EncounteredCreatures.None(name => name.Equals(closestEnemy.SpeciesName, StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
character.Speak(TextManager.Get("DialogUnidentifiedTargetSpotted"), null, 0.0f, "unidentifiedtargetspotted", 5.0f);
|
||||
}
|
||||
character.AddEncounter(closestEnemy);
|
||||
character.AIController.SelectTarget(closestEnemy.AiTarget);
|
||||
}
|
||||
else if (closestEnemy == null)
|
||||
else if (closestEnemy == null && character.IsOnPlayerTeam)
|
||||
{
|
||||
character.Speak(TextManager.Get("DialogIceSpireSpotted"), null, 0.0f, "icespirespotted", 60.0f);
|
||||
}
|
||||
@@ -1037,20 +1084,24 @@ namespace Barotrauma.Items.Components
|
||||
return false;
|
||||
}
|
||||
}
|
||||
character.Speak(TextManager.Get("DialogFireTurret"), null, 0.0f, "fireturret", 10.0f);
|
||||
if (character.IsOnPlayerTeam)
|
||||
{
|
||||
character.Speak(TextManager.Get("DialogFireTurret"), null, 0.0f, "fireturret", 10.0f);
|
||||
}
|
||||
character.SetInput(InputType.Shoot, true, true);
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool CheckTurretAngle(Vector2 target)
|
||||
private bool CheckTurretAngle(float angle)
|
||||
{
|
||||
float angle = -MathUtils.VectorToAngle(target - item.WorldPosition);
|
||||
float midRotation = (minRotation + maxRotation) / 2.0f;
|
||||
while (midRotation - angle < -MathHelper.Pi) { angle -= MathHelper.TwoPi; }
|
||||
while (midRotation - angle > MathHelper.Pi) { angle += MathHelper.TwoPi; }
|
||||
return angle > minRotation && angle < maxRotation;
|
||||
return angle >= minRotation && angle <= maxRotation;
|
||||
}
|
||||
|
||||
private bool CheckTurretAngle(Vector2 target) => CheckTurretAngle(-MathUtils.VectorToAngle(target - item.WorldPosition));
|
||||
|
||||
protected override void RemoveComponentSpecific()
|
||||
{
|
||||
base.RemoveComponentSpecific();
|
||||
@@ -1110,8 +1161,6 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
public override void FlipX(bool relativeToSub)
|
||||
{
|
||||
BaseRotation = MathHelper.ToDegrees(MathUtils.WrapAngleTwoPi(MathHelper.ToRadians(-BaseRotation)));
|
||||
|
||||
minRotation = MathHelper.Pi - minRotation;
|
||||
maxRotation = MathHelper.Pi - maxRotation;
|
||||
|
||||
@@ -1152,12 +1201,13 @@ namespace Barotrauma.Items.Components
|
||||
UpdateTransformedBarrelPos();
|
||||
}
|
||||
|
||||
public override void ReceiveSignal(int stepsTaken, string signal, Connection connection, Item source, Character sender, float power, float signalStrength = 1.0f)
|
||||
public override void ReceiveSignal(Signal signal, Connection connection)
|
||||
{
|
||||
Character sender = signal.sender;
|
||||
switch (connection.Name)
|
||||
{
|
||||
case "position_in":
|
||||
if (float.TryParse(signal, NumberStyles.Float, CultureInfo.InvariantCulture, out float newRotation))
|
||||
if (float.TryParse(signal.value, NumberStyles.Float, CultureInfo.InvariantCulture, out float newRotation))
|
||||
{
|
||||
if (!MathUtils.IsValid(newRotation)) { return; }
|
||||
targetRotation = MathHelper.ToRadians(newRotation);
|
||||
@@ -1167,6 +1217,7 @@ namespace Barotrauma.Items.Components
|
||||
resetUserTimer = 10.0f;
|
||||
break;
|
||||
case "trigger_in":
|
||||
if (signal.value == "0") { return; }
|
||||
item.Use((float)Timing.Step, sender);
|
||||
user = sender;
|
||||
resetUserTimer = 10.0f;
|
||||
@@ -1178,7 +1229,7 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
break;
|
||||
case "toggle_light":
|
||||
if (lightComponent != null && signal != "0")
|
||||
if (lightComponent != null && signal.value != "0")
|
||||
{
|
||||
lightComponent.IsOn = !lightComponent.IsOn;
|
||||
}
|
||||
@@ -1186,7 +1237,7 @@ namespace Barotrauma.Items.Components
|
||||
case "set_light":
|
||||
if (lightComponent != null)
|
||||
{
|
||||
lightComponent.IsOn = signal != "0";
|
||||
lightComponent.IsOn = signal.value != "0";
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user