v1.4.4.1 (Blood in the Water Update)
This commit is contained in:
+32
-4
@@ -34,10 +34,16 @@ namespace Barotrauma.Items.Components
|
||||
get { return outputContainer; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Should the output items left in the deconstructor be automatically moved to the main sub at the end of the round
|
||||
/// if the deconstructor is not in the main sub?
|
||||
/// </summary>
|
||||
public bool RelocateOutputToMainSub;
|
||||
|
||||
[Serialize(false, IsPropertySaveable.Yes)]
|
||||
public bool DeconstructItemsSimultaneously { get; set; }
|
||||
|
||||
[Editable, Serialize(1.0f, IsPropertySaveable.Yes)]
|
||||
[Editable(MinValueFloat = 0.1f, MaxValueFloat = 1000), Serialize(1.0f, IsPropertySaveable.Yes)]
|
||||
public float DeconstructionSpeed { get; set; }
|
||||
|
||||
public Deconstructor(Item item, ContentXElement element)
|
||||
@@ -290,6 +296,10 @@ namespace Barotrauma.Items.Components
|
||||
spawnedItem.AllowStealing = targetItem.AllowStealing;
|
||||
spawnedItem.OriginalOutpost = targetItem.OriginalOutpost;
|
||||
spawnedItem.SpawnedInCurrentOutpost = targetItem.SpawnedInCurrentOutpost;
|
||||
if (RelocateOutputToMainSub && user is { AIController: HumanAIController humanAi })
|
||||
{
|
||||
humanAi.HandleRelocation(spawnedItem);
|
||||
}
|
||||
for (int i = 0; i < outputContainer.Capacity; i++)
|
||||
{
|
||||
var containedItem = outputContainer.Inventory.GetItemAt(i);
|
||||
@@ -318,7 +328,12 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
GameAnalyticsManager.AddDesignEvent("ItemDeconstructed:" + (GameMain.GameSession?.GameMode?.Preset.Identifier.Value ?? "none") + ":" + targetItem.Prefab.Identifier);
|
||||
if (targetItem.Prefab.ContentPackage == ContentPackageManager.VanillaCorePackage &&
|
||||
/* we don't need info of every item, we can get a good sample size just by logging 5% */
|
||||
Rand.Range(0.0f, 1.0f) < 0.05f)
|
||||
{
|
||||
GameAnalyticsManager.AddDesignEvent("ItemDeconstructed:" + (GameMain.GameSession?.GameMode?.Preset.Identifier.Value ?? "none") + ":" + targetItem.Prefab.Identifier);
|
||||
}
|
||||
|
||||
if (targetItem.AllowDeconstruct && allowRemove)
|
||||
{
|
||||
@@ -329,6 +344,10 @@ namespace Barotrauma.Items.Components
|
||||
foreach (Item outputItem in ic.Inventory.AllItemsMod)
|
||||
{
|
||||
tryPutInOutputSlots(outputItem);
|
||||
if (RelocateOutputToMainSub && user != null && user.AIController is HumanAIController humanAi)
|
||||
{
|
||||
humanAi.HandleRelocation(outputItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
inputContainer.Inventory.RemoveItem(targetItem);
|
||||
@@ -436,11 +455,12 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
private void SetActive(bool active, Character user = null)
|
||||
public void SetActive(bool active, Character user = null, bool createNetworkEvent = false)
|
||||
{
|
||||
PutItemsToLinkedContainer();
|
||||
|
||||
this.user = user;
|
||||
RelocateOutputToMainSub = false;
|
||||
|
||||
if (inputContainer.Inventory.IsEmpty()) { active = false; }
|
||||
|
||||
@@ -453,6 +473,10 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
GameServer.Log(GameServer.CharacterLogName(user) + (IsActive ? " activated " : " deactivated ") + item.Name, ServerLog.MessageType.ItemInteraction);
|
||||
}
|
||||
if (createNetworkEvent)
|
||||
{
|
||||
item.CreateServerEvent(this);
|
||||
}
|
||||
#endif
|
||||
if (!IsActive)
|
||||
{
|
||||
@@ -462,7 +486,11 @@ namespace Barotrauma.Items.Components
|
||||
#if CLIENT
|
||||
else
|
||||
{
|
||||
HintManager.OnStartDeconstructing(user, this);
|
||||
HintManager.OnStartDeconstructing(user, this);
|
||||
if (Item.Submarine is { Info.IsOutpost: true } && user is { IsBot: true })
|
||||
{
|
||||
HintManager.OnItemMarkedForRelocation();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
private ItemContainer inputContainer, outputContainer;
|
||||
|
||||
[Serialize(1.0f, IsPropertySaveable.Yes)]
|
||||
[Editable(MinValueFloat = 0.1f, MaxValueFloat = 1000), Serialize(1.0f, IsPropertySaveable.Yes)]
|
||||
public float FabricationSpeed { get; set; }
|
||||
|
||||
[Serialize(1.0f, IsPropertySaveable.Yes)]
|
||||
@@ -469,7 +469,10 @@ namespace Barotrauma.Items.Components
|
||||
character.CheckTalents(AbilityEffectType.OnAllyItemFabricatedAmount, fabricationitemAmount);
|
||||
}
|
||||
user.CheckTalents(AbilityEffectType.OnItemFabricatedAmount, fabricationitemAmount);
|
||||
quality = GetFabricatedItemQuality(fabricatedItem, user).RollQuality();
|
||||
quality =
|
||||
fabricatedItem.TargetItem.MaxStackSize > 1 ?
|
||||
GetFabricatedItemQuality(fabricatedItem, user).Quality :
|
||||
GetFabricatedItemQuality(fabricatedItem, user).RollQuality();
|
||||
}
|
||||
|
||||
int amount = (int)fabricationitemAmount.Value;
|
||||
@@ -490,7 +493,12 @@ namespace Barotrauma.Items.Components
|
||||
for (int i = 0; i < amount; i++)
|
||||
{
|
||||
float outCondition = fabricatedItem.OutCondition;
|
||||
GameAnalyticsManager.AddDesignEvent("ItemFabricated:" + (GameMain.GameSession?.GameMode?.Preset.Identifier.Value ?? "none") + ":" + fabricatedItem.TargetItem.Identifier);
|
||||
if (fabricatedItem.TargetItem.ContentPackage == ContentPackageManager.VanillaCorePackage &&
|
||||
/* we don't need info of every fabricated item, we can get a good sample size just by logging 5% */
|
||||
Rand.Range(0.0f, 1.0f) < 0.05f)
|
||||
{
|
||||
GameAnalyticsManager.AddDesignEvent("ItemFabricated:" + (GameMain.GameSession?.GameMode?.Preset.Identifier.Value ?? "none") + ":" + fabricatedItem.TargetItem.Identifier);
|
||||
}
|
||||
if (i < amountFittingContainer)
|
||||
{
|
||||
Entity.Spawner.AddItemToSpawnQueue(fabricatedItem.TargetItem, outputContainer.Inventory, fabricatedItem.TargetItem.Health * outCondition, quality,
|
||||
@@ -577,11 +585,11 @@ namespace Barotrauma.Items.Components
|
||||
public static float CalculateBonusRollPercentage(float skillLevel, float target)
|
||||
=> Math.Clamp((skillLevel - target) / (100f - target) * 100f, min: 0, max: 100);
|
||||
|
||||
public readonly record struct QualityResult(int Quality, float PlusOnePercentage, float PlusTwoPercentage)
|
||||
public readonly record struct QualityResult(int Quality, bool HasRandomQuality, float PlusOnePercentage, float PlusTwoPercentage)
|
||||
{
|
||||
public static readonly QualityResult Empty = new QualityResult(0, 0, 0);
|
||||
public static readonly QualityResult Empty = new QualityResult(0, true, 0, 0);
|
||||
|
||||
public bool HasRandomQualityRollChance => PlusOnePercentage > 0f || PlusTwoPercentage > 0f;
|
||||
public bool HasRandomQualityRollChance => HasRandomQuality && (PlusOnePercentage > 0f || PlusTwoPercentage > 0f);
|
||||
|
||||
// The total real world percentage for a roll to succeed, taking into account that +1 needs to succeed for +2 to be attempted and
|
||||
// that the chance for only +1 goes down as +2 increases since some of the +1's will turn into +2s
|
||||
@@ -676,9 +684,23 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
bool hasRandomQuality = !(fabricatedItem.TargetItem.MaxStackSize > 1); //don't randomise items with a stacksize > 1
|
||||
float PlusOnePercentage = plusOne.Match(some: static f => f, none: static () => 0f);
|
||||
float PlusTwoPercentage = plusTwo.Match(some: static f => f, none: static () => 0f);
|
||||
|
||||
if (!hasRandomQuality && PlusOnePercentage > 0)
|
||||
{
|
||||
quality++;
|
||||
if (PlusTwoPercentage > 0)
|
||||
{
|
||||
quality++;
|
||||
}
|
||||
}
|
||||
|
||||
return new QualityResult(quality,
|
||||
PlusOnePercentage: plusOne.Match(some: static f => f, none: static () => 0f),
|
||||
PlusTwoPercentage: plusTwo.Match(some: static f => f, none: static () => 0f));
|
||||
hasRandomQuality,
|
||||
PlusOnePercentage,
|
||||
PlusTwoPercentage);
|
||||
}
|
||||
|
||||
partial void UpdateRequiredTimeProjSpecific();
|
||||
@@ -690,6 +712,8 @@ namespace Barotrauma.Items.Components
|
||||
GameSession.GetSessionCrewCharacters(CharacterType.Bot).Any(c => c.HasRecipeForItem(item.Identifier));
|
||||
}
|
||||
|
||||
private readonly HashSet<Item> usedIngredients = new HashSet<Item>();
|
||||
|
||||
private bool CanBeFabricated(FabricationRecipe fabricableItem, IReadOnlyDictionary<Identifier, List<Item>> availableIngredients, Character character)
|
||||
{
|
||||
if (fabricableItem == null) { return false; }
|
||||
@@ -733,22 +757,26 @@ namespace Barotrauma.Items.Components
|
||||
return false;
|
||||
}
|
||||
|
||||
//maintain a list of used ingredients so we don't end up considering the same item a suitable for multiple required ingredients
|
||||
usedIngredients.Clear();
|
||||
|
||||
return fabricableItem.RequiredItems.All(requiredItem =>
|
||||
{
|
||||
int availablePrefabsAmount = 0;
|
||||
int availableItemsAmount = 0;
|
||||
foreach (ItemPrefab requiredPrefab in requiredItem.ItemPrefabs)
|
||||
{
|
||||
if (!availableIngredients.ContainsKey(requiredPrefab.Identifier)) { continue; }
|
||||
if (!availableIngredients.TryGetValue(requiredPrefab.Identifier, out var availableItems)) { continue; }
|
||||
|
||||
var availablePrefabs = availableIngredients[requiredPrefab.Identifier];
|
||||
foreach (Item availablePrefab in availablePrefabs)
|
||||
foreach (Item availableItem in availableItems)
|
||||
{
|
||||
if (requiredItem.IsConditionSuitable(availablePrefab.ConditionPercentage))
|
||||
if (usedIngredients.Contains(availableItem)) { continue; }
|
||||
if (requiredItem.IsConditionSuitable(availableItem.ConditionPercentage))
|
||||
{
|
||||
availablePrefabsAmount++;
|
||||
usedIngredients.Add(availableItem);
|
||||
availableItemsAmount++;
|
||||
}
|
||||
|
||||
if (availablePrefabsAmount >= requiredItem.Amount)
|
||||
if (availableItemsAmount >= requiredItem.Amount)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
+15
-1
@@ -91,7 +91,7 @@ namespace Barotrauma.Items.Components
|
||||
ventList.Clear();
|
||||
foreach (MapEntity entity in item.linkedTo)
|
||||
{
|
||||
if (!(entity is Item linkedItem)) { continue; }
|
||||
if (entity is not Item linkedItem) { continue; }
|
||||
|
||||
Vent vent = linkedItem.GetComponent<Vent>();
|
||||
if (vent?.Item.CurrentHull == null) { continue; }
|
||||
@@ -132,5 +132,19 @@ namespace Barotrauma.Items.Components
|
||||
vent.IsActive = true;
|
||||
}
|
||||
}
|
||||
|
||||
public float GetVentOxygenFlow(Vent targetVent)
|
||||
{
|
||||
if (ventList == null)
|
||||
{
|
||||
GetVents();
|
||||
}
|
||||
foreach ((Vent vent, float hullVolume) in ventList)
|
||||
{
|
||||
if (vent != targetVent) { continue; }
|
||||
return generatedAmount * 100.0f * (hullVolume / totalHullVolume);
|
||||
}
|
||||
return 0.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma.Items.Components
|
||||
{
|
||||
@@ -215,10 +214,10 @@ namespace Barotrauma.Items.Components
|
||||
activePings[currentPingIndex].Direction = pingDirection;
|
||||
activePings[currentPingIndex].State = 0.0f;
|
||||
activePings[currentPingIndex].PrevPingRadius = 0.0f;
|
||||
if (item.AiTarget != null)
|
||||
foreach (AITarget aiTarget in GetAITargets())
|
||||
{
|
||||
item.AiTarget.SectorDegrees = useDirectionalPing ? DirectionalPingSector : 360.0f;
|
||||
item.AiTarget.SectorDir = new Vector2(pingDirection.X, -pingDirection.Y);
|
||||
aiTarget.SectorDegrees = useDirectionalPing ? DirectionalPingSector : 360.0f;
|
||||
aiTarget.SectorDir = new Vector2(pingDirection.X, -pingDirection.Y);
|
||||
}
|
||||
item.Use(deltaTime);
|
||||
}
|
||||
@@ -231,10 +230,10 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
for (var pingIndex = 0; pingIndex < activePingsCount;)
|
||||
{
|
||||
if (item.AiTarget != null)
|
||||
foreach (AITarget aiTarget in GetAITargets())
|
||||
{
|
||||
float range = MathUtils.InverseLerp(item.AiTarget.MinSoundRange, item.AiTarget.MaxSoundRange, Range * activePings[pingIndex].State / zoom);
|
||||
item.AiTarget.SoundRange = Math.Max(item.AiTarget.SoundRange, MathHelper.Lerp(item.AiTarget.MinSoundRange, item.AiTarget.MaxSoundRange, range));
|
||||
float range = MathUtils.InverseLerp(aiTarget.MinSoundRange, aiTarget.MaxSoundRange, Range * activePings[pingIndex].State / zoom);
|
||||
aiTarget.SoundRange = Math.Max(aiTarget.SoundRange, MathHelper.Lerp(aiTarget.MinSoundRange, aiTarget.MaxSoundRange, range));
|
||||
}
|
||||
if (activePings[pingIndex].State > 1.0f)
|
||||
{
|
||||
@@ -254,6 +253,24 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerable<AITarget> GetAITargets()
|
||||
{
|
||||
if (!UseTransducers)
|
||||
{
|
||||
if (item.AiTarget != null) { yield return item.AiTarget; }
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var transducer in connectedTransducers)
|
||||
{
|
||||
if (transducer.Transducer.Item.AiTarget != null)
|
||||
{
|
||||
yield return transducer.Transducer.Item.AiTarget;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Power consumption of the sonar. Only consume power when active and adjust the consumption based on the sonar mode.
|
||||
/// </summary>
|
||||
|
||||
@@ -22,6 +22,11 @@ namespace Barotrauma.Items.Components
|
||||
private const float AutoPilotMaxSpeed = 0.5f;
|
||||
private const float AIPilotMaxSpeed = 1.0f;
|
||||
|
||||
/// <summary>
|
||||
/// How many units before crush depth the pressure warning is shown
|
||||
/// </summary>
|
||||
public const float PressureWarningThreshold = 500.0f;
|
||||
|
||||
/// <summary>
|
||||
/// How fast the steering vector adjusts when the nav terminal is operated by something else than a character (= signals)
|
||||
/// </summary>
|
||||
|
||||
Reference in New Issue
Block a user