2 using System.Collections.Generic;
3 using System.Collections.Immutable;
4 using Microsoft.Xna.Framework;
5 using Microsoft.Xna.Framework.Graphics;
8 using System.Globalization;
17 private static bool initialized =
false;
19 private static UISprite spectateIcon, disconnectedIcon;
20 private static Sprite ownerIcon, moderatorIcon;
24 private GUIFrame infoFrame, contentFrame;
26 private readonly List<GUIButton> tabButtons =
new List<GUIButton>();
28 private List<LinkedGUI> linkedGUIList;
31 private float sizeMultiplier = 1f;
33 private IEnumerable<Character> crew;
34 private List<CharacterTeamType> teamIDs;
35 private const string inLobbyString =
"\u2022 \u2022 \u2022";
40 private bool isTransferMenuOpen;
41 private bool isSending;
44 private float transferMenuOpenState;
45 private bool transferMenuStateCompleted;
46 private readonly HashSet<Identifier> registeredEvents =
new HashSet<Identifier>();
47 private readonly TalentMenu talentMenu =
new TalentMenu();
49 private class LinkedGUI
51 private const ushort lowPingThreshold = 100;
52 private const ushort mediumPingThreshold = 200;
56 private ushort currentPing;
58 private readonly
bool wasCharacterAlive;
62 private readonly
GUIImage permissionIcon;
67 this.textBlock = textBlock;
69 this.permissionIcon = permissionIcon;
76 this.character = character;
77 this.textBlock = textBlock;
79 wasCharacterAlive = character !=
null && !character.
IsDead;
82 public bool HasMultiplayerCharacterChanged()
84 if (
Client ==
null) {
return false; }
86 if (GameSettings.CurrentConfig.VerboseLogging)
90 DebugConsole.Log($
"Refreshing tab menu crew list (client \"{Client.Name}\"'s character changed from \"{character?.Name ?? "null"}\" to \"{Client.Character?.Name ?? "null"}\")");
96 public bool HasCharacterDied()
98 if (character ==
null) {
return false; }
99 bool isAlive = !(character?.IsDead ??
true);
100 if (GameSettings.CurrentConfig.VerboseLogging)
102 if (wasCharacterAlive && !isAlive)
104 DebugConsole.Log(
Client ==
null ?
105 $
"Refreshing tab menu crew list (character \"{character?.Name ?? "null"}\" died)" :
106 $
"Refreshing tab menu crew list (client \"{Client.Name}\"'s character \"{character?.Name ?? "null"}\" died)");
108 else if (!wasCharacterAlive && isAlive)
110 DebugConsole.Log(
Client ==
null ?
112 $
"Refreshing tab menu crew list (character \"{character?.Name ?? "null"}\" came back to life)" :
113 $
"Refreshing tab menu crew list (client \"{Client.Name}\"'s character \"{character?.Name ?? "null"}\" came back to life)");
116 return isAlive != wasCharacterAlive;
119 public void TryPingRefresh()
121 if (
Client ==
null) {
return; }
124 textBlock.Text = currentPing.ToString();
125 textBlock.TextColor = GetPingColor();
128 public void TryPermissionIconRefresh(Sprite icon)
130 if (
Client ==
null || permissionIcon ==
null) {
return; }
131 permissionIcon.Sprite = icon;
134 private Color GetPingColor()
136 if (currentPing < lowPingThreshold)
138 return GUIStyle.Green;
140 else if (currentPing < mediumPingThreshold)
142 return GUIStyle.Yellow;
150 public void Remove(GUIFrame parent)
152 parent.RemoveChild(frame);
160 ownerIcon = GUIStyle.GetComponentStyle(
"OwnerIcon").GetDefaultSprite();
161 moderatorIcon = GUIStyle.GetComponentStyle(
"ModeratorIcon").GetDefaultSprite();
179 float menuOpenSpeed = deltaTime * 10f;
180 if (isTransferMenuOpen)
182 if (transferMenuStateCompleted)
184 transferMenuOpenState = transferMenuOpenState < 0.25f ? Math.Min(0.25f, transferMenuOpenState + (menuOpenSpeed / 2f)) : 0.25f;
188 if (transferMenuOpenState > 0.15f)
190 transferMenuStateCompleted =
false;
191 transferMenuOpenState = Math.Max(0.15f, transferMenuOpenState - menuOpenSpeed);
195 transferMenuStateCompleted =
true;
201 transferMenuStateCompleted =
false;
202 if (transferMenuOpenState < 1f)
204 transferMenuOpenState = Math.Min(1f, transferMenuOpenState + menuOpenSpeed);
208 if (transferMenu !=
null && transferMenuButton !=
null)
210 int pos = (int)(transferMenuOpenState * -transferMenu.
Rect.Height);
216 talentMenu?.Update();
219 if (linkedGUIList ==
null) {
return; }
223 for (
int i = 0; i < linkedGUIList.Count; i++)
225 linkedGUIList[i].TryPingRefresh();
226 linkedGUIList[i].TryPermissionIconRefresh(GetPermissionIcon(linkedGUIList[i].
Client));
227 if (linkedGUIList[i].HasMultiplayerCharacterChanged() || linkedGUIList[i].HasCharacterDied())
229 RemoveCurrentElements();
230 CreateMultiPlayerList(
true);
237 for (
int i = 0; i < linkedGUIList.Count; i++)
239 if (linkedGUIList[i].HasCharacterDied())
241 RemoveCurrentElements();
242 CreateSinglePlayerList(
true);
257 storedMessages.Clear();
270 Vector2 contentFrameSize =
new Vector2(0.45f, 0.667f);
275 RelativeSpacing = 0.01f
278 var buttonArea =
new GUILayoutGroup(
new RectTransform(
new Vector2(0.07f, 1f), parent: horizontalLayoutGroup.RectTransform), isHorizontal:
false)
280 AbsoluteSpacing = GUI.IntScale(5f)
282 var innerLayoutGroup =
new GUILayoutGroup(
new RectTransform(
new Vector2(0.92f, 1f), horizontalLayoutGroup.RectTransform))
284 RelativeSpacing = 0.01f,
288 float absoluteSpacing = innerLayoutGroup.
RelativeSpacing * innerLayoutGroup.Rect.Height;
289 int multiplier = GameMain.GameSession?.GameMode is CampaignMode ? 2 : 1;
290 int infoFrameHolderHeight = Math.Min((
int)(0.97f * innerLayoutGroup.Rect.Height), (
int)(innerLayoutGroup.Rect.Height - multiplier * (GUI.IntScale(15f) + absoluteSpacing)));
291 infoFrameHolder =
new GUIFrame(
new RectTransform(
new Point(innerLayoutGroup.Rect.Width, infoFrameHolderHeight), parent: innerLayoutGroup.RectTransform), style:
null);
293 GUIButton createTabButton(
InfoFrameTab tab,
string textTag)
295 var newButton =
new GUIButton(
new RectTransform(Vector2.One, buttonArea.RectTransform, scaleBasis:
ScaleBasis.BothWidth), style: $
"InfoFrameTabButton.{tab}")
298 ToolTip = TextManager.Get(textTag),
301 tabButtons.Add(newButton);
305 var crewButton = createTabButton(
InfoFrameTab.Crew,
"crew");
307 if (GameMain.GameSession?.GameMode is not TestGameMode)
309 var missionBtn = createTabButton(
InfoFrameTab.Mission,
"mission");
310 eventLogNotification = GameSession.CreateNotificationIcon(missionBtn);
311 eventLogNotification.
Visible = GameMain.GameSession?.EventManager?.EventLog?.UnreadEntries ??
false;
312 if (eventLogNotification.
Visible)
314 eventLogNotification.
Pulsate(Vector2.One, Vector2.One * 2, 1.0f);
318 if (GameMain.GameSession?.GameMode is CampaignMode campaignMode)
320 var reputationButton = createTabButton(
InfoFrameTab.Reputation,
"reputation");
322 var balanceFrame =
new GUIFrame(
new RectTransform(
new Point(innerLayoutGroup.Rect.Width, innerLayoutGroup.Rect.Height - infoFrameHolderHeight), parent: innerLayoutGroup.RectTransform), style:
"InnerFrame");
323 GUILayoutGroup salaryFrame =
new GUILayoutGroup(
new RectTransform(
new Vector2(0.66f, 1f), balanceFrame.RectTransform), isHorizontal:
true, childAnchor:
Anchor.CenterLeft);
325 GUIScrollBar salaryScrollBar =
null;
326 GUITextBlock salaryPercentage =
null;
327 if (GameMain.GameSession?.GameMode is MultiPlayerCampaign)
329 float value = campaignMode.Bank.RewardDistribution;
330 GUITextBlock salaryText =
new GUITextBlock(
new RectTransform(
new Vector2(0.25f, 1f), salaryFrame.RectTransform), TextManager.Get(
"defaultsalary"), textAlignment: Alignment.Center)
332 AutoScaleHorizontal =
true
334 salaryScrollBar =
new GUIScrollBar(
new RectTransform(
new Vector2(0.4f, 1f), salaryFrame.RectTransform), barSize: 0.1f, style:
"GUISlider")
336 Range =
new Vector2(0, 1),
337 BarScrollValue = value / 100f,
342 salaryPercentage =
new GUITextBlock(
new RectTransform(
new Vector2(0.15f, 1f), salaryFrame.RectTransform),
"0", textAlignment: Alignment.Center)
344 Text = ValueToPercentage(RoundRewardDistribution(salaryScrollBar.BarScroll, salaryScrollBar.Step))
347 salaryScrollBar.OnMoved = (scrollBar, value) =>
349 salaryPercentage.Text = ValueToPercentage(RoundRewardDistribution(value, scrollBar.Step));
352 salaryScrollBar.OnReleased = (bar, scroll) =>
354 int newRewardDistribution = RoundRewardDistribution(scroll, bar.Step);
355 SetRewardDistribution(Option.None, newRewardDistribution);
359 var resetButton =
new GUIButton(
new RectTransform(
new Vector2(0.2f, 1f), salaryFrame.RectTransform), TextManager.Get(
"ResetSalaries"), style:
"GUIButtonSmall")
361 TextBlock = { AutoScaleHorizontal =
true },
362 ToolTip = TextManager.Get(
"resetsalaries.tooltip"),
363 OnClicked = (button, userData) =>
365 GUI.AskForConfirmation(TextManager.Get(
"ResetSalaries"), TextManager.Get(
"ResetSalaries.Warning"), onConfirm: ResetRewardDistributions);
370 void UpdateSliderEnabled()
371 => salaryScrollBar.Enabled = resetButton.Enabled = CampaignMode.AllowedToManageWallets();
372 UpdateSliderEnabled();
374 Identifier defaultSalaryEventIdentifier =
"DefaultSalarySlider".ToIdentifier();
375 GameMain.Client?.OnPermissionChanged?.RegisterOverwriteExisting(defaultSalaryEventIdentifier, _ => UpdateSliderEnabled());
377 GUITextBlock balanceText =
new GUITextBlock(
new RectTransform(
new Vector2(0.33f, 1f), balanceFrame.RectTransform,
Anchor.TopRight),
string.Empty, textAlignment: Alignment.Right);
378 if (GameMain.IsMultiplayer)
380 balanceText.ToolTip = TextManager.Get(
"bankdescription");
382 GUIFrame bottomDisclaimerFrame =
new GUIFrame(
new RectTransform(
new Vector2(contentFrameSize.X, 0.1f), infoFrame.
RectTransform)
384 AbsoluteOffset = new Point(contentFrame.Rect.X, contentFrame.Rect.Bottom + GUI.IntScale(8))
387 PendingChangesFrame =
new GUIFrame(
new RectTransform(Vector2.One, bottomDisclaimerFrame.RectTransform,
Anchor.Center), style:
null);
389 if (GameMain.NetLobbyScreen?.CampaignCharacterDiscarded ??
false)
394 SetBalanceText(balanceText, campaignMode.Bank.Balance);
395 Identifier eventIdentifier = nameof(CreateInfoFrame).ToIdentifier();
396 campaignMode.OnMoneyChanged.RegisterOverwriteExisting(eventIdentifier, e =>
398 if (!e.Owner.IsNone()) { return; }
399 SetBalanceText(balanceText, e.Wallet.Balance);
401 if (salaryPercentage is not
null && salaryScrollBar is not
null)
403 float rewardDistribution = e.Wallet.RewardDistribution;
404 salaryScrollBar.BarScrollValue = rewardDistribution / 100f;
405 salaryPercentage.Text = ValueToPercentage(rewardDistribution);
408 registeredEvents.Add(eventIdentifier);
410 static void SetBalanceText(GUITextBlock text,
int balance)
412 text.Text = TextManager.GetWithVariable(
"bankbalanceformat",
"[money]",
string.Format(CultureInfo.InvariantCulture,
"{0:N0}", balance));
415 LocalizedString ValueToPercentage(
float value)
416 => TextManager.GetWithVariable(
"percentageformat",
"[value]", $
"{(int)MathF.Round(value)}");
424 var talentsButton = createTabButton(
InfoFrameTab.Talents,
"tabmenu.character");
425 talentsButton.OnAddedToGUIUpdateList += (component) =>
427 talentsButton.Enabled =
Character.Controlled?.Info !=
null || GameMain.Client?.CharacterInfo !=
null;
428 if (!talentsButton.Enabled && selectedTab ==
InfoFrameTab.Talents)
434 talentPointNotification = GameSession.CreateNotificationIcon(talentsButton);
441 CreateInfoFrame(selectedTab);
442 tabButtons.ForEach(tb => tb.Selected = (
InfoFrameTab)tb.UserData == selectedTab);
447 CreateCrewListFrame(infoFrameHolder);
450 CreateMissionInfo(infoFrameHolder);
469 private const float JobColumnWidthPercentage = 0.138f,
470 CharacterColumnWidthPercentage = 0.45f,
471 KillColumnWidthPercentage = 0.1f,
472 DeathColumnWidthPercentage = 0.1f,
473 PingColumnWidthPercentage = 0.15f,
474 WalletColumnWidthPercentage = 0.206f;
476 private int jobColumnWidth, characterColumnWidth, pingColumnWidth, walletColumnWidth, deathColumnWidth, killColumnWidth;
478 private void CreateCrewListFrame(
GUIFrame crewFrame)
481 teamIDs = crew.Select(c => c.TeamID).Distinct().ToList();
484 if (teamIDs.Count > 1 && GameMain.Client?.Character !=
null)
487 teamIDs = teamIDs.OrderBy(i => i != ownTeam).ThenBy(i => i).ToList();
492 var content =
new GUILayoutGroup(
new RectTransform(Vector2.One, crewFrame.
RectTransform));
494 crewListArray =
new GUIListBox[teamIDs.Count];
495 GUILayoutGroup[] headerFrames =
new GUILayoutGroup[teamIDs.Count];
497 float nameHeight = 0.075f;
499 Vector2 crewListSize =
new Vector2(1f, 1f / teamIDs.Count - (teamIDs.Count > 1 ? nameHeight * 1.1f : 0f));
500 for (
int i = 0; i < teamIDs.Count; i++)
502 if (teamIDs.Count > 1)
504 var nameText =
new GUITextBlock(
new RectTransform(
new Vector2(1.0f, nameHeight), content.RectTransform), CombatMission.GetTeamName(teamIDs[i]), textColor: CombatMission.GetTeamColor(teamIDs[i]))
508 var teamIcon =
new GUIImage(
new RectTransform(Vector2.One, nameText.RectTransform,
Anchor.CenterLeft, scaleBasis:
ScaleBasis.BothHeight),
509 style: teamIDs[i] ==
CharacterTeamType.Team2 ?
"SeparatistIcon" :
"CoalitionIcon")
511 Color = nameText.TextColor
513 nameText.Padding =
new Vector4(teamIcon.Rect.Width + nameText.Padding.X, nameText.Padding.Y, nameText.Padding.Z, nameText.Padding.W);
516 headerFrames[i] =
new GUILayoutGroup(
new RectTransform(Vector2.Zero, content.RectTransform,
Anchor.TopLeft,
Pivot.BottomLeft) { AbsoluteOffset = new Point(2, -1) }, isHorizontal:
true)
523 GUIListBox crewList =
new GUIListBox(
new RectTransform(crewListSize, content.RectTransform))
525 Padding =
new Vector4(2, 5, 0, 0),
526 AutoHideScrollBar =
false,
527 PlaySoundOnSelect =
true
529 crewList.UpdateDimensions();
531 if (teamIDs.Count > 1)
533 crewList.OnSelected = (component, obj) =>
535 for (
int i = 0; i < crewListArray.Length; i++)
537 if (crewListArray[i] == crewList)
continue;
540 SelectElement(component.UserData, crewList);
546 crewList.OnSelected = (component, obj) =>
548 SelectElement(component.UserData, crewList);
553 crewListArray[i] = crewList;
556 for (
int i = 0; i < teamIDs.Count; i++)
558 headerFrames[i].
RectTransform.
RelativeSize =
new Vector2(1f - crewListArray[i].ScrollBar.Rect.Width / (
float)crewListArray[i].Rect.Width, GUIStyle.HotkeyFont.Size / (
float)crewFrame.
RectTransform.
Rect.Height * 1.5f);
560 if (!GameMain.IsMultiplayer)
562 CreateSinglePlayerListContentHolder(headerFrames[i]);
566 CreateMultiPlayerListContentHolder(headerFrames[i]);
570 crewFrame.
RectTransform.
AbsoluteOffset =
new Point(0, (
int)(headerFrames[0].Rect.Height * headerFrames.Length) - (teamIDs.Count > 1 ? GUI.IntScale(10f) : 0));
572 float totalRelativeHeight = 0.0f;
573 if (teamIDs.Count > 1) { totalRelativeHeight += teamIDs.Count * nameHeight; }
574 headerFrames.ForEach(f => totalRelativeHeight += f.RectTransform.RelativeSize.Y);
575 crewListArray.ForEach(f => totalRelativeHeight += f.RectTransform.RelativeSize.Y);
576 if (totalRelativeHeight > 1.0f)
578 float heightOverflow = totalRelativeHeight - 1.0f;
579 float heightToReduce = heightOverflow / crewListArray.Length;
580 crewListArray.ForEach(l =>
582 l.RectTransform.Resize(l.RectTransform.RelativeSize -
new Vector2(0.0f, heightToReduce));
583 l.UpdateDimensions();
587 if (GameMain.IsMultiplayer)
589 CreateMultiPlayerList(
false);
590 CreateMultiPlayerLogContent(crewFrame);
594 CreateSinglePlayerList(
false);
598 private void CreateSinglePlayerListContentHolder(GUILayoutGroup headerFrame)
600 GUIButton jobButton =
new GUIButton(
new RectTransform(
new Vector2(0f, 1f), headerFrame.RectTransform), TextManager.Get(
"tabmenu.job"), style:
"GUIButtonSmallFreeScale");
601 GUIButton characterButton =
new GUIButton(
new RectTransform(
new Vector2(0f, 1f), headerFrame.RectTransform), TextManager.Get(
"name"), style:
"GUIButtonSmallFreeScale");
603 sizeMultiplier = (headerFrame.Rect.Width - headerFrame.AbsoluteSpacing * (headerFrame.CountChildren - 1)) / (float)headerFrame.Rect.Width;
605 jobButton.RectTransform.RelativeSize =
new Vector2(JobColumnWidthPercentage * sizeMultiplier, 1f);
606 characterButton.RectTransform.RelativeSize =
new Vector2((1f - JobColumnWidthPercentage * sizeMultiplier) * sizeMultiplier, 1f);
608 jobButton.TextBlock.Font = characterButton.TextBlock.Font = GUIStyle.HotkeyFont;
609 jobButton.CanBeFocused = characterButton.CanBeFocused =
false;
610 jobButton.TextBlock.ForceUpperCase = characterButton.TextBlock.ForceUpperCase =
ForceUpperCase.Yes;
612 jobColumnWidth = jobButton.Rect.Width;
613 characterColumnWidth = characterButton.Rect.Width;
616 private void CreateSinglePlayerList(
bool refresh)
620 crew = GameMain.GameSession.CrewManager.GetCharacters();
623 linkedGUIList =
new List<LinkedGUI>();
625 for (
int i = 0; i < teamIDs.Count; i++)
627 foreach (Character character
in crew.Where(c => c.TeamID == teamIDs[i]))
629 CreateSinglePlayerCharacterElement(character, i);
634 private void CreateSinglePlayerCharacterElement(Character character,
int i)
636 GUIFrame frame =
new GUIFrame(
new RectTransform(
new Point(crewListArray[i].Content.Rect.Width, GUI.IntScale(33f)), crewListArray[i].Content.RectTransform), style:
"ListBoxElement")
638 UserData = character,
642 var paddedFrame =
new GUILayoutGroup(
new RectTransform(
new Vector2(1.0f, 0.9f), frame.RectTransform,
Anchor.Center), isHorizontal:
true)
648 new GUICustomComponent(
new RectTransform(
new Point(jobColumnWidth, paddedFrame.Rect.Height), paddedFrame.RectTransform,
Anchor.Center), onDraw: (sb, component) => character.Info.DrawJobIcon(sb, component.Rect))
650 CanBeFocused =
false,
651 HoverColor = Color.White,
652 SelectedColor = Color.White
655 GUITextBlock characterNameBlock =
new GUITextBlock(
new RectTransform(
new Point(characterColumnWidth, paddedFrame.Rect.Height), paddedFrame.RectTransform),
656 ToolBox.LimitString(character.Info.Name, GUIStyle.Font, characterColumnWidth), textAlignment: Alignment.Center, textColor: character.Info.Job.Prefab.UIColor);
658 paddedFrame.Recalculate();
660 linkedGUIList.Add(
new LinkedGUI(character, frame, textBlock:
null));
663 private void CreateMultiPlayerListContentHolder(GUILayoutGroup headerFrame)
665 bool isCampaign = GameMain.GameSession?.Campaign is MultiPlayerCampaign;
666 GUIButton jobButton =
new GUIButton(
new RectTransform(
new Vector2(JobColumnWidthPercentage, 1f), headerFrame.RectTransform), TextManager.Get(
"tabmenu.job"), style:
"GUIButtonSmallFreeScale");
667 GUIButton characterButton =
new GUIButton(
new RectTransform(
new Vector2(CharacterColumnWidthPercentage, 1f), headerFrame.RectTransform), TextManager.Get(
"name"), style:
"GUIButtonSmallFreeScale");
669 if (GameMain.GameSession?.GameMode is PvPMode)
671 var killButton =
new GUIButton(
new RectTransform(
new Vector2(KillColumnWidthPercentage, 1f), headerFrame.RectTransform), TextManager.Get(
"killcount"), style:
"GUIButtonSmallFreeScale");
672 killColumnWidth = killButton.Rect.Width;
673 var deathButton =
new GUIButton(
new RectTransform(
new Vector2(DeathColumnWidthPercentage, 1f), headerFrame.RectTransform), TextManager.Get(
"deathcount"), style:
"GUIButtonSmallFreeScale");
674 deathColumnWidth = deathButton.Rect.Width;
677 GUIButton pingButton =
new GUIButton(
new RectTransform(
new Vector2(PingColumnWidthPercentage, 1f), headerFrame.RectTransform), TextManager.Get(
"serverlistping"), style:
"GUIButtonSmallFreeScale");
680 GUIButton walletButton =
new GUIButton(
new RectTransform(
new Vector2(WalletColumnWidthPercentage, 1f), headerFrame.RectTransform), TextManager.Get(
"crewwallet.wallet"), style:
"GUIButtonSmallFreeScale")
682 TextBlock = { Font = GUIStyle.HotkeyFont },
683 CanBeFocused =
false,
686 walletColumnWidth = walletButton.Rect.Width;
689 foreach (var btn
in headerFrame.GetAllChildren<GUIButton>())
691 btn.TextBlock.Font = GUIStyle.HotkeyFont;
692 btn.CanBeFocused =
false;
696 jobColumnWidth = jobButton.Rect.Width;
697 characterColumnWidth = characterButton.Rect.Width;
698 pingColumnWidth = pingButton.Rect.Width;
701 private void CreateMultiPlayerList(
bool refresh)
705 crew = GameMain.GameSession.CrewManager.GetCharacters();
708 linkedGUIList =
new List<LinkedGUI>();
710 var connectedClients = GameMain.Client.ConnectedClients;
712 for (
int i = 0; i < teamIDs.Count; i++)
714 foreach (Character character
in crew.Where(c => c.TeamID == teamIDs[i]))
716 if (character is not AICharacter && connectedClients.Any(c => c.Character ==
null && c.Name == character.Name)) {
continue; }
717 CreateMultiPlayerCharacterElement(character, GameMain.Client.PreviouslyConnectedClients.FirstOrDefault(c => c.Character == character), i);
721 for (
int j = 0; j < connectedClients.Count; j++)
723 Client client = connectedClients[j];
726 CreateMultiPlayerClientElement(client);
731 private void CreateMultiPlayerCharacterElement(Character character,
Client client,
int i)
733 GUIFrame frame =
new GUIFrame(
new RectTransform(
new Point(crewListArray[i].Content.Rect.Width, GUI.IntScale(33f)), crewListArray[i].Content.RectTransform), style:
"ListBoxElement")
735 UserData = character,
736 Color = (GameMain.NetworkMember !=
null && GameMain.Client.Character == character) ?
OwnCharacterBGColor : Color.Transparent
739 frame.OnSecondaryClicked += (component, data) =>
741 NetLobbyScreen.CreateModerationContextMenu(client);
745 var paddedFrame =
new GUILayoutGroup(
new RectTransform(
new Vector2(1.0f, 0.9f), frame.RectTransform,
Anchor.Center), isHorizontal:
true)
751 new GUICustomComponent(
new RectTransform(
new Point(jobColumnWidth, paddedFrame.Rect.Height), paddedFrame.RectTransform,
Anchor.Center), onDraw: (sb, component) => character.Info.DrawJobIcon(sb, component.Rect))
753 CanBeFocused =
false,
754 HoverColor = Color.White,
755 SelectedColor = Color.White
760 CreateNameWithPermissionIcon(client, paddedFrame, out GUIImage permissionIcon);
762 if (GameMain.GameSession?.GameMode is PvPMode)
764 new GUITextBlock(
new RectTransform(
new Point(killColumnWidth, paddedFrame.Rect.Height), paddedFrame.RectTransform),
string.Empty, textAlignment: Alignment.Center)
766 TextGetter = () => GameMain.GameSession.Missions.Sum(m => (m as CombatMission)?.GetClientKillCount(client) ?? 0).ToString()
768 new GUITextBlock(
new RectTransform(
new Point(deathColumnWidth, paddedFrame.Rect.Height), paddedFrame.RectTransform),
string.Empty, textAlignment: Alignment.Center)
770 TextGetter = () => GameMain.GameSession.Missions.Sum(m => (m as CombatMission)?.GetClientDeathCount(client) ?? 0).ToString()
774 linkedGUIList.Add(
new LinkedGUI(client, frame,
775 new GUITextBlock(
new RectTransform(
new Point(pingColumnWidth, paddedFrame.Rect.Height), paddedFrame.RectTransform), client.
Ping.ToString(), textAlignment: Alignment.Center),
780 GUITextBlock characterNameBlock =
new GUITextBlock(
new RectTransform(
new Point(characterColumnWidth, paddedFrame.Rect.Height), paddedFrame.RectTransform),
781 ToolBox.LimitString(character.Info.Name, GUIStyle.Font, characterColumnWidth), textAlignment: Alignment.Center, textColor: character.Info.Job.Prefab.UIColor);
783 if (GameMain.GameSession?.GameMode is PvPMode)
785 new GUITextBlock(
new RectTransform(
new Point(killColumnWidth, paddedFrame.Rect.Height), paddedFrame.RectTransform),
string.Empty, textAlignment: Alignment.Center)
787 TextGetter = () => GameMain.GameSession.Missions.Sum(m => (m as CombatMission)?.GetBotKillCount(character.Info) ?? 0).ToString()
789 new GUITextBlock(
new RectTransform(
new Point(deathColumnWidth, paddedFrame.Rect.Height), paddedFrame.RectTransform),
string.Empty, textAlignment: Alignment.Center)
791 TextGetter = () => GameMain.GameSession.Missions.Sum(m => (m as CombatMission)?.GetBotDeathCount(character.Info) ?? 0).ToString()
795 if (character is AICharacter)
797 linkedGUIList.Add(
new LinkedGUI(character, frame,
798 new GUITextBlock(
new RectTransform(
new Point(pingColumnWidth, paddedFrame.Rect.Height), paddedFrame.RectTransform), TextManager.Get(
"tabmenu.bot"), textAlignment: Alignment.Center) { ForceUpperCase = ForceUpperCase.Yes }));
802 linkedGUIList.Add(
new LinkedGUI(client:
null, frame, textBlock:
null, permissionIcon:
null));
804 new GUICustomComponent(
new RectTransform(
new Point(pingColumnWidth, paddedFrame.Rect.Height), paddedFrame.RectTransform,
Anchor.Center), onDraw: (sb, component) => DrawDisconnectedIcon(sb, component.Rect))
806 CanBeFocused =
false,
807 HoverColor = Color.White,
808 SelectedColor = Color.White
813 CreateWalletCrewFrame(character, paddedFrame);
815 paddedFrame.Recalculate();
818 private void CreateMultiPlayerClientElement(
Client client)
820 int teamIndex = GetTeamIndex(client);
821 if (teamIndex == -1) teamIndex = 0;
823 GUIFrame frame =
new GUIFrame(
new RectTransform(
new Point(crewListArray[teamIndex].Content.Rect.Width, GUI.IntScale(33f)), crewListArray[teamIndex].Content.RectTransform), style:
"ListBoxElement")
826 Color = Color.Transparent
829 frame.OnSecondaryClicked += (component, data) =>
831 NetLobbyScreen.CreateModerationContextMenu(client);
835 var paddedFrame =
new GUILayoutGroup(
new RectTransform(
new Vector2(1.0f, 0.9f), frame.RectTransform,
Anchor.Center), isHorizontal:
true)
841 new GUICustomComponent(
new RectTransform(
new Point(jobColumnWidth, paddedFrame.Rect.Height), paddedFrame.RectTransform,
Anchor.Center),
842 onDraw: (sb, component) => DrawNotInGameIcon(sb, component.Rect, client))
844 CanBeFocused =
false,
845 HoverColor = Color.White,
846 SelectedColor = Color.White
849 CreateNameWithPermissionIcon(client, paddedFrame, out GUIImage permissionIcon);
851 if (GameMain.GameSession?.GameMode is PvPMode)
853 new GUITextBlock(
new RectTransform(
new Point(killColumnWidth, paddedFrame.Rect.Height), paddedFrame.RectTransform),
string.Empty, textAlignment: Alignment.Center)
855 TextGetter = () => GameMain.GameSession.Missions.Sum(m => (m as CombatMission)?.GetClientKillCount(client) ?? 0).ToString()
857 new GUITextBlock(
new RectTransform(
new Point(deathColumnWidth, paddedFrame.Rect.Height), paddedFrame.RectTransform),
string.Empty, textAlignment: Alignment.Center)
859 TextGetter = () => GameMain.GameSession.Missions.Sum(m => (m as CombatMission)?.GetClientDeathCount(client) ?? 0).ToString()
863 linkedGUIList.Add(
new LinkedGUI(client, frame,
864 new GUITextBlock(
new RectTransform(
new Point(pingColumnWidth, paddedFrame.Rect.Height), paddedFrame.RectTransform), client.
Ping.ToString(), textAlignment: Alignment.Center),
869 CreateWalletCrewFrame(character, paddedFrame);
872 paddedFrame.Recalculate();
875 private int GetTeamIndex(
Client client)
877 if (teamIDs.Count <= 1) {
return 0; }
886 foreach (Character c
in crew)
890 return teamIDs.IndexOf(c.TeamID);
896 foreach (Character c
in crew)
898 if (client.
Name == c.Name)
900 return teamIDs.IndexOf(c.TeamID);
908 private void CreateWalletCrewFrame(Character character, GUILayoutGroup paddedFrame)
910 if (GameMain.GameSession?.Campaign is not MultiPlayerCampaign) {
return; }
912 GUILayoutGroup walletLayout =
new GUILayoutGroup(
new RectTransform(
new Point(walletColumnWidth, paddedFrame.Rect.Height), paddedFrame.RectTransform,
Anchor.Center), childAnchor:
Anchor.Center)
917 GUILayoutGroup paddedLayoutGroup =
new GUILayoutGroup(
new RectTransform(
new Vector2(0.9f, 1f), walletLayout.RectTransform,
Anchor.Center), isHorizontal:
true)
922 new GUIFrame(
new RectTransform(Vector2.One, paddedLayoutGroup.RectTransform), style:
null)
924 IgnoreLayoutGroups =
true,
925 ToolTip = TextManager.Get(
"walletdescription")
928 if (character.IsBot) {
return; }
930 Sprite walletSprite = GUIStyle.CrewWalletIconSmall.Value.Sprite;
932 GUIImage icon =
new GUIImage(
new RectTransform(Vector2.One, paddedLayoutGroup.RectTransform, scaleBasis:
ScaleBasis.BothHeight), walletSprite, scaleToFit:
true) { CanBeFocused =
false };
933 GUITextBlock walletBlock =
new GUITextBlock(
new RectTransform(Vector2.One, paddedLayoutGroup.RectTransform),
string.Empty, textAlignment: Alignment.Right, font: GUIStyle.Font)
935 AutoScaleHorizontal =
true,
936 Padding = Vector4.Zero,
940 GUIImage largeIcon =
new GUIImage(
new RectTransform(Vector2.One, paddedLayoutGroup.RectTransform), walletSprite, scaleToFit:
true)
942 CanBeFocused =
false,
943 IgnoreLayoutGroups =
true,
949 largeIcon.Visible =
true;
950 icon.Visible =
false;
951 walletBlock.Visible =
false;
952 largeIcon.Enabled =
false;
956 walletLayout.Recalculate();
957 paddedLayoutGroup.Recalculate();
958 SetWalletText(walletBlock, character.Wallet, icon, largeIcon);
960 if (GameMain.GameSession?.Campaign is MultiPlayerCampaign campaign)
962 Identifier eventIdentifier =
new Identifier($
"{nameof(CreateWalletCrewFrame)}.{character.ID}");
963 campaign.OnMoneyChanged.RegisterOverwriteExisting(eventIdentifier, e =>
965 if (!e.Owner.TryUnwrap(out var owner) || owner != character) { return; }
966 SetWalletText(walletBlock, e.Wallet, icon, largeIcon);
968 registeredEvents.Add(eventIdentifier);
971 static void SetWalletText(GUITextBlock block, Wallet wallet, GUIImage icon, GUIImage largeIcon)
973 const int million = 1000000,
974 tooSmallPixelTreshold = 50;
976 block.Text = TextManager.FormatCurrency(wallet.Balance);
977 block.ToolTip =
string.Empty;
979 if (wallet.Balance >= million)
981 block.Text = TextManager.Get(
"crewwallet.balance.toomuchtoshow");
982 block.ToolTip = block.Text;
985 largeIcon.Visible =
false;
987 block.Visible =
true;
989 if (tooSmallPixelTreshold > block.Rect.Width)
991 largeIcon.Visible =
true;
992 icon.Visible =
false;
993 block.Visible =
false;
994 largeIcon.ToolTip = block.Text;
999 private void CreateNameWithPermissionIcon(
Client client, GUILayoutGroup paddedFrame, out GUIImage permissionIcon)
1001 GUITextBlock characterNameBlock;
1002 Sprite permissionIconSprite = GetPermissionIcon(client);
1004 Color nameColor = prefab !=
null ? prefab.
UIColor : Color.White;
1006 Point iconSize =
new Point((
int)(paddedFrame.Rect.Height * 0.8f));
1007 float characterNameWidthAdjustment = (iconSize.X + paddedFrame.AbsoluteSpacing) / characterColumnWidth;
1009 characterNameBlock =
new GUITextBlock(
new RectTransform(
new Point(characterColumnWidth, paddedFrame.Rect.Height), paddedFrame.RectTransform),
1010 ToolBox.LimitString(client.
Name, GUIStyle.Font, (
int)(characterColumnWidth - paddedFrame.Rect.Width * characterNameWidthAdjustment)), textAlignment: Alignment.Center, textColor: nameColor);
1012 float iconWidth = iconSize.X / (float)characterColumnWidth;
1013 int xOffset = (int)(jobColumnWidth + characterNameBlock.TextPos.X - GUIStyle.Font.MeasureString(characterNameBlock.Text).X / 2f - paddedFrame.AbsoluteSpacing - iconWidth * paddedFrame.Rect.Width);
1014 permissionIcon =
new GUIImage(
new RectTransform(
new Vector2(iconWidth, 1f), paddedFrame.RectTransform) { AbsoluteOffset = new Point(xOffset + 2, 0) }, permissionIconSprite) { IgnoreLayoutGroups =
true };
1018 characterNameBlock.Strikethrough =
new GUITextBlock.StrikethroughSettings(
null, GUI.IntScale(1f), GUI.IntScale(5f));
1022 private Sprite GetPermissionIcon(
Client client)
1024 if (GameMain.NetworkMember ==
null || client ==
null || !client.
HasPermissions) {
return null; }
1032 return moderatorIcon;
1036 private void DrawNotInGameIcon(SpriteBatch spriteBatch, Rectangle area,
Client client)
1040 spectateIcon.
Draw(spriteBatch, area, Color.White);
1048 Vector2 stringOffset = GUIStyle.Font.MeasureString(inLobbyString) / 2f;
1049 GUIStyle.Font.DrawString(spriteBatch, inLobbyString, area.Center.ToVector2() - stringOffset, Color.White);
1053 private void DrawDisconnectedIcon(SpriteBatch spriteBatch, Rectangle area)
1055 disconnectedIcon.
Draw(spriteBatch, area, GUIStyle.Red);
1061 private bool SelectElement(
object userData, GUIComponent crewList)
1066 GUIComponent existingPreview = infoFrameHolder.
FindChild(
"SelectedCharacter");
1067 if (existingPreview !=
null) { infoFrameHolder.
RemoveChild(existingPreview); }
1069 GUIFrame background =
new GUIFrame(
new RectTransform(
new Vector2(0.543f, 0.69f), infoFrameHolder.
RectTransform,
Anchor.TopRight,
Pivot.TopLeft) { RelativeOffset = new Vector2(-0.061f, 0) })
1071 UserData =
"SelectedCharacter"
1074 if (character !=
null)
1076 if (GameMain.Client is
null)
1078 GUIComponent preview = character.Info.CreateInfoFrame(background,
false,
null);
1082 GUIComponent preview = character.Info.CreateInfoFrame(background,
false, GetPermissionIcon(GameMain.Client.ConnectedClients.Find(c => c.Character == character)));
1084 GameMain.Client.SelectCrewCharacter(character, preview);
1085 if (!character.IsBot && GameMain.GameSession?.Campaign is MultiPlayerCampaign mpCampaign) { CreateWalletFrame(background, character, mpCampaign); }
1088 if (background.FindChild(TalentMenu.ManageBotTalentsButtonUserData, recursive:
true) is GUIButton { Enabled: true } talentButton)
1090 talentButton.OnClicked = (button, o) =>
1092 talentMenu.CreateGUI(infoFrameHolder, character);
1097 else if (client !=
null)
1099 GUIComponent preview = CreateClientInfoFrame(background, client, GetPermissionIcon(client));
1100 GameMain.Client?.SelectCrewClient(client, preview);
1101 if (client.
Character !=
null && GameMain.GameSession?.Campaign is MultiPlayerCampaign mpCampaign)
1103 CreateWalletFrame(background, client.
Character, mpCampaign);
1110 private void CreateWalletFrame(GUIComponent parent, Character character, MultiPlayerCampaign campaign)
1112 if (campaign is
null) {
throw new ArgumentNullException(nameof(campaign),
"Tried to create a wallet frame when campaign was null"); }
1113 if (character is
null) {
throw new ArgumentNullException(nameof(character),
"Tried to create a wallet frame for a null character");}
1114 isTransferMenuOpen =
false;
1115 transferMenuOpenState = 1f;
1116 ImmutableHashSet<Character> salaryCrew = GameSession.GetSessionCrewCharacters(
CharacterType.Player).Where(c => c != character).ToImmutableHashSet();
1118 Wallet targetWallet = character.Wallet;
1120 GUIFrame walletFrame =
new GUIFrame(
new RectTransform(
new Vector2(1f, 0.35f), parent.RectTransform, anchor:
Anchor.TopLeft)
1122 RelativeOffset = new Vector2(0, 1.02f)
1125 GUILayoutGroup walletLayout =
new GUILayoutGroup(
new RectTransform(ToolBox.PaddingSizeParentRelative(walletFrame.RectTransform, 0.9f), walletFrame.RectTransform, anchor:
Anchor.Center));
1127 GUILayoutGroup headerLayout =
new GUILayoutGroup(
new RectTransform(
new Vector2(1f, 0.33f), walletLayout.RectTransform), isHorizontal:
true);
1128 GUIImage icon =
new GUIImage(
new RectTransform(Vector2.One, headerLayout.RectTransform, scaleBasis:
ScaleBasis.BothHeight), style:
"CrewWalletIconLarge", scaleToFit:
true);
1129 float relativeX = icon.RectTransform.NonScaledSize.X / (float)icon.Parent.RectTransform.NonScaledSize.X;
1130 GUILayoutGroup headerTextLayout =
new GUILayoutGroup(
new RectTransform(
new Vector2(1.0f - relativeX, 1f), headerLayout.RectTransform), isHorizontal:
true) { Stretch =
true };
1131 new GUITextBlock(
new RectTransform(
new Vector2(0.5f, 1f), headerTextLayout.RectTransform), TextManager.Get(
"crewwallet.wallet"), font: GUIStyle.LargeFont);
1132 GUIFrame walletTooltipFrame =
new GUIFrame(
new RectTransform(Vector2.One, headerLayout.RectTransform), style:
null)
1134 IgnoreLayoutGroups =
true,
1135 ToolTip = TextManager.Get(
"walletdescription")
1137 GUITextBlock moneyBlock =
new GUITextBlock(
new RectTransform(
new Vector2(0.5f, 1f), headerTextLayout.RectTransform), TextManager.FormatCurrency(targetWallet.Balance), font: GUIStyle.SubHeadingFont, textAlignment: Alignment.Right);
1139 GUILayoutGroup middleLayout =
new GUILayoutGroup(
new RectTransform(
new Vector2(1f, 0.66f), walletLayout.RectTransform));
1140 GUILayoutGroup salaryTextLayout =
new GUILayoutGroup(
new RectTransform(
new Vector2(1f, 0.5f), middleLayout.RectTransform), isHorizontal:
true);
1141 GUITextBlock salaryTitle =
new GUITextBlock(
new RectTransform(
new Vector2(0.5f, 1f), salaryTextLayout.RectTransform), TextManager.Get(
"crewwallet.salary"), font: GUIStyle.SubHeadingFont, textAlignment: Alignment.BottomLeft);
1142 GUITextBlock rewardBlock =
new GUITextBlock(
new RectTransform(
new Vector2(0.5f, 1f), salaryTextLayout.RectTransform),
string.Empty, textAlignment: Alignment.BottomRight);
1143 GUIFrame salaryTooltipFrame =
new GUIFrame(
new RectTransform(Vector2.One, middleLayout.RectTransform), style:
null)
1145 IgnoreLayoutGroups =
true,
1146 ToolTip = TextManager.Get(
"crewwallet.salary.tooltip")
1148 GUILayoutGroup sliderLayout =
new GUILayoutGroup(
new RectTransform(
new Vector2(1f, 0.5f), middleLayout.RectTransform), isHorizontal:
true, childAnchor:
Anchor.Center);
1149 GUIScrollBar salarySlider =
new GUIScrollBar(
new RectTransform(
new Vector2(0.9f, 1f), sliderLayout.RectTransform), style:
"GUISlider", barSize: 0.03f)
1151 Range =
new Vector2(0, 1),
1152 BarScrollValue = targetWallet.RewardDistribution / 100f,
1155 OnMoved = (bar, scroll) =>
1157 int rewardDistribution = RoundRewardDistribution(scroll, bar.Step);
1158 SetRewardText(rewardDistribution, rewardBlock);
1161 OnReleased = (bar, scroll) =>
1163 int newRewardDistribution = RoundRewardDistribution(scroll, bar.Step);
1164 if (newRewardDistribution == targetWallet.RewardDistribution) {
return false; }
1165 SetRewardDistribution(Option.Some(character), newRewardDistribution);
1170 SetRewardText(targetWallet.RewardDistribution, rewardBlock);
1173 GUIScissorComponent scissorComponent =
new GUIScissorComponent(
new RectTransform(
new Vector2(0.85f, 1.25f), walletFrame.RectTransform,
Anchor.BottomCenter,
Pivot.TopCenter))
1175 CanBeFocused =
false
1177 transferMenu =
new GUIFrame(
new RectTransform(Vector2.One, scissorComponent.Content.RectTransform));
1179 GUILayoutGroup transferMenuLayout =
new GUILayoutGroup(
new RectTransform(
new Vector2(1f, 0.8f), transferMenu.
RectTransform,
Anchor.BottomLeft), childAnchor:
Anchor.Center);
1180 GUILayoutGroup paddedTransferMenuLayout =
new GUILayoutGroup(
new RectTransform(ToolBox.PaddingSizeParentRelative(transferMenuLayout.RectTransform, 0.85f), transferMenuLayout.RectTransform));
1181 GUILayoutGroup mainLayout =
new GUILayoutGroup(
new RectTransform(
new Vector2(1f, 0.5f), paddedTransferMenuLayout.RectTransform), isHorizontal:
true, childAnchor:
Anchor.CenterLeft);
1182 GUILayoutGroup leftLayout =
new GUILayoutGroup(
new RectTransform(
new Vector2(0.5f, 1f), mainLayout.RectTransform));
1183 GUITextBlock leftName =
new GUITextBlock(
new RectTransform(
new Vector2(1f, 0.5f), leftLayout.RectTransform), character.Name, textAlignment: Alignment.CenterLeft, font: GUIStyle.SubHeadingFont);
1184 GUITextBlock leftBalance =
new GUITextBlock(
new RectTransform(
new Vector2(1f, 0.5f), leftLayout.RectTransform), TextManager.FormatCurrency(targetWallet.Balance), textAlignment: Alignment.Left) { TextColor = GUIStyle.Blue };
1185 GUILayoutGroup rightLayout =
new GUILayoutGroup(
new RectTransform(
new Vector2(0.5f, 1f), mainLayout.RectTransform), childAnchor:
Anchor.TopRight);
1186 GUITextBlock rightName =
new GUITextBlock(
new RectTransform(
new Vector2(1f, 0.5f), rightLayout.RectTransform),
string.Empty, font: GUIStyle.SubHeadingFont, textAlignment: Alignment.CenterRight);
1187 GUITextBlock rightBalance =
new GUITextBlock(
new RectTransform(
new Vector2(1f, 0.5f), rightLayout.RectTransform),
string.Empty, textAlignment: Alignment.Right) { TextColor = GUIStyle.Red };
1188 GUILayoutGroup centerLayout =
new GUILayoutGroup(
new RectTransform(
new Vector2(1f, 0.9f), mainLayout.RectTransform,
Anchor.Center), childAnchor:
Anchor.Center) { IgnoreLayoutGroups =
true };
1189 new GUIFrame(
new RectTransform(
new Vector2(0f, 1f), centerLayout.RectTransform,
Anchor.Center), style:
"VerticalLine") { IgnoreLayoutGroups =
true };
1190 GUIButton centerButton =
new GUIButton(
new RectTransform(
new Vector2(1f), centerLayout.RectTransform, scaleBasis:
ScaleBasis.BothHeight, anchor:
Anchor.Center), style:
"GUIButtonTransferArrow");
1192 GUILayoutGroup inputLayout =
new GUILayoutGroup(
new RectTransform(
new Vector2(1f, 0.25f), paddedTransferMenuLayout.RectTransform), childAnchor:
Anchor.Center);
1193 GUINumberInput transferAmountInput =
new GUINumberInput(
new RectTransform(
new Vector2(0.5f, 1f), inputLayout.RectTransform),
NumberType.Int, buttonVisibility: GUINumberInput.ButtonVisibility.ForceHidden)
1198 GUILayoutGroup buttonLayout =
new GUILayoutGroup(
new RectTransform(
new Vector2(1f, 0.25f), paddedTransferMenuLayout.RectTransform), childAnchor:
Anchor.Center);
1199 GUILayoutGroup centerButtonLayout =
new GUILayoutGroup(
new RectTransform(
new Vector2(0.75f, 1f), buttonLayout.RectTransform), isHorizontal:
true);
1200 GUIButton resetButton =
new GUIButton(
new RectTransform(
new Vector2(0.5f, 1f), centerButtonLayout.RectTransform), TextManager.Get(
"reset"), style:
"GUIButtonFreeScale") { Enabled =
false };
1201 GUIButton confirmButton =
new GUIButton(
new RectTransform(
new Vector2(0.5f, 1f), centerButtonLayout.RectTransform), TextManager.Get(
"confirm"), style:
"GUIButtonFreeScale") { Enabled =
false };
1203 ImmutableArray<GUILayoutGroup> layoutGroups = ImmutableArray.Create(transferMenuLayout, paddedTransferMenuLayout, mainLayout, leftLayout, rightLayout);
1204 MedicalClinicUI.EnsureTextDoesntOverflow(character.Name, leftName, leftLayout.Rect, layoutGroups);
1205 transferMenuButton =
new GUIButton(
new RectTransform(
new Vector2(0.5f, 0.2f), walletFrame.RectTransform,
Anchor.BottomCenter,
Pivot.TopCenter), style:
"UIToggleButtonVertical")
1207 ToolTip = TextManager.Get(
"crewwallet.transfer.tooltip"),
1208 OnClicked = (button, o) =>
1210 isTransferMenuOpen = !isTransferMenuOpen;
1211 if (!isTransferMenuOpen)
1213 transferAmountInput.IntValue = 0;
1215 ToggleTransferMenuIcon(button, open: isTransferMenuOpen);
1220 Identifier eventIdentifier = nameof(CreateWalletFrame).ToIdentifier();
1222 ToggleTransferMenuIcon(transferMenuButton, open: isTransferMenuOpen);
1223 ToggleCenterButton(centerButton, isSending);
1226 GameMain.Client?.OnPermissionChanged.RegisterOverwriteExisting(eventIdentifier, e => UpdateWalletInterface(registerEvents:
false));
1227 UpdateWalletInterface(registerEvents:
true);
1229 void UpdateWalletInterface(
bool registerEvents)
1231 if (!(
Character.Controlled is { } myCharacter))
1233 salarySlider.Enabled =
false;
1234 transferAmountInput.Enabled =
false;
1235 centerButton.Enabled =
false;
1236 confirmButton.Enabled =
false;
1240 bool hasMoneyPermissions = CampaignMode.AllowedToManageWallets();
1241 salarySlider.Enabled = hasMoneyPermissions;
1243 switch (hasMoneyPermissions)
1246 rightName.Text = TextManager.Get(
"crewwallet.bank");
1247 otherWallet = campaign.Bank;
1249 case false when character == myCharacter:
1250 rightName.Text = TextManager.Get(
"crewwallet.bank");
1251 otherWallet = campaign.Bank;
1253 ToggleCenterButton(centerButton, isSending);
1256 rightName.Text = myCharacter.Name;
1257 otherWallet = campaign.PersonalWallet;
1261 MedicalClinicUI.EnsureTextDoesntOverflow(rightName.Text.ToString(), rightName, rightLayout.Rect, layoutGroups);
1263 UpdatedConfirmButtonText();
1265 if (!hasMoneyPermissions)
1269 centerButton.Enabled = centerButton.CanBeFocused =
false;
1272 salarySlider.Enabled = salarySlider.CanBeFocused =
false;
1275 leftBalance.Text = TextManager.FormatCurrency(otherWallet.Balance);
1279 if (!registerEvents) {
return; }
1281 centerButton.OnClicked = (btn, o) =>
1283 isSending = !isSending;
1284 UpdatedConfirmButtonText();
1285 ToggleCenterButton(btn, isSending);
1290 transferAmountInput.OnValueChanged = input =>
1295 transferAmountInput.OnValueEntered = input =>
1300 resetButton.OnClicked = (button, o) =>
1302 transferAmountInput.IntValue = 0;
1307 confirmButton.OnClicked = (button, o) =>
1309 int amount = transferAmountInput.IntValue;
1310 if (amount == 0) {
return false; }
1312 Option<Character> target1 = Option<Character>.Some(character),
1313 target2 = otherWallet == campaign.Bank ? Option<Character>.None() : Option<Character>.Some(myCharacter);
1314 if (isSending) { (target1, target2) = (target2, target1); }
1316 SendTransaction(target1, target2, amount);
1317 isTransferMenuOpen =
false;
1318 ToggleTransferMenuIcon(transferMenuButton, isTransferMenuOpen);
1322 campaign.OnMoneyChanged.RegisterOverwriteExisting(eventIdentifier, e =>
1324 if (e.Wallet == targetWallet)
1326 moneyBlock.Text = TextManager.FormatCurrency(e.Info.Balance);
1327 salarySlider.BarScrollValue = e.Info.RewardDistribution / 100f;
1328 SetRewardText(e.Info.RewardDistribution, rewardBlock);
1334 registeredEvents.Add(eventIdentifier);
1336 void UpdatedConfirmButtonText()
1338 confirmButton.Text = TextManager.Get(hasMoneyPermissions || isSending ?
"confirm" :
"crewwallet.requestmoney");
1341 void UpdateAllInputs()
1349 confirmButton.Enabled = resetButton.Enabled = transferAmountInput.IntValue > 0;
1350 if (transferAmountInput.IntValue == 0)
1352 rightBalance.Text = TextManager.FormatCurrency(otherWallet.Balance);
1353 rightBalance.TextColor = GUIStyle.TextColorNormal;
1354 leftBalance.Text = TextManager.FormatCurrency(targetWallet.Balance);
1355 leftBalance.TextColor = GUIStyle.TextColorNormal;
1359 rightBalance.Text = TextManager.FormatCurrency(otherWallet.Balance + transferAmountInput.IntValue);
1360 rightBalance.TextColor = GUIStyle.Blue;
1361 leftBalance.Text = TextManager.FormatCurrency(targetWallet.Balance - transferAmountInput.IntValue);
1362 leftBalance.TextColor = GUIStyle.Red;
1366 rightBalance.Text = TextManager.FormatCurrency(otherWallet.Balance - transferAmountInput.IntValue);
1367 rightBalance.TextColor = GUIStyle.Red;
1368 leftBalance.Text = TextManager.FormatCurrency(targetWallet.Balance + transferAmountInput.IntValue);
1369 leftBalance.TextColor = GUIStyle.Blue;
1373 void UpdateMaxInput()
1375 int maxValue = isSending ? targetWallet.Balance : otherWallet.Balance;
1376 transferAmountInput.MaxValueInt = maxValue;
1378 transferAmountInput.Enabled =
true;
1379 transferAmountInput.ToolTip =
string.Empty;
1381 if (!hasMoneyPermissions && GameMain.Client?.ServerSettings is { } serverSettings)
1383 transferAmountInput.MaxValueInt = Math.Min(maxValue, serverSettings.MaximumMoneyTransferRequest);
1384 if (serverSettings.MaximumMoneyTransferRequest <= 0)
1386 transferAmountInput.Enabled =
false;
1387 transferAmountInput.ToolTip = TextManager.Get(
"wallettransferrequestdisabled");
1393 void SetRewardText(
int value, GUITextBlock block)
1395 var (_, percentage, sum) = Mission.GetRewardShare(value, salaryCrew, Option<int>.
None());
1396 LocalizedString tooltip =
string.Empty;
1397 block.TextColor = GUIStyle.TextColorNormal;
1401 tooltip = TextManager.GetWithVariables(
"crewwallet.salary.over100toolitp", (
"[sum]", $
"{(int)sum}"), (
"[newvalue]", $
"{percentage}"));
1402 block.TextColor = GUIStyle.Orange;
1405 LocalizedString text = TextManager.GetWithVariable(
"percentageformat",
"[value]", $
"{value}");
1408 block.ToolTip = RichString.Rich(tooltip);
1411 static void ToggleTransferMenuIcon(GUIButton btn,
bool open)
1413 foreach (GUIComponent child
in btn.Children)
1415 child.SpriteEffects = open ? SpriteEffects.None : SpriteEffects.FlipVertically;
1419 static void ToggleCenterButton(GUIButton btn,
bool isSending)
1421 foreach (GUIComponent child
in btn.Children)
1423 child.SpriteEffects = isSending ? SpriteEffects.None : SpriteEffects.FlipHorizontally;
1427 static void SendTransaction(Option<Character> to, Option<Character> from,
int amount)
1429 INetSerializableStruct transfer =
new NetWalletTransfer
1431 Sender = from.Select(option => option.ID),
1432 Receiver = to.Select(option => option.ID),
1436 transfer.Write(msg);
1437 GameMain.Client?.ClientPeer?.Send(msg, DeliveryMethod.Reliable);
1441 static void SetRewardDistribution(Option<Character> character,
int newValue)
1443 INetSerializableStruct transfer =
new NetWalletSetSalaryUpdate
1445 Target = character.Select(c => c.ID),
1446 NewRewardDistribution = newValue
1449 transfer.Write(msg);
1450 GameMain.Client?.ClientPeer?.Send(msg, DeliveryMethod.Reliable);
1453 static void ResetRewardDistributions()
1456 GameMain.Client?.ClientPeer?.Send(msg, DeliveryMethod.Reliable);
1459 static int RoundRewardDistribution(
float scroll,
float step)
1460 => (int)MathUtils.RoundTowardsClosest(scroll * 100, step * 100);
1462 private GUIComponent CreateClientInfoFrame(GUIFrame frame,
Client client, Sprite permissionIcon =
null)
1464 GUIComponent paddedFrame;
1468 paddedFrame =
new GUILayoutGroup(
new RectTransform(
new Vector2(0.874f, 0.58f), frame.RectTransform,
Anchor.TopCenter) { RelativeOffset = new Vector2(0.0f, 0.05f) })
1470 RelativeSpacing = 0.05f
1474 var headerArea =
new GUILayoutGroup(
new RectTransform(
new Vector2(1.0f, 0.322f), paddedFrame.RectTransform), isHorizontal:
true);
1476 new GUICustomComponent(
new RectTransform(
new Vector2(0.425f, 1.0f), headerArea.RectTransform),
1477 onDraw: (sb, component) => DrawNotInGameIcon(sb, component.Rect, client));
1479 GUIFont font = paddedFrame.Rect.Width < 280 ? GUIStyle.SmallFont : GUIStyle.Font;
1481 var headerTextArea =
new GUILayoutGroup(
new RectTransform(
new Vector2(0.575f, 1.0f), headerArea.RectTransform))
1483 RelativeSpacing = 0.02f,
1487 GUITextBlock clientNameBlock =
new GUITextBlock(
new RectTransform(
new Vector2(1.0f, 0.0f), headerTextArea.RectTransform), ToolBox.LimitString(client.
Name, GUIStyle.Font, headerTextArea.Rect.Width), textColor: Color.White, font: GUIStyle.Font)
1490 Padding = Vector4.Zero
1493 if (permissionIcon !=
null)
1495 Point iconSize = permissionIcon.SourceRect.Size;
1496 int iconWidth = (int)((
float)clientNameBlock.Rect.Height / iconSize.Y * iconSize.X);
1497 new GUIImage(
new RectTransform(
new Point(iconWidth, clientNameBlock.Rect.Height), clientNameBlock.RectTransform) { AbsoluteOffset = new Point(-iconWidth - 2, 0) }, permissionIcon) { IgnoreLayoutGroups =
true };
1500 new GUITextBlock(
new RectTransform(
new Vector2(1.0f, 0.0f), headerTextArea.RectTransform), client.
Spectating ? TextManager.Get(
"playingasspectator") : TextManager.Get(
"tabmenu.inlobby"), textColor: Color.White, font: font, wrap:
true)
1502 Padding = Vector4.Zero
1513 private void CreateMultiPlayerLogContent(GUIFrame crewFrame)
1515 var logContainer =
new GUIFrame(
new RectTransform(
new Vector2(0.543f, 0.717f), infoFrameHolder.
RectTransform,
Anchor.TopLeft,
Pivot.TopRight) { RelativeOffset = new Vector2(-0.145f, 0) });
1516 var innerFrame =
new GUIFrame(
new RectTransform(
new Vector2(0.900f, 0.900f), logContainer.RectTransform,
Anchor.TopCenter,
Pivot.TopCenter) { RelativeOffset = new Vector2(0f, 0.0475f) }, style:
null);
1517 var content =
new GUILayoutGroup(
new RectTransform(Vector2.One, innerFrame.RectTransform))
1522 logList =
new GUIListBox(
new RectTransform(Vector2.One, content.RectTransform))
1524 Padding =
new Vector4(0, 10 * GUI.Scale, 0, 10 * GUI.Scale),
1525 UserData = crewFrame,
1526 AutoHideScrollBar =
false,
1527 Spacing = (int)(5 * GUI.Scale)
1532 AddLineToLog(message, type);
1545 storedMessages.Add((msg, message.
ChangeType));
1550 instance.AddLineToLog(msg, message.
ChangeType);
1551 instance.RemoveCurrentElements();
1552 instance.CreateMultiPlayerList(
true);
1556 private void RemoveCurrentElements()
1558 for (
int i = 0; i < crewListArray.Length; i++)
1560 for (
int j = 0; j < linkedGUIList.Count; j++)
1562 linkedGUIList[j].Remove(crewListArray[i].Content);
1566 linkedGUIList.Clear();
1571 Color textColor = Color.White;
1576 textColor = GUIStyle.Green;
1579 textColor = GUIStyle.Orange;
1582 textColor = GUIStyle.Yellow;
1585 textColor = GUIStyle.Red;
1589 if (logList !=
null)
1591 var textBlock =
new GUITextBlock(
new RectTransform(
new Vector2(1.0f, 0.0f), logList.
Content.
RectTransform), RichString.Rich(line), wrap:
true, font: GUIStyle.SmallFont)
1593 TextColor = textColor,
1594 CanBeFocused =
false,
1597 textBlock.CalculateHeightFromText();
1598 if (textBlock.HasColorHighlight)
1600 foreach (var data
in textBlock.RichTextData)
1602 textBlock.ClickableAreas.Add(
new GUITextBlock.ClickableArea()
1605 OnClick = GameMain.NetLobbyScreen.SelectPlayer,
1606 OnSecondaryClick = GameMain.NetLobbyScreen.ShowPlayerContextMenu
1613 private void CreateMissionInfo(GUIFrame infoFrame)
1615 if (Level.Loaded?.LevelData ==
null)
1617 DebugConsole.ThrowError(
"Failed to display mission info in the tab menu (no level loaded).\n" + Environment.StackTrace);
1621 infoFrame.ClearChildren();
1622 GUIFrame missionFrame =
new GUIFrame(
new RectTransform(Vector2.One, infoFrame.RectTransform,
Anchor.TopCenter), style:
"GUIFrameListBox");
1623 int padding = (int)(0.0245f * missionFrame.Rect.Height);
1624 GUIFrame missionFrameContent =
new GUIFrame(
new RectTransform(
new Point(missionFrame.Rect.Width - padding * 2, missionFrame.Rect.Height - padding * 2), infoFrame.RectTransform,
Anchor.Center), style:
null);
1625 Location location = GameMain.GameSession.StartLocation;
1626 if (Level.Loaded.Type == LevelData.LevelType.LocationConnection)
1628 location ??= GameMain.GameSession.EndLocation;
1631 GUILayoutGroup locationInfoContainer =
new GUILayoutGroup(
new RectTransform(
new Vector2(1.0f, 0.3f), missionFrameContent.RectTransform))
1633 AbsoluteSpacing = GUI.IntScale(10)
1636 Sprite portrait = location.Type.GetPortrait(location.PortraitId);
1637 bool hasPortrait = portrait !=
null && portrait.SourceRect.Width > 0 && portrait.SourceRect.Height > 0;
1638 int contentWidth = missionFrameContent.Rect.Width;
1641 float portraitAspectRatio = portrait.SourceRect.Width / portrait.SourceRect.Height;
1642 GUIImage portraitImage =
new GUIImage(
new RectTransform(
new Vector2(0.5f, 1f), locationInfoContainer.RectTransform,
Anchor.CenterRight), portrait, scaleToFit:
true)
1644 IgnoreLayoutGroups =
true
1646 locationInfoContainer.Recalculate();
1647 portraitImage.RectTransform.NonScaledSize =
new Point(Math.Min((
int)(portraitImage.Rect.Size.Y * portraitAspectRatio), portraitImage.Rect.Width), portraitImage.Rect.Size.Y);
1650 new GUITextBlock(
new RectTransform(
new Vector2(1.0f, 0.0f), locationInfoContainer.RectTransform), location.DisplayName, font: GUIStyle.LargeFont);
1651 new GUITextBlock(
new RectTransform(
new Vector2(1.0f, 0.0f), locationInfoContainer.RectTransform), location.Type.Name, font: GUIStyle.SubHeadingFont);
1653 if (location.Faction?.Prefab !=
null)
1655 var factionLabel =
new GUITextBlock(
new RectTransform(
new Vector2(0.5f, 0.0f), locationInfoContainer.RectTransform),
1656 TextManager.Get(
"Faction"), font: GUIStyle.SubHeadingFont, textAlignment: Alignment.CenterLeft);
1657 new GUITextBlock(
new RectTransform(
new Vector2(1.0f, 1.0f), factionLabel.RectTransform), location.Faction.Prefab.Name, textAlignment: Alignment.CenterRight);
1659 var biomeLabel =
new GUITextBlock(
new RectTransform(
new Vector2(0.5f, 0.0f), locationInfoContainer.RectTransform),
1660 TextManager.Get(
"Biome",
"location"), font: GUIStyle.SubHeadingFont, textAlignment: Alignment.CenterLeft);
1661 new GUITextBlock(
new RectTransform(
new Vector2(1.0f, 1.0f), biomeLabel.RectTransform), Level.Loaded.LevelData.Biome.DisplayName, textAlignment: Alignment.CenterRight);
1662 var difficultyLabel =
new GUITextBlock(
new RectTransform(
new Vector2(0.5f, 0.0f), locationInfoContainer.RectTransform),
1663 TextManager.Get(
"LevelDifficulty"), font: GUIStyle.SubHeadingFont, textAlignment: Alignment.CenterLeft);
1664 new GUITextBlock(
new RectTransform(
new Vector2(1.0f, 1.0f), difficultyLabel.RectTransform), TextManager.GetWithVariable(
"percentageformat",
"[value]", ((
int)Level.Loaded.LevelData.Difficulty).ToString()), textAlignment: Alignment.CenterRight);
1666 new GUIFrame(
new RectTransform(
new Vector2(1.0f, 0.01f), missionFrameContent.RectTransform) { AbsoluteOffset = new Point(0, locationInfoContainer.Rect.Height + padding) }, style:
"HorizontalLine")
1668 CanBeFocused =
false
1671 int locationInfoYOffset = locationInfoContainer.Rect.Height + padding * 2;
1673 GUIListBox missionList =
new GUIListBox(
new RectTransform(
new Point(contentWidth, missionFrameContent.Rect.Height - locationInfoYOffset), missionFrameContent.RectTransform,
Anchor.TopCenter) { AbsoluteOffset = new Point(0, locationInfoYOffset) });
1674 missionList.ContentBackground.Color = Color.Transparent;
1675 missionList.Spacing = GUI.IntScale(15);
1677 if (GameMain.GameSession?.Missions !=
null)
1679 foreach (Mission mission
in GameMain.GameSession.Missions)
1681 if (!mission.Prefab.ShowInMenus) {
continue; }
1683 var textContent =
new List<LocalizedString>()
1685 mission.GetMissionRewardText(
Submarine.MainSub),
1686 mission.GetReputationRewardText(),
1689 textContent.AddRange(mission.ShownMessages);
1691 RoundSummary.CreateMissionEntry(
1692 missionList.Content,
1695 mission.Difficulty ?? 0,
1696 mission.Prefab.Icon, mission.Prefab.IconColor,
1697 out GUIImage missionIcon);
1698 if (missionIcon !=
null)
1700 UpdateMissionStateIcon();
1701 mission.OnMissionStateChanged += (mission) => UpdateMissionStateIcon();
1703 void UpdateMissionStateIcon()
1705 if (mission.DisplayAsCompleted || mission.DisplayAsFailed)
1707 RoundSummary.UpdateMissionStateIcon(mission.DisplayAsCompleted, missionIcon);
1715 GUILayoutGroup missionTextGroup =
new GUILayoutGroup(
new RectTransform(
new Vector2(1f, 0f), missionList.RectTransform,
Anchor.CenterLeft),
false, childAnchor:
Anchor.TopLeft);
1716 new GUITextBlock(
new RectTransform(
new Vector2(1.0f, 0.0f), missionTextGroup.RectTransform), TextManager.Get(
"NoMission"), font: GUIStyle.LargeFont);
1719 GameMain.GameSession?.EventManager?.EventLog?.CreateEventLogUI(missionList.Content);
1720 GameMain.GameSession.EnableEventLogNotificationIcon(enabled:
false);
1722 RoundSummary.AddSeparators(missionList.Content);
1725 private static void CreateSubmarineInfo(GUIFrame infoFrame, Submarine sub)
1727 if (sub ==
null) {
return; }
1729 GUIFrame subInfoFrame =
new GUIFrame(
new RectTransform(Vector2.One, infoFrame.RectTransform,
Anchor.TopCenter), style:
"GUIFrameListBox");
1730 GUIFrame paddedFrame =
new GUIFrame(
new RectTransform(Vector2.One * 0.97f, subInfoFrame.RectTransform,
Anchor.Center), style:
null);
1732 var previewButton =
new GUIButton(
new RectTransform(
new Vector2(1.0f, 0.43f), paddedFrame.RectTransform), style:
null)
1734 OnClicked = (btn, obj) => { SubmarinePreview.Create(sub.Info);
return false; },
1737 var previewImage = sub.Info.PreviewImage ?? SubmarineInfo.SavedSubmarines.FirstOrDefault(s => s.Name.Equals(sub.Info.Name, StringComparison.OrdinalIgnoreCase))?.PreviewImage;
1738 if (previewImage ==
null)
1740 new GUITextBlock(
new RectTransform(Vector2.One, previewButton.RectTransform), TextManager.Get(
"SubPreviewImageNotFound"));
1744 var submarinePreviewBackground =
new GUIFrame(
new RectTransform(Vector2.One, previewButton.RectTransform), style:
null)
1746 Color = Color.Black,
1747 HoverColor = Color.Black,
1748 SelectedColor = Color.Black,
1749 PressedColor = Color.Black,
1750 CanBeFocused =
false,
1752 new GUIImage(
new RectTransform(
new Vector2(0.98f), submarinePreviewBackground.RectTransform,
Anchor.Center), previewImage, scaleToFit:
true) { CanBeFocused =
false };
1753 new GUIFrame(
new RectTransform(Vector2.One, submarinePreviewBackground.RectTransform),
"InnerGlow", color: Color.Black) { CanBeFocused =
false };
1756 new GUIFrame(
new RectTransform(Vector2.One * 0.12f, previewButton.RectTransform, anchor:
Anchor.BottomRight, pivot:
Pivot.BottomRight, scaleBasis:
ScaleBasis.BothHeight)
1758 AbsoluteOffset = new Point((int)(0.03f * previewButton.Rect.Height))
1760 "ExpandButton", Color.White)
1762 Color = Color.White,
1763 HoverColor = Color.White,
1764 PressedColor = Color.White
1767 var subInfoTextLayout =
new GUILayoutGroup(
new RectTransform(Vector2.One, paddedFrame.RectTransform));
1769 LocalizedString className = !sub.Info.HasTag(
SubmarineTag.Shuttle) ?
1770 TextManager.GetWithVariables(
"submarine.classandtier",
1771 (
"[class]", TextManager.Get($
"submarineclass.{sub.Info.SubmarineClass}")),
1772 (
"[tier]", TextManager.Get($
"submarinetier.{sub.Info.Tier}"))) :
1773 TextManager.Get(
"shuttle");
1775 int nameHeight = (int)GUIStyle.LargeFont.MeasureString(sub.Info.DisplayName,
true).Y;
1776 int classHeight = (int)GUIStyle.SubHeadingFont.MeasureString(className).Y;
1778 var submarineNameText =
new GUITextBlock(
new RectTransform(
new Point(subInfoTextLayout.Rect.Width, nameHeight + HUDLayoutSettings.Padding / 2), subInfoTextLayout.RectTransform), sub.Info.DisplayName, textAlignment: Alignment.CenterLeft, font: GUIStyle.LargeFont) { CanBeFocused =
false };
1779 submarineNameText.RectTransform.MinSize =
new Point(0, (
int)submarineNameText.TextSize.Y);
1780 var submarineClassText =
new GUITextBlock(
new RectTransform(
new Point(subInfoTextLayout.Rect.Width, classHeight), subInfoTextLayout.RectTransform), className, textAlignment: Alignment.CenterLeft, font: GUIStyle.SubHeadingFont) { CanBeFocused =
false };
1781 submarineClassText.RectTransform.MinSize =
new Point(0, (
int)submarineClassText.TextSize.Y);
1783 if (GameMain.GameSession?.GameMode is CampaignMode campaign)
1785 GUILayoutGroup headerLayout =
new GUILayoutGroup(
new RectTransform(
new Vector2(1f, 0.09f), paddedFrame.RectTransform) { RelativeOffset = new Vector2(0f, 0.43f) }, isHorizontal:
true) { Stretch =
true };
1786 GUIImage headerIcon =
new GUIImage(
new RectTransform(Vector2.One, headerLayout.RectTransform, scaleBasis:
ScaleBasis.BothHeight), style:
"SubmarineIcon");
1787 new GUITextBlock(
new RectTransform(Vector2.One, headerLayout.RectTransform), TextManager.Get(
"uicategory.upgrades"), font: GUIStyle.LargeFont);
1789 var upgradeRootLayout =
new GUILayoutGroup(
new RectTransform(
new Vector2(1f, 0.48f), paddedFrame.RectTransform,
Anchor.BottomLeft,
Pivot.BottomLeft), isHorizontal:
true);
1791 var upgradeCategoryPanel = UpgradeStore.CreateUpgradeCategoryList(
new RectTransform(
new Vector2(0.4f, 1f), upgradeRootLayout.RectTransform));
1792 upgradeCategoryPanel.HideChildrenOutsideFrame =
true;
1793 UpgradeStore.UpdateCategoryList(upgradeCategoryPanel, campaign, sub, UpgradeStore.GetApplicableCategories(sub).ToArray());
1794 GUIComponent[] toRemove = upgradeCategoryPanel.Content.FindChildren(c => !c.Enabled).ToArray();
1795 toRemove.ForEach(c => upgradeCategoryPanel.RemoveChild(c));
1797 var upgradePanel =
new GUIListBox(
new RectTransform(
new Vector2(0.6f, 1f), upgradeRootLayout.RectTransform));
1798 upgradeCategoryPanel.OnSelected = (component, userData) =>
1800 upgradePanel.ClearChildren();
1801 if (userData is UpgradeStore.CategoryData categoryData &&
Submarine.MainSub !=
null)
1803 foreach (UpgradePrefab prefab
in categoryData.Prefabs)
1805 var frame = UpgradeStore.CreateUpgradeFrame(prefab, categoryData.Category, campaign,
new RectTransform(
new Vector2(1f, 0.3f), upgradePanel.Content.RectTransform), addBuyButton:
false).Frame;
1806 UpgradeStore.UpdateUpgradeEntry(frame, prefab, categoryData.Category, campaign);
1814 var specsListBox =
new GUIListBox(
new RectTransform(
new Vector2(1f, 0.57f), paddedFrame.RectTransform,
Anchor.BottomLeft,
Pivot.BottomLeft))
1816 CurrentSelectMode = GUIListBox.SelectMode.None
1818 sub.Info.CreateSpecsWindow(specsListBox, GUIStyle.Font,
1819 includeTitle:
false,
1820 includeClass:
false,
1821 includeDescription:
true);
1825 private GUIImage talentPointNotification, eventLogNotification;
1830 List<GUITextBlock> skillNames =
new List<GUITextBlock>();
1831 foreach (
Skill skill
in info.Job.GetSkills().OrderByDescending(
static s => s.Level))
1835 skillNames.Add(skillName);
1836 skillName.RectTransform.MinSize =
new Point(0, skillName.Rect.Height);
1841 float modifiedSkillLevel = MathF.Floor(character?.GetSkillLevel(skill.
Identifier) ?? skill.
Level);
1842 if (!MathUtils.NearlyEqual(MathF.Floor(modifiedSkillLevel), MathF.Floor(skill.
Level)))
1844 int skillChange = (int)MathF.Floor(modifiedSkillLevel - MathF.Floor(skill.
Level));
1845 string stringColor = skillChange
switch
1847 > 0 => XMLExtensions.ToStringHex(GUIStyle.Green),
1848 < 0 => XMLExtensions.ToStringHex(GUIStyle.Red),
1849 _ => XMLExtensions.ToStringHex(GUIStyle.TextColorNormal)
1852 RichString changeText =
RichString.
Rich($
"(‖color:{stringColor}‖{(skillChange > 0 ? "+
" : string.Empty) + skillChange}‖color:end‖)");
1858 parent.RecalculateChildren();
1865 talentMenu.UpdateTalentInfo();
1871 foreach (Identifier identifier
in registeredEvents)
1873 campaign.OnMoneyChanged.TryDeregister(identifier);
static Character? Controlled
Stores information about the Character that is needed between rounds in the menu etc....
GUIComponent CreateInfoFrame(GUIFrame frame, bool returnParent, Sprite permissionIcon=null)
void DrawJobIcon(SpriteBatch spriteBatch, Rectangle area, bool evaluateDisguise=false)
IEnumerable< Character > GetCharacters()
virtual void RemoveChild(GUIComponent child)
void Pulsate(Vector2 startScale, Vector2 endScale, float duration)
virtual void AddToGUIUpdateList(bool ignoreChildren=false, int order=0)
virtual void ClearChildren()
GUIComponent FindChild(Func< GUIComponent, bool > predicate, bool recursive=false)
RectTransform RectTransform
GUIFrame Content
A frame that contains the contents of the listbox. The frame itself is not rendered.
static void AutoScaleAndNormalize(params GUITextBlock[] textBlocks)
Set the text scale of the GUITextBlocks so that they all use the same scale and can fit the text with...
static GameSession?? GameSession
static bool IsMultiplayer
bool IsRunning
Is a round currently running?
static TabMenu TabMenuInstance
static void UpdateTalentNotificationIndicator(GUIImage indicator)
RoundSummary RoundSummary
static bool IsTabMenuOpen
static string GetTimeStamp()
PlayerConnectionChangeType ChangeType
static RichString Rich(LocalizedString str, Func< string, string >? postProcess=null)
void CreateReputationInfoPanel(GUIComponent parent, CampaignMode campaignMode)
readonly Identifier Identifier
static Submarine MainSub
Note that this can be null in some situations, e.g. editors and missions that don't load a submarine.
void Draw(SpriteBatch spriteBatch, RectangleF rect, Color color, SpriteEffects spriteEffects=SpriteEffects.None, Vector2? uvOffset=null)
PlayerConnectionChangeType
@ Character
Characters only
static GUIButton JobInfoFrame