Build 0.18.0.0

This commit is contained in:
Markus Isberg
2022-05-13 00:55:52 +09:00
parent 15d18e6ff6
commit 7547a9b78a
218 changed files with 3881 additions and 2192 deletions
@@ -99,8 +99,8 @@ namespace Barotrauma.Items.Components
{
if (!docked && value)
{
if (DockingTarget == null) AttemptDock();
if (DockingTarget == null) return;
if (DockingTarget == null) { AttemptDock(); }
if (DockingTarget == null) { return; }
docked = true;
}
@@ -126,6 +126,14 @@ namespace Barotrauma.Items.Components
/// </summary>
public event Action OnUnDocked;
private bool outpostAutoDockingPromptShown;
enum AllowOutpostAutoDocking
{
Ask, Yes, No
}
private AllowOutpostAutoDocking allowOutpostAutoDocking = AllowOutpostAutoDocking.Ask;
public DockingPort(Item item, ContentXElement element)
: base(item, element)
{
@@ -622,7 +630,8 @@ namespace Barotrauma.Items.Components
{
bodies[i + j * 2] = GameMain.World.CreateEdge(
ConvertUnits.ToSimUnits(new Vector2(hullRects[i].X, hullRects[i].Y - hullRects[i].Height * j)),
ConvertUnits.ToSimUnits(new Vector2(hullRects[i].Right, hullRects[i].Y - hullRects[i].Height * j)));
ConvertUnits.ToSimUnits(new Vector2(hullRects[i].Right, hullRects[i].Y - hullRects[i].Height * j)),
BodyType.Static);
}
}
@@ -632,7 +641,9 @@ namespace Barotrauma.Items.Components
ConvertUnits.ToSimUnits(hullRects[0].Width + hullRects[1].Width),
ConvertUnits.ToSimUnits(hullRects[0].Height),
density: 0.0f,
offset: ConvertUnits.ToSimUnits(new Vector2(hullRects[0].Right, hullRects[0].Y - hullRects[0].Height / 2) - hulls[0].Submarine.HiddenSubPosition));
offset: ConvertUnits.ToSimUnits(new Vector2(hullRects[0].Right, hullRects[0].Y - hullRects[0].Height / 2) - hulls[0].Submarine.HiddenSubPosition),
Physics.CollisionWall,
Physics.CollisionCharacter | Physics.CollisionItem | Physics.CollisionCharacter | Physics.CollisionItemBlocking | Physics.CollisionProjectile);
outsideBlocker.UserData = this;
}
@@ -742,7 +753,8 @@ namespace Barotrauma.Items.Components
{
bodies[i + j * 2] = GameMain.World.CreateEdge(
ConvertUnits.ToSimUnits(new Vector2(hullRects[i].X + hullRects[i].Width * j, hullRects[i].Y)),
ConvertUnits.ToSimUnits(new Vector2(hullRects[i].X + hullRects[i].Width * j, hullRects[i].Y - hullRects[i].Height)));
ConvertUnits.ToSimUnits(new Vector2(hullRects[i].X + hullRects[i].Width * j, hullRects[i].Y - hullRects[i].Height)),
BodyType.Static);
}
}
@@ -752,7 +764,9 @@ namespace Barotrauma.Items.Components
ConvertUnits.ToSimUnits(hullRects[0].Width),
ConvertUnits.ToSimUnits(hullRects[0].Height + hullRects[1].Height),
density: 0.0f,
offset: ConvertUnits.ToSimUnits(new Vector2(hullRects[0].Center.X, hullRects[0].Y) - hulls[0].Submarine.HiddenSubPosition));
offset: ConvertUnits.ToSimUnits(new Vector2(hullRects[0].Center.X, hullRects[0].Y) - hulls[0].Submarine.HiddenSubPosition),
Physics.CollisionWall,
Physics.CollisionCharacter | Physics.CollisionItem | Physics.CollisionCharacter | Physics.CollisionItemBlocking | Physics.CollisionProjectile);
outsideBlocker.UserData = this;
}
@@ -778,8 +792,6 @@ namespace Barotrauma.Items.Components
if (body == null) { continue; }
body.BodyType = BodyType.Static;
body.Friction = 0.5f;
body.CollisionCategories = Physics.CollisionWall;
}
}
@@ -947,7 +959,7 @@ namespace Barotrauma.Items.Components
{
foreach (Body body in bodies)
{
if (body == null) continue;
if (body == null) { continue; }
GameMain.World.Remove(body);
}
bodies = null;
@@ -961,6 +973,9 @@ namespace Barotrauma.Items.Components
{
item.CreateServerEvent(this);
}
#elif CLIENT
autodockingVerification?.Close();
autodockingVerification = null;
#endif
OnUnDocked?.Invoke();
OnUnDocked = null;
@@ -1140,27 +1155,86 @@ namespace Barotrauma.Items.Components
public override void ReceiveSignal(Signal signal, Connection connection)
{
if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsClient) { return; }
#if CLIENT
if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsClient &&
!(GameMain.GameSession?.Campaign?.AllowedToManageCampaign(ClientPermissions.ManageMap) ?? false))
{
return;
}
#endif
if (dockingCooldown > 0.0f) { return; }
bool wasDocked = docked;
DockingPort prevDockingTarget = DockingTarget;
bool newDockedState = wasDocked;
switch (connection.Name)
{
case "toggle":
if (signal.value != "0")
{
Docked = !docked;
newDockedState = !docked;
}
break;
case "set_active":
case "set_state":
Docked = signal.value != "0";
newDockedState = signal.value != "0";
break;
}
if (newDockedState != wasDocked)
{
bool tryingToToggleOutpostDocking = docked ?
DockingTarget?.Item?.Submarine?.Info?.IsOutpost ?? false :
FindAdjacentPort()?.Item?.Submarine?.Info?.IsOutpost ?? false;
//trying to dock/undock from an outpost and the signal was sent by some automated system instead of a character
// -> ask if the player really wants to dock/undock to prevent a softlock if someone's wired the docking port
// in a way that makes always makes it dock/undock immediately at the start of the roun
if (tryingToToggleOutpostDocking && signal.sender == null)
{
if (allowOutpostAutoDocking == AllowOutpostAutoDocking.Ask)
{
#if CLIENT
if (!outpostAutoDockingPromptShown)
{
autodockingVerification = new GUIMessageBox(string.Empty,
TextManager.Get(newDockedState ? "autodockverification" : "autoundockverification"),
new LocalizedString[] { TextManager.Get("Yes"), TextManager.Get("No") });
autodockingVerification.Buttons[0].OnClicked += (btn, userdata) =>
{
autodockingVerification?.Close();
autodockingVerification = null;
if (item.Removed || GameMain.Client == null) { return false; }
allowOutpostAutoDocking = AllowOutpostAutoDocking.Yes;
item.CreateClientEvent(this);
return true;
};
autodockingVerification.Buttons[1].OnClicked += (btn, userdata) =>
{
autodockingVerification?.Close();
autodockingVerification = null;
if (item.Removed || GameMain.Client == null) { return false; }
allowOutpostAutoDocking = AllowOutpostAutoDocking.No;
item.CreateClientEvent(this);
return true;
};
}
#endif
outpostAutoDockingPromptShown = true;
return;
}
else if (allowOutpostAutoDocking == AllowOutpostAutoDocking.No)
{
return;
}
}
if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsClient) { return; }
Docked = newDockedState;
}
#if SERVER
if (signal.sender != null && docked != wasDocked)
{
@@ -241,12 +241,14 @@ namespace Barotrauma.Items.Components
Body = new PhysicsBody(
ConvertUnits.ToSimUnits(Math.Max(doorRect.Width, 1)),
ConvertUnits.ToSimUnits(Math.Max(doorRect.Height, 1)),
0.0f,
1.5f)
radius: 0.0f,
density: 1.5f,
BodyType.Static,
Physics.CollisionWall,
Physics.CollisionCharacter | Physics.CollisionItem | Physics.CollisionCharacter | Physics.CollisionItemBlocking | Physics.CollisionProjectile,
findNewContacts: false)
{
UserData = item,
CollisionCategories = Physics.CollisionWall,
BodyType = BodyType.Static,
Friction = 0.5f
};
Body.SetTransformIgnoreContacts(
@@ -258,11 +260,16 @@ namespace Barotrauma.Items.Components
}
}
public override void Move(Vector2 amount)
public override void Move(Vector2 amount, bool ignoreContacts = false)
{
base.Move(amount);
Body?.SetTransform(Body.SimPosition + ConvertUnits.ToSimUnits(amount), 0.0f);
if (ignoreContacts)
{
Body?.SetTransformIgnoreContacts(Body.SimPosition + ConvertUnits.ToSimUnits(amount), 0.0f);
}
else
{
Body?.SetTransform(Body.SimPosition + ConvertUnits.ToSimUnits(amount), 0.0f);
}
#if CLIENT
UpdateConvexHulls();
@@ -164,6 +164,8 @@ namespace Barotrauma.Items.Components
public bool SwingWhenAiming { get; set; }
[Editable, Serialize(false, IsPropertySaveable.No, description: "Should the item swing around when it's being used (for example, when firing a weapon or a welding tool).")]
public bool SwingWhenUsing { get; set; }
[Editable, Serialize(false, IsPropertySaveable.No)]
public bool DisableHeadRotation { get; set; }
[ConditionallyEditable(ConditionallyEditable.ConditionType.Attachable, MinValueFloat = 0.0f, MaxValueFloat = 0.999f, DecimalCount = 3), Serialize(0.55f, IsPropertySaveable.No, description: "Sprite depth that's used when the item is NOT attached to a wall.")]
public float SpriteDepthWhenDropped
@@ -180,11 +182,12 @@ namespace Barotrauma.Items.Components
Pusher = null;
if (element.GetAttributeBool("blocksplayers", false))
{
Pusher = new PhysicsBody(item.body.width, item.body.height, item.body.radius, item.body.Density)
Pusher = new PhysicsBody(item.body.width, item.body.height, item.body.radius,
item.body.Density,
BodyType.Dynamic,
Physics.CollisionItemBlocking,
Physics.CollisionCharacter | Physics.CollisionProjectile)
{
BodyType = BodyType.Dynamic,
CollidesWith = Physics.CollisionCharacter | Physics.CollisionProjectile,
CollisionCategories = Physics.CollisionItemBlocking,
Enabled = false,
UserData = this
};
@@ -79,11 +79,18 @@ namespace Barotrauma.Items.Components
IsActive = true;
}
public override void Move(Vector2 amount)
public override void Move(Vector2 amount, bool ignoreContacts = false)
{
if (trigger != null && amount.LengthSquared() > 0.00001f)
{
trigger.SetTransform(item.SimPosition, 0.0f);
if (ignoreContacts)
{
trigger.SetTransformIgnoreContacts(item.SimPosition, 0.0f);
}
else
{
trigger.SetTransform(item.SimPosition, 0.0f);
}
}
}
@@ -119,17 +126,19 @@ namespace Barotrauma.Items.Components
}
var body = item.body ?? holdable.Body;
if (body != null)
{
trigger = new PhysicsBody(body.width, body.height, body.radius, body.Density)
trigger = new PhysicsBody(body.width, body.height, body.radius,
body.Density,
BodyType.Static,
Physics.CollisionWall,
Physics.CollisionNone,
findNewContacts: false)
{
UserData = item
};
trigger.FarseerBody.SetIsSensor(true);
trigger.FarseerBody.BodyType = BodyType.Static;
trigger.FarseerBody.CollisionCategories = Physics.CollisionWall;
trigger.FarseerBody.CollidesWith = Physics.CollisionNone;
}
}
@@ -111,8 +111,9 @@ namespace Barotrauma.Items.Components
ActivateNearbySleepingCharacters();
reloadTimer = reload;
reloadTimer /= (1f + character.GetStatValue(StatTypes.MeleeAttackSpeed));
reloadTimer /= (1f + item.GetQualityModifier(Quality.StatType.StrikingSpeedMultiplier));
reloadTimer /= 1f + character.GetStatValue(StatTypes.MeleeAttackSpeed);
reloadTimer /= 1f + item.GetQualityModifier(Quality.StatType.StrikingSpeedMultiplier);
character.AnimController.LockFlippingUntil = (float)Timing.TotalTime + reloadTimer;
item.body.FarseerBody.CollisionCategories = Physics.CollisionProjectile;
item.body.FarseerBody.CollidesWith = Physics.CollisionCharacter | Physics.CollisionWall | Physics.CollisionItemBlocking;
@@ -216,6 +217,10 @@ namespace Barotrauma.Items.Components
{
hitPos = MathUtils.WrapAnglePi(Math.Min(hitPos + deltaTime * 3f, MathHelper.PiOver4));
ac.HoldItem(deltaTime, item, handlePos, aimPos, Vector2.Zero, aim: false, hitPos, holdAngle + hitPos, aimMelee: true);
if (ac.InWater)
{
ac.LockFlippingUntil = (float)Timing.TotalTime + Reload;
}
}
else
{
@@ -71,6 +71,7 @@ namespace Barotrauma.Items.Components
//return if someone is already trying to pick the item
if (pickTimer > 0.0f) { return false; }
if (picker == null || picker.Inventory == null) { return false; }
if (!picker.Inventory.AccessibleWhenAlive && !picker.Inventory.AccessibleByOwner) { return false; }
if (PickingTime > 0.0f)
{
@@ -226,7 +227,7 @@ namespace Barotrauma.Items.Components
{
foreach (Connection c in connectionPanel.Connections)
{
foreach (Wire w in c.Wires)
foreach (Wire w in c.Wires.ToArray())
{
if (w == null) continue;
w.Item.Drop(character);
@@ -40,7 +40,7 @@ namespace Barotrauma.Items.Components
public override bool Use(float deltaTime, Character character = null)
{
if (character == null || character.Removed) return false;
if (character == null || character.Removed) { return false; }
if (!character.IsKeyDown(InputType.Aim) || character.Stun > 0.0f) { return false; }
IsActive = true;
@@ -55,12 +55,11 @@ namespace Barotrauma.Items.Components
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 dir = character.CursorPosition - character.Position;
if (!MathUtils.IsValid(dir)) { return true; }
float length = 200;
dir = dir.ClampLength(length) / length;
Vector2 propulsion = dir * Force * character.PropulsionSpeedMultiplier;
if (character.AnimController.InWater && Force > 0.0f) { character.AnimController.TargetMovement = dir; }
foreach (Limb limb in character.AnimController.Limbs)
@@ -416,7 +416,7 @@ namespace Barotrauma.Items.Components
}
}
public virtual void Move(Vector2 amount) { }
public virtual void Move(Vector2 amount, bool ignoreContacts = false) { }
/// <summary>a Character has picked the item</summary>
public virtual bool Pick(Character picker)
@@ -315,7 +315,7 @@ namespace Barotrauma.Items.Components
IsActive = activeContainedItems.Count > 0 || Inventory.AllItems.Any(it => it.body != null);
}
public override void Move(Vector2 amount)
public override void Move(Vector2 amount, bool ignoreContacts = false)
{
SetContainedItemPositions();
}
@@ -751,7 +751,11 @@ namespace Barotrauma.Items.Components
return;
}
#endif
Inventory.AllItemsMod.ForEach(it => it.Drop(null));
//if we're unloading the whole sub, no need to drop anything (everything's going to be removed anyway)
if (!Submarine.Unloading)
{
Inventory.AllItemsMod.ForEach(it => it.Drop(null));
}
}
public override void Load(ContentXElement componentElement, bool usePrefabValues, IdRemap idRemap)
@@ -462,19 +462,8 @@ namespace Barotrauma.Items.Components
{
dir = dir == Direction.Left ? Direction.Right : Direction.Left;
}
userPos.X = -UserPos.X;
for (int i = 0; i < limbPositions.Count; i++)
{
float diff = (item.Rect.X + limbPositions[i].Position.X * item.Scale) - item.Rect.Center.X;
Vector2 flippedPos =
new Vector2(
(item.Rect.Center.X - diff - item.Rect.X) / item.Scale,
limbPositions[i].Position.Y);
limbPositions[i] = new LimbPos(limbPositions[i].LimbType, flippedPos, limbPositions[i].AllowUsingLimb);
}
userPos.X = -UserPos.X;
FlipLimbPositions();
}
public override void FlipY(bool relativeToSub)
@@ -519,6 +508,11 @@ namespace Barotrauma.Items.Components
{
if (Screen.Selected == GameMain.SubEditorScreen)
{
if (item.FlippedX)
{
FlipLimbPositions();
}
// Don't save flipped positions.
foreach (var limbPos in limbPositions)
{
element.Add(new XElement("limbposition",
@@ -526,6 +520,10 @@ namespace Barotrauma.Items.Components
new XAttribute("position", XMLExtensions.Vector2ToString(limbPos.Position)),
new XAttribute("allowusinglimb", limbPos.AllowUsingLimb)));
}
if (item.FlippedX)
{
FlipLimbPositions();
}
}
return element;
}
@@ -558,5 +556,29 @@ namespace Barotrauma.Items.Components
}
}
}
private void FlipLimbPositions()
{
for (int i = 0; i < limbPositions.Count; i++)
{
float diff = (item.Rect.X + limbPositions[i].Position.X * item.Scale) - item.Rect.Center.X;
Vector2 flippedPos =
new Vector2(
(item.Rect.Center.X - diff - item.Rect.X) / item.Scale,
limbPositions[i].Position.Y);
limbPositions[i] = new LimbPos(limbPositions[i].LimbType, flippedPos, limbPositions[i].AllowUsingLimb);
}
}
public override void Reset()
{
base.Reset();
LoadLimbPositions(originalElement);
if (item.FlippedX)
{
FlipLimbPositions();
}
}
}
}
@@ -150,7 +150,7 @@ namespace Barotrauma.Items.Components
{
if (powerOut?.Grid != null) { return powerOut.Grid.Voltage; }
}
return voltage;
return currPowerConsumption <= 0.0f ? 1.0f : voltage;
}
set
{
@@ -231,6 +231,13 @@ namespace Barotrauma.Items.Components
set;
}
[Serialize(false, IsPropertySaveable.No, description:"Enable only if you want to make the projectile ignore collisions with other projectiles when it's shot. Doesn't have any effect, if the item is not set to be damaged by projectiles.")]
public bool IgnoreProjectilesWhileActive
{
get;
set;
}
public Body StickTarget
{
get;
@@ -405,6 +412,10 @@ namespace Barotrauma.Items.Components
item.body.CollisionCategories = Physics.CollisionProjectile;
item.body.CollidesWith = Physics.CollisionCharacter | Physics.CollisionWall | Physics.CollisionLevel | Physics.CollisionItemBlocking;
if (item.Prefab.DamagedByProjectiles && !IgnoreProjectilesWhileActive)
{
item.body.CollidesWith |= Physics.CollisionProjectile;
}
IsActive = true;
@@ -0,0 +1,10 @@
namespace Barotrauma.Items.Components
{
sealed class AndComponent : BooleanOperatorComponent
{
public AndComponent(Item item, ContentXElement element)
: base(item, element) { }
protected override bool GetOutput(int numTrueInputs) => numTrueInputs >= 2;
}
}
@@ -3,7 +3,7 @@ using System.Xml.Linq;
namespace Barotrauma.Items.Components
{
class AndComponent : ItemComponent
abstract class BooleanOperatorComponent : ItemComponent
{
protected string output, falseOutput;
@@ -70,22 +70,25 @@ namespace Barotrauma.Items.Components
}
}
public AndComponent(Item item, ContentXElement element)
public BooleanOperatorComponent(Item item, ContentXElement element)
: base(item, element)
{
timeSinceReceived = new float[] { Math.Max(timeFrame * 2.0f, 0.1f), Math.Max(timeFrame * 2.0f, 0.1f) };
IsActive = true;
}
public override void Update(float deltaTime, Camera cam)
protected abstract bool GetOutput(int numTrueInputs);
public sealed override void Update(float deltaTime, Camera cam)
{
bool state = true;
int receivedInputs = 0;
for (int i = 0; i < timeSinceReceived.Length; i++)
{
if (timeSinceReceived[i] > timeFrame) { state = false; }
if (timeSinceReceived[i] <= timeFrame) { receivedInputs += 1; }
timeSinceReceived[i] += deltaTime;
}
bool state = GetOutput(receivedInputs);
string signalOut = state ? output : falseOutput;
if (string.IsNullOrEmpty(signalOut))
{
@@ -0,0 +1,10 @@
namespace Barotrauma.Items.Components
{
sealed class OrComponent : BooleanOperatorComponent
{
public OrComponent(Item item, ContentXElement element)
: base(item, element) { }
protected override bool GetOutput(int numTrueInputs) => numTrueInputs > 0;
}
}
@@ -0,0 +1,10 @@
namespace Barotrauma.Items.Components
{
sealed class XorComponent : BooleanOperatorComponent
{
public XorComponent(Item item, ContentXElement element)
: base(item, element) { }
protected override bool GetOutput(int numTrueInputs) => numTrueInputs == 1;
}
}
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Xml.Linq;
@@ -19,11 +20,8 @@ namespace Barotrauma.Items.Components
public readonly string Name;
public readonly LocalizedString DisplayName;
private readonly Wire[] wires;
public IEnumerable<Wire> Wires
{
get { return wires; }
}
private readonly HashSet<Wire> wires;
public IReadOnlyCollection<Wire> Wires => wires;
private readonly Item item;
@@ -31,7 +29,7 @@ namespace Barotrauma.Items.Components
public readonly List<StatusEffect> Effects;
public readonly ushort[] wireId;
public readonly List<ushort> LoadedWireIds;
//The grid the connection is a part of
public GridInfo Grid;
@@ -92,7 +90,7 @@ namespace Barotrauma.Items.Components
MaxWires = Math.Max(element.Elements().Count(e => e.Name.ToString().Equals("link", StringComparison.OrdinalIgnoreCase)), MaxWires);
MaxPlayerConnectableWires = element.GetAttributeInt("maxplayerconnectablewires", MaxWires);
wires = new Wire[MaxWires];
wires = new HashSet<Wire>();
IsOutput = element.Name.ToString() == "output";
Name = element.GetAttributeString("name", IsOutput ? "output" : "input");
@@ -150,23 +148,15 @@ namespace Barotrauma.Items.Components
IsPower = Name == "power_in" || Name == "power" || Name == "power_out";
wireId = new ushort[MaxWires];
LoadedWireIds = new List<ushort>();
foreach (var subElement in element.Elements())
{
switch (subElement.Name.ToString().ToLowerInvariant())
{
case "link":
int index = -1;
for (int i = 0; i < MaxWires; i++)
{
if (wireId[i] < 1) { index = i; }
}
if (index == -1) { break; }
int id = subElement.GetAttributeInt("w", 0);
if (id < 0) { id = 0; }
wireId[index] = idRemap.GetOffsetId(id);
if (LoadedWireIds.Count < MaxWires) { LoadedWireIds.Add(idRemap.GetOffsetId(id)); }
break;
case "statuseffect":
@@ -185,138 +175,111 @@ namespace Barotrauma.Items.Components
private void RefreshRecipients()
{
recipients.Clear();
for (int i = 0; i < MaxWires; i++)
foreach (var wire in wires)
{
if (wires[i] == null) continue;
Connection recipient = wires[i].OtherConnection(this);
if (recipient != null) recipients.Add(recipient);
Connection recipient = wire.OtherConnection(this);
if (recipient != null) { recipients.Add(recipient); }
}
recipientsDirty = false;
}
public int FindEmptyIndex()
{
for (int i = 0; i < MaxWires; i++)
{
if (wires[i] == null) return i;
}
return -1;
}
public int FindWireIndex(Wire wire)
{
for (int i = 0; i < MaxWires; i++)
{
if (wires[i] == wire) return i;
}
return -1;
}
public int FindWireIndex(Item wireItem)
{
for (int i = 0; i < MaxWires; i++)
{
if (wires[i] == null && wireItem == null) return i;
if (wires[i] != null && wires[i].Item == wireItem) return i;
}
return -1;
}
public Wire FindWireByItem(Item it)
=> Wires.FirstOrDefault(w => w.Item == it);
public bool WireSlotsAvailable()
=> wires.Count < MaxWires;
public bool TryAddLink(Wire wire)
{
for (int i = 0; i < MaxWires; i++)
if (wire is null
|| wires.Contains(wire)
|| !WireSlotsAvailable())
{
if (wires[i] == null)
{
SetWire(i, wire);
return true;
}
return false;
}
return false;
wires.Add(wire);
return true;
}
public void SetWire(int index, Wire wire)
public void DisconnectWire(Wire wire)
{
Wire previousWire = wires[index];
if (wire != previousWire && previousWire != null)
{
var otherConnection = previousWire.OtherConnection(this);
if (otherConnection != null)
{
//Change the connection grids or flag them for updating
if (IsPower && otherConnection.IsPower && Grid != null)
{
//Check if both connections belong to a larger grid
if (otherConnection.recipients.Count > 1 && recipients.Count > 1)
{
Powered.ChangedConnections.Add(otherConnection);
Powered.ChangedConnections.Add(this);
}
else if (recipients.Count > 1)
{
//This wire was the only one at the other grid
otherConnection.Grid?.RemoveConnection(otherConnection);
otherConnection.Grid = null;
}
else if (otherConnection.recipients.Count > 1)
{
Grid?.RemoveConnection(this);
Grid = null;
}
else if (Grid.Connections.Count == 2)
{
//Delete the grid as these were the only 2 devices
Powered.Grids.Remove(Grid.ID);
Grid = null;
otherConnection.Grid = null;
}
}
otherConnection.recipientsDirty = true;
}
}
if (wire == null || !wires.Contains(wire)) { return; }
wires[index] = wire;
var prevOtherConnection = wire.OtherConnection(this);
if (prevOtherConnection != null)
{
//Change the connection grids or flag them for updating
if (IsPower && prevOtherConnection.IsPower && Grid != null)
{
//Check if both connections belong to a larger grid
if (prevOtherConnection.recipients.Count > 1 && recipients.Count > 1)
{
Powered.ChangedConnections.Add(prevOtherConnection);
Powered.ChangedConnections.Add(this);
}
else if (recipients.Count > 1)
{
//This wire was the only one at the other grid
prevOtherConnection.Grid?.RemoveConnection(prevOtherConnection);
prevOtherConnection.Grid = null;
}
else if (prevOtherConnection.recipients.Count > 1)
{
Grid?.RemoveConnection(this);
Grid = null;
}
else if (Grid.Connections.Count == 2)
{
//Delete the grid as these were the only 2 devices
Powered.Grids.Remove(Grid.ID);
Grid = null;
prevOtherConnection.Grid = null;
}
}
prevOtherConnection.recipientsDirty = true;
}
wires.Remove(wire);
recipientsDirty = true;
if (wire != null)
}
public void ConnectWire(Wire wire)
{
if (wire == null || !TryAddLink(wire)) { return; }
ConnectionPanel.DisconnectedWires.Remove(wire);
var otherConnection = wire.OtherConnection(this);
if (otherConnection != null)
{
ConnectionPanel.DisconnectedWires.Remove(wire);
var otherConnection = wire.OtherConnection(this);
if (otherConnection != null)
//Set the other connection grid if a grid exists already
if (Powered.ValidPowerConnection(this, otherConnection))
{
//Set the other connection grid if a grid exists already
if (Powered.ValidPowerConnection(this, otherConnection))
if (Grid == null && otherConnection.Grid != null)
{
if (Grid == null && otherConnection.Grid != null)
{
otherConnection.Grid.AddConnection(this);
Grid = otherConnection.Grid;
}
else if (Grid != null && otherConnection.Grid == null)
{
Grid.AddConnection(otherConnection);
otherConnection.Grid = Grid;
}
else
{
//Flag change so that proper grids can be formed
Powered.ChangedConnections.Add(this);
Powered.ChangedConnections.Add(otherConnection);
}
otherConnection.Grid.AddConnection(this);
Grid = otherConnection.Grid;
}
else if (Grid != null && otherConnection.Grid == null)
{
Grid.AddConnection(otherConnection);
otherConnection.Grid = Grid;
}
else
{
//Flag change so that proper grids can be formed
Powered.ChangedConnections.Add(this);
Powered.ChangedConnections.Add(otherConnection);
}
otherConnection.recipientsDirty = true;
}
otherConnection.recipientsDirty = true;
}
recipientsDirty = true;
}
public void SendSignal(Signal signal)
{
for (int i = 0; i < MaxWires; i++)
foreach (var wire in wires)
{
if (wires[i] == null) { continue; }
Connection recipient = wires[i].OtherConnection(this);
Connection recipient = wire.OtherConnection(this);
if (recipient == null) { continue; }
if (recipient.item == this.item || signal.source?.LastSentSignalRecipients.LastOrDefault() == recipient) { continue; }
@@ -350,35 +313,32 @@ namespace Barotrauma.Items.Components
}
}
for (int i = 0; i < MaxWires; i++)
foreach (var wire in wires)
{
if (wires[i] == null) continue;
wires[i].RemoveConnection(this);
wires[i] = null;
wire.RemoveConnection(this);
recipientsDirty = true;
}
wires.Clear();
}
public void ConnectLinked()
public void InitializeFromLoaded()
{
if (wireId == null) return;
if (LoadedWireIds.Count == 0) { return; }
for (int i = 0; i < MaxWires; i++)
for (int i = 0; i < LoadedWireIds.Count; i++)
{
if (wireId[i] == 0) { continue; }
if (!(Entity.FindEntityByID(LoadedWireIds[i]) is Item wireItem)) { continue; }
if (!(Entity.FindEntityByID(wireId[i]) is Item wireItem)) { continue; }
wires[i] = wireItem.GetComponent<Wire>();
recipientsDirty = true;
if (wires[i] != null)
var wire = wireItem.GetComponent<Wire>();
if (wire != null && TryAddLink(wire))
{
if (wires[i].Item.body != null) wires[i].Item.body.Enabled = false;
wires[i].Connect(this, false, false);
wires[i].FixNodeEnds();
if (wire.Item.body != null) wire.Item.body.Enabled = false;
wire.Connect(this, false, false);
wire.FixNodeEnds();
recipientsDirty = true;
}
}
LoadedWireIds.Clear();
}
@@ -386,19 +346,10 @@ namespace Barotrauma.Items.Components
{
XElement newElement = new XElement(IsOutput ? "output" : "input", new XAttribute("name", Name));
Array.Sort(wires, delegate (Wire wire1, Wire wire2)
foreach (var wire in wires.OrderBy(w => w.Item.ID))
{
if (wire1 == null) return 1;
if (wire2 == null) return -1;
return wire1.Item.ID.CompareTo(wire2.Item.ID);
});
for (int i = 0; i < MaxWires; i++)
{
if (wires[i] == null) continue;
newElement.Add(new XElement("link",
new XAttribute("w", wires[i].Item.ID.ToString())));
new XAttribute("w", wire.Item.ID.ToString())));
}
parentElement.Add(newElement);
@@ -49,7 +49,7 @@ namespace Barotrauma.Items.Components
public bool TemporarilyLocked
{
get { return Level.IsLoadedOutpost && item.GetComponent<DockingPort>() != null; }
get { return Level.IsLoadedOutpost && (item.GetComponent<DockingPort>()?.Docked ?? false); }
}
//connection panels can't be deactivated externally (by signals or status effects)
@@ -99,7 +99,7 @@ namespace Barotrauma.Items.Components
{
foreach (Connection c in Connections)
{
c.ConnectLinked();
c.InitializeFromLoaded();
}
if (disconnectedWireIds != null)
@@ -286,25 +286,8 @@ namespace Barotrauma.Items.Components
for (int i = 0; i < loadedConnections.Count && i < Connections.Count; i++)
{
if (loadedConnections[i].wireId.Length == Connections[i].wireId.Length)
{
loadedConnections[i].wireId.CopyTo(Connections[i].wireId, 0);
}
else
{
//backwards compatibility when maximum number of wires has changed
foreach (ushort id in loadedConnections[i].wireId)
{
for (int j = 0; j < Connections[i].wireId.Length; j++)
{
if (Connections[i].wireId[j] == 0)
{
Connections[i].wireId[j] = id;
break;
}
}
}
}
Connections[i].LoadedWireIds.Clear();
Connections[i].LoadedWireIds.AddRange(loadedConnections[i].LoadedWireIds);
}
disconnectedWireIds = element.GetAttributeUshortArray("disconnectedwires", Array.Empty<ushort>()).ToList();
@@ -361,10 +344,8 @@ namespace Barotrauma.Items.Components
DisconnectedWires.Clear();
foreach (Connection c in Connections)
{
foreach (Wire wire in c.Wires)
foreach (Wire wire in c.Wires.ToArray())
{
if (wire == null) { continue; }
if (wire.OtherConnection(c) == null) //wire not connected to anything else
{
#if CLIENT
@@ -408,13 +389,14 @@ namespace Barotrauma.Items.Components
foreach (Connection connection in Connections)
{
msg.WriteVariableUInt32((uint)connection.Wires.Count);
foreach (Wire wire in connection.Wires)
{
msg.Write(wire?.Item == null ? (ushort)0 : wire.Item.ID);
}
}
msg.Write((ushort)DisconnectedWires.Count());
msg.Write((ushort)DisconnectedWires.Count);
foreach (Wire disconnectedWire in DisconnectedWires)
{
msg.Write(disconnectedWire.Item.ID);
@@ -187,7 +187,7 @@ namespace Barotrauma.Items.Components
set;
}
public override void Move(Vector2 amount)
public override void Move(Vector2 amount, bool ignoreContacts = false)
{
#if CLIENT
Light.Position += amount;
@@ -1,33 +0,0 @@
using System.Xml.Linq;
namespace Barotrauma.Items.Components
{
class OrComponent : AndComponent
{
public OrComponent(Item item, ContentXElement element)
: base(item, element)
{
IsActive = true;
}
public override void Update(float deltaTime, Camera cam)
{
bool state = false;
for (int i = 0; i < timeSinceReceived.Length; i++)
{
if (timeSinceReceived[i] <= timeFrame) { state = true; }
timeSinceReceived[i] += deltaTime;
}
string signalOut = state ? output : falseOutput;
if (string.IsNullOrEmpty(signalOut))
{
//deactivate the component if state is false and there's no false output (will be woken up by non-zero signals in ReceiveSignal)
if (!state) { IsActive = false; }
return;
}
item.SendSignal(new Signal(signalOut, sender: signalSender[0] ?? signalSender[1]), "signal_out");
}
}
}
@@ -135,7 +135,7 @@ namespace Barotrauma.Items.Components
// = no point in receiving
if (!LinkToChat)
{
if (signalOutConnection == null || !signalOutConnection.Wires.Any(w => w != null))
if (signalOutConnection == null || signalOutConnection.Wires.Count <= 0)
{
return false;
}
@@ -143,12 +143,11 @@ namespace Barotrauma.Items.Components
{
if (connections[i] == null || connections[i].Item != item) { continue; }
foreach (Wire wire in connections[i].Wires)
if (connections[i].Wires.Contains(this))
{
if (wire != this) continue;
SetConnectedDirty();
connections[i].SetWire(connections[i].FindWireIndex(wire), null);
connections[i].DisconnectWire(this);
}
connections[i] = null;
@@ -597,15 +596,16 @@ namespace Barotrauma.Items.Components
for (int i = 0; i < 2; i++)
{
if (connections[i] == null) { continue; }
int wireIndex = connections[i].FindWireIndex(item);
if (wireIndex == -1) { continue; }
var wire = connections[i].FindWireByItem(item);
if (wire is null) { continue; }
#if SERVER
if (!connections[i].Item.Removed && (!connections[i].Item.Submarine?.Loading ?? true) && (!Level.Loaded?.Generating ?? true))
{
connections[i].Item.CreateServerEvent(connections[i].Item.GetComponent<ConnectionPanel>());
}
#endif
connections[i].SetWire(wireIndex, null);
connections[i].DisconnectWire(wire);
connections[i] = null;
}
@@ -1,34 +0,0 @@
using System.Xml.Linq;
namespace Barotrauma.Items.Components
{
class XorComponent : AndComponent
{
public XorComponent(Item item, ContentXElement element)
: base(item, element)
{
IsActive = true;
}
public override void Update(float deltaTime, Camera cam)
{
int receivedInputs = 0;
for (int i = 0; i < timeSinceReceived.Length; i++)
{
if (timeSinceReceived[i] <= timeFrame) { receivedInputs += 1; }
timeSinceReceived[i] += deltaTime;
}
bool state = receivedInputs == 1;
string signalOut = state ? output : falseOutput;
if (string.IsNullOrEmpty(signalOut))
{
//deactivate the component if state is false and there's no false output (will be woken up by non-zero signals in ReceiveSignal)
if (!state) { IsActive = false; }
return;
}
item.SendSignal(new Signal(signalOut, sender: signalSender[0] ?? signalSender[1]), "signal_out");
}
}
}
@@ -3,9 +3,8 @@ using FarseerPhysics.Dynamics;
using FarseerPhysics.Dynamics.Contacts;
using Microsoft.Xna.Framework;
using System;
using System.Linq;
using System.Collections.Generic;
using System.Xml.Linq;
using System.Linq;
namespace Barotrauma.Items.Components
{
@@ -93,13 +92,11 @@ namespace Barotrauma.Items.Components
base.OnItemLoaded();
float radiusAttribute = originalElement.GetAttributeFloat("radius", 10.0f);
Radius = ConvertUnits.ToSimUnits(radiusAttribute * item.Scale);
PhysicsBody = new PhysicsBody(0.0f, 0.0f, Radius, 1.5f)
PhysicsBody = new PhysicsBody(0.0f, 0.0f, Radius, 1.5f, BodyType.Static, Physics.CollisionWall, LevelTrigger.GetCollisionCategories(triggeredBy))
{
BodyType = BodyType.Static,
CollidesWith = LevelTrigger.GetCollisionCategories(triggeredBy),
CollisionCategories = Physics.CollisionWall,
UserData = item
};
PhysicsBody.SetTransformIgnoreContacts(item.SimPosition, 0.0f);
PhysicsBody.FarseerBody.SetIsSensor(true);
PhysicsBody.FarseerBody.OnCollision += OnCollision;
PhysicsBody.FarseerBody.OnSeparation += OnSeparation;
@@ -215,12 +212,18 @@ namespace Barotrauma.Items.Components
body.ApplyForce(force);
}
public override void Move(Vector2 amount)
public override void Move(Vector2 amount, bool ignoreContacts = false)
{
base.Move(amount);
if (PhysicsBody != null)
{
PhysicsBody.SetTransform(PhysicsBody.SimPosition + ConvertUnits.ToSimUnits(amount), 0.0f);
if (ignoreContacts)
{
PhysicsBody.SetTransformIgnoreContacts(PhysicsBody.SimPosition + ConvertUnits.ToSimUnits(amount), 0.0f);
}
else
{
PhysicsBody.SetTransform(PhysicsBody.SimPosition + ConvertUnits.ToSimUnits(amount), 0.0f);
}
PhysicsBody.Submarine = item.Submarine;
}
}
@@ -661,6 +661,7 @@ namespace Barotrauma.Items.Components
while (neededPower > 0.0001f && batteries.Count > 0)
{
batteries.RemoveAll(b => b.Charge <= 0.0001f || b.MaxOutPut <= 0.0001f);
if (!batteries.Any()) { break; }
float takePower = neededPower / batteries.Count;
takePower = Math.Min(takePower, batteries.Min(b => Math.Min(b.Charge * 3600.0f, b.MaxOutPut)));
foreach (PowerContainer battery in batteries)
@@ -1151,8 +1152,12 @@ namespace Barotrauma.Items.Components
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; }
if (enemy.Submarine != null && enemy.Submarine.TeamID == character.Submarine.TeamID) { continue; }
if (enemy.IsDead || !enemy.Enabled) { continue; }
if (character.Submarine != null)
{
if (enemy.Submarine == character.Submarine) { continue; }
if (enemy.Submarine != null && enemy.Submarine.TeamID == character.Submarine.TeamID) { continue; }
}
// Don't aim monsters that are inside any submarine.
if (!enemy.IsHuman && enemy.CurrentHull != null) { continue; }
if (HumanAIController.IsFriendly(character, enemy)) { continue; }