Unstable 1.8.4.0
This commit is contained in:
@@ -28,7 +28,7 @@ namespace Barotrauma
|
||||
public GUIComponent ReportButtonFrame { get; set; }
|
||||
|
||||
private GUIFrame guiFrame;
|
||||
private GUIFrame crewArea;
|
||||
private GUILayoutGroup crewArea;
|
||||
private GUIListBox crewList;
|
||||
private float crewListOpenState;
|
||||
private bool _isCrewMenuOpen = true;
|
||||
@@ -47,7 +47,7 @@ namespace Barotrauma
|
||||
|
||||
/// <summary>
|
||||
/// This property stores the preference in settings. Don't use for automatic logic.
|
||||
/// Use AutoShowCrewList(), AutoHideCrewList(), and ResetCrewList().
|
||||
/// Use AutoHideCrewList(), and ResetCrewList().
|
||||
/// </summary>
|
||||
public bool IsCrewMenuOpen
|
||||
{
|
||||
@@ -62,11 +62,9 @@ namespace Barotrauma
|
||||
|
||||
public static bool PreferCrewMenuOpen = true;
|
||||
|
||||
public bool AutoShowCrewList() => _isCrewMenuOpen = true;
|
||||
|
||||
public void AutoHideCrewList() => _isCrewMenuOpen = false;
|
||||
|
||||
public void ResetCrewList() => _isCrewMenuOpen = PreferCrewMenuOpen;
|
||||
public void ResetCrewListOpenState() => _isCrewMenuOpen = PreferCrewMenuOpen;
|
||||
|
||||
const float CommandNodeAnimDuration = 0.2f;
|
||||
|
||||
@@ -93,12 +91,30 @@ namespace Barotrauma
|
||||
|
||||
#region Crew Area
|
||||
|
||||
crewArea = new GUIFrame(HUDLayoutSettings.ToRectTransform(HUDLayoutSettings.CrewArea, guiFrame.RectTransform), style: null, color: Color.Transparent)
|
||||
crewArea = new GUILayoutGroup(HUDLayoutSettings.ToRectTransform(HUDLayoutSettings.CrewArea, guiFrame.RectTransform), childAnchor: Anchor.TopCenter)
|
||||
{
|
||||
CanBeFocused = false
|
||||
Stretch = true
|
||||
};
|
||||
crewArea.RectTransform.NonScaledSize = HUDLayoutSettings.CrewArea.Size;
|
||||
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
CharacterTeamType teamId = i == 0 ? CharacterTeamType.Team1 : CharacterTeamType.Team2;
|
||||
var nameText = new GUITextBlock(new RectTransform(new Point(crewArea.Rect.Width - GUI.IntScale(10), GUI.IntScale(30)), crewArea.RectTransform), CombatMission.GetTeamName(teamId), textColor: CombatMission.GetTeamColor(teamId))
|
||||
{
|
||||
ForceUpperCase = ForceUpperCase.Yes,
|
||||
TextGetter = () => CombatMission.GetTeamName(teamId),
|
||||
Visible = false,
|
||||
IgnoreLayoutGroups = true,
|
||||
UserData = teamId
|
||||
};
|
||||
var teamIcon = new GUIImage(new RectTransform(Vector2.One, nameText.RectTransform, Anchor.CenterLeft, scaleBasis: ScaleBasis.BothHeight), style: i == 0 ? "CoalitionIcon" : "SeparatistIcon")
|
||||
{
|
||||
Color = nameText.TextColor
|
||||
};
|
||||
nameText.Padding = new Vector4(teamIcon.Rect.Width + nameText.Padding.X, nameText.Padding.Y, nameText.Padding.Z, nameText.Padding.W);
|
||||
}
|
||||
|
||||
// AbsoluteOffset is set in UpdateProjectSpecific based on crewListOpenState
|
||||
crewList = new GUIListBox(new RectTransform(Vector2.One, crewArea.RectTransform), style: null, isScrollBarOnDefaultSide: false)
|
||||
{
|
||||
@@ -177,6 +193,12 @@ namespace Barotrauma
|
||||
|
||||
ChatBox.InputBox.OnTextChanged += ChatBox.TypingChatMessage;
|
||||
}
|
||||
else if (GameMain.Client == null)
|
||||
{
|
||||
//this method would throw a non-descriptive nullref exception later when trying to access the chatbox
|
||||
//if we'd try to continue from here, better to throw a more descriptive one at this point
|
||||
throw new InvalidOperationException($"Attempted to initialize {nameof(CrewManager)} for multiplayer, but no multiplayer client is active. Are you trying to load a multiplayer save in singleplayer?");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -290,6 +312,14 @@ namespace Barotrauma
|
||||
|
||||
#region Character list management
|
||||
|
||||
/// <summary>
|
||||
/// Note: this is only works client-side. TODO: make it work server-side too?
|
||||
/// </summary>
|
||||
public IEnumerable<Character> GetCharacters()
|
||||
{
|
||||
return characters;
|
||||
}
|
||||
|
||||
public Rectangle GetActiveCrewArea()
|
||||
{
|
||||
return crewArea.Rect;
|
||||
@@ -562,9 +592,19 @@ namespace Barotrauma
|
||||
public bool CharacterClicked(GUIComponent component, object selection)
|
||||
{
|
||||
if (!AllowCharacterSwitch) { return false; }
|
||||
if (!(selection is Character character) || character.IsDead || character.IsUnconscious) { return false; }
|
||||
if (selection is not Character character || character.IsDead || character.IsUnconscious) { return false; }
|
||||
if (!character.IsOnPlayerTeam) { return false; }
|
||||
|
||||
if (GameMain.IsMultiplayer)
|
||||
{
|
||||
if (Character.Controlled == null)
|
||||
{
|
||||
Camera cam = Screen.Selected.Cam;
|
||||
cam.Position = character.DrawPosition;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
SelectCharacter(character);
|
||||
if (GUI.KeyboardDispatcher.Subscriber == crewList) { GUI.KeyboardDispatcher.Subscriber = null; }
|
||||
return true;
|
||||
@@ -631,10 +671,9 @@ namespace Barotrauma
|
||||
{
|
||||
if (crewList != this.crewList) { return; }
|
||||
if (draggedElementData is not Character) { return; }
|
||||
if (!IsSinglePlayer) { return; }
|
||||
if (crewList.HasDraggedElementIndexChanged)
|
||||
{
|
||||
UpdateCrewListIndices();
|
||||
if (IsSinglePlayer) { UpdateCrewListIndices(); }
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -645,10 +684,13 @@ namespace Barotrauma
|
||||
private void ResetCrewListIndex(Character c)
|
||||
{
|
||||
if (c?.Info == null) { return; }
|
||||
c.Info.CrewListIndex = -1;
|
||||
UpdateCrewListIndices();
|
||||
//default to the bottom of the list
|
||||
c.Info.CrewListIndex = int.MaxValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Refresh the <see cref="CharacterInfo.CrewListIndex"/> of the characters based on their order in the crew list
|
||||
/// </summary>
|
||||
private void UpdateCrewListIndices()
|
||||
{
|
||||
if (crewList == null) { return; }
|
||||
@@ -661,20 +703,23 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Order the crew list according to the characters' <see cref="CharacterInfo.CrewListIndex"/>
|
||||
/// </summary>
|
||||
private void SortCrewList()
|
||||
{
|
||||
if (crewList == null) { return; }
|
||||
crewList.Content.RectTransform.SortChildren((x, y) =>
|
||||
{
|
||||
var infoX = (x.GUIComponent.UserData as Character)?.Info?.CrewListIndex;
|
||||
var infoY = (y.GUIComponent.UserData as Character)?.Info?.CrewListIndex;
|
||||
if (infoX.HasValue)
|
||||
int? index1 = (x.GUIComponent.UserData as Character)?.Info?.CrewListIndex;
|
||||
int? index2 = (y.GUIComponent.UserData as Character)?.Info?.CrewListIndex;
|
||||
if (index1.HasValue)
|
||||
{
|
||||
return infoY.HasValue ? infoX.Value.CompareTo(infoY.Value) : -1;
|
||||
return index2.HasValue ? index1.Value.CompareTo(index2.Value) : -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return infoY.HasValue ? 1 : 0;
|
||||
return index2.HasValue ? 1 : 0;
|
||||
}
|
||||
});
|
||||
UpdateCrewListIndices();
|
||||
@@ -1312,6 +1357,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (ConversationAction.IsDialogOpen) { return; }
|
||||
if (!AllowCharacterSwitch) { return; }
|
||||
if (character == null || character.Removed) { return; }
|
||||
//make the previously selected character wait in place for some time
|
||||
//(so they don't immediately start idling and walking away from their station)
|
||||
var aiController = Character.Controlled?.AIController;
|
||||
@@ -1323,6 +1369,16 @@ namespace Barotrauma
|
||||
{
|
||||
GameSession.TabMenuInstance.SelectInfoFrameTab(TabMenu.SelectedTab);
|
||||
}
|
||||
if (character.SelectedItem?.GetComponent<Controller>() == null && character.SelectedCharacter == null)
|
||||
{
|
||||
ResetCrewListOpenState();
|
||||
ChatBox.ResetChatBoxOpenState();
|
||||
}
|
||||
else
|
||||
{
|
||||
AutoHideCrewList();
|
||||
ChatBox.AutoHideChatBox();
|
||||
}
|
||||
}
|
||||
|
||||
private int TryAdjustIndex(int amount)
|
||||
@@ -1340,7 +1396,7 @@ namespace Barotrauma
|
||||
if (index > lastIndex) { index = 0; }
|
||||
if (index < 0) { index = lastIndex; }
|
||||
|
||||
if ((crewList.Content.GetChild(index)?.UserData as Character)?.IsOnPlayerTeam ?? false)
|
||||
if (crewList.Content.GetChild(index)?.UserData is Character { IsOnPlayerTeam: true, Removed: false })
|
||||
{
|
||||
return index;
|
||||
}
|
||||
@@ -1635,6 +1691,18 @@ namespace Barotrauma
|
||||
{
|
||||
crewArea.Visible = characters.Count > 0 && CharacterHealth.OpenHealthWindow == null;
|
||||
|
||||
CharacterTeamType myTeam = Character.Controlled?.TeamID ?? GameMain.Client?.MyClient?.TeamID ?? CharacterTeamType.Team1;
|
||||
if (GameMain.GameSession?.GameMode is PvPMode)
|
||||
{
|
||||
var team1Text = crewArea.GetChildByUserData(CharacterTeamType.Team1);
|
||||
team1Text.Visible = myTeam == CharacterTeamType.Team1;
|
||||
team1Text.IgnoreLayoutGroups = !team1Text.Visible;
|
||||
|
||||
var team2Text = crewArea.GetChildByUserData(CharacterTeamType.Team2);
|
||||
team2Text.Visible = myTeam == CharacterTeamType.Team2;
|
||||
team2Text.IgnoreLayoutGroups = !team2Text.Visible;
|
||||
}
|
||||
|
||||
foreach (GUIComponent characterComponent in crewList.Content.Children)
|
||||
{
|
||||
if (characterComponent.UserData is Character character)
|
||||
@@ -1645,7 +1713,7 @@ namespace Barotrauma
|
||||
continue;
|
||||
}
|
||||
|
||||
characterComponent.Visible = Character.Controlled == null || Character.Controlled.TeamID == character.TeamID;
|
||||
characterComponent.Visible = myTeam == character.TeamID;
|
||||
if (character.TeamID == CharacterTeamType.FriendlyNPC && Character.Controlled != null &&
|
||||
(character.CurrentHull == Character.Controlled.CurrentHull || Vector2.DistanceSquared(Character.Controlled.WorldPosition, character.WorldPosition) < 500.0f * 500.0f))
|
||||
{
|
||||
@@ -1873,7 +1941,7 @@ namespace Barotrauma
|
||||
{
|
||||
get
|
||||
{
|
||||
if (GameMain.GameSession?.CrewManager == null)
|
||||
if (GameMain.GameSession?.CrewManager == null || Screen.Selected is { IsEditor: true })
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -2010,7 +2078,7 @@ namespace Barotrauma
|
||||
// Character context works differently to others as we still use the "basic" command interface,
|
||||
// but the order will be automatically assigned to this character
|
||||
isContextual = forceContextual;
|
||||
if (entityContext is Character character)
|
||||
if (entityContext is Character { Info: not null } character)
|
||||
{
|
||||
characterContext = character;
|
||||
itemContext = null;
|
||||
@@ -2098,7 +2166,7 @@ namespace Barotrauma
|
||||
CreateNodeConnectors();
|
||||
if (Character.Controlled != null)
|
||||
{
|
||||
Character.Controlled.dontFollowCursor = true;
|
||||
Character.Controlled.FollowCursor = false;
|
||||
}
|
||||
|
||||
HintManager.OnShowCommandInterface();
|
||||
@@ -2242,7 +2310,7 @@ namespace Barotrauma
|
||||
returnNodeHotkey = expandNodeHotkey = Keys.None;
|
||||
if (Character.Controlled != null)
|
||||
{
|
||||
Character.Controlled.dontFollowCursor = false;
|
||||
Character.Controlled.FollowCursor = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2511,7 +2579,7 @@ namespace Barotrauma
|
||||
// --> Create shortcut node for Steer order
|
||||
if (CanFitMoreNodes() && ShouldDelegateOrder("steer") && IsNonDuplicateOrderPrefab(OrderPrefab.Prefabs["steer"]) &&
|
||||
subItems.Find(i => i.HasTag(Tags.NavTerminal) && i.IsPlayerTeamInteractable) is Item nav && characters.None(c => c.SelectedItem == nav) &&
|
||||
nav.GetComponent<Steering>() is Steering steering && steering.Voltage > steering.MinVoltage)
|
||||
nav.GetComponent<Steering>() is Steering { HasPower: true } steering)
|
||||
{
|
||||
var order = new Order(OrderPrefab.Prefabs["steer"], steering.Item, steering);
|
||||
AddOrderNode(order);
|
||||
@@ -2625,9 +2693,9 @@ namespace Barotrauma
|
||||
bool IsNonDuplicateOrder(Order order) => IsNonDuplicateOrderPrefab(order.Prefab, order.Option);
|
||||
bool IsNonDuplicateOrderPrefab(OrderPrefab orderPrefab, Identifier option = default)
|
||||
{
|
||||
return characterContext == null || (option.IsEmpty ?
|
||||
return characterContext == null || (characterContext.CurrentOrders != null && (option.IsEmpty ?
|
||||
characterContext.CurrentOrders.None(oi => oi?.Identifier == orderPrefab?.Identifier) :
|
||||
characterContext.CurrentOrders.None(oi => oi?.Identifier == orderPrefab?.Identifier && oi.Option == option));
|
||||
characterContext.CurrentOrders.None(oi => oi?.Identifier == orderPrefab?.Identifier && oi?.Option == option)));
|
||||
}
|
||||
void AddOrderNodeWithIdentifier(string identifier)
|
||||
{
|
||||
@@ -3000,7 +3068,7 @@ namespace Barotrauma
|
||||
{
|
||||
optionElement.OnSecondaryClicked = (button, _) => CreateAssignmentNodes(button);
|
||||
}
|
||||
var colorMultiplier = characters.Any(c => c.CurrentOrders.Any(o => o != null &&
|
||||
var colorMultiplier = characters.Any(c => c.CurrentOrders != null && c.CurrentOrders.Any(o => o != null &&
|
||||
o.Identifier == userData.Order.Identifier &&
|
||||
o.TargetEntity == userData.Order.TargetEntity)) ? 0.5f : 1f;
|
||||
CreateNodeIcon(Vector2.One, optionElement.RectTransform, item.Prefab.MinimapIcon ?? order.SymbolSprite, order.Color * colorMultiplier, tooltip: item.Name);
|
||||
@@ -3654,7 +3722,7 @@ namespace Barotrauma
|
||||
bool hasLeaks = Character.Controlled.CurrentHull.ConnectedGaps.Any(g => !g.IsRoomToRoom && g.Open > 0.0f);
|
||||
ToggleReportButton("reportbreach", hasLeaks);
|
||||
|
||||
bool hasIntruders = Character.CharacterList.Any(c => c.CurrentHull == Character.Controlled.CurrentHull && AIObjectiveFightIntruders.IsValidTarget(c, Character.Controlled, false));
|
||||
bool hasIntruders = Character.CharacterList.Any(c => c.CurrentHull == Character.Controlled.CurrentHull && AIObjectiveFightIntruders.IsValidTarget(c, Character.Controlled, targetCharactersInOtherSubs: false));
|
||||
ToggleReportButton("reportintruders", hasIntruders);
|
||||
|
||||
foreach (GUIComponent reportButton in ReportButtonFrame.Children)
|
||||
@@ -3780,5 +3848,72 @@ namespace Barotrauma
|
||||
GameMain.GameSession?.CrewManager?.AddOrder(order, fadeOutTime);
|
||||
}
|
||||
}
|
||||
|
||||
private class CharacterInfoComparer : IEqualityComparer<CharacterInfo>
|
||||
{
|
||||
public bool Equals(CharacterInfo x, CharacterInfo y)
|
||||
{
|
||||
if (ReferenceEquals(x, y))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (x is null || y is null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return x.ID == y.ID;
|
||||
}
|
||||
|
||||
public int GetHashCode(CharacterInfo obj)
|
||||
{
|
||||
return obj.ID;
|
||||
}
|
||||
}
|
||||
|
||||
public bool UpdateReserveBenchIfNeeded(IEnumerable<CharacterInfo> updatedReserveBench)
|
||||
{
|
||||
var newBench = updatedReserveBench.ToHashSet(new CharacterInfoComparer());
|
||||
var currentBench = reserveBench.ToHashSet(new CharacterInfoComparer());
|
||||
|
||||
bool updateNeeded = !newBench.SetEquals(currentBench);
|
||||
if (updateNeeded)
|
||||
{
|
||||
reserveBench.Clear(); // since this is the reserve bench (characters not instantiated), there's no need to retain any references etc
|
||||
reserveBench.AddRange(updatedReserveBench);
|
||||
}
|
||||
|
||||
return updateNeeded;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This will update which CharacterInfos should be in CrewManager and which shouldn't, excluding the reserve bench.
|
||||
/// The CharacterInfos themselves aren't updated, they will only be either added, removed, or kept as-is.
|
||||
/// </summary>
|
||||
public bool UpdateCrewManagerIfNecessary(List<CharacterInfo> updatedCrewManager)
|
||||
{
|
||||
// CharacterInfos no longer in the server's CrewManager
|
||||
var toRemove = characterInfos.Where(original => updatedCrewManager.None(updated => updated.ID == original.ID)).ToList();
|
||||
// CharacterInfos that are in the server's CrewManager but not on the client yet
|
||||
var toAdd = updatedCrewManager.Where(updated => characterInfos.None(original => original.ID == updated.ID)).ToList();
|
||||
|
||||
foreach (CharacterInfo characterInfo in toRemove)
|
||||
{
|
||||
if (characterInfo.Character is Character existingCharacter)
|
||||
{
|
||||
if (!existingCharacter.IsBot) { continue; } // on client side players are also stored here, we should skip those in this case
|
||||
RemoveCharacter(characterInfo.Character, removeInfo: true, resetCrewListIndex: true);
|
||||
}
|
||||
else
|
||||
{
|
||||
characterInfos.Remove(characterInfo);
|
||||
}
|
||||
}
|
||||
|
||||
characterInfos.AddRange(toAdd);
|
||||
|
||||
return toRemove.Count > 0 || toAdd.Count > 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user