Unstable v0.19.3.0

This commit is contained in:
Juan Pablo Arce
2022-09-02 15:10:56 -03:00
parent 28789616bd
commit 3f2c843247
336 changed files with 7152 additions and 7739 deletions
@@ -1191,7 +1191,7 @@ namespace Barotrauma.Items.Components
//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 (GameMain.NetworkMember != null && tryingToToggleOutpostDocking && signal.sender == null)
{
if (allowOutpostAutoDocking == AllowOutpostAutoDocking.Ask)
{
@@ -132,8 +132,8 @@ namespace Barotrauma.Items.Components
public static FoliageConfig CreateRandomConfig(int maxVariants, float minScale, float maxScale, Random? random = null)
{
int flowerVariant = Growable.RandomInt(0, maxVariants, random);
float flowerScale = (float) Growable.RandomDouble(minScale, maxScale, random);
float flowerRotation = (float) Growable.RandomDouble(0, MathHelper.TwoPi, random);
float flowerScale = (float)Growable.RandomDouble(minScale, maxScale, random);
float flowerRotation = (float)Growable.RandomDouble(0, MathHelper.TwoPi, random);
return new FoliageConfig { Variant = flowerVariant, Scale = flowerScale, Rotation = flowerRotation };
}
}
@@ -169,10 +169,10 @@ namespace Barotrauma.Items.Components
{
const float limit = 1.0f;
growthStep = value;
VineStep = Math.Min((float) Math.Pow(value, 2), limit);
VineStep = Math.Min((float)Math.Pow(value, 2), limit);
if (value > limit)
{
FlowerStep = Math.Min((float) Math.Pow(value - limit, 2), limit);
FlowerStep = Math.Min((float)Math.Pow(value - limit, 2), limit);
}
}
}
@@ -260,7 +260,7 @@ namespace Barotrauma.Items.Components
{
if (Type == VineTileType.Stem) { return; }
Type = (VineTileType) Sides;
Type = (VineTileType)Sides;
}
/// <summary>
@@ -310,7 +310,7 @@ namespace Barotrauma.Items.Components
public bool IsSideBlocked(TileSide side) => BlockedSides.HasFlag(side) || Sides.HasFlag(side);
public static Rectangle CreatePlantRect(Vector2 pos) => new Rectangle((int) pos.X - Size / 2, (int) pos.Y + Size / 2, Size, Size);
public static Rectangle CreatePlantRect(Vector2 pos) => new Rectangle((int)pos.X - Size / 2, (int)pos.Y + Size / 2, Size, Size);
}
internal static class GrowthSideExtension
@@ -318,7 +318,7 @@ namespace Barotrauma.Items.Components
// K&R algorithm for counting how many bits are set in a bit field
public static int Count(this TileSide side)
{
int n = (int) side;
int n = (int)side;
int count = 0;
while (n != 0)
{
@@ -607,7 +607,7 @@ namespace Barotrauma.Items.Components
#if CLIENT
foreach (VineTile vine in Vines)
{
vine.DecayDelay = (float) RandomDouble(0f, 30f);
vine.DecayDelay = (float)RandomDouble(0f, 30f);
}
#endif
#if SERVER
@@ -742,7 +742,7 @@ namespace Barotrauma.Items.Components
{
var (x, y, z, w) = GrowthWeights;
float[] weights = { x, y, z, w };
int index = (int) Math.Log2((int) side);
int index = (int)Math.Log2((int)side);
if (MathUtils.NearlyEqual(weights[index], 0f))
{
oldVines.FailedGrowthAttempts++;
@@ -778,7 +778,7 @@ namespace Barotrauma.Items.Components
foreach (VineTile otherVine in Vines)
{
var (distX, distY) = pos - otherVine.Position;
int absDistX = (int) Math.Abs(distX), absDistY = (int) Math.Abs(distY);
int absDistX = (int)Math.Abs(distX), absDistY = (int)Math.Abs(distY);
// check if the tile is within the with or height distance from us but ignore diagonals
if (absDistX > newVine.Rect.Width || absDistY > newVine.Rect.Height || absDistX > 0 && absDistY > 0) { continue; }
@@ -872,10 +872,10 @@ namespace Barotrauma.Items.Components
foreach (VineTile vine in Vines)
{
XElement vineElement = new XElement("Vine");
vineElement.Add(new XAttribute("sides", (int) vine.Sides));
vineElement.Add(new XAttribute("blockedsides", (int) vine.BlockedSides));
vineElement.Add(new XAttribute("sides", (int)vine.Sides));
vineElement.Add(new XAttribute("blockedsides", (int)vine.BlockedSides));
vineElement.Add(new XAttribute("pos", XMLExtensions.Vector2ToString(vine.Position)));
vineElement.Add(new XAttribute("tile", (int) vine.Type));
vineElement.Add(new XAttribute("tile", (int)vine.Type));
vineElement.Add(new XAttribute("failedattempts", vine.FailedGrowthAttempts));
#if SERVER
vineElement.Add(new XAttribute("growthscale", Decayed ? 1.0f : 2.0f));
@@ -902,10 +902,10 @@ namespace Barotrauma.Items.Components
{
if (element.Name.ToString().Equals("vine", StringComparison.OrdinalIgnoreCase))
{
VineTileType type = (VineTileType) element.GetAttributeInt("tile", 0);
VineTileType type = (VineTileType)element.GetAttributeInt("tile", 0);
Vector2 pos = element.GetAttributeVector2("pos", Vector2.Zero);
TileSide sides = (TileSide) element.GetAttributeInt("sides", 0);
TileSide blockedSides = (TileSide) element.GetAttributeInt("blockedsides", 0);
TileSide sides = (TileSide)element.GetAttributeInt("sides", 0);
TileSide blockedSides = (TileSide)element.GetAttributeInt("blockedsides", 0);
int failedAttempts = element.GetAttributeInt("failedattempts", 0);
float growthscale = element.GetAttributeFloat("growthscale", 0f);
int flowerConfig = element.GetAttributeInt("flowerconfig", FoliageConfig.EmptyConfigValue);
@@ -4,6 +4,7 @@ using FarseerPhysics.Dynamics.Contacts;
using Microsoft.Xna.Framework;
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
namespace Barotrauma.Items.Components
@@ -62,7 +63,7 @@ namespace Barotrauma.Items.Components
/// <summary>
/// Defines items that boost the weapon functionality, like battery cell for stun batons.
/// </summary>
public readonly Identifier[] PreferredContainedItems;
public readonly ImmutableHashSet<Identifier> PreferredContainedItems;
public MeleeWeapon(Item item, ContentXElement element)
: base(item, element)
@@ -77,7 +78,7 @@ namespace Barotrauma.Items.Components
}
item.IsShootable = true;
item.RequireAimToUse = element.Parent.GetAttributeBool("requireaimtouse", true);
PreferredContainedItems = element.GetAttributeIdentifierArray("preferredcontaineditems", Array.Empty<Identifier>());
PreferredContainedItems = element.GetAttributeIdentifierArray("preferredcontaineditems", Array.Empty<Identifier>()).ToImmutableHashSet();
}
public override void Equip(Character character)
@@ -387,14 +388,16 @@ namespace Barotrauma.Items.Components
User = null;
return;
}
float damageMultiplier = 1 + User.GetStatValue(StatTypes.MeleeAttackMultiplier);
damageMultiplier *= 1.0f + item.GetQualityModifier(Quality.StatType.StrikingPowerMultiplier);
Limb targetLimb = target.UserData as Limb;
Character targetCharacter = targetLimb?.character ?? target.UserData as Character;
if (Attack != null)
{
Attack.SetUser(User);
Attack.DamageMultiplier = 1 + User.GetStatValue(StatTypes.MeleeAttackMultiplier);
Attack.DamageMultiplier *= 1.0f + item.GetQualityModifier(Quality.StatType.StrikingPowerMultiplier);
Attack.DamageMultiplier = damageMultiplier;
if (targetLimb != null)
{
@@ -467,7 +470,7 @@ namespace Barotrauma.Items.Components
if (targetCharacter != null) //TODO: Allow OnUse to happen on structures too maybe??
{
ApplyStatusEffects(success ? ActionType.OnUse : ActionType.OnFailure, 1.0f, targetCharacter, targetLimb, user: User);
ApplyStatusEffects(success ? ActionType.OnUse : ActionType.OnFailure, 1.0f, targetCharacter, targetLimb, user: User, afflictionMultiplier: damageMultiplier);
}
if (DeleteOnUse)
@@ -287,7 +287,7 @@ namespace Barotrauma.Items.Components
public virtual void ServerEventWrite(IWriteMessage msg, Client c, NetEntityEvent.IData extraData = null)
{
msg.Write(activePicker?.ID ?? (ushort)0);
msg.WriteUInt16(activePicker?.ID ?? (ushort)0);
}
public virtual void ClientEventRead(IReadMessage msg, float sendingTime)
@@ -229,8 +229,6 @@ namespace Barotrauma.Items.Components
set;
}
public virtual bool RecreateGUIOnResolutionChange => false;
/// <summary>
/// How useful the item is in combat? Used by AI to decide which item it should use as a weapon. For the sake of clarity, use a value between 0 and 100 (not enforced).
/// </summary>
@@ -397,7 +395,7 @@ namespace Barotrauma.Items.Components
RelatedItem ri = RelatedItem.Load(element, returnEmpty, item.Name);
if (ri != null)
{
if (ri.Identifiers.Length == 0)
if (ri.Identifiers.Count == 0)
{
DisabledRequiredItems.Add(ri);
}
@@ -816,7 +814,7 @@ namespace Barotrauma.Items.Components
}
}
public void ApplyStatusEffects(ActionType type, float deltaTime, Character character = null, Limb targetLimb = null, Entity useTarget = null, Character user = null, Vector2? worldPosition = null, float applyOnUserFraction = 0.0f)
public void ApplyStatusEffects(ActionType type, float deltaTime, Character character = null, Limb targetLimb = null, Entity useTarget = null, Character user = null, Vector2? worldPosition = null, float afflictionMultiplier = 1.0f, float applyOnUserFraction = 0.0f)
{
if (statusEffectLists == null) { return; }
@@ -828,13 +826,14 @@ namespace Barotrauma.Items.Components
{
if (broken && !effect.AllowWhenBroken && effect.type != ActionType.OnBroken) { continue; }
if (user != null) { effect.SetUser(user); }
effect.AfflictionMultiplier = afflictionMultiplier;
item.ApplyStatusEffect(effect, type, deltaTime, character, targetLimb, useTarget, isNetworkEvent: false, checkCondition: false, worldPosition);
if (user != null && applyOnUserFraction > 0.0f && effect.HasTargetType(StatusEffect.TargetType.Character))
{
effect.AfflictionMultiplier = applyOnUserFraction;
item.ApplyStatusEffect(effect, type, deltaTime, user, targetLimb == null ? null : user.AnimController.GetLimb(targetLimb.type), useTarget, false, false, worldPosition);
effect.AfflictionMultiplier = 1.0f;
}
effect.AfflictionMultiplier = 1.0f;
reducesCondition |= effect.ReducesItemCondition();
}
//if any of the effects reduce the item's condition, set the user for OnBroken effects as well
@@ -1070,7 +1069,7 @@ namespace Barotrauma.Items.Components
AIObjectiveContainItem containObjective = null;
if (character.AIController is HumanAIController aiController)
{
containObjective = new AIObjectiveContainItem(character, container.ContainableItemIdentifiers.ToArray(), container, currentObjective.objectiveManager, spawnItemIfNotFound: spawnItemIfNotFound)
containObjective = new AIObjectiveContainItem(character, container.ContainableItemIdentifiers, container, currentObjective.objectiveManager, spawnItemIfNotFound: spawnItemIfNotFound)
{
ItemCount = itemCount,
Equip = equip,
@@ -216,9 +216,7 @@ namespace Barotrauma.Items.Components
}
private ImmutableHashSet<Identifier> containableItemIdentifiers;
public IEnumerable<Identifier> ContainableItemIdentifiers => containableItemIdentifiers;
public override bool RecreateGUIOnResolutionChange => true;
public ImmutableHashSet<Identifier> ContainableItemIdentifiers => containableItemIdentifiers;
public List<RelatedItem> ContainableItems { get; }
@@ -40,8 +40,6 @@ namespace Barotrauma.Items.Components
[Editable, Serialize(1.0f, IsPropertySaveable.Yes)]
public float DeconstructionSpeed { get; set; }
public override bool RecreateGUIOnResolutionChange => true;
public Deconstructor(Item item, ContentXElement element)
: base(item, element)
{
@@ -122,7 +120,7 @@ namespace Barotrauma.Items.Components
{
if ((Entity.Spawner?.IsInRemoveQueue(targetItem) ?? false) || !inputContainer.Inventory.AllItems.Contains(targetItem)) { continue; }
var validDeconstructItems = targetItem.Prefab.DeconstructItems.Where(it =>
(it.RequiredDeconstructor.Length == 0 || it.RequiredDeconstructor.Any(r => item.HasTag(r) || item.Prefab.Identifier == r)) &&
it.IsValidDeconstructor(item) &&
(it.RequiredOtherItem.Length == 0 || it.RequiredOtherItem.Any(r => items.Any(it => it != targetItem && (it.HasTag(r) || it.Prefab.Identifier == r))))).ToList();
ProcessItem(targetItem, items, validDeconstructItems, allowRemove: validDeconstructItems.Any() || !targetItem.Prefab.DeconstructItems.Any());
@@ -140,9 +138,7 @@ namespace Barotrauma.Items.Components
var targetItem = inputContainer.Inventory.LastOrDefault();
if (targetItem == null) { return; }
var validDeconstructItems = targetItem.Prefab.DeconstructItems.Where(it =>
it.RequiredDeconstructor.Length == 0 || it.RequiredDeconstructor.Any(r => item.HasTag(r) || item.Prefab.Identifier == r)).ToList();
var validDeconstructItems = targetItem.Prefab.DeconstructItems.Where(it => it.IsValidDeconstructor(item)).ToList();
float deconstructTime = validDeconstructItems.Any() ? targetItem.Prefab.DeconstructTime / (DeconstructionSpeed * deconstructionSpeedModifier) : 1.0f;
progressState = Math.Min(progressTimer / deconstructTime, 1.0f);
@@ -76,8 +76,6 @@ namespace Barotrauma.Items.Components
get { return outputContainer; }
}
public override bool RecreateGUIOnResolutionChange => true;
private float progressState;
private readonly Dictionary<uint, int> fabricationLimits = new Dictionary<uint, int>();
@@ -647,10 +645,13 @@ namespace Barotrauma.Items.Components
if (skills.Length == 0) { return 1.0f; }
if (character == null) { return 0.0f; }
float skillSum = (from t in skills let characterLevel = character.GetSkillLevel(t.Identifier) select (characterLevel - (t.Level * SkillRequirementMultiplier))).Sum();
float average = skillSum / skills.Length;
return (average + 100.0f) / 2.0f / 100.0f;
float minDegreeOfSuccess = 1.0f;
foreach (var skill in skills)
{
float characterLevel = character.GetSkillLevel(skill.Identifier);
minDegreeOfSuccess = Math.Min(minDegreeOfSuccess, (characterLevel - (skill.Level * SkillRequirementMultiplier) + 100.0f) / 2.0f / 100.0f);
}
return minDegreeOfSuccess;
}
public override float GetSkillMultiplier()
@@ -658,13 +659,16 @@ namespace Barotrauma.Items.Components
return SkillRequirementMultiplier;
}
private readonly HashSet<Inventory> linkedInventories = new HashSet<Inventory>();
private void RefreshAvailableIngredients()
{
Character user = this.user;
#if CLIENT
user ??= Character.Controlled;
#endif
linkedInventories.Clear();
List<Item> itemList = new List<Item>();
itemList.AddRange(inputContainer.Inventory.AllItems);
foreach (MapEntity linkedTo in item.linkedTo)
@@ -684,6 +688,7 @@ namespace Barotrauma.Items.Components
itemContainer = deconstructor.OutputContainer;
}
linkedInventories.Add(itemContainer.Inventory);
itemList.AddRange(itemContainer.Inventory.AllItems);
}
}
@@ -698,6 +703,7 @@ namespace Barotrauma.Items.Components
if (user?.Inventory != null)
{
itemList.AddRange(user.Inventory.AllItems);
linkedInventories.Add(user.Inventory);
}
availableIngredients.Clear();
foreach (Item item in itemList)
@@ -48,6 +48,9 @@ namespace Barotrauma.Items.Components
private Vector2 optimalFissionRate, allowedFissionRate;
private Vector2 optimalTurbineOutput, allowedTurbineOutput;
private float? signalControlledTargetFissionRate, signalControlledTargetTurbineOutput;
private double lastReceivedFissionRateSignalTime, lastReceivedTurbineOutputSignalTime;
private float temperatureBoost;
private bool _powerOn;
@@ -245,7 +248,7 @@ namespace Barotrauma.Items.Components
}
#endif
if (signalControlledTargetFissionRate.HasValue && Math.Abs(signalControlledTargetFissionRate.Value - TargetFissionRate) > 1.0f)
if (signalControlledTargetFissionRate.HasValue && lastReceivedFissionRateSignalTime > Timing.TotalTime - 1)
{
TargetFissionRate = adjustValueWithoutOverShooting(TargetFissionRate, signalControlledTargetFissionRate.Value, deltaTime * 5.0f);
#if CLIENT
@@ -256,7 +259,7 @@ namespace Barotrauma.Items.Components
{
signalControlledTargetFissionRate = null;
}
if (signalControlledTargetTurbineOutput.HasValue && Math.Abs(signalControlledTargetTurbineOutput.Value - TargetTurbineOutput) > 1.0f)
if (signalControlledTargetTurbineOutput.HasValue && lastReceivedTurbineOutputSignalTime > Timing.TotalTime - 1)
{
TargetTurbineOutput = adjustValueWithoutOverShooting(TargetTurbineOutput, signalControlledTargetTurbineOutput.Value, deltaTime * 5.0f);
#if CLIENT
@@ -841,6 +844,7 @@ namespace Barotrauma.Items.Components
if (PowerOn && float.TryParse(signal.value, NumberStyles.Float, CultureInfo.InvariantCulture, out float newFissionRate))
{
signalControlledTargetFissionRate = MathHelper.Clamp(newFissionRate, 0.0f, 100.0f);
lastReceivedFissionRateSignalTime = Timing.TotalTime;
registerUnsentChanges();
}
break;
@@ -848,6 +852,7 @@ namespace Barotrauma.Items.Components
if (PowerOn && float.TryParse(signal.value, NumberStyles.Float, CultureInfo.InvariantCulture, out float newTurbineOutput))
{
signalControlledTargetTurbineOutput = MathHelper.Clamp(newTurbineOutput, 0.0f, 100.0f);
lastReceivedTurbineOutputSignalTime = Timing.TotalTime;
registerUnsentChanges();
}
break;
@@ -858,7 +863,5 @@ namespace Barotrauma.Items.Components
if (GameMain.NetworkMember is { IsServer: true }) { unsentChanges = true; }
}
}
private float? signalControlledTargetFissionRate, signalControlledTargetTurbineOutput;
}
}
@@ -113,9 +113,23 @@ namespace Barotrauma.Items.Components
set;
}
[Editable, Serialize(false, IsPropertySaveable.No, description: "Does the sonar have mineral scanning mode. " +
"Only available in-game when the Item has no Steering component.")]
public bool HasMineralScanner { get; set; }
private bool hasMineralScanner;
[Editable, Serialize(false, IsPropertySaveable.No, description: "Does the sonar have mineral scanning mode. ")]
public bool HasMineralScanner
{
get => hasMineralScanner;
set
{
#if CLIENT
if (controlContainer != null && !hasMineralScanner && value)
{
AddMineralScannerSwitchToGUI();
}
#endif
hasMineralScanner = value;
}
}
public float Zoom
{
@@ -144,8 +158,6 @@ namespace Barotrauma.Items.Components
}
}
public override bool RecreateGUIOnResolutionChange => true;
public Sonar(Item item, ContentXElement element)
: base(item, element)
{
@@ -396,17 +408,17 @@ namespace Barotrauma.Items.Components
public void ServerEventWrite(IWriteMessage msg, Client c, NetEntityEvent.IData extraData = null)
{
msg.Write(currentMode == Mode.Active);
msg.WriteBoolean(currentMode == Mode.Active);
if (currentMode == Mode.Active)
{
msg.WriteRangedSingle(zoom, MinZoom, MaxZoom, 8);
msg.Write(useDirectionalPing);
msg.WriteBoolean(useDirectionalPing);
if (useDirectionalPing)
{
float pingAngle = MathUtils.WrapAngleTwoPi(MathUtils.VectorToAngle(pingDirection));
msg.WriteRangedSingle(MathUtils.InverseLerp(0.0f, MathHelper.TwoPi, pingAngle), 0.0f, 1.0f, 8);
}
msg.Write(useMineralScanner);
msg.WriteBoolean(useMineralScanner);
}
}
}
@@ -166,8 +166,6 @@ namespace Barotrauma.Items.Components
set { posToMaintain = value; }
}
public override bool RecreateGUIOnResolutionChange => true;
struct ObstacleDebugInfo
{
public Vector2 Point1;
@@ -401,14 +401,14 @@ namespace Barotrauma.Items.Components
msg.WriteVariableUInt32((uint)connection.Wires.Count);
foreach (Wire wire in connection.Wires)
{
msg.Write(wire?.Item == null ? (ushort)0 : wire.Item.ID);
msg.WriteUInt16(wire?.Item == null ? (ushort)0 : wire.Item.ID);
}
}
msg.Write((ushort)DisconnectedWires.Count);
msg.WriteUInt16((ushort)DisconnectedWires.Count);
foreach (Wire disconnectedWire in DisconnectedWires)
{
msg.Write(disconnectedWire.Item.ID);
msg.WriteUInt16(disconnectedWire.Item.ID);
}
}
}
@@ -155,7 +155,7 @@ namespace Barotrauma.Items.Components
{
//use semicolon as a separator because comma may be needed in the signals (for color or vector values for example)
//kind of hacky, we should probably add support for (string) arrays to SerializableEntityEditor so this wouldn't be needed
get { return signals == null ? "" : string.Join(";", signals); }
get { return signals == null ? string.Empty : string.Join(";", signals); }
set
{
if (value == null) { return; }
@@ -167,7 +167,31 @@ namespace Barotrauma.Items.Components
}
}
public override bool RecreateGUIOnResolutionChange => true;
private bool[] elementStates;
[Serialize("", IsPropertySaveable.Yes, description: "", alwaysUseInstanceValues: true)]
public string ElementStates
{
get { return elementStates == null ? string.Empty : string.Join(",", elementStates); }
set
{
if (value == null) { return; }
if (customInterfaceElementList.Count > 0)
{
string[] splitValues = value == "" ? Array.Empty<string>() : value.Split(',');
for (int i = 0; i < customInterfaceElementList.Count && i < splitValues.Length; i++)
{
if (!bool.TryParse(splitValues[i], out bool val)) { continue; }
customInterfaceElementList[i].State = val;
#if CLIENT
if (uiElements != null && i < uiElements.Count && uiElements[i] is GUITickBox tickBox)
{
tickBox.Selected = val;
}
#endif
}
}
}
}
private readonly List<CustomInterfaceElement> customInterfaceElementList = new List<CustomInterfaceElement>();
@@ -207,8 +231,10 @@ namespace Barotrauma.Items.Components
}
IsActive = true;
InitProjSpecific();
//load these here to ensure the UI elements (created in InitProjSpecific) are up-to-date
Labels = element.GetAttributeString("labels", "");
Signals = element.GetAttributeString("signals", "");
ElementStates = element.GetAttributeString("elementstates", "");
}
private void UpdateLabels(string[] newLabels)
@@ -386,6 +412,7 @@ namespace Barotrauma.Items.Components
{
labels = customInterfaceElementList.Select(ci => ci.Label).ToArray();
signals = customInterfaceElementList.Select(ci => ci.Signal).ToArray();
elementStates = customInterfaceElementList.Select(ci => ci.State).ToArray();
return base.Save(parentElement);
}
@@ -253,7 +253,13 @@ namespace Barotrauma.Items.Components
public void CheckIfNeedsUpdate()
{
if (item.body == null && powerConsumption <= 0.0f && Parent == null && turret == null && IsOn &&
if (!IsOn)
{
base.IsActive = false;
return;
}
if (item.body == null && powerConsumption <= 0.0f && Parent == null && turret == null &&
(statusEffectLists == null || !statusEffectLists.ContainsKey(ActionType.OnActive)) &&
(IsActiveConditionals == null || IsActiveConditionals.Count == 0))
{
@@ -268,7 +274,7 @@ namespace Barotrauma.Items.Components
}
else
{
IsActive = true;
base.IsActive = true;
}
}
@@ -374,7 +374,7 @@ namespace Barotrauma.Items.Components
public void ServerEventWrite(IWriteMessage msg, Client c, NetEntityEvent.IData extraData = null)
{
msg.Write(isOn);
msg.WriteBoolean(isOn);
}
public void ClientEventRead(IReadMessage msg, float sendingTime)
@@ -7,6 +7,7 @@ using System.Globalization;
using System.Linq;
using Barotrauma.Extensions;
using FarseerPhysics.Dynamics;
using System.Collections.Immutable;
namespace Barotrauma.Items.Components
{
@@ -1151,7 +1152,7 @@ namespace Barotrauma.Items.Components
if (objective.SubObjectives.None())
{
var loadItemsObjective = AIContainItems<Turret>(container, character, objective, usableProjectileCount + 1, equip: true, removeEmpty: true, dropItemOnDeselected: true);
loadItemsObjective.ignoredContainerIdentifiers = new Identifier[] { ((MapEntity)containerItem).Prefab.Identifier };
loadItemsObjective.ignoredContainerIdentifiers = ((MapEntity)containerItem).Prefab.Identifier.ToEnumerable().ToImmutableHashSet();
if (character.IsOnPlayerTeam)
{
character.Speak(TextManager.GetWithVariable("DialogLoadTurret", "[itemname]", item.Name, formatCapitals: FormatCapitals.Yes).Value,
@@ -1340,7 +1341,7 @@ namespace Barotrauma.Items.Components
{
if (character.AIController.SelectedAiTarget == null && !hadCurrentTarget)
{
if (CreatureMetrics.Instance.RecentlyEncountered.Contains(closestEnemy.SpeciesName))
if (CreatureMetrics.Instance.RecentlyEncountered.Contains(closestEnemy.SpeciesName) || closestEnemy.IsHuman)
{
character.Speak(TextManager.Get("DialogNewTargetSpotted").Value,
identifier: "newtargetspotted".ToIdentifier(),
@@ -1611,6 +1612,7 @@ namespace Barotrauma.Items.Components
targetRotation = rotation = (minRotation + maxRotation) / 2;
UpdateTransformedBarrelPos();
UpdateLightComponents();
}
public override void FlipY(bool relativeToSub)
@@ -1632,6 +1634,7 @@ namespace Barotrauma.Items.Components
targetRotation = rotation = (minRotation + maxRotation) / 2;
UpdateTransformedBarrelPos();
UpdateLightComponents();
}
public override void ReceiveSignal(Signal signal, Connection connection)
@@ -1714,12 +1717,12 @@ namespace Barotrauma.Items.Components
{
if (TryExtractEventData(extraData, out EventData eventData))
{
msg.Write(eventData.Projectile.ID);
msg.WriteUInt16(eventData.Projectile.ID);
msg.WriteRangedSingle(MathHelper.Clamp(rotation, minRotation, maxRotation), minRotation, maxRotation, 16);
}
else
{
msg.Write((ushort)0);
msg.WriteUInt16((ushort)0);
float wrappedTargetRotation = targetRotation;
while (wrappedTargetRotation < minRotation && MathUtils.IsValid(wrappedTargetRotation))
{
@@ -560,7 +560,7 @@ namespace Barotrauma.Items.Components
}
public override void ServerEventWrite(IWriteMessage msg, Client c, NetEntityEvent.IData extraData = null)
{
msg.Write((byte)Variant);
msg.WriteByte((byte)Variant);
base.ServerEventWrite(msg, c, extraData);
}
@@ -959,14 +959,14 @@ namespace Barotrauma
public void SharedWrite(IWriteMessage msg, NetEntityEvent.IData extraData = null)
{
msg.Write((byte)capacity);
msg.WriteByte((byte)capacity);
for (int i = 0; i < capacity; i++)
{
msg.WriteRangedInteger(slots[i].Items.Count, 0, MaxStackSize);
for (int j = 0; j < Math.Min(slots[i].Items.Count, MaxStackSize); j++)
{
var item = slots[i].Items[j];
msg.Write(item?.ID ?? (ushort)0);
msg.WriteUInt16(item?.ID ?? (ushort)0);
}
}
}
@@ -1536,7 +1536,7 @@ namespace Barotrauma
return false;
}
private bool ConditionalMatches(PropertyConditional conditional)
public bool ConditionalMatches(PropertyConditional conditional)
{
if (string.IsNullOrEmpty(conditional.TargetItemComponentName))
{
@@ -2861,77 +2861,77 @@ namespace Barotrauma
var propertyOwner = allProperties.Find(p => p.property == property);
if (allProperties.Count > 1)
{
msg.Write((byte)allProperties.FindIndex(p => p.property == property));
msg.WriteByte((byte)allProperties.FindIndex(p => p.property == property));
}
object value = property.GetValue(propertyOwner.obj);
if (value is string stringVal)
{
msg.Write(stringVal);
msg.WriteString(stringVal);
}
else if (value is Identifier idValue)
{
msg.Write(idValue);
msg.WriteIdentifier(idValue);
}
else if (value is float floatVal)
{
msg.Write(floatVal);
msg.WriteSingle(floatVal);
}
else if (value is int intVal)
{
msg.Write(intVal);
msg.WriteInt32(intVal);
}
else if (value is bool boolVal)
{
msg.Write(boolVal);
msg.WriteBoolean(boolVal);
}
else if (value is Color color)
{
msg.Write(color.R);
msg.Write(color.G);
msg.Write(color.B);
msg.Write(color.A);
msg.WriteByte(color.R);
msg.WriteByte(color.G);
msg.WriteByte(color.B);
msg.WriteByte(color.A);
}
else if (value is Vector2 vector2)
{
msg.Write(vector2.X);
msg.Write(vector2.Y);
msg.WriteSingle(vector2.X);
msg.WriteSingle(vector2.Y);
}
else if (value is Vector3 vector3)
{
msg.Write(vector3.X);
msg.Write(vector3.Y);
msg.Write(vector3.Z);
msg.WriteSingle(vector3.X);
msg.WriteSingle(vector3.Y);
msg.WriteSingle(vector3.Z);
}
else if (value is Vector4 vector4)
{
msg.Write(vector4.X);
msg.Write(vector4.Y);
msg.Write(vector4.Z);
msg.Write(vector4.W);
msg.WriteSingle(vector4.X);
msg.WriteSingle(vector4.Y);
msg.WriteSingle(vector4.Z);
msg.WriteSingle(vector4.W);
}
else if (value is Point point)
{
msg.Write(point.X);
msg.Write(point.Y);
msg.WriteInt32(point.X);
msg.WriteInt32(point.Y);
}
else if (value is Rectangle rect)
{
msg.Write(rect.X);
msg.Write(rect.Y);
msg.Write(rect.Width);
msg.Write(rect.Height);
msg.WriteInt32(rect.X);
msg.WriteInt32(rect.Y);
msg.WriteInt32(rect.Width);
msg.WriteInt32(rect.Height);
}
else if (value is Enum)
{
msg.Write((int)value);
msg.WriteInt32((int)value);
}
else if (value is string[] a)
{
msg.Write(a.Length);
msg.WriteInt32(a.Length);
for (int i = 0; i < a.Length; i++)
{
msg.Write(a[i] ?? "");
msg.WriteString(a[i] ?? "");
}
}
else
@@ -53,6 +53,11 @@ namespace Barotrauma
InfoText = element.GetAttributeString("infotext", string.Empty);
InfoTextOnOtherItemMissing = element.GetAttributeString("infotextonotheritemmissing", string.Empty);
}
public bool IsValidDeconstructor(Item deconstructor)
{
return RequiredDeconstructor.Length == 0 || RequiredDeconstructor.Any(r => deconstructor.HasTag(r) || deconstructor.Prefab.Identifier == r);
}
}
class FabricationRecipe
@@ -62,6 +67,10 @@ namespace Barotrauma
public abstract IEnumerable<ItemPrefab> ItemPrefabs { get; }
public abstract UInt32 UintIdentifier { get; }
public abstract bool MatchesItem(Item item);
public abstract ItemPrefab FirstMatchingPrefab { get; }
public RequiredItem(int amount, float minCondition, float maxCondition, bool useCondition)
{
Amount = amount;
@@ -92,12 +101,21 @@ namespace Barotrauma
public class RequiredItemByIdentifier : RequiredItem
{
public readonly Identifier ItemPrefabIdentifier;
public ItemPrefab ItemPrefab => ItemPrefab.Prefabs.TryGet(ItemPrefabIdentifier, out var prefab) ? prefab
: MapEntityPrefab.FindByName(ItemPrefabIdentifier.Value) as ItemPrefab ?? throw new Exception($"No ItemPrefab with identifier or name \"{ItemPrefabIdentifier}\"");
public override UInt32 UintIdentifier { get; }
public override IEnumerable<ItemPrefab> ItemPrefabs => ItemPrefab.ToEnumerable();
public override ItemPrefab FirstMatchingPrefab => ItemPrefab;
public override bool MatchesItem(Item item)
{
return item?.Prefab.Identifier == ItemPrefabIdentifier;
}
public RequiredItemByIdentifier(Identifier itemPrefab, int amount, float minCondition, float maxCondition, bool useCondition) : base(amount, minCondition, maxCondition, useCondition)
{
ItemPrefabIdentifier = itemPrefab;
@@ -109,10 +127,19 @@ namespace Barotrauma
public class RequiredItemByTag : RequiredItem
{
public readonly Identifier Tag;
public override UInt32 UintIdentifier { get; }
public override IEnumerable<ItemPrefab> ItemPrefabs => ItemPrefab.Prefabs.Where(p => p.Tags.Contains(Tag));
public override ItemPrefab FirstMatchingPrefab => ItemPrefab.Prefabs.FirstOrDefault(p => p.Tags.Contains(Tag));
public override bool MatchesItem(Item item)
{
if (item == null) { return false; }
return item.HasTag(Tag);
}
public RequiredItemByTag(Identifier tag, int amount, float minCondition, float maxCondition, bool useCondition) : base(amount, minCondition, maxCondition, useCondition)
{
Tag = tag;
@@ -208,10 +235,10 @@ namespace Barotrauma
if (requiredItemIdentifier != Identifier.Empty)
{
var existing = requiredItems.FindIndex(r =>
r is RequiredItemByIdentifier ri &&
ri.ItemPrefabIdentifier == requiredItemIdentifier &&
MathUtils.NearlyEqual(r.MinCondition, minCondition) &&
MathUtils.NearlyEqual(r.MaxCondition, maxCondition));
r is RequiredItemByIdentifier ri &&
ri.ItemPrefabIdentifier == requiredItemIdentifier &&
MathUtils.NearlyEqual(r.MinCondition, minCondition) &&
MathUtils.NearlyEqual(r.MaxCondition, maxCondition));
if (existing >= 0)
{
amount += requiredItems[existing].Amount;
@@ -222,10 +249,10 @@ namespace Barotrauma
else
{
var existing = requiredItems.FindIndex(r =>
r is RequiredItemByTag rt &&
rt.Tag == requiredItemTag &&
MathUtils.NearlyEqual(r.MinCondition, minCondition) &&
MathUtils.NearlyEqual(r.MaxCondition, maxCondition));
r is RequiredItemByTag rt &&
rt.Tag == requiredItemTag &&
MathUtils.NearlyEqual(r.MinCondition, minCondition) &&
MathUtils.NearlyEqual(r.MaxCondition, maxCondition));
if (existing >= 0)
{
amount += requiredItems[existing].Amount;
@@ -783,19 +810,12 @@ namespace Barotrauma
//works the same as nameIdentifier, but just replaces the description
Identifier descriptionIdentifier = ConfigElement.GetAttributeIdentifier("descriptionidentifier", "");
if (string.IsNullOrEmpty(OriginalName))
{
name = TextManager.Get(nameIdentifier.IsEmpty
? $"EntityName.{Identifier}"
: $"EntityName.{nameIdentifier}",
$"EntityName.{fallbackNameIdentifier}");
}
else if (Category.HasFlag(MapEntityCategory.Legacy))
{
// Legacy items use names as identifiers, so we have to define them in the xml. But we also want to support the translations. Therefore
name = TextManager.Get(nameIdentifier.IsEmpty
name = TextManager.Get(nameIdentifier.IsEmpty
? $"EntityName.{Identifier}"
: $"EntityName.{nameIdentifier}");
: $"EntityName.{nameIdentifier}",
$"EntityName.{fallbackNameIdentifier}");
if (!string.IsNullOrEmpty(OriginalName))
{
name = name.Fallback(OriginalName);
}
@@ -838,20 +858,17 @@ namespace Barotrauma
SerializableProperty.DeserializeProperties(this, ConfigElement);
if (Description.IsNullOrEmpty())
if (descriptionIdentifier != Identifier.Empty)
{
if (descriptionIdentifier != Identifier.Empty)
{
Description = TextManager.Get($"EntityDescription.{descriptionIdentifier}");
}
else if (nameIdentifier == Identifier.Empty)
{
Description = TextManager.Get($"EntityDescription.{Identifier}");
}
else
{
Description = TextManager.Get($"EntityDescription.{nameIdentifier}");
}
Description = TextManager.Get($"EntityDescription.{descriptionIdentifier}").Fallback(Description);
}
else if (nameIdentifier == Identifier.Empty)
{
Description = TextManager.Get($"EntityDescription.{Identifier}").Fallback(Description);
}
else
{
Description = TextManager.Get($"EntityDescription.{nameIdentifier}").Fallback(Description);
}
var allowDroppingOnSwapWith = ConfigElement.GetAttributeIdentifierArray("allowdroppingonswapwith", Array.Empty<Identifier>());
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Xml.Linq;
@@ -22,7 +23,7 @@ namespace Barotrauma
public bool IgnoreInEditor { get; set; }
private Identifier[] excludedIdentifiers;
private ImmutableHashSet<Identifier> excludedIdentifiers;
private RelationType type;
@@ -60,11 +61,11 @@ namespace Barotrauma
{
if (value == null) return;
Identifiers = value.Split(',').Select(s => s.Trim()).ToIdentifiers().ToArray();
Identifiers = value.Split(',').Select(s => s.Trim()).ToIdentifiers().ToImmutableHashSet();
}
}
public Identifier[] Identifiers { get; private set; }
public ImmutableHashSet<Identifier> Identifiers { get; private set; }
public string JoinedExcludedIdentifiers
{
@@ -73,27 +74,53 @@ namespace Barotrauma
{
if (value == null) return;
excludedIdentifiers = value.Split(',').Select(s => s.Trim()).ToIdentifiers().ToArray();
excludedIdentifiers = value.Split(',').Select(s => s.Trim()).ToIdentifiers().ToImmutableHashSet();
}
}
public bool MatchesItem(Item item)
{
if (item == null) { return false; }
if (excludedIdentifiers.Any(id => item.Prefab.Identifier == id || item.HasTag(id))) { return false; }
return Identifiers.Any(id => item.Prefab.Identifier == id || item.HasTag(id) || (AllowVariants && !item.Prefab.VariantOf.IsEmpty && item.Prefab.VariantOf == id));
if (excludedIdentifiers.Contains(item.Prefab.Identifier)) { return false; }
foreach (var excludedIdentifier in excludedIdentifiers)
{
if (item.HasTag(excludedIdentifier)) { return false; }
}
if (Identifiers.Contains(item.Prefab.Identifier)) { return true; }
foreach (var identifier in Identifiers)
{
if (item.HasTag(identifier)) { return true; }
}
if (AllowVariants && !item.Prefab.VariantOf.IsEmpty)
{
if (Identifiers.Contains(item.Prefab.VariantOf)) { return true; }
}
return false;
}
public bool MatchesItem(ItemPrefab itemPrefab)
{
if (itemPrefab == null) { return false; }
if (excludedIdentifiers.Any(id => itemPrefab.Identifier == id || itemPrefab.Tags.Contains(id))) { return false; }
return Identifiers.Any(id => itemPrefab.Identifier == id || itemPrefab.Tags.Contains(id) || (AllowVariants && !itemPrefab.VariantOf.IsEmpty && itemPrefab.VariantOf == id));
if (excludedIdentifiers.Contains(itemPrefab.Identifier)) { return false; }
foreach (var excludedIdentifier in excludedIdentifiers)
{
if (itemPrefab.Tags.Contains(excludedIdentifier)) { return false; }
}
if (Identifiers.Contains(itemPrefab.Identifier)) { return true; }
foreach (var identifier in Identifiers)
{
if (itemPrefab.Tags.Contains(identifier)) { return true; }
}
if (AllowVariants && !itemPrefab.VariantOf.IsEmpty)
{
if (Identifiers.Contains(itemPrefab.VariantOf)) { return true; }
}
return false;
}
public RelatedItem(Identifier[] identifiers, Identifier[] excludedIdentifiers)
{
this.Identifiers = identifiers.Select(id => id.Value.Trim().ToIdentifier()).ToArray();
this.excludedIdentifiers = excludedIdentifiers.Select(id => id.Value.Trim().ToIdentifier()).ToArray();
this.Identifiers = identifiers.Select(id => id.Value.Trim().ToIdentifier()).ToImmutableHashSet();
this.excludedIdentifiers = excludedIdentifiers.Select(id => id.Value.Trim().ToIdentifier()).ToImmutableHashSet();
statusEffects = new List<StatusEffect>();
}
@@ -161,7 +188,7 @@ namespace Barotrauma
new XAttribute("targetslot", TargetSlot),
new XAttribute("allowvariants", AllowVariants));
if (excludedIdentifiers.Length > 0)
if (excludedIdentifiers.Count > 0)
{
element.Add(new XAttribute("excludedidentifiers", JoinedExcludedIdentifiers));
}