Merge remote-tracking branch 'upstream/master' into develop

This commit is contained in:
EvilFactory
2024-06-18 12:19:13 -03:00
263 changed files with 7788 additions and 2849 deletions
@@ -409,9 +409,9 @@ namespace Barotrauma
{
senderName = (message.Type == ChatMessageType.Private ? "[PM] " : "") + message.SenderName;
}
if (message.Sender?.Info?.Job != null)
if (message.SenderCharacter?.Info?.Job != null)
{
senderColor = Color.Lerp(message.Sender.Info.Job.Prefab.UIColor, Color.White, 0.25f);
senderColor = Color.Lerp(message.SenderCharacter.Info.Job.Prefab.UIColor, Color.White, 0.25f);
}
var msgHolder = new GUIFrame(new RectTransform(new Vector2(0.95f, 0.0f), chatBox.Content.RectTransform, Anchor.TopCenter), style: null,
@@ -14,6 +14,7 @@ namespace Barotrauma
private readonly CampaignUI campaignUI;
private readonly GUIComponent parentComponent;
private GUILayoutGroup pendingAndCrewGroup;
private GUIListBox hireableList, pendingList, crewList;
private GUIFrame characterPreviewFrame;
private GUIDropDown sortingDropDown;
@@ -24,7 +25,14 @@ namespace Barotrauma
private PlayerBalanceElement? playerBalanceElement;
private List<CharacterInfo> PendingHires => campaign.Map?.CurrentLocation?.HireManager?.PendingHires;
private bool HasPermission => CampaignMode.AllowedToManageCampaign(ClientPermissions.ManageHires);
// Is the player hiring a new character for themselves instead of bots for the crew?
// The window can only be used for one of these purposes at the same time.
private static bool HiringNewCharacter => GameMain.NetworkMember?.ServerSettings is { RespawnMode: RespawnMode.Permadeath, IronmanMode: false } &&
GameMain.Client?.CharacterInfo is { PermanentlyDead: true };
private static bool HasPermissionToHire => CampaignMode.AllowedToManageCampaign(
HiringNewCharacter ? ClientPermissions.ManageMoney : ClientPermissions.ManageHires);
private Point resolutionWhenCreated;
@@ -60,20 +68,20 @@ namespace Barotrauma
RefreshCrewFrames(hireableList);
RefreshCrewFrames(crewList);
RefreshCrewFrames(pendingList);
if (clearAllButton != null) { clearAllButton.Enabled = HasPermission; }
if (clearAllButton != null) { clearAllButton.Enabled = HasPermissionToHire; }
}
private void RefreshCrewFrames(GUIListBox listBox)
{
if (listBox == null) { return; }
listBox.CanBeFocused = HasPermission;
listBox.CanBeFocused = HasPermissionToHire;
foreach (GUIComponent child in listBox.Content.Children)
{
if (child.FindChild(c => c is GUIButton && c.UserData is CharacterInfo, true) is GUIButton buyButton)
{
CharacterInfo characterInfo = buyButton.UserData as CharacterInfo;
bool enoughReputationToHire = EnoughReputationToHire(characterInfo);
buyButton.Enabled = HasPermission && enoughReputationToHire;
bool enougMoneyToHire = !HiringNewCharacter || campaign.CanAfford(HireManager.GetSalaryFor(characterInfo));
buyButton.Enabled = HasPermissionToHire && EnoughReputationToHire(characterInfo) && enougMoneyToHire;
foreach (GUITextBlock text in child.GetAllChildren<GUITextBlock>())
{
text.TextColor = new Color(text.TextColor, buyButton.Enabled ? 1.0f : 0.6f);
@@ -174,7 +182,7 @@ namespace Barotrauma
playerBalanceElement = CampaignUI.AddBalanceElement(pendingAndCrewMainGroup, new Vector2(1.0f, 0.75f / 14.0f));
var pendingAndCrewGroup = new GUILayoutGroup(new RectTransform(new Vector2(0.9f, 0.95f), anchor: Anchor.Center,
pendingAndCrewGroup = new GUILayoutGroup(new RectTransform(new Vector2(0.9f, 0.95f), anchor: Anchor.Center,
parent: new GUIFrame(new RectTransform(new Vector2(1.0f, 13.25f / 14.0f), pendingAndCrewMainGroup.RectTransform)
{
MaxSize = new Point(panelMaxWidth, campaignUI.GetTabContainer(CampaignMode.InteractionType.Crew).Rect.Height)
@@ -222,7 +230,7 @@ namespace Barotrauma
{
ClickSound = GUISoundType.Cart,
ForceUpperCase = ForceUpperCase.Yes,
Enabled = HasPermission,
Enabled = HasPermissionToHire,
OnClicked = (b, o) => RemoveAllPendingHires()
};
GUITextBlock.AutoScaleAndNormalize(validateHiresButton.TextBlock, clearAllButton.TextBlock);
@@ -277,7 +285,7 @@ namespace Barotrauma
{
foreach (CharacterInfo c in hireableCharacters)
{
if (c == null) { continue; }
if (c == null || PendingHires.Contains(c)) { continue; }
CreateCharacterFrame(c, hireableList);
}
}
@@ -289,8 +297,8 @@ namespace Barotrauma
{
HireManager hireManager = location.HireManager;
if (hireManager == null) { return; }
int hireVal = hireManager.AvailableCharacters.Aggregate(0, (curr, hire) => curr + hire.GetIdentifier());
int newVal = availableHires.Aggregate(0, (curr, hire) => curr + hire.GetIdentifier());
int hireVal = hireManager.AvailableCharacters.Aggregate(0, (curr, hire) => curr + hire.ID);
int newVal = availableHires.Aggregate(0, (curr, hire) => curr + hire.ID);
if (hireVal != newVal)
{
location.HireManager.AvailableCharacters = availableHires;
@@ -371,7 +379,7 @@ namespace Barotrauma
}
}
private void CreateCharacterFrame(CharacterInfo characterInfo, GUIListBox listBox)
public GUIComponent CreateCharacterFrame(CharacterInfo characterInfo, GUIListBox listBox, bool hideSalary = false)
{
Skill skill = null;
Color? jobColor = null;
@@ -442,33 +450,41 @@ namespace Barotrauma
CanBeFocused = false
};
}
if (listBox != crewList)
if (!hideSalary)
{
new GUITextBlock(new RectTransform(new Vector2(width, 1.0f), mainGroup.RectTransform),
TextManager.FormatCurrency(HireManager.GetSalaryFor(characterInfo)),
textAlignment: Alignment.Center)
if (listBox != crewList)
{
CanBeFocused = false
};
}
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 GUITextBlock(new RectTransform(new Vector2(width, 1.0f), mainGroup.RectTransform),
TextManager.FormatCurrency(HireManager.GetSalaryFor(characterInfo)),
textAlignment: Alignment.Center)
{
CanBeFocused = false
};
}
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 };
}
}
if (listBox == hireableList)
{
var hireButton = new GUIButton(new RectTransform(new Vector2(width, 0.9f), mainGroup.RectTransform), style: "CrewManagementAddButton")
{
ToolTip = TextManager.Get("hirebutton"),
ClickSound = GUISoundType.Cart,
UserData = characterInfo,
Enabled = CanHire(characterInfo),
Enabled = CanHire(characterInfo) && !HiringNewCharacter,
OnClicked = (b, o) => AddPendingHire(o as CharacterInfo)
};
hireButton.OnAddedToGUIUpdateList += (GUIComponent btn) =>
{
if (HiringNewCharacter)
{
return;
}
if (PendingHires.Count + campaign.CrewManager.GetCharacterInfos().Count() >= CrewManager.MaxCrewSize)
{
if (btn.Enabled)
@@ -483,6 +499,41 @@ namespace Barotrauma
btn.Enabled = CanHire(characterInfo);
}
};
if (HiringNewCharacter)
{
bool canHire = CanHire(characterInfo) && campaign.CanAfford(HireManager.GetSalaryFor(characterInfo));
var takeoverButton = new GUIButton(new RectTransform(new Vector2(width, 0.9f), mainGroup.RectTransform), style: "CrewManagementTakeControlButton")
{
ToolTip = canHire ? TextManager.Get("hireandtakecontrol") : TextManager.Get("hireandtakecontroldisabled"),
ClickSound = GUISoundType.ConfirmTransaction,
UserData = characterInfo,
Enabled = canHire,
OnClicked = (b, o) =>
{
if (GameMain.Client is not GameClient gameClient)
{
return false;
}
Client client = gameClient.ConnectedClients.FirstOrDefault(c => c.SessionId == gameClient.SessionId);
if (!campaign.TryPurchase(client, HireManager.GetSalaryFor(characterInfo)))
{
return false;
}
gameClient.SendTakeOverBotRequest(characterInfo);
needsHireableRefresh = true;
campaign.ShowCampaignUI = false;
return true;
}
};
takeoverButton.OnAddedToGUIUpdateList += (GUIComponent btn) =>
{
bool canHireCurrently = HiringNewCharacter && CanHire(characterInfo) && campaign.CanAfford(HireManager.GetSalaryFor(characterInfo));
btn.ToolTip = TextManager.Get(canHireCurrently ? "hireandtakecontrol" : "hireandtakecontroldisabled");
btn.Visible = GameMain.GameSession is { AllowHrManagerBotTakeover: true };
btn.Enabled = canHireCurrently;
};
}
}
else if (listBox == pendingList)
{
@@ -501,7 +552,7 @@ namespace Barotrauma
{
UserData = characterInfo,
//can't fire if there's only one character in the crew
Enabled = currentCrew.Contains(characterInfo) && currentCrew.Count() > 1 && HasPermission,
Enabled = currentCrew.Contains(characterInfo) && currentCrew.Count() > 1 && HasPermissionToHire,
OnClicked = (btn, obj) =>
{
var confirmDialog = new GUIMessageBox(
@@ -534,11 +585,13 @@ namespace Barotrauma
};
}
bool CanHire(CharacterInfo characterInfo)
bool CanHire(CharacterInfo thisCharacterInfo)
{
if (!HasPermission) { return false; }
return EnoughReputationToHire(characterInfo);
if (!HasPermissionToHire) { return false; }
return EnoughReputationToHire(thisCharacterInfo);
}
return frame;
}
private bool EnoughReputationToHire(CharacterInfo characterInfo)
@@ -709,10 +762,10 @@ namespace Barotrauma
totalBlock.Text = TextManager.FormatCurrency(total);
bool enoughMoney = campaign == null || campaign.CanAfford(total);
totalBlock.TextColor = enoughMoney ? Color.White : Color.Red;
validateHiresButton.Enabled = enoughMoney && HasPermission && pendingList.Content.RectTransform.Children.Any();
validateHiresButton.Enabled = enoughMoney && HasPermissionToHire && pendingList.Content.RectTransform.Children.Any();
}
public bool ValidateHires(List<CharacterInfo> hires, bool takeMoney = true, bool createNetworkEvent = false)
public bool ValidateHires(List<CharacterInfo> hires, bool takeMoney = true, bool createNetworkEvent = false, bool createNotification = true)
{
if (hires == null || hires.None()) { return false; }
@@ -750,11 +803,14 @@ namespace Barotrauma
{
UpdateLocationView(campaign.Map.CurrentLocation, true);
SelectCharacter(null, null, null);
var dialog = new GUIMessageBox(
TextManager.Get("newcrewmembers"),
TextManager.GetWithVariable("crewhiredmessage", "[location]", campaignUI?.Campaign?.Map?.CurrentLocation?.DisplayName),
new LocalizedString[] { TextManager.Get("Ok") });
dialog.Buttons[0].OnClicked += dialog.Close;
if (createNotification)
{
var dialog = new GUIMessageBox(
TextManager.Get("newcrewmembers"),
TextManager.GetWithVariable("crewhiredmessage", "[location]", campaignUI?.Campaign?.Map?.CurrentLocation?.DisplayName),
new LocalizedString[] { TextManager.Get("Ok") });
dialog.Buttons[0].OnClicked += dialog.Close;
}
}
if (createNetworkEvent)
@@ -767,7 +823,7 @@ namespace Barotrauma
private bool CreateRenamingComponent(GUIButton button, object userData)
{
if (!HasPermission || userData is not CharacterInfo characterInfo) { return false; }
if (!HasPermissionToHire || userData is not CharacterInfo characterInfo) { return false; }
var outerGlowFrame = new GUIFrame(new RectTransform(new Vector2(1.25f, 1.25f), parentComponent.RectTransform, Anchor.Center),
style: "OuterGlow", color: Color.Black * 0.7f);
var frame = new GUIFrame(new RectTransform(new Vector2(0.33f, 0.4f), outerGlowFrame.RectTransform, anchor: Anchor.Center)
@@ -875,6 +931,9 @@ namespace Barotrauma
{
playerBalanceElement = CampaignUI.UpdateBalanceElement(playerBalanceElement);
}
// When showing this window to someone hiring a new character, the right side panels aren't needed
pendingAndCrewGroup.Visible = !HiringNewCharacter;
if (needsHireableRefresh)
{
@@ -949,7 +1008,7 @@ namespace Barotrauma
}
}
public void SetPendingHires(List<int> characterInfos, Location location)
public void SetPendingHires(List<UInt16> characterInfos, Location location)
{
List<CharacterInfo> oldHires = PendingHires.ToList();
foreach (CharacterInfo pendingHire in oldHires)
@@ -957,9 +1016,9 @@ namespace Barotrauma
RemovePendingHire(pendingHire, createNetworkMessage: false);
}
PendingHires.Clear();
foreach (int identifier in characterInfos)
foreach (UInt16 identifier in characterInfos)
{
CharacterInfo match = location.HireManager.AvailableCharacters.Find(info => info.GetIdentifierUsingOriginalName() == identifier);
CharacterInfo match = location.HireManager.AvailableCharacters.Find(info => info.ID == identifier);
if (match != null)
{
AddPendingHire(match, createNetworkMessage: false);
@@ -992,7 +1051,7 @@ namespace Barotrauma
msg.WriteUInt16((ushort)PendingHires.Count);
foreach (CharacterInfo pendingHire in PendingHires)
{
msg.WriteInt32(pendingHire.GetIdentifierUsingOriginalName());
msg.WriteUInt16(pendingHire.ID);
}
}
@@ -1002,17 +1061,16 @@ namespace Barotrauma
msg.WriteBoolean(validRenaming);
if (validRenaming)
{
int identifier = renameCharacter.info.GetIdentifierUsingOriginalName();
msg.WriteInt32(identifier);
msg.WriteUInt16(renameCharacter.info.ID);
msg.WriteString(renameCharacter.newName);
bool existingCrewMember = campaign.CrewManager?.GetCharacterInfos().Any(ci => ci.GetIdentifierUsingOriginalName() == identifier) ?? false;
bool existingCrewMember = campaign.CrewManager?.GetCharacterInfos().Any(ci => ci.ID == renameCharacter.info.ID) ?? false;
msg.WriteBoolean(existingCrewMember);
}
msg.WriteBoolean(firedCharacter != null);
if (firedCharacter != null)
{
msg.WriteInt32(firedCharacter.GetIdentifier());
msg.WriteUInt16(firedCharacter.ID);
}
GameMain.Client.ClientPeer?.Send(msg, DeliveryMethod.Reliable);
@@ -0,0 +1,529 @@
#nullable enable
using Barotrauma.Networking;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System.Collections.Generic;
using System.Linq;
namespace Barotrauma;
internal class DeathPrompt
{
private static CoroutineHandle? createPromptCoroutine;
private GUIComponent? skillPanel;
private GUIComponent? newCharacterPanel;
private GUIComponent? takeOverBotPanel;
private GUIComponent? content;
public static GUIComponent? takeOverBotPanelFrame;
/// <summary>
/// Private constructor, because these should only be created using the Show method
/// </summary>
private DeathPrompt() { }
public static void Create(float delay)
{
if (!RespawnManager.UseDeathPrompt) { return; }
if (GameMain.GameSession.DeathPrompt != null)
{
return;
}
if (createPromptCoroutine != null && CoroutineManager.IsCoroutineRunning(createPromptCoroutine)) { return; }
if ((GameMain.GameSession is not { IsRunning: true })) { return; }
createPromptCoroutine = CoroutineManager.Invoke(() =>
{
if (GameMain.GameSession != null)
{
GameMain.GameSession.DeathPrompt = new DeathPrompt();
GameMain.GameSession.DeathPrompt.CreatePrompt();
SoundPlayer.OverrideMusicType = "crewdead".ToIdentifier();
SoundPlayer.OverrideMusicDuration = 25.0f;
}
}, delay);
}
public void AddToGUIUpdateList()
{
content?.AddToGUIUpdateList();
}
private void CreatePrompt()
{
const float FadeInInterval = 1.0f;
const float FadeInDuration = 1.0f;
bool permadeath = GameMain.NetworkMember is { ServerSettings.RespawnMode: RespawnMode.Permadeath };
bool ironman = GameMain.NetworkMember is { ServerSettings: { RespawnMode: RespawnMode.Permadeath, IronmanMode: true } };
var background = new GUICustomComponent(new RectTransform(Vector2.One, GUI.Canvas, Anchor.Center), onDraw: DrawBackground)
{
UserData = this
};
background.FadeIn(wait: 0, duration: 5.0f);
var foreground = new GUIImage(new RectTransform(new Vector2(1.0f, GUI.RelativeHorizontalAspectRatio), background.RectTransform, Anchor.BottomCenter) { AbsoluteOffset = new Point(0, GUI.IntScale(-20)) }, "DeathScreenForeground")
{
Color = Color.White
};
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))
{
UserData = this
};
frame.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)
{
TextGetter = () =>
{
return GameMain.Client.EndRoundTimeRemaining > 0.0f ?
TextManager.GetWithVariable("endinground", "[time]", ToolBox.SecondsToReadableTime(GameMain.Client.EndRoundTimeRemaining))
.Fallback(ToolBox.SecondsToReadableTime(GameMain.Client.EndRoundTimeRemaining), useDefaultLanguageIfFound: false) :
string.Empty;
}
};
var content = new GUILayoutGroup(new RectTransform(new Vector2(0.8f, 0.8f), frame.RectTransform, Anchor.Center))
{
Stretch = true,
RelativeSpacing = 0.05f
};
//"you have died" header
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), content.RectTransform), TextManager.Get("deathprompt.header"), font: GUIStyle.LargeFont, textAlignment: Alignment.Center)
.FadeIn(wait: 0, duration: FadeInDuration);
var causeOfDeath = GameMain.Client?.Character?.CauseOfDeath;
if (causeOfDeath != null && causeOfDeath.Type != CauseOfDeathType.Unknown)
{
var causeOfDeathDescription = causeOfDeath.Affliction != null ?
causeOfDeath.Affliction.SelfCauseOfDeathDescription :
TextManager.Get("Self_CauseOfDeathDescription." + causeOfDeath.Type.ToString(), "Self_CauseOfDeathDescription.Damage");
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), content.RectTransform), causeOfDeathDescription)
.FadeIn(wait: FadeInInterval * 2, duration: FadeInDuration);
}
if (permadeath)
{
if (ironman)
{
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), content.RectTransform),
TextManager.Get("deathprompt.permadeathnotification") + "\n\n" + TextManager.Get("deathprompt.ironmanexplanation"), wrap: true)
.FadeIn(wait: FadeInInterval * 3, duration: FadeInDuration);
}
else
{
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), content.RectTransform),
TextManager.Get("deathprompt.permadeathnotification") + '\n' + TextManager.Get("deathprompt.takeoverbotexplanation"), wrap: true)
.FadeIn(wait: FadeInInterval * 3, duration: FadeInDuration);
}
}
else if (RespawnManager.SkillLossPercentageOnDeath > 0)
{
string skillLossAmount = ((int)RespawnManager.SkillLossPercentageOnDeath).ToString();
string skillLossText = $"‖color: { XMLExtensions.ToStringHex(GUIStyle.Red)}‖{skillLossAmount}‖end‖";
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), content.RectTransform),
RichString.Rich(TextManager.GetWithVariable("respawnskillpenalty", "[percentage]", skillLossText)))
.FadeIn(wait: FadeInInterval * 3, duration: FadeInDuration);
};
//"what do you want to do" buttons in the middle
//-------------------------------------------------------------------------------------------------------
var decisionButtonContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.15f), content.RectTransform), isHorizontal: true)
{
Stretch = true,
RelativeSpacing = 0.05f
};
if (ironman)
{
// The only option is to spectate
var buttonContainerMiddle = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 1.0f), decisionButtonContainer.RectTransform), childAnchor: Anchor.Center);
new GUIButton(new RectTransform(new Vector2(0.5f, 1.0f), buttonContainerMiddle.RectTransform), TextManager.Get("spectatebutton"))
{
OnClicked = (btn, userdata) =>
{
GameMain.Client?.SendRespawnPromptResponse(waitForNextRoundRespawn: true);
Close();
return true;
}
}.FadeIn(wait: FadeInInterval * 4, duration: FadeInDuration, alsoChildren: true);
}
else
{
var buttonContainerLeft = new GUILayoutGroup(new RectTransform(new Vector2(0.5f, 1.0f), decisionButtonContainer.RectTransform));
var buttonContainerRight = new GUILayoutGroup(new RectTransform(new Vector2(0.5f, 1.0f), decisionButtonContainer.RectTransform));
// The default "I'll wait" button
new GUIButton(new RectTransform(new Vector2(1.0f, 1.0f), buttonContainerLeft.RectTransform), TextManager.Get("respawnquestionpromptwait"))
{
OnClicked = (btn, userdata) =>
{
GameMain.Client?.SendRespawnPromptResponse(waitForNextRoundRespawn: true);
Close();
return true;
}
}.FadeIn(wait: FadeInInterval * 4, duration: FadeInDuration, alsoChildren: true);
if (permadeath)
{
if (GameMain.Client != null && GameMain.Client.ServerSettings.AllowBotTakeoverOnPermadeath)
{
new GUIButton(new RectTransform(new Vector2(1.0f, 1.0f), buttonContainerRight.RectTransform), TextManager.Get("deathprompt.takeoverbot"))
{
Enabled = false,
OnAddedToGUIUpdateList = (component) =>
{
component.Enabled = GetAvailableBots().Any();
},
OnClicked = (btn, userdata) =>
{
if (takeOverBotPanel == null)
{
CreateTakeOverBotPanel(frame, this);
}
else
{
takeOverBotPanel.Parent?.RemoveChild(takeOverBotPanel);
takeOverBotPanel = null;
}
return true;
}
}.FadeIn(wait: FadeInInterval * 4, duration: FadeInDuration, alsoChildren: true);
}
}
else
{
new GUIButton(new RectTransform(new Vector2(1.0f, 1.0f), buttonContainerRight.RectTransform), TextManager.Get("deathprompt.respawnnow"))
{
OnClicked = (btn, userdata) =>
{
GameMain.Client?.SendRespawnPromptResponse(waitForNextRoundRespawn: false);
Close();
return true;
},
Enabled = GameMain.NetworkMember is { ServerSettings.RespawnMode: RespawnMode.MidRound }
}.FadeIn(wait: FadeInInterval * 4, duration: FadeInDuration, alsoChildren: true);
}
//"info buttons" at the bottom
//-------------------------------------------------------------------------------------------------------
var infoButtonContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.2f), content.RectTransform), childAnchor: Anchor.TopRight)
{
Stretch = true,
RelativeSpacing = 0.025f
};
if (permadeath)
{
if (Level.IsLoadedFriendlyOutpost)
{
new GUIButton(new RectTransform(new Vector2(0.6f, 1.0f), infoButtonContainer.RectTransform), TextManager.Get("npctitle.hrmanager"), style: "GUIButtonSmall")
{
OnClicked = (btn, userdata) =>
{
if (GameMain.GameSession?.Campaign is { } campaign)
{
campaign.ShowCampaignUI = true;
campaign.CampaignUI?.SelectTab(CampaignMode.InteractionType.Crew);
}
Close();
return true;
}
}.FadeIn(wait: FadeInInterval * 5, duration: FadeInDuration, alsoChildren: true);
}
}
else
{
new GUIButton(new RectTransform(new Vector2(0.6f, 1.0f), infoButtonContainer.RectTransform), TextManager.Get("deathprompt.showskills"), style: "GUIButtonSmall")
{
OnClicked = (btn, userdata) =>
{
if (skillPanel == null)
{
CreateSkillPanel(frame, GameMain.Client?.Character?.Info ?? GameMain.Client?.CharacterInfo);
}
else
{
skillPanel.Parent?.RemoveChild(skillPanel);
skillPanel = null;
}
return true;
}
}.FadeIn(wait: FadeInInterval * 5, duration: FadeInDuration, alsoChildren: true);
new GUIButton(new RectTransform(new Vector2(0.6f, 1.0f), infoButtonContainer.RectTransform), TextManager.Get("deathprompt.newcharacter"), style: "GUIButtonSmall")
{
OnClicked = (btn, userdata) =>
{
if (newCharacterPanel == null)
{
CreateNewCharacterPanel(frame);
}
else
{
newCharacterPanel.Parent?.RemoveChild(newCharacterPanel);
newCharacterPanel = null;
}
return true;
}
}.FadeIn(wait: FadeInInterval * 5, duration: FadeInDuration, alsoChildren: true);
}
}
//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;
}
private void CreateSkillPanel(GUIComponent parent, CharacterInfo? characterInfo)
{
if (characterInfo == null) { return; }
var frame = new GUIFrame(new RectTransform(new Vector2(1.0f, 1.0f), parent.RectTransform, Anchor.CenterRight, Pivot.CenterLeft));
var content = new GUILayoutGroup(new RectTransform(new Vector2(0.9f, 0.8f), frame.RectTransform, Anchor.Center), isHorizontal: true)
{
Stretch = true
};
var leftColumn = new GUILayoutGroup(new RectTransform(new Vector2(0.4f, 1.0f), content.RectTransform))
{
RelativeSpacing = 0.05f
};
var middleColumn = new GUILayoutGroup(new RectTransform(new Vector2(0.3f, 1.0f), content.RectTransform))
{
RelativeSpacing = 0.05f
};
var rightColumn = new GUILayoutGroup(new RectTransform(new Vector2(0.3f, 1.0f), content.RectTransform))
{
RelativeSpacing = 0.05f
};
var leftHeader = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), leftColumn.RectTransform), TextManager.Get("Skills"), font: GUIStyle.SubHeadingFont, textColor: GUIStyle.TextColorBright);
var middleHeader = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), middleColumn.RectTransform), TextManager.Get("deathprompt.SkillsLostHeader"), font: GUIStyle.SubHeadingFont, textColor: GUIStyle.TextColorBright);
var rightHeader = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), rightColumn.RectTransform), TextManager.Get("deathprompt.respawnnow"), font: GUIStyle.SubHeadingFont, textColor: GUIStyle.TextColorBright);
GUITextBlock.AutoScaleAndNormalize(leftHeader, middleHeader, rightHeader);
foreach (var skill in characterInfo.Job.GetSkills().OrderByDescending(s => s.Level))
{
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), leftColumn.RectTransform), skill.DisplayName);
int previousSkill = (int)skill.HighestLevelDuringRound;
int reducedSkill = (int)RespawnManager.GetReducedSkill(characterInfo, skill, RespawnManager.SkillLossPercentageOnDeath);
int reducedSkillOnImmediateRespawn = (int)RespawnManager.GetReducedSkill(characterInfo, skill, RespawnManager.SkillLossPercentageOnImmediateRespawn, currentSkillLevel: reducedSkill);
int skillLoss = reducedSkill - previousSkill;
int skillLossOnImmediateRespawn = reducedSkillOnImmediateRespawn - previousSkill;
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), middleColumn.RectTransform),
RichString.Rich($"{reducedSkill} (‖color:{XMLExtensions.ToStringHex(GUIStyle.Red)}‖{skillLoss}‖end‖)"));
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), rightColumn.RectTransform),
RichString.Rich($"{reducedSkillOnImmediateRespawn} (‖color:{XMLExtensions.ToStringHex(GUIStyle.Red)}‖{skillLossOnImmediateRespawn}‖end‖)"));
}
new GUIButton(new RectTransform(new Vector2(1.0f, 0.15f), leftColumn.RectTransform, Anchor.BottomLeft), TextManager.Get("Close"), style: "GUIButtonSmall")
{
IgnoreLayoutGroups = true,
OnClicked = (btn, userdata) =>
{
frame.Parent?.RemoveChild(frame);
skillPanel = null;
return true;
}
};
skillPanel = frame;
}
private void CreateNewCharacterPanel(GUIComponent parent)
{
var frame = new GUIFrame(new RectTransform(new Vector2(1.0f, 1.5f), parent.RectTransform, Anchor.CenterRight, Pivot.CenterLeft));
var content = new GUILayoutGroup(new RectTransform(new Vector2(0.9f, 0.9f), frame.RectTransform, Anchor.Center), isHorizontal: false)
{
Stretch = true,
RelativeSpacing = 0.05f
};
GameMain.NetLobbyScreen.CreatePlayerFrame(content, alwaysAllowEditing: true, createPendingText: false);
var buttonContainer = new GUILayoutGroup(new RectTransform(new Vector2(0.98f, 0.15f), content.RectTransform), isHorizontal: true)
{
RelativeSpacing = 0.05f,
Stretch = true
};
new GUIButton(new RectTransform(new Vector2(0.5f, 1.0f), buttonContainer.RectTransform, Anchor.BottomLeft), TextManager.Get("Cancel"), style: "GUIButtonSmall")
{
OnClicked = (btn, userdata) =>
{
frame.Parent?.RemoveChild(frame);
newCharacterPanel = null;
return true;
}
};
new GUIButton(new RectTransform(new Vector2(0.5f, 1.0f), buttonContainer.RectTransform, Anchor.BottomLeft), TextManager.Get("ApplySettingsYes"), style: "GUIButtonSmall")
{
OnClicked = (btn, userdata) =>
{
GameMain.NetLobbyScreen.TryDiscardCampaignCharacter(onYes: () =>
{
frame.Parent?.RemoveChild(frame);
newCharacterPanel = null;
});
return true;
}
};
newCharacterPanel = frame;
}
public static void CreateTakeOverBotPanel()
{
var panelHolder = new GUIFrame(new RectTransform(new Vector2(0.3f, 0.3f), GUI.Canvas, Anchor.Center));
var takeOverBotPanel = CreateTakeOverBotPanel(panelHolder, deathPrompt: null);
if (takeOverBotPanel != null)
{
takeOverBotPanel.RectTransform.SetPosition(Anchor.Center);
GUIMessageBox.MessageBoxes.Add(panelHolder);
}
}
/// <summary>
/// Static because the "take over bot" panel can be accessed outside the death prompt too
/// </summary>
private static GUIComponent? CreateTakeOverBotPanel(GUIComponent parent, DeathPrompt? deathPrompt)
{
if (GameMain.GameSession?.CrewManager == null) { return null; }
if (GameMain.GameSession?.Campaign is not MultiPlayerCampaign campaign) { return null; }
if (campaign.CampaignUI == null) { campaign.InitCampaignUI(); }
var frame = new GUIFrame(new RectTransform(new Vector2(1.0f, 1.0f), parent.RectTransform, Anchor.CenterRight, Pivot.CenterLeft));
takeOverBotPanelFrame = frame;
var content = new GUILayoutGroup(new RectTransform(new Vector2(0.9f, 0.9f), frame.RectTransform, Anchor.Center), isHorizontal: false)
{
Stretch = true,
RelativeSpacing = 0.05f
};
var botList = new GUIListBox(new RectTransform(new Vector2(1.0f, 0.9f), content.RectTransform));
foreach (CharacterInfo c in GetAvailableBots())
{
var characterFrame = campaign.CampaignUI?.CrewManagement.CreateCharacterFrame(c, botList, hideSalary: true);
if (characterFrame != null)
{
characterFrame.UserData = c;
}
}
botList.UpdateScrollBarSize();
var buttonContainer = new GUILayoutGroup(new RectTransform(new Vector2(0.98f, 0.15f), content.RectTransform), isHorizontal: true)
{
RelativeSpacing = 0.05f,
Stretch = true
};
new GUIButton(new RectTransform(new Vector2(0.5f, 1.0f), buttonContainer.RectTransform, Anchor.BottomLeft), TextManager.Get("Cancel"), style: "GUIButtonSmall")
{
OnClicked = (btn, userdata) =>
{
GUIMessageBox.MessageBoxes.Remove(frame.Parent);
frame.Parent?.RemoveChild(frame);
if (deathPrompt != null)
{
deathPrompt.takeOverBotPanel = null;
}
return true;
}
};
new GUIButton(new RectTransform(new Vector2(0.5f, 1.0f), buttonContainer.RectTransform, Anchor.BottomLeft), TextManager.Get("inputtype.select"), style: "GUIButtonSmall")
{
Enabled = false,
OnAddedToGUIUpdateList = (component) =>
{
component.Enabled = botList.SelectedData is CharacterInfo;
},
OnClicked = (btn, userdata) =>
{
if (botList.SelectedData is CharacterInfo selectedCharacter && GameMain.Client is GameClient client)
{
client.SendTakeOverBotRequest(selectedCharacter);
GUIMessageBox.MessageBoxes.Remove(frame.Parent);
deathPrompt?.Close();
return true;
}
else
{
DebugConsole.ThrowError($"Conditions for sending bot takeover request not met");
return false;
}
}
};
if (deathPrompt != null)
{
deathPrompt.takeOverBotPanel = frame;
}
return frame;
}
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));
}
else
{
return Enumerable.Empty<CharacterInfo>();
}
}
private void DrawBackground(SpriteBatch spriteBatch, GUICustomComponent guiCustomComponent)
{
var background = GUIStyle.GetComponentStyle("DeathScreenBackground");
if (background != null)
{
GUI.DrawBackgroundSprite(spriteBatch, background.GetDefaultSprite(), Color.White * (guiCustomComponent.Color.A / 255.0f));
}
}
public void Close()
{
if (GameMain.GameSession != null)
{
GameMain.GameSession.DeathPrompt = null;
}
}
public static void CloseBotPanel()
{
if (takeOverBotPanelFrame is GUIComponent frame)
{
GUIMessageBox.MessageBoxes.Remove(frame.Parent);
frame.Parent?.RemoveChild(frame);
}
takeOverBotPanelFrame = null;
}
}
@@ -717,9 +717,9 @@ namespace Barotrauma
private static readonly Queue<GUIComponent> removals = new Queue<GUIComponent>();
private static readonly Queue<GUIComponent> additions = new Queue<GUIComponent>();
// A helpers list for all elements that have a draw order less than 0.
private static readonly List<GUIComponent> first = new List<GUIComponent>();
private static readonly List<GUIComponent> firstAdditions = new List<GUIComponent>();
// A helper list for all elements that have a draw order greater than 0.
private static readonly List<GUIComponent> last = new List<GUIComponent>();
private static readonly List<GUIComponent> lastAdditions = new List<GUIComponent>();
/// <summary>
/// Adds the component on the addition queue.
@@ -737,11 +737,11 @@ namespace Barotrauma
if (!component.Visible) { return; }
if (component.UpdateOrder < 0)
{
first.Add(component);
firstAdditions.Add(component);
}
else if (component.UpdateOrder > 0)
{
last.Add(component);
lastAdditions.Add(component);
}
else
{
@@ -800,9 +800,9 @@ namespace Barotrauma
RemoveFromUpdateList(component);
}
}
ProcessHelperList(first);
ProcessHelperList(firstAdditions);
ProcessAdditions();
ProcessHelperList(last);
ProcessHelperList(lastAdditions);
ProcessRemovals();
}
}
@@ -897,7 +897,7 @@ namespace Barotrauma
public static IEnumerable<GUIComponent> GetAdditions()
{
return additions;
return additions.Union(firstAdditions).Union(lastAdditions);
}
#endregion
@@ -2171,6 +2171,28 @@ namespace Barotrauma
return frame;
}
public static GUITextBox CreateTextBoxWithPlaceholder(RectTransform rectT, string text, LocalizedString placeholder)
{
var holder = new GUIFrame(rectT, style: null);
var textBox = new GUITextBox(new RectTransform(Vector2.One, holder.RectTransform, Anchor.CenterLeft), text, createClearButton: false);
var placeholderElement = new GUITextBlock(new RectTransform(Vector2.One, holder.RectTransform, Anchor.CenterLeft),
textColor: Color.DarkGray * 0.6f,
text: placeholder,
textAlignment: Alignment.CenterLeft)
{
CanBeFocused = false
};
new GUICustomComponent(new RectTransform(Vector2.Zero, holder.RectTransform),
onUpdate: delegate { placeholderElement.RectTransform.NonScaledSize = textBox.Frame.RectTransform.NonScaledSize; });
textBox.OnSelected += delegate { placeholderElement.Visible = false; };
textBox.OnDeselected += delegate { placeholderElement.Visible = textBox.Text.IsNullOrWhiteSpace(); };
placeholderElement.Visible = string.IsNullOrWhiteSpace(text);
return textBox;
}
public static void NotifyPrompt(LocalizedString header, LocalizedString body)
{
GUIMessageBox msgBox = new GUIMessageBox(header, body, new[] { TextManager.Get("Ok") }, new Vector2(0.2f, 0.175f), minSize: new Point(300, 175));
@@ -815,7 +815,8 @@ namespace Barotrauma
protected virtual void SetAlpha(float a)
{
color = new Color(color.R / 255.0f, color.G / 255.0f, color.B / 255.0f, a);
hoverColor = new Color(hoverColor.R / 255.0f, hoverColor.G / 255.0f, hoverColor.B / 255.0f, a);;
hoverColor = new Color(hoverColor.R / 255.0f, hoverColor.G / 255.0f, hoverColor.B / 255.0f, a);
disabledColor = new Color(disabledColor.R / 255.0f, disabledColor.G / 255.0f, disabledColor.B / 255.0f, a);
}
public virtual void Flash(Color? color = null, float flashDuration = 1.5f, bool useRectangleFlash = false, bool useCircularFlash = false, Vector2? flashRectInflate = null)
@@ -835,15 +836,29 @@ namespace Barotrauma
flashColor = (color == null) ? GUIStyle.Red : (Color)color;
}
public void FadeOut(float duration, bool removeAfter, float wait = 0.0f, Action onRemove = null)
public void FadeOut(float duration, bool removeAfter, float wait = 0.0f, Action onRemove = null, bool alsoChildren = false)
{
CoroutineManager.StartCoroutine(LerpAlpha(0.0f, duration, removeAfter, wait, onRemove));
if (alsoChildren)
{
foreach (var child in Children)
{
child.FadeOut(duration, removeAfter, wait, onRemove, alsoChildren);
}
}
}
public void FadeIn(float wait, float duration)
public void FadeIn(float wait, float duration, bool alsoChildren = false)
{
SetAlpha(0.0f);
CoroutineManager.StartCoroutine(LerpAlpha(1.0f, duration, false, wait));
if (alsoChildren)
{
foreach (var child in Children)
{
child.FadeIn(wait, duration, alsoChildren);
}
}
}
public void SlideIn(float wait, float duration, int amount, SlideDirection direction)
@@ -201,7 +201,7 @@ namespace Barotrauma
}
else if (sprite?.Texture is { IsDisposed: false })
{
spriteBatch.Draw(sprite.Texture, Rect.Center.ToVector2(), sourceRect, currentColor * (currentColor.A / 255.0f), Rotation, origin,
spriteBatch.Draw(sprite.Texture, new Vector2(Rect.X + Rect.Width / 2.0f, Rect.Y + Rect.Height / 2.0f), sourceRect, currentColor * (currentColor.A / 255.0f), Rotation, origin,
Scale, SpriteEffects, 0.0f);
}
@@ -9,7 +9,6 @@ namespace Barotrauma
{
public class GUIMessageBox : GUIFrame
{
#warning TODO: change this to List<GUIMessageBox> and fix incorrect uses of this list
public readonly static List<GUIComponent> MessageBoxes = new List<GUIComponent>();
private static int DefaultWidth
{
@@ -128,7 +128,7 @@ namespace Barotrauma
}
set
{
if (MathUtils.NearlyEqual(value, floatValue)) { return; }
if (Math.Abs(value - floatValue) < 0.0001f && MathUtils.NearlyEqual(value, floatValue)) { return; }
floatValue = value;
ClampFloatValue();
float newValue = floatValue;
@@ -1,5 +1,6 @@
#nullable enable
using System;
using Microsoft.Xna.Framework;
using System.Collections.Generic;
using System.Linq;
@@ -25,6 +26,11 @@ namespace Barotrauma
public delegate void OnValueChangedHandler(GUISelectionCarousel<T> carousel);
public OnValueChangedHandler? OnValueChanged;
/// <summary>
/// Are there some conditions for selecting a particular element?
/// </summary>
public Func<T, bool>? ElementSelectionCondition { get; set; }
public GUITextBlock TextBlock { get; private set; }
@@ -89,35 +95,9 @@ namespace Barotrauma
GUIStyle.Apply(TextBlock, "TextBlock", this);
RightButton = new GUIButton(new RectTransform(new Vector2(0.15f, 1.0f), layoutGroup.RectTransform), style: "GUIButtonToggleRight");
GUIStyle.Apply(RightButton, "RightButton", this);
RightButton.OnClicked += (btn, userData) =>
{
if (elements.Count < 2) { return false; }
if (SelectedElement == null)
{
SelectElement(elements.First());
}
else
{
int newIndex = (elements.IndexOf(SelectedElement) + 1) % elements.Count;
SelectElement(elements[newIndex]);
}
return true;
};
LeftButton.OnClicked += (btn, userData) =>
{
if (elements.Count < 2) { return false; }
if (SelectedElement == null)
{
SelectElement(elements.First());
}
else
{
int newIndex = MathUtils.PositiveModulo((elements.IndexOf(SelectedElement) - 1), elements.Count);
SelectElement(elements[newIndex]);
}
return true;
};
RightButton.OnClicked += (_, _) => SelectNextValidElement();
LeftButton.OnClicked += (_, _) => SelectNextValidElement(directionLeft: true);
if (newElements != null && newElements.Any())
{
@@ -140,9 +120,11 @@ namespace Barotrauma
SelectElement(null);
return;
}
if (elements.FirstOrDefault(e => value.Equals(e.value)) is { } element)
var matchingElement = elements.Where(e => value.Equals(e.value)) // selection is in the set of possible values
.FirstOrDefault(e => ElementSelectionCondition == null || ElementSelectionCondition(e.value)); // selection matches extra conditions, if any
if (matchingElement != null)
{
SelectElement(element);
SelectElement(matchingElement);
}
}
@@ -187,5 +169,42 @@ namespace Barotrauma
SelectElement(newElement);
}
}
/// <summary>
/// Refresh the current selection, for example if there are conditions for which elements are valid, and those might have changed
/// </summary>
public void Refresh()
{
if (SelectedElement != null)
{
if (ElementSelectionCondition == null || ElementSelectionCondition(SelectedElement.value))
{
return;
}
}
SelectElement(elements.FirstOrDefault(e => ElementSelectionCondition == null || ElementSelectionCondition(e.value)));
}
private bool SelectNextValidElement(bool directionLeft = false)
{
if (elements.Count < 2) { return false; }
// Try to find a valid next/previous element
int currentIndex = SelectedElement == null ? -1 : elements.IndexOf(SelectedElement);
int newIndex = currentIndex;
for (int i = 0; i < elements.Count; i++)
{
newIndex = directionLeft ? MathUtils.PositiveModulo((newIndex - 1), elements.Count) : (newIndex + 1) % elements.Count;
if (ElementSelectionCondition == null || ElementSelectionCondition(elements[newIndex].value))
{
SelectElement(elements[newIndex]);
return true;
}
}
// No valid elements found
SelectElement(null);
return true;
}
}
}
@@ -438,8 +438,11 @@ namespace Barotrauma
protected override void SetAlpha(float a)
{
// base.SetAlpha(a);
textColor = new Color(TextColor.R / 255.0f, TextColor.G / 255.0f, TextColor.B / 255.0f, a);
textColor = new Color(TextColor, a);
if (hoverTextColor.HasValue)
{
hoverTextColor = new Color(hoverTextColor.Value, a);
}
}
/// <summary>
@@ -2108,13 +2108,13 @@ namespace Barotrauma
deliveryPrompt.Buttons[0].OnClicked = (btn, userdata) =>
{
ConfirmPurchase(deliverImmediately: true);
deliveryPrompt.Close();
deliveryPrompt?.Close();
return true;
};
deliveryPrompt.Buttons[1].OnClicked = (btn, userdata) =>
{
ConfirmPurchase(deliverImmediately: false);
deliveryPrompt.Close();
deliveryPrompt?.Close();
return true;
};
}
@@ -742,8 +742,8 @@ namespace Barotrauma
private (LocalizedString header, LocalizedString body) GetItemTransferWarningText()
{
var header = TextManager.Get("itemtransferheader").Fallback("lowfuelheader");
var body = TextManager.Get("itemtransferwarning").Fallback("lowfuelwarning");
var header = TextManager.Get("itemtransferheader").Fallback("lowfuelheader", useDefaultLanguageIfFound: false);
var body = TextManager.Get("itemtransferwarning").Fallback("lowfuelwarning", useDefaultLanguageIfFound: false);
return (header, body);
}
@@ -320,7 +320,61 @@ namespace Barotrauma
var reputationButton = createTabButton(InfoFrameTab.Reputation, "reputation");
var balanceFrame = new GUIFrame(new RectTransform(new Point(innerLayoutGroup.Rect.Width, innerLayoutGroup.Rect.Height - infoFrameHolderHeight), parent: innerLayoutGroup.RectTransform), style: "InnerFrame");
GUITextBlock balanceText = new GUITextBlock(new RectTransform(Vector2.One, balanceFrame.RectTransform), string.Empty, textAlignment: Alignment.Right);
GUILayoutGroup salaryFrame = new GUILayoutGroup(new RectTransform(new Vector2(0.66f, 1f), balanceFrame.RectTransform), isHorizontal: true, childAnchor: Anchor.CenterLeft);
GUIScrollBar salaryScrollBar = null;
GUITextBlock salaryPercentage = null;
if (GameMain.GameSession?.GameMode is MultiPlayerCampaign)
{
float value = campaignMode.Bank.RewardDistribution;
GUITextBlock salaryText = new GUITextBlock(new RectTransform(new Vector2(0.25f, 1f), salaryFrame.RectTransform), TextManager.Get("defaultsalary"), textAlignment: Alignment.Center)
{
AutoScaleHorizontal = true
};
salaryScrollBar = new GUIScrollBar(new RectTransform(new Vector2(0.4f, 1f), salaryFrame.RectTransform), barSize: 0.1f, style: "GUISlider")
{
Range = new Vector2(0, 1),
BarScrollValue = value / 100f,
Step = 0.01f,
BarSize = 0.1f,
};
salaryPercentage = new GUITextBlock(new RectTransform(new Vector2(0.15f, 1f), salaryFrame.RectTransform), "0", textAlignment: Alignment.Center)
{
Text = ValueToPercentage(RoundRewardDistribution(salaryScrollBar.BarScroll, salaryScrollBar.Step))
};
salaryScrollBar.OnMoved = (scrollBar, value) =>
{
salaryPercentage.Text = ValueToPercentage(RoundRewardDistribution(value, scrollBar.Step));
return true;
};
salaryScrollBar.OnReleased = (bar, scroll) =>
{
int newRewardDistribution = RoundRewardDistribution(scroll, bar.Step);
SetRewardDistribution(Option.None, newRewardDistribution);
return true;
};
var resetButton = new GUIButton(new RectTransform(new Vector2(0.2f, 1f), salaryFrame.RectTransform), TextManager.Get("ResetSalaries"), style: "GUIButtonSmall")
{
TextBlock = { AutoScaleHorizontal = true },
ToolTip = TextManager.Get("resetsalaries.tooltip"),
OnClicked = (button, userData) =>
{
GUI.AskForConfirmation(TextManager.Get("ResetSalaries"), TextManager.Get("ResetSalaries.Warning"), onConfirm: ResetRewardDistributions);
return true;
}
};
void UpdateSliderEnabled()
=> salaryScrollBar.Enabled = resetButton.Enabled = CampaignMode.AllowedToManageWallets();
UpdateSliderEnabled();
Identifier defaultSalaryEventIdentifier = "DefaultSalarySlider".ToIdentifier();
GameMain.Client?.OnPermissionChanged?.RegisterOverwriteExisting(defaultSalaryEventIdentifier, _ => UpdateSliderEnabled());
}
GUITextBlock balanceText = new GUITextBlock(new RectTransform(new Vector2(0.33f, 1f), balanceFrame.RectTransform, Anchor.TopRight), string.Empty, textAlignment: Alignment.Right);
if (GameMain.IsMultiplayer)
{
balanceText.ToolTip = TextManager.Get("bankdescription");
@@ -343,6 +397,13 @@ namespace Barotrauma
{
if (!e.Owner.IsNone()) { return; }
SetBalanceText(balanceText, e.Wallet.Balance);
if (salaryPercentage is not null && salaryScrollBar is not null)
{
float rewardDistribution = e.Wallet.RewardDistribution;
salaryScrollBar.BarScrollValue = rewardDistribution / 100f;
salaryPercentage.Text = ValueToPercentage(rewardDistribution);
}
});
registeredEvents.Add(eventIdentifier);
@@ -350,6 +411,9 @@ namespace Barotrauma
{
text.Text = TextManager.GetWithVariable("bankbalanceformat", "[money]", string.Format(CultureInfo.InvariantCulture, "{0:N0}", balance));
}
LocalizedString ValueToPercentage(float value)
=> TextManager.GetWithVariable("percentageformat", "[value]", $"{(int)MathF.Round(value)}");
}
var submarineButton = createTabButton(InfoFrameTab.Submarine, "submarine");
@@ -1037,11 +1101,10 @@ namespace Barotrauma
{
int newRewardDistribution = RoundRewardDistribution(scroll, bar.Step);
if (newRewardDistribution == targetWallet.RewardDistribution) { return false; }
SetRewardDistribution(character, newRewardDistribution);
SetRewardDistribution(Option.Some(character), newRewardDistribution);
return true;
}
};
int RoundRewardDistribution(float scroll, float step) => (int)MathUtils.RoundTowardsClosest(scroll * 100, step * 100);
SetRewardText(targetWallet.RewardDistribution, rewardBlock);
@@ -1201,6 +1264,7 @@ namespace Barotrauma
{
moneyBlock.Text = TextManager.FormatCurrency(e.Info.Balance);
salarySlider.BarScrollValue = e.Info.RewardDistribution / 100f;
SetRewardText(e.Info.RewardDistribution, rewardBlock);
}
UpdateAllInputs();
@@ -1311,20 +1375,29 @@ namespace Barotrauma
transfer.Write(msg);
GameMain.Client?.ClientPeer?.Send(msg, DeliveryMethod.Reliable);
}
static void SetRewardDistribution(Character character, int newValue)
{
INetSerializableStruct transfer = new NetWalletSetSalaryUpdate
{
Target = character.ID,
NewRewardDistribution = newValue
};
IWriteMessage msg = new WriteOnlyMessage().WithHeader(ClientPacketHeader.REWARD_DISTRIBUTION);
transfer.Write(msg);
GameMain.Client?.ClientPeer?.Send(msg, DeliveryMethod.Reliable);
}
}
static void SetRewardDistribution(Option<Character> character, int newValue)
{
INetSerializableStruct transfer = new NetWalletSetSalaryUpdate
{
Target = character.Select(c => c.ID),
NewRewardDistribution = newValue
};
IWriteMessage msg = new WriteOnlyMessage().WithHeader(ClientPacketHeader.REWARD_DISTRIBUTION);
transfer.Write(msg);
GameMain.Client?.ClientPeer?.Send(msg, DeliveryMethod.Reliable);
}
static void ResetRewardDistributions()
{
IWriteMessage msg = new WriteOnlyMessage().WithHeader(ClientPacketHeader.RESET_REWARD_DISTRIBUTION);
GameMain.Client?.ClientPeer?.Send(msg, DeliveryMethod.Reliable);
}
static int RoundRewardDistribution(float scroll, float step)
=> (int)MathUtils.RoundTowardsClosest(scroll * 100, step * 100);
private GUIComponent CreateClientInfoFrame(GUIFrame frame, Client client, Sprite permissionIcon = null)
{
GUIComponent paddedFrame;
@@ -133,43 +133,47 @@ namespace Barotrauma
GUIFrame containerFrame = new GUIFrame(new RectTransform(new Vector2(1f, 0.9f), characterLayout.RectTransform), style: null);
GUILayoutGroup playerFrame = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.9f), containerFrame.RectTransform, Anchor.TopCenter));
GameMain.NetLobbyScreen.CreatePlayerFrame(playerFrame, alwaysAllowEditing: true, createPendingText: false);
GUIButton newCharacterBox = new GUIButton(new RectTransform(new Vector2(0.5f, 0.2f), skillLayout.RectTransform, Anchor.BottomRight),
text: GameMain.NetLobbyScreen.CampaignCharacterDiscarded ? TextManager.Get("settings") : TextManager.Get("createnew"), style: "GUIButtonSmall")
// TODO: What is CampaignCharacterDiscarded and can it be relevant in permadeath mode?
if (!GameMain.NetLobbyScreen.PermadeathMode)
{
IgnoreLayoutGroups = false,
TextBlock =
GUIButton newCharacterBox = new GUIButton(new RectTransform(new Vector2(0.5f, 0.2f), skillLayout.RectTransform, Anchor.BottomRight),
text: GameMain.NetLobbyScreen.CampaignCharacterDiscarded ? TextManager.Get("settings") : TextManager.Get("createnew"), style: "GUIButtonSmall")
{
AutoScaleHorizontal = true
}
};
newCharacterBox.OnClicked = (button, o) =>
{
if (!GameMain.NetLobbyScreen.CampaignCharacterDiscarded)
{
GameMain.NetLobbyScreen.TryDiscardCampaignCharacter(() =>
IgnoreLayoutGroups = false,
TextBlock =
{
newCharacterBox.Text = TextManager.Get("settings");
if (TabMenu.PendingChangesFrame != null)
{
NetLobbyScreen.CreateChangesPendingFrame(TabMenu.PendingChangesFrame);
}
AutoScaleHorizontal = true
}
};
OpenMenu();
});
return true;
}
OpenMenu();
return true;
void OpenMenu()
newCharacterBox.OnClicked = (button, o) =>
{
characterSettingsFrame!.Visible = true;
content.Visible = false;
}
};
if (!GameMain.NetLobbyScreen.CampaignCharacterDiscarded)
{
GameMain.NetLobbyScreen.TryDiscardCampaignCharacter(() =>
{
newCharacterBox.Text = TextManager.Get("settings");
if (TabMenu.PendingChangesFrame != null)
{
NetLobbyScreen.CreateChangesPendingFrame(TabMenu.PendingChangesFrame);
}
OpenMenu();
});
return true;
}
OpenMenu();
return true;
void OpenMenu()
{
characterSettingsFrame!.Visible = true;
content.Visible = false;
}
};
}
GUILayoutGroup characterCloseButtonLayout = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.1f), characterLayout.RectTransform), childAnchor: Anchor.BottomCenter);
new GUIButton(new RectTransform(new Vector2(0.4f, 1f), characterCloseButtonLayout.RectTransform), TextManager.Get("ApplySettingsButton")) //TODO: Is this text appropriate for this circumstance for all languages?
@@ -177,6 +181,7 @@ namespace Barotrauma
OnClicked = (button, o) =>
{
GameMain.Client?.SendCharacterInfo(GameMain.Client.PendingName);
GameMain.NetLobbyScreen.CampaignCharacterDiscarded = false;
characterSettingsFrame.Visible = false;
content.Visible = true;
return true;
@@ -773,7 +773,7 @@ namespace Barotrauma
subItems ??= GetSubItems();
return subItems.Any(i =>
i.Prefab.SwappableItem != null &&
!i.HiddenInGame && i.AllowSwapping &&
!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)));
}
@@ -876,7 +876,7 @@ namespace Barotrauma
{
parent.Content.ClearChildren();
currentUpgradeCategory = category;
var entitiesOnSub = submarine.GetItems(true).Where(i => submarine.IsEntityFoundOnThisSub(i, true) && !i.HiddenInGame && i.AllowSwapping && i.Prefab.SwappableItem != null && category.ItemTags.Any(t => i.HasTag(t))).ToList();
var entitiesOnSub = submarine.GetItems(true).Where(i => submarine.IsEntityFoundOnThisSub(i, true) && !i.IsHidden && i.AllowSwapping && i.Prefab.SwappableItem != null && category.ItemTags.Any(t => i.HasTag(t))).ToList();
foreach (Item item in entitiesOnSub)
{
@@ -115,7 +115,6 @@ namespace Barotrauma
if (IsMouseOver || (!RequireMouseOn && SelectedWidgets.Contains(this) && PlayerInput.PrimaryMouseButtonHeld()))
{
Hovered?.Invoke();
System.Diagnostics.Debug.WriteLine("hovered");
if (RequireMouseOn || PlayerInput.PrimaryMouseButtonDown())
{
if ((multiselect && !SelectedWidgets.Contains(this)) || SelectedWidgets.None())