(63921aa0d) Implement GetVisibleHulls method.
This commit is contained in:
@@ -169,7 +169,15 @@ namespace Barotrauma
|
||||
bool highPressure = Character.CurrentHull == null || Character.CurrentHull.LethalPressure > 0 && Character.PressureProtection <= 0;
|
||||
bool shouldKeepTheGearOn = !ObjectiveManager.IsCurrentObjective<AIObjectiveIdle>();
|
||||
|
||||
bool removeDivingSuit = (oxygenLow && !highPressure) || (!shouldKeepTheGearOn && Character.CurrentHull.WaterPercentage < 1 && !Character.IsClimbing && steeringManager == insideSteering && !PathSteering.InStairs);
|
||||
// Don't allow to drop the diving suit in water or while climbing or if the current path has stairs
|
||||
bool removeDivingSuit =
|
||||
(oxygenLow && !highPressure) ||
|
||||
(!shouldKeepTheGearOn &&
|
||||
Character.CurrentHull.WaterPercentage < 1 &&
|
||||
!Character.IsClimbing &&
|
||||
steeringManager == insideSteering &&
|
||||
!PathSteering.InStairs);
|
||||
|
||||
if (removeDivingSuit)
|
||||
{
|
||||
var divingSuit = Character.Inventory.FindItemByIdentifier("divingsuit") ?? Character.Inventory.FindItemByTag("divingsuit");
|
||||
@@ -495,8 +503,10 @@ namespace Barotrauma
|
||||
|
||||
public static void DoForEachCrewMember(Character character, Action<HumanAIController> action)
|
||||
{
|
||||
if (character == null) { return; }
|
||||
foreach (var c in Character.CharacterList)
|
||||
{
|
||||
if (c == null || c.IsDead || c.Removed) { continue; }
|
||||
if (c.AIController is HumanAIController humanAi && humanAi.IsFriendly(character))
|
||||
{
|
||||
action(humanAi);
|
||||
|
||||
@@ -53,13 +53,9 @@ namespace Barotrauma
|
||||
(currentPath.NextNode != null && currentPath.NextNode.Ladders != null));
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the previous, current or the next node is in stairs.
|
||||
/// Returns true if any node in the path is in stairs
|
||||
/// </summary>
|
||||
public bool InStairs =>
|
||||
currentPath != null && (
|
||||
currentPath.PrevNode != null && currentPath.PrevNode.Stairs != null ||
|
||||
currentPath.CurrentNode != null && currentPath.CurrentNode.Stairs != null ||
|
||||
currentPath.NextNode != null && currentPath.NextNode.Stairs != null);
|
||||
public bool InStairs => currentPath != null && currentPath.Nodes.Any(n => n.Stairs != null);
|
||||
|
||||
public bool IsNextNodeLadder
|
||||
{
|
||||
@@ -304,7 +300,9 @@ namespace Barotrauma
|
||||
float horizontalDistance = Math.Abs(collider.SimPosition.X - currentPath.CurrentNode.SimPosition.X);
|
||||
bool isAboveFeet = currentPath.CurrentNode.SimPosition.Y > colliderBottom.Y;
|
||||
bool isNotTooHigh = currentPath.CurrentNode.SimPosition.Y < colliderBottom.Y + characterHeight;
|
||||
if (currentPath.CurrentNode != null && currentPath.CurrentNode.Stairs != null)
|
||||
float margin = MathHelper.Lerp(1, 10, MathHelper.Clamp(Math.Abs(velocity.X) / 10, 0, 1));
|
||||
float targetDistance = collider.radius * margin;
|
||||
if (horizontalDistance < targetDistance && isAboveFeet && isNotTooHigh)
|
||||
{
|
||||
float multiplierX = MathHelper.Lerp(1, 10, MathHelper.Clamp(Math.Abs(velocity.X) / 10, 0, 1));
|
||||
float multiplierY = MathHelper.Lerp(1, 10, MathHelper.Clamp(Math.Abs(velocity.Y) / 10, 0, 1));
|
||||
|
||||
@@ -1141,6 +1141,32 @@ namespace Barotrauma
|
||||
{
|
||||
#if DEBUG
|
||||
DebugConsole.ThrowError("AIObjectiveFixLeak failed - the item \"" + weldingTool + "\" has no RepairTool component but is tagged as a welding tool");
|
||||
#endif
|
||||
abandon = true;
|
||||
return;
|
||||
}
|
||||
Vector2 gapDiff = Leak.WorldPosition - character.WorldPosition;
|
||||
// TODO: use the collider size/reach?
|
||||
if (!character.AnimController.InWater && Math.Abs(gapDiff.X) < 100 && gapDiff.Y < 0.0f && gapDiff.Y > -150)
|
||||
{
|
||||
HumanAIController.AnimController.Crouching = true;
|
||||
}
|
||||
float reach = ConvertUnits.ToSimUnits(repairTool.Range);
|
||||
bool canOperate = ConvertUnits.ToSimUnits(gapDiff.Length()) < reach * 1.5f;
|
||||
if (canOperate)
|
||||
{
|
||||
TryAddSubObjective(ref operateObjective, () => new AIObjectiveOperateItem(repairTool, character, objectiveManager, option: "", requireEquip: true, operateTarget: Leak));
|
||||
}
|
||||
else
|
||||
{
|
||||
TryAddSubObjective(ref gotoObjective, () => new AIObjectiveGoTo(ConvertUnits.ToSimUnits(GetStandPosition()), character, objectiveManager) { CloseEnough = reach * 0.75f });
|
||||
}
|
||||
if (subObjectives.Any()) { return; }
|
||||
var repairTool = weldingTool.GetComponent<RepairTool>();
|
||||
if (repairTool == null)
|
||||
{
|
||||
#if DEBUG
|
||||
DebugConsole.ThrowError("AIObjectiveFixLeak failed - the item \"" + weldingTool + "\" has no RepairTool component but is tagged as a welding tool");
|
||||
#endif
|
||||
abandon = true;
|
||||
return;
|
||||
|
||||
@@ -73,6 +73,21 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public override void Update(float deltaTime)
|
||||
{
|
||||
if (objectiveManager.CurrentObjective == this)
|
||||
{
|
||||
if (randomTimer > 0)
|
||||
{
|
||||
randomTimer -= deltaTime;
|
||||
}
|
||||
else
|
||||
{
|
||||
SetRandom();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override bool IsCompleted() => false;
|
||||
public override bool CanBeCompleted => true;
|
||||
|
||||
|
||||
@@ -773,6 +773,10 @@ namespace Barotrauma
|
||||
{
|
||||
isCompleted = true;
|
||||
}
|
||||
if (component.AIOperate(deltaTime, character, this))
|
||||
{
|
||||
isCompleted = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
+3
-4
@@ -97,12 +97,11 @@ namespace Barotrauma
|
||||
|
||||
public static string GetDefaultFileName(string speciesName, AnimationType animType) => $"{speciesName.CapitaliseFirstInvariant()}{animType.ToString()}";
|
||||
public static string GetDefaultFolder(string speciesName) => $"Content/Characters/{speciesName.CapitaliseFirstInvariant()}/Animations/";
|
||||
public static string GetDefaultFile(string speciesName, AnimationType animType, ContentPackage contentPackage = null) =>
|
||||
$"{GetFolder(speciesName, contentPackage)}{GetDefaultFileName(speciesName, animType)}.xml";
|
||||
public static string GetDefaultFile(string speciesName, AnimationType animType) => $"{GetFolder(speciesName)}{GetDefaultFileName(speciesName, animType)}.xml";
|
||||
|
||||
public static string GetFolder(string speciesName, ContentPackage contentPackage = null)
|
||||
public static string GetFolder(string speciesName)
|
||||
{
|
||||
var folder = XMLExtensions.TryLoadXml(Character.GetConfigFile(speciesName, contentPackage))?.Root?.Element("animations")?.GetAttributeString("folder", string.Empty);
|
||||
var folder = XMLExtensions.TryLoadXml(Character.GetConfigFile(speciesName))?.Root?.Element("animations")?.GetAttributeString("folder", string.Empty);
|
||||
if (string.IsNullOrEmpty(folder) || folder.ToLowerInvariant() == "default")
|
||||
{
|
||||
folder = GetDefaultFolder(speciesName);
|
||||
|
||||
+3
-3
@@ -64,7 +64,7 @@ namespace Barotrauma
|
||||
|
||||
public static string GetDefaultFileName(string speciesName) => $"{speciesName.CapitaliseFirstInvariant()}DefaultRagdoll";
|
||||
public static string GetDefaultFolder(string speciesName) => $"Content/Characters/{speciesName.CapitaliseFirstInvariant()}/Ragdolls/";
|
||||
public static string GetDefaultFile(string speciesName, ContentPackage contentPackage = null) => $"{GetFolder(speciesName, contentPackage)}{GetDefaultFileName(speciesName)}.xml";
|
||||
public static string GetDefaultFile(string speciesName) => $"{GetFolder(speciesName)}{GetDefaultFileName(speciesName)}.xml";
|
||||
|
||||
private static readonly object[] dummyParams = new object[]
|
||||
{
|
||||
@@ -79,9 +79,9 @@ namespace Barotrauma
|
||||
new XAttribute("sourcerect", $"0, 0, 1, 1")))
|
||||
};
|
||||
|
||||
public static string GetFolder(string speciesName, ContentPackage contentPackage = null)
|
||||
public static string GetFolder(string speciesName)
|
||||
{
|
||||
var folder = XMLExtensions.TryLoadXml(Character.GetConfigFile(speciesName, contentPackage))?.Root?.Element("ragdolls")?.GetAttributeString("folder", string.Empty);
|
||||
var folder = XMLExtensions.TryLoadXml(Character.GetConfigFile(speciesName))?.Root?.Element("ragdolls")?.GetAttributeString("folder", string.Empty);
|
||||
if (string.IsNullOrEmpty(folder) || folder.ToLowerInvariant() == "default")
|
||||
{
|
||||
//DebugConsole.NewMessage("[RagollParams] Using the default folder.");
|
||||
|
||||
@@ -853,26 +853,15 @@ namespace Barotrauma
|
||||
{
|
||||
if (characterConfigFiles == null)
|
||||
{
|
||||
characterConfigFiles = GameMain.Instance.GetFilesOfType(ContentType.Character);
|
||||
characterConfigFiles = GameMain.Instance.GetFilesOfType(ContentType.Character, searchAllContentPackages: true);
|
||||
}
|
||||
return characterConfigFiles;
|
||||
}
|
||||
}
|
||||
|
||||
public static string GetConfigFile(string speciesName, ContentPackage contentPackage = null)
|
||||
public static string GetConfigFile(string speciesName)
|
||||
{
|
||||
string configFile = null;
|
||||
if (contentPackage == null)
|
||||
{
|
||||
configFile = GameMain.Instance.GetFilesOfType(ContentType.Character, searchAllContentPackages: true)
|
||||
.FirstOrDefault(c => Path.GetFileName(c).ToLowerInvariant() == $"{speciesName.ToLowerInvariant()}.xml");
|
||||
}
|
||||
else
|
||||
{
|
||||
configFile = contentPackage.GetFilesOfType(ContentType.Character)?
|
||||
.FirstOrDefault(c => Path.GetFileName(c).ToLowerInvariant() == $"{speciesName.ToLowerInvariant()}.xml");
|
||||
}
|
||||
|
||||
string configFile = CharacterConfigFiles.FirstOrDefault(c => Path.GetFileName(c).ToLowerInvariant() == $"{speciesName.ToLowerInvariant()}.xml");
|
||||
if (configFile == null)
|
||||
{
|
||||
DebugConsole.ThrowError($"Couldn't find a config file for {speciesName} from the selected content packages!");
|
||||
@@ -1147,33 +1136,7 @@ namespace Barotrauma
|
||||
|
||||
if (!(this is AICharacter) || Controlled == this || IsRemotePlayer)
|
||||
{
|
||||
SmoothedCursorPosition = cursorPosition;
|
||||
}
|
||||
else
|
||||
{
|
||||
//apply some smoothing to the cursor positions of remote players when playing as a client
|
||||
//to make aiming look a little less choppy
|
||||
Vector2 smoothedCursorDiff = cursorPosition - SmoothedCursorPosition;
|
||||
smoothedCursorDiff = NetConfig.InterpolateCursorPositionError(smoothedCursorDiff);
|
||||
SmoothedCursorPosition = cursorPosition - smoothedCursorDiff;
|
||||
}
|
||||
|
||||
if (!(this is AICharacter) || Controlled == this || IsRemotePlayer)
|
||||
{
|
||||
SmoothedCursorPosition = cursorPosition;
|
||||
}
|
||||
else
|
||||
{
|
||||
//apply some smoothing to the cursor positions of remote players when playing as a client
|
||||
//to make aiming look a little less choppy
|
||||
Vector2 smoothedCursorDiff = cursorPosition - SmoothedCursorPosition;
|
||||
smoothedCursorDiff = NetConfig.InterpolateCursorPositionError(smoothedCursorDiff);
|
||||
SmoothedCursorPosition = cursorPosition - smoothedCursorDiff;
|
||||
}
|
||||
|
||||
if (!(this is AICharacter) || Controlled == this || IsRemotePlayer)
|
||||
{
|
||||
if (speedMultipliers.Count == 0) return 1f;
|
||||
Vector2 targetMovement = GetTargetMovement();
|
||||
|
||||
AnimController.TargetMovement = targetMovement;
|
||||
AnimController.IgnorePlatforms = AnimController.TargetMovement.Y < -0.1f;
|
||||
@@ -2681,5 +2644,57 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
public AttackContext GetAttackContext() => AnimController.CurrentAnimationParams.IsGroundedAnimation ? AttackContext.Ground : AttackContext.Water;
|
||||
|
||||
private List<Hull> visibleHulls = new List<Hull>();
|
||||
private HashSet<Hull> tempList = new HashSet<Hull>();
|
||||
/// <summary>
|
||||
/// Returns hulls that are visible to the player, including the current hull.
|
||||
/// Can be heavy if used every frame.
|
||||
/// </summary>
|
||||
public List<Hull> GetVisibleHulls()
|
||||
{
|
||||
visibleHulls.Clear();
|
||||
tempList.Clear();
|
||||
if (CurrentHull != null)
|
||||
{
|
||||
visibleHulls.Add(CurrentHull);
|
||||
var adjacentHulls = CurrentHull.GetConnectedHulls(true, 1);
|
||||
float maxDistance = 1000f;
|
||||
foreach (var hull in adjacentHulls)
|
||||
{
|
||||
if (hull.ConnectedGaps.Any(g => g.Open > 0.9f && g.linkedTo.Contains(CurrentHull) &&
|
||||
Vector2.DistanceSquared(g.WorldPosition, WorldPosition) < Math.Pow(maxDistance / 2, 2)))
|
||||
{
|
||||
if (Vector2.DistanceSquared(hull.WorldPosition, WorldPosition) < Math.Pow(maxDistance, 2))
|
||||
{
|
||||
visibleHulls.Add(hull);
|
||||
}
|
||||
}
|
||||
}
|
||||
visibleHulls.AddRange(CurrentHull.GetLinkedEntities<Hull>(tempList, filter: h =>
|
||||
{
|
||||
// Ignore adjacent hulls because they were already handled above
|
||||
if (adjacentHulls.Contains(h))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (h.ConnectedGaps.Any(g =>
|
||||
g.Open > 0.9f &&
|
||||
Vector2.DistanceSquared(g.WorldPosition, WorldPosition) < Math.Pow(maxDistance / 2, 2) &&
|
||||
CanSeeTarget(g)))
|
||||
{
|
||||
return Vector2.DistanceSquared(h.WorldPosition, WorldPosition) < Math.Pow(maxDistance, 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
return visibleHulls;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -362,11 +362,10 @@ namespace Barotrauma
|
||||
case ContentType.Character:
|
||||
XDocument doc = XMLExtensions.TryLoadXml(file.Path);
|
||||
string speciesName = doc.Root.GetAttributeString("name", "");
|
||||
//TODO: check non-default paths if defined
|
||||
filePaths.Add(RagdollParams.GetDefaultFile(speciesName, this));
|
||||
filePaths.Add(RagdollParams.GetDefaultFile(speciesName));
|
||||
foreach (AnimationType animationType in Enum.GetValues(typeof(AnimationType)))
|
||||
{
|
||||
filePaths.Add(AnimationParams.GetDefaultFile(speciesName, animationType, this));
|
||||
filePaths.Add(AnimationParams.GetDefaultFile(speciesName, animationType));
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -492,11 +491,6 @@ namespace Barotrauma
|
||||
public ContentFile(string path, ContentType type, Workshop.Item workShopItem = null)
|
||||
{
|
||||
Path = path;
|
||||
|
||||
#if OSX
|
||||
Path = Path.Replace("\\", "/");
|
||||
#endif
|
||||
|
||||
Type = type;
|
||||
WorkShopItem = workShopItem;
|
||||
}
|
||||
|
||||
@@ -582,6 +582,25 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
if (targetItem.Prefab.DeconstructItems.Any())
|
||||
{
|
||||
inputContainer.Inventory.RemoveItem(targetItem);
|
||||
Entity.Spawner.AddToRemoveQueue(targetItem);
|
||||
MoveInputQueue();
|
||||
PutItemsToLinkedContainer();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (outputContainer.Inventory.Items.All(i => i != null))
|
||||
{
|
||||
targetItem.Drop(dropper: null);
|
||||
}
|
||||
else
|
||||
{
|
||||
outputContainer.Inventory.TryPutItem(targetItem, user: null, createNetworkEvent: true);
|
||||
}
|
||||
}
|
||||
|
||||
if (targetItem.Prefab.DeconstructItems.Any())
|
||||
{
|
||||
inputContainer.Inventory.RemoveItem(targetItem);
|
||||
|
||||
@@ -144,17 +144,6 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
public Vector2 SteeringInput
|
||||
{
|
||||
get { return steeringInput; }
|
||||
set
|
||||
{
|
||||
if (!MathUtils.IsValid(value)) return;
|
||||
steeringInput.X = MathHelper.Clamp(value.X, -100.0f, 100.0f);
|
||||
steeringInput.Y = MathHelper.Clamp(value.Y, -100.0f, 100.0f);
|
||||
}
|
||||
}
|
||||
|
||||
public SteeringPath SteeringPath
|
||||
{
|
||||
if (!CanBeSelected) return false;
|
||||
@@ -175,6 +164,12 @@ namespace Barotrauma.Items.Components
|
||||
set { posToMaintain = value; }
|
||||
}
|
||||
|
||||
public Vector2? PosToMaintain
|
||||
{
|
||||
get { return posToMaintain; }
|
||||
set { posToMaintain = value; }
|
||||
}
|
||||
|
||||
struct ObstacleDebugInfo
|
||||
{
|
||||
public Vector2 Point1;
|
||||
|
||||
@@ -1139,70 +1139,6 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateTransform()
|
||||
{
|
||||
Submarine prevSub = Submarine;
|
||||
|
||||
FindHull();
|
||||
|
||||
if (Submarine == null && prevSub != null)
|
||||
{
|
||||
body.SetTransform(body.SimPosition + prevSub.SimPosition, body.Rotation);
|
||||
}
|
||||
else if (Submarine != null && prevSub == null)
|
||||
{
|
||||
body.SetTransform(body.SimPosition - Submarine.SimPosition, body.Rotation);
|
||||
}
|
||||
else if (Submarine != null && prevSub != null && Submarine != prevSub)
|
||||
{
|
||||
body.SetTransform(body.SimPosition + prevSub.SimPosition - Submarine.SimPosition, body.Rotation);
|
||||
}
|
||||
|
||||
Vector2 displayPos = ConvertUnits.ToDisplayUnits(body.SimPosition);
|
||||
rect.X = (int)(displayPos.X - rect.Width / 2.0f);
|
||||
rect.Y = (int)(displayPos.Y + rect.Height / 2.0f);
|
||||
|
||||
if (Math.Abs(body.LinearVelocity.X) > NetConfig.MaxPhysicsBodyVelocity ||
|
||||
Math.Abs(body.LinearVelocity.Y) > NetConfig.MaxPhysicsBodyVelocity)
|
||||
{
|
||||
body.LinearVelocity = new Vector2(
|
||||
MathHelper.Clamp(body.LinearVelocity.X, -NetConfig.MaxPhysicsBodyVelocity, NetConfig.MaxPhysicsBodyVelocity),
|
||||
MathHelper.Clamp(body.LinearVelocity.Y, -NetConfig.MaxPhysicsBodyVelocity, NetConfig.MaxPhysicsBodyVelocity));
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateTransform()
|
||||
{
|
||||
Submarine prevSub = Submarine;
|
||||
|
||||
FindHull();
|
||||
|
||||
if (Submarine == null && prevSub != null)
|
||||
{
|
||||
body.SetTransform(body.SimPosition + prevSub.SimPosition, body.Rotation);
|
||||
}
|
||||
else if (Submarine != null && prevSub == null)
|
||||
{
|
||||
body.SetTransform(body.SimPosition - Submarine.SimPosition, body.Rotation);
|
||||
}
|
||||
else if (Submarine != null && prevSub != null && Submarine != prevSub)
|
||||
{
|
||||
body.SetTransform(body.SimPosition + prevSub.SimPosition - Submarine.SimPosition, body.Rotation);
|
||||
}
|
||||
|
||||
Vector2 displayPos = ConvertUnits.ToDisplayUnits(body.SimPosition);
|
||||
rect.X = (int)(displayPos.X - rect.Width / 2.0f);
|
||||
rect.Y = (int)(displayPos.Y + rect.Height / 2.0f);
|
||||
|
||||
if (Math.Abs(body.LinearVelocity.X) > NetConfig.MaxPhysicsBodyVelocity ||
|
||||
Math.Abs(body.LinearVelocity.Y) > NetConfig.MaxPhysicsBodyVelocity)
|
||||
{
|
||||
body.LinearVelocity = new Vector2(
|
||||
MathHelper.Clamp(body.LinearVelocity.X, -NetConfig.MaxPhysicsBodyVelocity, NetConfig.MaxPhysicsBodyVelocity),
|
||||
MathHelper.Clamp(body.LinearVelocity.Y, -NetConfig.MaxPhysicsBodyVelocity, NetConfig.MaxPhysicsBodyVelocity));
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateTransform()
|
||||
{
|
||||
Submarine prevSub = Submarine;
|
||||
@@ -1591,7 +1527,11 @@ namespace Barotrauma
|
||||
|
||||
if (!picked) return false;
|
||||
|
||||
if (picker != null)
|
||||
if (picker.SelectedConstruction == this)
|
||||
{
|
||||
if (picker.IsKeyHit(InputType.Select) || forceSelectKey) picker.SelectedConstruction = null;
|
||||
}
|
||||
else if (selected)
|
||||
{
|
||||
if (picker.SelectedConstruction == this)
|
||||
{
|
||||
@@ -2006,7 +1946,6 @@ namespace Barotrauma
|
||||
return Load(element, submarine, createNetworkEvent: false);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Instantiate a new item and load its data from the XML element.
|
||||
/// </summary>
|
||||
@@ -2019,10 +1958,30 @@ namespace Barotrauma
|
||||
string name = element.Attribute("name").Value;
|
||||
string identifier = element.GetAttributeString("identifier", "");
|
||||
|
||||
ItemPrefab prefab = ItemPrefab.Find(name, identifier);
|
||||
ItemPrefab prefab;
|
||||
if (string.IsNullOrEmpty(identifier))
|
||||
{
|
||||
//legacy support:
|
||||
//1. attempt to find a prefab with an empty identifier and a matching name
|
||||
prefab = MapEntityPrefab.Find(name, "", showErrorMessages: false) as ItemPrefab;
|
||||
//2. not found, attempt to find a prefab with a matching name
|
||||
if (prefab == null) prefab = MapEntityPrefab.Find(name) as ItemPrefab;
|
||||
}
|
||||
else
|
||||
{
|
||||
prefab = MapEntityPrefab.Find(null, identifier, showErrorMessages: false) as ItemPrefab;
|
||||
|
||||
//not found, see if we can find a prefab with a matching alias
|
||||
if (prefab == null)
|
||||
{
|
||||
string lowerCaseName = name.ToLowerInvariant();
|
||||
prefab = MapEntityPrefab.List.Find(me => me.Aliases != null && me.Aliases.Contains(lowerCaseName)) as ItemPrefab;
|
||||
}
|
||||
}
|
||||
|
||||
if (prefab == null)
|
||||
{
|
||||
DebugConsole.ThrowError("Error loading item - item prefab \"" + name + "\" (identifier \"" + identifier + "\") not found.");
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Xml.Linq;
|
||||
using System.Linq;
|
||||
using Barotrauma.Extensions;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
@@ -440,7 +441,6 @@ namespace Barotrauma
|
||||
configFile = filePath;
|
||||
ConfigElement = element;
|
||||
|
||||
string nonTranslatedName = element.GetAttributeString("name", "");
|
||||
identifier = element.GetAttributeString("identifier", "");
|
||||
|
||||
//nameidentifier can be used to make multiple items use the same names and descriptions
|
||||
@@ -448,21 +448,20 @@ namespace Barotrauma
|
||||
|
||||
if (string.IsNullOrEmpty(nameIdentifier))
|
||||
{
|
||||
name = TextManager.Get("EntityName." + identifier, true) ?? nonTranslatedName;
|
||||
name = TextManager.Get("EntityName." + identifier, true) ?? element.GetAttributeString("name", "");
|
||||
}
|
||||
else
|
||||
{
|
||||
name = TextManager.Get("EntityName." + nameIdentifier, true) ?? nonTranslatedName;
|
||||
name = TextManager.Get("EntityName." + nameIdentifier, true) ?? element.GetAttributeString("name", "");
|
||||
}
|
||||
|
||||
if (name == "") { DebugConsole.ThrowError("Unnamed item in " + filePath + "!"); }
|
||||
|
||||
DebugConsole.Log(" " + name);
|
||||
|
||||
Aliases = new HashSet<string>
|
||||
(element.GetAttributeStringArray("aliases", null, convertToLowerInvariant: true) ??
|
||||
element.GetAttributeStringArray("Aliases", new string[0], convertToLowerInvariant: true));
|
||||
Aliases.Add(nonTranslatedName.ToLowerInvariant());
|
||||
Aliases =
|
||||
element.GetAttributeStringArray("aliases", null, convertToLowerInvariant: true) ??
|
||||
element.GetAttributeStringArray("Aliases", new string[0], convertToLowerInvariant: true);
|
||||
|
||||
if (!Enum.TryParse(element.GetAttributeString("category", "Misc"), true, out MapEntityCategory category))
|
||||
{
|
||||
@@ -482,7 +481,7 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
Tags = new HashSet<string>(element.GetAttributeStringArray("tags", new string[0], convertToLowerInvariant: true));
|
||||
if (!Tags.Any())
|
||||
if (Tags.None())
|
||||
{
|
||||
Tags = new HashSet<string>(element.GetAttributeStringArray("Tags", new string[0], convertToLowerInvariant: true));
|
||||
}
|
||||
@@ -720,42 +719,7 @@ namespace Barotrauma
|
||||
return prices[location.Type.Identifier.ToLowerInvariant()];
|
||||
}
|
||||
|
||||
public static ItemPrefab Find(string name, string identifier)
|
||||
{
|
||||
ItemPrefab prefab;
|
||||
if (string.IsNullOrEmpty(identifier))
|
||||
{
|
||||
//legacy support:
|
||||
//1. attempt to find a prefab with an empty identifier and a matching name
|
||||
prefab = Find(name, "", showErrorMessages: false) as ItemPrefab;
|
||||
//2. not found, attempt to find a prefab with a matching name
|
||||
if (prefab == null) prefab = Find(name) as ItemPrefab;
|
||||
//not found, see if we can find a prefab with a matching alias
|
||||
if (prefab == null)
|
||||
{
|
||||
string lowerCaseName = name.ToLowerInvariant();
|
||||
prefab = List.Find(me => me.Aliases != null && me.Aliases.Contains(lowerCaseName)) as ItemPrefab;
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
prefab = Find(null, identifier, showErrorMessages: false) as ItemPrefab;
|
||||
|
||||
//not found, see if we can find a prefab with a matching alias
|
||||
if (prefab == null)
|
||||
{
|
||||
string lowerCaseName = name.ToLowerInvariant();
|
||||
prefab = List.Find(me => me.Aliases != null && me.Aliases.Contains(lowerCaseName)) as ItemPrefab;
|
||||
}
|
||||
}
|
||||
|
||||
if (prefab == null)
|
||||
{
|
||||
DebugConsole.ThrowError("Error loading item - item prefab \"" + name + "\" (identifier \"" + identifier + "\") not found.");
|
||||
}
|
||||
return prefab;
|
||||
}
|
||||
public IEnumerable<PriceInfo> GetPrices()
|
||||
{
|
||||
return prices?.Values;
|
||||
|
||||
@@ -78,11 +78,30 @@ namespace Barotrauma
|
||||
|
||||
private float[] leftDelta;
|
||||
private float[] rightDelta;
|
||||
|
||||
public List<Gap> ConnectedGaps;
|
||||
|
||||
public readonly List<Gap> ConnectedGaps = new List<Gap>();
|
||||
|
||||
public readonly List<Gap> ConnectedGaps = new List<Gap>();
|
||||
|
||||
private string roomName;
|
||||
[Editable, Serialize("", true, translationTextTag: "RoomName.")]
|
||||
public string RoomName
|
||||
{
|
||||
get { return roomName; }
|
||||
set
|
||||
{
|
||||
if (roomName == value) { return; }
|
||||
roomName = value;
|
||||
DisplayName = TextManager.Get(roomName, returnNull: true) ?? roomName;
|
||||
}
|
||||
}
|
||||
|
||||
public string DisplayName
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
private string roomName;
|
||||
[Editable, Serialize("", true, translationTextTag: "RoomName.")]
|
||||
public string RoomName
|
||||
@@ -838,9 +857,6 @@ namespace Barotrauma
|
||||
OxygenPercentage = 100.0f;
|
||||
|
||||
FireSources = new List<FireSource>();
|
||||
linkedTo = new System.Collections.ObjectModel.ObservableCollection<MapEntity>();
|
||||
|
||||
|
||||
|
||||
properties = SerializableProperty.GetProperties(this);
|
||||
|
||||
@@ -1205,93 +1221,36 @@ namespace Barotrauma
|
||||
FireSources.Remove(fire);
|
||||
}
|
||||
|
||||
public IEnumerable<Hull> GetConnectedHulls(int? searchDepth)
|
||||
private HashSet<Hull> adjacentHulls = new HashSet<Hull>();
|
||||
public IEnumerable<Hull> GetConnectedHulls(bool includingThis, int? searchDepth = null)
|
||||
{
|
||||
return GetAdjacentHulls(new HashSet<Hull>(), 0, searchDepth);
|
||||
adjacentHulls.Clear();
|
||||
int startStep = 0;
|
||||
return GetAdjacentHulls(includingThis, adjacentHulls, ref startStep, searchDepth);
|
||||
}
|
||||
|
||||
private HashSet<Hull> GetAdjacentHulls(HashSet<Hull> connectedHulls, int steps, int? searchDepth)
|
||||
private HashSet<Hull> GetAdjacentHulls(bool includingThis, HashSet<Hull> connectedHulls, ref int step, int? searchDepth)
|
||||
{
|
||||
if (distance >= maxDistance) return float.MaxValue;
|
||||
if (this == target)
|
||||
if (includingThis)
|
||||
{
|
||||
return distance + Vector2.Distance(startPos, endPos);
|
||||
connectedHulls.Add(this);
|
||||
}
|
||||
if (step > searchDepth.Value)
|
||||
{
|
||||
return connectedHulls;
|
||||
}
|
||||
|
||||
connectedHulls.Add(this);
|
||||
|
||||
foreach (Gap g in ConnectedGaps)
|
||||
{
|
||||
if (g.ConnectedDoor != null)
|
||||
{
|
||||
//gap blocked if the door is not open or the predicted state is not open
|
||||
if (!g.ConnectedDoor.IsOpen || (g.ConnectedDoor.PredictedState.HasValue && !g.ConnectedDoor.PredictedState.Value))
|
||||
{
|
||||
if (g.ConnectedDoor.OpenState < 0.1f) continue;
|
||||
}
|
||||
}
|
||||
else if (g.Open <= 0.0f)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 2 && i < g.linkedTo.Count; i++)
|
||||
{
|
||||
if (g.linkedTo[i] is Hull hull && !connectedHulls.Contains(hull))
|
||||
{
|
||||
float dist = hull.GetApproximateHullDistance(g.Position, endPos, connectedHulls, target, distance + Vector2.Distance(startPos, g.Position), maxDistance);
|
||||
if (dist < float.MaxValue) return dist;
|
||||
step++;
|
||||
hull.GetAdjacentHulls(true, connectedHulls, ref step, searchDepth);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return float.MaxValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Approximate distance from this hull to the target hull, moving through open gaps without passing through walls.
|
||||
/// Uses a greedy algo and may not use the most optimal path. Returns float.MaxValue if no path is found.
|
||||
/// </summary>
|
||||
public float GetApproximateDistance(Vector2 startPos, Vector2 endPos, Hull targetHull, float maxDistance)
|
||||
{
|
||||
return GetApproximateHullDistance(startPos, endPos, new HashSet<Hull>(), targetHull, 0.0f, maxDistance);
|
||||
}
|
||||
|
||||
private float GetApproximateHullDistance(Vector2 startPos, Vector2 endPos, HashSet<Hull> connectedHulls, Hull target, float distance, float maxDistance)
|
||||
{
|
||||
if (distance >= maxDistance) return float.MaxValue;
|
||||
if (this == target)
|
||||
{
|
||||
return distance + Vector2.Distance(startPos, endPos);
|
||||
}
|
||||
|
||||
connectedHulls.Add(this);
|
||||
|
||||
foreach (Gap g in ConnectedGaps)
|
||||
{
|
||||
if (g.ConnectedDoor != null)
|
||||
{
|
||||
//gap blocked if the door is not open or the predicted state is not open
|
||||
if (!g.ConnectedDoor.IsOpen || (g.ConnectedDoor.PredictedState.HasValue && !g.ConnectedDoor.PredictedState.Value))
|
||||
{
|
||||
if (g.ConnectedDoor.OpenState < 0.1f) continue;
|
||||
}
|
||||
}
|
||||
else if (g.Open <= 0.0f)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 2 && i < g.linkedTo.Count; i++)
|
||||
{
|
||||
if (g.linkedTo[i] is Hull hull && !connectedHulls.Contains(hull))
|
||||
{
|
||||
hull.GetAdjacentHulls(connectedHulls, steps++, searchDepth);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return float.MaxValue;
|
||||
return connectedHulls;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -20,12 +20,12 @@ namespace Barotrauma
|
||||
protected List<ushort> linkedToID;
|
||||
|
||||
//observable collection because some entities may need to be notified when the collection is modified
|
||||
public ObservableCollection<MapEntity> linkedTo;
|
||||
public readonly ObservableCollection<MapEntity> linkedTo = new ObservableCollection<MapEntity>();
|
||||
|
||||
private bool flippedX, flippedY;
|
||||
public bool FlippedX { get { return flippedX; } }
|
||||
public bool FlippedY { get { return flippedY; } }
|
||||
|
||||
|
||||
public bool ShouldBeSaved = true;
|
||||
|
||||
//the position and dimensions of the entity
|
||||
@@ -41,7 +41,7 @@ namespace Barotrauma
|
||||
get { return isHighlighted || ExternalHighlight; }
|
||||
set { isHighlighted = value; }
|
||||
}
|
||||
|
||||
|
||||
public virtual Rectangle Rect
|
||||
{
|
||||
get { return rect; }
|
||||
@@ -161,7 +161,7 @@ namespace Barotrauma
|
||||
// Quick undo/redo for size and movement only. TODO: Remove if we do a more general implementation.
|
||||
private Memento<Rectangle> rectMemento;
|
||||
|
||||
public MapEntity(MapEntityPrefab prefab, Submarine submarine) : base(submarine)
|
||||
public MapEntity(MapEntityPrefab prefab, Submarine submarine) : base(submarine)
|
||||
{
|
||||
this.prefab = prefab;
|
||||
Scale = prefab != null ? prefab.Scale : 1;
|
||||
@@ -289,7 +289,7 @@ namespace Barotrauma
|
||||
|
||||
mapEntityList.Insert(i, this);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Remove the entity from the entity list without removing links to other entities
|
||||
/// </summary>
|
||||
@@ -409,7 +409,7 @@ namespace Barotrauma
|
||||
|
||||
try
|
||||
{
|
||||
MethodInfo loadMethod = t.GetMethod("Load", new [] { typeof(XElement), typeof(Submarine) });
|
||||
MethodInfo loadMethod = t.GetMethod("Load", new[] { typeof(XElement), typeof(Submarine) });
|
||||
if (loadMethod == null)
|
||||
{
|
||||
DebugConsole.ThrowError("Could not find the method \"Load\" in " + t + ".");
|
||||
@@ -499,6 +499,38 @@ namespace Barotrauma
|
||||
if (linkedTo.Contains(e)) linkedTo.Remove(e);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets all linked entities of specific type.
|
||||
/// </summary>
|
||||
public HashSet<T> GetLinkedEntities<T>(HashSet<T> list = null, int? maxDepth = null, Func<T, bool> filter = null) where T : MapEntity
|
||||
{
|
||||
list = list ?? new HashSet<T>();
|
||||
int startDepth = 0;
|
||||
GetLinkedEntitiesRecursive<T>(this, list, ref startDepth, maxDepth, filter);
|
||||
return list;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets all linked entities of specific type.
|
||||
/// </summary>
|
||||
private static void GetLinkedEntitiesRecursive<T>(MapEntity mapEntity, HashSet<T> linkedTargets, ref int depth, int? maxDepth = null, Func<T, bool> filter = null)
|
||||
where T : MapEntity
|
||||
{
|
||||
if (depth > maxDepth) { return; }
|
||||
foreach (var linkedEntity in mapEntity.linkedTo)
|
||||
{
|
||||
if (linkedEntity is T linkedTarget)
|
||||
{
|
||||
if (!linkedTargets.Contains(linkedTarget) && (filter == null || filter(linkedTarget)))
|
||||
{
|
||||
linkedTargets.Add(linkedTarget);
|
||||
depth++;
|
||||
GetLinkedEntitiesRecursive(linkedEntity, linkedTargets, ref depth, maxDepth, filter);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#region Serialized properties
|
||||
// We could use NaN or nullables, but in this case the first is not preferable, because it needs to be checked every time the value is used.
|
||||
// Nullable on the other requires boxing that we don't want to do too often, since it generates garbage.
|
||||
|
||||
@@ -115,7 +115,6 @@ namespace Barotrauma
|
||||
Linkable = true
|
||||
};
|
||||
ep.AllowedLinks.Add("hull");
|
||||
ep.Aliases = new HashSet<string> { "hull" };
|
||||
List.Add(ep);
|
||||
|
||||
ep = new MapEntityPrefab
|
||||
|
||||
@@ -225,6 +225,12 @@ namespace Barotrauma
|
||||
string nonTranslatedName = element.GetAttributeString("name", null) ?? element.Name.ToString();
|
||||
sp.Aliases.Add(nonTranslatedName.ToLowerInvariant());
|
||||
|
||||
SerializableProperty.DeserializeProperties(sp, element);
|
||||
if (sp.Body)
|
||||
{
|
||||
sp.Tags.Add("wall");
|
||||
}
|
||||
|
||||
SerializableProperty.DeserializeProperties(sp, element);
|
||||
if (sp.Body)
|
||||
{
|
||||
|
||||
@@ -131,12 +131,7 @@ namespace Barotrauma.Networking
|
||||
float dist = Vector2.Distance(listener.WorldPosition, sender.WorldPosition);
|
||||
if (dist > range) { return 1.0f; }
|
||||
|
||||
Hull listenerHull = listener == null ? null : Hull.FindHull(listener.WorldPosition);
|
||||
Hull sourceHull = sender == null ? null : Hull.FindHull(sender.WorldPosition);
|
||||
if (sourceHull != listenerHull)
|
||||
{
|
||||
if (Submarine.CheckVisibility(listener.SimPosition, sender.SimPosition) != null) dist = (dist + 100f) * obstructionmult;
|
||||
}
|
||||
if (Submarine.CheckVisibility(listener.SimPosition, sender.SimPosition) != null) dist = (dist + 100f) * obstructionmult;
|
||||
if (dist > range) { return 1.0f; }
|
||||
|
||||
return dist / range;
|
||||
|
||||
Reference in New Issue
Block a user