Merge remote-tracking branch 'upstream/dev' into develop
This commit is contained in:
@@ -450,6 +450,7 @@ namespace Barotrauma.Items.Components
|
||||
public override bool Select(Character activator)
|
||||
{
|
||||
if (activator == null || activator.Removed) { return false; }
|
||||
if (Item.Condition <= 0.0f && !UpdateWhenInactive) { return false; }
|
||||
|
||||
if (UsableIn == UseEnvironment.Water && !activator.AnimController.InWater ||
|
||||
UsableIn == UseEnvironment.Air && activator.AnimController.InWater)
|
||||
|
||||
+11
-3
@@ -104,12 +104,14 @@ namespace Barotrauma.Items.Components
|
||||
// doesn't quite work properly, remaining time changes if tinkering stops
|
||||
float deconstructionSpeedModifier = userDeconstructorSpeedMultiplier * (1f + tinkeringStrength * TinkeringSpeedIncrease);
|
||||
|
||||
float deconstructionSpeed = item.StatManager.GetAdjustedValue(ItemTalentStats.DeconstructorSpeed, DeconstructionSpeed);
|
||||
|
||||
if (DeconstructItemsSimultaneously)
|
||||
{
|
||||
float deconstructTime = 0.0f;
|
||||
foreach (Item targetItem in inputContainer.Inventory.AllItems)
|
||||
{
|
||||
deconstructTime += targetItem.Prefab.DeconstructTime / (DeconstructionSpeed * deconstructionSpeedModifier);
|
||||
deconstructTime += targetItem.Prefab.DeconstructTime / (deconstructionSpeed * deconstructionSpeedModifier);
|
||||
}
|
||||
|
||||
progressState = Math.Min(progressTimer / deconstructTime, 1.0f);
|
||||
@@ -139,7 +141,7 @@ namespace Barotrauma.Items.Components
|
||||
if (targetItem == null) { return; }
|
||||
|
||||
var validDeconstructItems = targetItem.Prefab.DeconstructItems.Where(it => it.IsValidDeconstructor(item)).ToList();
|
||||
float deconstructTime = validDeconstructItems.Any() ? targetItem.Prefab.DeconstructTime / (DeconstructionSpeed * deconstructionSpeedModifier) : 1.0f;
|
||||
float deconstructTime = validDeconstructItems.Any() ? targetItem.Prefab.DeconstructTime / (deconstructionSpeed * deconstructionSpeedModifier) : 1.0f;
|
||||
|
||||
progressState = Math.Min(progressTimer / deconstructTime, 1.0f);
|
||||
if (progressTimer > deconstructTime)
|
||||
@@ -218,7 +220,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
if (percentageHealth < deconstructProduct.MinCondition || percentageHealth > deconstructProduct.MaxCondition) { return; }
|
||||
|
||||
if (!(MapEntityPrefab.Find(null, deconstructProduct.ItemIdentifier) is ItemPrefab itemPrefab))
|
||||
if (MapEntityPrefab.FindByIdentifier(deconstructProduct.ItemIdentifier) is not ItemPrefab itemPrefab)
|
||||
{
|
||||
DebugConsole.ThrowError("Tried to deconstruct item \"" + targetItem.Name + "\" but couldn't find item prefab \"" + deconstructProduct.ItemIdentifier + "\"!");
|
||||
return;
|
||||
@@ -460,6 +462,12 @@ namespace Barotrauma.Items.Components
|
||||
progressTimer = 0.0f;
|
||||
progressState = 0.0f;
|
||||
}
|
||||
#if CLIENT
|
||||
else
|
||||
{
|
||||
HintManager.OnStartDeconstructing(user, this);
|
||||
}
|
||||
#endif
|
||||
|
||||
inputContainer.Inventory.Locked = IsActive;
|
||||
}
|
||||
|
||||
@@ -30,11 +30,8 @@ namespace Barotrauma.Items.Components
|
||||
Serialize(500.0f, IsPropertySaveable.Yes, description: "The amount of force exerted on the submarine when the engine is operating at full power.")]
|
||||
public float MaxForce
|
||||
{
|
||||
get { return maxForce; }
|
||||
set
|
||||
{
|
||||
maxForce = Math.Max(0.0f, value);
|
||||
}
|
||||
get => maxForce;
|
||||
set => maxForce = Math.Max(0.0f, value);
|
||||
}
|
||||
|
||||
[Editable, Serialize("0.0,0.0", IsPropertySaveable.Yes,
|
||||
@@ -94,7 +91,7 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
|
||||
partial void InitProjSpecific(ContentXElement element);
|
||||
|
||||
|
||||
public override void Update(float deltaTime, Camera cam)
|
||||
{
|
||||
UpdateOnActiveEffects(deltaTime);
|
||||
@@ -129,12 +126,14 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
forceMultiplier *= MathHelper.Lerp(0.5f, 2.0f, (float)Math.Sqrt(User.GetSkillLevel("helm") / 100));
|
||||
}
|
||||
currForce *= maxForce * forceMultiplier;
|
||||
if (item.GetComponent<Repairable>() is Repairable repairable && repairable.IsTinkering)
|
||||
currForce *= item.StatManager.GetAdjustedValue(ItemTalentStats.EngineMaxSpeed, MaxForce) * forceMultiplier;
|
||||
if (item.GetComponent<Repairable>() is { IsTinkering: true } repairable)
|
||||
{
|
||||
currForce *= 1f + repairable.TinkeringStrength * TinkeringForceIncrease;
|
||||
}
|
||||
|
||||
currForce = item.StatManager.GetAdjustedValue(ItemTalentStats.EngineSpeed, currForce);
|
||||
|
||||
//less effective when in a bad condition
|
||||
currForce *= MathHelper.Lerp(0.5f, 2.0f, condition);
|
||||
if (item.Submarine.FlippedX) { currForce *= -1; }
|
||||
|
||||
@@ -15,6 +15,8 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
private ImmutableDictionary<uint, FabricationRecipe> fabricationRecipes; //this is not readonly because tutorials fuck this up!!!!
|
||||
|
||||
private const int MaxAmountToFabricate = 99;
|
||||
|
||||
private FabricationRecipe fabricatedItem;
|
||||
private float timeUntilReady;
|
||||
private float requiredTime;
|
||||
@@ -39,6 +41,16 @@ namespace Barotrauma.Items.Components
|
||||
[Serialize(1.0f, IsPropertySaveable.Yes)]
|
||||
public float SkillRequirementMultiplier { get; set; }
|
||||
|
||||
private int amountToFabricate;
|
||||
[Serialize(1, IsPropertySaveable.Yes)]
|
||||
public int AmountToFabricate
|
||||
{
|
||||
get { return amountToFabricate; }
|
||||
set { amountToFabricate = MathHelper.Clamp(value, 1, MaxAmountToFabricate); }
|
||||
}
|
||||
|
||||
private int amountRemaining;
|
||||
|
||||
private const float TinkeringSpeedIncrease = 2.5f;
|
||||
|
||||
private enum FabricatorState
|
||||
@@ -89,7 +101,7 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
DebugConsole.ThrowError("Error in item " + item.Name + "! Fabrication recipes should be defined in the craftable item's xml, not in the fabricator.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var fabricationRecipes = new Dictionary<uint, FabricationRecipe>();
|
||||
@@ -104,6 +116,18 @@ namespace Barotrauma.Items.Components
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
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}\".");
|
||||
recipeInvalid = true;
|
||||
}
|
||||
}
|
||||
if (recipeInvalid) { continue; }
|
||||
|
||||
fabricationRecipes.Add(recipe.RecipeHash, recipe);
|
||||
if (recipe.FabricationLimitMax >= 0)
|
||||
{
|
||||
@@ -171,16 +195,20 @@ namespace Barotrauma.Items.Components
|
||||
if (selectedItem == null) { return; }
|
||||
if (!outputContainer.Inventory.CanBePut(selectedItem.TargetItem, selectedItem.OutCondition * selectedItem.TargetItem.Health)) { return; }
|
||||
|
||||
#if CLIENT
|
||||
itemList.Enabled = false;
|
||||
activateButton.Text = TextManager.Get("FabricatorCancel");
|
||||
#endif
|
||||
|
||||
IsActive = true;
|
||||
this.user = user;
|
||||
fabricatedItem = selectedItem;
|
||||
RefreshAvailableIngredients();
|
||||
|
||||
#if CLIENT
|
||||
itemList.Enabled = false;
|
||||
if (amountInput != null)
|
||||
{
|
||||
amountInput.Enabled = false;
|
||||
}
|
||||
RefreshActivateButtonText();
|
||||
#endif
|
||||
|
||||
bool isClient = GameMain.NetworkMember != null && GameMain.NetworkMember.IsClient;
|
||||
if (!isClient)
|
||||
{
|
||||
@@ -237,10 +265,11 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
#elif CLIENT
|
||||
itemList.Enabled = true;
|
||||
if (activateButton != null)
|
||||
if (amountInput != null)
|
||||
{
|
||||
activateButton.Text = TextManager.Get(CreateButtonText);
|
||||
amountInput.Enabled = true;
|
||||
}
|
||||
RefreshActivateButtonText();
|
||||
#endif
|
||||
fabricatedItem = null;
|
||||
}
|
||||
@@ -356,9 +385,10 @@ namespace Barotrauma.Items.Components
|
||||
bool ingredientsStolen = false;
|
||||
bool ingredientsAllowStealing = true;
|
||||
|
||||
if (GameMain.NetworkMember == null || GameMain.NetworkMember.IsServer)
|
||||
if (GameMain.NetworkMember is null || GameMain.NetworkMember.IsServer)
|
||||
{
|
||||
fabricatedItem.RequiredItems.ForEach(requiredItem =>
|
||||
List<Item> foundAvailableItems = new List<Item>();
|
||||
foreach (FabricationRecipe.RequiredItem requiredItem in fabricatedItem.RequiredItems)
|
||||
{
|
||||
for (int usedPrefabsAmount = 0; usedPrefabsAmount < requiredItem.Amount; usedPrefabsAmount++)
|
||||
{
|
||||
@@ -367,10 +397,7 @@ namespace Barotrauma.Items.Components
|
||||
if (!availableIngredients.ContainsKey(requiredPrefab.Identifier)) { continue; }
|
||||
|
||||
var availableItems = availableIngredients[requiredPrefab.Identifier];
|
||||
var availableItem = availableItems.FirstOrDefault(potentialPrefab =>
|
||||
{
|
||||
return requiredItem.IsConditionSuitable(potentialPrefab.ConditionPercentage);
|
||||
});
|
||||
var availableItem = availableItems.FirstOrDefault(potentialPrefab => requiredItem.IsConditionSuitable(potentialPrefab.ConditionPercentage));
|
||||
|
||||
if (availableItem == null) { continue; }
|
||||
|
||||
@@ -401,13 +428,21 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
foundAvailableItems.Add(availableItem);
|
||||
availableItems.Remove(availableItem);
|
||||
Entity.Spawner.AddItemToRemoveQueue(availableItem);
|
||||
inputContainer.Inventory.RemoveItem(availableItem);
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
var fabricationIngredients = new AbilityFabricationItemIngredients(foundAvailableItems);
|
||||
user?.CheckTalents(AbilityEffectType.OnItemFabricatedIngredients, fabricationIngredients);
|
||||
|
||||
foreach (Item availableItem in fabricationIngredients.Items)
|
||||
{
|
||||
Entity.Spawner.AddItemToRemoveQueue(availableItem);
|
||||
inputContainer.Inventory.RemoveItem(availableItem);
|
||||
}
|
||||
|
||||
int amountFittingContainer = outputContainer.Inventory.HowManyCanBePut(fabricatedItem.TargetItem, fabricatedItem.OutCondition * fabricatedItem.TargetItem.Health);
|
||||
|
||||
@@ -500,20 +535,16 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
//disabled "continuous fabrication" for now
|
||||
//before we enable it, there should be some UI controls for fabricating a specific number of items
|
||||
|
||||
/*var prevFabricatedItem = fabricatedItem;
|
||||
var prevFabricatedItem = fabricatedItem;
|
||||
var prevUser = user;
|
||||
CancelFabricating();
|
||||
if (CanBeFabricated(prevFabricatedItem))
|
||||
|
||||
amountRemaining--;
|
||||
if (amountRemaining > 0 && CanBeFabricated(prevFabricatedItem, availableIngredients, prevUser))
|
||||
{
|
||||
//keep fabricating if we can fabricate more
|
||||
StartFabricating(prevFabricatedItem, prevUser, addToServerLog: false);
|
||||
}*/
|
||||
|
||||
|
||||
CancelFabricating();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -535,12 +566,13 @@ namespace Barotrauma.Items.Components
|
||||
return currPowerConsumption;
|
||||
}
|
||||
|
||||
private int GetFabricatedItemQuality(FabricationRecipe fabricatedItem, Character user)
|
||||
private static int GetFabricatedItemQuality(FabricationRecipe fabricatedItem, Character user)
|
||||
{
|
||||
if (user == null) { return 0; }
|
||||
if (user?.Info == null) { return 0; }
|
||||
if (fabricatedItem.TargetItem.ConfigElement.GetChildElement("Quality") == null) { return 0; }
|
||||
int quality = 0;
|
||||
float floatQuality = 0.0f;
|
||||
floatQuality += user.GetStatValue(StatTypes.IncreaseFabricationQuality, includeSaved: false);
|
||||
foreach (var tag in fabricatedItem.TargetItem.Tags)
|
||||
{
|
||||
floatQuality += user.Info.GetSavedStatValue(StatTypes.IncreaseFabricationQuality, tag);
|
||||
@@ -571,11 +603,25 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
|
||||
partial void UpdateRequiredTimeProjSpecific();
|
||||
|
||||
private static bool AnyOneHasRecipeForItem(Character user, ItemPrefab item)
|
||||
{
|
||||
return
|
||||
(user != null && user.HasRecipeForItem(item.Identifier)) ||
|
||||
GameSession.GetSessionCrewCharacters(CharacterType.Bot).Any(c => c.HasRecipeForItem(item.Identifier));
|
||||
}
|
||||
|
||||
private bool CanBeFabricated(FabricationRecipe fabricableItem, IReadOnlyDictionary<Identifier, List<Item>> availableIngredients, Character character)
|
||||
{
|
||||
if (fabricableItem == null) { return false; }
|
||||
if (fabricableItem.RequiresRecipe && (character == null || !character.HasRecipeForItem(fabricableItem.TargetItem.Identifier))) { return false; }
|
||||
if (fabricableItem.RequiresRecipe)
|
||||
{
|
||||
if (character == null) { return false; }
|
||||
if (!AnyOneHasRecipeForItem(character, fabricableItem.TargetItem))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (fabricableItem.RequiredMoney > 0)
|
||||
{
|
||||
@@ -637,9 +683,15 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
//fabricating takes 100 times longer if degree of success is close to 0
|
||||
//characters with a higher skill than required can fabricate up to 100% faster
|
||||
return fabricableItem.RequiredTime / FabricationSpeed / MathHelper.Clamp(t, 0.01f, 2.0f);
|
||||
float time = fabricableItem.RequiredTime / item.StatManager.GetAdjustedValue(ItemTalentStats.FabricationSpeed, FabricationSpeed) / MathHelper.Clamp(t, 0.01f, 2.0f);
|
||||
|
||||
if (user?.Info is { } info && fabricableItem.TargetItem is { } it)
|
||||
{
|
||||
time /= 1f + it.Tags.Sum(tag => info.GetSavedStatValue(StatTypes.FabricationSpeed, tag));
|
||||
}
|
||||
return time;
|
||||
}
|
||||
|
||||
|
||||
public float FabricationDegreeOfSuccess(Character character, ImmutableArray<Skill> skills)
|
||||
{
|
||||
if (skills.Length == 0) { return 1.0f; }
|
||||
@@ -700,7 +752,7 @@ namespace Barotrauma.Items.Components
|
||||
itemList.AddRange(container.Inventory.AllItems);
|
||||
}
|
||||
}
|
||||
if (user?.Inventory != null)
|
||||
if (user?.Inventory != null && user.SelectedItem == item)
|
||||
{
|
||||
itemList.AddRange(user.Inventory.AllItems);
|
||||
linkedInventories.Add(user.Inventory);
|
||||
@@ -713,7 +765,31 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
availableIngredients[itemIdentifier] = new List<Item>(itemList.Count);
|
||||
}
|
||||
availableIngredients[itemIdentifier].Add(item);
|
||||
//order by condition (prefer using worst-condition items)
|
||||
int index = 0;
|
||||
while (index < availableIngredients[itemIdentifier].Count &&
|
||||
compare(item, availableIngredients[itemIdentifier][index], inputContainer.Inventory) < 0)
|
||||
{
|
||||
index++;
|
||||
}
|
||||
|
||||
static int compare(Item item1, Item item2, Inventory inputInventory)
|
||||
{
|
||||
bool item1InInputInventory = item1.ParentInventory == inputInventory;
|
||||
bool item2InInputInventory = item2.ParentInventory == inputInventory;
|
||||
//prefer items in the input inventory
|
||||
if (item1InInputInventory != item2InInputInventory)
|
||||
{
|
||||
return item1InInputInventory ? 1 : -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
//prefer items in worse condition
|
||||
return Math.Sign(item2.Condition - item1.Condition);
|
||||
}
|
||||
}
|
||||
|
||||
availableIngredients[itemIdentifier].Insert(index, item);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -827,5 +903,15 @@ namespace Barotrauma.Items.Components
|
||||
public float Value { get; set; }
|
||||
public ItemPrefab ItemPrefab { get; set; }
|
||||
}
|
||||
|
||||
internal sealed class AbilityFabricationItemIngredients : AbilityObject
|
||||
{
|
||||
public List<Item> Items { get; set; }
|
||||
|
||||
public AbilityFabricationItemIngredients(List<Item> items)
|
||||
{
|
||||
Items = items;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,8 @@ namespace Barotrauma.Items.Components
|
||||
public float? ReceivedOxygenAmount,
|
||||
ReceivedWaterAmount;
|
||||
|
||||
public double LastOxygenDataTime, LastWaterDataTime;
|
||||
|
||||
public readonly HashSet<IdCard> Cards = new HashSet<IdCard>();
|
||||
|
||||
public bool Distort;
|
||||
@@ -23,12 +25,8 @@ namespace Barotrauma.Items.Components
|
||||
public List<Hull> LinkedHulls = new List<Hull>();
|
||||
}
|
||||
|
||||
private DateTime resetDataTime;
|
||||
|
||||
private bool hasPower;
|
||||
|
||||
private readonly Dictionary<Hull, HullData> hullDatas;
|
||||
|
||||
[Editable, Serialize(false, IsPropertySaveable.Yes, description: "Does the machine require inputs from water detectors in order to show the water levels inside rooms.")]
|
||||
public bool RequireWaterDetectors
|
||||
{
|
||||
@@ -75,7 +73,6 @@ namespace Barotrauma.Items.Components
|
||||
: base(item, element)
|
||||
{
|
||||
IsActive = true;
|
||||
hullDatas = new Dictionary<Hull, HullData>();
|
||||
InitProjSpecific();
|
||||
}
|
||||
|
||||
@@ -83,37 +80,6 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
public override void Update(float deltaTime, Camera cam)
|
||||
{
|
||||
//periodically reset all hull data
|
||||
//(so that outdated hull info won't be shown if detectors stop sending signals)
|
||||
if (DateTime.Now > resetDataTime)
|
||||
{
|
||||
foreach (HullData hullData in hullDatas.Values)
|
||||
{
|
||||
if (!hullData.Distort)
|
||||
{
|
||||
hullData.ReceivedOxygenAmount = null;
|
||||
hullData.ReceivedWaterAmount = null;
|
||||
}
|
||||
}
|
||||
resetDataTime = DateTime.Now + new TimeSpan(0, 0, 1);
|
||||
}
|
||||
|
||||
#if CLIENT
|
||||
if (cardRefreshTimer > cardRefreshDelay)
|
||||
{
|
||||
if (item.Submarine is { } sub)
|
||||
{
|
||||
UpdateIDCards(sub);
|
||||
}
|
||||
|
||||
cardRefreshTimer = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
cardRefreshTimer += deltaTime;
|
||||
}
|
||||
#endif
|
||||
|
||||
hasPower = Voltage > MinVoltage;
|
||||
if (hasPower)
|
||||
{
|
||||
@@ -138,65 +104,5 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
return picker != null;
|
||||
}
|
||||
|
||||
public override void ReceiveSignal(Signal signal, Connection connection)
|
||||
{
|
||||
Item source = signal.source;
|
||||
if (source == null || source.CurrentHull == null) { return; }
|
||||
|
||||
Hull sourceHull = source.CurrentHull;
|
||||
if (!hullDatas.TryGetValue(sourceHull, out HullData hullData))
|
||||
{
|
||||
hullData = new HullData();
|
||||
hullDatas.Add(sourceHull, hullData);
|
||||
}
|
||||
|
||||
if (hullData.Distort) { return; }
|
||||
|
||||
switch (connection.Name)
|
||||
{
|
||||
case "water_data_in":
|
||||
//cheating a bit because water detectors don't actually send the water level
|
||||
bool fromWaterDetector = source.GetComponent<WaterDetector>() != null;
|
||||
hullData.ReceivedWaterAmount = null;
|
||||
if (fromWaterDetector)
|
||||
{
|
||||
hullData.ReceivedWaterAmount = WaterDetector.GetWaterPercentage(sourceHull);
|
||||
}
|
||||
foreach (var linked in sourceHull.linkedTo)
|
||||
{
|
||||
if (!(linked is Hull linkedHull)) { continue; }
|
||||
if (!hullDatas.TryGetValue(linkedHull, out HullData linkedHullData))
|
||||
{
|
||||
linkedHullData = new HullData();
|
||||
hullDatas.Add(linkedHull, linkedHullData);
|
||||
}
|
||||
linkedHullData.ReceivedWaterAmount = null;
|
||||
if (fromWaterDetector)
|
||||
{
|
||||
linkedHullData.ReceivedWaterAmount = WaterDetector.GetWaterPercentage(linkedHull);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "oxygen_data_in":
|
||||
if (!float.TryParse(signal.value, System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out float oxy))
|
||||
{
|
||||
oxy = Rand.Range(0.0f, 100.0f);
|
||||
}
|
||||
hullData.ReceivedOxygenAmount = oxy;
|
||||
foreach (var linked in sourceHull.linkedTo)
|
||||
{
|
||||
if (!(linked is Hull linkedHull)) { continue; }
|
||||
if (!hullDatas.TryGetValue(linkedHull, out HullData linkedHullData))
|
||||
{
|
||||
linkedHullData = new HullData();
|
||||
hullDatas.Add(linkedHull, linkedHullData);
|
||||
}
|
||||
linkedHullData.ReceivedOxygenAmount = oxy;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,8 +57,8 @@ namespace Barotrauma.Items.Components
|
||||
[Editable, Serialize(80.0f, IsPropertySaveable.No, description: "How fast the item pumps water in/out when operating at 100%.", alwaysUseInstanceValues: true)]
|
||||
public float MaxFlow
|
||||
{
|
||||
get { return maxFlow; }
|
||||
set { maxFlow = value; }
|
||||
get => maxFlow;
|
||||
set => maxFlow = value;
|
||||
}
|
||||
|
||||
[Editable, Serialize(true, IsPropertySaveable.Yes, alwaysUseInstanceValues: true)]
|
||||
@@ -92,13 +92,16 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
|
||||
partial void InitProjSpecific(ContentXElement element);
|
||||
|
||||
|
||||
public override void Update(float deltaTime, Camera cam)
|
||||
{
|
||||
pumpSpeedLockTimer -= deltaTime;
|
||||
isActiveLockTimer -= deltaTime;
|
||||
|
||||
if (!IsActive) { return; }
|
||||
if (!IsActive)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
currFlow = 0.0f;
|
||||
|
||||
@@ -122,7 +125,10 @@ namespace Barotrauma.Items.Components
|
||||
FlowPercentage = ((float)TargetLevel - hullPercentage) * 10.0f;
|
||||
}
|
||||
|
||||
if (!HasPower) { return; }
|
||||
if (!HasPower)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
UpdateProjSpecific(deltaTime);
|
||||
|
||||
@@ -132,13 +138,15 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
float powerFactor = Math.Min(currPowerConsumption <= 0.0f || MinVoltage <= 0.0f ? 1.0f : Voltage, MaxOverVoltageFactor);
|
||||
|
||||
currFlow = flowPercentage / 100.0f * maxFlow * powerFactor;
|
||||
currFlow = flowPercentage / 100.0f * item.StatManager.GetAdjustedValue(ItemTalentStats.PumpMaxFlow, MaxFlow) * powerFactor;
|
||||
|
||||
if (item.GetComponent<Repairable>() is Repairable repairable && repairable.IsTinkering)
|
||||
if (item.GetComponent<Repairable>() is { IsTinkering: true } repairable)
|
||||
{
|
||||
currFlow *= 1f + repairable.TinkeringStrength * TinkeringSpeedIncrease;
|
||||
}
|
||||
|
||||
currFlow = item.StatManager.GetAdjustedValue(ItemTalentStats.PumpSpeed, currFlow);
|
||||
|
||||
//less effective when in a bad condition
|
||||
currFlow *= MathHelper.Lerp(0.5f, 1.0f, item.Condition / item.MaxCondition);
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
const float NetworkUpdateIntervalHigh = 0.5f;
|
||||
|
||||
const float TemperatureBoostAmount = 20;
|
||||
const float TemperatureBoostAmount = 25;
|
||||
|
||||
//the rate at which the reactor is being run on (higher rate -> higher temperature)
|
||||
private float fissionRate;
|
||||
@@ -26,10 +26,6 @@ namespace Barotrauma.Items.Components
|
||||
//amount of power generated balanced with the load)
|
||||
private bool autoTemp;
|
||||
|
||||
//automatical adjustment to the power output when
|
||||
//turbine output and temperature are in the optimal range
|
||||
private float autoAdjustAmount;
|
||||
|
||||
private float fuelConsumptionRate;
|
||||
|
||||
private float meltDownTimer, meltDownDelay;
|
||||
@@ -53,6 +49,8 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
private float temperatureBoost;
|
||||
|
||||
public bool AllowTemperatureBoost => Math.Abs(temperatureBoost) < TemperatureBoostAmount * 0.9f;
|
||||
|
||||
private bool _powerOn;
|
||||
|
||||
[Serialize(defaultValue: false, isSaveable: IsPropertySaveable.Yes)]
|
||||
@@ -95,15 +93,12 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[Editable(0.0f, float.MaxValue), Serialize(10000.0f, IsPropertySaveable.Yes, description: "How much power (kW) the reactor generates when operating at full capacity.", alwaysUseInstanceValues: true)]
|
||||
public float MaxPowerOutput
|
||||
{
|
||||
get { return maxPowerOutput; }
|
||||
set
|
||||
{
|
||||
maxPowerOutput = Math.Max(0.0f, value);
|
||||
}
|
||||
get => maxPowerOutput;
|
||||
set => maxPowerOutput = Math.Max(0.0f, value);
|
||||
}
|
||||
|
||||
[Editable(0.0f, float.MaxValue), Serialize(120.0f, IsPropertySaveable.Yes, description: "How long the temperature has to stay critical until a meltdown occurs.")]
|
||||
@@ -152,11 +147,11 @@ namespace Barotrauma.Items.Components
|
||||
turbineOutput = MathHelper.Clamp(value, 0.0f, 100.0f);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[Serialize(0.2f, IsPropertySaveable.Yes, description: "How fast the condition of the contained fuel rods deteriorates per second."), Editable(0.0f, 1000.0f, decimals: 3)]
|
||||
public float FuelConsumptionRate
|
||||
{
|
||||
get { return fuelConsumptionRate; }
|
||||
get => fuelConsumptionRate;
|
||||
set
|
||||
{
|
||||
if (!MathUtils.IsValid(value)) return;
|
||||
@@ -256,6 +251,8 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
#endif
|
||||
|
||||
float maxPowerOut = GetMaxOutput();
|
||||
|
||||
if (signalControlledTargetFissionRate.HasValue && lastReceivedFissionRateSignalTime > Timing.TotalTime - 1)
|
||||
{
|
||||
TargetFissionRate = adjustValueWithoutOverShooting(TargetFissionRate, signalControlledTargetFissionRate.Value, deltaTime * 5.0f);
|
||||
@@ -289,9 +286,9 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
//use a smoothed "correct output" instead of the actual correct output based on the load
|
||||
//so the player doesn't have to keep adjusting the rate impossibly fast when the load fluctuates heavily
|
||||
if (!MathUtils.NearlyEqual(MaxPowerOutput, 0.0f))
|
||||
if (!MathUtils.NearlyEqual(maxPowerOut, 0.0f))
|
||||
{
|
||||
CorrectTurbineOutput += MathHelper.Clamp((Load / MaxPowerOutput * 100.0f) - CorrectTurbineOutput, -20.0f, 20.0f) * deltaTime;
|
||||
CorrectTurbineOutput += MathHelper.Clamp((Load / maxPowerOut * 100.0f) - CorrectTurbineOutput, -20.0f, 20.0f) * deltaTime;
|
||||
}
|
||||
|
||||
//calculate tolerances of the meters based on the skills of the user
|
||||
@@ -315,7 +312,7 @@ namespace Barotrauma.Items.Components
|
||||
Temperature += MathHelper.Clamp(Math.Sign(temperatureDiff) * 10.0f * deltaTime, -Math.Abs(temperatureDiff), Math.Abs(temperatureDiff));
|
||||
temperatureBoost = adjustValueWithoutOverShooting(temperatureBoost, 0.0f, deltaTime);
|
||||
#if CLIENT
|
||||
temperatureBoostUpButton.Enabled = temperatureBoostDownButton.Enabled = Math.Abs(temperatureBoost) < TemperatureBoostAmount * 0.9f;
|
||||
temperatureBoostUpButton.Enabled = temperatureBoostDownButton.Enabled = AllowTemperatureBoost;
|
||||
#endif
|
||||
|
||||
FissionRate = MathHelper.Lerp(fissionRate, Math.Min(TargetFissionRate, AvailableFuel), deltaTime);
|
||||
@@ -350,7 +347,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
if (!isConnectedToFriendlyOutpost)
|
||||
{
|
||||
item.Condition -= fissionRate / 100.0f * fuelConsumptionRate * deltaTime;
|
||||
item.Condition -= fissionRate / 100.0f * GetFuelConsumption() * deltaTime;
|
||||
}
|
||||
}
|
||||
fuelLeft += item.ConditionPercentage;
|
||||
@@ -359,10 +356,10 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
if (fissionRate > 0.0f)
|
||||
{
|
||||
if (item.AiTarget != null && MaxPowerOutput > 0)
|
||||
if (item.AiTarget != null && maxPowerOut > 0)
|
||||
{
|
||||
var aiTarget = item.AiTarget;
|
||||
float range = Math.Abs(currPowerConsumption) / MaxPowerOutput;
|
||||
float range = Math.Abs(currPowerConsumption) / maxPowerOut;
|
||||
aiTarget.SoundRange = MathHelper.Lerp(aiTarget.MinSoundRange, aiTarget.MaxSoundRange, range);
|
||||
if (item.CurrentHull != null)
|
||||
{
|
||||
@@ -433,15 +430,17 @@ namespace Barotrauma.Items.Components
|
||||
tolerance = 3f;
|
||||
}
|
||||
|
||||
float maxPowerOut = GetMaxOutput();
|
||||
|
||||
float temperatureFactor = Math.Min(temperature / 50.0f, 1.0f);
|
||||
float minOutput = MaxPowerOutput * Math.Clamp(Math.Min((turbineOutput - tolerance) / 100.0f, temperatureFactor), 0, 1);
|
||||
float maxOutput = MaxPowerOutput * Math.Min((turbineOutput + tolerance) / 100.0f, temperatureFactor);
|
||||
float minOutput = maxPowerOut * Math.Clamp(Math.Min((turbineOutput - tolerance) / 100.0f, temperatureFactor), 0, 1);
|
||||
float maxOutput = maxPowerOut * Math.Min((turbineOutput + tolerance) / 100.0f, temperatureFactor);
|
||||
|
||||
minUpdatePowerOut = minOutput;
|
||||
maxUpdatePowerOut = maxOutput;
|
||||
|
||||
float reactorMax = PowerOn ? MaxPowerOutput : maxUpdatePowerOut;
|
||||
|
||||
float reactorMax = PowerOn ? maxPowerOut : maxUpdatePowerOut;
|
||||
|
||||
return new PowerRange(minOutput, maxOutput, reactorMax);
|
||||
}
|
||||
|
||||
@@ -464,11 +463,13 @@ namespace Barotrauma.Items.Components
|
||||
float output = MathHelper.Clamp(ratio * (maxUpdatePowerOut - minUpdatePowerOut) + minUpdatePowerOut, minUpdatePowerOut, maxUpdatePowerOut);
|
||||
float newLoad = loadLeft;
|
||||
|
||||
float maxOutput = GetMaxOutput();
|
||||
|
||||
//Adjust behaviour for multi reactor setup
|
||||
if (MaxPowerOutput != minMaxPower.ReactorMaxOutput)
|
||||
if (maxOutput != minMaxPower.ReactorMaxOutput)
|
||||
{
|
||||
float idealLoad = MaxPowerOutput / minMaxPower.ReactorMaxOutput * loadLeft;
|
||||
float loadAdjust = MathHelper.Clamp((ratio - 0.5f) * 25 + idealLoad - (turbineOutput / 100 * MaxPowerOutput), -MaxPowerOutput / 100, MaxPowerOutput / 100);
|
||||
float idealLoad = maxOutput / minMaxPower.ReactorMaxOutput * loadLeft;
|
||||
float loadAdjust = MathHelper.Clamp((ratio - 0.5f) * 25 + idealLoad - (turbineOutput / 100 * maxOutput), -maxOutput / 100, maxOutput / 100);
|
||||
newLoad = MathHelper.Clamp(loadLeft - (expectedPower - output) + loadAdjust, 0, loadLeft);
|
||||
}
|
||||
|
||||
@@ -509,7 +510,7 @@ namespace Barotrauma.Items.Components
|
||||
//calculate the maximum output if the fission rate is cranked as high as it goes and turbine output is at max
|
||||
float theoreticalMaxHeat = GetGeneratedHeat(fissionRate: maxFissionRate);
|
||||
float temperatureFactor = Math.Min(theoreticalMaxHeat / 50.0f, 1.0f);
|
||||
float theoreticalMaxOutput = Math.Min(maxTurbineOutput / 100.0f, temperatureFactor) * MaxPowerOutput;
|
||||
float theoreticalMaxOutput = Math.Min(maxTurbineOutput / 100.0f, temperatureFactor) * GetMaxOutput();
|
||||
|
||||
//maximum output not enough, we need more fuel
|
||||
return theoreticalMaxOutput < Load * minimumOutputRatio;
|
||||
@@ -693,7 +694,7 @@ namespace Barotrauma.Items.Components
|
||||
aiUpdateTimer = AIUpdateInterval;
|
||||
// load more fuel if the current maximum output is only 50% of the current load
|
||||
// or if the fuel rod is (almost) deplenished
|
||||
float minCondition = fuelConsumptionRate * MathUtils.Pow2((degreeOfSuccess - refuelLimit) * 2);
|
||||
float minCondition = GetFuelConsumption() * MathUtils.Pow2((degreeOfSuccess - refuelLimit) * 2);
|
||||
if (NeedMoreFuel(minimumOutputRatio: 0.5f, minCondition: minCondition))
|
||||
{
|
||||
bool outOfFuel = false;
|
||||
@@ -871,5 +872,8 @@ namespace Barotrauma.Items.Components
|
||||
if (GameMain.NetworkMember is { IsServer: true }) { unsentChanges = true; }
|
||||
}
|
||||
}
|
||||
|
||||
private float GetMaxOutput() => item.StatManager.GetAdjustedValue(ItemTalentStats.ReactorMaxOutput, MaxPowerOutput);
|
||||
private float GetFuelConsumption() => item.StatManager.GetAdjustedValue(ItemTalentStats.ReactorFuelEfficiency, fuelConsumptionRate);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -151,15 +151,7 @@ namespace Barotrauma.Items.Components
|
||||
set
|
||||
{
|
||||
bool changed = currentMode != value;
|
||||
|
||||
currentMode = value;
|
||||
if (value == Mode.Passive)
|
||||
{
|
||||
if (item.AiTarget != null)
|
||||
{
|
||||
item.AiTarget.SectorDegrees = 360.0f;
|
||||
}
|
||||
}
|
||||
#if CLIENT
|
||||
if (changed) { prevPassivePingRadius = float.MaxValue; }
|
||||
UpdateGUIElements();
|
||||
@@ -206,13 +198,6 @@ namespace Barotrauma.Items.Components
|
||||
var activePing = activePings[currentPingIndex];
|
||||
if (activePing.State > 1.0f)
|
||||
{
|
||||
if (item.AiTarget != null)
|
||||
{
|
||||
float range = MathUtils.InverseLerp(item.AiTarget.MinSoundRange, item.AiTarget.MaxSoundRange, Range * activePing.State / zoom);
|
||||
item.AiTarget.SoundRange = MathHelper.Lerp(item.AiTarget.MinSoundRange, item.AiTarget.MaxSoundRange, range);
|
||||
item.AiTarget.SectorDegrees = activePing.IsDirectional ? DirectionalPingSector : 360.0f;
|
||||
item.AiTarget.SectorDir = new Vector2(pingDirection.X, -pingDirection.Y);
|
||||
}
|
||||
aiPingCheckPending = true;
|
||||
currentPingIndex = -1;
|
||||
}
|
||||
@@ -228,21 +213,27 @@ namespace Barotrauma.Items.Components
|
||||
activePings[currentPingIndex].Direction = pingDirection;
|
||||
activePings[currentPingIndex].State = 0.0f;
|
||||
activePings[currentPingIndex].PrevPingRadius = 0.0f;
|
||||
if (item.AiTarget != null)
|
||||
{
|
||||
item.AiTarget.SectorDegrees = useDirectionalPing ? DirectionalPingSector : 360.0f;
|
||||
item.AiTarget.SectorDir = new Vector2(pingDirection.X, -pingDirection.Y);
|
||||
}
|
||||
item.Use(deltaTime);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (item.AiTarget != null)
|
||||
{
|
||||
item.AiTarget.SectorDegrees = 360.0f;
|
||||
}
|
||||
aiPingCheckPending = false;
|
||||
}
|
||||
}
|
||||
|
||||
for (var pingIndex = 0; pingIndex < activePingsCount;)
|
||||
{
|
||||
if (item.AiTarget != null)
|
||||
{
|
||||
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));
|
||||
}
|
||||
if (activePings[pingIndex].State > 1.0f)
|
||||
{
|
||||
var lastIndex = --activePingsCount;
|
||||
|
||||
@@ -144,6 +144,11 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
public float TargetVelocityLengthSquared
|
||||
{
|
||||
get => TargetVelocity.LengthSquared();
|
||||
}
|
||||
|
||||
public Vector2 SteeringInput
|
||||
{
|
||||
get { return steeringInput; }
|
||||
|
||||
Reference in New Issue
Block a user