Merge branch 'master' of https://github.com/Regalis11/Barotrauma into develop
This commit is contained in:
@@ -18,17 +18,40 @@ namespace Barotrauma
|
||||
public readonly ChatManager ChatManager = new ChatManager();
|
||||
|
||||
public bool IsSinglePlayer { get; private set; }
|
||||
|
||||
|
||||
private bool _toggleOpen = true;
|
||||
public bool ToggleOpen
|
||||
{
|
||||
get { return _toggleOpen; }
|
||||
set
|
||||
{
|
||||
_toggleOpen = PreferChatBoxOpen = value;
|
||||
if (value) { hideableElements.Visible = true; }
|
||||
}
|
||||
get => _toggleOpen;
|
||||
set => SetToggleOpenState(value, setPreference: true);
|
||||
}
|
||||
|
||||
public static ChatBox GetChatBox()
|
||||
{
|
||||
if (GameMain.GameSession?.GameMode is not GameMode gameMode) { return null; }
|
||||
return gameMode.IsSinglePlayer ? GameMain.GameSession.CrewManager?.ChatBox : GameMain.Client?.ChatBox;
|
||||
}
|
||||
|
||||
public static void AutoHideChatBox() => SetChatBoxOpen(false);
|
||||
|
||||
private void SetToggleOpenState(bool value, bool setPreference = true)
|
||||
{
|
||||
_toggleOpen = value;
|
||||
if (setPreference)
|
||||
{
|
||||
PreferChatBoxOpen = value;
|
||||
}
|
||||
if (value) { hideableElements.Visible = true; }
|
||||
}
|
||||
|
||||
public static void ResetChatBoxOpenState() => GetChatBox()?.ResetOpenState();
|
||||
|
||||
public void ResetOpenState() => SetOpen(PreferChatBoxOpen);
|
||||
|
||||
private static void SetChatBoxOpen(bool isOpen) => GetChatBox()?.SetOpen(isOpen);
|
||||
|
||||
private void SetOpen(bool value) => SetToggleOpenState(value, setPreference: false);
|
||||
|
||||
private float openState;
|
||||
|
||||
public static bool PreferChatBoxOpen = true;
|
||||
@@ -199,7 +222,7 @@ namespace Barotrauma
|
||||
if (channelMemPending)
|
||||
{
|
||||
int.TryParse(channelText.Text, out int newChannel);
|
||||
radio.SetChannelMemory(index, newChannel);
|
||||
SetChannelMemory(index, newChannel);
|
||||
btn.ToolTip = TextManager.GetWithVariables("radiochannelpreset",
|
||||
("[index]", index.ToString()),
|
||||
("[channel]", radio.GetChannelMemory(index).ToString()));
|
||||
@@ -330,7 +353,7 @@ namespace Barotrauma
|
||||
};
|
||||
|
||||
showNewMessagesButton.Visible = false;
|
||||
ToggleOpen = PreferChatBoxOpen = GameSettings.CurrentConfig.ChatOpen;
|
||||
SetToggleOpenState(GameSettings.CurrentConfig.ChatOpen, setPreference: true);
|
||||
}
|
||||
|
||||
public void Toggle()
|
||||
@@ -802,6 +825,15 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void SetChannelMemory(int index, int channel)
|
||||
{
|
||||
if (Character.Controlled != null && ChatMessage.CanUseRadio(Character.Controlled, out WifiComponent radio))
|
||||
{
|
||||
radio.SetChannelMemory(index, channel);
|
||||
radio.Item.CreateClientEvent(radio);
|
||||
}
|
||||
}
|
||||
|
||||
public void ApplySelectionInputs() => ApplySelectionInputs(InputBox, true, ChatKeyStates.GetChatKeyStates());
|
||||
|
||||
|
||||
@@ -11,13 +11,14 @@ internal class DeathPrompt
|
||||
{
|
||||
private static CoroutineHandle? createPromptCoroutine;
|
||||
|
||||
private GUIFrame? deathPromptFrame;
|
||||
private GUIComponent? skillPanel;
|
||||
private GUIComponent? newCharacterPanel;
|
||||
private GUIComponent? takeOverBotPanel;
|
||||
|
||||
private GUIComponent? content;
|
||||
|
||||
public static GUIComponent? takeOverBotPanelFrame;
|
||||
|
||||
private static GUIComponent? takeOverBotPanelFrame;
|
||||
|
||||
/// <summary>
|
||||
/// Private constructor, because these should only be created using the Show method
|
||||
@@ -73,11 +74,11 @@ internal class DeathPrompt
|
||||
foreground.FadeIn(wait: 0, duration: 5.0f);
|
||||
foreground.Pulsate(startScale: Vector2.One, Vector2.One * 0.8f, duration: 25.0f);
|
||||
|
||||
var frame = new GUIFrame(new RectTransform(new Vector2(0.3f, 0.3f), background.RectTransform, Anchor.Center))
|
||||
deathPromptFrame = new GUIFrame(new RectTransform(new Vector2(0.3f, 0.3f), background.RectTransform, Anchor.Center))
|
||||
{
|
||||
UserData = this
|
||||
};
|
||||
frame.FadeIn(wait: 0, duration: FadeInDuration);
|
||||
deathPromptFrame.FadeIn(wait: 0, duration: FadeInDuration);
|
||||
|
||||
new GUITextBlock(new RectTransform(new Vector2(0.5f, 0.1f), background.RectTransform, Anchor.TopCenter) { RelativeOffset = new Vector2(0.0f, 0.2f) }, string.Empty, font: GUIStyle.LargeFont, textAlignment: Alignment.TopCenter)
|
||||
{
|
||||
@@ -90,7 +91,7 @@ internal class DeathPrompt
|
||||
}
|
||||
};
|
||||
|
||||
var content = new GUILayoutGroup(new RectTransform(new Vector2(0.8f, 0.8f), frame.RectTransform, Anchor.Center))
|
||||
var content = new GUILayoutGroup(new RectTransform(new Vector2(0.8f, 0.8f), deathPromptFrame.RectTransform, Anchor.Center))
|
||||
{
|
||||
Stretch = true,
|
||||
RelativeSpacing = 0.05f
|
||||
@@ -188,7 +189,7 @@ internal class DeathPrompt
|
||||
{
|
||||
if (takeOverBotPanel == null)
|
||||
{
|
||||
CreateTakeOverBotPanel(frame, this);
|
||||
CreateTakeOverBotPanel(deathPromptFrame, this);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -202,7 +203,7 @@ internal class DeathPrompt
|
||||
}
|
||||
else
|
||||
{
|
||||
new GUIButton(new RectTransform(new Vector2(1.0f, 1.0f), buttonContainerRight.RectTransform), TextManager.Get("deathprompt.respawnnow"))
|
||||
var respawnNowButton = new GUIButton(new RectTransform(new Vector2(1.0f, 1.0f), buttonContainerRight.RectTransform), TextManager.Get("deathprompt.respawnnow"))
|
||||
{
|
||||
OnClicked = (btn, userdata) =>
|
||||
{
|
||||
@@ -211,7 +212,13 @@ internal class DeathPrompt
|
||||
return true;
|
||||
},
|
||||
Enabled = GameMain.NetworkMember is { ServerSettings.RespawnMode: RespawnMode.MidRound }
|
||||
}.FadeIn(wait: FadeInInterval * 4, duration: FadeInDuration, alsoChildren: true);
|
||||
};
|
||||
if (GameMain.NetworkMember is { ServerSettings.RespawnMode: RespawnMode.BetweenRounds })
|
||||
{
|
||||
respawnNowButton.ToolTip = TextManager.Get("respawnnotavailable.respawnmode.betweenrounds");
|
||||
}
|
||||
|
||||
respawnNowButton.FadeIn(wait: FadeInInterval * 4, duration: FadeInDuration, alsoChildren: true);
|
||||
}
|
||||
|
||||
//"info buttons" at the bottom
|
||||
@@ -249,7 +256,7 @@ internal class DeathPrompt
|
||||
{
|
||||
if (skillPanel == null)
|
||||
{
|
||||
CreateSkillPanel(frame, GameMain.Client?.Character?.Info ?? GameMain.Client?.CharacterInfo);
|
||||
CreateSkillPanel(deathPromptFrame, GameMain.Client?.Character?.Info ?? GameMain.Client?.CharacterInfo);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -266,7 +273,7 @@ internal class DeathPrompt
|
||||
{
|
||||
if (newCharacterPanel == null)
|
||||
{
|
||||
CreateNewCharacterPanel(frame);
|
||||
CreateNewCharacterPanel(deathPromptFrame);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -279,15 +286,6 @@ internal class DeathPrompt
|
||||
}
|
||||
}
|
||||
|
||||
//TODO
|
||||
/*new GUIButton(new RectTransform(new Vector2(0.4f, 1.0f), infoButtonContainer.RectTransform), "Respawn settings", style: "GUIButtonSmall")
|
||||
{
|
||||
OnClicked = (btn, userdata) =>
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}.FadeIn(wait: FadeInInterval * 5, duration: FadeInDuration, alsoChildren: true);*/
|
||||
|
||||
this.content = background;
|
||||
}
|
||||
|
||||
@@ -382,8 +380,10 @@ internal class DeathPrompt
|
||||
{
|
||||
OnClicked = (btn, userdata) =>
|
||||
{
|
||||
GameMain.NetLobbyScreen.TryDiscardCampaignCharacter(onYes: () =>
|
||||
{
|
||||
GameMain.NetLobbyScreen.TryDiscardCampaignCharacter(onYes: () =>
|
||||
{
|
||||
GameMain.Client?.SendCharacterInfo(GameMain.Client.PendingName);
|
||||
GameMain.NetLobbyScreen.CampaignCharacterDiscarded = false;
|
||||
frame.Parent?.RemoveChild(frame);
|
||||
newCharacterPanel = null;
|
||||
});
|
||||
@@ -465,6 +465,11 @@ internal class DeathPrompt
|
||||
{
|
||||
if (botList.SelectedData is CharacterInfo selectedCharacter && GameMain.Client is GameClient client)
|
||||
{
|
||||
if (!GetAvailableBots().Contains(selectedCharacter)) // Someone may have taken over the bot while the list was open, etc
|
||||
{
|
||||
CreateTakeOverBotPanel(frame, deathPrompt); // Update
|
||||
return true;
|
||||
}
|
||||
client.SendTakeOverBotRequest(selectedCharacter);
|
||||
GUIMessageBox.MessageBoxes.Remove(frame.Parent);
|
||||
deathPrompt?.Close();
|
||||
@@ -484,15 +489,26 @@ internal class DeathPrompt
|
||||
return frame;
|
||||
}
|
||||
|
||||
public void UpdateBotList()
|
||||
{
|
||||
if (deathPromptFrame != null && takeOverBotPanelFrame != null)
|
||||
{
|
||||
CloseBotPanel();
|
||||
CreateTakeOverBotPanel(deathPromptFrame, deathPrompt: this);
|
||||
}
|
||||
}
|
||||
|
||||
private static IEnumerable<CharacterInfo> GetAvailableBots()
|
||||
{
|
||||
if (GameMain.GameSession?.CrewManager is { } crewManager)
|
||||
{
|
||||
return crewManager.GetCharacterInfos().Where(c =>
|
||||
/*either an alive bot */
|
||||
c is { Character.IsBot: true, Character.IsDead: false } ||
|
||||
/* or a newly hired bot that hasn't spawned yet */
|
||||
(c.IsNewHire && c.Character == null));
|
||||
return crewManager.GetCharacterInfos(includeReserveBench: true).Where(c =>
|
||||
// a bot on reserve bench
|
||||
c.IsOnReserveBench ||
|
||||
// an alive bot
|
||||
(c.Character != null && c.Character is { IsBot: true, IsDead: false }) ||
|
||||
// a newly hired bot that hasn't spawned yet
|
||||
(c.Character == null && c.IsNewHire));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -106,12 +106,35 @@ namespace Barotrauma
|
||||
public static float VerticalAspectRatio => GameMain.GraphicsHeight / (float)GameMain.GraphicsWidth;
|
||||
public static float RelativeHorizontalAspectRatio => HorizontalAspectRatio / (ReferenceResolution.X / ReferenceResolution.Y);
|
||||
public static float RelativeVerticalAspectRatio => VerticalAspectRatio / (ReferenceResolution.Y / ReferenceResolution.X);
|
||||
|
||||
/// <summary>
|
||||
/// Returns the difference of the current aspect ratio to the reference aspect ratio (16:9).
|
||||
/// E.g. if the aspect ratio is 16:9, returns 0; if it's 4:3, returns 0.444; if the aspect ratio is 12:5, returns -0.623.
|
||||
/// </summary>
|
||||
public static float AspectRatioDifference
|
||||
{
|
||||
get
|
||||
{
|
||||
// ~ 1.777
|
||||
float referenceAspectRatio = ReferenceResolution.X / ReferenceResolution.Y;
|
||||
float aspectRatioDifference = referenceAspectRatio - HorizontalAspectRatio;
|
||||
if (MathUtils.NearlyEqual(aspectRatioDifference, 0))
|
||||
{
|
||||
// Handle possible rounding errors, so that we can trust that this returns 0 when the aspect ratio matches the reference aspect ratio.
|
||||
return 0;
|
||||
}
|
||||
return aspectRatioDifference;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A horizontal scaling factor for low aspect ratios (small width relative to height)
|
||||
/// </summary>
|
||||
public static float AspectRatioAdjustment => HorizontalAspectRatio < 1.4f ? (1.0f - (1.4f - HorizontalAspectRatio)) : 1.0f;
|
||||
|
||||
public static bool IsUltrawide => HorizontalAspectRatio > 2.3f;
|
||||
|
||||
public static bool IsHUDScaled => GameSettings.CurrentConfig.Graphics.HUDScale > 1 || GameSettings.CurrentConfig.Graphics.InventoryScale > 1;
|
||||
|
||||
public static int UIWidth
|
||||
{
|
||||
@@ -625,9 +648,13 @@ namespace Barotrauma
|
||||
|
||||
DrawMessages(spriteBatch, cam);
|
||||
|
||||
if (MouseOn != null && !MouseOn.ToolTip.IsNullOrWhiteSpace())
|
||||
{
|
||||
MouseOn.DrawToolTip(spriteBatch);
|
||||
if (MouseOn != null)
|
||||
{
|
||||
if (!MouseOn.ToolTip.IsNullOrWhiteSpace())
|
||||
{
|
||||
MouseOn.DrawToolTip(spriteBatch);
|
||||
}
|
||||
MouseOn.OnDrawToolTip?.Invoke(MouseOn);
|
||||
}
|
||||
|
||||
if (SubEditorScreen.IsSubEditor())
|
||||
@@ -884,6 +911,11 @@ namespace Barotrauma
|
||||
PauseMenu.AddToGUIUpdateList();
|
||||
}
|
||||
|
||||
foreach (var openAccordion in GUIComponent.OpenAccordionPopups)
|
||||
{
|
||||
openAccordion.AddToGUIUpdateList(order: 1);
|
||||
}
|
||||
|
||||
SocialOverlay.Instance?.AddToGuiUpdateList();
|
||||
|
||||
GUIContextMenu.AddActiveToGUIUpdateList();
|
||||
@@ -2495,7 +2527,12 @@ namespace Barotrauma
|
||||
{
|
||||
IgnoreLayoutGroups = true,
|
||||
ToolTip = TextManager.Get("bugreportbutton") + $" (v{GameMain.Version})",
|
||||
OnClicked = (btn, userdata) => { GameMain.Instance.ShowBugReporter(); return true; }
|
||||
OnClicked = (btn, userdata) =>
|
||||
{
|
||||
if (PauseMenuOpen) { TogglePauseMenu(); }
|
||||
GameMain.Instance.ShowBugReporter();
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
CreateButton("PauseMenuResume", buttonContainer, null);
|
||||
@@ -2531,23 +2568,37 @@ namespace Barotrauma
|
||||
GameMain.GameSession?.EndRound("");
|
||||
});
|
||||
}
|
||||
else if (!GameMain.GameSession.GameMode.IsSinglePlayer && GameMain.Client != null && GameMain.Client.HasPermission(ClientPermissions.ManageRound))
|
||||
else if (!GameMain.GameSession.GameMode.IsSinglePlayer && GameMain.Client != null)
|
||||
{
|
||||
bool canSave = GameMain.GameSession.GameMode is CampaignMode && IsFriendlyOutpostLevel();
|
||||
if (canSave)
|
||||
//server owner (host) can't return to the lobby without ending the round for everyone
|
||||
if (!GameMain.Client.IsServerOwner)
|
||||
{
|
||||
CreateButton("PauseMenuSaveQuit", buttonContainer, verificationTextTag: "PauseMenuSaveAndReturnToServerLobbyVerification", action: () =>
|
||||
{
|
||||
GameMain.Client?.RequestRoundEnd(save: true);
|
||||
});
|
||||
CreateButton("ReturnToServerlobby", buttonContainer,
|
||||
verificationTextTag: "PauseMenuReturnToServerLobbyVerificationSelf",
|
||||
action: () =>
|
||||
{
|
||||
GameMain.Client?.EndRoundForSelf();
|
||||
});
|
||||
}
|
||||
|
||||
CreateButton(GameMain.GameSession.GameMode is CampaignMode ? "ReturnToServerlobby" : "EndRound", buttonContainer,
|
||||
verificationTextTag: GameMain.GameSession.GameMode is CampaignMode ? "PauseMenuReturnToServerLobbyVerification" : "EndRoundSubNotAtLevelEnd",
|
||||
action: () =>
|
||||
if (GameMain.Client.HasPermission(ClientPermissions.ManageRound))
|
||||
{
|
||||
bool canSave = GameMain.GameSession.GameMode is CampaignMode && IsFriendlyOutpostLevel();
|
||||
if (canSave)
|
||||
{
|
||||
GameMain.Client?.RequestRoundEnd(save: false);
|
||||
});
|
||||
CreateButton("PauseMenuSaveQuit", buttonContainer, verificationTextTag: "PauseMenuSaveAndReturnToServerLobbyVerification", action: () =>
|
||||
{
|
||||
GameMain.Client?.RequestEndRound(save: true);
|
||||
}, color: GUIStyle.Red);
|
||||
}
|
||||
|
||||
CreateButton("EndRound", buttonContainer,
|
||||
verificationTextTag: GameMain.GameSession.GameMode is CampaignMode ? "PauseMenuReturnToServerLobbyVerification" : "EndRoundSubNotAtLevelEnd",
|
||||
action: () =>
|
||||
{
|
||||
GameMain.Client?.RequestEndRound(save: false);
|
||||
}, color: GUIStyle.Red);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2575,9 +2626,9 @@ namespace Barotrauma
|
||||
|
||||
}
|
||||
|
||||
void CreateButton(string textTag, GUIComponent parent, Action action, string verificationTextTag = null)
|
||||
void CreateButton(string textTag, GUIComponent parent, Action action, string verificationTextTag = null, Color? color = null)
|
||||
{
|
||||
new GUIButton(new RectTransform(new Vector2(1.0f, 0.1f), parent.RectTransform), TextManager.Get(textTag))
|
||||
var button = new GUIButton(new RectTransform(new Vector2(1.0f, 0.1f), parent.RectTransform), TextManager.Get(textTag))
|
||||
{
|
||||
OnClicked = (btn, userData) =>
|
||||
{
|
||||
@@ -2593,25 +2644,29 @@ namespace Barotrauma
|
||||
return true;
|
||||
}
|
||||
};
|
||||
if (color.HasValue)
|
||||
{
|
||||
button.Color = color.Value;
|
||||
}
|
||||
}
|
||||
|
||||
void CreateVerificationPrompt(string textTag, Action confirmAction)
|
||||
}
|
||||
public static void CreateVerificationPrompt(string textTag, Action confirmAction)
|
||||
{
|
||||
var msgBox = new GUIMessageBox("", TextManager.Get(textTag),
|
||||
new LocalizedString[] { TextManager.Get("Yes"), TextManager.Get("No") })
|
||||
{
|
||||
var msgBox = new GUIMessageBox("", TextManager.Get(textTag),
|
||||
new LocalizedString[] { TextManager.Get("Yes"), TextManager.Get("No") })
|
||||
{
|
||||
UserData = "verificationprompt",
|
||||
DrawOnTop = true
|
||||
};
|
||||
msgBox.Buttons[0].OnClicked = (_, __) =>
|
||||
{
|
||||
PauseMenuOpen = false;
|
||||
confirmAction?.Invoke();
|
||||
return true;
|
||||
};
|
||||
msgBox.Buttons[0].OnClicked += msgBox.Close;
|
||||
msgBox.Buttons[1].OnClicked += msgBox.Close;
|
||||
}
|
||||
UserData = "verificationprompt",
|
||||
DrawOnTop = true
|
||||
};
|
||||
msgBox.Buttons[0].OnClicked = (_, __) =>
|
||||
{
|
||||
PauseMenuOpen = false;
|
||||
confirmAction?.Invoke();
|
||||
return true;
|
||||
};
|
||||
msgBox.Buttons[0].OnClicked += msgBox.Close;
|
||||
msgBox.Buttons[1].OnClicked += msgBox.Close;
|
||||
}
|
||||
|
||||
private static bool TogglePauseMenu(GUIButton button, object obj)
|
||||
@@ -2697,12 +2752,6 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public static bool IsFourByThree()
|
||||
{
|
||||
float aspectRatio = HorizontalAspectRatio;
|
||||
return aspectRatio > 1.3f && aspectRatio < 1.4f;
|
||||
}
|
||||
|
||||
public static void SetSavingIndicatorState(bool enabled)
|
||||
{
|
||||
if (enabled)
|
||||
|
||||
@@ -9,6 +9,7 @@ using Barotrauma.IO;
|
||||
using RestSharp;
|
||||
using System.Net;
|
||||
using Barotrauma.Steam;
|
||||
using Steamworks;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
@@ -158,6 +159,12 @@ namespace Barotrauma
|
||||
|
||||
public Action<GUIComponent> OnAddedToGUIUpdateList;
|
||||
|
||||
/// <summary>
|
||||
/// Triggers when a tooltip should be draw on the component.
|
||||
/// Note that the callback triggers even if the item has no tooltip (which can be useful for e.g. only contructing the tooltip when needed).
|
||||
/// </summary>
|
||||
public Action<GUIComponent> OnDrawToolTip;
|
||||
|
||||
public enum ComponentState { None, Hover, Pressed, Selected, HoverSelected };
|
||||
|
||||
protected Alignment alignment;
|
||||
@@ -1120,7 +1127,7 @@ namespace Barotrauma
|
||||
component = LoadGUIImage(element, parent);
|
||||
break;
|
||||
case "accordion":
|
||||
return LoadAccordion(element, parent);
|
||||
return LoadAccordion(element, parent, openOnTop: element.GetAttributeBool("openontop", false));
|
||||
case "gridtext":
|
||||
LoadGridText(element, parent);
|
||||
return null;
|
||||
@@ -1138,6 +1145,21 @@ namespace Barotrauma
|
||||
FromXML(subElement, component is GUIListBox listBox ? listBox.Content.RectTransform : component.RectTransform);
|
||||
}
|
||||
|
||||
component.toolTip = element.GetAttributeString("tooltip", string.Empty);
|
||||
|
||||
GUITextBlock textBlock = component as GUITextBlock ?? (component as GUIButton)?.TextBlock;
|
||||
if (textBlock != null)
|
||||
{
|
||||
if (element.GetAttributeBool("autoscalevertical", false))
|
||||
{
|
||||
textBlock.AutoScaleVertical = true;
|
||||
}
|
||||
if (element.GetAttributeBool("autoscalehorizontal", false))
|
||||
{
|
||||
textBlock.AutoScaleHorizontal = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (element.GetAttributeBool("resizetofitchildren", false))
|
||||
{
|
||||
Vector2 relativeResizeScale = element.GetAttributeVector2("relativeresizescale", Vector2.One);
|
||||
@@ -1180,7 +1202,8 @@ namespace Barotrauma
|
||||
{
|
||||
foreach (XAttribute attribute in element.Attributes())
|
||||
{
|
||||
switch (attribute.Name.ToString().ToLowerInvariant())
|
||||
string conditionName = attribute.Name.ToString().ToLowerInvariant();
|
||||
switch (conditionName)
|
||||
{
|
||||
case "language":
|
||||
var languages = element.GetAttributeIdentifierArray(attribute.Name.ToString(), Array.Empty<Identifier>())
|
||||
@@ -1199,6 +1222,10 @@ namespace Barotrauma
|
||||
var maxVersion = new Version(attribute.Value);
|
||||
if (GameMain.Version > maxVersion) { return false; }
|
||||
break;
|
||||
case "identifierdismissed":
|
||||
Identifier identifier = element.GetAttributeIdentifier(attribute.Name.ToString(), Identifier.Empty);
|
||||
if (MainMenuScreen.DismissedNotifications.Contains(identifier)) { return false; }
|
||||
break;
|
||||
case "buildconfiguration":
|
||||
switch (attribute.Value.ToString().ToLowerInvariant())
|
||||
{
|
||||
@@ -1222,6 +1249,20 @@ namespace Barotrauma
|
||||
#endif
|
||||
}
|
||||
return false;
|
||||
case "mingamelaunches":
|
||||
if (int.TryParse(attribute.Value, out int minLaunches))
|
||||
{
|
||||
return SteamManager.GetStatInt(AchievementStat.GameLaunchCount) > minLaunches;
|
||||
}
|
||||
return false;
|
||||
case "appsubscribed":
|
||||
case "appnotsubscribed":
|
||||
if (SteamManager.IsInitialized &&
|
||||
int.TryParse(attribute.Value, out int appId))
|
||||
{
|
||||
return SteamApps.IsSubscribedToApp(appId) == (conditionName == "appsubscribed");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1262,12 +1303,18 @@ namespace Barotrauma
|
||||
|
||||
private static GUIButton LoadLink(XElement element, RectTransform parent)
|
||||
{
|
||||
Identifier identifier = element.GetAttributeIdentifier("identifier", Identifier.Empty);
|
||||
|
||||
var button = LoadGUIButton(element, parent);
|
||||
string url = element.GetAttributeString("url", "");
|
||||
button.OnClicked = (btn, userdata) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!identifier.IsEmpty)
|
||||
{
|
||||
MainMenuScreen.AddDismissedNotification(identifier);
|
||||
}
|
||||
if (SteamManager.IsInitialized)
|
||||
{
|
||||
SteamManager.OverlayCustomUrl(url);
|
||||
@@ -1324,6 +1371,8 @@ namespace Barotrauma
|
||||
|
||||
private static GUIButton LoadGUIButton(XElement element, RectTransform parent)
|
||||
{
|
||||
Identifier identifier = element.GetAttributeIdentifier("identifier", Identifier.Empty);
|
||||
|
||||
string style = element.GetAttributeString("style", "");
|
||||
if (style == "null") { style = null; }
|
||||
|
||||
@@ -1335,10 +1384,19 @@ namespace Barotrauma
|
||||
element.GetAttributeString("text", "");
|
||||
text = text.Replace(@"\n", "\n");
|
||||
|
||||
return new GUIButton(RectTransform.Load(element, parent),
|
||||
var button = new GUIButton(RectTransform.Load(element, parent),
|
||||
text: text,
|
||||
textAlignment: textAlignment,
|
||||
style: style);
|
||||
button.OnClicked = (btn, userdata) =>
|
||||
{
|
||||
if (!identifier.IsEmpty)
|
||||
{
|
||||
MainMenuScreen.AddDismissedNotification(identifier);
|
||||
}
|
||||
return true;
|
||||
};
|
||||
return button;
|
||||
}
|
||||
|
||||
private static GUIListBox LoadGUIListBox(XElement element, RectTransform parent)
|
||||
@@ -1391,11 +1449,14 @@ namespace Barotrauma
|
||||
{
|
||||
sprite = new Sprite(element);
|
||||
}
|
||||
|
||||
return new GUIImage(RectTransform.Load(element, parent), sprite, scaleToFit: true);
|
||||
var scaleToFit = element.GetAttributeEnum("scaletofit", GUIImage.ScalingMode.ScaleToFitSmallestExtent);
|
||||
return new GUIImage(RectTransform.Load(element, parent), sprite, scaleToFit: scaleToFit);
|
||||
}
|
||||
|
||||
private static GUIButton LoadAccordion(ContentXElement element, RectTransform parent)
|
||||
public static readonly List<GUIComponent> OpenAccordionPopups = new List<GUIComponent>();
|
||||
|
||||
/// <param name="openOnTop">Should the contents of the accordion be forced to open on top of other UI elements?</param>
|
||||
private static GUIButton LoadAccordion(ContentXElement element, RectTransform parent, bool openOnTop)
|
||||
{
|
||||
var button = LoadGUIButton(element, parent);
|
||||
List<GUIComponent> content = new List<GUIComponent>();
|
||||
@@ -1407,6 +1468,7 @@ namespace Barotrauma
|
||||
contentElement.Visible = false;
|
||||
contentElement.IgnoreLayoutGroups = true;
|
||||
content.Add(contentElement);
|
||||
contentElement.UserData = (contentElement.RectTransform.Anchor, contentElement.RectTransform.Pivot);
|
||||
}
|
||||
}
|
||||
button.OnClicked = (btn, userdata) =>
|
||||
@@ -1414,8 +1476,32 @@ namespace Barotrauma
|
||||
bool visible = content.FirstOrDefault()?.Visible ?? true;
|
||||
foreach (GUIComponent contentElement in content)
|
||||
{
|
||||
contentElement.Visible = !visible;
|
||||
contentElement.IgnoreLayoutGroups = !contentElement.Visible;
|
||||
if (openOnTop)
|
||||
{
|
||||
contentElement.rectTransform.Parent = null;
|
||||
//the element is drawn in screen space over anything (no longer a child of the original parent),
|
||||
//we need to calculate the screen space position manually
|
||||
contentElement.rectTransform.SetPosition(Anchor.TopLeft);
|
||||
(Anchor anchor, Pivot pivot) = ((Anchor anchor, Pivot pivot))contentElement.UserData;
|
||||
contentElement.rectTransform.ScreenSpaceOffset =
|
||||
RectTransform.CalculateAnchorPoint(anchor, button.Rect) +
|
||||
RectTransform.CalculatePivotOffset(pivot, contentElement.Rect.Size);
|
||||
contentElement.Visible = true;
|
||||
if (OpenAccordionPopups.Contains(contentElement))
|
||||
{
|
||||
OpenAccordionPopups.Remove(contentElement);
|
||||
}
|
||||
else
|
||||
{
|
||||
OpenAccordionPopups.Clear();
|
||||
OpenAccordionPopups.Add(contentElement);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
contentElement.Visible = !visible;
|
||||
contentElement.IgnoreLayoutGroups = !contentElement.Visible;
|
||||
}
|
||||
}
|
||||
if (button.Parent is GUILayoutGroup layoutGroup)
|
||||
{
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Barotrauma
|
||||
@@ -14,6 +13,24 @@ namespace Barotrauma
|
||||
|
||||
private static bool loadingTextures;
|
||||
|
||||
public enum ScalingMode
|
||||
{
|
||||
/// <summary>
|
||||
/// No automatic scaling, the image is drawn using <see cref="Scale"/>
|
||||
/// </summary>
|
||||
None,
|
||||
/// <summary>
|
||||
/// Automatically scales the image so it fits the smallest extent of the component
|
||||
/// (leaving empty space around the image if its aspect ratio is different than that of the GUIImage)
|
||||
/// </summary>
|
||||
ScaleToFitSmallestExtent,
|
||||
/// <summary>
|
||||
/// Automatically scales the image so it fits the largest extent of the component,
|
||||
/// cutting out the parts that go outside the bounds of the component.
|
||||
/// </summary>
|
||||
ScaleToFitLargestExtent,
|
||||
}
|
||||
|
||||
public static bool LoadingTextures
|
||||
{
|
||||
get
|
||||
@@ -30,7 +47,7 @@ namespace Barotrauma
|
||||
|
||||
private bool crop;
|
||||
|
||||
private readonly bool scaleToFit;
|
||||
private readonly ScalingMode scaleToFit;
|
||||
|
||||
private bool lazyLoaded, loading;
|
||||
|
||||
@@ -89,7 +106,7 @@ namespace Barotrauma
|
||||
sprite = value;
|
||||
sourceRect = value == null ? Rectangle.Empty : value.SourceRect;
|
||||
origin = value == null ? Vector2.Zero : value.size / 2;
|
||||
if (scaleToFit) { RecalculateScale(); }
|
||||
if (scaleToFit != ScalingMode.None) { RecalculateScale(); }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,17 +114,27 @@ namespace Barotrauma
|
||||
|
||||
public ComponentState? OverrideState = null;
|
||||
|
||||
public GUIImage(RectTransform rectT, string style, bool scaleToFit = false)
|
||||
public GUIImage(RectTransform rectT, string style, bool scaleToFit)
|
||||
: this(rectT, null, null, scaleToFit ? ScalingMode.ScaleToFitSmallestExtent : ScalingMode.None, style)
|
||||
{
|
||||
}
|
||||
|
||||
public GUIImage(RectTransform rectT, string style, ScalingMode scaleToFit = ScalingMode.None)
|
||||
: this(rectT, null, null, scaleToFit, style)
|
||||
{
|
||||
}
|
||||
|
||||
public GUIImage(RectTransform rectT, Sprite sprite, Rectangle? sourceRect = null, bool scaleToFit = false)
|
||||
public GUIImage(RectTransform rectT, Sprite sprite, bool scaleToFit, Rectangle? sourceRect = null)
|
||||
: this(rectT, sprite, sourceRect, scaleToFit ? ScalingMode.ScaleToFitSmallestExtent : ScalingMode.None, null)
|
||||
{
|
||||
}
|
||||
|
||||
public GUIImage(RectTransform rectT, Sprite sprite, Rectangle? sourceRect = null, ScalingMode scaleToFit = ScalingMode.None)
|
||||
: this(rectT, sprite, sourceRect, scaleToFit, null)
|
||||
{
|
||||
}
|
||||
|
||||
private GUIImage(RectTransform rectT, Sprite sprite, Rectangle? sourceRect, bool scaleToFit, string style) : base(style, rectT)
|
||||
private GUIImage(RectTransform rectT, Sprite sprite, Rectangle? sourceRect, ScalingMode scaleToFit, string style) : base(style, rectT)
|
||||
{
|
||||
this.scaleToFit = scaleToFit;
|
||||
Sprite = sprite;
|
||||
@@ -123,7 +150,7 @@ namespace Barotrauma
|
||||
{
|
||||
color = hoverColor = selectedColor = pressedColor = disabledColor = Color.White;
|
||||
}
|
||||
if (!scaleToFit)
|
||||
if (scaleToFit == ScalingMode.None)
|
||||
{
|
||||
Scale = 1.0f;
|
||||
}
|
||||
@@ -176,9 +203,11 @@ namespace Barotrauma
|
||||
|
||||
Color currentColor = GetColor(State);
|
||||
|
||||
if (BlendState != null)
|
||||
Rectangle prevScissorRect = spriteBatch.GraphicsDevice.ScissorRectangle;
|
||||
if (BlendState != null || scaleToFit == ScalingMode.ScaleToFitLargestExtent)
|
||||
{
|
||||
spriteBatch.End();
|
||||
spriteBatch.GraphicsDevice.ScissorRectangle = Rectangle.Intersect(prevScissorRect, Rect);
|
||||
spriteBatch.Begin(blendState: BlendState, samplerState: GUI.SamplerState, rasterizerState: GameMain.ScissorTestEnable);
|
||||
}
|
||||
|
||||
@@ -205,9 +234,10 @@ namespace Barotrauma
|
||||
Scale, SpriteEffects, 0.0f);
|
||||
}
|
||||
|
||||
if (BlendState != null)
|
||||
if (BlendState != null || scaleToFit == ScalingMode.ScaleToFitLargestExtent)
|
||||
{
|
||||
spriteBatch.End();
|
||||
spriteBatch.GraphicsDevice.ScissorRectangle = prevScissorRect;
|
||||
spriteBatch.Begin(SpriteSortMode.Deferred, samplerState: GUI.SamplerState, rasterizerState: GameMain.ScissorTestEnable);
|
||||
}
|
||||
}
|
||||
@@ -219,9 +249,18 @@ namespace Barotrauma
|
||||
sourceRect = sprite.SourceRect;
|
||||
}
|
||||
|
||||
Scale = sprite == null || sprite.SourceRect.Width == 0 || sprite.SourceRect.Height == 0 ?
|
||||
1.0f :
|
||||
Math.Min(RectTransform.Rect.Width / (float)sprite.SourceRect.Width, RectTransform.Rect.Height / (float)sprite.SourceRect.Height);
|
||||
if (sprite == null || sprite.SourceRect.Width == 0 || sprite.SourceRect.Height == 0)
|
||||
{
|
||||
Scale = 1.0f;
|
||||
}
|
||||
else if (scaleToFit == ScalingMode.ScaleToFitLargestExtent)
|
||||
{
|
||||
Scale = Math.Max(RectTransform.Rect.Width / (float)sprite.SourceRect.Width, RectTransform.Rect.Height / (float)sprite.SourceRect.Height);
|
||||
}
|
||||
else
|
||||
{
|
||||
Scale = Math.Min(RectTransform.Rect.Width / (float)sprite.SourceRect.Width, RectTransform.Rect.Height / (float)sprite.SourceRect.Height);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<bool> LoadTextureAsync()
|
||||
|
||||
@@ -1030,7 +1030,7 @@ namespace Barotrauma
|
||||
while (index < Content.CountChildren)
|
||||
{
|
||||
GUIComponent child = Content.GetChild(index);
|
||||
if (child.Visible)
|
||||
if (child.Visible && child.CanBeFocused)
|
||||
{
|
||||
Select(index, force, GetAutoScroll(!SmoothScroll && autoScroll == AutoScroll.Enabled), takeKeyBoardFocus, playSelectSound);
|
||||
if (SmoothScroll)
|
||||
@@ -1049,7 +1049,7 @@ namespace Barotrauma
|
||||
while (index >= 0)
|
||||
{
|
||||
GUIComponent child = Content.GetChild(index);
|
||||
if (child.Visible)
|
||||
if (child.Visible && child.CanBeFocused)
|
||||
{
|
||||
Select(index, force, GetAutoScroll(!SmoothScroll && autoScroll == AutoScroll.Enabled), takeKeyBoardFocus, playSelectSound);
|
||||
if (SmoothScroll)
|
||||
|
||||
@@ -289,7 +289,7 @@ namespace Barotrauma
|
||||
GUIStyle.Apply(Text, "", this);
|
||||
Content.Recalculate();
|
||||
Text.RectTransform.NonScaledSize = Text.RectTransform.MinSize = Text.RectTransform.MaxSize =
|
||||
new Point(Text.Rect.Width, Text.Rect.Height);
|
||||
new Point(Text.Rect.Width, Math.Min(Text.Rect.Height, GameMain.GraphicsHeight));
|
||||
Text.RectTransform.IsFixedSize = true;
|
||||
if (headerText.IsNullOrWhiteSpace())
|
||||
{
|
||||
|
||||
@@ -38,6 +38,8 @@ namespace Barotrauma
|
||||
private static bool ReplacingPermanentlyDeadCharacter =>
|
||||
GameMain.NetworkMember?.ServerSettings is { RespawnMode: RespawnMode.Permadeath, IronmanMode: false } &&
|
||||
GameMain.Client?.CharacterInfo is { PermanentlyDead: true };
|
||||
|
||||
private static bool ReserveBenchEnabled => GameMain.GameSession?.Campaign is MultiPlayerCampaign;
|
||||
|
||||
private bool hadPermissionToHire;
|
||||
private static bool HasPermissionToHire => ReplacingPermanentlyDeadCharacter ?
|
||||
@@ -277,13 +279,42 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
PendingHires?.ForEach(ci => AddPendingHire(ci));
|
||||
PendingHires?.ForEach(ci => AddPendingHire(ci, createNetworkMessage: false));
|
||||
}
|
||||
SetTotalHireCost();
|
||||
}
|
||||
UpdateCrew();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This will simply update each of the HR view lists (hireables, pending hires, and crew) from the most up to date information.
|
||||
/// It is a sane version of UpdateLocationView that won't break things even if used outside of whatever arbitrary conditions that one was made for.
|
||||
/// </summary>
|
||||
public void RefreshHRView()
|
||||
{
|
||||
if (campaign?.CurrentLocation is not Location currentLocation)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (characterPreviewFrame != null)
|
||||
{
|
||||
characterPreviewFrame.Parent?.RemoveChild(characterPreviewFrame);
|
||||
characterPreviewFrame = null;
|
||||
}
|
||||
|
||||
UpdateHireables(currentLocation);
|
||||
|
||||
if (pendingList != null)
|
||||
{
|
||||
pendingList.Content.ClearChildren();
|
||||
PendingHires?.ForEach(ci => AddPendingHire(ci, checkCrewSizeLimit: false, createNetworkMessage: false)); // don't check limits here, just display the data as it is
|
||||
SetTotalHireCost();
|
||||
}
|
||||
|
||||
UpdateCrew();
|
||||
}
|
||||
|
||||
public void UpdateHireables()
|
||||
{
|
||||
UpdateHireables(campaign?.CurrentLocation);
|
||||
@@ -329,10 +360,11 @@ namespace Barotrauma
|
||||
public void UpdateCrew()
|
||||
{
|
||||
crewList.Content.Children.ToList().ForEach(c => crewList.Content.RemoveChild(c));
|
||||
foreach (CharacterInfo c in GameMain.GameSession.CrewManager.GetCharacterInfos())
|
||||
foreach (CharacterInfo ci in GameMain.GameSession.CrewManager.GetCharacterInfos(includeReserveBench: true))
|
||||
{
|
||||
if (c == null || !((c.Character?.IsBot ?? true) || campaign is SinglePlayerCampaign)) { continue; }
|
||||
CreateCharacterFrame(c, crewList);
|
||||
// CrewManager is used to store info on all characters including players, but we only want bots in HR
|
||||
if (ci.Character != null && (ci.Character.IsRemotePlayer || !ci.Character.IsBot)) { continue; }
|
||||
CreateCharacterFrame(ci, crewList);
|
||||
}
|
||||
SortCharacters(crewList, SortingMethod.JobAsc);
|
||||
crewList.UpdateScrollBarSize();
|
||||
@@ -369,6 +401,10 @@ namespace Barotrauma
|
||||
((InfoSkill)x.GUIComponent.UserData).SkillLevel.CompareTo(((InfoSkill)y.GUIComponent.UserData).SkillLevel));
|
||||
if (sortingMethod == SortingMethod.SkillDesc) { list.Content.RectTransform.ReverseChildren(); }
|
||||
}
|
||||
|
||||
// Always apply this in the end to group by reserve bench status (does nothing if there are no reserve benched bots)
|
||||
list.Content.RectTransform.SortChildren((x, y) =>
|
||||
((InfoSkill)x.GUIComponent.UserData).CharacterInfo.BotStatus.CompareTo(((InfoSkill)y.GUIComponent.UserData).CharacterInfo.BotStatus));
|
||||
|
||||
int? CompareReputationRequirement(GUIComponent c1, GUIComponent c2)
|
||||
{
|
||||
@@ -401,6 +437,8 @@ namespace Barotrauma
|
||||
|
||||
public GUIComponent CreateCharacterFrame(CharacterInfo characterInfo, GUIListBox listBox, bool hideSalary = false)
|
||||
{
|
||||
string characterName = listBox == hireableList ? characterInfo.OriginalName : characterInfo.Name;
|
||||
|
||||
Skill skill = null;
|
||||
Color? jobColor = null;
|
||||
if (characterInfo.Job != null)
|
||||
@@ -415,6 +453,7 @@ namespace Barotrauma
|
||||
};
|
||||
GUILayoutGroup mainGroup = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.95f), frame.RectTransform, anchor: Anchor.Center), isHorizontal: true, childAnchor: Anchor.CenterLeft)
|
||||
{
|
||||
AbsoluteSpacing = 1,
|
||||
Stretch = true
|
||||
};
|
||||
|
||||
@@ -428,13 +467,15 @@ namespace Barotrauma
|
||||
GUILayoutGroup nameAndJobGroup = new GUILayoutGroup(new RectTransform(new Vector2(0.4f - portraitWidth, 0.8f), mainGroup.RectTransform)) { CanBeFocused = false };
|
||||
GUILayoutGroup nameGroup = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.5f), nameAndJobGroup.RectTransform), isHorizontal: true, childAnchor: Anchor.CenterLeft) { CanBeFocused = false };
|
||||
GUITextBlock nameBlock = new GUITextBlock(new RectTransform(Vector2.One, nameGroup.RectTransform),
|
||||
listBox == hireableList ? characterInfo.OriginalName : characterInfo.Name,
|
||||
characterName,
|
||||
textColor: jobColor, textAlignment: Alignment.BottomLeft)
|
||||
{
|
||||
CanBeFocused = false
|
||||
};
|
||||
nameBlock.Text = ToolBox.LimitString(nameBlock.Text, nameBlock.Font, nameBlock.Rect.Width);
|
||||
|
||||
const float smallColumnWidth = 0.6f / 3;
|
||||
const float skillColumnWidth = smallColumnWidth * 0.7f;
|
||||
const float buttonWidth = 0.12f;
|
||||
|
||||
GUITextBlock jobBlock = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.5f), nameAndJobGroup.RectTransform),
|
||||
characterInfo.Title ?? characterInfo.Job.Name, textColor: Color.White, font: GUIStyle.SmallFont, textAlignment: Alignment.TopLeft)
|
||||
{
|
||||
@@ -449,33 +490,28 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
var fullJobText = jobBlock.Text;
|
||||
jobBlock.Text = ToolBox.LimitString(fullJobText, jobBlock.Font, jobBlock.Rect.Width);
|
||||
if (jobBlock.Text != fullJobText)
|
||||
{
|
||||
jobBlock.ToolTip = fullJobText;
|
||||
jobBlock.CanBeFocused = true;
|
||||
}
|
||||
float width = 0.6f / 3;
|
||||
if (characterInfo.Job != null && skill != null)
|
||||
{
|
||||
GUILayoutGroup skillGroup = new GUILayoutGroup(new RectTransform(new Vector2(width, 0.6f), mainGroup.RectTransform), isHorizontal: true);
|
||||
GUILayoutGroup skillGroup = new GUILayoutGroup(new RectTransform(new Vector2(skillColumnWidth, 0.6f), mainGroup.RectTransform), isHorizontal: true);
|
||||
float iconWidth = (float)skillGroup.Rect.Height / skillGroup.Rect.Width;
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f - iconWidth, 1.0f), skillGroup.RectTransform), ((int)skill.Level).ToString(),
|
||||
textAlignment: Alignment.CenterRight)
|
||||
{
|
||||
Padding = Vector4.Zero,
|
||||
CanBeFocused = false
|
||||
};
|
||||
GUIImage skillIcon = new GUIImage(new RectTransform(Vector2.One, skillGroup.RectTransform, scaleBasis: ScaleBasis.Smallest), skill.Icon, scaleToFit: true)
|
||||
{
|
||||
CanBeFocused = false
|
||||
};
|
||||
if (jobColor.HasValue) { skillIcon.Color = jobColor.Value; }
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f - iconWidth, 1.0f), skillGroup.RectTransform), ((int)skill.Level).ToString(), textAlignment: Alignment.CenterLeft)
|
||||
{
|
||||
CanBeFocused = false
|
||||
};
|
||||
}
|
||||
|
||||
if (!hideSalary)
|
||||
{
|
||||
if (listBox != crewList)
|
||||
{
|
||||
new GUITextBlock(new RectTransform(new Vector2(width, 1.0f), mainGroup.RectTransform),
|
||||
new GUITextBlock(new RectTransform(new Vector2(smallColumnWidth, 1.0f), mainGroup.RectTransform),
|
||||
TextManager.FormatCurrency(ReplacingPermanentlyDeadCharacter ? campaign.NewCharacterCost(characterInfo) : HireManager.GetSalaryFor(characterInfo)),
|
||||
textAlignment: Alignment.Center)
|
||||
{
|
||||
@@ -485,19 +521,24 @@ namespace Barotrauma
|
||||
else
|
||||
{
|
||||
// Just a bit of padding to make list layouts similar
|
||||
new GUIFrame(new RectTransform(new Vector2(width, 1.0f), mainGroup.RectTransform), style: null) { CanBeFocused = false };
|
||||
new GUIFrame(new RectTransform(new Vector2(smallColumnWidth, 1.0f), mainGroup.RectTransform), style: null) { CanBeFocused = false };
|
||||
}
|
||||
}
|
||||
|
||||
if (listBox == hireableList)
|
||||
{
|
||||
var hireButton = new GUIButton(new RectTransform(new Vector2(width, 0.9f), mainGroup.RectTransform), style: "CrewManagementAddButton")
|
||||
var hireButton = new GUIButton(new RectTransform(new Vector2(buttonWidth, 0.9f), mainGroup.RectTransform), style: "CrewManagementAddButton")
|
||||
{
|
||||
ToolTip = TextManager.Get("hirebutton"),
|
||||
ToolTip = TextManager.Get(ReserveBenchEnabled ? "hirebutton.crew" : "hirebutton"),
|
||||
ClickSound = GUISoundType.Cart,
|
||||
UserData = characterInfo,
|
||||
Enabled = CanHire(characterInfo) && !ReplacingPermanentlyDeadCharacter,
|
||||
OnClicked = (b, o) => AddPendingHire(o as CharacterInfo)
|
||||
OnClicked = (b, o) =>
|
||||
{
|
||||
var currentCharacterInfo = (CharacterInfo)o;
|
||||
currentCharacterInfo.BotStatus = BotStatus.PendingHireToActiveService;
|
||||
return AddPendingHire(currentCharacterInfo);
|
||||
}
|
||||
};
|
||||
hireButton.OnAddedToGUIUpdateList += (GUIComponent btn) =>
|
||||
{
|
||||
@@ -505,7 +546,7 @@ namespace Barotrauma
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (PendingHires.Count + campaign.CrewManager.GetCharacterInfos().Count() >= CrewManager.MaxCrewSize)
|
||||
if (PendingHires.Count(ci => ci.BotStatus == BotStatus.PendingHireToActiveService) + campaign.CrewManager.GetCharacterInfos().Count() >= CrewManager.MaxCrewSize)
|
||||
{
|
||||
if (btn.Enabled)
|
||||
{
|
||||
@@ -523,7 +564,7 @@ namespace Barotrauma
|
||||
if (ReplacingPermanentlyDeadCharacter)
|
||||
{
|
||||
bool canHire = CanHire(characterInfo) && campaign.CanAffordNewCharacter(characterInfo);
|
||||
var takeoverButton = new GUIButton(new RectTransform(new Vector2(width, 0.9f), mainGroup.RectTransform), style: "CrewManagementTakeControlButton")
|
||||
var takeoverButton = new GUIButton(new RectTransform(new Vector2(buttonWidth, 0.9f), mainGroup.RectTransform), style: "CrewManagementTakeControlButton")
|
||||
{
|
||||
ToolTip = canHire ? TextManager.Get("hireandtakecontrol") : TextManager.Get("hireandtakecontroldisabled"),
|
||||
ClickSound = GUISoundType.ConfirmTransaction,
|
||||
@@ -554,25 +595,90 @@ namespace Barotrauma
|
||||
btn.Enabled = canHireCurrently;
|
||||
};
|
||||
}
|
||||
|
||||
if (ReserveBenchEnabled && !ReplacingPermanentlyDeadCharacter)
|
||||
{
|
||||
var hireToReserveBenchButton = new GUIButton(new RectTransform(new Vector2(buttonWidth, 0.9f), mainGroup.RectTransform), style: "CrewManagementAddAsReserveButton")
|
||||
{
|
||||
ToolTip = TextManager.Get("hirebutton.reservebench"),
|
||||
ClickSound = GUISoundType.Cart,
|
||||
UserData = characterInfo,
|
||||
Enabled = CanHire(characterInfo),
|
||||
OnClicked = (b, o) =>
|
||||
{
|
||||
var currentCharacterInfo = (CharacterInfo)o;
|
||||
currentCharacterInfo.BotStatus = BotStatus.PendingHireToReserveBench;
|
||||
return AddPendingHire(currentCharacterInfo, checkCrewSizeLimit: false);
|
||||
}
|
||||
};
|
||||
hireToReserveBenchButton.OnAddedToGUIUpdateList += (GUIComponent btn) =>
|
||||
{
|
||||
btn.Visible = ReserveBenchEnabled;
|
||||
btn.Enabled = CanHire(characterInfo) && !ReplacingPermanentlyDeadCharacter;
|
||||
};
|
||||
}
|
||||
}
|
||||
else if (listBox == pendingList)
|
||||
{
|
||||
new GUIButton(new RectTransform(new Vector2(width, 0.9f), mainGroup.RectTransform), style: "CrewManagementRemoveButton")
|
||||
if (ReserveBenchEnabled && !ReplacingPermanentlyDeadCharacter)
|
||||
{
|
||||
new GUIButton(new RectTransform(new Vector2(buttonWidth, 0.9f), mainGroup.RectTransform),
|
||||
style: characterInfo.BotStatus == BotStatus.PendingHireToActiveService ? "CrewManagementReserveBenchButtonActive" : "CrewManagementReserveBenchButtonReserve")
|
||||
{
|
||||
UserData = characterInfo,
|
||||
ToolTip = TextManager.Get(characterInfo.BotStatus == BotStatus.PendingHireToActiveService ? "ReserveBenchTogglePendingHire.Active" : "ReserveBenchTogglePendingHire.Reserve"),
|
||||
Enabled = CanHire(characterInfo) && (characterInfo.BotStatus == BotStatus.PendingHireToActiveService || !ActiveServiceFull()), // note that this is a toggle
|
||||
OnClicked = (btn, obj) =>
|
||||
{
|
||||
SelectCharacter(null, null, null);
|
||||
var currentCharacterInfo = (CharacterInfo)obj;
|
||||
GameMain.Client?.ToggleReserveBench(currentCharacterInfo, pendingHire: true);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
new GUIButton(new RectTransform(new Vector2(buttonWidth, 0.9f), mainGroup.RectTransform), style: "CrewManagementRemoveButton")
|
||||
{
|
||||
ClickSound = GUISoundType.Cart,
|
||||
UserData = characterInfo,
|
||||
Enabled = CanHire(characterInfo),
|
||||
Enabled = CanHire(characterInfo), // =just check user's rights
|
||||
OnClicked = (b, o) => RemovePendingHire(o as CharacterInfo)
|
||||
};
|
||||
}
|
||||
else if (listBox == crewList && campaign != null)
|
||||
{
|
||||
var currentCrew = GameMain.GameSession.CrewManager.GetCharacterInfos();
|
||||
new GUIButton(new RectTransform(new Vector2(width, 0.9f), mainGroup.RectTransform), style: "CrewManagementFireButton")
|
||||
if (ReserveBenchEnabled && !ReplacingPermanentlyDeadCharacter)
|
||||
{
|
||||
new GUIButton(new RectTransform(new Vector2(buttonWidth, 0.9f), mainGroup.RectTransform),
|
||||
style: characterInfo.BotStatus == BotStatus.ActiveService ? "CrewManagementReserveBenchButtonActive" : "CrewManagementReserveBenchButtonReserve")
|
||||
{
|
||||
UserData = characterInfo,
|
||||
ToolTip = TextManager.Get(characterInfo.BotStatus == BotStatus.ActiveService ? "ReserveBenchToggle.Active" : "ReserveBenchToggle.Reserve"),
|
||||
Enabled = CanHire(characterInfo) && (characterInfo.BotStatus == BotStatus.ActiveService || !ActiveServiceFull()), // note that this is a toggle
|
||||
OnClicked = (btn, obj) =>
|
||||
{
|
||||
SelectCharacter(null, null, null);
|
||||
var currentCharacterInfo = (CharacterInfo)obj;
|
||||
if (currentCharacterInfo.BotStatus == BotStatus.ActiveService && // switching to reserve bench
|
||||
characterInfo.Character != null) // may not have a Character to remove if not spawned this round
|
||||
{
|
||||
GameMain.GameSession.CrewManager.RemoveCharacter(characterInfo.Character, removeInfo: true, resetCrewListIndex: true);
|
||||
}
|
||||
GameMain.Client?.ToggleReserveBench(currentCharacterInfo); // update changes to server
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
var cm = GameMain.GameSession.CrewManager;
|
||||
// Can't fire if there's only one character in active service
|
||||
var fireButtonEnabled = HasPermissionToHire && (characterInfo.IsOnReserveBench ||
|
||||
(cm.GetCharacterInfos().Contains(characterInfo) && cm.GetCharacterInfos().Count() > 1));
|
||||
new GUIButton(new RectTransform(new Vector2(buttonWidth, 0.9f), mainGroup.RectTransform), style: "CrewManagementFireButton")
|
||||
{
|
||||
UserData = characterInfo,
|
||||
//can't fire if there's only one character in the crew
|
||||
Enabled = currentCrew.Contains(characterInfo) && currentCrew.Count() > 1 && HasPermissionToHire,
|
||||
Enabled = fireButtonEnabled,
|
||||
OnClicked = (btn, obj) =>
|
||||
{
|
||||
var confirmDialog = new GUIMessageBox(
|
||||
@@ -587,11 +693,25 @@ namespace Barotrauma
|
||||
}
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ReserveBenchEnabled && characterInfo.IsOnReserveBench) // Applies to unspecified listings like the death prompt and the bot list after permadeath
|
||||
{
|
||||
new GUIImage(new RectTransform(new Vector2(smallColumnWidth / 2, 0.6f), mainGroup.RectTransform), style: "CrewManagementReserveBenchIconReserve")
|
||||
{
|
||||
ToolTip = TextManager.Get("ReserveBenchStatus.Reserve.WillSpawn")
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
new GUILayoutGroup(new RectTransform(new Vector2(smallColumnWidth / 2, 0.6f), mainGroup.RectTransform)) { CanBeFocused = false };
|
||||
}
|
||||
}
|
||||
|
||||
if (listBox == pendingList || listBox == crewList)
|
||||
{
|
||||
nameBlock.RectTransform.Resize(new Point(nameBlock.Rect.Width - nameBlock.Rect.Height, nameBlock.Rect.Height));
|
||||
nameBlock.Text = ToolBox.LimitString(nameBlock.Text, nameBlock.Font, nameBlock.Rect.Width);
|
||||
nameBlock.Text = ToolBox.LimitString(characterName, nameBlock.Font, nameBlock.Rect.Width);
|
||||
nameBlock.RectTransform.Resize(new Point((int)(nameBlock.Padding.X + nameBlock.TextSize.X + nameBlock.Padding.Z), nameBlock.Rect.Height));
|
||||
Point size = new Point((int)(0.7f * nameBlock.Rect.Height));
|
||||
new GUIImage(new RectTransform(size, nameGroup.RectTransform), "EditIcon") { CanBeFocused = false };
|
||||
@@ -605,6 +725,16 @@ namespace Barotrauma
|
||||
};
|
||||
}
|
||||
|
||||
//recalculate everything and truncate texts if needed
|
||||
mainGroup.Recalculate();
|
||||
nameBlock.Text = ToolBox.LimitString(characterName, nameBlock.Font, nameBlock.Rect.Width);
|
||||
jobBlock.Text = ToolBox.LimitString(fullJobText, jobBlock.Font, jobBlock.Rect.Width);
|
||||
if (jobBlock.Text != fullJobText)
|
||||
{
|
||||
jobBlock.ToolTip = fullJobText;
|
||||
jobBlock.CanBeFocused = true;
|
||||
}
|
||||
|
||||
bool CanHire(CharacterInfo thisCharacterInfo)
|
||||
{
|
||||
if (!HasPermissionToHire) { return false; }
|
||||
@@ -613,6 +743,15 @@ namespace Barotrauma
|
||||
|
||||
return frame;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Is there (going to be) no space left in active service?
|
||||
/// </summary>
|
||||
private bool ActiveServiceFull()
|
||||
{
|
||||
int pendingHireCount = PendingHires?.Count(ci => ci.BotStatus == BotStatus.PendingHireToActiveService) ?? 0;
|
||||
return pendingHireCount + campaign.CrewManager.GetCharacterInfos().Count() >= CrewManager.MaxCrewSize;
|
||||
}
|
||||
|
||||
private bool EnoughReputationToHire(CharacterInfo characterInfo)
|
||||
{
|
||||
@@ -656,7 +795,7 @@ namespace Barotrauma
|
||||
GUILayoutGroup infoLabelGroup = new GUILayoutGroup(new RectTransform(new Vector2(0.4f, 1.0f), infoGroup.RectTransform)) { Stretch = true };
|
||||
GUILayoutGroup infoValueGroup = new GUILayoutGroup(new RectTransform(new Vector2(0.6f, 1.0f), infoGroup.RectTransform)) { Stretch = true };
|
||||
float blockHeight = 1.0f / 4;
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, blockHeight), infoLabelGroup.RectTransform), TextManager.Get("name"));
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, blockHeight), infoLabelGroup.RectTransform), TextManager.Get("name"), textColor: GUIStyle.TextColorBright);
|
||||
GUITextBlock nameBlock = new GUITextBlock(new RectTransform(new Vector2(1.0f, blockHeight), infoValueGroup.RectTransform), "");
|
||||
string name = listBox == hireableList ? characterInfo.OriginalName : characterInfo.Name;
|
||||
nameBlock.Text = ToolBox.LimitString(name, nameBlock.Font, nameBlock.Rect.Width);
|
||||
@@ -664,17 +803,17 @@ namespace Barotrauma
|
||||
if (characterInfo.HasSpecifierTags)
|
||||
{
|
||||
var menuCategoryVar = characterInfo.Prefab.MenuCategoryVar;
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, blockHeight), infoLabelGroup.RectTransform), TextManager.Get(menuCategoryVar));
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, blockHeight), infoLabelGroup.RectTransform), TextManager.Get(menuCategoryVar), textColor: GUIStyle.TextColorBright);
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, blockHeight), infoValueGroup.RectTransform), TextManager.Get(characterInfo.ReplaceVars($"[{menuCategoryVar}]")));
|
||||
}
|
||||
if (characterInfo.Job is Job job)
|
||||
{
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, blockHeight), infoLabelGroup.RectTransform), TextManager.Get("tabmenu.job"));
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, blockHeight), infoLabelGroup.RectTransform), TextManager.Get("tabmenu.job"), textColor: GUIStyle.TextColorBright);
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, blockHeight), infoValueGroup.RectTransform), job.Name);
|
||||
}
|
||||
if (characterInfo.PersonalityTrait is NPCPersonalityTrait trait)
|
||||
{
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, blockHeight), infoLabelGroup.RectTransform), TextManager.Get("PersonalityTrait"));
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, blockHeight), infoLabelGroup.RectTransform), TextManager.Get("PersonalityTrait"), textColor: GUIStyle.TextColorBright);
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, blockHeight), infoValueGroup.RectTransform), trait.DisplayName);
|
||||
}
|
||||
infoLabelGroup.Recalculate();
|
||||
@@ -727,9 +866,9 @@ namespace Barotrauma
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool AddPendingHire(CharacterInfo characterInfo, bool createNetworkMessage = true)
|
||||
private bool AddPendingHire(CharacterInfo characterInfo, bool checkCrewSizeLimit = true, bool createNetworkMessage = true)
|
||||
{
|
||||
if (PendingHires.Count + campaign.CrewManager.GetCharacterInfos().Count() >= CrewManager.MaxCrewSize)
|
||||
if (checkCrewSizeLimit && characterInfo.BotStatus == BotStatus.PendingHireToActiveService && ActiveServiceFull())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -792,7 +931,7 @@ namespace Barotrauma
|
||||
List<CharacterInfo> nonDuplicateHires = new List<CharacterInfo>();
|
||||
hires.ForEach(hireInfo =>
|
||||
{
|
||||
if (campaign.CrewManager.GetCharacterInfos().None(crewInfo => crewInfo.IsNewHire && crewInfo.GetIdentifierUsingOriginalName() == hireInfo.GetIdentifierUsingOriginalName()))
|
||||
if (campaign.CrewManager.GetCharacterInfos(includeReserveBench: true).None(crewInfo => crewInfo.IsNewHire && crewInfo.GetIdentifierUsingOriginalName() == hireInfo.GetIdentifierUsingOriginalName()))
|
||||
{
|
||||
nonDuplicateHires.Add(hireInfo);
|
||||
}
|
||||
@@ -806,12 +945,21 @@ namespace Barotrauma
|
||||
if (!campaign.CanAfford(total)) { return false; }
|
||||
}
|
||||
|
||||
bool atLeastOneHired = false;
|
||||
bool atLeastOneHiredToActiveDuty = false;
|
||||
bool atLeastOneHiredToReserveBench = false;
|
||||
foreach (CharacterInfo ci in nonDuplicateHires)
|
||||
{
|
||||
bool toReserveBench = ci.BotStatus == BotStatus.PendingHireToReserveBench;
|
||||
if (campaign.TryHireCharacter(campaign.Map.CurrentLocation, ci, takeMoney: takeMoney))
|
||||
{
|
||||
atLeastOneHired = true;
|
||||
if (toReserveBench)
|
||||
{
|
||||
atLeastOneHiredToReserveBench = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
atLeastOneHiredToActiveDuty = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -819,15 +967,27 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
if (atLeastOneHired)
|
||||
if (atLeastOneHiredToActiveDuty || atLeastOneHiredToReserveBench)
|
||||
{
|
||||
UpdateLocationView(campaign.Map.CurrentLocation, true);
|
||||
SelectCharacter(null, null, null);
|
||||
if (createNotification)
|
||||
{
|
||||
LocalizedString msg = string.Empty;
|
||||
if (atLeastOneHiredToActiveDuty)
|
||||
{
|
||||
msg += TextManager.GetWithVariable("crewhiredmessage", "[location]", campaignUI?.Campaign?.Map?.CurrentLocation?.DisplayName);
|
||||
}
|
||||
if (atLeastOneHiredToReserveBench)
|
||||
{
|
||||
if (!msg.IsNullOrEmpty()) { msg += "\n\n"; }
|
||||
msg += GameMain.NetworkMember?.ServerSettings is { RespawnMode: RespawnMode.Permadeath, IronmanMode: false } ?
|
||||
TextManager.Get("crewhiredmessage.reservebench.permadeath") :
|
||||
TextManager.Get( "crewhiredmessage.reservebench");
|
||||
}
|
||||
|
||||
var dialog = new GUIMessageBox(
|
||||
TextManager.Get("newcrewmembers"),
|
||||
TextManager.GetWithVariable("crewhiredmessage", "[location]", campaignUI?.Campaign?.Map?.CurrentLocation?.DisplayName),
|
||||
TextManager.Get("newcrewmembers"), msg,
|
||||
new LocalizedString[] { TextManager.Get("Ok") });
|
||||
dialog.Buttons[0].OnClicked += dialog.Close;
|
||||
}
|
||||
@@ -1034,7 +1194,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public void SetPendingHires(List<UInt16> characterInfos, Location location)
|
||||
public void SetPendingHires(List<UInt16> characterInfos, bool[] characterInfoReserveBenchStatuses, Location location, bool checkCrewSizeLimit)
|
||||
{
|
||||
List<CharacterInfo> oldHires = PendingHires.ToList();
|
||||
foreach (CharacterInfo pendingHire in oldHires)
|
||||
@@ -1042,18 +1202,25 @@ namespace Barotrauma
|
||||
RemovePendingHire(pendingHire, createNetworkMessage: false);
|
||||
}
|
||||
PendingHires.Clear();
|
||||
int i = 0;
|
||||
foreach (UInt16 identifier in characterInfos)
|
||||
{
|
||||
CharacterInfo match = location.HireManager.AvailableCharacters.Find(info => info.ID == identifier);
|
||||
if (match != null)
|
||||
{
|
||||
AddPendingHire(match, createNetworkMessage: false);
|
||||
match.BotStatus = characterInfoReserveBenchStatuses[i] ? BotStatus.PendingHireToReserveBench : BotStatus.PendingHireToActiveService;
|
||||
AddPendingHire(match, checkCrewSizeLimit: checkCrewSizeLimit, createNetworkMessage: false);
|
||||
if (!PendingHires.Contains(match))
|
||||
{
|
||||
DebugConsole.ThrowError("Failed to add a pending hire");
|
||||
}
|
||||
System.Diagnostics.Debug.Assert(PendingHires.Contains(match));
|
||||
}
|
||||
else
|
||||
{
|
||||
DebugConsole.ThrowError("Received a hire that doesn't exist.");
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1064,7 +1231,7 @@ namespace Barotrauma
|
||||
/// <param name="renameCharacter">When not null tell the server to rename this character. Item1 is the character to rename, Item2 is the new name, Item3 indicates whether the renamed character is already a part of the crew.</param>
|
||||
/// <param name="firedCharacter">When not null tell the server to fire this character</param>
|
||||
/// <param name="validateHires">When set to true will tell the server to validate pending hires</param>
|
||||
public void SendCrewState(bool updatePending, (CharacterInfo info, string newName) renameCharacter = default, CharacterInfo firedCharacter = null, bool validateHires = false)
|
||||
public void SendCrewState(bool updatePending = false, (CharacterInfo info, string newName) renameCharacter = default, CharacterInfo firedCharacter = null, bool validateHires = false)
|
||||
{
|
||||
if (campaign is MultiPlayerCampaign)
|
||||
{
|
||||
@@ -1078,6 +1245,7 @@ namespace Barotrauma
|
||||
foreach (CharacterInfo pendingHire in PendingHires)
|
||||
{
|
||||
msg.WriteUInt16(pendingHire.ID);
|
||||
msg.WriteBoolean(pendingHire.BotStatus == BotStatus.PendingHireToReserveBench);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1089,7 +1257,9 @@ namespace Barotrauma
|
||||
{
|
||||
msg.WriteUInt16(renameCharacter.info.ID);
|
||||
msg.WriteString(renameCharacter.newName);
|
||||
bool existingCrewMember = campaign.CrewManager?.GetCharacterInfos().Any(ci => ci.ID == renameCharacter.info.ID) ?? false;
|
||||
bool existingCrewMember =
|
||||
campaign.CrewManager is CrewManager crewManager &&
|
||||
crewManager.GetCharacterInfos(includeReserveBench: true).Any(ci => ci.ID == renameCharacter.info.ID);
|
||||
msg.WriteBoolean(existingCrewMember);
|
||||
}
|
||||
|
||||
|
||||
@@ -25,8 +25,6 @@ namespace Barotrauma
|
||||
private Video currSplashScreen;
|
||||
private DateTime videoStartTime;
|
||||
|
||||
private bool mirrorBackground;
|
||||
|
||||
public struct PendingSplashScreen
|
||||
{
|
||||
public string Filename;
|
||||
@@ -108,8 +106,7 @@ namespace Barotrauma
|
||||
|
||||
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, samplerState: GUI.SamplerState);
|
||||
|
||||
GUI.DrawBackgroundSprite(spriteBatch, currentBackgroundTexture, Color.White, drawArea,
|
||||
spriteEffects: mirrorBackground ? SpriteEffects.FlipHorizontally : SpriteEffects.None);
|
||||
GUI.DrawBackgroundSprite(spriteBatch, currentBackgroundTexture, Color.White, drawArea);
|
||||
overlay.Draw(spriteBatch, Vector2.Zero, scale: overlayScale);
|
||||
|
||||
double noiseT = Timing.TotalTime * 0.02f;
|
||||
@@ -386,7 +383,6 @@ namespace Barotrauma
|
||||
{
|
||||
currentBackgroundTexture = missions.Where(m => m.Prefab.HasPortraits).First().Prefab.GetPortrait(Rand.Int(int.MaxValue));
|
||||
}
|
||||
mirrorBackground = Rand.Range(0.0f, 1.0f) < 0.5f;
|
||||
|
||||
while (!drawn)
|
||||
{
|
||||
|
||||
@@ -6,6 +6,7 @@ using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using Microsoft.Xna.Framework.Input;
|
||||
using PlayerBalanceElement = Barotrauma.CampaignUI.PlayerBalanceElement;
|
||||
|
||||
namespace Barotrauma
|
||||
@@ -1573,15 +1574,24 @@ namespace Barotrauma
|
||||
if (locationHasDealOnItem)
|
||||
{
|
||||
var relativeWidth = (0.9f * nameAndQuantityFrame.Rect.Height) / nameAndQuantityFrame.Rect.Width;
|
||||
Vector2 dealIconSize = new Vector2(relativeWidth, 0.9f) * 0.5f;
|
||||
var dealIcon = new GUIImage(
|
||||
new RectTransform(new Vector2(relativeWidth, 0.9f), nameAndQuantityFrame.RectTransform, anchor: Anchor.CenterLeft)
|
||||
new RectTransform(dealIconSize, nameAndQuantityFrame.RectTransform, anchor: Anchor.CenterRight)
|
||||
{
|
||||
AbsoluteOffset = new Point((int)nameBlock.Padding.X, 0)
|
||||
},
|
||||
"StoreDealIcon", scaleToFit: true)
|
||||
{
|
||||
CanBeFocused = false
|
||||
CanBeFocused = false,
|
||||
UserData = "StoreDealIcon"
|
||||
};
|
||||
var dealIconColor = dealIcon.Color;
|
||||
if (forceDisable)
|
||||
{
|
||||
dealIconColor.A = 0;
|
||||
}
|
||||
|
||||
dealIcon.Color = dealIconColor;
|
||||
dealIcon.SetAsFirstChild();
|
||||
}
|
||||
bool isParentOnLeftSideOfInterface = parentComponent == storeBuyList || parentComponent == storeDailySpecialsGroup ||
|
||||
@@ -1713,7 +1723,7 @@ namespace Barotrauma
|
||||
mainGroup.Recalculate();
|
||||
mainGroup.RectTransform.RecalculateChildren(true, true);
|
||||
amountInput?.LayoutGroup.Recalculate();
|
||||
nameBlock.Text = ToolBox.LimitString(nameBlock.Text, nameBlock.Font, nameBlock.Rect.Width);
|
||||
nameBlock.Text = ToolBox.LimitString(nameBlock.Text.SanitizedString, nameBlock.Font, nameBlock.Rect.Width);
|
||||
mainGroup.RectTransform.Children.ForEach(c => c.IsFixedSize = true);
|
||||
|
||||
return frame;
|
||||
@@ -1795,6 +1805,9 @@ namespace Barotrauma
|
||||
|
||||
private void SetItemFrameStatus(GUIComponent itemFrame, bool enabled)
|
||||
{
|
||||
float full = 1f;
|
||||
float dim = 0.7f;
|
||||
float alpha = (enabled ? full : dim);
|
||||
if (itemFrame?.UserData is not PurchasedItem pi) { return; }
|
||||
bool refreshFrameStatus = !pi.IsStoreComponentEnabled.HasValue || pi.IsStoreComponentEnabled.Value != enabled;
|
||||
if (!refreshFrameStatus) { return; }
|
||||
@@ -1802,14 +1815,14 @@ namespace Barotrauma
|
||||
{
|
||||
if (pi.ItemPrefab?.InventoryIcon != null)
|
||||
{
|
||||
icon.Color = pi.ItemPrefab.InventoryIconColor * (enabled ? 1.0f : 0.5f);
|
||||
icon.Color = pi.ItemPrefab.InventoryIconColor * alpha;
|
||||
}
|
||||
else if (pi.ItemPrefab?.Sprite != null)
|
||||
{
|
||||
icon.Color = pi.ItemPrefab.SpriteColor * (enabled ? 1.0f : 0.5f);
|
||||
icon.Color = pi.ItemPrefab.SpriteColor * alpha;
|
||||
}
|
||||
};
|
||||
var color = Color.White * (enabled ? 1.0f : 0.5f);
|
||||
var color = Color.White * alpha;
|
||||
if (itemFrame.FindChild("name", recursive: true) is GUITextBlock name)
|
||||
{
|
||||
name.TextColor = color;
|
||||
@@ -1835,7 +1848,7 @@ namespace Barotrauma
|
||||
}
|
||||
if (itemFrame.FindChild("price", recursive: true) is GUITextBlock priceBlock)
|
||||
{
|
||||
priceBlock.TextColor = isDiscounted ? storeSpecialColor * (enabled ? 1.0f : 0.5f) : color;
|
||||
priceBlock.TextColor = isDiscounted ? storeSpecialColor * alpha : color;
|
||||
}
|
||||
if (itemFrame.FindChild("addbutton", recursive: true) is GUIButton addButton)
|
||||
{
|
||||
@@ -1845,6 +1858,10 @@ namespace Barotrauma
|
||||
{
|
||||
removeButton.Enabled = enabled;
|
||||
}
|
||||
if (itemFrame.FindChild("StoreDealIcon", recursive: true) is GUIImage dealIcon)
|
||||
{
|
||||
dealIcon.Color = dealIcon.Color * alpha;
|
||||
}
|
||||
pi.IsStoreComponentEnabled = enabled;
|
||||
itemFrame.UserData = pi;
|
||||
}
|
||||
@@ -2271,6 +2288,15 @@ namespace Barotrauma
|
||||
{
|
||||
updateStopwatch.Restart();
|
||||
|
||||
if (GameMain.DevMode)
|
||||
{
|
||||
if (PlayerInput.KeyDown(Keys.D0))
|
||||
{
|
||||
CreateUI();
|
||||
needsRefresh = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (GameMain.GraphicsWidth != resolutionWhenCreated.X || GameMain.GraphicsHeight != resolutionWhenCreated.Y)
|
||||
{
|
||||
CreateUI();
|
||||
|
||||
@@ -255,7 +255,7 @@ namespace Barotrauma
|
||||
pageIndicators = new GUIImage[pageCount];
|
||||
for (int i = 0; i < pageCount; i++)
|
||||
{
|
||||
pageIndicators[i] = new GUIImage(new RectTransform(indicatorSize, pageIndicatorHolder.RectTransform) { AbsoluteOffset = new Point(xPos, yPos) }, pageIndicator, null, true);
|
||||
pageIndicators[i] = new GUIImage(new RectTransform(indicatorSize, pageIndicatorHolder.RectTransform) { AbsoluteOffset = new Point(xPos, yPos) }, pageIndicator, scaleToFit: true);
|
||||
xPos += indicatorSize.X + HUDLayoutSettings.Padding;
|
||||
}
|
||||
|
||||
|
||||
@@ -120,9 +120,20 @@ namespace Barotrauma
|
||||
{
|
||||
if (Client == null) { return; }
|
||||
if (currentPing == Client.Ping) { return; }
|
||||
currentPing = Client.Ping;
|
||||
textBlock.Text = currentPing.ToString();
|
||||
textBlock.TextColor = GetPingColor();
|
||||
if (GameMain.NetworkMember != null && GameMain.NetworkMember.ConnectedClients.Contains(Client))
|
||||
{
|
||||
currentPing = Client.Ping;
|
||||
textBlock.Text = currentPing.ToString();
|
||||
textBlock.TextColor = GetPingColor();
|
||||
textBlock.ToolTip = string.Empty;
|
||||
}
|
||||
else
|
||||
{
|
||||
currentPing = 0;
|
||||
textBlock.Text = "-";
|
||||
textBlock.TextColor = GUIStyle.Red;
|
||||
textBlock.ToolTip = TextManager.Get("causeofdeathdescription.disconnected");
|
||||
}
|
||||
}
|
||||
|
||||
public void TryPermissionIconRefresh(Sprite icon)
|
||||
@@ -461,7 +472,7 @@ namespace Barotrauma
|
||||
CreateSubmarineInfo(infoFrameHolder, Submarine.MainSub);
|
||||
break;
|
||||
case InfoFrameTab.Talents:
|
||||
talentMenu.CreateGUI(infoFrameHolder, Character.Controlled ?? GameMain.Client?.Character);
|
||||
talentMenu.CreateGUI(infoFrameHolder, Character.Controlled?.Info ?? GameMain.Client?.CharacterInfo);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -709,38 +720,49 @@ namespace Barotrauma
|
||||
|
||||
var connectedClients = GameMain.Client.ConnectedClients;
|
||||
|
||||
for (int i = 0; i < teamIDs.Count; i++)
|
||||
for (int teamID = 0; teamID < teamIDs.Count; teamID++)
|
||||
{
|
||||
foreach (Character character in crew.Where(c => c.TeamID == teamIDs[i]))
|
||||
foreach (Character character in crew.Where(c => c.TeamID == teamIDs[teamID]))
|
||||
{
|
||||
if (character is not AICharacter && connectedClients.Any(c => c.Character == null && c.Name == character.Name)) { continue; }
|
||||
CreateMultiPlayerCharacterElement(character, GameMain.Client.PreviouslyConnectedClients.FirstOrDefault(c => c.Character == character), i);
|
||||
CreateMultiPlayerCharacterElement(character, GameMain.Client.PreviouslyConnectedClients.FirstOrDefault(c => c.Character == character), teamID);
|
||||
}
|
||||
|
||||
foreach (CharacterInfo characterInfo in GameMain.GameSession.CrewManager?.GetReserveBenchInfos() ?? Enumerable.Empty<CharacterInfo>())
|
||||
{
|
||||
CreateMultiPlayerCharacterElement(character: null, client: null, teamID, justCharacterInfo: characterInfo);
|
||||
}
|
||||
}
|
||||
|
||||
for (int j = 0; j < connectedClients.Count; j++)
|
||||
{
|
||||
Client client = connectedClients[j];
|
||||
if (!client.InGame || client.Character == null || client.Character.IsDead)
|
||||
if (client.Character == null || client.Character.IsDead)
|
||||
{
|
||||
CreateMultiPlayerClientElement(client);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void CreateMultiPlayerCharacterElement(Character character, Client client, int i)
|
||||
|
||||
/// <param name="justCharacterInfo">The character element can be generated based on just a CharacterInfo, and Character and Client can be left null. Otherwise, those are required and the CharacterInfo of the Character is used.</param>
|
||||
private void CreateMultiPlayerCharacterElement(Character character, Client client, int teamID, CharacterInfo justCharacterInfo = null)
|
||||
{
|
||||
GUIFrame frame = new GUIFrame(new RectTransform(new Point(crewListArray[i].Content.Rect.Width, GUI.IntScale(33f)), crewListArray[i].Content.RectTransform), style: "ListBoxElement")
|
||||
CharacterInfo characterInfo = justCharacterInfo ?? character.Info;
|
||||
|
||||
GUIFrame frame = new GUIFrame(new RectTransform(new Point(crewListArray[teamID].Content.Rect.Width, GUI.IntScale(33f)), crewListArray[teamID].Content.RectTransform), style: "ListBoxElement")
|
||||
{
|
||||
UserData = character,
|
||||
UserData = character != null ? character : characterInfo,
|
||||
Color = (GameMain.NetworkMember != null && GameMain.Client.Character == character) ? OwnCharacterBGColor : Color.Transparent
|
||||
};
|
||||
|
||||
frame.OnSecondaryClicked += (component, data) =>
|
||||
|
||||
if (client != null)
|
||||
{
|
||||
NetLobbyScreen.CreateModerationContextMenu(client);
|
||||
return true;
|
||||
};
|
||||
frame.OnSecondaryClicked += (component, data) =>
|
||||
{
|
||||
NetLobbyScreen.CreateModerationContextMenu(client);
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
var paddedFrame = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.9f), frame.RectTransform, Anchor.Center), isHorizontal: true)
|
||||
{
|
||||
@@ -748,7 +770,18 @@ namespace Barotrauma
|
||||
Stretch = true
|
||||
};
|
||||
|
||||
new GUICustomComponent(new RectTransform(new Point(jobColumnWidth, paddedFrame.Rect.Height), paddedFrame.RectTransform, Anchor.Center), onDraw: (sb, component) => character.Info.DrawJobIcon(sb, component.Rect))
|
||||
new GUICustomComponent(new RectTransform(new Point(jobColumnWidth, paddedFrame.Rect.Height), paddedFrame.RectTransform, Anchor.Center),
|
||||
onDraw: (sb, component) =>
|
||||
{
|
||||
if (client == null)
|
||||
{
|
||||
characterInfo?.DrawJobIcon(sb, component.Rect);
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawClientJobIcon(sb, component.Rect, client);
|
||||
}
|
||||
})
|
||||
{
|
||||
CanBeFocused = false,
|
||||
HoverColor = Color.White,
|
||||
@@ -778,39 +811,60 @@ namespace Barotrauma
|
||||
else
|
||||
{
|
||||
GUITextBlock characterNameBlock = new GUITextBlock(new RectTransform(new Point(characterColumnWidth, paddedFrame.Rect.Height), paddedFrame.RectTransform),
|
||||
ToolBox.LimitString(character.Info.Name, GUIStyle.Font, characterColumnWidth), textAlignment: Alignment.Center, textColor: character.Info.Job.Prefab.UIColor);
|
||||
ToolBox.LimitString(characterInfo.Name, GUIStyle.Font, characterColumnWidth), textAlignment: Alignment.Center, textColor: characterInfo.Job.Prefab.UIColor);
|
||||
|
||||
if (GameMain.GameSession?.GameMode is PvPMode)
|
||||
{
|
||||
new GUITextBlock(new RectTransform(new Point(killColumnWidth, paddedFrame.Rect.Height), paddedFrame.RectTransform), string.Empty, textAlignment: Alignment.Center)
|
||||
{
|
||||
TextGetter = () => GameMain.GameSession.Missions.Sum(m => (m as CombatMission)?.GetBotKillCount(character.Info) ?? 0).ToString()
|
||||
TextGetter = () => GameMain.GameSession.Missions.Sum(m => (m as CombatMission)?.GetBotKillCount(characterInfo) ?? 0).ToString()
|
||||
};
|
||||
new GUITextBlock(new RectTransform(new Point(deathColumnWidth, paddedFrame.Rect.Height), paddedFrame.RectTransform), string.Empty, textAlignment: Alignment.Center)
|
||||
{
|
||||
TextGetter = () => GameMain.GameSession.Missions.Sum(m => (m as CombatMission)?.GetBotDeathCount(character.Info) ?? 0).ToString()
|
||||
TextGetter = () => GameMain.GameSession.Missions.Sum(m => (m as CombatMission)?.GetBotDeathCount(characterInfo) ?? 0).ToString()
|
||||
};
|
||||
}
|
||||
|
||||
if (character is AICharacter)
|
||||
{
|
||||
linkedGUIList.Add(new LinkedGUI(character, frame,
|
||||
new GUITextBlock(new RectTransform(new Point(pingColumnWidth, paddedFrame.Rect.Height), paddedFrame.RectTransform), TextManager.Get("tabmenu.bot"), textAlignment: Alignment.Center) { ForceUpperCase = ForceUpperCase.Yes }));
|
||||
// "BOT" instead of ping (which isn't relevant for bots)
|
||||
linkedGUIList.Add(new LinkedGUI(character, frame,
|
||||
new GUITextBlock(new RectTransform(new Point(pingColumnWidth, paddedFrame.Rect.Height), paddedFrame.RectTransform), TextManager.Get("tabmenu.bot"), textAlignment: Alignment.Center) { ForceUpperCase = ForceUpperCase.Yes }));
|
||||
}
|
||||
else
|
||||
else if (characterInfo.IsOnReserveBench)
|
||||
{
|
||||
linkedGUIList.Add(new LinkedGUI(client: null, frame, textBlock: null, permissionIcon: null));
|
||||
|
||||
new GUICustomComponent(new RectTransform(new Point(pingColumnWidth, paddedFrame.Rect.Height), paddedFrame.RectTransform, Anchor.Center), onDraw: (sb, component) => DrawDisconnectedIcon(sb, component.Rect))
|
||||
// Reserve bench icon
|
||||
new GUIImage(new RectTransform(new Point(pingColumnWidth, paddedFrame.Rect.Height - 4), paddedFrame.RectTransform), style: "CrewManagementReserveBenchIconReserve", scaleToFit: true)
|
||||
{
|
||||
CanBeFocused = false,
|
||||
HoverColor = Color.White,
|
||||
SelectedColor = Color.White
|
||||
ToolTip = TextManager.Get("ReserveBenchStatus.Reserve")
|
||||
};
|
||||
}
|
||||
|
||||
if (characterInfo.IsOnReserveBench)
|
||||
{
|
||||
//black bar to dim out the elements (1px shorter and to the right so it won't dim the left border too)
|
||||
new GUIFrame(
|
||||
new RectTransform(new Point(paddedFrame.Rect.Width - 1, frame.Rect.Height), paddedFrame.RectTransform, Anchor.Center)
|
||||
{
|
||||
AbsoluteOffset = new Point(1, 0)
|
||||
},
|
||||
style: null, color: Color.Black * 0.7f)
|
||||
{
|
||||
IgnoreLayoutGroups = true,
|
||||
CanBeFocused = false
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
CreateWalletCrewFrame(character, paddedFrame);
|
||||
|
||||
if (character != null)
|
||||
{
|
||||
CreateWalletCrewFrame(character, paddedFrame);
|
||||
}
|
||||
else if (characterInfo.IsOnReserveBench)
|
||||
{
|
||||
// Empty column for reserve benched bots
|
||||
new GUILayoutGroup(new RectTransform(new Point(walletColumnWidth, paddedFrame.Rect.Height), paddedFrame.RectTransform, Anchor.Center), childAnchor: Anchor.Center) { CanBeFocused = false };
|
||||
}
|
||||
|
||||
paddedFrame.Recalculate();
|
||||
}
|
||||
@@ -839,7 +893,7 @@ namespace Barotrauma
|
||||
};
|
||||
|
||||
new GUICustomComponent(new RectTransform(new Point(jobColumnWidth, paddedFrame.Rect.Height), paddedFrame.RectTransform, Anchor.Center),
|
||||
onDraw: (sb, component) => DrawNotInGameIcon(sb, component.Rect, client))
|
||||
onDraw: (sb, component) => DrawClientJobIcon(sb, component.Rect, client))
|
||||
{
|
||||
CanBeFocused = false,
|
||||
HoverColor = Color.White,
|
||||
@@ -864,10 +918,7 @@ namespace Barotrauma
|
||||
new GUITextBlock(new RectTransform(new Point(pingColumnWidth, paddedFrame.Rect.Height), paddedFrame.RectTransform), client.Ping.ToString(), textAlignment: Alignment.Center),
|
||||
permissionIcon));
|
||||
|
||||
if (client.Character is { } character)
|
||||
{
|
||||
CreateWalletCrewFrame(character, paddedFrame);
|
||||
}
|
||||
CreateWalletCrewFrame(client.Character, paddedFrame);
|
||||
|
||||
paddedFrame.Recalculate();
|
||||
}
|
||||
@@ -925,7 +976,7 @@ namespace Barotrauma
|
||||
ToolTip = TextManager.Get("walletdescription")
|
||||
};
|
||||
|
||||
if (character.IsBot) { return; }
|
||||
if (character == null || character.IsBot) { return; }
|
||||
|
||||
Sprite walletSprite = GUIStyle.CrewWalletIconSmall.Value.Sprite;
|
||||
|
||||
@@ -1033,13 +1084,13 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawNotInGameIcon(SpriteBatch spriteBatch, Rectangle area, Client client)
|
||||
private void DrawClientJobIcon(SpriteBatch spriteBatch, Rectangle area, Client client)
|
||||
{
|
||||
if (client.Spectating)
|
||||
{
|
||||
spectateIcon.Draw(spriteBatch, area, Color.White);
|
||||
}
|
||||
else if (client.Character != null && client.Character.IsDead)
|
||||
else if (client.Character != null && client.InGame)
|
||||
{
|
||||
client.Character.Info?.DrawJobIcon(spriteBatch, area);
|
||||
}
|
||||
@@ -1065,7 +1116,13 @@ namespace Barotrauma
|
||||
|
||||
GUIComponent existingPreview = infoFrameHolder.FindChild("SelectedCharacter");
|
||||
if (existingPreview != null) { infoFrameHolder.RemoveChild(existingPreview); }
|
||||
|
||||
|
||||
if (userData is CharacterInfo { IsOnReserveBench: true })
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Modal info panel that pops up on the right
|
||||
GUIFrame background = new GUIFrame(new RectTransform(new Vector2(0.543f, 0.69f), infoFrameHolder.RectTransform, Anchor.TopRight, Pivot.TopLeft) { RelativeOffset = new Vector2(-0.061f, 0) })
|
||||
{
|
||||
UserData = "SelectedCharacter"
|
||||
@@ -1089,7 +1146,7 @@ namespace Barotrauma
|
||||
{
|
||||
talentButton.OnClicked = (button, o) =>
|
||||
{
|
||||
talentMenu.CreateGUI(infoFrameHolder, character);
|
||||
talentMenu.CreateGUI(infoFrameHolder, character.Info);
|
||||
return true;
|
||||
};
|
||||
}
|
||||
@@ -1474,7 +1531,7 @@ namespace Barotrauma
|
||||
var headerArea = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.322f), paddedFrame.RectTransform), isHorizontal: true);
|
||||
|
||||
new GUICustomComponent(new RectTransform(new Vector2(0.425f, 1.0f), headerArea.RectTransform),
|
||||
onDraw: (sb, component) => DrawNotInGameIcon(sb, component.Rect, client));
|
||||
onDraw: (sb, component) => DrawClientJobIcon(sb, component.Rect, client));
|
||||
|
||||
GUIFont font = paddedFrame.Rect.Width < 280 ? GUIStyle.SmallFont : GUIStyle.Font;
|
||||
|
||||
@@ -1564,6 +1621,11 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
linkedGUIList.Clear();
|
||||
|
||||
foreach (GUIListBox crewList in crewListArray)
|
||||
{
|
||||
crewList.Content.ClearChildren();
|
||||
}
|
||||
}
|
||||
|
||||
private void AddLineToLog(string line, PlayerConnectionChangeType type)
|
||||
@@ -1648,7 +1710,7 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), locationInfoContainer.RectTransform), location.DisplayName, font: GUIStyle.LargeFont);
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), locationInfoContainer.RectTransform), location.Type.Name, font: GUIStyle.SubHeadingFont);
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), locationInfoContainer.RectTransform), location.GetLocationTypeToDisplay().Name, font: GUIStyle.SubHeadingFont);
|
||||
|
||||
if (location.Faction?.Prefab != null)
|
||||
{
|
||||
|
||||
@@ -88,17 +88,17 @@ namespace Barotrauma
|
||||
private StartAnimation? startAnimation;
|
||||
private GUIComponent? talentMainArea;
|
||||
|
||||
public void CreateGUI(GUIFrame parent, Character? targetCharacter)
|
||||
public void CreateGUI(GUIFrame parent, CharacterInfo? characterInfo)
|
||||
{
|
||||
this.characterInfo = characterInfo;
|
||||
character = characterInfo?.Character;
|
||||
|
||||
parent.ClearChildren();
|
||||
talentButtons.Clear();
|
||||
talentShowCaseButtons.Clear();
|
||||
talentCornerIcons.Clear();
|
||||
showCaseTalentFrames.Clear();
|
||||
|
||||
character = targetCharacter;
|
||||
characterInfo = targetCharacter?.Info;
|
||||
|
||||
GUIFrame background = new GUIFrame(new RectTransform(Vector2.One, parent.RectTransform, Anchor.TopCenter), style: "GUIFrameListBox");
|
||||
int padding = GUI.IntScale(15);
|
||||
GUIFrame frame = new GUIFrame(new RectTransform(new Point(background.Rect.Width - padding, background.Rect.Height - padding), parent.RectTransform, Anchor.Center), style: null);
|
||||
@@ -999,8 +999,8 @@ namespace Barotrauma
|
||||
if (characterInfo is null || talentResetButton is null || talentApplyButton is null) { return; }
|
||||
|
||||
int talentCount = selectedTalents.Count - characterInfo.GetUnlockedTalentsInTree().Count();
|
||||
talentApplyButton.Enabled = talentCount > 0;
|
||||
talentResetButton.Enabled = talentCount > 0 || characterInfo.TalentRefundPoints > 0;
|
||||
talentApplyButton.Enabled = character != null && talentCount > 0;
|
||||
talentResetButton.Enabled = character != null && (talentCount > 0 || characterInfo.TalentRefundPoints > 0);
|
||||
|
||||
if (talentCount == 0 && characterInfo.TalentRefundPoints > 0)
|
||||
{
|
||||
|
||||
@@ -127,9 +127,10 @@ namespace Barotrauma
|
||||
Campaign.OnMoneyChanged.RegisterOverwriteExisting(eventId, _ => RequestRefresh());
|
||||
}
|
||||
|
||||
public void RequestRefresh()
|
||||
public void RequestRefresh(bool refreshUpgrades = false)
|
||||
{
|
||||
needsRefresh = true;
|
||||
if (refreshUpgrades) { SelectTab(UpgradeTab.Upgrade); }
|
||||
}
|
||||
|
||||
private void RefreshAll()
|
||||
@@ -673,6 +674,10 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!upgrades.ContainsKey(category) && HasSwappableItems(category))
|
||||
{
|
||||
upgrades.Add(category, new List<UpgradePrefab>());
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var (category, prefabs) in upgrades)
|
||||
@@ -771,20 +776,28 @@ namespace Barotrauma
|
||||
{
|
||||
if (Submarine.MainSub == null) { return false; }
|
||||
subItems ??= GetSubItems();
|
||||
return subItems.Any(i =>
|
||||
i.Prefab.SwappableItem != null &&
|
||||
!i.IsHidden && i.AllowSwapping &&
|
||||
(i.Prefab.SwappableItem.CanBeBought || ItemPrefab.Prefabs.Any(ip => ip.SwappableItem?.ReplacementOnUninstall == i.Prefab.Identifier)) &&
|
||||
Submarine.MainSub.IsEntityFoundOnThisSub(i, true) && category.ItemTags.Any(t => i.HasTag(t)));
|
||||
return subItems.Any(item => HasSwappableItems(category, item));
|
||||
}
|
||||
|
||||
private static bool HasSwappableItems(UpgradeCategory category, Item item)
|
||||
{
|
||||
if (Submarine.MainSub == null) { return false; }
|
||||
return
|
||||
item.Prefab.SwappableItem != null &&
|
||||
!item.IsHidden && item.AllowSwapping &&
|
||||
(item.Prefab.SwappableItem.CanBeBought || ItemPrefab.Prefabs.Any(ip => ip.SwappableItem?.ReplacementOnUninstall == item.Prefab.Identifier)) &&
|
||||
Submarine.MainSub.IsEntityFoundOnThisSub(item, true) && category.ItemTags.Any(t => item.HasTag(t));
|
||||
}
|
||||
private static List<Item> GetSubItems() => Submarine.MainSub?.GetItems(true) ?? new List<Item>();
|
||||
|
||||
private void SelectUpgradeCategory(List<UpgradePrefab> prefabs, UpgradeCategory category, Submarine submarine)
|
||||
{
|
||||
if (selectedUpgradeCategoryLayout == null) { return; }
|
||||
|
||||
customizeTabOpen = false;
|
||||
bool hasSwappableItems = HasSwappableItems(category);
|
||||
bool hasUpgradeModules = prefabs.Count > 0;
|
||||
|
||||
customizeTabOpen = !hasUpgradeModules && hasSwappableItems;
|
||||
|
||||
GUIComponent[] categoryFrames = GetFrames(category);
|
||||
foreach (GUIComponent itemFrame in itemPreviews.Values)
|
||||
@@ -799,9 +812,7 @@ namespace Barotrauma
|
||||
GUIFrame frame = new GUIFrame(rectT(1.0f, 0.4f, selectedUpgradeCategoryLayout));
|
||||
GUIFrame paddedFrame = new GUIFrame(rectT(0.93f, 0.9f, frame, Anchor.Center), style: null);
|
||||
|
||||
bool hasSwappableItems = HasSwappableItems(category);
|
||||
|
||||
float listHeight = hasSwappableItems ? 0.9f : 1.0f;
|
||||
float listHeight = hasSwappableItems && hasUpgradeModules ? 0.9f : 1.0f;
|
||||
|
||||
GUIListBox prefabList = new GUIListBox(rectT(1.0f, listHeight, paddedFrame, Anchor.BottomLeft))
|
||||
{
|
||||
@@ -810,7 +821,8 @@ namespace Barotrauma
|
||||
ScrollBarVisible = true
|
||||
};
|
||||
|
||||
if (hasSwappableItems)
|
||||
//both swappable items and upgrade modules -> create 2 tabs
|
||||
if (hasSwappableItems && hasUpgradeModules)
|
||||
{
|
||||
GUILayoutGroup buttonLayout = new GUILayoutGroup(rectT(1.0f, 0.1f, paddedFrame, anchor: Anchor.TopLeft), isHorizontal: true);
|
||||
|
||||
@@ -852,8 +864,15 @@ namespace Barotrauma
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
CreateUpgradePrefabList(prefabList, category, prefabs, submarine);
|
||||
//only either upgrade modules or swappable items -> just create the list
|
||||
else if (hasUpgradeModules)
|
||||
{
|
||||
CreateUpgradePrefabList(prefabList, category, prefabs, submarine);
|
||||
}
|
||||
else if (hasSwappableItems)
|
||||
{
|
||||
CreateSwappableItemList(prefabList, category, submarine);
|
||||
}
|
||||
}
|
||||
|
||||
private void CreateUpgradePrefabList(GUIListBox parent, UpgradeCategory category, List<UpgradePrefab> prefabs, Submarine submarine)
|
||||
@@ -1370,9 +1389,10 @@ namespace Barotrauma
|
||||
Item[] entitiesOnSub = drawnSubmarine.GetItems(true).Where(i => drawnSubmarine.IsEntityFoundOnThisSub(i, true)).ToArray();
|
||||
foreach (UpgradeCategory category in UpgradeCategory.Categories)
|
||||
{
|
||||
//hide categories with no upgrades in them
|
||||
if (UpgradePrefab.Prefabs.None(p => p.UpgradeCategories.Contains(category))) { continue; }
|
||||
if (entitiesOnSub.Any(item => category.CanBeApplied(item, null)))
|
||||
//hide categories with no upgrades or swappables in them
|
||||
bool hasSwappableItems = HasSwappableItems(category);
|
||||
if (!hasSwappableItems && UpgradePrefab.Prefabs.None(p => p.UpgradeCategories.Contains(category))) { continue; }
|
||||
if (hasSwappableItems || entitiesOnSub.Any(item => category.CanBeApplied(item, null)))
|
||||
{
|
||||
yield return category;
|
||||
}
|
||||
@@ -1534,7 +1554,7 @@ namespace Barotrauma
|
||||
|
||||
description.Padding = new Vector4(description.Padding.X, 24 * GUI.Scale, description.Padding.Z, description.Padding.W);
|
||||
List<Entity> pointsOfInterest = (from category in UpgradeCategory.Categories from item in submarine.GetItems(UpgradeManager.UpgradeAlsoConnectedSubs)
|
||||
where category.CanBeApplied(item, null) && item.IsPlayerTeamInteractable select item).Cast<Entity>().Distinct().ToList();
|
||||
where (category.CanBeApplied(item, null) || HasSwappableItems(category, item)) && item.IsPlayerTeamInteractable select item).Cast<Entity>().Distinct().ToList();
|
||||
|
||||
List<ushort> ids = GameMain.GameSession.SubmarineInfo?.LeftBehindDockingPortIDs ?? new List<ushort>();
|
||||
pointsOfInterest.AddRange(submarine.GetItems(UpgradeManager.UpgradeAlsoConnectedSubs).Where(item => ids.Contains(item.ID)));
|
||||
@@ -1799,7 +1819,7 @@ namespace Barotrauma
|
||||
// Disables the parent and only re-enables if the submarine contains valid items
|
||||
if (!category.IsWallUpgrade && drawnSubmarine?.Info != null)
|
||||
{
|
||||
if (UpgradePrefab.Prefabs.None(p => p.UpgradeCategories.Contains(category) && p.GetMaxLevel(drawnSubmarine.Info) > 0))
|
||||
if (UpgradePrefab.Prefabs.None(p => p.UpgradeCategories.Contains(category) && p.GetMaxLevel(drawnSubmarine.Info) > 0) && !HasSwappableItems(category))
|
||||
{
|
||||
parent.ToolTip = TextManager.Get("upgradecategorynotapplicable");
|
||||
parent.Enabled = false;
|
||||
|
||||
Reference in New Issue
Block a user