Unstable 0.1300.0.10

This commit is contained in:
Markus Isberg
2021-04-16 15:51:16 +03:00
parent f48dfb5862
commit 245b48c3a3
29 changed files with 289 additions and 84 deletions
@@ -267,7 +267,7 @@ namespace Barotrauma
public void UnequipEmptyItems(Item parentItem, bool avoidDroppingInSea = true) => UnequipEmptyItems(Character, parentItem, avoidDroppingInSea);
public void UnequipContainedItems(Item parentItem, Func<Item, bool> predicate, bool avoidDroppingInSea = true) => UnequipContainedItems(Character, parentItem, predicate, avoidDroppingInSea);
public void UnequipContainedItems(Item parentItem, Func<Item, bool> predicate = null, bool avoidDroppingInSea = true) => UnequipContainedItems(Character, parentItem, predicate, avoidDroppingInSea);
public static void UnequipEmptyItems(Character character, Item parentItem, bool avoidDroppingInSea = true) => UnequipContainedItems(character, parentItem, it => it.Condition <= 0, avoidDroppingInSea);
@@ -275,14 +275,14 @@ namespace Barotrauma
{
var inventory = parentItem.OwnInventory;
if (inventory == null) { return; }
if (inventory.AllItems.Any(predicate))
if (predicate == null || inventory.AllItems.Any(predicate))
{
foreach (Item containedItem in inventory.AllItemsMod)
{
if (containedItem == null) { continue; }
if (predicate(containedItem))
if (predicate == null || predicate(containedItem))
{
if (character.Submarine == null && avoidDroppingInSea)
if (character.Submarine != Submarine.MainSub && avoidDroppingInSea)
{
// If we are outside of main sub, try to put the item in the inventory instead dropping it in the sea.
if (character.Inventory.TryPutItem(containedItem, character, CharacterInventory.anySlot))
@@ -186,11 +186,14 @@ namespace Barotrauma
{
findSafety.Priority = 0;
}
distanceTimer -= deltaTime;
if (distanceTimer < 0)
if (!character.IsOnPlayerTeam && !objectiveManager.IsCurrentObjective<AIObjectiveFightIntruders>())
{
distanceTimer = distanceCheckInterval;
sqrDistance = Vector2.DistanceSquared(character.WorldPosition, Enemy.WorldPosition);
distanceTimer -= deltaTime;
if (distanceTimer < 0)
{
distanceTimer = distanceCheckInterval;
sqrDistance = Vector2.DistanceSquared(character.WorldPosition, Enemy.WorldPosition);
}
}
}
@@ -34,6 +34,7 @@ namespace Barotrauma
public float ConditionLevel { get; set; } = 1;
public bool Equip { get; set; }
public bool RemoveEmpty { get; set; } = true;
public bool RemoveExisting { get; set; }
public bool MoveWholeStack { get; set; }
@@ -105,7 +106,11 @@ namespace Barotrauma
}
if (character.CanInteractWith(container.Item, checkLinked: false))
{
if (RemoveEmpty)
if (RemoveExisting)
{
HumanAIController.UnequipContainedItems(container.Item);
}
else if (RemoveEmpty)
{
HumanAIController.UnequipEmptyItems(container.Item);
}
@@ -128,7 +133,7 @@ namespace Barotrauma
}
else
{
if (ItemToContain.ParentInventory == character.Inventory)
if (ItemToContain.ParentInventory == character.Inventory && character.Submarine == Submarine.MainSub)
{
ItemToContain.Drop(character);
}
@@ -60,11 +60,12 @@ namespace Barotrauma
{
HumanAIController.UnequipContainedItems(targetItem, it => !it.HasTag("oxygensource"));
HumanAIController.UnequipEmptyItems(targetItem);
float min = character.Submarine == null ? 0.01f : MIN_OXYGEN;
// Seek oxygen that has at least 10% condition left, if we are inside a friendly sub.
// The margin helps us to survive, because we might need some oxygen before we can find more oxygen.
// When we are venturing outside of our sub, let's just suppose that we have enough oxygen with us and optimize it so that we don't keep switching off half used tanks.
float min = character.Submarine != Submarine.MainSub ? 0.01f : MIN_OXYGEN;
if (targetItem.OwnInventory != null && targetItem.OwnInventory.AllItems.None(it => it != null && it.HasTag(OXYGEN_SOURCE) && it.Condition > min))
{
// No valid oxygen source loaded.
// Seek oxygen that has at least 10% condition left.
TryAddSubObjective(ref getOxygen, () =>
{
if (character.IsOnPlayerTeam)
@@ -82,20 +83,22 @@ namespace Barotrauma
{
AllowToFindDivingGear = false,
AllowDangerousPressure = true,
ConditionLevel = MIN_OXYGEN
ConditionLevel = MIN_OXYGEN,
RemoveExisting = true
};
},
onAbandon: () =>
{
getOxygen = null;
int remainingTanks = ReportOxygenTankCount();
// Try to seek any oxygen sources.
// Try to seek any oxygen sources, even if they have minimal amount of oxygen.
TryAddSubObjective(ref getOxygen, () =>
{
return new AIObjectiveContainItem(character, OXYGEN_SOURCE, targetItem.GetComponent<ItemContainer>(), objectiveManager, spawnItemIfNotFound: character.TeamID == CharacterTeamType.FriendlyNPC)
{
AllowToFindDivingGear = false,
AllowDangerousPressure = true
AllowDangerousPressure = true,
RemoveExisting = true
};
},
onAbandon: () =>
@@ -50,7 +50,10 @@ namespace Barotrauma
}
else
{
if (HumanAIController.NeedsDivingGear(character.CurrentHull, out _) && !HumanAIController.HasDivingGear(character, conditionPercentage: AIObjectiveFindDivingGear.MIN_OXYGEN))
if (HumanAIController.NeedsDivingGear(character.CurrentHull, out bool needsSuit) &&
(needsSuit ?
!HumanAIController.HasDivingSuit(character, conditionPercentage: AIObjectiveFindDivingGear.MIN_OXYGEN) :
!HumanAIController.HasDivingMask(character, conditionPercentage: AIObjectiveFindDivingGear.MIN_OXYGEN)))
{
Priority = 100;
}
@@ -279,9 +279,13 @@ namespace Barotrauma
if (character.TeamID == CharacterTeamType.FriendlyNPC != item.SpawnedInOutpost) { continue; }
}
if (!CheckItem(item)) { continue; }
if (ignoredContainerIdentifiers != null && item.Container != null)
if (item.Container != null)
{
if (ignoredContainerIdentifiers.Contains(item.ContainerIdentifier)) { continue; }
if (item.Container.HasTag("donttakeitems")) { continue; }
if (ignoredContainerIdentifiers != null)
{
if (ignoredContainerIdentifiers.Contains(item.ContainerIdentifier)) { continue; }
}
}
// Don't allow going into another sub, unless it's connected and of the same team and type.
if (!character.Submarine.IsEntityFoundOnThisSub(item, includingConnectedSubs: true)) { continue; }
@@ -423,7 +427,7 @@ namespace Barotrauma
// TODO: Use the item name as the variable here.
if (character.IsOnPlayerTeam && objectiveManager.CurrentOrder == objectiveManager.CurrentObjective)
{
string msg = TextManager.Get("dialogcannotreachtarget", true);
string msg = TextManager.Get("dialogcannotfinditem", true);
if (msg != null)
{
character.Speak(msg, identifier: "dialogcannotfinditem", minDurationBetweenSimilar: 20.0f);
@@ -124,7 +124,7 @@ namespace Barotrauma
public override bool CanBePut(Item item, int i)
{
return
base.CanBePut(item, i) && item.AllowedSlots.Contains(SlotTypes[i]) &&
base.CanBePut(item, i) && item.AllowedSlots.Any(s => s.HasFlag(SlotTypes[i])) &&
(SlotTypes[i] == InvSlotType.Any || slots[i].ItemCount < 1);
}
@@ -206,7 +206,7 @@ namespace Barotrauma
if (allowedSlots != null && !allowedSlots.Contains(InvSlotType.Any))
{
int slot = FindLimbSlot(allowedSlots.First());
if (slot > -1 && slots[slot].Items.Any(it => it != item) && slots[slot].First().Prefab.AllowDroppingOnSwap)
if (slot > -1 && slots[slot].Items.Any(it => it != item) && slots[slot].First().AllowDroppingOnSwapWith(item))
{
foreach (Item existingItem in slots[slot].Items.ToList())
{
@@ -12,11 +12,11 @@ namespace Barotrauma.Items.Components
{
partial class Steering : Powered, IServerSerializable, IClientSerializable
{
public const float AutopilotMinDistToPathNode = 30.0f;
private const float AutopilotRayCastInterval = 0.5f;
private const float RecalculatePathInterval = 5.0f;
private const float AutopilotMinDistToPathNode = 30.0f;
private const float AutoPilotSteeringLerp = 0.1f;
private const float AutoPilotMaxSpeed = 0.5f;
@@ -1,5 +1,6 @@
using Barotrauma.Networking;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
namespace Barotrauma.Items.Components
@@ -31,6 +32,19 @@ namespace Barotrauma.Items.Components
}
}
/// <summary>
/// Can be used to display messages on the terminal via status effects
/// </summary>
public string ShowMessage
{
get { return messageHistory.Count == 0 ? string.Empty : messageHistory.Last(); }
set
{
if (string.IsNullOrEmpty(value)) { return; }
ShowOnDisplay(value);
}
}
private string OutputValue { get; set; }
public Terminal(Item item, XElement element)
@@ -659,12 +659,12 @@ namespace Barotrauma
else
{
swapSuccessful =
(existingItems.All(existingItem => otherInventory.TryPutItem(existingItem, otherIndex, false, false, user, createNetworkEvent)) ||
existingItems.Count == 1 && otherInventory.TryPutItem(existingItems.First(),user, CharacterInventory.anySlot, createNetworkEvent))
(existingItems.All(existingItem => otherInventory.TryPutItem(existingItem, otherIndex, false, false, user, createNetworkEvent)) ||
existingItems.Count == 1 && otherInventory.TryPutItem(existingItems.First(), user, CharacterInventory.anySlot, createNetworkEvent))
&&
stackedItems.Distinct().All(stackedItem => TryPutItem(stackedItem, index, false, false, user, createNetworkEvent));
if (!swapSuccessful && existingItems.Count == 1 && existingItems[0].Prefab.AllowDroppingOnSwap)
if (!swapSuccessful && existingItems.Count == 1 && existingItems[0].AllowDroppingOnSwapWith(item))
{
existingItems[0].Drop(user, createNetworkEvent);
swapSuccessful = stackedItems.Distinct().Any(stackedItem => TryPutItem(stackedItem, index, false, false, user, createNetworkEvent));
@@ -1102,6 +1102,27 @@ namespace Barotrauma
if (findNewHull) { FindHull(); }
}
/// <summary>
/// Is dropping the item allowed when trying to swap it with the other item
/// </summary>
public bool AllowDroppingOnSwapWith(Item otherItem)
{
if (!Prefab.AllowDroppingOnSwap || otherItem == null) { return false; }
if (Prefab.AllowDroppingOnSwapWith.Any())
{
foreach (string tagOrIdentifier in Prefab.AllowDroppingOnSwapWith)
{
if (otherItem.prefab.Identifier.Equals(tagOrIdentifier, StringComparison.OrdinalIgnoreCase)) { return true; }
if (otherItem.HasTag(tagOrIdentifier)) { return true; }
}
return false;
}
else
{
return true;
}
}
public void SetActiveSprite()
{
SetActiveSpriteProjSpecific();
@@ -517,6 +517,12 @@ namespace Barotrauma
[Serialize(false, false)]
public bool AllowDroppingOnSwap { get; private set; }
private readonly HashSet<string> allowDroppingOnSwapWith = new HashSet<string>();
public IEnumerable<string> AllowDroppingOnSwapWith
{
get { return allowDroppingOnSwapWith; }
}
public Vector2 Size => size;
public bool CanBeBought => (DefaultPrice != null && DefaultPrice.CanBeBought) || (locationPrices != null && locationPrices.Any(p => p.Value.CanBeBought));
@@ -657,7 +663,7 @@ namespace Barotrauma
{
category = MapEntityCategory.Misc;
}
Category = category;
Category = category;
var parentType = element.Parent?.GetAttributeString("itemtype", "") ?? string.Empty;
@@ -695,7 +701,7 @@ namespace Barotrauma
identifier = GenerateLegacyIdentifier(originalName);
}
}
if (string.Equals(parentType, "wrecked", StringComparison.OrdinalIgnoreCase))
{
if (!string.IsNullOrEmpty(name))
@@ -703,7 +709,7 @@ namespace Barotrauma
name = TextManager.GetWithVariable("wreckeditemformat", "[name]", name);
}
}
if (string.IsNullOrEmpty(name))
{
DebugConsole.ThrowError($"Unnamed item ({identifier}) in {filePath}!");
@@ -715,11 +721,11 @@ namespace Barotrauma
(element.GetAttributeStringArray("aliases", null, convertToLowerInvariant: true) ??
element.GetAttributeStringArray("Aliases", new string[0], convertToLowerInvariant: true));
Aliases.Add(originalName.ToLowerInvariant());
Triggers = new List<Rectangle>();
DeconstructItems = new List<DeconstructItem>();
FabricationRecipes = new List<FabricationRecipe>();
DeconstructTime = 1.0f;
Triggers = new List<Rectangle>();
DeconstructItems = new List<DeconstructItem>();
FabricationRecipes = new List<FabricationRecipe>();
DeconstructTime = 1.0f;
if (element.Attribute("allowasextracargo") != null)
{
@@ -755,6 +761,16 @@ namespace Barotrauma
}
}
var allowDroppingOnSwapWith = element.GetAttributeStringArray("allowdroppingonswapwith", new string[0]);
if (allowDroppingOnSwapWith.Any())
{
AllowDroppingOnSwap = true;
foreach (string tag in allowDroppingOnSwapWith)
{
this.allowDroppingOnSwapWith.Add(tag);
}
}
foreach (XElement subElement in element.Elements())
{
switch (subElement.Name.ToString().ToLowerInvariant())
@@ -203,9 +203,9 @@ namespace Barotrauma
public void AutoOrient()
{
Vector2 searchPosLeft = new Vector2(rect.X, rect.Y - rect.Height / 2);
Hull hullLeft = Hull.FindHullOld(searchPosLeft, null, false);
Hull hullLeft = Hull.FindHullUnoptimized(searchPosLeft, null, false);
Vector2 searchPosRight = new Vector2(rect.Right, rect.Y - rect.Height / 2);
Hull hullRight = Hull.FindHullOld(searchPosRight, null, false);
Hull hullRight = Hull.FindHullUnoptimized(searchPosRight, null, false);
if (hullLeft != null && hullRight != null && hullLeft != hullRight)
{
@@ -214,9 +214,9 @@ namespace Barotrauma
}
Vector2 searchPosTop = new Vector2(rect.Center.X, rect.Y);
Hull hullTop = Hull.FindHullOld(searchPosTop, null, false);
Hull hullTop = Hull.FindHullUnoptimized(searchPosTop, null, false);
Vector2 searchPosBottom = new Vector2(rect.Center.X, rect.Y - rect.Height);
Hull hullBottom = Hull.FindHullOld(searchPosBottom, null, false);
Hull hullBottom = Hull.FindHullUnoptimized(searchPosBottom, null, false);
if (hullTop != null && hullBottom != null && hullTop != hullBottom)
{
@@ -261,8 +261,8 @@ namespace Barotrauma
for (int i = 0; i < 2; i++)
{
hulls[i] = Hull.FindHullOld(searchPos[i], null, false);
if (hulls[i] == null) hulls[i] = Hull.FindHullOld(searchPos[i], null, false, true);
hulls[i] = Hull.FindHullUnoptimized(searchPos[i], null, false);
if (hulls[i] == null) hulls[i] = Hull.FindHullUnoptimized(searchPos[i], null, false, true);
}
if (hulls[0] == null && hulls[1] == null) { return; }
@@ -990,7 +990,13 @@ namespace Barotrauma
return float.MaxValue;
}
//returns the water block which contains the point (or null if it isn't inside any)
/// <summary>
/// Returns the hull which contains the point (or null if it isn't inside any)
/// </summary>
/// <param name="position">The position to check</param>
/// <param name="guess">This hull is checked first: if the current hull is known, this can be used as an optimization</param>
/// <param name="useWorldCoordinates">Should world coordinates or the sub's local coordinates be used?</param>
/// <param name="inclusive">Does being exactly at the edge of the hull count as being inside?</param>
public static Hull FindHull(Vector2 position, Hull guess = null, bool useWorldCoordinates = true, bool inclusive = true)
{
if (EntityGrids == null) return null;
@@ -1038,20 +1044,19 @@ namespace Barotrauma
return null;
}
//returns the water block which contains the point (or null if it isn't inside any)
public static Hull FindHullOld(Vector2 position, Hull guess = null, bool useWorldCoordinates = true, bool inclusive = true)
/// <summary>
/// Returns the hull which contains the point (or null if it isn't inside any). The difference to FindHull is that this method goes through all hulls without trying
/// to first find the sub the point is inside and checking the hulls in that sub.
/// = This is slower, use with caution in situations where the sub's extents or hulls may have changed after it was loaded.
/// </summary>
public static Hull FindHullUnoptimized(Vector2 position, Hull guess = null, bool useWorldCoordinates = true, bool inclusive = true)
{
return FindHullOld(position, hullList, guess, useWorldCoordinates, inclusive);
}
public static Hull FindHullOld(Vector2 position, List<Hull> hulls, Hull guess = null, bool useWorldCoordinates = true, bool inclusive = true)
{
if (guess != null && hulls.Contains(guess))
if (guess != null && hullList.Contains(guess))
{
if (Submarine.RectContains(useWorldCoordinates ? guess.WorldRect : guess.rect, position, inclusive)) return guess;
}
foreach (Hull hull in hulls)
foreach (Hull hull in hullList)
{
if (Submarine.RectContains(useWorldCoordinates ? hull.WorldRect : hull.rect, position, inclusive)) return hull;
}
@@ -166,7 +166,7 @@ namespace Barotrauma
public class AbyssIsland
{
public readonly Rectangle Area;
public Rectangle Area;
public readonly List<VoronoiCell> Cells;
public AbyssIsland(Rectangle area, List<VoronoiCell> cells)
@@ -844,6 +844,11 @@ namespace Barotrauma
}
}
foreach (AbyssIsland island in AbyssIslands)
{
island.Area = new Rectangle(borders.Width - island.Area.Right, island.Area.Y, island.Area.Width, island.Area.Height);
}
foreach (Cave cave in Caves)
{
cave.Area = new Rectangle(borders.Width - cave.Area.Right, cave.Area.Y, cave.Area.Width, cave.Area.Height);
@@ -1328,7 +1333,6 @@ namespace Barotrauma
for (int i = 0; i < tunnel.Cells.Count; i++)
{
tunnel.Cells[i].CellType = CellType.Path;
var newWaypoint = new WayPoint(new Rectangle((int)tunnel.Cells[i].Site.Coord.X, (int)tunnel.Cells[i].Center.Y, 10, 10), null)
{
Tunnel = tunnel
@@ -1385,8 +1389,23 @@ namespace Barotrauma
ConvertUnits.ToSimUnits(wayPoint.WorldPosition),
ConvertUnits.ToSimUnits(closestWaypoint.WorldPosition), collisionCategory: Physics.CollisionLevel | Physics.CollisionWall) == null)
{
wayPoint.linkedTo.Add(closestWaypoint);
closestWaypoint.linkedTo.Add(wayPoint);
Vector2 diff = closestWaypoint.WorldPosition - wayPoint.WorldPosition;
float dist = diff.Length();
float step = ConvertUnits.ToDisplayUnits(Steering.AutopilotMinDistToPathNode) * 0.8f;
WayPoint prevWaypoint = wayPoint;
for (float x = step; x < dist - step; x += step)
{
var newWaypoint = new WayPoint(wayPoint.WorldPosition + (diff / dist * x), SpawnType.Path, submarine: null)
{
Tunnel = tunnel
};
prevWaypoint.linkedTo.Add(newWaypoint);
newWaypoint.linkedTo.Add(prevWaypoint);
prevWaypoint = newWaypoint;
}
prevWaypoint.linkedTo.Add(closestWaypoint);
closestWaypoint.linkedTo.Add(prevWaypoint);
}
}
}
@@ -1104,8 +1104,35 @@ namespace Barotrauma
DebugConsole.ThrowError($"Failed to connect waypoints between outpost modules. No waypoint in the {GetOpposingGapPosition(module.ThisGapPosition).ToString().ToLower()} gap of the module \"{module.PreviousModule.Info.Name}\".");
continue;
}
startWaypoint.linkedTo.Add(endWaypoint);
endWaypoint.linkedTo.Add(startWaypoint);
if (startWaypoint.WorldPosition.X > endWaypoint.WorldPosition.X)
{
var temp = startWaypoint;
startWaypoint = endWaypoint;
endWaypoint = temp;
}
if (hallwayLength > 100 && isHorizontal)
{
WayPoint prevWayPoint = startWaypoint;
for (float x = leftHull.Rect.Right + 50; x < rightHull.Rect.X - 50; x += 100.0f)
{
var newWayPoint = new WayPoint(new Vector2(x, hullBounds.Y + 110.0f), SpawnType.Path, sub);
prevWayPoint.linkedTo.Add(newWayPoint);
newWayPoint.linkedTo.Add(prevWayPoint);
prevWayPoint = newWayPoint;
}
if (prevWayPoint != null)
{
prevWayPoint.linkedTo.Add(endWaypoint);
endWaypoint.linkedTo.Add(prevWayPoint);
}
}
else
{
startWaypoint.linkedTo.Add(endWaypoint);
endWaypoint.linkedTo.Add(startWaypoint);
}
WayPoint closestWaypoint = null;
float closestDistSqr = 30.0f * 30.0f;
@@ -786,6 +786,13 @@ namespace Barotrauma
public void FindHull()
{
CurrentHull = Hull.FindHull(WorldPosition, CurrentHull);
#if CLIENT
//we may not be able to find the hull with the optimized method in the sub editor if new hulls have been added, use the unoptimized method
if (Screen.Selected == GameMain.SubEditorScreen)
{
CurrentHull ??= Hull.FindHullUnoptimized(WorldPosition);
}
#endif
}
public override void OnMapLoaded()