v0.10.6.2

This commit is contained in:
Joonas Rikkonen
2020-10-29 17:55:26 +02:00
parent 20a69375ca
commit bbf06f0984
255 changed files with 6196 additions and 3096 deletions
@@ -1,6 +1,4 @@
using Barotrauma.Items.Components;
using Barotrauma.Networking;
using Microsoft.Xna.Framework;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -11,7 +9,7 @@ namespace Barotrauma
[Flags]
public enum InvSlotType
{
None = 0, Any = 1, RightHand = 2, LeftHand = 4, Head = 8, InnerClothes = 16, OuterClothes = 32, Headset = 64, Card = 128
None = 0, Any = 1, RightHand = 2, LeftHand = 4, Head = 8, InnerClothes = 16, OuterClothes = 32, Headset = 64, Card = 128, Bag = 256
};
partial class CharacterInventory : Inventory
@@ -24,6 +22,9 @@ namespace Barotrauma
private set;
}
public static readonly List<InvSlotType> anySlot = new List<InvSlotType>() { InvSlotType.Any };
protected bool[] IsEquipped;
public bool AccessibleWhenAlive
@@ -68,7 +69,7 @@ namespace Barotrauma
#if CLIENT
//clients don't create items until the server says so
if (GameMain.Client != null) return;
if (GameMain.Client != null) { return; }
#endif
foreach (XElement subElement in element.Elements())
@@ -76,8 +77,7 @@ namespace Barotrauma
if (!subElement.Name.ToString().Equals("item", StringComparison.OrdinalIgnoreCase)) { continue; }
string itemIdentifier = subElement.GetAttributeString("identifier", "");
ItemPrefab itemPrefab = MapEntityPrefab.Find(null, itemIdentifier) as ItemPrefab;
if (itemPrefab == null)
if (!(MapEntityPrefab.Find(null, itemIdentifier) is ItemPrefab itemPrefab))
{
DebugConsole.ThrowError("Error in character inventory \"" + character.SpeciesName + "\" - item \"" + itemIdentifier + "\" not found.");
continue;
@@ -164,7 +164,7 @@ namespace Barotrauma
#if DEBUG
throw new Exception("Tried to put a removed item (" + item.Name + ") in an inventory");
#else
DebugConsole.ThrowError("Tried to put a removed item (" + item.Name + ") in an inventory.\n" + Environment.StackTrace);
DebugConsole.ThrowError("Tried to put a removed item (" + item.Name + ") in an inventory.\n" + Environment.StackTrace.CleanupStackTrace());
return false;
#endif
}
@@ -284,7 +284,7 @@ namespace Barotrauma
{
if (index < 0 || index >= Items.Length)
{
string errorMsg = "CharacterInventory.TryPutItem failed: index was out of range(" + index + ").\n" + Environment.StackTrace;
string errorMsg = "CharacterInventory.TryPutItem failed: index was out of range(" + index + ").\n" + Environment.StackTrace.CleanupStackTrace();
GameAnalyticsManager.AddErrorEventOnce("CharacterInventory.TryPutItem:IndexOutOfRange", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
return false;
}
@@ -431,7 +431,7 @@ namespace Barotrauma.Items.Components
string errorMsg =
"Attempted to create a door body at an invalid position (item pos: " + item.Position
+ ", item world pos: " + item.WorldPosition
+ ", docking target world pos: " + DockingTarget.Door.Item.WorldPosition + ")\n" + Environment.StackTrace;
+ ", docking target world pos: " + DockingTarget.Door.Item.WorldPosition + ")\n" + Environment.StackTrace.CleanupStackTrace();
DebugConsole.ThrowError(errorMsg);
GameAnalyticsManager.AddErrorEventOnce(
@@ -377,6 +377,8 @@ namespace Barotrauma.Items.Components
private int flowerVariants;
private int leafVariants;
private int[] flowerTiles;
private const int serverHealthUpdateDelay = 10;
private int serverHealthUpdateTimer;
public float Health
{
@@ -469,6 +471,20 @@ namespace Barotrauma.Items.Components
{
Health -= FloodTolerance;
}
#if SERVER
if (FullyGrown)
{
if (serverHealthUpdateTimer > serverHealthUpdateDelay)
{
item.CreateServerEvent(this);
serverHealthUpdateTimer = 0;
}
else
{
serverHealthUpdateTimer++;
}
}
#endif
}
CheckPlantState();
@@ -195,7 +195,9 @@ namespace Barotrauma.Items.Components
}
}
}
}
}
characterUsable = element.GetAttributeBool("characterusable", true);
}
private bool OnPusherCollision(Fixture sender, Fixture other, Contact contact)
@@ -312,7 +314,7 @@ namespace Barotrauma.Items.Components
if (item.Removed)
{
DebugConsole.ThrowError($"Attempted to equip a removed item ({item.Name})\n" + Environment.StackTrace);
DebugConsole.ThrowError($"Attempted to equip a removed item ({item.Name})\n" + Environment.StackTrace.CleanupStackTrace());
return;
}
@@ -416,7 +418,7 @@ namespace Barotrauma.Items.Components
{
if (item.Removed)
{
DebugConsole.ThrowError($"Attempted to pick up a removed item ({item.Name})\n" + Environment.StackTrace);
DebugConsole.ThrowError($"Attempted to pick up a removed item ({item.Name})\n" + Environment.StackTrace.CleanupStackTrace());
return false;
}
@@ -514,9 +516,10 @@ namespace Barotrauma.Items.Components
public override bool Use(float deltaTime, Character character = null)
{
if (!attachable || item.body == null) { return character == null || character.IsKeyDown(InputType.Aim); }
if (!attachable || item.body == null) { return character == null || (character.IsKeyDown(InputType.Aim) && characterUsable); }
if (character != null)
{
if (!characterUsable && !attachable) { return false; }
if (!character.IsKeyDown(InputType.Aim)) { return false; }
if (!CanBeAttached(character)) { return false; }
@@ -104,14 +104,14 @@ namespace Barotrauma.Items.Components
ApplyStatusEffects(ActionType.OnPicked, 1.0f, picker);
#if CLIENT
if (!GameMain.Instance.LoadingScreenOpen && picker == Character.Controlled) GUI.PlayUISound(GUISoundType.PickItem);
if (!GameMain.Instance.LoadingScreenOpen && picker == Character.Controlled) SoundPlayer.PlayUISound(GUISoundType.PickItem);
PlaySound(ActionType.OnPicked, picker);
#endif
return true;
}
#if CLIENT
if (!GameMain.Instance.LoadingScreenOpen && picker == Character.Controlled) GUI.PlayUISound(GUISoundType.PickItemFail);
if (!GameMain.Instance.LoadingScreenOpen && picker == Character.Controlled) SoundPlayer.PlayUISound(GUISoundType.PickItemFail);
#endif
return false;
@@ -248,6 +248,7 @@ namespace Barotrauma.Items.Components
partial void UseProjSpecific(float deltaTime, Vector2 raystart);
private static readonly List<Body> hitBodies = new List<Body>();
private readonly HashSet<Character> hitCharacters = new HashSet<Character>();
private readonly List<FireSource> fireSourcesInRange = new List<FireSource>();
private void Repair(Vector2 rayStart, Vector2 rayEnd, float deltaTime, Character user, float degreeOfSuccess, List<Body> ignoredBodies)
@@ -291,10 +292,14 @@ namespace Barotrauma.Items.Components
return true;
},
allowInsideFixture: true);
hitBodies.Clear();
hitBodies.AddRange(bodies);
lastPickedFraction = Submarine.LastPickedFraction;
Type lastHitType = null;
hitCharacters.Clear();
foreach (Body body in bodies)
foreach (Body body in hitBodies)
{
Type bodyType = body.UserData?.GetType();
if (!RepairThroughWalls && bodyType != null && bodyType != lastHitType)
@@ -372,13 +377,23 @@ namespace Barotrauma.Items.Components
fireSourcesInRange.Add(fs);
}
}
foreach (FireSource fs in hull.FakeFireSources)
{
if (fs.IsInDamageRange(displayPos, 100.0f) && !fireSourcesInRange.Contains(fs))
{
fireSourcesInRange.Add(fs);
}
}
}
foreach (FireSource fs in fireSourcesInRange)
{
fs.Extinguish(deltaTime, ExtinguishAmount);
#if SERVER
GameMain.Server.KarmaManager.OnExtinguishingFire(user, deltaTime);
if (!(fs is DummyFireSource))
{
GameMain.Server.KarmaManager.OnExtinguishingFire(user, deltaTime);
}
#endif
}
}
@@ -562,13 +577,22 @@ namespace Barotrauma.Items.Components
partial void FixItemProjSpecific(Character user, float deltaTime, Item targetItem);
private float sinTime;
private float repairTimer;
private Gap previousGap;
private readonly float repairTimeOut = 5;
public override bool AIOperate(float deltaTime, Character character, AIObjectiveOperateItem objective)
{
if (!(objective.OperateTarget is Gap leak)) { return true; }
if (leak.Submarine == null) { return true; }
if (leak != previousGap)
{
sinTime = 0;
repairTimer = 0;
previousGap = leak;
}
Vector2 fromCharacterToLeak = leak.WorldPosition - character.WorldPosition;
float dist = fromCharacterToLeak.Length();
float reach = Range + ConvertUnits.ToDisplayUnits(((HumanoidAnimController)character.AnimController).ArmLength);
float reach = AIObjectiveFixLeak.CalculateReach(this, character);
//too far away -> consider this done and hope the AI is smart enough to move closer
if (dist > reach * 2) { return true; }
@@ -626,7 +650,11 @@ namespace Barotrauma.Items.Components
else if (dist < reach * 2)
{
// In or almost in range
character.CursorPosition = leak.Position;
character.CursorPosition = leak.WorldPosition;
if (character.Submarine != null)
{
character.CursorPosition -= character.Submarine.Position;
}
character.CursorPosition += VectorExtensions.Forward(Item.body.TransformedRotation + (float)Math.Sin(sinTime) / 2, dist / 2);
if (character.AnimController.InWater)
{
@@ -656,6 +684,12 @@ namespace Barotrauma.Items.Components
var angle = VectorExtensions.Angle(VectorExtensions.Forward(item.body.TransformedRotation), fromItemToLeak);
if (angle < MathHelper.PiOver4)
{
if (Submarine.PickBody(item.SimPosition, leak.SimPosition, collisionCategory: Physics.CollisionWall, allowInsideFixture: true)?.UserData is Item i)
{
var door = i.GetComponent<Door>();
// Hit a door, abandon so that we don't weld it shut.
return door != null && !door.IsOpen && !door.IsBroken;
}
// Check that we don't hit any friendlies
if (Submarine.PickBodies(item.SimPosition, leak.SimPosition, collisionCategory: Physics.CollisionCharacter).None(hit =>
{
@@ -669,17 +703,24 @@ namespace Barotrauma.Items.Components
{
character.SetInput(InputType.Shoot, false, true);
Use(deltaTime, character);
repairTimer += deltaTime;
if (repairTimer > repairTimeOut)
{
#if DEBUG
DebugConsole.NewMessage($"{character.Name}: timed out while welding a leak in {leak.FlowTargetHull.DisplayName}.", color: Color.Yellow);
#endif
return true;
}
}
}
bool leakFixed = (leak.Open <= 0.0f || leak.Removed) &&
(leak.ConnectedWall == null || leak.ConnectedWall.Sections.Average(s => s.damage) < 1);
if (leakFixed && leak.FlowTargetHull != null)
if (leakFixed && leak.FlowTargetHull?.DisplayName != null)
{
if (!leak.FlowTargetHull.ConnectedGaps.Any(g => !g.IsRoomToRoom && g.Open > 0.0f))
{
{
character.Speak(TextManager.GetWithVariable("DialogLeaksFixed", "[roomname]", leak.FlowTargetHull.DisplayName, true), null, 0.0f, "leaksfixed", 10.0f);
}
else
@@ -6,18 +6,20 @@ namespace Barotrauma.Items.Components
{
class Throwable : Holdable
{
private float throwForce, throwPos;
private float throwPos;
private bool throwing, throwDone;
private bool midAir;
[Serialize(1.0f, false, description: "The impulse applied to the physics body of the item when thrown. Higher values make the item be thrown faster.")]
public float ThrowForce
public Character CurrentThrower
{
get { return throwForce; }
set { throwForce = value; }
get;
private set;
}
[Serialize(1.0f, false, description: "The impulse applied to the physics body of the item when thrown. Higher values make the item be thrown faster.")]
public float ThrowForce { get; set; }
public Throwable(Item item, XElement element)
: base(item, element)
{
@@ -60,6 +62,21 @@ namespace Barotrauma.Items.Components
{
if (item.body.LinearVelocity.LengthSquared() < 0.01f)
{
CurrentThrower = null;
if (statusEffectLists?.ContainsKey(ActionType.OnImpact) ?? false)
{
foreach (var statusEffect in statusEffectLists[ActionType.OnImpact])
{
statusEffect.SetUser(null);
}
}
if (statusEffectLists?.ContainsKey(ActionType.OnBroken) ?? false)
{
foreach (var statusEffect in statusEffectLists[ActionType.OnBroken])
{
statusEffect.SetUser(null);
}
}
item.body.CollidesWith = Physics.CollisionWall | Physics.CollisionLevel | Physics.CollisionPlatform;
midAir = false;
}
@@ -117,9 +134,24 @@ namespace Barotrauma.Items.Components
#if SERVER
GameServer.Log(GameServer.CharacterLogName(picker) + " threw " + item.Name, ServerLog.MessageType.ItemInteraction);
#endif
Character thrower = picker;
item.Drop(thrower, createNetworkEvent: GameMain.NetworkMember == null || GameMain.NetworkMember.IsServer);
item.body.ApplyLinearImpulse(throwVector * throwForce * item.body.Mass * 3.0f, maxVelocity: NetConfig.MaxPhysicsBodyVelocity);
CurrentThrower = picker;
if (statusEffectLists?.ContainsKey(ActionType.OnImpact) ?? false)
{
foreach (var statusEffect in statusEffectLists[ActionType.OnImpact])
{
statusEffect.SetUser(CurrentThrower);
}
}
if (statusEffectLists?.ContainsKey(ActionType.OnBroken) ?? false)
{
foreach (var statusEffect in statusEffectLists[ActionType.OnBroken])
{
statusEffect.SetUser(CurrentThrower);
}
}
item.Drop(CurrentThrower, createNetworkEvent: GameMain.NetworkMember == null || GameMain.NetworkMember.IsServer);
item.body.ApplyLinearImpulse(throwVector * ThrowForce * item.body.Mass * 3.0f, maxVelocity: NetConfig.MaxPhysicsBodyVelocity);
//disable platform collisions until the item comes back to rest again
item.body.CollidesWith = Physics.CollisionWall | Physics.CollisionLevel;
@@ -135,12 +167,12 @@ namespace Barotrauma.Items.Components
if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsServer)
{
GameMain.NetworkMember.CreateEntityEvent(item, new object[] { NetEntityEvent.Type.ApplyStatusEffect, ActionType.OnSecondaryUse, this, thrower.ID });
GameMain.NetworkMember.CreateEntityEvent(item, new object[] { NetEntityEvent.Type.ApplyStatusEffect, ActionType.OnSecondaryUse, this, CurrentThrower.ID });
}
if (GameMain.NetworkMember == null || GameMain.NetworkMember.IsServer)
{
//Stun grenades, flares, etc. all have their throw-related things handled in "onSecondaryUse"
ApplyStatusEffects(ActionType.OnSecondaryUse, deltaTime, thrower, user: thrower);
ApplyStatusEffects(ActionType.OnSecondaryUse, deltaTime, CurrentThrower, user: CurrentThrower);
}
throwing = false;
}
@@ -146,7 +146,7 @@ namespace Barotrauma.Items.Components
public bool DrawHudWhenEquipped
{
get;
private set;
protected set;
}
[Serialize(false, false, description: "Can the item be selected by interacting with it.")]
@@ -604,7 +604,7 @@ namespace Barotrauma.Items.Components
if (character == null)
{
string errorMsg = "ItemComponent.DegreeOfSuccess failed (character was null).\n" + Environment.StackTrace;
string errorMsg = "ItemComponent.DegreeOfSuccess failed (character was null).\n" + Environment.StackTrace.CleanupStackTrace();
DebugConsole.ThrowError(errorMsg);
GameAnalyticsManager.AddErrorEventOnce("ItemComponent.DegreeOfSuccess:CharacterNull", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
return 0.0f;
@@ -846,7 +846,7 @@ namespace Barotrauma.Items.Components
DebugConsole.ThrowError("Error while loading entity of the type " + t + ".", e.InnerException);
GameAnalyticsManager.AddErrorEventOnce("ItemComponent.Load:TargetInvocationException" + item.Name + element.Name,
GameAnalyticsSDK.Net.EGAErrorSeverity.Error,
"Error while loading entity of the type " + t + " (" + e.InnerException + ")\n" + Environment.StackTrace);
"Error while loading entity of the type " + t + " (" + e.InnerException + ")\n" + Environment.StackTrace.CleanupStackTrace());
}
return ic;
@@ -1014,8 +1014,8 @@ namespace Barotrauma.Items.Components
var container = i.GetComponent<ItemContainer>();
if (container == null) { return 0; }
if (container.Inventory.IsFull()) { return 0; }
// Ignore containers that are identical to the source container
if (sourceC != null && container.Item.Prefab == sourceC.Item.Prefab) { 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)
@@ -328,10 +328,10 @@ namespace Barotrauma.Items.Components
}
catch (Exception e)
{
DebugConsole.Log("SetTransformIgnoreContacts threw an exception in SetContainedItemPositions (" + e.Message + ")\n" + e.StackTrace);
DebugConsole.Log("SetTransformIgnoreContacts threw an exception in SetContainedItemPositions (" + e.Message + ")\n" + e.StackTrace.CleanupStackTrace());
GameAnalyticsManager.AddErrorEventOnce("ItemContainer.SetContainedItemPositions.InvalidPosition:" + contained.Name,
GameAnalyticsSDK.Net.EGAErrorSeverity.Error,
"SetTransformIgnoreContacts threw an exception in SetContainedItemPositions (" + e.Message + ")\n" + e.StackTrace);
"SetTransformIgnoreContacts threw an exception in SetContainedItemPositions (" + e.Message + ")\n" + e.StackTrace.CleanupStackTrace());
}
contained.body.Submarine = item.Submarine;
}
@@ -349,6 +349,14 @@ namespace Barotrauma.Items.Components
}
}
public override void OnItemLoaded()
{
if (item.Submarine == null || !item.Submarine.Loading)
{
SpawnAlwaysContainedItems();
}
}
public override void OnMapLoaded()
{
if (itemIds != null)
@@ -361,7 +369,11 @@ namespace Barotrauma.Items.Components
}
itemIds = null;
}
SpawnAlwaysContainedItems();
}
private void SpawnAlwaysContainedItems()
{
if (SpawnWithId.Length > 0)
{
ItemPrefab prefab = ItemPrefab.Prefabs.Find(m => m.Identifier == SpawnWithId);
@@ -375,6 +387,7 @@ namespace Barotrauma.Items.Components
}
}
protected override void ShallowRemoveComponentSpecific()
{
}
@@ -388,9 +401,9 @@ namespace Barotrauma.Items.Components
inventoryBottomSprite?.Remove();
ContainedStateIndicator?.Remove();
if (Screen.Selected == GameMain.SubEditorScreen && !Submarine.Unloading)
if (SubEditorScreen.IsSubEditor())
{
GameMain.SubEditorScreen.HandleContainerContentsDeletion(Item, Inventory);
Inventory.DeleteAllItems();
return;
}
#endif
@@ -34,7 +34,7 @@ namespace Barotrauma.Items.Components
set { maxFlow = value; }
}
[Editable, Serialize(false, false, alwaysUseInstanceValues: true)]
[Editable, Serialize(true, false, alwaysUseInstanceValues: true)]
public bool IsOn
{
get { return IsActive; }
@@ -0,0 +1,21 @@
using Barotrauma.Networking;
using System.Xml.Linq;
#if CLIENT
using Microsoft.Xna.Framework.Graphics;
#endif
namespace Barotrauma.Items.Components
{
class NameTag : ItemComponent
{
[InGameEditable, Serialize("", false, description: "Name written on the tag.", alwaysUseInstanceValues: true)]
public string WrittenName { get; set; }
public NameTag(Item item, XElement element) : base(item, element)
{
AllowInGameEditing = true;
DrawHudWhenEquipped = true;
item.EditableWhenEquipped = true;
}
}
}
@@ -201,6 +201,7 @@ namespace Barotrauma.Items.Components
if (seed.Decayed || seed.FullyGrown)
{
container?.Inventory.RemoveItem(seed.Item);
Entity.Spawner?.AddToRemoveQueue(seed.Item);
GrowableSeeds[i] = null;
return true;
}
@@ -214,14 +214,15 @@ namespace Barotrauma.Items.Components
}
if (HasBeenTuned) { return true; }
if (string.IsNullOrEmpty(objective.Option) || objective.Option.Equals("charge", StringComparison.OrdinalIgnoreCase))
float targetRatio = string.IsNullOrEmpty(objective.Option) || objective.Option.Equals("charge", StringComparison.OrdinalIgnoreCase) ? aiRechargeTargetRatio : -1;
if (targetRatio > 0 || float.TryParse(objective.Option, out targetRatio))
{
if (Math.Abs(rechargeSpeed - maxRechargeSpeed * aiRechargeTargetRatio) > 0.05f)
if (Math.Abs(rechargeSpeed - maxRechargeSpeed * targetRatio) > 0.05f)
{
#if SERVER
item.CreateServerEvent(this);
#endif
RechargeSpeed = maxRechargeSpeed * aiRechargeTargetRatio;
RechargeSpeed = maxRechargeSpeed * targetRatio;
#if CLIENT
if (rechargeSpeedSlider != null)
{
@@ -639,6 +639,7 @@ namespace Barotrauma.Items.Components
}
target.Body.ApplyLinearImpulse(velocity * item.body.Mass);
target.Body.LinearVelocity = target.Body.LinearVelocity.ClampLength(NetConfig.MaxPhysicsBodyVelocity * 0.5f);
if (hits.Count() >= MaxTargetsToHit || hits.LastOrDefault()?.UserData is VoronoiCell)
{
@@ -271,7 +271,7 @@ namespace Barotrauma.Items.Components
if (wires[i] == null) { continue; }
Connection recipient = wires[i].OtherConnection(this);
if (recipient == null) { continue; }
if (recipient == null || !recipient.IsPower) { continue; }
recipient.item.GetComponent<Powered>()?.ReceivePowerProbeSignal(recipient, source, power);
}
@@ -5,7 +5,7 @@ namespace Barotrauma.Items.Components
{
partial class MemoryComponent : ItemComponent, IServerSerializable
{
const int MaxValueLength = 256;
const int MaxValueLength = ChatMessage.MaxLength;
private string value;
@@ -11,6 +11,7 @@ namespace Barotrauma.Items.Components
private string previousReceivedSignal;
private bool previousResult;
private GroupCollection previousGroups;
private Regex regex;
@@ -19,6 +20,9 @@ namespace Barotrauma.Items.Components
[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; }
[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; }
[Serialize("0", true, description: "The signal this item outputs when the received signal does not match the regular expression.", alwaysUseInstanceValues: true)]
public string FalseOutput { get; set; }
@@ -64,6 +68,7 @@ namespace Barotrauma.Items.Components
{
Match match = regex.Match(receivedSignal);
previousResult = match.Success;
previousGroups = UseCaptureGroup && previousResult ? match.Groups : null;
previousReceivedSignal = receivedSignal;
}
@@ -75,7 +80,30 @@ namespace Barotrauma.Items.Components
}
}
string signalOut = previousResult ? Output : FalseOutput;
string signalOut;
if (previousResult)
{
if (UseCaptureGroup)
{
if (previousGroups != null && previousGroups.TryGetValue(Output, out Group group))
{
signalOut = group.Value;
}
else
{
signalOut = FalseOutput;
}
}
else
{
signalOut = Output;
}
}
else
{
signalOut = FalseOutput;
}
if (ContinuousOutput)
{
if (!string.IsNullOrEmpty(signalOut)) { item.SendSignal(0, signalOut, "signal_out", null); }
@@ -37,7 +37,7 @@ namespace Barotrauma.Items.Components
}
}
[Editable, Serialize(false, true, description: "Can the relay currently pass power and signals through it.", alwaysUseInstanceValues: true)]
[Editable, Serialize(true, true, description: "Can the relay currently pass power and signals through it.", alwaysUseInstanceValues: true)]
public bool IsOn
{
get
@@ -1,10 +1,11 @@
using System.Xml.Linq;
using Barotrauma.Networking;
using System.Xml.Linq;
namespace Barotrauma.Items.Components
{
partial class Terminal : ItemComponent
{
private const int MaxMessageLength = 150;
private const int MaxMessageLength = ChatMessage.MaxLength;
public string DisplayedWelcomeMessage
{
@@ -21,7 +22,7 @@ namespace Barotrauma.Items.Components
{
if (welcomeMessage == value) { return; }
welcomeMessage = value;
DisplayedWelcomeMessage = TextManager.Get(welcomeMessage, returnNull: true) ?? welcomeMessage;
DisplayedWelcomeMessage = TextManager.Get(welcomeMessage, returnNull: true) ?? welcomeMessage.Replace("\\n", "\n");
}
}
@@ -45,7 +46,9 @@ namespace Barotrauma.Items.Components
{
signal = signal.Substring(0, MaxMessageLength);
}
ShowOnDisplay(signal);
string inputSignal = signal.Replace("\\n", "\n");
ShowOnDisplay(inputSignal);
}
}
}
@@ -63,7 +63,7 @@ namespace Barotrauma.Items.Components
public bool Hidden;
private float removeNodeDelay;
private float editNodeDelay;
private bool locked;
public bool Locked
@@ -198,7 +198,21 @@ namespace Barotrauma.Items.Components
int newNodeIndex = 0;
if (nodes.Count > 1)
{
if (Vector2.DistanceSquared(nodes[nodes.Count - 1], nodePos) < Vector2.DistanceSquared(nodes[0], nodePos))
if (connections[0] != null && connections[0] != newConnection)
{
if (Vector2.DistanceSquared(nodes[0], connections[0].Item.Position - (refSub?.HiddenSubPosition ?? Vector2.Zero)) < Vector2.DistanceSquared(nodes[nodes.Count - 1], nodePos))
{
newNodeIndex = nodes.Count;
}
}
else if (connections[1] != null && connections[1] != newConnection)
{
if (Vector2.DistanceSquared(nodes[0], connections[1].Item.Position - (refSub?.HiddenSubPosition ?? Vector2.Zero)) < Vector2.DistanceSquared(nodes[nodes.Count - 1], nodePos))
{
newNodeIndex = nodes.Count;
}
}
else if (Vector2.DistanceSquared(nodes[nodes.Count - 1], nodePos) < Vector2.DistanceSquared(nodes[0], nodePos))
{
newNodeIndex = nodes.Count;
}
@@ -276,7 +290,7 @@ namespace Barotrauma.Items.Components
if (nodes.Count == 0) { return; }
Character user = item.ParentInventory?.Owner as Character;
removeNodeDelay = (user?.SelectedConstruction == null) ? removeNodeDelay - deltaTime : 0.5f;
editNodeDelay = (user?.SelectedConstruction == null) ? editNodeDelay - deltaTime : 0.5f;
Submarine sub = item.Submarine;
if (connections[0] != null && connections[0].Item.Submarine != null) { sub = connections[0].Item.Submarine; }
@@ -402,7 +416,9 @@ namespace Barotrauma.Items.Components
#endif
//clients communicate node addition/removal with network events
if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsServer) { return false; }
if (newNodePos != Vector2.Zero && canPlaceNode && nodes.Count > 0 && Vector2.Distance(newNodePos, nodes[nodes.Count - 1]) > MinNodeDistance)
if (newNodePos != Vector2.Zero && canPlaceNode && editNodeDelay <= 0.0f && nodes.Count > 0 &&
Vector2.DistanceSquared(newNodePos, nodes[nodes.Count - 1]) > MinNodeDistance * MinNodeDistance)
{
if (nodes.Count >= MaxNodeCount)
{
@@ -426,6 +442,7 @@ namespace Barotrauma.Items.Components
}
#endif
}
editNodeDelay = 0.1f;
return true;
}
@@ -436,7 +453,7 @@ namespace Barotrauma.Items.Components
//clients communicate node addition/removal with network events
if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsServer) { return false; }
if (nodes.Count > 1 && removeNodeDelay <= 0.0f)
if (nodes.Count > 1 && editNodeDelay <= 0.0f)
{
nodes.RemoveAt(nodes.Count - 1);
UpdateSections();
@@ -452,7 +469,7 @@ namespace Barotrauma.Items.Components
}
#endif
}
removeNodeDelay = 0.1f;
editNodeDelay = 0.1f;
Drawable = IsActive || sections.Count > 0;
return true;
@@ -384,7 +384,7 @@ namespace Barotrauma.Items.Components
if (!flashLowPower && character != null && character == Character.Controlled)
{
flashLowPower = true;
GUI.PlayUISound(GUISoundType.PickItemFail);
SoundPlayer.PlayUISound(GUISoundType.PickItemFail);
}
#endif
return false;
@@ -422,7 +422,7 @@ namespace Barotrauma.Items.Components
{
flashNoAmmo = true;
failedLaunchAttempts = 0;
GUI.PlayUISound(GUISoundType.PickItemFail);
SoundPlayer.PlayUISound(GUISoundType.PickItemFail);
}
#endif
return false;
@@ -151,7 +151,7 @@ namespace Barotrauma
{
if (i < 0 || i >= Items.Length)
{
string errorMsg = "Inventory.TryPutItem failed: index was out of range(" + i + ").\n" + Environment.StackTrace;
string errorMsg = "Inventory.TryPutItem failed: index was out of range(" + i + ").\n" + Environment.StackTrace.CleanupStackTrace();
GameAnalyticsManager.AddErrorEventOnce("Inventory.TryPutItem:IndexOutOfRange", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
return false;
}
@@ -192,7 +192,7 @@ namespace Barotrauma
{
if (i < 0 || i >= Items.Length)
{
string errorMsg = "Inventory.PutItem failed: index was out of range(" + i + ").\n" + Environment.StackTrace;
string errorMsg = "Inventory.PutItem failed: index was out of range(" + i + ").\n" + Environment.StackTrace.CleanupStackTrace();
GameAnalyticsManager.AddErrorEventOnce("Inventory.PutItem:IndexOutOfRange", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
return;
}
@@ -304,13 +304,16 @@ namespace Barotrauma
for (int j = 0; j < otherInventory.capacity; j++)
{
if (otherInventory.Items[j] == item) otherInventory.Items[j] = null;
if (otherInventory.Items[j] == item) { otherInventory.Items[j] = null; }
}
for (int j = 0; j < capacity; j++)
{
if (Items[j] == existingItem) Items[j] = null;
if (Items[j] == existingItem) { Items[j] = null; }
}
(otherInventory.Owner as Character)?.DeselectItem(item);
(otherInventory.Owner as Character)?.DeselectItem(existingItem);
bool swapSuccessful = false;
if (otherIsEquipped)
{
@@ -486,6 +489,22 @@ namespace Barotrauma
}
Items[i].Remove();
}
}
}
public List<Item> GetAllItems()
{
List<Item> deletedItems = new List<Item>();
for (int i = 0; i < capacity; i++)
{
if (Items[i] == null) continue;
foreach (ItemContainer itemContainer in Items[i].GetComponents<ItemContainer>())
{
deletedItems.AddRange(itemContainer.Inventory.GetAllItems());
}
deletedItems.Add(Items[i]);
}
return deletedItems;
}
}
}
@@ -119,6 +119,8 @@ namespace Barotrauma
}
}
public bool EditableWhenEquipped { get; set; } = false;
//the inventory in which the item is contained in
public Inventory ParentInventory
{
@@ -1016,7 +1018,7 @@ namespace Barotrauma
{
string errorMsg =
"Attempted to move the item " + Name +
" to an invalid position (" + simPosition + ")\n" + Environment.StackTrace;
" to an invalid position (" + simPosition + ")\n" + Environment.StackTrace.CleanupStackTrace();
DebugConsole.ThrowError(errorMsg);
GameAnalyticsManager.AddErrorEventOnce(
@@ -1073,7 +1075,7 @@ namespace Barotrauma
{
if (!MathUtils.IsValid(amount))
{
DebugConsole.ThrowError($"Attempted to move an item by an invalid amount ({amount})\n{Environment.StackTrace}");
DebugConsole.ThrowError($"Attempted to move an item by an invalid amount ({amount})\n{Environment.StackTrace.CleanupStackTrace()}");
return;
}
@@ -1360,12 +1362,15 @@ namespace Barotrauma
public AttackResult AddDamage(Character attacker, Vector2 worldPosition, Attack attack, float deltaTime, bool playSound = true)
{
if (Indestructible) return new AttackResult();
if (Indestructible) { return new AttackResult(); }
float damageAmount = attack.GetItemDamage(deltaTime);
Condition -= damageAmount;
ApplyStatusEffects(ActionType.OnDamaged, 1.0f);
if (damageAmount > 0)
{
ApplyStatusEffects(ActionType.OnDamaged, 1.0f);
}
return new AttackResult(damageAmount, null);
}
@@ -1629,7 +1634,7 @@ namespace Barotrauma
OnCollisionProjSpecific(impact);
if (GameMain.NetworkMember == null || GameMain.NetworkMember.IsServer)
{
if (ImpactTolerance > 0.0f && condition > 0.0f && impact > ImpactTolerance)
if (ImpactTolerance > 0.0f && condition > 0.0f && Math.Abs(impact) > ImpactTolerance)
{
ApplyStatusEffects(ActionType.OnImpact, 1.0f);
#if SERVER
@@ -1653,10 +1658,14 @@ namespace Barotrauma
public override void FlipX(bool relativeToSub)
{
if (!Prefab.CanFlipX) { return; }
//call the base method even if the item can't flip, to handle repositioning when flipping the whole sub
base.FlipX(relativeToSub);
if (!Prefab.CanFlipX)
{
flippedX = false;
return;
}
#if CLIENT
if (Prefab.CanSpriteFlipX)
{
@@ -1672,10 +1681,15 @@ namespace Barotrauma
public override void FlipY(bool relativeToSub)
{
if (!Prefab.CanFlipY) { return; }
//call the base method even if the item can't flip, to handle repositioning when flipping the whole sub
base.FlipY(relativeToSub);
if (!Prefab.CanFlipY)
{
flippedY = false;
return;
}
#if CLIENT
if (Prefab.CanSpriteFlipY)
{
@@ -1980,17 +1994,14 @@ namespace Barotrauma
{
if (picker.SelectedConstruction == this)
{
if (picker.IsKeyHit(InputType.Select) || forceSelectKey) picker.SelectedConstruction = null;
if (picker.IsKeyHit(InputType.Select) || forceSelectKey)
{
picker.SelectedConstruction = null;
}
}
else if (selected)
{
picker.SelectedConstruction = this;
#if CLIENT
if (GameMain.GameSession?.CrewManager != null && picker == Character.Controlled && GetComponent<Ladder>() == null)
{
GameMain.GameSession.CrewManager.ToggleCrewListOpen = false;
}
#endif
}
}
@@ -2215,7 +2226,7 @@ namespace Barotrauma
{
if (Removed)
{
DebugConsole.ThrowError($"Tried to equip a removed item ({Name}).\n{Environment.StackTrace}");
DebugConsole.ThrowError($"Tried to equip a removed item ({Name}).\n{Environment.StackTrace.CleanupStackTrace()}");
return;
}
@@ -2257,7 +2268,7 @@ namespace Barotrauma
var propertyOwner = allProperties.Find(p => p.Second == property);
if (allProperties.Count > 1)
{
msg.WriteRangedInteger(allProperties.FindIndex(p => p.Second == property), 0, allProperties.Count - 1);
msg.Write((byte)allProperties.FindIndex(p => p.Second == property));
}
object value = property.GetValue(propertyOwner.First);
@@ -2339,7 +2350,7 @@ namespace Barotrauma
int propertyIndex = 0;
if (allProperties.Count > 1)
{
propertyIndex = msg.ReadRangedInteger(0, allProperties.Count - 1);
propertyIndex = msg.ReadByte();
}
bool allowEditing = true;
@@ -2360,6 +2371,7 @@ namespace Barotrauma
if (type == typeof(string))
{
string val = msg.ReadString();
logValue = val;
if (allowEditing)
{
property.TrySetValue(parentObject, val);
@@ -2712,7 +2724,7 @@ namespace Barotrauma
{
if (Removed)
{
DebugConsole.ThrowError("Attempting to remove an already removed item (" + Name + ")\n" + Environment.StackTrace);
DebugConsole.ThrowError("Attempting to remove an already removed item (" + Name + ")\n" + Environment.StackTrace.CleanupStackTrace());
return;
}
DebugConsole.Log("Removing item " + Name + " (ID: " + ID + ")");
@@ -93,7 +93,7 @@ namespace Barotrauma
{
if (!Item.ItemList.Contains(container.Item))
{
string errorMsg = "Attempted to create a network event for an item (" + container.Item.Name + ") that hasn't been fully initialized yet.\n" + Environment.StackTrace;
string errorMsg = "Attempted to create a network event for an item (" + container.Item.Name + ") that hasn't been fully initialized yet.\n" + Environment.StackTrace.CleanupStackTrace();
DebugConsole.ThrowError(errorMsg);
GameAnalyticsManager.AddErrorEventOnce(
"ItemInventory.CreateServerEvent:EventForUninitializedItem" + container.Item.Name + container.Item.ID,
@@ -319,6 +319,13 @@ namespace Barotrauma
private set;
}
[Serialize(false, false)]
public bool AllowSellingWhenBroken
{
get;
private set;
}
[Serialize(false, false)]
public bool Indestructible
{