Unstable 0.1500.0.0

This commit is contained in:
Markus Isberg
2021-08-26 21:08:21 +09:00
parent 265a2e7ab3
commit 501e02c026
245 changed files with 9775 additions and 2034 deletions
@@ -122,6 +122,12 @@ namespace Barotrauma.Items.Components
float voltageFactor = MinVoltage <= 0.0f ? 1.0f : Math.Min(Voltage, 1.0f);
Vector2 currForce = new Vector2(force * maxForce * forceMultiplier * voltageFactor, 0.0f);
if (item.GetComponent<Repairable>()?.IsTinkering ?? false)
{
currForce *= 2.5f;
}
//less effective when in a bad condition
currForce *= MathHelper.Lerp(0.5f, 2.0f, item.Condition / item.MaxCondition);
if (item.Submarine.FlippedX) { currForce *= -1; }
@@ -4,8 +4,8 @@ using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Security.Cryptography;
using System.Xml.Linq;
using Barotrauma.Abilities;
namespace Barotrauma.Items.Components
{
@@ -24,6 +24,12 @@ namespace Barotrauma.Items.Components
private Character user;
public float FabricationSpeedMultiplier
{
get;
set;
}
private ItemContainer inputContainer, outputContainer;
[Serialize(1.0f, true)]
@@ -240,8 +246,10 @@ namespace Barotrauma.Items.Components
public override void Update(float deltaTime, Camera cam)
{
if (fabricatedItem == null || !CanBeFabricated(fabricatedItem))
var availableIngredients = GetAvailableIngredients();
if (fabricatedItem == null || !CanBeFabricated(fabricatedItem, availableIngredients, user))
{
FabricationSpeedMultiplier = 1f;
CancelFabricating();
return;
}
@@ -278,38 +286,56 @@ namespace Barotrauma.Items.Components
if (powerConsumption <= 0) { Voltage = 1.0f; }
timeUntilReady -= deltaTime * Math.Min(Voltage, 1.0f);
timeUntilReady -= deltaTime * Math.Min(Voltage, 1.0f) * FabricationSpeedMultiplier;
FabricationSpeedMultiplier = 1f;
UpdateRequiredTimeProjSpecific();
if (timeUntilReady > 0.0f) { return; }
if (GameMain.NetworkMember == null || GameMain.NetworkMember.IsServer)
{
var availableIngredients = GetAvailableIngredients();
foreach (FabricationRecipe.RequiredItem ingredient in fabricatedItem.RequiredItems)
{
for (int i = 0; i < ingredient.Amount; i++)
fabricatedItem.RequiredItems.ForEach(requiredItem => {
for (int usedPrefabsAmount = 0; usedPrefabsAmount < requiredItem.Amount; usedPrefabsAmount++)
{
var availableItem = availableIngredients.FirstOrDefault(it =>
it != null && ingredient.ItemPrefabs.Contains(it.Prefab) &&
it.ConditionPercentage >= ingredient.MinCondition * 100.0f &&
it.ConditionPercentage <= ingredient.MaxCondition * 100.0f);
if (availableItem == null) { continue; }
if (ingredient.UseCondition && availableItem.ConditionPercentage - ingredient.MinCondition * 100 > 0.0f) //Leave it behind with reduced condition if it has enough to stay above 0
foreach (ItemPrefab requiredPrefab in requiredItem.ItemPrefabs)
{
availableItem.Condition -= availableItem.Prefab.Health * ingredient.MinCondition;
continue;
if (!availableIngredients.ContainsKey(requiredPrefab.Identifier)) { continue; }
var availablePrefabs = availableIngredients[requiredPrefab.Identifier];
var availablePrefab = availablePrefabs.FirstOrDefault(potentialPrefab =>
{
return potentialPrefab.ConditionPercentage >= requiredItem.MinCondition * 100.0f &&
potentialPrefab.ConditionPercentage <= requiredItem.MaxCondition * 100.0f;
});
if (availablePrefab == null) { continue; }
if (requiredItem.UseCondition && availablePrefab.ConditionPercentage - requiredItem.MinCondition * 100 > 0.0f) //Leave it behind with reduced condition if it has enough to stay above 0
{
availablePrefab.Condition -= availablePrefab.Prefab.Health * requiredItem.MinCondition;
continue;
}
availablePrefabs.Remove(availablePrefab);
Entity.Spawner.AddToRemoveQueue(availablePrefab);
inputContainer.Inventory.RemoveItem(availablePrefab);
}
availableIngredients.Remove(availableItem);
Entity.Spawner.AddToRemoveQueue(availableItem);
inputContainer.Inventory.RemoveItem(availableItem);
}
}
});
Character tempUser = user;
int amountFittingContainer = outputContainer.Inventory.HowManyCanBePut(fabricatedItem.TargetItem, fabricatedItem.OutCondition * fabricatedItem.TargetItem.Health);
for (int i = 0; i < fabricatedItem.Amount; i++)
var itemsCreated = new AbilityValue(fabricatedItem.Amount);
foreach (Character character in Character.CharacterList.Where(c => c.TeamID == user.TeamID))
{
character.CheckTalents(AbilityEffectType.OnAllyItemFabricatedAmount, (fabricatedItem.TargetItem, itemsCreated));
}
tempUser.CheckTalents(AbilityEffectType.OnItemFabricatedAmount, (fabricatedItem.TargetItem, itemsCreated));
for (int i = 0; i < (int)itemsCreated.Value; i++)
{
if (i < amountFittingContainer)
{
@@ -339,9 +365,13 @@ namespace Barotrauma.Items.Components
foreach (Skill skill in fabricatedItem.RequiredSkills)
{
float userSkill = user.GetSkillLevel(skill.Identifier);
float addedSkill = skill.Level * SkillSettings.Current.SkillIncreasePerFabricatorRequiredSkill / Math.Max(userSkill, 1.0f);
var addedSkillValue = new AbilityValue(0f);
user.CheckTalents(AbilityEffectType.OnItemFabricationSkillGain, addedSkillValue);
user.Info.IncreaseSkillLevel(
skill.Identifier,
skill.Level * SkillSettings.Current.SkillIncreasePerFabricatorRequiredSkill / Math.Max(userSkill, 1.0f),
addedSkill + addedSkillValue.Value,
user.Position + Vector2.UnitY * 150.0f);
}
}
@@ -365,24 +395,36 @@ namespace Barotrauma.Items.Components
partial void UpdateRequiredTimeProjSpecific();
private bool CanBeFabricated(FabricationRecipe fabricableItem)
private bool CanBeFabricated(FabricationRecipe fabricableItem, Dictionary<string, List<Item>> availableIngredients, Character character)
{
if (fabricableItem == null) { return false; }
List<Item> availableIngredients = GetAvailableIngredients();
return CanBeFabricated(fabricableItem, availableIngredients);
}
if (fabricableItem.RequiresRecipe && (character == null || !character.HasRecipeForItem(fabricableItem.TargetItem.Identifier))) { return false; }
private bool CanBeFabricated(FabricationRecipe fabricableItem, IEnumerable<Item> availableIngredients)
{
if (fabricableItem == null) { return false; }
foreach (FabricationRecipe.RequiredItem requiredItem in fabricableItem.RequiredItems)
return fabricableItem.RequiredItems.All(requiredItem =>
{
if (availableIngredients.Count(it => IsItemValidIngredient(it, requiredItem)) < requiredItem.Amount)
int availablePrefabsAmount = 0;
foreach (ItemPrefab requiredPrefab in requiredItem.ItemPrefabs)
{
return false;
if (!availableIngredients.ContainsKey(requiredPrefab.Identifier)) { continue; }
var availablePrefabs = availableIngredients[requiredPrefab.Identifier];
foreach (Item availablePrefab in availablePrefabs)
{
if (availablePrefab.Condition / availablePrefab.Prefab.Health >= requiredItem.MinCondition &&
availablePrefab.Condition / availablePrefab.Prefab.Health <= requiredItem.MaxCondition)
{
availablePrefabsAmount++;
}
if (availablePrefabsAmount >= requiredItem.Amount)
{
return true;
}
}
}
}
return true;
return false;
});
}
private float GetRequiredTime(FabricationRecipe fabricableItem, Character user)
@@ -416,7 +458,7 @@ namespace Barotrauma.Items.Components
/// Get a list of all items available in the input container and linked containers
/// </summary>
/// <returns></returns>
private List<Item> GetAvailableIngredients()
private Dictionary<string, List<Item>> GetAvailableIngredients()
{
List<Item> availableIngredients = new List<Item>();
availableIngredients.AddRange(inputContainer.Inventory.AllItems);
@@ -448,7 +490,19 @@ namespace Barotrauma.Items.Components
}
#endif
return availableIngredients;
Dictionary<string, List<Item>> ingredientsDictionary = new Dictionary<string, List<Item>>();
for (int i = 0; i < availableIngredients.Count; i++)
{
var itemIdentifier = availableIngredients[i].prefab.Identifier;
if (!ingredientsDictionary.ContainsKey(itemIdentifier))
{
ingredientsDictionary[itemIdentifier] = new List<Item>(availableIngredients.Count);
}
ingredientsDictionary[itemIdentifier].Add(availableIngredients[i]);
}
return ingredientsDictionary;
}
/// <summary>
@@ -463,40 +517,41 @@ namespace Barotrauma.Items.Components
bool isClient = GameMain.NetworkMember != null && GameMain.NetworkMember.IsClient;
var availableIngredients = GetAvailableIngredients();
foreach (var requiredItem in targetItem.RequiredItems)
{
targetItem.RequiredItems.ForEach(requiredItem => {
for (int i = 0; i < requiredItem.Amount; i++)
{
var matchingItem = availableIngredients.Find(it => !usedItems.Contains(it) && IsItemValidIngredient(it, requiredItem));
if (matchingItem == null) { continue; }
foreach (ItemPrefab requiredPrefab in requiredItem.ItemPrefabs)
{
if (!availableIngredients.ContainsKey(requiredPrefab.Identifier)) { continue; }
availableIngredients.Remove(matchingItem);
if (matchingItem.ParentInventory == inputContainer.Inventory)
{
//already in input container, all good
usedItems.Add(matchingItem);
}
else //in another inventory, we need to move the item
{
if (!inputContainer.Inventory.CanBePut(matchingItem))
var availablePrefabs = availableIngredients[requiredPrefab.Identifier];
var availablePrefab = availablePrefabs.FirstOrDefault(potentialPrefab =>
{
var unneededItem = inputContainer.Inventory.AllItems.FirstOrDefault(it => !usedItems.Contains(it));
unneededItem?.Drop(null, createNetworkEvent: !isClient);
}
inputContainer.Inventory.TryPutItem(matchingItem, user: null, createNetworkEvent: !isClient);
}
}
}
}
return !usedItems.Contains(potentialPrefab) &&
potentialPrefab.ConditionPercentage >= requiredItem.MinCondition * 100.0f &&
potentialPrefab.ConditionPercentage <= requiredItem.MaxCondition * 100.0f;
});
if (availablePrefab == null) { continue; }
private bool IsItemValidIngredient(Item item, FabricationRecipe.RequiredItem requiredItem)
{
return
item != null &&
requiredItem.ItemPrefabs.Contains(item.prefab) &&
item.Condition / item.Prefab.Health >= requiredItem.MinCondition &&
item.Condition / item.Prefab.Health <= requiredItem.MaxCondition;
availablePrefabs.Remove(availablePrefab);
if (availablePrefab.ParentInventory == inputContainer.Inventory)
{
//already in input container, all good
usedItems.Add(availablePrefab);
}
else //in another inventory, we need to move the item
{
if (!inputContainer.Inventory.CanBePut(availablePrefab))
{
var unneededItem = inputContainer.Inventory.AllItems.FirstOrDefault(it => !usedItems.Contains(it));
unneededItem?.Drop(null, createNetworkEvent: !isClient);
}
inputContainer.Inventory.TryPutItem(availablePrefab, user: null, createNetworkEvent: !isClient);
}
}
}
});
}
public override XElement Save(XElement parentElement)
@@ -7,10 +7,15 @@ namespace Barotrauma.Items.Components
{
partial class MiniMap : Powered
{
class HullData
internal class HullData
{
public float? Oxygen;
public float? Water;
public float? HullOxygenAmount,
HullWaterAmount;
public float? ReceivedOxygenAmount,
ReceivedWaterAmount;
public readonly HashSet<IdCard> Cards = new HashSet<IdCard>();
public bool Distort;
public float DistortionTimer;
@@ -45,17 +50,45 @@ namespace Barotrauma.Items.Components
set;
}
[Editable, Serialize(true, true, description: "Enable hull status mode.")]
public bool EnableHullStatus
{
get;
set;
}
[Editable, Serialize(true, true, description: "Enable electrical view mode.")]
public bool EnableElectricalView
{
get;
set;
}
[Editable, Serialize(true, true, description: "Enable hull condition mode.")]
public bool EnableHullCondition
{
get;
set;
}
[Editable, Serialize(true, true, description: "Enable item finder mode.")]
public bool EnableItemFinder
{
get;
set;
}
public MiniMap(Item item, XElement element)
: base(item, element)
{
IsActive = true;
hullDatas = new Dictionary<Hull, HullData>();
InitProjSpecific(element);
InitProjSpecific();
}
partial void InitProjSpecific(XElement element);
partial void InitProjSpecific();
public override void Update(float deltaTime, Camera cam)
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)
@@ -65,13 +98,29 @@ namespace Barotrauma.Items.Components
{
if (!hullData.Distort)
{
hullData.Oxygen = null;
hullData.Water = null;
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
currPowerConsumption = powerConsumption;
currPowerConsumption *= MathHelper.Lerp(1.5f, 1.0f, item.Condition / item.MaxCondition);
@@ -81,7 +130,7 @@ namespace Barotrauma.Items.Components
ApplyStatusEffects(ActionType.OnActive, deltaTime, null);
}
}
public override bool Pick(Character picker)
{
return picker != null;
@@ -107,11 +156,11 @@ namespace Barotrauma.Items.Components
//cheating a bit because water detectors don't actually send the water level
if (source.GetComponent<WaterDetector>() == null)
{
hullData.Water = Rand.Range(0.0f, 1.0f);
hullData.ReceivedWaterAmount = Rand.Range(0.0f, 1.0f);
}
else
{
hullData.Water = Math.Min(sourceHull.WaterVolume / sourceHull.Volume, 1.0f);
hullData.ReceivedWaterAmount = Math.Min(sourceHull.WaterVolume / sourceHull.Volume, 1.0f);
}
break;
case "oxygen_data_in":
@@ -122,7 +171,7 @@ namespace Barotrauma.Items.Components
oxy = Rand.Range(0.0f, 100.0f);
}
hullData.Oxygen = oxy;
hullData.ReceivedOxygenAmount = oxy;
break;
}
}
@@ -105,6 +105,12 @@ namespace Barotrauma.Items.Components
float powerFactor = Math.Min(currPowerConsumption <= 0.0f || MinVoltage <= 0.0f ? 1.0f : Voltage, 1.0f);
currFlow = flowPercentage / 100.0f * maxFlow * powerFactor;
if (item.GetComponent<Repairable>()?.IsTinkering ?? false)
{
currFlow *= 2.5f;
}
//less effective when in a bad condition
currFlow *= MathHelper.Lerp(0.5f, 1.0f, item.Condition / item.MaxCondition);
@@ -1,4 +1,4 @@
using Barotrauma.Networking;
using Barotrauma.Networking;
using FarseerPhysics;
using Microsoft.Xna.Framework;
using System;
@@ -364,6 +364,19 @@ namespace Barotrauma.Items.Components
float velY = MathHelper.Lerp((neutralBallastLevel * 100 - 50) * 2, -100 * Math.Sign(targetVelocity.Y), Math.Abs(targetVelocity.Y) / 100.0f);
item.SendSignal(new Signal(velY.ToString(CultureInfo.InvariantCulture), sender: user), "velocity_y_out");
// converts the controlled sub's velocity to km/h and sends it.
// TODO: add current_velocity_x and current_velocity_y pins on the navigation terminals and shuttle terminals
// TODO: increase the size of the connection panels of both navigation terminals
if (controlledSub is { } sub)
{
item.SendSignal(new Signal((ConvertUnits.ToDisplayUnits(sub.Velocity.X * Physics.DisplayToRealWorldRatio) * 3.6f).ToString("0.0000", CultureInfo.InvariantCulture), sender: user), "current_velocity_x");
item.SendSignal(new Signal((ConvertUnits.ToDisplayUnits(sub.Velocity.Y * Physics.DisplayToRealWorldRatio) * -3.6f).ToString("0.0000", CultureInfo.InvariantCulture), sender: user), "current_velocity_y");
item.SendSignal(new Signal(sub.WorldPosition.X.ToString("0.0000", CultureInfo.InvariantCulture), sender: user), "current_position_x");
item.SendSignal(new Signal(sub.RealWorldDepth.ToString("0.0000", CultureInfo.InvariantCulture), sender: user), "current_depth");
}
// if our tactical AI pilot has left, revert back to maintaining position
if (navigateTactically && (user == null || user.SelectedConstruction != item))
{