Unstable 1.2.1.0
This commit is contained in:
@@ -48,13 +48,13 @@ namespace Barotrauma
|
||||
private set;
|
||||
}
|
||||
|
||||
private static string[] ParseSlotTypes(XElement element)
|
||||
private static string[] ParseSlotTypes(ContentXElement element)
|
||||
{
|
||||
string slotString = element.GetAttributeString("slots", null);
|
||||
return slotString == null ? Array.Empty<string>() : slotString.Split(',');
|
||||
}
|
||||
|
||||
public CharacterInventory(XElement element, Character character, bool spawnInitialItems)
|
||||
public CharacterInventory(ContentXElement element, Character character, bool spawnInitialItems)
|
||||
: base(character, ParseSlotTypes(element).Length)
|
||||
{
|
||||
this.character = character;
|
||||
@@ -73,7 +73,8 @@ namespace Barotrauma
|
||||
slotTypeNames[i] = slotTypeNames[i].Trim();
|
||||
if (!Enum.TryParse(slotTypeNames[i], out parsedSlotType))
|
||||
{
|
||||
DebugConsole.ThrowError("Error in the inventory config of \"" + character.SpeciesName + "\" - " + slotTypeNames[i] + " is not a valid inventory slot type.");
|
||||
DebugConsole.ThrowError("Error in the inventory config of \"" + character.SpeciesName + "\" - " + slotTypeNames[i] + " is not a valid inventory slot type.",
|
||||
contentPackage: element.ContentPackage);
|
||||
}
|
||||
SlotTypes[i] = parsedSlotType;
|
||||
switch (SlotTypes[i])
|
||||
@@ -99,7 +100,8 @@ namespace Barotrauma
|
||||
DebugConsole.ThrowError(
|
||||
$"Character \"{character.SpeciesName}\" is configured to spawn with so many items it will have less than 2 free inventory slots. " +
|
||||
"This can cause issues with talents that spawn extra loot in monsters' inventories."
|
||||
+ " Consider increasing the inventory size.");
|
||||
+ " Consider increasing the inventory size.",
|
||||
contentPackage: element.ContentPackage);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -115,7 +117,8 @@ namespace Barotrauma
|
||||
string itemIdentifier = subElement.GetAttributeString("identifier", "");
|
||||
if (!ItemPrefab.Prefabs.TryGet(itemIdentifier, out var itemPrefab))
|
||||
{
|
||||
DebugConsole.ThrowError("Error in character inventory \"" + character.SpeciesName + "\" - item \"" + itemIdentifier + "\" not found.");
|
||||
DebugConsole.ThrowError("Error in character inventory \"" + character.SpeciesName + "\" - item \"" + itemIdentifier + "\" not found.",
|
||||
contentPackage: element.ContentPackage);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -131,7 +134,7 @@ namespace Barotrauma
|
||||
if (item != null && item.ParentInventory != this)
|
||||
{
|
||||
string errorMsg = $"Failed to spawn the initial item \"{item.Prefab.Identifier}\" in the inventory of \"{character.SpeciesName}\".";
|
||||
DebugConsole.ThrowError(errorMsg);
|
||||
DebugConsole.ThrowError(errorMsg, contentPackage: element.ContentPackage);
|
||||
GameAnalyticsManager.AddErrorEventOnce("CharacterInventory:FailedToSpawnInitialItem", GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
|
||||
}
|
||||
else if (!character.Enabled)
|
||||
|
||||
@@ -184,6 +184,8 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
public bool IsFullyClosed => IsClosed && OpenState <= 0f;
|
||||
|
||||
public bool HasWindow => Window != Rectangle.Empty;
|
||||
|
||||
[Serialize(false, IsPropertySaveable.No, description: "If the door has integrated buttons, it can be opened by interacting with it directly (instead of using buttons wired to it).")]
|
||||
public bool HasIntegratedButtons { get; private set; }
|
||||
|
||||
@@ -381,6 +383,31 @@ namespace Barotrauma.Items.Components
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Is the given position inside the vertical bounds of the window, and roughly on the door horizontally? Or the other way around if the door opens horizontally.
|
||||
/// </summary>
|
||||
/// <param name="position">Position in the same coordinate space as the door.</param>
|
||||
/// <param name="maxPerpendicularDistance">Maximum horizontal distance from the door (or vertical if the door opens horizontally)</param>
|
||||
public bool IsPositionOnWindow(Vector2 position, float maxPerpendicularDistance = 10.0f)
|
||||
{
|
||||
if (IsHorizontal)
|
||||
{
|
||||
return
|
||||
position.X >= item.Rect.X + Window.X &&
|
||||
position.X <= item.Rect.X + Window.X + Window.Width &&
|
||||
position.Y >= item.Rect.Y - maxPerpendicularDistance &&
|
||||
position.Y <= item.Rect.Y - item.Rect.Height - maxPerpendicularDistance;
|
||||
}
|
||||
else
|
||||
{
|
||||
return
|
||||
position.Y >= item.Rect.Y + Window.Y &&
|
||||
position.Y <= item.Rect.Y + Window.Y + Window.Height &&
|
||||
position.X >= item.Rect.X - maxPerpendicularDistance &&
|
||||
position.Y <= item.Rect.Right + maxPerpendicularDistance;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Update(float deltaTime, Camera cam)
|
||||
{
|
||||
UpdateProjSpecific(deltaTime);
|
||||
|
||||
@@ -226,7 +226,8 @@ namespace Barotrauma.Items.Components
|
||||
foreach ((Character character, Node node) in charactersInRange)
|
||||
{
|
||||
if (character == null || character.Removed) { continue; }
|
||||
character.ApplyAttack(user, node.WorldPosition, attack, MathHelper.Clamp(Voltage, 1.0f, MaxOverVoltageFactor));
|
||||
character.ApplyAttack(user, node.WorldPosition, attack, MathHelper.Clamp(Voltage, 1.0f, MaxOverVoltageFactor),
|
||||
impulseDirection: character.WorldPosition - node.WorldPosition);
|
||||
}
|
||||
}
|
||||
DischargeProjSpecific();
|
||||
|
||||
@@ -168,8 +168,8 @@ namespace Barotrauma.Items.Components
|
||||
conditionIncrease += user?.GetStatValue(StatTypes.GeneticMaterialRefineBonus) ?? 0.0f;
|
||||
if (item.Prefab == otherGeneticMaterial.item.Prefab)
|
||||
{
|
||||
float taintedProbability = GetTaintedProbabilityOnRefine(otherGeneticMaterial, user);
|
||||
item.Condition = Math.Max(item.Condition, otherGeneticMaterial.item.Condition) + conditionIncrease;
|
||||
float taintedProbability = GetTaintedProbabilityOnRefine(user);
|
||||
if (taintedProbability >= Rand.Range(0.0f, 1.0f))
|
||||
{
|
||||
MakeTainted();
|
||||
@@ -221,10 +221,10 @@ namespace Barotrauma.Items.Components
|
||||
return taintedEffectStrength;
|
||||
}
|
||||
|
||||
private float GetTaintedProbabilityOnRefine(Character user)
|
||||
private float GetTaintedProbabilityOnRefine(GeneticMaterial otherGeneticMaterial, Character user)
|
||||
{
|
||||
if (user == null) { return 1.0f; }
|
||||
float probability = MathHelper.Lerp(0.0f, 0.99f, item.Condition / 100.0f);
|
||||
float probability = MathHelper.Lerp(0.0f, 0.99f, Math.Max(item.Condition, otherGeneticMaterial.Item.Condition) / 100.0f);
|
||||
probability *= MathHelper.Lerp(1.0f, 0.25f, DegreeOfSuccess(user));
|
||||
return MathHelper.Clamp(probability, 0.0f, 1.0f);
|
||||
}
|
||||
|
||||
@@ -59,7 +59,8 @@ namespace Barotrauma.Items.Components
|
||||
StatusEffect effect = StatusEffect.Load(subElement, Prefab?.Name.Value);
|
||||
if (effect.type != ActionType.OnProduceSpawned)
|
||||
{
|
||||
DebugConsole.ThrowError("Only OnProduceSpawned type can be used in <ProducedItem>.");
|
||||
DebugConsole.ThrowError("Only OnProduceSpawned type can be used in <ProducedItem>.",
|
||||
contentPackage: element.ContentPackage);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -134,7 +134,8 @@ namespace Barotrauma.Items.Components
|
||||
suitableProjectiles = element.GetAttributeIdentifierArray(nameof(suitableProjectiles), Array.Empty<Identifier>()).ToHashSet();
|
||||
if (ReloadSkillRequirement > 0 && ReloadNoSkill <= reload)
|
||||
{
|
||||
DebugConsole.AddWarning($"Invalid XML at {item.Name}: ReloadNoSkill is lower or equal than it's reload skill, despite having ReloadSkillRequirement.");
|
||||
DebugConsole.AddWarning($"Invalid XML at {item.Name}: ReloadNoSkill is lower or equal than it's reload skill, despite having ReloadSkillRequirement.",
|
||||
item.Prefab.ContentPackage);
|
||||
}
|
||||
InitProjSpecific(element);
|
||||
}
|
||||
|
||||
@@ -137,7 +137,8 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
if (element.GetAttribute("limbfixamount") != null)
|
||||
{
|
||||
DebugConsole.ThrowError("Error in item \"" + item.Name + "\" - RepairTool damage should be configured using a StatusEffect with Afflictions, not the limbfixamount attribute.");
|
||||
DebugConsole.ThrowError("Error in item \"" + item.Name + "\" - RepairTool damage should be configured using a StatusEffect with Afflictions, not the limbfixamount attribute.",
|
||||
contentPackage: element.ContentPackage);
|
||||
}
|
||||
|
||||
fixableEntities = new HashSet<Identifier>();
|
||||
@@ -149,7 +150,8 @@ namespace Barotrauma.Items.Components
|
||||
case "fixable":
|
||||
if (subElement.GetAttribute("name") != null)
|
||||
{
|
||||
DebugConsole.ThrowError("Error in RepairTool " + item.Name + " - use identifiers instead of names to configure fixable entities.");
|
||||
DebugConsole.ThrowError("Error in RepairTool " + item.Name + " - use identifiers instead of names to configure fixable entities.",
|
||||
contentPackage: element.ContentPackage);
|
||||
fixableEntities.Add(subElement.GetAttribute("name").Value.ToIdentifier());
|
||||
}
|
||||
else
|
||||
@@ -536,7 +538,7 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
Vector2 displayPos = ConvertUnits.ToDisplayUnits(rayStart + (rayEnd - rayStart) * lastPickedFraction * 0.9f);
|
||||
if (item.CurrentHull.Submarine != null) { displayPos += item.CurrentHull.Submarine.Position; }
|
||||
new FireSource(displayPos);
|
||||
new FireSource(displayPos, sourceCharacter: user);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
if (aimPos == Vector2.Zero)
|
||||
{
|
||||
aimPos = new Vector2(0.6f, 0.1f);
|
||||
aimPos = new Vector2(0.45f, 0.1f);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -71,6 +71,18 @@ namespace Barotrauma.Items.Components
|
||||
protected const float CorrectionDelay = 1.0f;
|
||||
protected CoroutineHandle delayedCorrectionCoroutine;
|
||||
|
||||
/// <summary>
|
||||
/// If enabled, the contents of the item are not transferred when the player transfers items between subs.
|
||||
/// Use this if this component uses item containers in a way where removing the item from the container via external means would cause problems.
|
||||
/// </summary>
|
||||
public virtual bool DontTransferInventoryBetweenSubs => false;
|
||||
|
||||
/// <summary>
|
||||
/// If enabled, the items inside any of the item containers on this item cannot be sold at an outpost.
|
||||
/// Use in similar cases as <see cref="DontTransferInventoryBetweenSubs"/>.
|
||||
/// </summary>
|
||||
public virtual bool DisallowSellingItemsFromContainer => false;
|
||||
|
||||
[Editable, Serialize(0.0f, IsPropertySaveable.No, description: "How long it takes to pick up the item (in seconds).")]
|
||||
public float PickingTime
|
||||
{
|
||||
@@ -285,7 +297,8 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
DebugConsole.ThrowError("Invalid select key in " + element + "!", e);
|
||||
DebugConsole.ThrowError("Invalid select key in " + element + "!", e,
|
||||
contentPackage: element.ContentPackage);
|
||||
}
|
||||
|
||||
PickKey = InputType.Select;
|
||||
@@ -298,7 +311,8 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
DebugConsole.ThrowError("Invalid pick key in " + element + "!", e);
|
||||
DebugConsole.ThrowError("Invalid pick key in " + element + "!", e,
|
||||
contentPackage: element.ContentPackage);
|
||||
}
|
||||
|
||||
SerializableProperties = SerializableProperty.DeserializeProperties(this, element);
|
||||
@@ -310,7 +324,8 @@ namespace Barotrauma.Items.Components
|
||||
var component = item.Components.Find(ic => ic.Name.Equals(inheritRequiredSkillsFrom, StringComparison.OrdinalIgnoreCase));
|
||||
if (component == null)
|
||||
{
|
||||
DebugConsole.ThrowError($"Error in item \"{item.Name}\" - component \"{name}\" is set to inherit its required skills from \"{inheritRequiredSkillsFrom}\", but a component of that type couldn't be found.");
|
||||
DebugConsole.ThrowError($"Error in item \"{item.Name}\" - component \"{name}\" is set to inherit its required skills from \"{inheritRequiredSkillsFrom}\", but a component of that type couldn't be found.",
|
||||
contentPackage: element.ContentPackage);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -325,7 +340,8 @@ namespace Barotrauma.Items.Components
|
||||
var component = item.Components.Find(ic => ic.Name.Equals(inheritStatusEffectsFrom, StringComparison.OrdinalIgnoreCase));
|
||||
if (component == null)
|
||||
{
|
||||
DebugConsole.ThrowError($"Error in item \"{item.Name}\" - component \"{name}\" is set to inherit its StatusEffects from \"{inheritStatusEffectsFrom}\", but a component of that type couldn't be found.");
|
||||
DebugConsole.ThrowError($"Error in item \"{item.Name}\" - component \"{name}\" is set to inherit its StatusEffects from \"{inheritStatusEffectsFrom}\", but a component of that type couldn't be found.",
|
||||
contentPackage: element.ContentPackage);
|
||||
}
|
||||
else if (component.statusEffectLists != null)
|
||||
{
|
||||
@@ -360,7 +376,8 @@ namespace Barotrauma.Items.Components
|
||||
case "requiredskills":
|
||||
if (subElement.GetAttribute("name") != null)
|
||||
{
|
||||
DebugConsole.ThrowError("Error in item config \"" + item.ConfigFilePath + "\" - skill requirement in component " + GetType().ToString() + " should use a skill identifier instead of the name of the skill.");
|
||||
DebugConsole.ThrowError("Error in item config \"" + item.ConfigFilePath + "\" - skill requirement in component " + GetType().ToString() + " should use a skill identifier instead of the name of the skill.",
|
||||
contentPackage: element.ContentPackage);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -426,7 +443,8 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
else if (!allowEmpty)
|
||||
{
|
||||
DebugConsole.ThrowError("Error in item config \"" + item.ConfigFilePath + "\" - component " + GetType().ToString() + " requires an item with no identifiers.");
|
||||
DebugConsole.ThrowError("Error in item config \"" + item.ConfigFilePath + "\" - component " + GetType().ToString() + " requires an item with no identifiers.",
|
||||
contentPackage: element.ContentPackage);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -968,7 +986,8 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
if (errorMessages)
|
||||
{
|
||||
DebugConsole.ThrowError($"Could not find the component \"{typeName}\" ({item.Prefab.ContentFile.Path})");
|
||||
DebugConsole.ThrowError($"Could not find the component \"{typeName}\" ({item.Prefab.ContentFile.Path})",
|
||||
contentPackage: element.ContentPackage);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -977,7 +996,8 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
if (errorMessages)
|
||||
{
|
||||
DebugConsole.ThrowError($"Could not find the component \"{typeName}\" ({item.Prefab.ContentFile.Path})", e);
|
||||
DebugConsole.ThrowError($"Could not find the component \"{typeName}\" ({item.Prefab.ContentFile.Path})", e,
|
||||
contentPackage: element.ContentPackage);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -990,14 +1010,16 @@ namespace Barotrauma.Items.Components
|
||||
if (constructor == null)
|
||||
{
|
||||
DebugConsole.ThrowError(
|
||||
$"Could not find the constructor of the component \"{typeName}\" ({item.Prefab.ContentFile.Path})");
|
||||
$"Could not find the constructor of the component \"{typeName}\" ({item.Prefab.ContentFile.Path})",
|
||||
contentPackage: element.ContentPackage);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
DebugConsole.ThrowError(
|
||||
$"Could not find the constructor of the component \"{typeName}\" ({item.Prefab.ContentFile.Path})", e);
|
||||
$"Could not find the constructor of the component \"{typeName}\" ({item.Prefab.ContentFile.Path})", e,
|
||||
contentPackage: element.ContentPackage);
|
||||
return null;
|
||||
}
|
||||
ItemComponent ic = null;
|
||||
@@ -1010,7 +1032,7 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
catch (TargetInvocationException e)
|
||||
{
|
||||
DebugConsole.ThrowError($"Error while loading component of the type {type}.", e.InnerException);
|
||||
DebugConsole.ThrowError($"Error while loading component of the type {type}.", e.InnerException, contentPackage: element.ContentPackage);
|
||||
GameAnalyticsManager.AddErrorEventOnce(
|
||||
$"ItemComponent.Load:TargetInvocationException{item.Name}{element.Name}",
|
||||
GameAnalyticsManager.ErrorSeverity.Error,
|
||||
|
||||
@@ -284,7 +284,8 @@ namespace Barotrauma.Items.Components
|
||||
RelatedItem containable = RelatedItem.Load(subElement, returnEmpty: false, parentDebugName: item.Name);
|
||||
if (containable == null)
|
||||
{
|
||||
DebugConsole.ThrowError("Error in item config \"" + item.ConfigFilePath + "\" - containable with no identifiers.");
|
||||
DebugConsole.ThrowError("Error in item config \"" + item.ConfigFilePath + "\" - containable with no identifiers.",
|
||||
contentPackage: element.ContentPackage);
|
||||
continue;
|
||||
}
|
||||
ContainableItems ??= new List<RelatedItem>();
|
||||
@@ -321,7 +322,8 @@ namespace Barotrauma.Items.Components
|
||||
RelatedItem containable = RelatedItem.Load(subSubElement, returnEmpty: false, parentDebugName: item.Name);
|
||||
if (containable == null)
|
||||
{
|
||||
DebugConsole.ThrowError("Error in item config \"" + item.ConfigFilePath + "\" - containable with no identifiers.");
|
||||
DebugConsole.ThrowError("Error in item config \"" + item.ConfigFilePath + "\" - containable with no identifiers.",
|
||||
contentPackage: element.ContentPackage);
|
||||
continue;
|
||||
}
|
||||
subContainableItems.Add(containable);
|
||||
@@ -349,7 +351,8 @@ namespace Barotrauma.Items.Components
|
||||
RelatedItem containable = RelatedItem.Load(subElement, returnEmpty: false, parentDebugName: item.Name);
|
||||
if (containable == null)
|
||||
{
|
||||
DebugConsole.ThrowError("Error when loading containable restrictions for \"" + item.Name + "\" - containable with no identifiers.");
|
||||
DebugConsole.ThrowError("Error when loading containable restrictions for \"" + item.Name + "\" - containable with no identifiers.",
|
||||
contentPackage: element.ContentPackage);
|
||||
continue;
|
||||
}
|
||||
ContainableItems[containableIndex] = containable;
|
||||
|
||||
@@ -622,7 +622,7 @@ namespace Barotrauma.Items.Components
|
||||
return element;
|
||||
}
|
||||
|
||||
private void LoadLimbPositions(XElement element)
|
||||
private void LoadLimbPositions(ContentXElement element)
|
||||
{
|
||||
limbPositions.Clear();
|
||||
foreach (var subElement in element.Elements())
|
||||
@@ -631,7 +631,8 @@ namespace Barotrauma.Items.Components
|
||||
string limbStr = subElement.GetAttributeString("limb", "");
|
||||
if (!Enum.TryParse(subElement.GetAttribute("limb").Value, out LimbType limbType))
|
||||
{
|
||||
DebugConsole.ThrowError($"Error in item \"{item.Name}\" - {limbStr} is not a valid limb type.");
|
||||
DebugConsole.ThrowError($"Error in item \"{item.Name}\" - {limbStr} is not a valid limb type.",
|
||||
contentPackage: element.ContentPackage);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -101,7 +101,8 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
if (subElement.Name.ToString().Equals("fabricableitem", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
DebugConsole.ThrowError("Error in item " + item.Name + "! Fabrication recipes should be defined in the craftable item's xml, not in the fabricator.");
|
||||
DebugConsole.ThrowError("Error in item " + item.Name + "! Fabrication recipes should be defined in the craftable item's xml, not in the fabricator.",
|
||||
contentPackage: element.ContentPackage);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -119,12 +120,16 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
//the errors below may be caused by a mod overriding a base item instead of this one, log the package of the base item in that case
|
||||
var packageToLog = itemPrefab.GetParentModPackageOrThisPackage();
|
||||
|
||||
bool recipeInvalid = false;
|
||||
foreach (var requiredItem in recipe.RequiredItems)
|
||||
{
|
||||
if (requiredItem.ItemPrefabs.None())
|
||||
{
|
||||
DebugConsole.ThrowError($"Error in the fabrication recipe for \"{itemPrefab.Name}\". Could not find the ingredient \"{requiredItem}\".");
|
||||
DebugConsole.ThrowError($"Error in the fabrication recipe for \"{itemPrefab.Name}\". Could not find the ingredient \"{requiredItem}\".",
|
||||
contentPackage: packageToLog);
|
||||
recipeInvalid = true;
|
||||
}
|
||||
}
|
||||
@@ -132,7 +137,8 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
if (fabricationRecipes.TryGetValue(recipe.RecipeHash, out var duplicateRecipe))
|
||||
{
|
||||
DebugConsole.ThrowError($"Error in the fabrication recipe for \"{itemPrefab.Name}\". Duplicate recipe in \"{duplicateRecipe.TargetItem.Identifier}\".");
|
||||
DebugConsole.ThrowError($"Error in the fabrication recipe for \"{itemPrefab.Name}\". Duplicate recipe in \"{duplicateRecipe.TargetItem.Identifier}\".",
|
||||
contentPackage: packageToLog);
|
||||
continue;
|
||||
}
|
||||
fabricationRecipes.Add(recipe.RecipeHash, recipe);
|
||||
@@ -416,7 +422,7 @@ namespace Barotrauma.Items.Components
|
||||
if (requiredItem.UseCondition && suitableIngredient.ConditionPercentage - requiredItem.MinCondition * 100 > 0.0f)
|
||||
{
|
||||
suitableIngredient.Condition -= suitableIngredient.Prefab.Health * requiredItem.MinCondition;
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
if (suitableIngredient.OwnInventory != null)
|
||||
{
|
||||
|
||||
@@ -82,6 +82,9 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
private List<LightComponent>? lightComponents;
|
||||
|
||||
// We don't want the seeds to be transferred to a new submarine as seeds are not supposed to leave the container after they have been planted.
|
||||
public override bool DontTransferInventoryBetweenSubs => true;
|
||||
|
||||
public Planter(Item item, ContentXElement element) : base(item, element)
|
||||
{
|
||||
canBePicked = true;
|
||||
|
||||
@@ -407,7 +407,7 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
if (!(this is RelayComponent))
|
||||
if (this is not RelayComponent)
|
||||
{
|
||||
if (PowerConnections.Any(p => !p.IsOutput) && PowerConnections.Any(p => p.IsOutput))
|
||||
{
|
||||
|
||||
@@ -306,7 +306,8 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
if (item.body == null)
|
||||
{
|
||||
DebugConsole.ThrowError($"Error in projectile definition ({item.Name}): No body defined!");
|
||||
DebugConsole.ThrowError($"Error in projectile definition ({item.Name}): No body defined!",
|
||||
contentPackage: element.ContentPackage);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -60,7 +60,8 @@ namespace Barotrauma.Items.Components
|
||||
string statTypeString = subElement.GetAttributeString("stattype", "");
|
||||
if (!Enum.TryParse(statTypeString, true, out StatType statType))
|
||||
{
|
||||
DebugConsole.ThrowError("Invalid stat type type \"" + statTypeString + "\" in item (" + ((MapEntity)item).Prefab.Identifier + ")");
|
||||
DebugConsole.ThrowError("Invalid stat type type \"" + statTypeString + "\" in item (" + ((MapEntity)item).Prefab.Identifier + ")",
|
||||
contentPackage: element.ContentPackage);
|
||||
}
|
||||
float statValue = subElement.GetAttributeFloat("value", 0f);
|
||||
statValues.TryAdd(statType, statValue);
|
||||
|
||||
@@ -82,7 +82,8 @@ namespace Barotrauma.Items.Components
|
||||
Holdable = item.GetComponent<Holdable>();
|
||||
if (Holdable == null || !Holdable.Attachable)
|
||||
{
|
||||
DebugConsole.ThrowError("Error in initializing a Scanner component: an attachable Holdable component is required on the same item and none was found");
|
||||
DebugConsole.ThrowError("Error in initializing a Scanner component: an attachable Holdable component is required on the same item and none was found",
|
||||
contentPackage: item.Prefab.ContentPackage);
|
||||
IsActive = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,8 @@ namespace Barotrauma.Items.Components
|
||||
RequiredSignalCount = element.GetChildElements("TerminalButton").Count(c => c.GetAttribute("style") != null);
|
||||
if (RequiredSignalCount < 1)
|
||||
{
|
||||
DebugConsole.ThrowError($"Error in item \"{item.Name}\": no TerminalButton elements defined for the ButtonTerminal component!");
|
||||
DebugConsole.ThrowError($"Error in item \"{item.Name}\": no TerminalButton elements defined for the ButtonTerminal component!",
|
||||
contentPackage: element.ContentPackage);
|
||||
}
|
||||
InitProjSpecific(element);
|
||||
}
|
||||
|
||||
@@ -26,19 +26,40 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
public override bool IsActive => true;
|
||||
|
||||
// We don't want the components and wires to transfer between subs as it would cause issues.
|
||||
public override bool DontTransferInventoryBetweenSubs => true;
|
||||
|
||||
// We don't want to sell the components and wires inside the circuit box
|
||||
public override bool DisallowSellingItemsFromContainer => true;
|
||||
|
||||
public Option<CircuitBoxConnection> FindInputOutputConnection(Identifier connectionName)
|
||||
{
|
||||
foreach (CircuitBoxInputConnection input in Inputs)
|
||||
{
|
||||
if (input.Name != connectionName) { continue; }
|
||||
|
||||
return Option.Some<CircuitBoxConnection>(input);
|
||||
}
|
||||
|
||||
foreach (CircuitBoxOutputConnection output in Outputs)
|
||||
{
|
||||
if (output.Name != connectionName) { continue; }
|
||||
return Option.Some<CircuitBoxConnection>(output);
|
||||
}
|
||||
|
||||
return Option.None;
|
||||
}
|
||||
|
||||
public Option<CircuitBoxConnection> FindInputOutputConnection(Connection connection)
|
||||
{
|
||||
foreach (CircuitBoxInputConnection input in Inputs)
|
||||
{
|
||||
if (input.Connection != connection) { continue; }
|
||||
return Option.Some<CircuitBoxConnection>(input);
|
||||
}
|
||||
|
||||
foreach (CircuitBoxOutputConnection output in Outputs)
|
||||
{
|
||||
if (output.Connection != connection) { continue; }
|
||||
return Option.Some<CircuitBoxConnection>(output);
|
||||
}
|
||||
|
||||
@@ -338,7 +359,7 @@ namespace Barotrauma.Items.Components
|
||||
return;
|
||||
}
|
||||
|
||||
SpawnItem(this, prefab, WireContainer, wire =>
|
||||
SpawnItem(prefab, user: null, container: WireContainer, onSpawned: wire =>
|
||||
{
|
||||
AddWireDirect(wireId, prefab, Option.Some(wire), one, two);
|
||||
onItemSpawned(wire);
|
||||
@@ -359,7 +380,7 @@ namespace Barotrauma.Items.Components
|
||||
private void AddWireDirect(ushort id, ItemPrefab prefab, Option<Item> backingItem, CircuitBoxConnection one, CircuitBoxConnection two)
|
||||
=> Wires.Add(new CircuitBoxWire(this, id, backingItem, one, two, prefab));
|
||||
|
||||
private bool AddComponentInternal(ushort id, ItemPrefab prefab, ItemPrefab usedResource, Vector2 pos, Action<Item> onItemSpawned)
|
||||
private bool AddComponentInternal(ushort id, ItemPrefab prefab, ItemPrefab usedResource, Vector2 pos, Character? user, Action<Item>? onItemSpawned)
|
||||
{
|
||||
if (id is ICircuitBoxIdentifiable.NullComponentID)
|
||||
{
|
||||
@@ -373,12 +394,12 @@ namespace Barotrauma.Items.Components
|
||||
return false;
|
||||
}
|
||||
|
||||
SpawnItem(this, prefab, ComponentContainer, spawnedItem =>
|
||||
SpawnItem(prefab, user, ComponentContainer, spawnedItem =>
|
||||
{
|
||||
Components.Add(new CircuitBoxComponent(id, spawnedItem, pos, this, usedResource));
|
||||
onItemSpawned(spawnedItem);
|
||||
onItemSpawned?.Invoke(spawnedItem);
|
||||
OnViewUpdateProjSpecific();
|
||||
});
|
||||
|
||||
OnViewUpdateProjSpecific();
|
||||
return true;
|
||||
}
|
||||
@@ -646,7 +667,7 @@ namespace Barotrauma.Items.Components
|
||||
return Option.None;
|
||||
}
|
||||
|
||||
public static void SpawnItem(CircuitBox circuitBox, ItemPrefab prefab, ItemContainer? container, Action<Item> onSpawned)
|
||||
public static void SpawnItem(ItemPrefab prefab, Character? user, ItemContainer? container, Action<Item> onSpawned)
|
||||
{
|
||||
if (container is null)
|
||||
{
|
||||
@@ -655,13 +676,27 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
if (IsInGame())
|
||||
{
|
||||
Entity.Spawner?.AddItemToSpawnQueue(prefab, container.Inventory, onSpawned: onSpawned);
|
||||
Entity.Spawner?.AddItemToSpawnQueue(prefab, container.Inventory, onSpawned: it =>
|
||||
{
|
||||
AssignWifiComponentTeam(it, user);
|
||||
onSpawned(it);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
Item forceSpawnedItem = new Item(prefab, Vector2.Zero, null);
|
||||
container.Inventory.TryPutItem(forceSpawnedItem, null);
|
||||
onSpawned(forceSpawnedItem);
|
||||
AssignWifiComponentTeam(forceSpawnedItem, user);
|
||||
|
||||
static void AssignWifiComponentTeam(Item item, Character? user)
|
||||
{
|
||||
if (user == null) { return; }
|
||||
foreach (WifiComponent wifiComponent in item.GetComponents<WifiComponent>())
|
||||
{
|
||||
wifiComponent.TeamID = user.TeamID;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void RemoveItem(Item item)
|
||||
|
||||
@@ -97,7 +97,8 @@ namespace Barotrauma.Items.Components
|
||||
string triggeredByAttribute = element.GetAttributeString("triggeredby", "Character");
|
||||
if (!Enum.TryParse(triggeredByAttribute, out triggeredBy))
|
||||
{
|
||||
DebugConsole.ThrowError($"Error in ForceComponent config: \"{triggeredByAttribute}\" is not a valid triggerer type.");
|
||||
DebugConsole.ThrowError($"Error in ForceComponent config: \"{triggeredByAttribute}\" is not a valid triggerer type.",
|
||||
contentPackage: element.ContentPackage);
|
||||
}
|
||||
triggerOnce = element.GetAttributeBool("triggeronce", false);
|
||||
string parentDebugName = $"TriggerComponent in {item.Name}";
|
||||
|
||||
@@ -362,7 +362,8 @@ namespace Barotrauma.Items.Components
|
||||
case "sprite":
|
||||
if (subElement.GetAttribute("texture") == null)
|
||||
{
|
||||
DebugConsole.ThrowError("Item \"" + item.Name + "\" doesn't have a texture specified!");
|
||||
DebugConsole.ThrowError("Item \"" + item.Name + "\" doesn't have a texture specified!",
|
||||
contentPackage: element.ContentPackage);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -98,11 +98,11 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
/// <param name="maxStackSize">Defaults to <see cref="ItemPrefab.MaxStackSize"/> if null</param>
|
||||
public int HowManyCanBePut(ItemPrefab itemPrefab, int? maxStackSize = null, float? condition = null)
|
||||
public int HowManyCanBePut(ItemPrefab itemPrefab, int? maxStackSize = null, float? condition = null, bool ignoreItemsInSlot = false)
|
||||
{
|
||||
if (itemPrefab == null) { return 0; }
|
||||
maxStackSize ??= itemPrefab.GetMaxStackSize(inventory);
|
||||
if (items.Count > 0)
|
||||
if (items.Count > 0 && !ignoreItemsInSlot)
|
||||
{
|
||||
if (condition.HasValue)
|
||||
{
|
||||
@@ -517,10 +517,10 @@ namespace Barotrauma
|
||||
return count;
|
||||
}
|
||||
|
||||
public virtual int HowManyCanBePut(ItemPrefab itemPrefab, int i, float? condition)
|
||||
public virtual int HowManyCanBePut(ItemPrefab itemPrefab, int i, float? condition, bool ignoreItemsInSlot = false)
|
||||
{
|
||||
if (i < 0 || i >= slots.Length) { return 0; }
|
||||
return slots[i].HowManyCanBePut(itemPrefab, condition: condition);
|
||||
return slots[i].HowManyCanBePut(itemPrefab, condition: condition, ignoreItemsInSlot: ignoreItemsInSlot);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -240,7 +240,21 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public Item RootContainer { get; private set; }
|
||||
private Item rootContainer;
|
||||
public Item RootContainer
|
||||
{
|
||||
get { return rootContainer; }
|
||||
private set
|
||||
{
|
||||
if (value == this)
|
||||
{
|
||||
DebugConsole.ThrowError($"Attempted to set the item \"{Prefab.Identifier}\" as it's own root container!\n{Environment.StackTrace.CleanupStackTrace()}");
|
||||
rootContainer = null;
|
||||
return;
|
||||
}
|
||||
rootContainer = value;
|
||||
}
|
||||
}
|
||||
|
||||
private bool inWaterProofContainer;
|
||||
|
||||
@@ -443,7 +457,7 @@ namespace Barotrauma
|
||||
set
|
||||
{
|
||||
if (scale == value) { return; }
|
||||
scale = MathHelper.Clamp(value, 0.01f, 10.0f);
|
||||
scale = MathHelper.Clamp(value, Prefab.MinScale, Prefab.MaxScale);
|
||||
|
||||
float relativeScale = scale / base.Prefab.Scale;
|
||||
|
||||
@@ -862,7 +876,25 @@ namespace Barotrauma
|
||||
{
|
||||
get
|
||||
{
|
||||
return ownInventory?.AllItems ?? Enumerable.Empty<Item>();
|
||||
if (OwnInventories.Length < 2)
|
||||
{
|
||||
if (OwnInventory == null) { yield break; }
|
||||
|
||||
foreach (var item in OwnInventory.AllItems)
|
||||
{
|
||||
yield return item;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var inventory in OwnInventories)
|
||||
{
|
||||
foreach (var item in inventory.AllItems)
|
||||
{
|
||||
yield return item;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -871,6 +903,8 @@ namespace Barotrauma
|
||||
get { return ownInventory; }
|
||||
}
|
||||
|
||||
public readonly ImmutableArray<ItemInventory> OwnInventories = ImmutableArray<ItemInventory>.Empty;
|
||||
|
||||
[Editable, Serialize(false, IsPropertySaveable.Yes, description:
|
||||
"Enable if you want to display the item HUD side by side with another item's HUD, when linked together. " +
|
||||
"Disclaimer: It's possible or even likely that the views block each other, if they were not designed to be viewed together!")]
|
||||
@@ -1057,7 +1091,8 @@ namespace Barotrauma
|
||||
{
|
||||
if (!Physics.TryParseCollisionCategory(collisionCategoryStr, out Category cat))
|
||||
{
|
||||
DebugConsole.ThrowError("Invalid collision category in item \"" + Name + "\" (" + collisionCategoryStr + ")");
|
||||
DebugConsole.ThrowError("Invalid collision category in item \"" + Name + "\" (" + collisionCategoryStr + ")",
|
||||
contentPackage: element.ContentPackage);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1192,6 +1227,8 @@ namespace Barotrauma
|
||||
ownInventory = itemContainer.Inventory;
|
||||
}
|
||||
|
||||
OwnInventories = GetComponents<ItemContainer>().Select(ic => ic.Inventory).ToImmutableArray();
|
||||
|
||||
qualityComponent = GetComponent<Quality>();
|
||||
|
||||
IsLadder = GetComponent<Ladder>() != null;
|
||||
@@ -1210,7 +1247,8 @@ namespace Barotrauma
|
||||
var holdables = components.Where(c => c is Holdable);
|
||||
if (holdables.Count() > 1)
|
||||
{
|
||||
DebugConsole.AddWarning($"Item {Prefab.Identifier} has multiple {nameof(Holdable)} components ({string.Join(", ", holdables.Select(h => h.GetType().Name))}).");
|
||||
DebugConsole.AddWarning($"Item {Prefab.Identifier} has multiple {nameof(Holdable)} components ({string.Join(", ", holdables.Select(h => h.GetType().Name))}).",
|
||||
Prefab.ContentPackage);
|
||||
}
|
||||
|
||||
InsertToList();
|
||||
@@ -1654,6 +1692,12 @@ namespace Barotrauma
|
||||
while (rootContainer.Container != null)
|
||||
{
|
||||
rootContainer = rootContainer.Container;
|
||||
if (rootContainer == this)
|
||||
{
|
||||
DebugConsole.ThrowError($"Invalid container hierarchy: \"{Prefab.Identifier}\" was contained inside itself!\n{Environment.StackTrace.CleanupStackTrace()}");
|
||||
rootContainer = null;
|
||||
break;
|
||||
}
|
||||
inWaterProofContainer |= rootContainer.WaterProof;
|
||||
}
|
||||
newRootContainer = rootContainer;
|
||||
@@ -1916,7 +1960,7 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
|
||||
public AttackResult AddDamage(Character attacker, Vector2 worldPosition, Attack attack, float deltaTime, bool playSound = true)
|
||||
public AttackResult AddDamage(Character attacker, Vector2 worldPosition, Attack attack, Vector2 impulseDirection, float deltaTime,bool playSound = true)
|
||||
{
|
||||
if (Indestructible || InvulnerableToDamage) { return new AttackResult(); }
|
||||
|
||||
@@ -2533,8 +2577,7 @@ namespace Barotrauma
|
||||
foreach (Connection c in connectionPanel.Connections)
|
||||
{
|
||||
if (connectionFilter != null && !connectionFilter.Invoke(c)) { continue; }
|
||||
var recipients = c.Recipients;
|
||||
foreach (Connection recipient in recipients)
|
||||
foreach (Connection recipient in c.Recipients)
|
||||
{
|
||||
var component = recipient.Item.GetComponent<T>();
|
||||
if (component != null && !connectedComponents.Contains(component))
|
||||
@@ -2587,9 +2630,20 @@ namespace Barotrauma
|
||||
private void GetConnectedComponentsRecursive<T>(Connection c, HashSet<Connection> alreadySearched, List<T> connectedComponents, bool ignoreInactiveRelays, bool allowTraversingBackwards = true) where T : ItemComponent
|
||||
{
|
||||
alreadySearched.Add(c);
|
||||
|
||||
var recipients = c.Recipients;
|
||||
foreach (Connection recipient in recipients)
|
||||
static IEnumerable<Connection> GetRecipients(Connection c)
|
||||
{
|
||||
foreach (Connection recipient in c.Recipients)
|
||||
{
|
||||
yield return recipient;
|
||||
}
|
||||
//check circuit box inputs/outputs this connection is connected to
|
||||
foreach (var circuitBoxConnection in c.CircuitBoxConnections)
|
||||
{
|
||||
yield return circuitBoxConnection.Connection;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (Connection recipient in GetRecipients(c))
|
||||
{
|
||||
if (alreadySearched.Contains(recipient)) { continue; }
|
||||
var component = recipient.Item.GetComponent<T>();
|
||||
@@ -2598,23 +2652,53 @@ namespace Barotrauma
|
||||
connectedComponents.Add(component);
|
||||
}
|
||||
|
||||
//connected to a wifi component -> see which other wifi components it can communicate with
|
||||
var wifiComponent = recipient.Item.GetComponent<WifiComponent>();
|
||||
if (wifiComponent != null && wifiComponent.CanTransmit())
|
||||
var circuitBox = recipient.Item.GetComponent<CircuitBox>();
|
||||
if (circuitBox != null)
|
||||
{
|
||||
foreach (var wifiReceiver in wifiComponent.GetTransmittersInRange())
|
||||
//if this is a circuit box, check what the connection is connected to inside the box
|
||||
var potentialCbConnection = circuitBox.FindInputOutputConnection(recipient);
|
||||
if (potentialCbConnection.TryUnwrap(out var cbConnection))
|
||||
{
|
||||
var receiverConnections = wifiReceiver.Item.Connections;
|
||||
if (receiverConnections == null) { continue; }
|
||||
foreach (Connection wifiOutput in receiverConnections)
|
||||
if (cbConnection is CircuitBoxInputConnection inputConnection)
|
||||
{
|
||||
if ((wifiOutput.IsOutput == recipient.IsOutput) || alreadySearched.Contains(wifiOutput)) { continue; }
|
||||
GetConnectedComponentsRecursive(wifiOutput, alreadySearched, connectedComponents, ignoreInactiveRelays, allowTraversingBackwards);
|
||||
foreach (var connectedTo in inputConnection.ExternallyConnectedTo)
|
||||
{
|
||||
if (alreadySearched.Contains(connectedTo.Connection)) { continue; }
|
||||
CheckRecipient(connectedTo.Connection);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var connectedFrom in cbConnection.ExternallyConnectedFrom)
|
||||
{
|
||||
if (alreadySearched.Contains(connectedFrom.Connection) || !allowTraversingBackwards) { continue; }
|
||||
CheckRecipient(connectedFrom.Connection);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
CheckRecipient(recipient);
|
||||
|
||||
recipient.Item.GetConnectedComponentsRecursive(recipient, alreadySearched, connectedComponents, ignoreInactiveRelays, allowTraversingBackwards);
|
||||
void CheckRecipient(Connection recipient)
|
||||
{
|
||||
//connected to a wifi component -> see which other wifi components it can communicate with
|
||||
var wifiComponent = recipient.Item.GetComponent<WifiComponent>();
|
||||
if (wifiComponent != null && wifiComponent.CanTransmit())
|
||||
{
|
||||
foreach (var wifiReceiver in wifiComponent.GetTransmittersInRange())
|
||||
{
|
||||
var receiverConnections = wifiReceiver.Item.Connections;
|
||||
if (receiverConnections == null) { continue; }
|
||||
foreach (Connection wifiOutput in receiverConnections)
|
||||
{
|
||||
if ((wifiOutput.IsOutput == recipient.IsOutput) || alreadySearched.Contains(wifiOutput)) { continue; }
|
||||
GetConnectedComponentsRecursive(wifiOutput, alreadySearched, connectedComponents, ignoreInactiveRelays, allowTraversingBackwards);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
recipient.Item.GetConnectedComponentsRecursive(recipient, alreadySearched, connectedComponents, ignoreInactiveRelays, allowTraversingBackwards);
|
||||
}
|
||||
}
|
||||
|
||||
if (ignoreInactiveRelays)
|
||||
|
||||
@@ -58,12 +58,12 @@ namespace Barotrauma
|
||||
return itemPrefab != null && slots[i].CanBePut(itemPrefab, condition, quality) && slots[i].Items.Count < container.GetMaxStackSize(i);
|
||||
}
|
||||
|
||||
public override int HowManyCanBePut(ItemPrefab itemPrefab, int i, float? condition)
|
||||
public override int HowManyCanBePut(ItemPrefab itemPrefab, int i, float? condition, bool ignoreItemsInSlot = false)
|
||||
{
|
||||
if (itemPrefab == null) { return 0; }
|
||||
if (i < 0 || i >= slots.Length) { return 0; }
|
||||
if (!container.CanBeContained(itemPrefab, i)) { return 0; }
|
||||
return slots[i].HowManyCanBePut(itemPrefab, maxStackSize: Math.Min(itemPrefab.GetMaxStackSize(this), container.GetMaxStackSize(i)), condition);
|
||||
return slots[i].HowManyCanBePut(itemPrefab, maxStackSize: Math.Min(itemPrefab.GetMaxStackSize(this), container.GetMaxStackSize(i)), condition, ignoreItemsInSlot);
|
||||
}
|
||||
|
||||
public override bool IsFull(bool takeStacksIntoAccount = false)
|
||||
|
||||
@@ -229,7 +229,7 @@ namespace Barotrauma
|
||||
/// </summary>
|
||||
public readonly int FabricationLimitMin, FabricationLimitMax;
|
||||
|
||||
public FabricationRecipe(XElement element, Identifier itemPrefab)
|
||||
public FabricationRecipe(ContentXElement element, Identifier itemPrefab)
|
||||
{
|
||||
TargetItemPrefabIdentifier = itemPrefab;
|
||||
var displayNameIdentifier = element.GetAttributeIdentifier("displayname", "");
|
||||
@@ -245,7 +245,8 @@ namespace Barotrauma
|
||||
OutCondition = element.GetAttributeFloat("outcondition", 1.0f);
|
||||
if (OutCondition > 1.0f)
|
||||
{
|
||||
DebugConsole.AddWarning($"Error in \"{itemPrefab}\"'s fabrication recipe: out condition is above 100% ({OutCondition * 100}).");
|
||||
DebugConsole.AddWarning($"Error in \"{itemPrefab}\"'s fabrication recipe: out condition is above 100% ({OutCondition * 100}).",
|
||||
element.ContentPackage);
|
||||
}
|
||||
var requiredItems = new List<RequiredItem>();
|
||||
RequiresRecipe = element.GetAttributeBool("requiresrecipe", false);
|
||||
@@ -267,9 +268,10 @@ namespace Barotrauma
|
||||
switch (subElement.Name.ToString().ToLowerInvariant())
|
||||
{
|
||||
case "requiredskill":
|
||||
if (subElement.Attribute("name") != null)
|
||||
if (subElement.GetAttribute("name") != null)
|
||||
{
|
||||
DebugConsole.ThrowError("Error in fabricable item " + itemPrefab + "! Use skill identifiers instead of names.");
|
||||
DebugConsole.ThrowError("Error in fabricable item " + itemPrefab + "! Use skill identifiers instead of names.",
|
||||
contentPackage: element.ContentPackage);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -283,7 +285,8 @@ namespace Barotrauma
|
||||
Identifier requiredItemTag = subElement.GetAttributeIdentifier("tag", Identifier.Empty);
|
||||
if (requiredItemIdentifier == Identifier.Empty && requiredItemTag == Identifier.Empty)
|
||||
{
|
||||
DebugConsole.ThrowError("Error in fabricable item " + itemPrefab + "! One of the required items has no identifier or tag.");
|
||||
DebugConsole.ThrowError("Error in fabricable item " + itemPrefab + "! One of the required items has no identifier or tag.",
|
||||
contentPackage: element.ContentPackage);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -819,7 +822,7 @@ namespace Barotrauma
|
||||
[Serialize(null, IsPropertySaveable.No)]
|
||||
public string EquipConfirmationText { get; set; }
|
||||
|
||||
[Serialize(true, IsPropertySaveable.No, description: "Can the item be rotated in the submarine editor.")]
|
||||
[Serialize(true, IsPropertySaveable.No, description: "Can the item be rotated in the submarine editor?")]
|
||||
public bool AllowRotatingInEditor { get; set; }
|
||||
|
||||
[Serialize(false, IsPropertySaveable.No)]
|
||||
@@ -830,7 +833,13 @@ namespace Barotrauma
|
||||
|
||||
[Serialize(true, IsPropertySaveable.No)]
|
||||
public bool CanFlipY { get; private set; }
|
||||
|
||||
|
||||
[Serialize(0.1f, IsPropertySaveable.No)]
|
||||
public float MinScale { get; private set; }
|
||||
|
||||
[Serialize(10.0f, IsPropertySaveable.No)]
|
||||
public float MaxScale { get; private set; }
|
||||
|
||||
[Serialize(false, IsPropertySaveable.No)]
|
||||
public bool IsDangerous { get; private set; }
|
||||
|
||||
@@ -843,7 +852,7 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
private int maxStackSizeCharacterInventory;
|
||||
[Serialize(-1, IsPropertySaveable.No)]
|
||||
[Serialize(-1, IsPropertySaveable.No, description: "Maximum stack size when the item is in a character inventory.")]
|
||||
public int MaxStackSizeCharacterInventory
|
||||
{
|
||||
get { return maxStackSizeCharacterInventory; }
|
||||
@@ -851,7 +860,9 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
private int maxStackSizeHoldableOrWearableInventory;
|
||||
[Serialize(-1, IsPropertySaveable.No)]
|
||||
[Serialize(-1, IsPropertySaveable.No, description:
|
||||
"Maximum stack size when the item is inside a holdable or wearable item. "+
|
||||
"If not set, defaults to MaxStackSizeCharacterInventory.")]
|
||||
public int MaxStackSizeHoldableOrWearableInventory
|
||||
{
|
||||
get { return maxStackSizeHoldableOrWearableInventory; }
|
||||
@@ -864,15 +875,20 @@ namespace Barotrauma
|
||||
{
|
||||
return maxStackSizeCharacterInventory;
|
||||
}
|
||||
else if (maxStackSizeHoldableOrWearableInventory > 0 &&
|
||||
inventory?.Owner is Item item && (item.GetComponent<Holdable>() != null || item.GetComponent<Wearable>() != null))
|
||||
else if (inventory?.Owner is Item item &&
|
||||
(item.GetComponent<Holdable>() is { Attachable: false } || item.GetComponent<Wearable>() != null))
|
||||
{
|
||||
return maxStackSizeHoldableOrWearableInventory;
|
||||
}
|
||||
else
|
||||
{
|
||||
return maxStackSize;
|
||||
if (maxStackSizeHoldableOrWearableInventory > 0)
|
||||
{
|
||||
return maxStackSizeHoldableOrWearableInventory;
|
||||
}
|
||||
else if (maxStackSizeCharacterInventory > 0)
|
||||
{
|
||||
//if maxStackSizeHoldableOrWearableInventory is not set, it defaults to maxStackSizeCharacterInventory
|
||||
return maxStackSizeCharacterInventory;
|
||||
}
|
||||
}
|
||||
return maxStackSize;
|
||||
}
|
||||
|
||||
[Serialize(false, IsPropertySaveable.No)]
|
||||
@@ -880,7 +896,7 @@ namespace Barotrauma
|
||||
|
||||
public ImmutableHashSet<Identifier> AllowDroppingOnSwapWith { get; private set; }
|
||||
|
||||
[Serialize(false, IsPropertySaveable.No)]
|
||||
[Serialize(false, IsPropertySaveable.No, "If enabled, the item is not transferred when the player transfers items between subs.")]
|
||||
public bool DontTransferBetweenSubs { get; private set; }
|
||||
|
||||
[Serialize(true, IsPropertySaveable.No)]
|
||||
@@ -1009,7 +1025,8 @@ namespace Barotrauma
|
||||
|
||||
if (ConfigElement.GetAttribute("cargocontainername") != null)
|
||||
{
|
||||
DebugConsole.ThrowError($"Error in item prefab \"{ToString()}\" - cargo container should be configured using the item's identifier, not the name.");
|
||||
DebugConsole.ThrowError($"Error in item prefab \"{ToString()}\" - cargo container should be configured using the item's identifier, not the name.",
|
||||
contentPackage: ConfigElement.ContentPackage);
|
||||
}
|
||||
|
||||
SerializableProperty.DeserializeProperties(this, ConfigElement);
|
||||
@@ -1032,6 +1049,7 @@ namespace Barotrauma
|
||||
var levelCommonness = new Dictionary<Identifier, CommonnessInfo>();
|
||||
var levelQuantity = new Dictionary<Identifier, FixedQuantityResourceInfo>();
|
||||
|
||||
List<FabricationRecipe> loadedRecipes = new List<FabricationRecipe>();
|
||||
foreach (ContentXElement subElement in ConfigElement.Elements())
|
||||
{
|
||||
switch (subElement.Name.ToString().ToLowerInvariant())
|
||||
@@ -1046,7 +1064,8 @@ namespace Barotrauma
|
||||
if (subElement.GetAttribute("sourcerect") == null &&
|
||||
subElement.GetAttribute("sheetindex") == null)
|
||||
{
|
||||
DebugConsole.ThrowError($"Warning - sprite sourcerect not configured for item \"{ToString()}\"!");
|
||||
DebugConsole.ThrowError($"Warning - sprite sourcerect not configured for item \"{ToString()}\"!",
|
||||
contentPackage: ConfigElement.ContentPackage);
|
||||
}
|
||||
Size = Sprite.size;
|
||||
|
||||
@@ -1064,7 +1083,8 @@ namespace Barotrauma
|
||||
if (priceInfo.StoreIdentifier.IsEmpty) { continue; }
|
||||
if (storePrices.ContainsKey(priceInfo.StoreIdentifier))
|
||||
{
|
||||
DebugConsole.AddWarning($"Error in item prefab \"{this}\": price for the store \"{priceInfo.StoreIdentifier}\" defined more than once.");
|
||||
DebugConsole.AddWarning($"Error in item prefab \"{this}\": price for the store \"{priceInfo.StoreIdentifier}\" defined more than once.",
|
||||
ContentPackage);
|
||||
storePrices[priceInfo.StoreIdentifier] = priceInfo;
|
||||
}
|
||||
else
|
||||
@@ -1077,7 +1097,8 @@ namespace Barotrauma
|
||||
{
|
||||
if (storePrices.ContainsKey(locationType))
|
||||
{
|
||||
DebugConsole.AddWarning($"Error in item prefab \"{this}\": price for the location type \"{locationType}\" defined more than once.");
|
||||
DebugConsole.AddWarning($"Error in item prefab \"{this}\": price for the location type \"{locationType}\" defined more than once.",
|
||||
ContentPackage);
|
||||
storePrices[locationType] = new PriceInfo(subElement);
|
||||
}
|
||||
else
|
||||
@@ -1095,13 +1116,15 @@ namespace Barotrauma
|
||||
{
|
||||
if (itemElement.Attribute("name") != null)
|
||||
{
|
||||
DebugConsole.ThrowError($"Error in item config \"{ToString()}\" - use item identifiers instead of names to configure the deconstruct items.");
|
||||
DebugConsole.ThrowError($"Error in item config \"{ToString()}\" - use item identifiers instead of names to configure the deconstruct items.",
|
||||
contentPackage: ConfigElement.ContentPackage);
|
||||
continue;
|
||||
}
|
||||
var deconstructItem = new DeconstructItem(itemElement, Identifier);
|
||||
if (deconstructItem.ItemIdentifier.IsEmpty)
|
||||
{
|
||||
DebugConsole.ThrowError($"Error in item config \"{ToString()}\" - deconstruction output contains an item with no identifier.");
|
||||
DebugConsole.ThrowError($"Error in item config \"{ToString()}\" - deconstruction output contains an item with no identifier.",
|
||||
contentPackage: ConfigElement.ContentPackage);
|
||||
continue;
|
||||
}
|
||||
deconstructItems.Add(deconstructItem);
|
||||
@@ -1114,16 +1137,21 @@ namespace Barotrauma
|
||||
var newRecipe = new FabricationRecipe(subElement, Identifier);
|
||||
if (fabricationRecipes.TryGetValue(newRecipe.RecipeHash, out var prevRecipe))
|
||||
{
|
||||
//the errors below may be caused by a mod overriding a base item instead of this one, log the package of the base item in that case
|
||||
var packageToLog = GetParentModPackageOrThisPackage();
|
||||
|
||||
int prevRecipeIndex = loadedRecipes.IndexOf(prevRecipe);
|
||||
DebugConsole.ThrowError(
|
||||
$"Error in item prefab \"{ToString()}\": " +
|
||||
$"{prevRecipe.TargetItemPrefabIdentifier} has the same hash as {newRecipe.TargetItemPrefabIdentifier}. " +
|
||||
$"This will cause issues with fabrication."
|
||||
);
|
||||
$"Fabrication recipe #{loadedRecipes.Count + 1} has the same hash as recipe #{prevRecipeIndex + 1}. This is most likely caused by identical, duplicate recipes. " +
|
||||
$"This will cause issues with fabrication.",
|
||||
contentPackage: packageToLog);
|
||||
}
|
||||
else
|
||||
{
|
||||
fabricationRecipes.Add(newRecipe.RecipeHash, newRecipe);
|
||||
}
|
||||
loadedRecipes.Add(newRecipe);
|
||||
break;
|
||||
case "preferredcontainer":
|
||||
var preferredContainer = new PreferredContainer(subElement);
|
||||
@@ -1132,7 +1160,8 @@ namespace Barotrauma
|
||||
//it's ok for variants to clear the primary and secondary containers to disable the PreferredContainer element
|
||||
if (variantOf == null)
|
||||
{
|
||||
DebugConsole.ThrowError($"Error in item prefab \"{ToString()}\": preferred container has no preferences defined ({subElement}).");
|
||||
DebugConsole.ThrowError($"Error in item prefab \"{ToString()}\": preferred container has no preferences defined ({subElement}).",
|
||||
contentPackage: ConfigElement.ContentPackage);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -1182,7 +1211,8 @@ namespace Barotrauma
|
||||
case "suitabletreatment":
|
||||
if (subElement.GetAttribute("name") != null)
|
||||
{
|
||||
DebugConsole.ThrowError($"Error in item prefab \"{ToString()}\" - suitable treatments should be defined using item identifiers, not item names.");
|
||||
DebugConsole.ThrowError($"Error in item prefab \"{ToString()}\" - suitable treatments should be defined using item identifiers, not item names.",
|
||||
contentPackage: ConfigElement.ContentPackage);
|
||||
}
|
||||
Identifier treatmentIdentifier = subElement.GetAttributeIdentifier("identifier", subElement.GetAttributeIdentifier("type", Identifier.Empty));
|
||||
float suitability = subElement.GetAttributeFloat("suitability", 0.0f);
|
||||
@@ -1191,6 +1221,8 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
Size = ConfigElement.GetAttributeVector2(nameof(Size), Size);
|
||||
|
||||
#if CLIENT
|
||||
ParseSubElementsClient(ConfigElement, variantOf);
|
||||
#endif
|
||||
@@ -1221,7 +1253,7 @@ namespace Barotrauma
|
||||
|
||||
if (Sprite == null)
|
||||
{
|
||||
DebugConsole.ThrowError($"Item \"{ToString()}\" has no sprite!");
|
||||
DebugConsole.ThrowError($"Item \"{ToString()}\" has no sprite!", contentPackage: ConfigElement.ContentPackage);
|
||||
#if SERVER
|
||||
this.sprite = new Sprite("", Vector2.Zero);
|
||||
this.sprite.SourceRect = new Rectangle(0, 0, 32, 32);
|
||||
@@ -1238,7 +1270,8 @@ namespace Barotrauma
|
||||
if (Identifier == Identifier.Empty)
|
||||
{
|
||||
DebugConsole.ThrowError(
|
||||
$"Item prefab \"{ToString()}\" has no identifier. All item prefabs have a unique identifier string that's used to differentiate between items during saving and loading.");
|
||||
$"Item prefab \"{ToString()}\" has no identifier. All item prefabs have a unique identifier string that's used to differentiate between items during saving and loading.",
|
||||
contentPackage: ConfigElement.ContentPackage);
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
@@ -1246,7 +1279,8 @@ namespace Barotrauma
|
||||
{
|
||||
if (!string.IsNullOrEmpty(OriginalName))
|
||||
{
|
||||
DebugConsole.AddWarning($"Item \"{(Identifier == Identifier.Empty ? Name : Identifier.Value)}\" has a hard-coded name, and won't be localized to other languages.");
|
||||
DebugConsole.AddWarning($"Item \"{(Identifier == Identifier.Empty ? Name : Identifier.Value)}\" has a hard-coded name, and won't be localized to other languages.",
|
||||
ContentPackage);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -1306,9 +1340,9 @@ namespace Barotrauma
|
||||
{
|
||||
string message = $"Tried to get price info for \"{Identifier}\" with a null store parameter!\n{Environment.StackTrace.CleanupStackTrace()}";
|
||||
#if DEBUG
|
||||
DebugConsole.LogError(message);
|
||||
DebugConsole.LogError(message, contentPackage: ContentPackage);
|
||||
#else
|
||||
DebugConsole.AddWarning(message);
|
||||
DebugConsole.AddWarning(message, ContentPackage);
|
||||
GameAnalyticsManager.AddErrorEventOnce("ItemPrefab.GetPriceInfo:StoreParameterNull", GameAnalyticsManager.ErrorSeverity.Error, message);
|
||||
#endif
|
||||
return null;
|
||||
@@ -1515,6 +1549,9 @@ namespace Barotrauma
|
||||
|
||||
void CheckXML(XElement originalElement, XElement variantElement, XElement result)
|
||||
{
|
||||
//if either the parent or the variant are non-vanilla, assume the error is coming from that package
|
||||
var packageToLog = parent.ContentPackage != GameMain.VanillaContent ? parent.ContentPackage : ContentPackage;
|
||||
|
||||
if (result == null) { return; }
|
||||
if (result.Name.ToIdentifier() == "RequiredItem" &&
|
||||
result.Parent?.Name.ToIdentifier() == "Fabricate")
|
||||
@@ -1528,7 +1565,8 @@ namespace Barotrauma
|
||||
{
|
||||
DebugConsole.AddWarning($"Potential error in item variant \"{Identifier}\": " +
|
||||
$"the item inherits the fabrication requirement of x{originalAmount} \"{originalIdentifier}\" from the base item \"{parent.Identifier}\". " +
|
||||
$"If this is not intentional, you can use empty <RequiredItem /> elements in the item variant to remove any excess inherited fabrication requirements.");
|
||||
$"If this is not intentional, you can use empty <RequiredItem /> elements in the item variant to remove any excess inherited fabrication requirements.",
|
||||
packageToLog);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -1539,7 +1577,8 @@ namespace Barotrauma
|
||||
DebugConsole.AddWarning($"Potential error in item variant \"{Identifier}\": " +
|
||||
$"the base item \"{parent.Identifier}\" requires x{originalAmount} \"{originalIdentifier}\" to fabricate. " +
|
||||
$"The variant only overrides the required item, not the amount, resulting in a requirement of x{originalAmount} \"{resultIdentifier}\". "+
|
||||
"Specify the amount in the variant to fix this.");
|
||||
"Specify the amount in the variant to fix this.",
|
||||
packageToLog);
|
||||
}
|
||||
}
|
||||
if (originalElement?.Name.ToIdentifier() == "Deconstruct" &&
|
||||
@@ -1549,18 +1588,35 @@ namespace Barotrauma
|
||||
variantElement.Elements().Any(e => e.Name.ToIdentifier() == "RequiredItem"))
|
||||
{
|
||||
DebugConsole.AddWarning($"Potential error in item variant \"{Identifier}\": " +
|
||||
$"the item defines deconstruction recipes using 'RequiredItem' instead of 'Item'. Overriding the base recipe may not work correctly.");
|
||||
$"the item defines deconstruction recipes using 'RequiredItem' instead of 'Item'. Overriding the base recipe may not work correctly.",
|
||||
packageToLog);
|
||||
}
|
||||
if (variantElement.Elements().Any(e => e.Name.ToIdentifier() == "Item") &&
|
||||
originalElement.Elements().Any(e => e.Name.ToIdentifier() == "RequiredItem"))
|
||||
{
|
||||
DebugConsole.AddWarning($"Potential error in item \"{parent.Identifier}\": " +
|
||||
$"the item defines deconstruction recipes using 'RequiredItem' instead of 'Item'. The item variant \"{Identifier}\" may not override the base recipe correctly.");
|
||||
$"the item defines deconstruction recipes using 'RequiredItem' instead of 'Item'. The item variant \"{Identifier}\" may not override the base recipe correctly.",
|
||||
packageToLog);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// If the base prefab this one is a variant of is defined in a non-vanilla package, returns that non-vanilla package.
|
||||
/// Otherwise returns the package of this prefab. Can be useful for logging errors that may have been caused by a mod overriding
|
||||
/// the base item.
|
||||
/// </summary>
|
||||
public ContentPackage GetParentModPackageOrThisPackage()
|
||||
{
|
||||
if (ParentPrefab != null &&
|
||||
ParentPrefab.ContentPackage != ContentPackageManager.VanillaCorePackage)
|
||||
{
|
||||
return ParentPrefab.ContentPackage;
|
||||
}
|
||||
return ContentPackage;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{Name} (identifier: {Identifier})";
|
||||
|
||||
@@ -222,7 +222,7 @@ namespace Barotrauma
|
||||
if (element.GetAttribute("name") != null)
|
||||
{
|
||||
//backwards compatibility + a console warning
|
||||
DebugConsole.ThrowError($"Error in RelatedItem config (" + (string.IsNullOrEmpty(parentDebugName) ? element.ToString() : parentDebugName) + ") - use item tags or identifiers instead of names.");
|
||||
DebugConsole.ThrowError($"Error in RelatedItem config (" + (string.IsNullOrEmpty(parentDebugName) ? element.ToString() : parentDebugName) + ") - use item tags or identifiers instead of names.", contentPackage: element.ContentPackage);
|
||||
Identifier[] itemNames = element.GetAttributeIdentifierArray("name", Array.Empty<Identifier>());
|
||||
//attempt to convert to identifiers and tags
|
||||
List<Identifier> convertedIdentifiers = new List<Identifier>();
|
||||
@@ -299,7 +299,7 @@ namespace Barotrauma
|
||||
}
|
||||
if (!Enum.TryParse(typeStr, true, out type))
|
||||
{
|
||||
DebugConsole.ThrowError("Error in RelatedItem config (" + parentDebugName + ") - \"" + typeStr + "\" is not a valid relation type.");
|
||||
DebugConsole.ThrowError("Error in RelatedItem config (" + parentDebugName + ") - \"" + typeStr + "\" is not a valid relation type.", contentPackage: element.ContentPackage);
|
||||
type = RelationType.Invalid;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user