Unstable 1.1.14.0

This commit is contained in:
Markus Isberg
2023-10-02 16:43:54 +03:00
parent 94f5a93a0c
commit cf8f0de659
606 changed files with 21906 additions and 11456 deletions
@@ -428,7 +428,7 @@ namespace Barotrauma.Items.Components
}
}
public override void UpdateHUD(Character character, float deltaTime, Camera cam)
public override void UpdateHUDComponentSpecific(Character character, float deltaTime, Camera cam)
{
inSufficientPowerWarning.Visible = IsActive && !hasPower;
}
@@ -108,7 +108,7 @@ namespace Barotrauma.Items.Components
}
}
public override void UpdateHUD(Character character, float deltaTime, Camera cam)
public override void UpdateHUDComponentSpecific(Character character, float deltaTime, Camera cam)
{
powerIndicator.Selected = hasPower && IsActive;
autoControlIndicator.Selected = controlLockTimer > 0.0f;
@@ -138,14 +138,14 @@ namespace Barotrauma.Items.Components
}
}
public void Draw(SpriteBatch spriteBatch, bool editing, float itemDepth = -1)
public void Draw(SpriteBatch spriteBatch, bool editing, float itemDepth = -1, Color? overrideColor = null)
{
if (propellerSprite != null)
{
Vector2 drawPos = item.DrawPosition;
drawPos += PropellerPos;
drawPos.Y = -drawPos.Y;
propellerSprite.Draw(spriteBatch, (int)Math.Floor(spriteIndex), drawPos, Color.White, propellerSprite.Origin, 0.0f, Vector2.One);
propellerSprite.Draw(spriteBatch, (int)Math.Floor(spriteIndex), drawPos, overrideColor ?? Color.White, propellerSprite.Origin, 0.0f, Vector2.One);
}
if (editing && !DisablePropellerDamage && propellerDamage != null && !GUI.DisableHUD)
@@ -38,6 +38,11 @@ namespace Barotrauma.Items.Components
}
private FabricationRecipe selectedItem;
/// <summary>
/// Which character's skills the current view is displayed based on
/// </summary>
private Character displayingForCharacter;
public Identifier SelectedItemIdentifier => SelectedItem?.TargetItem.Identifier ?? Identifier.Empty;
private GUIComponent inSufficientPowerWarning;
@@ -358,9 +363,11 @@ namespace Barotrauma.Items.Components
if (inputInventoryHolder != null)
{
inputContainer.AllowUIOverlap = true;
inputContainer.Inventory.DrawWhenEquipped = true;
inputContainer.Inventory.RectTransform = inputInventoryHolder.RectTransform;
}
outputContainer.AllowUIOverlap = true;
outputContainer.Inventory.DrawWhenEquipped = true;
outputContainer.Inventory.RectTransform = outputInventoryHolder.RectTransform;
}
@@ -453,13 +460,8 @@ namespace Barotrauma.Items.Components
requiresRecipeText.RectTransform.RepositionChildInHierarchy(itemList.Content.RectTransform.GetChildIndex(firstRequiresRecipe.RectTransform));
}
FilterEntities(selectedItemCategory, itemFilterBox?.Text ?? string.Empty);
HideEmptyItemListCategories();
if (selectedItem != null)
{
//reselect to recreate the info based on the new user's skills
SelectItem(character, selectedItem);
}
}
private readonly Dictionary<FabricationRecipe.RequiredItem, int> missingIngredientCounts = new Dictionary<FabricationRecipe.RequiredItem, int>();
@@ -538,6 +540,8 @@ namespace Barotrauma.Items.Components
int slotIndex = 0;
foreach (var kvp in missingIngredientCounts)
{
if (inputContainer.Inventory?.visualSlots == null) { break; }
var requiredItem = kvp.Key;
int missingCount = kvp.Value;
@@ -560,11 +564,10 @@ namespace Barotrauma.Items.Components
var requiredItemPrefab = requiredItem.FirstMatchingPrefab;
float iconAlpha = 0.0f;
ItemPrefab requiredItemToDisplay;
int count = requiredItem.ItemPrefabs.Count();
if (count > 1)
ItemPrefab requiredItemToDisplay = requiredItem.DefaultItem.IsEmpty ? null : requiredItem.ItemPrefabs.FirstOrDefault(p => p.Identifier == requiredItem.DefaultItem);
if (requiredItemToDisplay == null && requiredItem.ItemPrefabs.Multiple())
{
float iconCycleSpeed = 0.5f / count;
float iconCycleSpeed = 0.75f;
float iconCycleT = (float)Timing.TotalTime * iconCycleSpeed;
int iconIndex = (int)(iconCycleT % requiredItem.ItemPrefabs.Count());
@@ -573,7 +576,7 @@ namespace Barotrauma.Items.Components
}
else
{
requiredItemToDisplay = requiredItem.ItemPrefabs.FirstOrDefault();
requiredItemToDisplay ??= requiredItem.ItemPrefabs.FirstOrDefault();
iconAlpha = 1.0f;
}
if (iconAlpha > 0.0f)
@@ -616,9 +619,12 @@ namespace Barotrauma.Items.Components
if (slotRect.Contains(PlayerInput.MousePosition))
{
var suitableIngredients = requiredItem.ItemPrefabs.Select(ip => ip.Name).Distinct();
LocalizedString toolTipText = string.Join(", ", suitableIngredients.Count() > 3 ? suitableIngredients.SkipLast(suitableIngredients.Count() - 3) : suitableIngredients);
if (suitableIngredients.Count() > 3) { toolTipText += "..."; }
LocalizedString toolTipText = requiredItem.OverrideHeader;
if (requiredItem.OverrideHeader.IsNullOrEmpty())
{
var suitableIngredients = requiredItem.ItemPrefabs.Where(ip => !ip.HideInMenus).OrderBy(ip => ip.DefaultPrice?.Price ?? 0).Select(ip => ip.Name).Distinct();
toolTipText = GetSuitableIngredientText(suitableIngredients);
}
if (requiredItem.UseCondition && requiredItem.MinCondition < 1.0f)
{
toolTipText += " " + (int)Math.Round(requiredItem.MinCondition * 100) + "%";
@@ -656,15 +662,68 @@ namespace Barotrauma.Items.Components
}
}
private LocalizedString GetSuitableIngredientText(IEnumerable<LocalizedString> itemNameList)
{
int count = itemNameList.Count();
if (count == 0)
{
return string.Empty;
}
else if (count == 1)
{
return itemNameList.First();
}
else if (count == 2)
{
//[item1] or [item2]
return TextManager.GetWithVariables(
"DialogRequiredTreatmentOptionsLast",
("[treatment1]", itemNameList.ElementAt(0)),
("[treatment2]", itemNameList.ElementAt(1)));
}
else
{
// [item1], [item2], [item3] ... or [lastitem]
LocalizedString itemListStr = TextManager.GetWithVariables(
"DialogRequiredTreatmentOptionsFirst",
("[treatment1]", itemNameList.ElementAt(0)),
("[treatment2]", itemNameList.ElementAt(1)));
int i;
bool isTruncated = false;
for (i = 2; i < count - 1; i++)
{
if (itemListStr.Length > 50)
{
isTruncated = true;
break;
}
itemListStr = TextManager.GetWithVariables(
"DialogRequiredTreatmentOptionsFirst",
("[treatment1]", itemListStr),
("[treatment2]", itemNameList.ElementAt(i)));
}
itemListStr = TextManager.GetWithVariables(
"DialogRequiredTreatmentOptionsLast",
("[treatment1]", itemListStr),
("[treatment2]", itemNameList.ElementAt(i)));
if (isTruncated)
{
itemListStr += TextManager.Get("ellipsis");
}
return itemListStr;
}
}
private void DrawOutputOverLay(SpriteBatch spriteBatch, GUICustomComponent overlayComponent)
{
overlayComponent.RectTransform.SetAsLastChild();
FabricationRecipe targetItem = fabricatedItem ?? selectedItem;
if (targetItem != null)
if (targetItem != null && outputContainer.Inventory?.visualSlots != null)
{
Rectangle slotRect = outputContainer.Inventory.visualSlots[0].Rect;
if (fabricatedItem != null)
{
float clampedProgressState = Math.Clamp(progressState, 0f, 1f);
@@ -699,6 +758,16 @@ namespace Barotrauma.Items.Components
{
FabricationRecipe recipe = child.UserData as FabricationRecipe;
if (recipe?.DisplayName == null) { continue; }
if (recipe.HideForNonTraitors)
{
if (Character.Controlled is not { IsTraitor: true })
{
child.Visible = false;
continue;
}
}
child.Visible =
(string.IsNullOrWhiteSpace(filter) || recipe.DisplayName.Contains(filter, StringComparison.OrdinalIgnoreCase)) &&
(!category.HasValue || recipe.TargetItem.Category.HasFlag(category.Value));
@@ -749,8 +818,9 @@ namespace Barotrauma.Items.Components
private bool SelectItem(Character user, FabricationRecipe selectedItem, float? overrideRequiredTime = null)
{
this.selectedItem = selectedItem;
displayingForCharacter = user;
int max = Math.Max(selectedItem.TargetItem.MaxStackSize / selectedItem.Amount, 1);
int max = Math.Max(selectedItem.TargetItem.GetMaxStackSize(outputContainer.Inventory) / selectedItem.Amount, 1);
if (amountInput != null)
{
@@ -924,7 +994,7 @@ namespace Barotrauma.Items.Components
return true;
}
public override void UpdateHUD(Character character, float deltaTime, Camera cam)
public override void UpdateHUDComponentSpecific(Character character, float deltaTime, Camera cam)
{
activateButton.Enabled = false;
inSufficientPowerWarning.Visible = IsActive && !hasPower;
@@ -933,6 +1003,12 @@ namespace Barotrauma.Items.Components
if (!IsActive)
{
if (selectedItem != null && displayingForCharacter != character)
{
//reselect to recreate the info based on the new user's skills
SelectItem(character, selectedItem);
}
//only check ingredients if the fabricator isn't active (if it is, this is done in Update)
if (refreshIngredientsTimer <= 0.0f)
{
@@ -998,9 +1074,13 @@ namespace Barotrauma.Items.Components
{
fabricationLimits[msg.ReadUInt32()] = 0;
}
State = newState;
this.amountToFabricate = amountToFabricate;
//don't touch the amount unless another character changed it or the fabricator is running
//otherwise we may end up reverting the changes the client just did to the amount
if ((user != null && user != Character.Controlled) || State != FabricatorState.Stopped)
{
this.amountToFabricate = amountToFabricate;
}
this.amountRemaining = amountRemaining;
if (newState == FabricatorState.Stopped || recipeHash == 0)
{
@@ -295,7 +295,7 @@ namespace Barotrauma.Items.Components
}
}
OrderPrefab[] reports = OrderPrefab.Prefabs.Where(o => o.IsReport && o.SymbolSprite != null && !o.Hidden).OrderBy(o => o.Identifier).ToArray();
OrderPrefab[] reports = OrderPrefab.Prefabs.Where(o => o.IsVisibleAsReportButton).OrderBy(o => o.Identifier).ToArray();
GUIFrame bottomFrame = new GUIFrame(new RectTransform(new Vector2(0.5f, 0.15f), paddedContainer.RectTransform, Anchor.BottomCenter) { MaxSize = new Point(int.MaxValue, GUI.IntScale(40)) }, style: null)
{
@@ -350,10 +350,16 @@ namespace Barotrauma.Items.Components
}
};
List<ItemPrefab> shownItemPrefabs = new List<ItemPrefab>();
foreach (ItemPrefab prefab in ItemPrefab.Prefabs.OrderBy(prefab => prefab.Name))
{
if (prefab.HideInMenus) { continue; }
if (shownItemPrefabs.Any(ip => DisplayAsSameItem(ip, prefab)))
{
continue;
}
CreateItemFrame(prefab, listBox.Content.RectTransform);
shownItemPrefabs.Add(prefab);
}
searchBar.OnDeselected += (sender, key) =>
@@ -398,6 +404,27 @@ namespace Barotrauma.Items.Components
new Point(int.MaxValue, paddedContainer.Rect.Height - bottomFrame.Rect.Height - buttonLayout.Rect.Height);
}
private static Sprite GetPreviewSprite(ItemPrefab prefab)
{
return prefab.InventoryIcon ?? prefab.Sprite;
}
/// <summary>
/// If the items have an identical name and icon (e.g. a variant with an alternative fabrication/deconstruction recipe),
/// they're displayed as if they were the same item, not as two separate entries.
/// </summary>
private static bool DisplayAsSameItem(ItemPrefab prefab1, ItemPrefab prefab2)
{
if (prefab1 == prefab2) { return true; }
if (prefab1.Name == prefab2.Name)
{
var sprite1 = GetPreviewSprite(prefab1);
var sprite2 = GetPreviewSprite(prefab2);
return sprite1?.FullPath == sprite2?.FullPath && sprite1?.SourceRect == sprite2?.SourceRect;
}
return false;
}
private bool VisibleOnItemFinder(Item it)
{
if (it?.Submarine == null) { return false; }
@@ -413,7 +440,7 @@ namespace Barotrauma.Items.Components
if (it.Container?.GetComponent<ItemContainer>() is { DrawInventory: false } or { AllowAccess: false }) { return false; }
if (it.HasTag("traitormissionitem")) { return false; }
if (it.HasTag(Tags.TraitorMissionItem)) { return false; }
return true;
}
@@ -539,13 +566,13 @@ namespace Barotrauma.Items.Components
displayedSubs.Add(item.Submarine);
displayedSubs.AddRange(item.Submarine.DockedTo.Where(s => s.TeamID == item.Submarine.TeamID));
subEntities = MapEntity.mapEntityList.Where(me => (item.Submarine is { } sub && sub.IsEntityFoundOnThisSub(me, includingConnectedSubs: true, allowDifferentType: false)) && !me.HiddenInGame).OrderByDescending(w => w.SpriteDepth).ToList();
subEntities = MapEntity.MapEntityList.Where(me => (item.Submarine is { } sub && sub.IsEntityFoundOnThisSub(me, includingConnectedSubs: true, allowDifferentType: false)) && !me.HiddenInGame).OrderByDescending(w => w.SpriteDepth).ToList();
BakeSubmarine(item.Submarine, parentRect);
elementSize = GuiFrame.Rect.Size;
}
public override void UpdateHUD(Character character, float deltaTime, Camera cam)
public override void UpdateHUDComponentSpecific(Character character, float deltaTime, Camera cam)
{
//recreate HUD if the subs we should display have changed
if (item.Submarine == null && displayedSubs.Count > 0 || // item not inside a sub anymore, but display is still showing subs
@@ -824,7 +851,8 @@ namespace Barotrauma.Items.Components
foreach (GUIComponent component in listBox.Content.Children)
{
component.Visible = false;
if (component.UserData is ItemPrefab { Name: { } prefabName} prefab && itemsFoundOnSub.Contains(prefab))
if (component.UserData is ItemPrefab { Name: { } prefabName} prefab &&
(itemsFoundOnSub.Contains(prefab) || itemsFoundOnSub.Any(ip => DisplayAsSameItem(ip, prefab))))
{
component.Visible = prefabName.ToLower().Contains(text.ToLower());
@@ -851,9 +879,9 @@ namespace Barotrauma.Items.Components
tooltip.RectTransform.ScreenSpaceOffset = new Point(box.Rect.X, box.Rect.Y - height);
}
private void CreateItemFrame(ItemPrefab prefab, RectTransform parent)
private static void CreateItemFrame(ItemPrefab prefab, RectTransform parent)
{
Sprite sprite = prefab.InventoryIcon ?? prefab.Sprite;
Sprite sprite = GetPreviewSprite(prefab);
if (sprite is null) { return; }
GUIFrame frame = new GUIFrame(new RectTransform(new Vector2(1f, 0.25f), parent), style: "ListBoxElement")
{
@@ -899,7 +927,7 @@ namespace Barotrauma.Items.Components
{
if (!VisibleOnItemFinder(it)) { continue; }
if (it.Prefab == searchedPrefab)
if (DisplayAsSameItem(it.Prefab, searchedPrefab))
{
// ignore items on players and hidden inventories
if (it.FindParentInventory(inv => inv is CharacterInventory || inv is ItemInventory { Owner: Item { HiddenInGame: true }}) is { }) { continue; }
@@ -1079,7 +1107,7 @@ namespace Barotrauma.Items.Components
if (ShowHullIntegrity)
{
float amount = 1f + hullData.LinkedHulls.Count;
gapOpenSum = hull.ConnectedGaps.Concat(hullData.LinkedHulls.SelectMany(h => h.ConnectedGaps)).Where(g => !g.IsRoomToRoom && !g.HiddenInGame).Sum(g => g.Open) / amount;
gapOpenSum = hull.ConnectedGaps.Concat(hullData.LinkedHulls.SelectMany(h => h.ConnectedGaps)).Where(g => g.linkedTo.Count == 1 && !g.HiddenInGame).Sum(g => g.Open) / amount;
borderColor = Color.Lerp(neutralColor, GUIStyle.Red, Math.Min(gapOpenSum, 1.0f));
}
@@ -181,7 +181,7 @@ namespace Barotrauma.Items.Components
private float flickerTimer;
private readonly float flickerFrequency = 1;
public override void UpdateHUD(Character character, float deltaTime, Camera cam)
public override void UpdateHUDComponentSpecific(Character character, float deltaTime, Camera cam)
{
autoControlIndicator.Selected = IsAutoControlled;
PowerButton.Enabled = isActiveLockTimer <= 0.0f;
@@ -615,7 +615,7 @@ namespace Barotrauma.Items.Components
turbineOutputMeter, TurbineOutput, new Vector2(0.0f, 100.0f), clampedOptimalTurbineOutput, clampedAllowedTurbineOutput);
}
public override void UpdateHUD(Character character, float deltaTime, Camera cam)
public override void UpdateHUDComponentSpecific(Character character, float deltaTime, Camera cam)
{
IsActive = true;
@@ -109,7 +109,7 @@ namespace Barotrauma.Items.Components
},
{
BlipType.Destructible,
new Color[] { Color.TransparentBlack, new Color(74, 113, 75) * 0.8f, new Color(151, 236, 172) * 0.8f, new Color(153, 217, 234) * 0.8f }
new Color[] { Color.TransparentBlack, new Color(94, 114, 73) * 0.8f, new Color(255, 236, 151) * 0.8f, new Color(242, 243, 194) * 0.8f }
},
{
BlipType.Door,
@@ -358,11 +358,6 @@ namespace Barotrauma.Items.Components
}
}
protected override void TryCreateDragHandle()
{
base.TryCreateDragHandle();
}
private void SetPingDirection(Vector2 direction)
{
pingDirection = direction;
@@ -471,7 +466,7 @@ namespace Barotrauma.Items.Components
}
}
public override void UpdateHUD(Character character, float deltaTime, Camera cam)
public override void UpdateHUDComponentSpecific(Character character, float deltaTime, Camera cam)
{
showDirectionalIndicatorTimer -= deltaTime;
if (GameMain.Client != null)
@@ -981,38 +976,41 @@ namespace Barotrauma.Items.Components
}
}
if (GameMain.GameSession == null || Level.Loaded == null) { return; }
if (GameMain.GameSession == null) { return; }
if (Level.Loaded.StartLocation?.Type is { ShowSonarMarker: true })
if (Level.Loaded != null)
{
DrawMarker(spriteBatch,
Level.Loaded.StartLocation.Name,
(Level.Loaded.StartOutpost != null ? "outpost" : "location").ToIdentifier(),
"startlocation",
Level.Loaded.StartExitPosition, transducerCenter,
displayScale, center, DisplayRadius);
}
if (Level.Loaded.StartLocation?.Type is { ShowSonarMarker: true })
{
DrawMarker(spriteBatch,
Level.Loaded.StartLocation.Name,
(Level.Loaded.StartOutpost != null ? "outpost" : "location").ToIdentifier(),
"startlocation",
Level.Loaded.StartExitPosition, transducerCenter,
displayScale, center, DisplayRadius);
}
if (Level.Loaded is { EndLocation.Type.ShowSonarMarker: true, Type: LevelData.LevelType.LocationConnection })
{
DrawMarker(spriteBatch,
Level.Loaded.EndLocation.Name,
(Level.Loaded.EndOutpost != null ? "outpost" : "location").ToIdentifier(),
"endlocation",
Level.Loaded.EndExitPosition, transducerCenter,
displayScale, center, DisplayRadius);
}
if (Level.Loaded is { EndLocation.Type.ShowSonarMarker: true, Type: LevelData.LevelType.LocationConnection })
{
DrawMarker(spriteBatch,
Level.Loaded.EndLocation.Name,
(Level.Loaded.EndOutpost != null ? "outpost" : "location").ToIdentifier(),
"endlocation",
Level.Loaded.EndExitPosition, transducerCenter,
displayScale, center, DisplayRadius);
}
for (int i = 0; i < Level.Loaded.Caves.Count; i++)
{
var cave = Level.Loaded.Caves[i];
if (!cave.DisplayOnSonar) { continue; }
DrawMarker(spriteBatch,
caveLabel.Value,
"cave".ToIdentifier(),
"cave" + i,
cave.StartPos.ToVector2(), transducerCenter,
displayScale, center, DisplayRadius);
for (int i = 0; i < Level.Loaded.Caves.Count; i++)
{
var cave = Level.Loaded.Caves[i];
if (cave.MissionsToDisplayOnSonar.None()) { continue; }
DrawMarker(spriteBatch,
caveLabel.Value,
"cave".ToIdentifier(),
"cave" + i,
cave.StartPos.ToVector2(), transducerCenter,
displayScale, center, DisplayRadius);
}
}
int missionIndex = 0;
@@ -1070,7 +1068,7 @@ namespace Barotrauma.Items.Components
{
if (!sub.ShowSonarMarker) { continue; }
if (connectedSubs.Contains(sub)) { continue; }
if (sub.WorldPosition.Y > Level.Loaded.Size.Y) { continue; }
if (Level.Loaded != null && sub.WorldPosition.Y > Level.Loaded.Size.Y) { continue; }
if (item.Submarine != null || Character.Controlled != null)
{
@@ -532,6 +532,22 @@ namespace Barotrauma.Items.Components
};
}
/// <summary>
/// Map the rectangular steering vector to a circular area using FG-Squircular Mapping which preserves the angle of the vector.
/// </summary>
private static Vector2 MapSquareToCircle(Vector2 steeringVector)
{
float xSqr = steeringVector.X * steeringVector.X;
float ySqr = steeringVector.Y * steeringVector.Y;
float length = MathF.Sqrt(ySqr + xSqr);
if (MathUtils.NearlyEqual(length, 0.0f)) { return Vector2.Zero; }
//FG-Squircular mapping formula from https://arxiv.org/ftp/arxiv/papers/1509/1509.06344.pdf
float x = steeringVector.X * MathF.Sqrt(xSqr + ySqr - xSqr * ySqr) / length;
float y = steeringVector.Y * MathF.Sqrt(xSqr + ySqr - xSqr * ySqr) / length;
return new Vector2(x, y);
}
public void DrawHUD(SpriteBatch spriteBatch, Rectangle rect)
{
int width = rect.Width, height = rect.Height;
@@ -545,11 +561,9 @@ namespace Barotrauma.Items.Components
if (!AutoPilot)
{
Vector2 unitSteeringInput = steeringInput / 100.0f;
//map input from rectangle to circle
Vector2 steeringInputPos = new Vector2(
steeringInput.X * (float)Math.Sqrt(1.0f - 0.5f * unitSteeringInput.Y * unitSteeringInput.Y),
-steeringInput.Y * (float)Math.Sqrt(1.0f - 0.5f * unitSteeringInput.X * unitSteeringInput.X));
Vector2 steeringInputPos = MapSquareToCircle(steeringInput / 100f) * 100.0f;
steeringInputPos.Y = -steeringInputPos.Y;
steeringInputPos += steeringOrigin;
if (steeringIndicator != null)
@@ -604,10 +618,8 @@ namespace Barotrauma.Items.Components
}
//map velocity from rectangle to circle
Vector2 unitTargetVel = targetVelocity / 100.0f;
Vector2 steeringPos = new Vector2(
targetVelocity.X * 0.9f * (float)Math.Sqrt(1.0f - 0.5f * unitTargetVel.Y * unitTargetVel.Y),
-targetVelocity.Y * 0.9f * (float)Math.Sqrt(1.0f - 0.5f * unitTargetVel.X * unitTargetVel.X));
Vector2 steeringPos = MapSquareToCircle(targetVelocity / 100f) * 90.0f;
steeringPos.Y = -steeringPos.Y;
steeringPos += steeringOrigin;
if (steeringIndicator != null)
@@ -682,7 +694,7 @@ namespace Barotrauma.Items.Components
}
}
public override void UpdateHUD(Character character, float deltaTime, Camera cam)
public override void UpdateHUDComponentSpecific(Character character, float deltaTime, Camera cam)
{
if (swapDestinationOrder == null)
{