(45f083a5a) Merge branch 'dev' of https://github.com/Regalis11/Barotrauma-development into dev
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
using FarseerPhysics;
|
||||
using Barotrauma.Networking;
|
||||
using FarseerPhysics;
|
||||
using FarseerPhysics.Collision;
|
||||
using FarseerPhysics.Dynamics;
|
||||
using Microsoft.Xna.Framework;
|
||||
@@ -164,11 +165,12 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
//set the rotation of the projectile again because dropping the projectile resets the rotation
|
||||
projectile.Item.SetTransform(projectilePos,
|
||||
rotation + ((item.body.Dir == 1.0f) ? projectile.LaunchRotationRadians : projectile.LaunchRotationRadians - MathHelper.Pi));
|
||||
rotation + (projectile.Item.body.Dir * projectile.LaunchRotationRadians));
|
||||
|
||||
//recoil
|
||||
item.body.ApplyLinearImpulse(
|
||||
new Vector2((float)Math.Cos(projectile.Item.body.Rotation), (float)Math.Sin(projectile.Item.body.Rotation)) * item.body.Mass * -50.0f);
|
||||
new Vector2((float)Math.Cos(projectile.Item.body.Rotation), (float)Math.Sin(projectile.Item.body.Rotation)) * item.body.Mass * -50.0f,
|
||||
maxVelocity: NetConfig.MaxPhysicsBodyVelocity);
|
||||
|
||||
item.RemoveContained(projectile.Item);
|
||||
|
||||
|
||||
@@ -303,10 +303,8 @@ namespace Barotrauma.Items.Components
|
||||
// Too close -> steer away
|
||||
character.AIController.SteeringManager.SteeringManual(deltaTime, Vector2.Normalize(character.SimPosition - leak.SimPosition) / 2);
|
||||
}
|
||||
else if (!character.IsClimbing)
|
||||
else
|
||||
{
|
||||
// Close enough -> stop if not in ladders.
|
||||
// In ladders, we most likely want to move back and forth, because we cannot aim -> if the leak is on the side, it should get fixed.
|
||||
character.AIController.SteeringManager.Reset();
|
||||
}
|
||||
}
|
||||
@@ -317,7 +315,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
// Press the trigger only when the tool is approximately facing the target.
|
||||
// If the character is climbing, ignore the check, because we cannot aim while climbing.
|
||||
if (character.IsClimbing || VectorExtensions.Angle(VectorExtensions.Forward(item.body.TransformedRotation), fromItemToLeak) < MathHelper.PiOver4)
|
||||
if (VectorExtensions.Angle(VectorExtensions.Forward(item.body.TransformedRotation), fromItemToLeak) < MathHelper.PiOver4)
|
||||
{
|
||||
Use(deltaTime, character);
|
||||
}
|
||||
|
||||
@@ -106,10 +106,10 @@ namespace Barotrauma.Items.Components
|
||||
#endif
|
||||
Character thrower = picker;
|
||||
item.Drop(thrower, createNetworkEvent: GameMain.NetworkMember == null || GameMain.NetworkMember.IsServer);
|
||||
item.body.ApplyLinearImpulse(throwVector * throwForce * item.body.Mass * 3.0f);
|
||||
item.body.ApplyLinearImpulse(throwVector * throwForce * item.body.Mass * 3.0f, maxVelocity: NetConfig.MaxPhysicsBodyVelocity);
|
||||
|
||||
ac.GetLimb(LimbType.Head).body.ApplyLinearImpulse(throwVector*10.0f);
|
||||
ac.GetLimb(LimbType.Torso).body.ApplyLinearImpulse(throwVector * 10.0f);
|
||||
ac.GetLimb(LimbType.Head).body.ApplyLinearImpulse(throwVector * 10.0f, maxVelocity: NetConfig.MaxPhysicsBodyVelocity);
|
||||
ac.GetLimb(LimbType.Torso).body.ApplyLinearImpulse(throwVector * 10.0f, maxVelocity: NetConfig.MaxPhysicsBodyVelocity);
|
||||
|
||||
Limb rightHand = ac.GetLimb(LimbType.RightHand);
|
||||
item.body.AngularVelocity = rightHand.body.AngularVelocity;
|
||||
|
||||
@@ -538,7 +538,6 @@ namespace Barotrauma.Items.Components
|
||||
GameAnalyticsManager.AddErrorEventOnce("ItemComponent.DegreeOfSuccess:CharacterNull", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
|
||||
return 0.0f;
|
||||
}
|
||||
float average = skillSuccessSum / requiredSkills.Count;
|
||||
|
||||
float skillSuccessSum = 0.0f;
|
||||
for (int i = 0; i < requiredSkills.Count; i++)
|
||||
@@ -735,15 +734,13 @@ namespace Barotrauma.Items.Components
|
||||
private void OverrideRequiredItems(XElement element)
|
||||
{
|
||||
var prevRequiredItems = new Dictionary<RelatedItem.RelationType, List<RelatedItem>>(requiredItems);
|
||||
bool overrideRequiredItems = false;
|
||||
requiredItems.Clear();
|
||||
|
||||
foreach (XElement subElement in element.Elements())
|
||||
{
|
||||
switch (subElement.Name.ToString().ToLowerInvariant())
|
||||
{
|
||||
case "requireditem":
|
||||
if (!overrideRequiredItems) requiredItems.Clear();
|
||||
overrideRequiredItems = true;
|
||||
|
||||
RelatedItem newRequiredItem = RelatedItem.Load(subElement, item.Name);
|
||||
if (newRequiredItem == null) continue;
|
||||
|
||||
|
||||
@@ -90,7 +90,7 @@ namespace Barotrauma.Items.Components
|
||||
Force = MathHelper.Lerp(force, (voltage < minVoltage) ? 0.0f : targetForce, 0.1f);
|
||||
if (Math.Abs(Force) > 1.0f)
|
||||
{
|
||||
Vector2 currForce = new Vector2((force / 100.0f) * maxForce * Math.Min(voltage / minVoltage, 1.0f), 0.0f);
|
||||
Vector2 currForce = new Vector2((force / 10.0f) * maxForce * Math.Min(voltage / minVoltage, 1.0f), 0.0f);
|
||||
//less effective when in a bad condition
|
||||
currForce *= MathHelper.Lerp(0.5f, 2.0f, item.Condition / item.MaxCondition);
|
||||
|
||||
|
||||
@@ -9,138 +9,13 @@ using System.Xml.Linq;
|
||||
namespace Barotrauma.Items.Components
|
||||
{
|
||||
|
||||
partial class Fabricator : Powered, IServerSerializable, IClientSerializable
|
||||
{
|
||||
public class RequiredItem
|
||||
{
|
||||
public readonly ItemPrefab ItemPrefab;
|
||||
public int Amount;
|
||||
public readonly float MinCondition;
|
||||
public readonly bool UseCondition;
|
||||
|
||||
public RequiredItem(ItemPrefab itemPrefab, int amount, float minCondition, bool useCondition)
|
||||
{
|
||||
ItemPrefab = itemPrefab;
|
||||
Amount = amount;
|
||||
MinCondition = minCondition;
|
||||
UseCondition = useCondition;
|
||||
}
|
||||
}
|
||||
|
||||
public readonly ItemPrefab TargetItem;
|
||||
|
||||
public readonly string DisplayName;
|
||||
|
||||
public readonly List<RequiredItem> RequiredItems;
|
||||
|
||||
private FabricationRecipe fabricatedItem;
|
||||
private float timeUntilReady;
|
||||
private float requiredTime;
|
||||
|
||||
private Character user;
|
||||
|
||||
private ItemContainer inputContainer, outputContainer;
|
||||
|
||||
public readonly List<Skill> RequiredSkills;
|
||||
|
||||
public FabricableItem(XElement element)
|
||||
{
|
||||
if (element.Attribute("name") != null)
|
||||
{
|
||||
string name = element.Attribute("name").Value;
|
||||
DebugConsole.ThrowError("Error in fabricable item config (" + name + ") - use item identifiers instead of names");
|
||||
TargetItem = MapEntityPrefab.Find(name) as ItemPrefab;
|
||||
if (TargetItem == null)
|
||||
{
|
||||
DebugConsole.ThrowError("Error in fabricable item config - item prefab \"" + name + "\" not found.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
string identifier = element.GetAttributeString("identifier", "");
|
||||
TargetItem = MapEntityPrefab.Find(null, identifier) as ItemPrefab;
|
||||
if (TargetItem == null)
|
||||
{
|
||||
DebugConsole.ThrowError("Error in fabricable item config - item prefab \"" + identifier + "\" not found.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
string displayName = element.GetAttributeString("displayname", "");
|
||||
DisplayName = string.IsNullOrEmpty(displayName) ? TargetItem.Name : TextManager.Get($"DisplayName.{displayName}");
|
||||
|
||||
RequiredSkills = new List<Skill>();
|
||||
RequiredTime = element.GetAttributeFloat("requiredtime", 1.0f);
|
||||
OutCondition = element.GetAttributeFloat("outcondition", 1.0f);
|
||||
RequiredItems = new List<RequiredItem>();
|
||||
|
||||
foreach (XElement subElement in element.Elements())
|
||||
{
|
||||
if (!(me is ItemPrefab itemPrefab)) { continue; }
|
||||
|
||||
foreach (FabricationRecipe recipe in itemPrefab.FabricationRecipes)
|
||||
{
|
||||
case "requiredskill":
|
||||
if (subElement.Attribute("name") != null)
|
||||
{
|
||||
DebugConsole.ThrowError("Error in fabricable item " + TargetItem.Name + "! Use skill identifiers instead of names.");
|
||||
continue;
|
||||
}
|
||||
|
||||
RequiredSkills.Add(new Skill(
|
||||
subElement.GetAttributeString("identifier", ""),
|
||||
subElement.GetAttributeInt("level", 0)));
|
||||
break;
|
||||
case "item":
|
||||
case "requireditem":
|
||||
string requiredItemIdentifier = subElement.GetAttributeString("identifier", "");
|
||||
if (string.IsNullOrWhiteSpace(requiredItemIdentifier))
|
||||
{
|
||||
DebugConsole.ThrowError("Error in fabricable item " + TargetItem.Name + "! One of the required items has no identifier.");
|
||||
continue;
|
||||
}
|
||||
|
||||
float minCondition = subElement.GetAttributeFloat("mincondition", 1.0f);
|
||||
//Substract mincondition from required item's condition or delete it regardless?
|
||||
bool useCondition = subElement.GetAttributeBool("usecondition", true);
|
||||
int count = subElement.GetAttributeInt("count", 1);
|
||||
|
||||
|
||||
ItemPrefab requiredItem = MapEntityPrefab.Find(null, requiredItemIdentifier.Trim()) as ItemPrefab;
|
||||
if (requiredItem == null)
|
||||
{
|
||||
DebugConsole.ThrowError("Error in fabricable item " + TargetItem.Name + "! Required item \"" + requiredItemIdentifier + "\" not found.");
|
||||
continue;
|
||||
}
|
||||
|
||||
var existing = RequiredItems.Find(r => r.ItemPrefab == requiredItem);
|
||||
if (existing == null)
|
||||
{
|
||||
RequiredItems.Add(new RequiredItem(requiredItem, count, minCondition, useCondition));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
RequiredItems.Remove(existing);
|
||||
RequiredItems.Add(new RequiredItem(requiredItem, existing.Amount + count, minCondition, useCondition));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
InitProjSpecific();
|
||||
}
|
||||
}
|
||||
|
||||
partial class Fabricator : Powered, IServerSerializable, IClientSerializable
|
||||
{
|
||||
public const float SkillIncreaseMultiplier = 0.5f;
|
||||
|
||||
private List<FabricableItem> fabricableItems;
|
||||
private List<FabricationRecipe> fabricationRecipes = new List<FabricationRecipe>();
|
||||
|
||||
private FabricableItem fabricatedItem;
|
||||
private FabricationRecipe fabricatedItem;
|
||||
private float timeUntilReady;
|
||||
private float requiredTime;
|
||||
|
||||
@@ -152,6 +27,37 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
public Fabricator(Item item, XElement element)
|
||||
: base(item, element)
|
||||
{
|
||||
foreach (XElement subElement in element.Elements())
|
||||
{
|
||||
if (subElement.Name.ToString().ToLowerInvariant() == "fabricableitem")
|
||||
{
|
||||
DebugConsole.ThrowError("Error in item " + item.Name + "! Fabrication recipes should be defined in the craftable item's xml, not in the fabricator.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (MapEntityPrefab me in MapEntityPrefab.List)
|
||||
{
|
||||
if (!(me is ItemPrefab itemPrefab)) { continue; }
|
||||
|
||||
foreach (FabricationRecipe recipe in itemPrefab.FabricationRecipes)
|
||||
{
|
||||
if (recipe.SuitableFabricatorIdentifiers.Length > 0)
|
||||
{
|
||||
if (!recipe.SuitableFabricatorIdentifiers.Any(i => item.prefab.Identifier == i || item.HasTag(i)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
fabricationRecipes.Add(recipe);
|
||||
}
|
||||
}
|
||||
|
||||
InitProjSpecific();
|
||||
}
|
||||
|
||||
public override void OnItemLoaded()
|
||||
{
|
||||
var containers = item.GetComponents<ItemContainer>().ToList();
|
||||
if (containers.Count < 2)
|
||||
@@ -175,30 +81,6 @@ namespace Barotrauma.Items.Components
|
||||
OnItemLoadedProjSpecific();
|
||||
}
|
||||
|
||||
public override void OnItemLoaded()
|
||||
{
|
||||
var containers = item.GetComponents<ItemContainer>().ToList();
|
||||
if (containers.Count < 2)
|
||||
{
|
||||
DebugConsole.ThrowError("Error in item \"" + item.Name + "\": Fabricators must have two ItemContainer components!");
|
||||
return;
|
||||
}
|
||||
|
||||
inputContainer = containers[0];
|
||||
outputContainer = containers[1];
|
||||
|
||||
foreach (FabricableItem fabricableItem in fabricableItems)
|
||||
{
|
||||
int ingredientCount = fabricableItem.RequiredItems.Sum(it => it.Amount);
|
||||
if (ingredientCount > inputContainer.Capacity)
|
||||
{
|
||||
DebugConsole.ThrowError("Error in item \"" + item.Name + "\": There's not enough room in the input inventory for the ingredients of \"" + fabricableItem.TargetItem.Name + "\"!");
|
||||
}
|
||||
}
|
||||
|
||||
OnItemLoadedProjSpecific();
|
||||
}
|
||||
|
||||
partial void OnItemLoadedProjSpecific();
|
||||
|
||||
|
||||
@@ -217,7 +99,7 @@ namespace Barotrauma.Items.Components
|
||||
return (picker != null);
|
||||
}
|
||||
|
||||
private void StartFabricating(FabricableItem selectedItem, Character user)
|
||||
private void StartFabricating(FabricationRecipe selectedItem, Character user)
|
||||
{
|
||||
if (selectedItem == null) return;
|
||||
if (!outputContainer.Inventory.IsEmpty()) return;
|
||||
@@ -302,7 +184,7 @@ namespace Barotrauma.Items.Components
|
||||
if (timeUntilReady > 0.0f) { return; }
|
||||
|
||||
var availableIngredients = GetAvailableIngredients();
|
||||
foreach (FabricableItem.RequiredItem ingredient in fabricatedItem.RequiredItems)
|
||||
foreach (FabricationRecipe.RequiredItem ingredient in fabricatedItem.RequiredItems)
|
||||
{
|
||||
for (int i = 0; i < ingredient.Amount; i++)
|
||||
{
|
||||
@@ -328,13 +210,8 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
Entity.Spawner.AddToSpawnQueue(fabricatedItem.TargetItem, outputContainer.Inventory, fabricatedItem.TargetItem.Health * fabricatedItem.OutCondition);
|
||||
}
|
||||
|
||||
bool isNotClient = true;
|
||||
#if CLIENT
|
||||
isNotClient = GameMain.Client == null;
|
||||
#endif
|
||||
|
||||
if (isNotClient && user != null)
|
||||
|
||||
if ((GameMain.NetworkMember == null || GameMain.NetworkMember.IsServer) && user != null && !user.Removed)
|
||||
{
|
||||
foreach (Skill skill in fabricatedItem.RequiredSkills)
|
||||
{
|
||||
@@ -345,17 +222,17 @@ namespace Barotrauma.Items.Components
|
||||
CancelFabricating(null);
|
||||
}
|
||||
|
||||
private bool CanBeFabricated(FabricableItem fabricableItem)
|
||||
private bool CanBeFabricated(FabricationRecipe fabricableItem)
|
||||
{
|
||||
if (fabricableItem == null) { return false; }
|
||||
List<Item> availableIngredients = GetAvailableIngredients();
|
||||
return CanBeFabricated(fabricableItem, availableIngredients);
|
||||
}
|
||||
|
||||
private bool CanBeFabricated(FabricableItem fabricableItem, IEnumerable<Item> availableIngredients)
|
||||
private bool CanBeFabricated(FabricationRecipe fabricableItem, IEnumerable<Item> availableIngredients)
|
||||
{
|
||||
if (fabricableItem == null) { return false; }
|
||||
foreach (FabricableItem.RequiredItem requiredItem in fabricableItem.RequiredItems)
|
||||
foreach (FabricationRecipe.RequiredItem requiredItem in fabricableItem.RequiredItems)
|
||||
{
|
||||
if (availableIngredients.Count(it => IsItemValidIngredient(it, requiredItem)) < requiredItem.Amount)
|
||||
{
|
||||
@@ -365,7 +242,7 @@ namespace Barotrauma.Items.Components
|
||||
return true;
|
||||
}
|
||||
|
||||
private float GetRequiredTime(FabricableItem fabricableItem, Character user)
|
||||
private float GetRequiredTime(FabricationRecipe fabricableItem, Character user)
|
||||
{
|
||||
float degreeOfSuccess = DegreeOfSuccess(user, fabricableItem.RequiredSkills);
|
||||
|
||||
@@ -407,7 +284,7 @@ namespace Barotrauma.Items.Components
|
||||
/// Move the items required for fabrication into the input container.
|
||||
/// The method assumes that all the required ingredients are available either in the input container or linked containers.
|
||||
/// </summary>
|
||||
private void MoveIngredientsToInputContainer(FabricableItem targetItem)
|
||||
private void MoveIngredientsToInputContainer(FabricationRecipe targetItem)
|
||||
{
|
||||
//required ingredients that are already present in the input container
|
||||
List<Item> usedItems = new List<Item>();
|
||||
@@ -438,7 +315,7 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsItemValidIngredient(Item item, FabricableItem.RequiredItem requiredItem)
|
||||
private bool IsItemValidIngredient(Item item, FabricationRecipe.RequiredItem requiredItem)
|
||||
{
|
||||
return
|
||||
item != null &&
|
||||
|
||||
@@ -377,23 +377,14 @@ namespace Barotrauma.Items.Components
|
||||
target.Body.ApplyLinearImpulse(item.body.LinearVelocity * item.body.Mass);
|
||||
return true;
|
||||
}
|
||||
else if (target.Body.UserData is Limb limb)
|
||||
{
|
||||
//severed limbs don't deactivate the projectile (but may still slow it down enough to make it inactive)
|
||||
if (limb.IsSevered)
|
||||
{
|
||||
target.Body.ApplyLinearImpulse(item.body.LinearVelocity * item.body.Mass);
|
||||
return true;
|
||||
}
|
||||
|
||||
limb.character.LastDamageSource = item;
|
||||
attackResult = attack.DoDamageToLimb(User, limb, item.WorldPosition, 1.0f);
|
||||
if (limb.character != null) character = limb.character;
|
||||
}
|
||||
else if (target.Body.UserData is Structure structure)
|
||||
{
|
||||
attackResult = attack.DoDamage(User, structure, item.WorldPosition, 1.0f);
|
||||
}
|
||||
limb.character.LastDamageSource = item;
|
||||
if (attack != null) { attackResult = attack.DoDamageToLimb(User, limb, item.WorldPosition, 1.0f); }
|
||||
if (limb.character != null) { character = limb.character; }
|
||||
}
|
||||
else if (target.Body.UserData is Structure structure)
|
||||
{
|
||||
if (attack != null) { attackResult = attack.DoDamage(User, structure, item.WorldPosition, 1.0f); }
|
||||
}
|
||||
|
||||
if (character != null) character.LastDamageSource = item;
|
||||
|
||||
@@ -22,6 +22,10 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
private float blinkTimer;
|
||||
|
||||
private bool itemLoaded;
|
||||
|
||||
private float blinkTimer;
|
||||
|
||||
public PhysicsBody ParentBody;
|
||||
|
||||
[Editable(MinValueFloat = 0.0f, MaxValueFloat = 2048.0f), Serialize(100.0f, true)]
|
||||
@@ -77,7 +81,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
IsActive = value;
|
||||
#if SERVER
|
||||
if (GameMain.Server != null && GameMain.Server.GameStarted) { item.CreateServerEvent(this); }
|
||||
if (GameMain.Server != null && itemLoaded) { item.CreateServerEvent(this); }
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -315,7 +315,7 @@ namespace Barotrauma.Items.Components
|
||||
Vector2 diff = nodes[nodes.Count - 1] - newNodePos;
|
||||
Vector2 pullBackDir = diff == Vector2.Zero ? Vector2.Zero : Vector2.Normalize(diff);
|
||||
|
||||
user.AnimController.Collider.ApplyForce(pullBackDir * user.Mass * 50.0f);
|
||||
user.AnimController.Collider.ApplyForce(pullBackDir * user.Mass * 50.0f, maxVelocity: NetConfig.MaxPhysicsBodyVelocity);
|
||||
user.AnimController.UpdateUseItem(true, user.WorldPosition + pullBackDir * 200.0f);
|
||||
|
||||
if (GameMain.NetworkMember == null || GameMain.NetworkMember.IsServer)
|
||||
|
||||
Reference in New Issue
Block a user