4 using Microsoft.Xna.Framework;
5 using Microsoft.Xna.Framework.Graphics;
7 using System.Collections.Generic;
8 using System.Collections.Immutable;
9 using System.Globalization;
14 partial class NetLobbyScreen : Screen
16 private GUIListBox chatBox;
17 private GUIButton serverLogReverseButton;
18 private GUIListBox serverLogBox, serverLogFilterTicks;
20 private GUIComponent jobVariantTooltip;
22 private GUIComponent playStyleIconContainer;
24 private GUITextBox chatInput;
25 private GUITextBox serverLogFilter;
38 private readonly List<GUIComponent> traitorElements =
new List<GUIComponent>();
71 private bool createPendingChangesText =
true;
85 private Sprite backgroundSprite;
97 private readonly List<GUIComponent> midRoundRespawnSettings =
new List<GUIComponent>();
98 private readonly List<GUIComponent> permadeathEnabledRespawnSettings =
new List<GUIComponent>();
99 private readonly List<GUIComponent> permadeathDisabledRespawnSettings =
new List<GUIComponent>();
100 private readonly List<GUIComponent> ironmanDisabledRespawnSettings =
new List<GUIComponent>();
101 private readonly List<GUIComponent> campaignDisabledElements =
new List<GUIComponent>();
109 private Identifier micIconStyle;
110 private float micCheckTimer;
111 const float MicCheckInterval = 1.0f;
113 private float autoRestartTimer;
127 private readonly List<GUIComponent> clientDisabledElements =
new List<GUIComponent>();
132 private readonly List<GUIComponent> clientHiddenElements =
new List<GUIComponent>();
134 private readonly List<GUIComponent> botSettingsElements =
new List<GUIComponent>();
136 private readonly Dictionary<GUIComponent, string> settingAssignedComponents =
new Dictionary<GUIComponent, string>();
150 private readonly List<GUIButton> chatPanelTabButtons =
new List<GUIButton>();
152 private GUITextBlock publicOrPrivateText, playstyleText;
158 private int selectedModeIndex;
161 get {
return selectedModeIndex; }
168 selectedModeIndex = value;
205 set { shuttleTickBox.
Selected = value; }
223 if (missionTypeTickBoxes[index].
Selected)
239 missionTypeTickBoxes[index].
Selected = ((int)type & (
int)value) != 0;
253 return new List<JobVariant>();
256 List<JobVariant> jobPreferences =
new List<JobVariant>();
259 if (child.
UserData is not JobVariant jobPrefab) {
continue; }
260 jobPreferences.Add(jobPrefab);
262 return jobPreferences;
274 if (levelSeed == value) {
return; }
278 int intSeed = ToolBox.StringToInt(levelSeed);
284 private const float MainPanelWidth = 0.7f;
285 private const float SidePanelWidth = 0.3f;
289 private const float PanelSpacing = 0.005f;
294 private static int PanelBorderSize => GUI.IntScale(20);
296 private static Point GetSizeWithoutBorder(
GUIComponent parent) =>
new Point(parent.Rect.Width - PanelBorderSize * 2, parent.Rect.Height - PanelBorderSize * 2);
303 RelativeSpacing = PanelSpacing
309 RelativeSpacing = PanelSpacing
312 var mainPanel =
new GUIFrame(
new RectTransform(
new Vector2(MainPanelWidth, 1.0f), horizontalLayout.RectTransform));
314 var mainPanelLayout =
new GUILayoutGroup(
new RectTransform(
new Point(mainPanel.Rect.Width, mainPanel.Rect.Height - PanelBorderSize), mainPanel.RectTransform,
Anchor.TopCenter), childAnchor:
Anchor.TopCenter)
318 RelativeSpacing = PanelSpacing * 4
324 RelativeSpacing = 0.025f
326 CreateServerInfoContents(serverInfoHolder);
328 var mainPanelTopLayout =
new GUILayoutGroup(
new RectTransform(
new Point(mainPanel.Rect.Width - PanelBorderSize * 2, mainPanel.Rect.Height / 2), mainPanelLayout.RectTransform,
Anchor.Center), isHorizontal:
true)
331 RelativeSpacing = PanelSpacing
334 var mainPanelBottomLayout =
new GUILayoutGroup(
new RectTransform(
new Point(mainPanel.Rect.Width - PanelBorderSize * 2, mainPanel.Rect.Height / 2), mainPanelLayout.RectTransform,
Anchor.Center), isHorizontal:
true)
337 RelativeSpacing = PanelSpacing
344 CreateGameModeDropdown(mainPanelTopLayout);
345 CreateSubmarineListPanel(mainPanelTopLayout);
346 CreateSubmarineInfoPanel(mainPanelTopLayout);
352 CreateGameModePanel(mainPanelBottomLayout);
353 CreateGameModeSettingsPanel(mainPanelBottomLayout);
354 CreateGeneralSettingsPanel(mainPanelBottomLayout);
355 mainPanelBottomLayout.Recalculate();
357 foreach (var child
in mainPanelBottomLayout.GetAllChildren<
GUIComponent>())
359 if (traitorDangerGroup.
Children.Contains(child))
365 child.DisabledColor =
new Color(child.Color, child.Color.A / 255.0f * 0.8f);
368 textBlock.DisabledTextColor =
new Color(textBlock.TextColor, textBlock.TextColor.A / 255.0f * 0.8f);
376 var sidePanel =
new GUIFrame(
new RectTransform(
new Vector2(SidePanelWidth, 1.0f), horizontalLayout.RectTransform));
378 sidePanel.RectTransform,
Anchor.Center))
380 RelativeSpacing = PanelSpacing * 4,
384 CreateSidePanelContents(sidePanelLayout);
393 RelativeSpacing = PanelSpacing
395 CreateBottomPanelContents(bottomBar);
398 private void AssignComponentToServerSetting(
GUIComponent component,
string settingName)
400 settingAssignedComponents[component] = settingName;
405 settingAssignedComponents.ForEach(kvp =>
GameMain.
Client.ServerSettings.AssignGUIComponent(kvp.Value, kvp.Key));
408 private void CreateServerInfoContents(
GUIComponent parent)
413 HideElementsOutsideFrame =
true,
414 IgnoreLayoutGroups =
true
417 GUIFrame serverInfoContent =
new GUIFrame(
new RectTransform(
new Vector2(0.98f, 0.9f), serverInfoFrame.
RectTransform,
Anchor.Center), style:
null);
419 var serverLabelContainer =
new GUILayoutGroup(
new RectTransform(
new Vector2(0.5f, 0.05f), serverInfoContent.RectTransform), isHorizontal:
true)
421 AbsoluteSpacing = GUI.IntScale(5)
424 playstyleText =
new GUITextBlock(
new RectTransform(
new Vector2(0.3f, 1.0f), serverLabelContainer.RectTransform),
425 "", font: GUIStyle.SmallFont, textAlignment: Alignment.Center, textColor: Color.White, style:
"GUISlopedHeader");
426 publicOrPrivateText =
new GUITextBlock(
new RectTransform(
new Vector2(0.3f, 1.0f), serverLabelContainer.RectTransform),
427 "", font: GUIStyle.SmallFont, textAlignment: Alignment.Center, textColor: Color.White, style:
"GUISlopedHeader");
429 var serverNameShadow =
new GUITextBlock(
new RectTransform(
new Vector2(0.2f, 0.3f), serverInfoContent.RectTransform,
Anchor.CenterLeft) { AbsoluteOffset = new Point(GUI.IntScale(3)) },
430 string.Empty, font: GUIStyle.LargeFont, textColor: Color.Black)
432 IgnoreLayoutGroups =
true
434 var serverName =
new GUITextBlock(
new RectTransform(
new Vector2(0.2f, 0.3f), serverInfoContent.RectTransform,
Anchor.CenterLeft),
435 string.Empty, font: GUIStyle.LargeFont, textColor: GUIStyle.TextColorBright)
437 IgnoreLayoutGroups =
true,
438 TextGetter = serverNameShadow.TextGetter = () => GameMain.Client?.ServerName
441 ServerMessageButton =
new GUIButton(
new RectTransform(
new Vector2(0.2f, 0.15f), serverInfoContent.RectTransform,
Anchor.BottomLeft),
442 TextManager.Get(
"workshopitemdescription"), style:
"GUIButtonSmall")
444 IgnoreLayoutGroups =
true,
445 OnClicked = (bt, userdata) =>
447 if (GameMain.Client?.ServerSettings is { } serverSettings)
449 CreateServerMessagePopup(serverSettings.ServerName, serverSettings.ServerMessageText);
455 playStyleIconContainer =
new GUILayoutGroup(
new RectTransform(
new Vector2(0.5f, 0.4f), serverInfoContent.RectTransform,
Anchor.BottomRight), isHorizontal:
true, childAnchor:
Anchor.BottomRight)
457 AbsoluteSpacing = GUI.IntScale(5)
460 Favorite =
new GUITickBox(
new RectTransform(
new Vector2(0.5f, 0.5f), serverInfoContent.RectTransform,
Anchor.TopRight, scaleBasis:
ScaleBasis.BothHeight),
461 "",
null,
"GUIServerListFavoriteTickBox")
463 IgnoreLayoutGroups =
true,
465 ToolTip = TextManager.Get(
"addtofavorites"),
466 OnSelected = (tickbox) =>
468 if (GameMain.Client ==
null) {
return true; }
469 ServerInfo info = GameMain.Client.CreateServerInfoFromSettings();
470 if (tickbox.Selected)
472 GameMain.ServerListScreen.AddToFavoriteServers(info);
476 GameMain.ServerListScreen.RemoveFromFavoriteServers(info);
478 tickbox.ToolTip = TextManager.Get(tickbox.Selected ?
"removefromfavorites" :
"addtofavorites");
483 SettingsButton =
new GUIButton(
new RectTransform(
new Vector2(0.25f, 0.4f), serverInfoContent.RectTransform,
Anchor.TopRight),
484 TextManager.Get(
"ServerSettingsButton"), style:
"GUIButtonFreeScale");
487 private void CreateServerMessagePopup(
string serverName,
string message)
489 if (
string.IsNullOrEmpty(message)) {
return; }
490 var popup =
new GUIMessageBox(serverName,
string.Empty, minSize:
new Point(GUI.IntScale(650), GUI.IntScale(650)));
492 popup.Header.Font = GUIStyle.LargeFont;
493 popup.Header.RectTransform.MinSize =
new Point(0, (
int)popup.Header.TextSize.Y);
494 var textListBox =
new GUIListBox(
new RectTransform(
new Vector2(1.0f, 0.7f), popup.Content.RectTransform));
495 var text =
new GUITextBlock(
new RectTransform(
new Vector2(1.0f, 0.0f), textListBox.Content.RectTransform), message, wrap:
true)
499 text.RectTransform.MinSize =
new Point(0, (
int)text.TextSize.Y);
504 playStyleIconContainer?.ClearChildren();
505 if (
GameMain.
Client?.
ClientPeer?.ServerConnection is not { } serverConnection || serverConnection.Endpoint ==
null) {
return; }
509 foreach (var tag
in playStyleTags)
511 var playStyleIcon = GUIStyle.GetComponentStyle($
"PlayStyleIcon.{tag}")
513 if (playStyleIcon is
null) {
continue; }
516 playStyleIcon, scaleToFit:
true)
518 ToolTip = TextManager.Get($
"servertagdescription.{tag}"),
524 private void CreateGameModeDropdown(
GUIComponent parent)
533 RelativeSpacing = 0.005f
536 var modeLabel = CreateSubHeader(
"GameMode", gameModeHolder);
537 var voteText =
new GUITextBlock(
new RectTransform(
new Vector2(0.5f, 1.0f), modeLabel.RectTransform,
Anchor.TopRight),
538 TextManager.Get(
"Votes"), textAlignment: Alignment.CenterRight)
540 UserData =
"modevotes",
543 ModeList =
new GUIListBox(
new RectTransform(Vector2.One, gameModeHolder.
RectTransform))
545 PlaySoundOnSelect =
true,
546 OnSelected = VotableClicked
549 foreach (GameModePreset mode
in GameModePreset.List)
551 if (mode.IsSinglePlayer) {
continue; }
553 var modeFrame =
new GUIFrame(
new RectTransform(
new Vector2(1.0f, 0.25f), ModeList.Content.RectTransform), style:
null)
558 var modeContent =
new GUILayoutGroup(
new RectTransform(
new Vector2(0.76f, 0.9f), modeFrame.RectTransform,
Anchor.CenterRight))
560 AbsoluteSpacing = GUI.IntScale(5),
564 var modeTitle =
new GUITextBlock(
new RectTransform(
new Vector2(1.0f, 0.0f), modeContent.RectTransform), mode.Name, font: GUIStyle.SubHeadingFont);
565 modeTitle.RectTransform.NonScaledSize =
new Point(
int.MaxValue, (
int)modeTitle.TextSize.Y);
566 modeTitle.RectTransform.IsFixedSize =
true;
567 var modeDescription =
new GUITextBlock(
new RectTransform(
new Vector2(1.0f, 0.0f), modeContent.RectTransform), mode.Description, font: GUIStyle.SmallFont, wrap:
true);
569 modeDescription.Padding =
new Vector4(modeDescription.Padding.X, modeDescription.Padding.Y, GUI.IntScale(30), modeDescription.Padding.W);
570 modeTitle.HoverColor = modeDescription.HoverColor = modeTitle.SelectedColor = modeDescription.SelectedColor = Color.Transparent;
571 modeTitle.HoverTextColor = modeDescription.HoverTextColor = modeTitle.TextColor;
572 modeTitle.TextColor = modeDescription.TextColor = modeTitle.TextColor * 0.5f;
573 modeFrame.OnAddedToGUIUpdateList = (c) =>
575 modeTitle.State = modeDescription.State = c.State;
577 modeDescription.RectTransform.SizeChanged += () =>
579 modeDescription.RectTransform.NonScaledSize =
new Point(modeDescription.Rect.Width, (
int)modeDescription.TextSize.Y);
580 modeFrame.RectTransform.MinSize =
new Point(0, (
int)(modeContent.Children.Sum(c => c.Rect.Height + modeContent.AbsoluteSpacing) / modeContent.RectTransform.RelativeSize.Y));
583 new GUIImage(
new RectTransform(
new Vector2(0.2f, 0.8f), modeFrame.RectTransform,
Anchor.CenterLeft) { RelativeOffset = new Vector2(0.02f, 0.0f) },
584 style:
"GameModeIcon." + mode.Identifier, scaleToFit:
true);
588 private void CreateSubmarineListPanel(GUIComponent parent)
590 var submarineListHolder =
new GUILayoutGroup(
new RectTransform(Vector2.One, parent.RectTransform))
593 RelativeSpacing = 0.005f
596 var subLabel = CreateSubHeader(
"Submarine", submarineListHolder);
599 new RectTransform(Vector2.One * 1.2f, subLabel.RectTransform, anchor:
Anchor.CenterRight,
601 { AbsoluteOffset = new Point(0, GUI.IntScale(5)) },
604 OnClicked = (button, o) =>
606 CreateSubmarineVisibilityMenu();
610 clientHiddenElements.Add(SubVisibilityButton);
612 var filterContainer =
new GUILayoutGroup(
new RectTransform(
new Vector2(1.0f, 0.05f), submarineListHolder.RectTransform), isHorizontal:
true)
616 var searchTitle =
new GUITextBlock(
new RectTransform(
new Vector2(0.001f, 1.0f), filterContainer.RectTransform), TextManager.Get(
"serverlog.filter"), textAlignment: Alignment.CenterLeft, font: GUIStyle.Font);
617 subSearchBox =
new GUITextBox(
new RectTransform(Vector2.One, filterContainer.RectTransform,
Anchor.CenterRight), font: GUIStyle.Font, createClearButton:
true);
619 subSearchBox.
OnSelected += (sender, userdata) => { searchTitle.Visible =
false; };
620 subSearchBox.
OnDeselected += (sender, userdata) => { searchTitle.Visible =
true; };
623 UpdateSubVisibility();
627 SubList =
new GUIListBox(
new RectTransform(
new Vector2(1.0f, 0.93f), submarineListHolder.RectTransform))
629 PlaySoundOnSelect =
true,
630 OnSelected = VotableClicked
633 var voteText =
new GUITextBlock(
new RectTransform(
new Vector2(0.5f, 1.0f), subLabel.RectTransform,
Anchor.TopRight),
634 TextManager.Get(
"Votes"), textAlignment: Alignment.CenterRight)
636 UserData =
"subvotes",
642 private void CreateSubmarineInfoPanel(GUIComponent parent)
644 var submarineInfoHolder =
new GUILayoutGroup(
new RectTransform(Vector2.One, parent.RectTransform,
Anchor.Center))
647 RelativeSpacing = 0.005f
651 subPreviewContainer =
new GUIFrame(
new RectTransform(Vector2.One, submarineInfoHolder.RectTransform), style:
null);
654 if (SelectedSub !=
null) { CreateSubPreview(SelectedSub); }
658 private GUIComponent CreateGameModePanel(GUIComponent parent)
660 var gameModeSpecificFrame =
new GUIFrame(
new RectTransform(Vector2.One, parent.RectTransform), style:
null);
661 CampaignSetupFrame =
new GUIFrame(
new RectTransform(Vector2.One, gameModeSpecificFrame.RectTransform), style:
null)
665 CampaignFrame =
new GUIFrame(
new RectTransform(Vector2.One, gameModeSpecificFrame.RectTransform), style:
null)
669 GUILayoutGroup campaignContent =
new GUILayoutGroup(
new RectTransform(
new Vector2(0.9f, 0.5f), CampaignFrame.RectTransform,
Anchor.Center))
671 RelativeSpacing = 0.05f,
674 new GUITextBlock(
new RectTransform(
new Vector2(1.0f, 0.3f), campaignContent.RectTransform),
675 TextManager.Get(
"gamemode.multiplayercampaign"), font: GUIStyle.SubHeadingFont, textAlignment: Alignment.Center);
677 QuitCampaignButton =
new GUIButton(
new RectTransform(
new Vector2(1.0f, 0.3f), campaignContent.RectTransform),
678 TextManager.Get(
"quitbutton"), textAlignment: Alignment.Center)
680 OnClicked = (_, __) =>
682 if (GameMain.Client ==
null) {
return false; }
683 if (GameMain.Client.GameStarted)
685 GameMain.Client.RequestRoundEnd(save:
false);
689 GameMain.Client.RequestRoundEnd(save:
false, quitCampaign:
true);
696 MissionTypeFrame =
new GUIFrame(
new RectTransform(Vector2.One, gameModeSpecificFrame.RectTransform), style:
null);
698 GUILayoutGroup missionHolder =
new GUILayoutGroup(
new RectTransform(Vector2.One, MissionTypeFrame.RectTransform))
703 CreateSubHeader(
"MissionType", missionHolder);
704 missionTypeList =
new GUIListBox(
new RectTransform(Vector2.One, missionHolder.RectTransform))
706 OnSelected = (component, obj) =>
711 clientDisabledElements.Add(missionTypeList);
714 missionTypeTickBoxes =
new GUITickBox[missionTypes.Length - 2];
716 for (
int i = 0; i < missionTypes.Length; i++)
718 var missionType = missionTypes[i];
721 GUIFrame frame =
new GUIFrame(
new RectTransform(
new Vector2(1.0f, 0.05f), missionTypeList.
Content.
RectTransform) { MinSize = new Point(0, GUI.IntScale(30)) }, style:
null)
723 UserData = missionType,
726 if (MissionPrefab.HiddenMissionClasses.Contains(missionType))
728 missionTypeTickBoxes[index] =
new GUITickBox(
new RectTransform(Vector2.One, frame.RectTransform),
string.Empty)
730 UserData = (int)missionType,
737 missionTypeTickBoxes[index] =
new GUITickBox(
new RectTransform(Vector2.One, frame.RectTransform),
738 TextManager.Get(
"MissionType." + missionType.ToString()))
740 UserData = (int)missionType,
741 ToolTip = TextManager.Get(
"MissionTypeDescription." + missionType.ToString()),
742 OnSelected = (tickbox) =>
745 int missionTypeAnd = (int)
MissionType.All & (!tickbox.Selected ? (~(
int)tickbox.UserData) : (
int)
MissionType.All);
746 GameMain.Client?.ServerSettings.ClientAdminWrite(
ServerSettings.
NetFlags.Misc, (
int)missionTypeOr, (int)missionTypeAnd);
754 clientDisabledElements.AddRange(missionTypeTickBoxes);
756 return gameModeSpecificFrame;
759 private GUIComponent CreateGameModeSettingsPanel(GUIComponent parent)
765 GUILayoutGroup settingsLayout =
new GUILayoutGroup(
new RectTransform(Vector2.One, parent.RectTransform))
769 CreateSubHeader(
"GameModeSettings", settingsLayout);
771 var settingsContent =
new GUIListBox(
new RectTransform(Vector2.One, settingsLayout.RectTransform)).Content;
775 var seedLabel =
new GUITextBlock(
new RectTransform(
new Vector2(1.0f, 0.1f), settingsContent.RectTransform), TextManager.Get(
"LevelSeed"))
779 LevelSeedBox =
new GUITextBox(
new RectTransform(
new Vector2(0.5f, 1.0f), seedLabel.RectTransform,
Anchor.CenterRight));
780 LevelSeedBox.OnDeselected += (textBox, key) =>
784 campaignDisabledElements.Add(LevelSeedBox);
785 campaignDisabledElements.Add(seedLabel);
786 clientDisabledElements.Add(LevelSeedBox);
787 clientDisabledElements.Add(seedLabel);
788 LevelSeed = ToolBox.RandomSeed(8);
792 var levelDifficultyHolder = CreateLabeledSlider(settingsContent,
"LevelDifficulty",
"",
"LevelDifficultyExplanation", out levelDifficultySlider, out var difficultySliderLabel,
793 step: 0.01f, range:
new Vector2(0.0f, 100.0f));
794 levelDifficultySlider.OnReleased = (scrollbar, value) =>
799 levelDifficultySlider.OnMoved = (scrollbar, value) =>
801 if (!EventManagerSettings.Prefabs.Any()) {
return true; }
802 difficultySliderLabel.Text =
803 EventManagerSettings.GetByDifficultyPercentile(value).Name
804 + $
" ({TextManager.GetWithVariable("percentageformat
", "[value]
", ((int)Math.Round(scrollbar.BarScrollValue)).ToString())})";
805 difficultySliderLabel.TextColor = ToolBox.GradientLerp(scrollbar.BarScroll, GUIStyle.Green, GUIStyle.Orange, GUIStyle.Red);
809 campaignDisabledElements.AddRange(levelDifficultyHolder.GetAllChildren());
810 clientDisabledElements.AddRange(levelDifficultyHolder.GetAllChildren());
813 CreateSubHeader(
"BotSettings", settingsContent);
815 var botCountSettingHolder =
new GUILayoutGroup(
new RectTransform(
new Vector2(1.0f, 0.1f), settingsContent.RectTransform), isHorizontal:
true, childAnchor:
Anchor.CenterLeft) { Stretch =
true };
816 new GUITextBlock(
new RectTransform(
new Vector2(0.7f, 0.0f), botCountSettingHolder.RectTransform), TextManager.Get(
"BotCount"), wrap:
true);
817 var botCountSelection =
new GUISelectionCarousel<int>(
new RectTransform(
new Vector2(0.5f, 1.0f), botCountSettingHolder.RectTransform));
818 for (
int i = 0; i <= NetConfig.MaxPlayers; i++)
820 botCountSelection.AddElement(i, i.ToString());
823 clientDisabledElements.AddRange(botCountSettingHolder.GetAllChildren());
824 botSettingsElements.Add(botCountSelection);
826 var botSpawnModeSettingHolder =
new GUILayoutGroup(
new RectTransform(
new Vector2(1.0f, 0.1f), settingsContent.RectTransform), isHorizontal:
true, childAnchor:
Anchor.CenterLeft) { Stretch =
true };
827 new GUITextBlock(
new RectTransform(
new Vector2(0.7f, 0.0f), botSpawnModeSettingHolder.RectTransform), TextManager.Get(
"BotSpawnMode"), wrap:
true);
828 var botSpawnModeSelection =
new GUISelectionCarousel<BotSpawnMode>(
new RectTransform(
new Vector2(0.5f, 1.0f), botSpawnModeSettingHolder.RectTransform));
829 foreach (var botSpawnMode
in Enum.GetValues(typeof(
BotSpawnMode)).Cast<BotSpawnMode>())
831 botSpawnModeSelection.AddElement(botSpawnMode, botSpawnMode.ToString(), TextManager.Get($
"botspawnmode.{botSpawnMode}.tooltip"));
833 botSpawnModeSelection.OnValueChanged += (_) => GameMain.Client?.ServerSettings.ClientAdminWrite(
ServerSettings.
NetFlags.Properties);
835 clientDisabledElements.AddRange(botSpawnModeSettingHolder.GetAllChildren());
836 botSettingsElements.Add(botSpawnModeSelection);
838 botCountSelection.OnValueChanged += (_) =>
840 botSpawnModeSelection.Enabled = GameMain.Client.ServerSettings.BotCount > 0;
846 CreateSubHeader(
"TraitorSettings", settingsContent);
849 new GUIFrame(
new RectTransform(
new Point(1, GUI.IntScale(5)), settingsContent.RectTransform), style:
null);
853 var traitorProbabilityHolder = CreateLabeledSlider(settingsContent,
"traitor.probability",
"",
"traitor.probability.tooltip",
854 out traitorProbabilitySlider, out var traitorProbabilityText,
855 step: 0.01f, range:
new Vector2(0.0f, 1.0f));
856 traitorProbabilitySlider.OnMoved = (scrollbar, value) =>
858 traitorProbabilityText.Text = TextManager.GetWithVariable(
"percentageformat",
"[value]", ((
int)Math.Round(scrollbar.BarScrollValue * 100)).ToString());
859 traitorProbabilityText.TextColor =
862 ToolBox.GradientLerp(scrollbar.BarScroll, GUIStyle.Yellow, GUIStyle.Orange, GUIStyle.Red);
863 RefreshEnabledElements();
866 traitorProbabilitySlider.OnMoved(traitorProbabilitySlider, traitorProbabilitySlider.BarScroll);
867 traitorProbabilitySlider.OnReleased += (scrollbar, value) => { GameMain.Client?.ServerSettings.ClientAdminWrite(
ServerSettings.
NetFlags.Properties);
return true; };
869 traitorElements.Clear();
870 clientDisabledElements.AddRange(traitorProbabilityHolder.GetAllChildren());
872 var traitorDangerHolder =
new GUILayoutGroup(
new RectTransform(
new Vector2(1.0f, 0.1f), settingsContent.RectTransform), isHorizontal:
true, childAnchor:
Anchor.CenterLeft)
877 var dangerLevelLabel =
new GUITextBlock(
new RectTransform(
new Vector2(0.7f, 1.0f), traitorDangerHolder.RectTransform), TextManager.Get(
"traitor.dangerlevelsetting"), wrap:
true)
879 ToolTip = TextManager.Get(
"traitor.dangerlevelsetting.tooltip")
882 var traitorDangerContainer =
new GUILayoutGroup(
new RectTransform(
new Vector2(0.5f, 1.0f), traitorDangerHolder.RectTransform), isHorizontal:
true, childAnchor:
Anchor.CenterLeft) { RelativeSpacing = 0.05f, Stretch =
true };
883 var traitorDangerButtons =
new GUIButton[2];
884 traitorDangerButtons[0] =
new GUIButton(
new RectTransform(
new Vector2(0.15f, 1.0f), traitorDangerContainer.RectTransform), style:
"GUIButtonToggleLeft")
886 OnClicked = (button, obj) =>
893 traitorDangerGroup =
new GUILayoutGroup(
new RectTransform(
new Vector2(0.7f, 1.0f), traitorDangerContainer.RectTransform), isHorizontal:
true, childAnchor:
Anchor.CenterLeft)
898 for (
int i = TraitorEventPrefab.MinDangerLevel; i <= TraitorEventPrefab.MaxDangerLevel; i++)
900 var difficultyColor = Mission.GetDifficultyColor(i);
901 new GUIImage(
new RectTransform(
new Vector2(0.75f), traitorDangerGroup.
RectTransform),
"DifficultyIndicator", scaleToFit:
true)
905 $
"‖color:{Color.White.ToStringHex()}‖{TextManager.Get($"traitor.dangerlevel.{i}
")}‖color:end‖" +
'\n' +
906 TextManager.Get($
"traitor.dangerlevel.{i}.description")),
907 Color = difficultyColor,
908 DisabledColor = Color.Gray * 0.5f,
912 traitorDangerButtons[1] =
new GUIButton(
new RectTransform(
new Vector2(0.15f, 1.0f), traitorDangerContainer.RectTransform), style:
"GUIButtonToggleRight")
914 OnClicked = (button, obj) =>
922 SetTraitorDangerIndicators(GameMain.Client?.ServerSettings.TraitorDangerLevel ?? TraitorEventPrefab.MinDangerLevel);
923 traitorElements.Add(dangerLevelLabel);
924 traitorElements.AddRange(traitorDangerGroup.
Children);
925 traitorElements.AddRange(traitorDangerButtons);
927 var traitorsMinPlayerCountHolder =
new GUILayoutGroup(
new RectTransform(
new Vector2(1.0f, 0.1f), settingsContent.RectTransform), isHorizontal:
true, childAnchor:
Anchor.CenterLeft) { Stretch =
true };
928 new GUITextBlock(
new RectTransform(
new Vector2(0.7f, 0.0f), traitorsMinPlayerCountHolder.RectTransform), TextManager.Get(
"ServerSettingsTraitorsMinPlayerCount"), wrap:
true)
930 ToolTip = TextManager.Get(
"ServerSettingsTraitorsMinPlayerCountToolTip")
932 var traitorsMinPlayerCount =
new GUISelectionCarousel<int>(
new RectTransform(
new Vector2(0.5f, 1.0f), traitorsMinPlayerCountHolder.RectTransform));
933 for (
int i = 1; i <= NetConfig.MaxPlayers; i++)
935 traitorsMinPlayerCount.AddElement(i, i.ToString());
937 traitorsMinPlayerCount.OnValueChanged += (_) => GameMain.Client?.ServerSettings.ClientAdminWrite(
ServerSettings.
NetFlags.Properties);
939 traitorElements.AddRange(traitorsMinPlayerCountHolder.Children);
941 foreach (var traitorElement
in traitorElements)
943 if (!clientDisabledElements.Contains(traitorElement))
945 clientDisabledElements.Add(traitorElement);
949 return settingsContent;
952 private GUIComponent CreateGeneralSettingsPanel(GUIComponent parent)
958 GUILayoutGroup settingsLayout =
new GUILayoutGroup(
new RectTransform(Vector2.One, parent.RectTransform))
962 var respawnSettingsHeader = CreateSubHeader(
"RespawnSettings", settingsLayout);
964 var settingsContent =
new GUIListBox(
new RectTransform(Vector2.One, settingsLayout.RectTransform)).Content;
968 var respawnModeHolder =
new GUILayoutGroup(
new RectTransform(
new Vector2(1.0f, 0.1f), settingsContent.RectTransform), isHorizontal:
true, childAnchor:
Anchor.CenterLeft) { Stretch =
true };
969 respawnModeLabel =
new GUITextBlock(
new RectTransform(
new Vector2(0.4f, 0.0f), respawnModeHolder.RectTransform), TextManager.Get(
"RespawnMode"), wrap:
true);
970 respawnModeSelection =
new GUISelectionCarousel<RespawnMode>(
new RectTransform(
new Vector2(0.6f, 1.0f), respawnModeHolder.RectTransform));
971 foreach (var respawnMode
in Enum.GetValues(typeof(
RespawnMode)).Cast<RespawnMode>())
973 respawnModeSelection.
AddElement(respawnMode, TextManager.Get($
"respawnmode.{respawnMode}"), TextManager.Get($
"respawnmode.{respawnMode}.tooltip"));
980 GUILayoutGroup shuttleHolder =
new GUILayoutGroup(
new RectTransform(
new Vector2(1.0f, 0.05f), settingsContent.RectTransform), isHorizontal:
true)
985 shuttleTickBox =
new GUITickBox(
new RectTransform(Vector2.One, shuttleHolder.RectTransform), TextManager.Get(
"RespawnShuttle"))
987 ToolTip = TextManager.Get(
"RespawnShuttleExplanation"),
989 OnSelected = (GUITickBox box) =>
996 midRoundRespawnSettings.Add(shuttleTickBox);
1009 ShuttleList =
new GUIDropDown(
new RectTransform(Vector2.One, shuttleHolder.RectTransform), elementCount: 10)
1011 OnSelected = (component, obj) =>
1013 GameMain.Client?.RequestSelectSub(obj as SubmarineInfo, isShuttle:
true);
1017 ShuttleList.ListBox.RectTransform.MinSize =
new Point(250, 0);
1018 shuttleHolder.RectTransform.MinSize =
new Point(0, ShuttleList.RectTransform.Children.Max(c => c.MinSize.Y));
1019 midRoundRespawnSettings.Add(ShuttleList);
1021 respawnIntervalElement = CreateLabeledSlider(settingsContent,
"ServerSettingsRespawnInterval",
"",
"", out var respawnIntervalSlider, out var respawnIntervalSliderLabel,
1022 range:
new Vector2(10.0f, 600.0f));
1023 LocalizedString intervalLabel = respawnIntervalSliderLabel.Text;
1024 respawnIntervalSlider.StepValue = 10.0f;
1025 respawnIntervalSlider.OnMoved = (GUIScrollBar scrollBar,
float barScroll) =>
1027 GUITextBlock text = scrollBar.UserData as GUITextBlock;
1028 text.Text = intervalLabel +
" " + ToolBox.SecondsToReadableTime(scrollBar.BarScrollValue);
1031 respawnIntervalSlider.OnReleased = (GUIScrollBar scrollBar,
float barScroll) =>
1036 respawnIntervalSlider.OnMoved(respawnIntervalSlider, respawnIntervalSlider.BarScroll);
1039 var minRespawnElement = CreateLabeledSlider(settingsContent,
"ServerSettingsMinRespawn",
"",
"ServerSettingsMinRespawnToolTip", out var minRespawnSlider, out var minRespawnSliderLabel,
1040 step: 0.1f, range:
new Vector2(0.0f, 1.0f));
1041 minRespawnSlider.OnMoved = (GUIScrollBar scrollBar,
float barScroll) =>
1043 GUITextBlock text = scrollBar.UserData as GUITextBlock;
1044 text.Text = ToolBox.GetFormattedPercentage(scrollBar.BarScrollValue);
1047 minRespawnSlider.OnReleased = (GUIScrollBar scrollBar,
float barScroll) =>
1052 minRespawnSlider.OnMoved(minRespawnSlider, minRespawnSlider.BarScroll);
1053 midRoundRespawnSettings.AddRange(minRespawnElement.GetAllChildren());
1056 var respawnDurationElement = CreateLabeledSlider(settingsContent,
"ServerSettingsRespawnDuration",
"",
"ServerSettingsRespawnDurationTooltip", out var respawnDurationSlider, out var respawnDurationSliderLabel,
1057 step: 0.1f, range:
new Vector2(60.0f, 660.0f));
1058 respawnDurationSlider.OnMoved = (GUIScrollBar scrollBar,
float barScroll) =>
1060 GUITextBlock text = scrollBar.UserData as GUITextBlock;
1061 text.Text = scrollBar.BarScrollValue <= 0 ? TextManager.Get(
"Unlimited") : ToolBox.SecondsToReadableTime(scrollBar.BarScrollValue);
1064 respawnDurationSlider.OnReleased = (GUIScrollBar scrollBar,
float barScroll) =>
1069 respawnDurationSlider.ScrollToValue = (GUIScrollBar scrollBar,
float barScroll) =>
1071 return barScroll >= 1.0f ? 0.0f : barScroll * (scrollBar.Range.Y - scrollBar.Range.X) + scrollBar.Range.X;
1073 respawnDurationSlider.ValueToScroll = (GUIScrollBar scrollBar,
float value) =>
1075 return value <= 0.0f ? 1.0f : (value - scrollBar.Range.X) / (scrollBar.Range.Y - scrollBar.Range.X);
1077 respawnDurationSlider.OnMoved(respawnDurationSlider, respawnDurationSlider.BarScroll);
1078 midRoundRespawnSettings.AddRange(respawnDurationElement.GetAllChildren());
1081 var skillLossElement = CreateLabeledSlider(settingsContent,
"ServerSettingsSkillLossPercentageOnDeath",
"",
"ServerSettingsSkillLossPercentageOnDeathToolTip",
1082 out var skillLossSlider, out var skillLossSliderLabel, range:
new Vector2(0, 100));
1083 skillLossSlider.StepValue = 1;
1084 skillLossSlider.OnMoved = (GUIScrollBar scrollBar,
float barScroll) =>
1086 GUITextBlock text = scrollBar.UserData as GUITextBlock;
1087 text.Text = TextManager.GetWithVariable(
"percentageformat",
"[value]", ((
int)Math.Round(scrollBar.BarScrollValue)).ToString());
1090 skillLossSlider.OnReleased = (GUIScrollBar scrollBar,
float barScroll) =>
1095 permadeathDisabledRespawnSettings.AddRange(skillLossElement.GetAllChildren());
1096 clientDisabledElements.AddRange(skillLossElement.GetAllChildren());
1098 skillLossSlider.OnMoved(skillLossSlider, skillLossSlider.BarScroll);
1100 var skillLossImmediateRespawnElement = CreateLabeledSlider(settingsContent,
"ServerSettingsSkillLossPercentageOnImmediateRespawn",
"",
"ServerSettingsSkillLossPercentageOnImmediateRespawnToolTip",
1101 out var skillLossImmediateRespawnSlider, out var skillLossImmediateRespawnSliderLabel, range:
new Vector2(0, 100));
1102 skillLossImmediateRespawnSlider.StepValue = 1;
1103 skillLossImmediateRespawnSlider.OnMoved = (GUIScrollBar scrollBar,
float barScroll) =>
1105 GUITextBlock text = scrollBar.UserData as GUITextBlock;
1106 text.Text = TextManager.GetWithVariable(
"percentageformat",
"[value]", ((
int)Math.Round(scrollBar.BarScrollValue)).ToString());
1109 skillLossImmediateRespawnSlider.OnReleased = (GUIScrollBar scrollBar,
float barScroll) =>
1114 midRoundRespawnSettings.AddRange(skillLossImmediateRespawnElement.GetAllChildren());
1115 permadeathDisabledRespawnSettings.AddRange(skillLossImmediateRespawnElement.GetAllChildren());
1117 skillLossImmediateRespawnSlider.OnMoved(skillLossImmediateRespawnSlider, skillLossImmediateRespawnSlider.BarScroll);
1119 var newCharacterCostSliderElement = CreateLabeledSlider(settingsContent,
1120 "ServerSettings.ReplaceCostPercentage",
"",
"ServerSettings.ReplaceCostPercentage.tooltip",
1121 out var newCharacterCostSlider, out var newCharacterCostSliderLabel,
1122 range:
new Vector2(0, 200), step: 10f);
1123 newCharacterCostSlider.StepValue = 10f;
1124 newCharacterCostSlider.OnMoved = (GUIScrollBar scrollBar,
float _) =>
1126 GUITextBlock textBlock = scrollBar.UserData as GUITextBlock;
1127 int currentMultiplier = (int)Math.Round(scrollBar.BarScrollValue);
1128 if (currentMultiplier < 1)
1130 textBlock.Text = TextManager.Get(
"ServerSettings.ReplaceCostPercentage.Free");
1134 textBlock.Text = TextManager.GetWithVariable(
"percentageformat",
"[value]", currentMultiplier.ToString());
1138 newCharacterCostSlider.OnReleased = (GUIScrollBar scrollBar,
float barScroll) =>
1143 clientDisabledElements.AddRange(newCharacterCostSliderElement.GetAllChildren());
1144 permadeathEnabledRespawnSettings.AddRange(newCharacterCostSliderElement.GetAllChildren());
1145 ironmanDisabledRespawnSettings.AddRange(newCharacterCostSliderElement.GetAllChildren());
1147 newCharacterCostSlider.OnMoved(newCharacterCostSlider, newCharacterCostSlider.BarScroll);
1149 var allowBotTakeoverTickbox =
new GUITickBox(
new RectTransform(Vector2.One, settingsContent.RectTransform), TextManager.Get(
"AllowBotTakeover"))
1151 ToolTip = TextManager.Get(
"AllowBotTakeover.Tooltip"),
1152 Selected = GameMain.Client !=
null && GameMain.Client.ServerSettings.AllowBotTakeoverOnPermadeath,
1153 OnSelected = (GUITickBox box) =>
1160 permadeathEnabledRespawnSettings.Add(allowBotTakeoverTickbox);
1161 ironmanDisabledRespawnSettings.Add(allowBotTakeoverTickbox);
1162 clientDisabledElements.Add(allowBotTakeoverTickbox);
1164 var ironmanTickbox =
new GUITickBox(
new RectTransform(Vector2.One, settingsContent.RectTransform), TextManager.Get(
"IronmanMode").ToUpper())
1166 ToolTip = TextManager.Get(
"IronmanMode.Tooltip"),
1167 Selected = GameMain.Client !=
null && GameMain.Client.ServerSettings.IronmanMode,
1168 OnSelected = (GUITickBox box) =>
1175 permadeathEnabledRespawnSettings.Add(ironmanTickbox);
1176 clientDisabledElements.Add(ironmanTickbox);
1178 foreach (var respawnElement
in midRoundRespawnSettings)
1180 if (!clientDisabledElements.Contains(respawnElement))
1182 clientDisabledElements.Add(respawnElement);
1186 return settingsContent;
1192 TextManager.Get(textTag), font: GUIStyle.SubHeadingFont, textAlignment: Alignment.BottomLeft, textColor: GUIStyle.TextColorBright)
1194 CanBeFocused =
false
1196 if (!toolTipTag.IsNullOrEmpty())
1198 header.
ToolTip = TextManager.Get(toolTipTag);
1206 if (!headerTag.IsNullOrEmpty())
1213 TextManager.Get(headerTag), textAlignment: Alignment.CenterLeft)
1215 CanBeFocused =
false
1223 RelativeSpacing = 0.05f
1227 new GUIFrame(
new RectTransform(
new Point(GUI.IntScale(5), 0), container.RectTransform), style:
null);
1229 slider =
new GUIScrollBar(
new RectTransform(
new Vector2(0.5f, 1.0f), container.RectTransform), barSize: 0.1f, style:
"GUISlider");
1230 if (step.HasValue) { slider.Step = step.Value; }
1231 if (range.HasValue) { slider.Range = range.Value; }
1233 container.RectTransform.MinSize =
new Point(0, slider.RectTransform.MinSize.Y);
1234 container.RectTransform.MaxSize =
new Point(
int.MaxValue, slider.RectTransform.MaxSize.Y);
1238 string.IsNullOrEmpty(valueLabelTag) ?
"" : TextManager.Get(valueLabelTag), textAlignment: Alignment.CenterLeft, font: GUIStyle.SmallFont)
1240 CanBeFocused =
false
1246 slider.ToolTip = label.ToolTip = TextManager.Get(tooltipTag);
1247 return verticalLayout ?? container;
1255 RelativeSpacing = 0.05f,
1256 ToolTip = TextManager.Get(labelTag)
1260 TextManager.Get(labelTag), textAlignment: Alignment.CenterLeft, font: font)
1262 AutoScaleHorizontal =
true
1264 if (!
string.IsNullOrEmpty(toolTipTag))
1266 label.
ToolTip = TextManager.Get(toolTipTag);
1275 container.RectTransform.MaxSize =
new Point(
int.MaxValue, input.RectTransform.MaxSize.Y);
1285 RelativeSpacing = 0.05f,
1286 ToolTip = TextManager.Get(labelTag)
1290 TextManager.Get(labelTag), textAlignment: Alignment.CenterLeft)
1292 AutoScaleHorizontal =
true
1294 if (!
string.IsNullOrEmpty(toolTipTag))
1296 label.
ToolTip = TextManager.Get(toolTipTag);
1298 var input =
new GUIDropDown(
new RectTransform(
new Vector2(0.3f, 1.0f), container.RectTransform), elementCount: numElements);
1300 container.RectTransform.MinSize =
new Point(0, input.RectTransform.MinSize.Y);
1301 container.RectTransform.MaxSize =
new Point(
int.MaxValue, input.RectTransform.MaxSize.Y);
1306 private void CreateSidePanelContents(
GUIComponent rightPanel)
1316 spectateBox =
new GUITickBox(
new RectTransform(
new Vector2(0.4f, 0.06f), myCharacterContent.RectTransform),
1317 TextManager.Get(
"spectatebutton"))
1320 OnSelected = ToggleSpectate,
1321 UserData =
"spectate"
1324 playerInfoContent =
new GUILayoutGroup(
new RectTransform(
new Vector2(1.0f, 0.9f), myCharacterContent.RectTransform))
1331 GUIFrame logFrame =
new GUIFrame(
new RectTransform(
new Vector2(1.0f, 0.45f), rightPanel.
RectTransform), style:
null);
1332 GUILayoutGroup logContents =
new GUILayoutGroup(
new RectTransform(Vector2.One, logFrame.RectTransform,
Anchor.Center))
1337 GUILayoutGroup socialHolder =
null; GUILayoutGroup serverLogHolder =
null;
1339 LogButtons =
new GUILayoutGroup(
new RectTransform(
new Vector2(1.0f, 0.05f), logContents.RectTransform),
true)
1342 RelativeSpacing = 0.02f
1345 clientHiddenElements.Add(LogButtons);
1348 chatPanelTabButtons.Add(
new GUIButton(
new RectTransform(
new Vector2(0.5f, 1.25f), LogButtons.RectTransform),
1349 TextManager.Get(
"Chat"), style:
"GUITabButton")
1352 OnClicked = (GUIButton button, object userData) =>
1354 if (socialHolder != null) { socialHolder.Visible = true; }
1355 if (serverLogHolder != null) { serverLogHolder.Visible = false; }
1356 chatPanelTabButtons.ForEach(otherBtn => otherBtn.Selected = otherBtn == button);
1362 chatPanelTabButtons.Add(
new GUIButton(
new RectTransform(
new Vector2(0.5f, 1.25f), LogButtons.RectTransform),
1363 TextManager.Get(
"ServerLog"), style:
"GUITabButton")
1365 OnClicked = (GUIButton button, object userData) =>
1367 if (socialHolder != null) { socialHolder.Visible = false; }
1368 if (serverLogHolder is { Visible: false })
1370 if (GameMain.Client?.ServerSettings?.ServerLog == null) { return false; }
1371 serverLogHolder.Visible = true;
1372 GameMain.Client.ServerSettings.ServerLog.AssignLogFrame(serverLogReverseButton, serverLogBox, serverLogFilterTicks.Content, serverLogFilter);
1374 chatPanelTabButtons.ForEach(otherBtn => otherBtn.Selected = otherBtn == button);
1379 GUITextBlock.AutoScaleAndNormalize(chatPanelTabButtons.Select(btn => btn.TextBlock));
1381 GUIFrame logHolderBottom =
new GUIFrame(
new RectTransform(Vector2.One, logContents.RectTransform), style:
null)
1383 CanBeFocused =
false
1386 socialHolder =
new GUILayoutGroup(
new RectTransform(Vector2.One, logHolderBottom.RectTransform,
Anchor.Center))
1392 new GUIFrame(
new RectTransform(
new Vector2(1.0f, 0.02f), socialHolder.RectTransform), style:
null)
1394 CanBeFocused =
false
1397 GUILayoutGroup socialHolderHorizontal =
new GUILayoutGroup(
new RectTransform(
new Vector2(1.0f, 0.9f), socialHolder.RectTransform), isHorizontal:
true)
1404 chatBox =
new GUIListBox(
new RectTransform(
new Vector2(0.6f, 1.0f), socialHolderHorizontal.RectTransform));
1408 PlayerList =
new GUIListBox(
new RectTransform(
new Vector2(0.4f, 1.0f), socialHolderHorizontal.RectTransform))
1410 PlaySoundOnSelect =
true,
1411 OnSelected = (component, userdata) => { SelectPlayer(userdata as
Client);
return true; }
1415 new GUIFrame(
new RectTransform(
new Vector2(1.0f, 0.02f), socialHolder.RectTransform), style:
null)
1417 CanBeFocused =
false
1422 var chatRow =
new GUILayoutGroup(
new RectTransform(
new Vector2(1.0f, 0.07f), socialHolder.RectTransform),
1423 isHorizontal:
true, childAnchor:
Anchor.CenterLeft)
1428 chatInput =
new GUITextBox(
new RectTransform(
new Vector2(0.95f, 1.0f), chatRow.RectTransform))
1431 Font = GUIStyle.SmallFont,
1432 DeselectAfterMessage =
false
1435 micIcon =
new GUIImage(
new RectTransform(
new Vector2(0.05f, 1.0f), chatRow.RectTransform), style:
"GUIMicrophoneUnavailable");
1437 serverLogHolder =
new GUILayoutGroup(
new RectTransform(Vector2.One, logHolderBottom.RectTransform,
Anchor.Center))
1444 new GUIFrame(
new RectTransform(
new Vector2(1.0f, 0.02f), serverLogHolder.RectTransform), style:
null)
1446 CanBeFocused =
false
1449 GUILayoutGroup serverLogHolderHorizontal =
new GUILayoutGroup(
new RectTransform(
new Vector2(1.0f, 0.9f), serverLogHolder.RectTransform), isHorizontal:
true)
1456 GUILayoutGroup serverLogListboxLayout =
new GUILayoutGroup(
new RectTransform(
new Vector2(0.5f, 1.0f), serverLogHolderHorizontal.RectTransform))
1461 serverLogReverseButton =
new GUIButton(
new RectTransform(
new Vector2(1.0f, 0.05f), serverLogListboxLayout.RectTransform), style:
"UIToggleButtonVertical");
1462 serverLogBox =
new GUIListBox(
new RectTransform(
new Vector2(1.0f, 0.95f), serverLogListboxLayout.RectTransform));
1466 serverLogFilterTicks =
new GUIListBox(
new RectTransform(
new Vector2(0.5f, 1.0f), serverLogHolderHorizontal.RectTransform) { MinSize = new Point(150, 0) })
1468 OnSelected = (component, userdata) => {
return false; }
1472 new GUIFrame(
new RectTransform(
new Vector2(1.0f, 0.02f), serverLogHolder.RectTransform), style:
null)
1474 CanBeFocused =
false
1479 serverLogFilter =
new GUITextBox(
new RectTransform(
new Vector2(1.0f, 0.07f), serverLogHolder.RectTransform))
1482 Font = GUIStyle.SmallFont
1487 private void CreateBottomPanelContents(GUIComponent bottomBar)
1491 GUILayoutGroup bottomBarLeft =
new GUILayoutGroup(
new RectTransform(
new Vector2(0.3f, 1.0f), bottomBar.RectTransform), childAnchor:
Anchor.CenterLeft)
1494 IsHorizontal =
true,
1495 RelativeSpacing = PanelSpacing
1497 GUILayoutGroup bottomBarMid =
new GUILayoutGroup(
new RectTransform(
new Vector2(0.4f, 1.0f), bottomBar.RectTransform), childAnchor:
Anchor.CenterLeft)
1500 IsHorizontal =
true,
1501 RelativeSpacing = PanelSpacing
1503 GUILayoutGroup bottomBarRight =
new GUILayoutGroup(
new RectTransform(
new Vector2(0.3f, 1.0f), bottomBar.RectTransform), childAnchor:
Anchor.CenterLeft)
1506 IsHorizontal =
true,
1507 RelativeSpacing = PanelSpacing
1510 var disconnectButton =
new GUIButton(
new RectTransform(
new Vector2(0.5f, 1.0f), bottomBarLeft.RectTransform), TextManager.Get(
"disconnect"))
1512 OnClicked = (bt, userdata) => { GameMain.QuitToMainMenu(save:
false, showVerificationPrompt:
true);
return true; }
1514 disconnectButton.TextBlock.AutoScaleHorizontal =
true;
1518 FileTransferFrame =
new GUIFrame(
new RectTransform(Vector2.One, bottomBarLeft.RectTransform), style:
"TextFrame");
1519 var fileTransferContent =
new GUILayoutGroup(
new RectTransform(
new Vector2(0.95f, 0.9f), FileTransferFrame.RectTransform,
Anchor.Center))
1522 RelativeSpacing = 0.05f
1524 FileTransferTitle =
new GUITextBlock(
new RectTransform(
new Vector2(1.0f, 0.5f), fileTransferContent.RectTransform),
"", font: GUIStyle.SmallFont);
1525 var fileTransferBottom =
new GUILayoutGroup(
new RectTransform(
new Vector2(1.0f, 0.5f), fileTransferContent.RectTransform), isHorizontal:
true, childAnchor:
Anchor.CenterLeft)
1529 FileTransferProgressBar =
new GUIProgressBar(
new RectTransform(
new Vector2(0.6f, 1.0f), fileTransferBottom.RectTransform), 0.0f, Color.DarkGreen);
1530 FileTransferProgressText =
new GUITextBlock(
new RectTransform(Vector2.One, FileTransferProgressBar.RectTransform),
"",
1531 font: GUIStyle.SmallFont, textAlignment: Alignment.CenterLeft);
1532 new GUIButton(
new RectTransform(
new Vector2(0.4f, 1.0f), fileTransferBottom.RectTransform), TextManager.Get(
"cancel"), style:
"GUIButtonSmall")
1534 OnClicked = (btn, userdata) =>
1537 GameMain.Client?.CancelFileTransfer(transfer);
1538 GameMain.Client?.FileReceiver.StopTransfer(transfer);
1544 roundControlsHolder =
new GUILayoutGroup(
new RectTransform(Vector2.One, bottomBarRight.RectTransform),
1545 isHorizontal:
true, childAnchor:
Anchor.CenterLeft)
1550 GUIFrame readyToStartContainer =
new GUIFrame(
new RectTransform(Vector2.One, roundControlsHolder.
RectTransform), style:
"TextFrame")
1556 ReadyToStartBox =
new GUITickBox(
new RectTransform(
new Vector2(0.95f, 0.75f), readyToStartContainer.RectTransform, anchor:
Anchor.Center),
1557 TextManager.Get(
"ReadyToStartTickBox"));
1559 joinOnGoingRoundButton =
new GUIButton(
new RectTransform(Vector2.One, roundControlsHolder.
RectTransform),
1560 TextManager.Get(
"ServerListJoin"));
1563 StartButton =
new GUIButton(
new RectTransform(Vector2.One, roundControlsHolder.
RectTransform),
1564 TextManager.Get(
"StartGameButton"))
1566 OnClicked = (btn, obj) =>
1568 if (GameMain.Client ==
null) {
return true; }
1569 if (CampaignSetupFrame.Visible && CampaignSetupUI !=
null)
1576 GameMain.Client.RequestStartRound(continueCampaign: GameMain.GameSession?.GameMode is CampaignMode && CampaignSetupFrame is not { Visible:
true });
1577 CoroutineManager.StartCoroutine(WaitForStartRound(StartButton),
"WaitForStartRound");
1582 clientHiddenElements.Add(StartButton);
1583 bottomBar.RectTransform.MinSize =
1584 new Point(0, (
int)Math.Max(ReadyToStartBox.RectTransform.MinSize.Y / 0.75f, StartButton.RectTransform.MinSize.Y));
1588 autoRestartText =
new GUITextBlock(
new RectTransform(Vector2.One, bottomBarMid.RectTransform),
"", font: GUIStyle.SmallFont, style:
"TextFrame", textAlignment: Alignment.Center);
1589 GUIFrame autoRestartBoxContainer =
new GUIFrame(
new RectTransform(Vector2.One, bottomBarMid.RectTransform), style:
"TextFrame");
1590 autoRestartBox =
new GUITickBox(
new RectTransform(
new Vector2(0.95f, 0.75f), autoRestartBoxContainer.RectTransform,
Anchor.Center), TextManager.Get(
"AutoRestart"))
1592 OnSelected = (tickBox) =>
1598 clientDisabledElements.Add(autoRestartBox);
1605 CoroutineManager.StopCoroutines(
"WaitForStartRound");
1606 if (StartButton !=
null)
1608 StartButton.Enabled =
true;
1610 GUI.ClearCursorWait();
1615 GUI.SetCursorWaiting();
1616 LocalizedString headerText = TextManager.Get(
"RoundStartingPleaseWait");
1619 if (startButton !=
null)
1624 DateTime timeOut = DateTime.Now +
new TimeSpan(0, 0, 10);
1627 msgBox.Header.Text = headerText +
new string(
'.', ((
int)Timing.TotalTime % 3 + 1));
1632 if (startButton !=
null)
1636 GUI.ClearCursorWait();
1643 chatInput.Deselect();
1644 CampaignCharacterDiscarded =
false;
1646 CharacterAppearanceCustomizationMenu?.Dispose();
1647 JobSelectionFrame =
null;
1654 visibilityMenuOrder.Clear();
1656 CharacterAppearanceCustomizationMenu?.Dispose();
1657 JobSelectionFrame =
null;
1661 GUI.PreventPauseMenuToggle =
false;
1662 CampaignCharacterDiscarded =
false;
1665 changesPendingText =
null;
1670 chatInput.OnDeselected += (sender, key) =>
1676 clientDisabledElements.ForEach(c => c.Enabled =
false);
1677 clientHiddenElements.ForEach(c => c.Visible =
false);
1679 RefreshEnabledElements();
1685 ReadyToStartBox.Selected =
false;
1690 joinOnGoingRoundButton.
Visible =
false;
1701 roundControlsHolder.
Children.ForEach(c => c.IgnoreLayoutGroups = !c.Visible);
1704 AssignComponentsToServerSettings();
1706 RefreshPlaystyleIcons();
1715 var settings = client.ServerSettings;
1717 bool campaignSelected = CampaignFrame.Visible || CampaignSetupFrame.Visible;
1718 bool campaignStarted = CampaignFrame.Visible;
1719 bool gameStarted = client !=
null && client.GameStarted;
1722 foreach (var element
in clientDisabledElements)
1724 element.Enabled = manageSettings;
1728 traitorElements.ForEach(e => e.Enabled &= settings.TraitorProbability > 0);
1729 SetTraitorDangerIndicators(settings.TraitorDangerLevel);
1730 respawnModeSelection.
Enabled = respawnModeLabel.
Enabled = manageSettings && !gameStarted;
1731 midRoundRespawnSettings.ForEach(e => e.Enabled &= settings.RespawnMode ==
RespawnMode.MidRound);
1732 permadeathDisabledRespawnSettings.ForEach(e => e.Enabled &= settings.RespawnMode !=
RespawnMode.Permadeath);
1733 permadeathEnabledRespawnSettings.ForEach(e => e.Enabled &= settings.RespawnMode ==
RespawnMode.Permadeath && !gameStarted);
1734 ironmanDisabledRespawnSettings.ForEach(e => e.Enabled &= !settings.IronmanMode);
1737 respawnIntervalElement.
GetAllChildren().ForEach(e => e.Enabled = settings.RespawnMode !=
RespawnMode.BetweenRounds && manageSettings);
1740 shuttleTickBox.
Enabled &= !gameStarted;
1741 if (ShuttleList !=
null)
1745 ShuttleList.ButtonEnabled = ShuttleList.Enabled;
1747 if (SubList !=
null)
1749 SubList.Enabled = !campaignStarted && (settings.AllowSubVoting || HasPermission(
ClientPermissions.SelectSub));
1751 if (ModeList !=
null)
1753 ModeList.Enabled = !gameStarted && (settings.AllowModeVoting || HasPermission(
ClientPermissions.SelectMode));
1756 RefreshStartButtonVisibility();
1758 botSettingsElements.ForEach(b => b.Enabled = !campaignStarted && manageSettings);
1760 campaignDisabledElements.ForEach(e => e.Enabled = !campaignSelected && manageSettings);
1761 levelDifficultySlider.ToolTip = levelDifficultySlider.Enabled ?
string.Empty : TextManager.Get(
"campaigndifficultydisabled");
1764 foreach (var element
in clientHiddenElements)
1766 element.Visible = manageSettings;
1769 ReadyToStartBox.Parent.Visible = !gameStarted;
1772 client?.UpdateLogButtonPermissions();
1773 roundControlsHolder.
Children.ForEach(c => c.IgnoreLayoutGroups = !c.Visible);
1774 roundControlsHolder.
Children.ForEach(c => c.RectTransform.RelativeSize = Vector2.One);
1777 SettingsButton.OnClicked = settings.ToggleSettingsFrame;
1779 RefreshGameModeContent();
1791 joinOnGoingRoundButton.
Visible =
true;
1792 joinOnGoingRoundButton.
Enabled =
true;
1793 StartButton.Visible =
false;
1798 if (newCampaignCharacterInfo !=
null)
1800 if (CampaignCharacterDiscarded) {
return; }
1801 if (campaignCharacterInfo != newCampaignCharacterInfo)
1803 campaignCharacterInfo = newCampaignCharacterInfo;
1804 UpdatePlayerFrame(campaignCharacterInfo,
false);
1807 else if (campaignCharacterInfo !=
null)
1809 campaignCharacterInfo =
null;
1810 UpdatePlayerFrame(
null,
false);
1814 private void UpdatePlayerFrame(
CharacterInfo characterInfo,
bool allowEditing =
true)
1816 UpdatePlayerFrame(characterInfo, allowEditing, playerInfoContent);
1824 allowEditing: alwaysAllowEditing || campaignCharacterInfo ==
null,
1826 createPendingText: createPendingText);
1829 private void UpdatePlayerFrame(
CharacterInfo characterInfo,
bool allowEditing,
GUIComponent parent,
bool createPendingText =
true)
1834 spectateBox.
Enabled = !PermanentlyDead;
1836 createPendingChangesText = createPendingText;
1837 if (characterInfo ==
null || CampaignCharacterDiscarded)
1839 characterInfo =
new CharacterInfo(CharacterPrefab.HumanSpeciesName, GameMain.Client.Name,
null);
1840 characterInfo.
RecreateHead(MultiplayerPreferences.Instance);
1841 GameMain.Client.CharacterInfo = characterInfo;
1847 bool isGameRunning = GameMain.GameSession?.IsRunning ??
false;
1852 bool nameChangePending = isGameRunning && GameMain.Client.PendingName !=
string.Empty && GameMain.Client?.
Character?.
Name != GameMain.Client.PendingName;
1854 changesPendingText =
null;
1856 if (TabMenu.PendingChanges)
1858 CreateChangesPendingText();
1861 CharacterNameBox =
new GUITextBox(
new RectTransform(
new Vector2(1.0f, 0.065f), parent.
RectTransform), !nameChangePending ? characterInfo.
Name : GameMain.Client.PendingName, textAlignment: Alignment.Center)
1867 if (!allowEditing ||
1870 CharacterNameBox.Readonly =
true;
1871 CharacterNameBox.Enabled =
false;
1875 CharacterNameBox.OnEnterPressed += (tb, text) =>
1877 CharacterNameBox.Deselect();
1880 CharacterNameBox.OnDeselected += (tb, key) =>
1882 if (GameMain.Client ==
null)
1888 if (newName == GameMain.Client.Name) {
return; }
1889 if (
string.IsNullOrWhiteSpace(newName))
1891 tb.Text = GameMain.Client.Name;
1897 GameMain.Client.PendingName = tb.Text;
1898 TabMenu.PendingChanges =
true;
1899 if (createPendingText)
1901 CreateChangesPendingText();
1906 ReadyToStartBox.Selected =
false;
1909 GameMain.Client.SetName(tb.Text);
1915 new GUIFrame(
new RectTransform(
new Vector2(1.0f, 0.006f), parent.
RectTransform), style:
null);
1917 if (allowEditing && (!PermadeathMode || !isGameRunning))
1919 GUILayoutGroup characterInfoTabs =
new GUILayoutGroup(
new RectTransform(
new Vector2(1.0f, 0.07f), parent.
RectTransform), isHorizontal:
true)
1922 RelativeSpacing = 0.02f
1925 jobPreferencesButton =
new GUIButton(
new RectTransform(
new Vector2(0.5f, 1f), characterInfoTabs.RectTransform),
1926 TextManager.Get(
"JobPreferences"), style:
"GUITabButton")
1929 OnClicked = SelectJobPreferencesTab
1931 appearanceButton =
new GUIButton(
new RectTransform(
new Vector2(0.5f, 1f), characterInfoTabs.RectTransform),
1932 TextManager.Get(
"CharacterAppearance"), style:
"GUITabButton")
1934 OnClicked = SelectAppearanceTab
1937 GUITextBlock.AutoScaleAndNormalize(jobPreferencesButton.
TextBlock, appearanceButton.
TextBlock);
1941 characterInfoFrame =
new GUIFrame(
new RectTransform(Vector2.One, parent.
RectTransform), style:
null);
1944 JobPreferenceContainer =
new GUIFrame(
new RectTransform(Vector2.One, characterInfoFrame.
RectTransform),
1945 style:
"GUIFrameListBox");
1946 characterInfo.
CreateIcon(
new RectTransform(
new Vector2(1.0f, 0.4f), JobPreferenceContainer.RectTransform,
Anchor.TopCenter) { RelativeOffset = new Vector2(0f, 0.025f) });
1947 JobList =
new GUIListBox(
new RectTransform(
new Vector2(1.0f, 0.6f), JobPreferenceContainer.RectTransform,
Anchor.BottomCenter),
true)
1950 PlaySoundOnSelect =
true,
1951 OnSelected = (child, obj) =>
1953 if (child.IsParentOf(GUI.MouseOn)) {
return false; }
1954 return OpenJobSelection(child, obj);
1958 for (
int i = 0; i < 3; i++)
1960 JobVariant jobPrefab =
null;
1961 while (i < MultiplayerPreferences.Instance.JobPreferences.Count)
1963 var jobPreference = MultiplayerPreferences.Instance.JobPreferences[i];
1964 if (!JobPrefab.Prefabs.TryGet(jobPreference.JobIdentifier, out JobPrefab prefab) || prefab.HiddenJob)
1966 MultiplayerPreferences.Instance.JobPreferences.RemoveAt(i);
1971 int variant = Math.Min(jobPreference.Variant, prefab.Variants - 1);
1972 jobPrefab =
new JobVariant(prefab, variant);
1976 var slot =
new GUIFrame(
new RectTransform(
new Vector2(0.333f, 1.0f), JobList.Content.RectTransform), style:
"ListBoxElementSquare")
1978 CanBeFocused =
true,
1979 UserData = jobPrefab
1983 UpdateJobPreferences(characterInfo);
1985 appearanceFrame =
new GUIFrame(
new RectTransform(Vector2.One, characterInfoFrame.
RectTransform), style:
"GUIFrameListBox")
1995 if (PermanentlyDead)
1998 new RectTransform(
new Vector2(1.0f, 0.0f), parent.
RectTransform),
1999 TextManager.Get(
"deceased"),
2000 textAlignment: Alignment.Center, font: GUIStyle.LargeFont);
2002 if (GameMain.Client?.ServerSettings is { IronmanMode: true })
2005 new RectTransform(
new Vector2(1.0f, 0.0f), parent.
RectTransform),
2006 TextManager.Get(
"lobby.ironmaninfo"),
2007 textAlignment: Alignment.Center, wrap:
true);
2012 new RectTransform(
new Vector2(1.0f, 0.0f), parent.
RectTransform),
2013 TextManager.Get(
"lobby.permadeathinfo"),
2014 textAlignment: Alignment.Center, wrap:
true);
2016 new RectTransform(
new Vector2(1.0f, 0.0f), parent.
RectTransform),
2017 TextManager.Get(
"lobby.permadeathoptionsexplanation"),
2018 textAlignment: Alignment.Center, wrap:
true);
2023 new GUITextBlock(
new RectTransform(
new Vector2(1.0f, 0.0f), parent.
RectTransform), characterInfo.
Job.
Name, textAlignment: Alignment.Center, font: GUIStyle.SubHeadingFont, wrap:
true)
2025 HoverColor = Color.Transparent,
2026 SelectedColor = Color.Transparent
2029 new GUITextBlock(
new RectTransform(
new Vector2(1.0f, 0.0f), parent.
RectTransform), TextManager.Get(
"Skills"), font: GUIStyle.SubHeadingFont);
2032 Color textColor = Color.White * (0.5f + skill.Level / 200.0f);
2033 var skillText =
new GUITextBlock(
new RectTransform(
new Vector2(1.0f, 0.0f), parent.
RectTransform),
2034 " - " + TextManager.AddPunctuation(
':', TextManager.Get(
"SkillName." + skill.Identifier), ((
int)skill.Level).ToString()),
2036 font: GUIStyle.SmallFont);
2041 new GUIFrame(
new RectTransform(
new Vector2(1.0f, 0.15f), parent.
RectTransform), style:
null);
2043 if (GameMain.Client?.ServerSettings?.RespawnMode !=
RespawnMode.Permadeath)
2046 new GUIButton(
new RectTransform(
new Vector2(0.8f, 0.1f), parent.
RectTransform,
Anchor.BottomCenter), TextManager.Get(
"CreateNew"))
2048 IgnoreLayoutGroups =
true,
2049 OnClicked = (btn, userdata) =>
2051 TryDiscardCampaignCharacter(() =>
2053 UpdatePlayerFrame(
null,
true, parent);
2061 TeamPreferenceListBox =
null;
2062 if (SelectedMode == GameModePreset.PvP)
2064 TeamPreferenceListBox =
new GUIListBox(
new RectTransform(
new Vector2(1.0f, 0.04f), parent.
RectTransform, anchor:
Anchor.TopLeft, pivot:
Pivot.TopLeft), isHorizontal:
true, style:
null)
2067 KeepSpaceForScrollBar =
false,
2068 PlaySoundOnSelect =
true,
2069 ScrollBarEnabled =
false,
2070 ScrollBarVisible =
false
2072 TeamPreferenceListBox.RectTransform.MinSize =
new Point(0, GUI.IntScale(30));
2073 TeamPreferenceListBox.UpdateDimensions();
2075 Color team1Color =
new Color(0, 110, 150, 255);
2076 var team1Option =
new GUITextBlock(
new RectTransform(
new Vector2(0.3f, 1.0f), TeamPreferenceListBox.Content.RectTransform), TextManager.Get(
"teampreference.team1"), textAlignment: Alignment.Center, style:
null)
2079 CanBeFocused =
true,
2080 Padding = Vector4.One * 10.0f * GUI.Scale,
2081 Color = Color.Lerp(team1Color, Color.Black, 0.7f) * 0.7f,
2082 HoverColor = team1Color * 0.95f,
2083 SelectedColor = team1Color * 0.8f,
2084 OutlineColor = team1Color,
2085 TextColor = Color.White,
2086 HoverTextColor = Color.White,
2087 SelectedTextColor = Color.White
2090 Color noPreferenceColor =
new Color(100, 100, 100, 255);
2091 var noPreferenceOption =
new GUITextBlock(
new RectTransform(
new Vector2(0.4f, 1.0f), TeamPreferenceListBox.Content.RectTransform), TextManager.Get(
"teampreference.nopreference"), textAlignment: Alignment.Center, style:
null)
2094 CanBeFocused =
true,
2095 Padding = Vector4.One * 10.0f * GUI.Scale,
2096 Color = Color.Lerp(noPreferenceColor, Color.Black, 0.7f) * 0.7f,
2097 HoverColor = noPreferenceColor * 0.95f,
2098 SelectedColor = noPreferenceColor * 0.8f,
2099 OutlineColor = noPreferenceColor,
2100 TextColor = Color.White,
2101 HoverTextColor = Color.White,
2102 SelectedTextColor = Color.White
2105 Color team2Color =
new Color(150, 110, 0, 255);
2106 var team2Option =
new GUITextBlock(
new RectTransform(
new Vector2(0.3f, 1.0f), TeamPreferenceListBox.Content.RectTransform), TextManager.Get(
"teampreference.team2"), textAlignment: Alignment.Center, style:
null)
2109 CanBeFocused =
true,
2110 Padding = Vector4.One * 10.0f * GUI.Scale,
2111 Color = Color.Lerp(team2Color, Color.Black, 0.7f) * 0.7f,
2112 HoverColor = team2Color * 0.95f,
2113 SelectedColor = team2Color * 0.8f,
2114 OutlineColor = team2Color,
2115 TextColor = Color.White,
2116 HoverTextColor = Color.White,
2117 SelectedTextColor = Color.White
2120 TeamPreferenceListBox.Select(MultiplayerPreferences.Instance.TeamPreference);
2122 TeamPreferenceListBox.OnSelected += (component, obj) =>
2124 if ((CharacterTeamType)obj == MultiplayerPreferences.Instance.TeamPreference) {
return true; }
2127 GameMain.Client.ForceNameAndJobUpdate();
2128 GameSettings.SaveCurrentConfig();
2137 var confirmation =
new GUIMessageBox(TextManager.Get(
"NewCampaignCharacterHeader"), TextManager.Get(
"NewCampaignCharacterText"),
2138 new[] { TextManager.Get(
"Yes"), TextManager.Get(
"No") });
2139 confirmation.Buttons[0].OnClicked += confirmation.Close;
2140 confirmation.Buttons[0].OnClicked += (btn2, userdata2) =>
2142 CampaignCharacterDiscarded =
true;
2143 campaignCharacterInfo =
null;
2147 confirmation.Buttons[1].OnClicked += confirmation.Close;
2150 private void CreateChangesPendingText()
2152 if (!createPendingChangesText || changesPendingText !=
null || playerInfoContent ==
null) {
return; }
2154 changesPendingText =
new GUIFrame(
new RectTransform(
new Vector2(1.0f, 0.065f), playerInfoContent.
RectTransform, Anchor.BottomCenter, Pivot.TopCenter) { RelativeOffset = new Vector2(0f, -0.03f) },
2157 Color = Color.Black,
2158 IgnoreLayoutGroups =
true
2160 var text =
new GUITextBlock(
new RectTransform(Vector2.One, changesPendingText.
RectTransform,
Anchor.Center),
2161 TextManager.Get(
"tabmenu.characterchangespending"), textColor: GUIStyle.Orange, textAlignment: Alignment.Center, style:
null);
2162 changesPendingText.
RectTransform.
MinSize =
new Point((
int)(text.TextSize.X * 1.2f), (
int)(text.TextSize.Y * 2.0f));
2174 TextManager.Get(
"tabmenu.characterchangespending"), textColor: GUIStyle.Orange, textAlignment: Alignment.Center, style:
null)
2176 AutoScaleHorizontal =
true
2182 jobVariantTooltip =
new GUIFrame(
new RectTransform(
new Point((
int)(400 * GUI.Scale), (
int)(180 * GUI.Scale)), GUI.Canvas, pivot:
Pivot.BottomRight),
2183 style:
"GUIToolTip")
2185 UserData =
new JobVariant(jobPrefab, variant)
2189 var content =
new GUILayoutGroup(
new RectTransform(
new Vector2(0.95f, 0.95f), jobVariantTooltip.RectTransform, Anchor.Center))
2192 AbsoluteSpacing = (int)(15 * GUI.Scale)
2195 new GUITextBlock(
new RectTransform(
new Vector2(1.0f, 0.0f), content.RectTransform), TextManager.GetWithVariable(
"startingequipmentname",
"[number]", (variant + 1).ToString()), font: GUIStyle.SubHeadingFont, textAlignment: Alignment.Center);
2198 .Where(it => it.ShowPreview)
2199 .Select(it => it.ItemIdentifier)
2202 int itemsPerRow = 5;
2203 int rows = (int)Math.Max(Math.Ceiling(itemIdentifiers.Count() / (
float)itemsPerRow), 1);
2205 new GUICustomComponent(
new RectTransform(
new Vector2(1.0f, 0.4f * rows), content.RectTransform,
Anchor.BottomCenter),
2206 onDraw: (sb, component) => { DrawJobVariantItems(sb, component, new JobVariant(jobPrefab, variant), itemsPerRow); });
2208 jobVariantTooltip.RectTransform.MinSize =
new Point(0, content.RectTransform.Children.Sum(c => c.Rect.Height + content.AbsoluteSpacing));
2211 private void SetTraitorDangerIndicators(
int dangerLevel)
2214 foreach (var child
in traitorDangerGroup.
Children)
2216 child.Enabled = i < dangerLevel && GameMain.Client?.ServerSettings is { TraitorProbability: > 0 };
2246 TextManager.Get(
"PlayingAsSpectator"),
2247 textAlignment: Alignment.Center);
2251 UpdatePlayerFrame(campaignCharacterInfo, allowEditing: campaignCharacterInfo ==
null);
2262 if (campaignCharacterInfo !=
null && campaignCharacterInfo.
PermanentlyDead) {
return; }
2265 if (spectateBox.
Selected && !allowSpectating) { spectateBox.
Selected =
false; }
2268 spectateBox.
Visible = allowSpectating;
2274 autoRestartTimer = timer;
2284 if (subList ==
null) {
return; }
2290 AddSubmarine(subList, sub);
2298 subList = listBox.Content;
2300 else if (subList is GUIDropDown dropDown)
2302 subList = dropDown.ListBox.Content;
2305 var frame =
new GUIFrame(
new RectTransform(
new Vector2(1.0f, 0.1f), subList.
RectTransform)
2308 MinSize = new Point(0, (int)(GUIStyle.SmallFont.LineHeight * 2.3f))
2310 style:
"ListBoxElement")
2316 int buttonSize = (int)(frame.Rect.Height * 0.8f);
2317 var subTextBlock =
new GUITextBlock(
new RectTransform(
new Vector2(0.8f, 1.0f), frame.RectTransform,
Anchor.CenterLeft),
2318 ToolBox.LimitString(sub.
DisplayName.
Value, GUIStyle.Font, subList.
Rect.Width - 65), textAlignment: Alignment.CenterLeft)
2320 CanBeFocused =
false
2325 SubmarineInfo.SavedSubmarines.FirstOrDefault(s => s.Name == sub.
Name);
2327 if (matchingSub ==
null)
2329 subTextBlock.TextColor =
new Color(subTextBlock.TextColor, 0.5f);
2330 frame.ToolTip = TextManager.Get(
"SubNotFound");
2334 subTextBlock.TextColor =
new Color(subTextBlock.TextColor, 0.5f);
2335 frame.ToolTip = TextManager.Get(
"SubDoesntMatch");
2339 if (subList == ShuttleList || subList == ShuttleList.ListBox || subList == ShuttleList.ListBox.Content)
2341 subTextBlock.TextColor =
new Color(subTextBlock.TextColor, sub.
HasTag(
SubmarineTag.Shuttle) ? 1.0f : 0.6f);
2347 subTextBlock.TextColor = Color.Lerp(subTextBlock.TextColor, Color.DarkRed, 0.5f);
2348 frame.ToolTip = TextManager.Get(
"ContentPackageMismatch") +
"\n\n" + frame.ToolTip.SanitizedString;
2351 CreateSubmarineClassText(
2358 private void CreateSubmarineClassText(
2359 GUIComponent parent,
2361 GUITextBlock subTextBlock,
2362 GUIComponent subList)
2366 new GUITextBlock(
new RectTransform(
new Vector2(0.5f, 1.0f), parent.RectTransform,
Anchor.CenterRight) { AbsoluteOffset = new Point(GUI.IntScale(20), 0) },
2367 TextManager.Get(
"Shuttle",
"RespawnShuttle"), textAlignment: Alignment.CenterRight, font: GUIStyle.SmallFont)
2369 TextColor = subTextBlock.TextColor * 0.8f,
2370 ToolTip = subTextBlock.ToolTip?.SanitizedString,
2371 CanBeFocused =
false
2374 if (subList == SubList.Content)
2376 subTextBlock.TextColor *= 0.8f;
2377 foreach (GUIComponent child
in parent.Children)
2379 child.Color *= 0.8f;
2385 var infoContainer =
new GUILayoutGroup(
new RectTransform(
new Vector2(0.5f, 1.0f), parent.RectTransform,
Anchor.CenterRight) { AbsoluteOffset = new Point(GUI.IntScale(20), 0) }, isHorizontal:
false);
2386 new GUITextBlock(
new RectTransform(
new Vector2(1.0f, 0.5f), infoContainer.RectTransform),
2387 TextManager.GetWithVariable(
"currencyformat",
"[credits]",
string.Format(CultureInfo.InvariantCulture,
"{0:N0}", sub.Price)), textAlignment: Alignment.BottomRight, font: GUIStyle.SmallFont)
2389 UserData =
"pricetext",
2390 TextColor = subTextBlock.TextColor * 0.8f,
2391 CanBeFocused =
false
2393 new GUITextBlock(
new RectTransform(
new Vector2(1.0f, 0.5f), infoContainer.RectTransform),
2394 TextManager.Get($
"submarineclass.{sub.SubmarineClass}"), textAlignment: Alignment.TopRight, font: GUIStyle.SmallFont)
2396 UserData =
"classtext",
2397 TextColor = subTextBlock.TextColor * 0.8f,
2398 ToolTip = subTextBlock.ToolTip,
2399 CanBeFocused =
false
2416 if (selectedSub.Price > CampaignSettings.CurrentSettings.InitialMoney)
2418 new GUIMessageBox(TextManager.Get(
"warning"), TextManager.Get(
"campaignsubtooexpensive"));
2420 if (!selectedSub.IsCampaignCompatible)
2422 new GUIMessageBox(TextManager.Get(
"warning"), TextManager.Get(
"campaignsubincompatible"));
2425 if (!selectedSub.RequiredContentPackagesInstalled)
2427 var msgBox =
new GUIMessageBox(TextManager.Get(
"ContentPackageMismatch"),
2428 selectedSub.RequiredContentPackages.Any() ?
2429 TextManager.GetWithVariable(
"ContentPackageMismatchWarning",
"[requiredcontentpackages]",
string.Join(
", ", selectedSub.RequiredContentPackages)) :
2430 TextManager.Get(
"ContentPackageMismatchWarningGeneric"),
2431 new LocalizedString[] { TextManager.Get(
"Yes"), TextManager.Get(
"No") });
2433 msgBox.Buttons[0].OnClicked = msgBox.Close;
2434 msgBox.Buttons[0].OnClicked += (button, obj) =>
2439 msgBox.Buttons[1].OnClicked = msgBox.Close;
2451 CreateSubPreview(sub);
2453 voteType = VoteType.Sub;
2464 if (HighlightedModeIndex == SelectedModeIndex &&
2468 var verificationBox =
new GUIMessageBox(
"", TextManager.Get(
"endcampaignverification"),
new LocalizedString[] { TextManager.Get(
"yes"), TextManager.Get(
"no") });
2469 verificationBox.Buttons[0].OnClicked += (btn, userdata) =>
2472 HighlightMode(SelectedModeIndex);
2473 verificationBox.Close(btn, userdata);
2476 verificationBox.Buttons[1].OnClicked = verificationBox.Close;
2480 HighlightMode(SelectedModeIndex);
2482 if (presetName ==
"multiplayercampaign")
2484 GUI.SetCursorWaiting(endCondition: () =>
2486 return CampaignFrame.Visible || CampaignSetupFrame.Visible;
2490 return presetName !=
"multiplayercampaign";
2499 voteType = VoteType.Mode;
2514 client.
Name, textAlignment: Alignment.CenterLeft, font: GUIStyle.SmallFont, style:
null)
2516 Padding = Vector4.One * 10.0f * GUI.Scale,
2517 Color = Color.White * 0.25f,
2518 HoverColor = Color.White * 0.5f,
2519 SelectedColor = Color.White * 0.85f,
2520 OutlineColor = Color.White * 0.5f,
2521 TextColor = Color.White,
2522 SelectedTextColor = Color.Black,
2526 sprite: GUIStyle.GetComponentStyle(
"GUISoundIcon").GetDefaultSprite(), scaleToFit:
true)
2529 CanBeFocused =
false,
2532 HoverColor = Color.White
2536 "GUISoundIconDisabled")
2538 UserData =
"soundicondisabled",
2539 CanBeFocused =
true,
2542 HoverColor = Color.White
2548 CanBeFocused =
false,
2549 ToolTip = TextManager.Get(
"ReadyToStartTickBox"),
2550 UserData =
"clientready"
2556 onDraw: DrawDownloadThrobber(client, soundIcon, soundIconDisabled, readyTick));
2559 private Action<SpriteBatch, GUICustomComponent> DrawDownloadThrobber(
Client client, params
GUIComponent[] otherComponents)
2560 => (sb, c) => DrawDownloadThrobber(client, otherComponents, sb, c);
2571 int drawRectX = otherComponents.Where(c => c.Visible)
2572 .Select(c => c.Rect)
2574 .Min(r => r.X) - component.
Parent.
Rect.Height - 10;
2579 var sheet = GUIStyle.GenericThrobber;
2582 pos: drawRect.Location.ToVector2(),
2583 spriteIndex: (
int)Math.Floor(Timing.TotalTime * 24.0f) % sheet.FrameCount,
2585 origin: Vector2.Zero, rotate: 0.0f,
2586 scale: Vector2.One * component.
Parent.
Rect.Height / sheet.FrameSize.ToVector2());
2587 if (component.
ToolTip.IsNullOrEmpty())
2589 component.
ToolTip = TextManager.Get(
"PlayerIsDownloadingFiles");
2596 if (playerFrame ==
null) {
return; }
2597 playerFrame.Text = client.
Name;
2599 playerFrame.ToolTip =
"";
2600 Color color = Color.White;
2606 color =
new Color(0, 110, 150, 255);
2607 playerFrame.ToolTip = TextManager.GetWithVariable(
"teampreference",
"[team]", TextManager.Get(
"teampreference.team1"));
2610 color =
new Color(150, 110, 0, 255);
2611 playerFrame.ToolTip = TextManager.GetWithVariable(
"teampreference",
"[team]", TextManager.Get(
"teampreference.team2"));
2614 playerFrame.ToolTip = TextManager.GetWithVariable(
"teampreference",
"[team]", TextManager.Get(
"none"));
2627 playerFrame.ToolTip = TextManager.GetWithVariable(
"jobpreference",
"[job]", TextManager.Get(
"none"));
2630 playerFrame.Color = color * 0.4f;
2631 playerFrame.HoverColor = color * 0.6f;
2632 playerFrame.SelectedColor = color * 0.8f;
2633 playerFrame.OutlineColor = color * 0.5f;
2634 playerFrame.TextColor = color;
2640 if (PlayerFrame ==
null) {
return; }
2642 var soundIconDisabled = PlayerFrame.
FindChild(
"soundicondisabled");
2646 if (!soundIcon.Visible)
2650 soundIcon.Visible = !muted && !mutedLocally;
2651 soundIconDisabled.Visible = muted || mutedLocally;
2652 soundIconDisabled.ToolTip = TextManager.Get(mutedLocally ?
"MutedLocally" :
"MutedGlobally");
2658 if (PlayerFrame ==
null) {
return; }
2662 soundIcon.Visible =
true;
2668 if (child !=
null) { PlayerList.
RemoveChild(child); }
2672 => area.Data.ExtractClient();
2676 var client = ExtractClientFromClickableArea(area);
2677 if (client is
null) {
return; }
2683 var client = ExtractClientFromClickableArea(area);
2684 if (client is
null) {
return; }
2685 CreateModerationContextMenu(client);
2688 #region Context Menu
2691 if (GUIContextMenu.CurrentContextMenu !=
null) {
return; }
2693 if (!(
GameMain.
Client is { PreviouslyConnectedClients: var previouslyConnectedClients })
2694 || !previouslyConnectedClients.Contains(client)) {
return; }
2696 bool hasAccountId = client.
AccountId.IsSome();
2704 canKick = canBan = canManagePermissions =
false;
2707 List<ContextMenuOption> options =
new List<ContextMenuOption>();
2709 if (client.
AccountId.TryUnwrap(out var accountId))
2711 options.Add(
new ContextMenuOption(accountId.ViewProfileLabel(), isEnabled: hasAccountId, onSelected: () =>
2713 accountId.OpenProfile();
2717 options.Add(
new ContextMenuOption(
"ModerationMenu.ManagePlayer", isEnabled:
true, onSelected: () =>
2723 List<ContextMenuOption> rankOptions =
new List<ContextMenuOption>();
2728 LocalizedString label = TextManager.GetWithVariables(rank.Permissions == ClientPermissions.None ?
"clearrankprompt" :
"giverankprompt", (
"[user]", client.Name), (
"[rank]", rank.DisplayName));
2729 GUIMessageBox msgBox = new GUIMessageBox(string.Empty, label, new[] { TextManager.Get(
"Yes"), TextManager.Get(
"Cancel") });
2731 msgBox.Buttons[0].OnClicked = delegate
2733 client.SetPermissions(rank.Permissions, rank.PermittedCommands);
2734 GameMain.Client.UpdateClientPermissions(client);
2738 msgBox.Buttons[1].OnClicked = delegate
2746 options.Add(
new ContextMenuOption(
"Rank", isEnabled: canManagePermissions, options: rankOptions.ToArray()));
2754 client.MutedLocally = !client.MutedLocally;
2763 kickOption =
new ContextMenuOption(
"Kick", isEnabled: kickEnabled, onSelected: delegate
2770 kickOption =
new ContextMenuOption(
"VoteToKick", isEnabled: kickEnabled, onSelected: delegate
2772 GameMain.Client?.VoteForKick(client);
2776 options.Add(kickOption);
2779 if (GameMain.Client?.ServerSettings?.BanList?.BannedPlayers?.Any(bp => bp.MatchesClient(client)) ??
false)
2781 options.Add(
new ContextMenuOption(
"clientpermission.unban", isEnabled: canBan, onSelected: delegate
2783 GameMain.Client?.UnbanPlayer(client.
Name);
2788 options.Add(
new ContextMenuOption(
"Ban", isEnabled: canBan, onSelected: delegate
2790 GameMain.Client?.CreateKickReasonPrompt(client.
Name,
true);
2794 GUIContextMenu.CreateContextMenu(
null, client.
Name, headerColor: clientColor, options.ToArray());
2806 OnClicked = (btn, userdata) =>
2808 if (GUI.MouseOn == btn || GUI.MouseOn == btn.TextBlock)
2810 ClosePlayerFrame(btn, userdata);
2816 new GUIFrame(
new RectTransform(GUI.Canvas.RelativeSize, PlayerFrame.RectTransform,
Anchor.Center), style:
"GUIBackgroundBlocker");
2817 Vector2 frameSize = hasManagePermissions ?
new Vector2(.28f, .5f) :
new Vector2(.28f, .15f);
2819 var playerFrameInner =
new GUIFrame(
new RectTransform(frameSize, PlayerFrame.RectTransform,
Anchor.Center) { MinSize = new Point(550, 0) });
2823 RelativeSpacing = 0.03f
2826 var headerContainer =
new GUILayoutGroup(
new RectTransform(
new Vector2(1.0f, 0.25f), paddedPlayerFrame.RectTransform), isHorizontal:
false);
2828 var headerTextContainer =
new GUILayoutGroup(
new RectTransform(
new Vector2(1f, 0.5f), headerContainer.RectTransform), isHorizontal:
true, childAnchor:
Anchor.CenterLeft)
2833 var headerVolumeContainer =
new GUILayoutGroup(
new RectTransform(
new Vector2(1f, 0.5f), headerContainer.RectTransform), isHorizontal:
true, childAnchor:
Anchor.CenterLeft)
2839 text: selectedClient.
Name, font: GUIStyle.LargeFont);
2840 nameText.Text = ToolBox.LimitString(nameText.Text, nameText.Font, (
int)(nameText.Rect.Width * 0.95f));
2842 if (hasManagePermissions && !selectedClient.
IsOwner)
2844 PlayerFrame.UserData = selectedClient;
2847 TextManager.Get(
"Rank"), font: GUIStyle.SubHeadingFont);
2849 TextManager.Get(
"Rank"))
2851 UserData = selectedClient,
2858 rankDropDown.AddItem(TextManager.Get(
"CustomRank"),
null);
2863 rankDropDown.SelectItem(currentPreset);
2865 rankDropDown.OnSelected += (c, userdata) =>
2868 if (selectedPreset !=
null)
2870 var client = PlayerFrame.UserData as
Client;
2875 SelectPlayer(client);
2880 var permissionLabels =
new GUILayoutGroup(
new RectTransform(
new Vector2(1.0f, 0.1f), paddedPlayerFrame.RectTransform), isHorizontal:
true)
2883 RelativeSpacing = 0.05f
2885 var permissionLabel =
new GUITextBlock(
new RectTransform(
new Vector2(0.5f, 1.0f), permissionLabels.RectTransform), TextManager.Get(
"Permissions"), font: GUIStyle.SubHeadingFont);
2887 TextManager.Get(
"PermittedConsoleCommands"), wrap:
true, font: GUIStyle.SubHeadingFont);
2890 var permissionContainer =
new GUILayoutGroup(
new RectTransform(
new Vector2(1.0f, 0.4f), paddedPlayerFrame.RectTransform), isHorizontal:
true)
2893 RelativeSpacing = 0.05f
2899 RelativeSpacing = 0.05f
2902 new GUITickBox(
new RectTransform(
new Vector2(0.15f, 0.15f), listBoxContainerLeft.RectTransform), TextManager.Get(
"all",
"clientpermission.all"))
2904 Enabled = !myClient,
2905 OnSelected = (tickbox) =>
2908 rankDropDown.SelectItem(
null);
2910 if (PlayerFrame.UserData is not
Client client) {
return false; }
2915 permissionTickBox.
Enabled =
false;
2916 permissionTickBox.Selected = tickbox.Selected;
2917 permissionTickBox.Enabled =
true;
2925 UserData = selectedClient
2932 var permissionTick =
new GUITickBox(
new RectTransform(
new Vector2(0.15f, 0.15f), permissionsBox.Content.RectTransform),
2933 TextManager.Get(
"ClientPermission." + permission), font: GUIStyle.SmallFont)
2935 UserData = permission,
2937 Enabled = !myClient,
2938 OnSelected = (tickBox) =>
2941 rankDropDown.SelectItem(
null);
2943 if (PlayerFrame.UserData is not
Client client) {
return false; }
2946 if (tickBox.Selected)
2948 client.GivePermission(thisPermission);
2952 client.RemovePermission(thisPermission);
2954 if (tickBox.Enabled)
2961 permissionTick.ToolTip = permissionTick.TextBlock.ToolTip = TextManager.Get(
"ClientPermission." + permission +
".description");
2967 RelativeSpacing = 0.05f
2970 new GUITickBox(
new RectTransform(
new Vector2(0.15f, 0.15f), listBoxContainerRight.RectTransform), TextManager.Get(
"all",
"clientpermission.all"))
2972 Enabled = !myClient,
2973 OnSelected = (tickbox) =>
2976 rankDropDown.SelectItem(
null);
2978 if (PlayerFrame.UserData is not
Client client) {
return false; }
2983 commandTickBox.
Enabled =
false;
2984 commandTickBox.Selected = tickbox.Selected;
2985 commandTickBox.Enabled =
true;
2993 UserData = selectedClient
2995 foreach (DebugConsole.Command command in DebugConsole.Commands)
2997 var commandTickBox =
new GUITickBox(
new RectTransform(
new Vector2(0.15f, 0.15f), commandList.Content.RectTransform),
2998 command.Names[0].Value, font: GUIStyle.SmallFont)
3001 Enabled = !myClient,
3002 ToolTip = command.Help,
3005 commandTickBox.OnSelected += (
GUITickBox tickBox) =>
3008 rankDropDown.SelectItem(
null);
3010 DebugConsole.Command selectedCommand = tickBox.UserData as DebugConsole.Command;
3011 if (PlayerFrame.UserData is not
Client client) {
return false; }
3013 if (!tickBox.Selected)
3015 client.PermittedConsoleCommands.Remove(selectedCommand);
3017 else if (!client.PermittedConsoleCommands.Contains(selectedCommand))
3019 client.PermittedConsoleCommands.Add(selectedCommand);
3021 if (tickBox.Enabled)
3030 var buttonAreaTop = myClient ? null :
new GUILayoutGroup(
new RectTransform(
new Vector2(1.0f, 0.08f), paddedPlayerFrame.RectTransform), isHorizontal:
true);
3031 var buttonAreaLower =
new GUILayoutGroup(
new RectTransform(
new Vector2(1.0f, 0.08f), paddedPlayerFrame.RectTransform), isHorizontal:
true, childAnchor:
Anchor.CenterLeft);
3038 if (
GameMain.
Client?.ServerSettings?.BanList?.BannedPlayers?.Any(bp => bp.MatchesClient(selectedClient)) ??
false)
3041 TextManager.Get(
"clientpermission.unban"))
3043 UserData = selectedClient,
3050 TextManager.Get(
"Ban"))
3052 UserData = selectedClient,
3053 OnClicked = (bt, userdata) => { BanPlayer(selectedClient);
return true; }
3056 banButton.
OnClicked += ClosePlayerFrame;
3064 var kickVoteButton =
new GUIButton(
new RectTransform(
new Vector2(0.34f, 1.0f), buttonAreaLower.RectTransform),
3065 TextManager.Get(
"VoteToKick"))
3068 UserData = selectedClient
3075 var kickButton =
new GUIButton(
new RectTransform(
new Vector2(0.34f, 1.0f), buttonAreaLower.RectTransform),
3076 TextManager.Get(
"Kick"))
3078 UserData = selectedClient,
3079 OnClicked = (bt, userdata) => { KickPlayer(selectedClient);
return true; }
3081 kickButton.OnClicked += ClosePlayerFrame;
3084 var volumeLayout =
new GUILayoutGroup(
new RectTransform(
new Vector2(0.5f, 1f), headerVolumeContainer.RectTransform), isHorizontal:
false);
3085 var volumeTextLayout =
new GUILayoutGroup(
new RectTransform(
new Vector2(1f, 0.5f), volumeLayout.RectTransform), isHorizontal:
true, childAnchor:
Anchor.CenterLeft);
3086 new GUITextBlock(
new RectTransform(
new Vector2(0.6f, 1f), volumeTextLayout.RectTransform), TextManager.Get(
"VoiceChatVolume"));
3087 var volumePercentageText =
new GUITextBlock(
new RectTransform(
new Vector2(0.4f, 1f), volumeTextLayout.RectTransform), ToolBox.GetFormattedPercentage(selectedClient.
VoiceVolume), textAlignment: Alignment.Right);
3088 new GUIScrollBar(
new RectTransform(
new Vector2(1f, 0.5f), volumeLayout.RectTransform), barSize: 0.1f, style:
"GUISlider")
3090 Range =
new Vector2(0f, 1f),
3092 OnMoved = (_, barScroll) =>
3097 volumePercentageText.Text = ToolBox.GetFormattedPercentage(newVolume);
3103 TextManager.Get(
"Mute"))
3106 OnSelected = (tickBox) => { selectedClient.
MutedLocally = tickBox.Selected;
return true; }
3110 if (buttonAreaTop.CountChildren > 0)
3116 if (selectedClient.
AccountId.TryUnwrap(out var accountId))
3118 var viewSteamProfileButton =
new GUIButton(
new RectTransform(
new Vector2(0.3f, 1.0f), headerTextContainer.RectTransform,
Anchor.TopCenter) { MaxSize = new Point(int.MaxValue, (int)(40 * GUI.Scale)) },
3119 accountId.ViewProfileLabel())
3121 UserData = selectedClient
3123 viewSteamProfileButton.TextBlock.AutoScaleHorizontal =
true;
3124 viewSteamProfileButton.OnClicked = (bt, userdata) =>
3126 accountId.OpenProfile();
3132 TextManager.Get(
"Close"))
3134 IgnoreLayoutGroups =
true,
3135 OnClicked = ClosePlayerFrame
3139 for (
int i = 0; i < buttonAreaLower.CountChildren; i++)
3141 buttonAreaLower.GetChild(i).RectTransform.RelativeSize =
new Vector2(xSize, 1f);
3144 buttonAreaLower.RectTransform.NonScaledSize =
new Point(buttonAreaLower.Rect.Width, buttonAreaLower.RectTransform.Children.Max(c => c.NonScaledSize.Y));
3146 if (buttonAreaTop !=
null)
3148 if (buttonAreaTop.CountChildren == 0)
3150 paddedPlayerFrame.RemoveChild(buttonAreaTop);
3154 for (
int i = 0; i < buttonAreaTop.CountChildren; i++)
3156 buttonAreaTop.GetChild(i).RectTransform.RelativeSize =
new Vector2(1f / 3f, 1f);
3159 buttonAreaTop.RectTransform.NonScaledSize =
3160 buttonAreaLower.RectTransform.NonScaledSize =
3161 new Point(buttonAreaLower.Rect.Width, Math.Max(buttonAreaLower.RectTransform.NonScaledSize.Y, buttonAreaTop.RectTransform.Children.Max(c => c.NonScaledSize.Y)));
3168 private bool ClosePlayerFrame(
GUIButton button,
object userData)
3189 base.AddToGUIUpdateList();
3192 JobInfoFrame?.AddToGUIUpdateList();
3194 CharacterAppearanceCustomizationMenu?.AddToGUIUpdateList();
3195 JobSelectionFrame?.AddToGUIUpdateList();
3198 public override void Update(
double deltaTime)
3202 UpdateMicIcon((
float)deltaTime);
3210 double voipAmplitude = 0.0f;
3213 voipAmplitude = client.VoipSound?.CurrentAmplitude ?? 0.0f;
3222 else if (voip.LastEnqueueAudio > DateTime.Now -
new TimeSpan(0, 0, 0, 0, milliseconds: 100))
3232 autoRestartText.
Visible = autoRestartTimer > 0.0f && autoRestartBox.
Selected;
3233 if (!MathUtils.NearlyEqual(autoRestartTimer, 0.0f) && autoRestartBox.
Selected)
3235 autoRestartTimer = Math.Max(autoRestartTimer - (
float)deltaTime, 0.0f);
3236 if (autoRestartTimer > 0.0f)
3238 autoRestartText.
Text = TextManager.Get(
"RestartingIn") +
" " + ToolBox.SecondsToReadableTime(Math.Max(autoRestartTimer, 0));
3242 CharacterAppearanceCustomizationMenu?.Update();
3246 JobSelectionFrame.Visible =
false;
3249 if (GUI.MouseOn?.UserData is JobVariant jobPrefab && GUI.MouseOn.Style?.
Name ==
"JobVariantButton")
3251 if (jobVariantTooltip?.UserData is not JobVariant prevVisibleVariant || prevVisibleVariant.Prefab != jobPrefab.
Prefab || prevVisibleVariant.Variant != jobPrefab.Variant)
3253 CreateJobVariantTooltip(jobPrefab.
Prefab, jobPrefab.Variant, GUI.MouseOn.Parent);
3256 if (jobVariantTooltip !=
null)
3258 jobVariantTooltip?.AddToGUIUpdateList();
3259 Rectangle mouseRect = jobVariantTooltip.MouseRect;
3260 mouseRect.Inflate(60 * GUI.Scale, 60 * GUI.Scale);
3265 private void UpdateMicIcon(
float deltaTime)
3267 micCheckTimer -= deltaTime;
3268 if (micCheckTimer > 0.0f) {
return; }
3270 Identifier newMicIconStyle =
"GUIMicrophoneEnabled".ToIdentifier();
3271 if (GameSettings.CurrentConfig.Audio.VoiceSetting == VoiceMode.Disabled)
3273 newMicIconStyle =
"GUIMicrophoneDisabled".ToIdentifier();
3278 if (voipCaptureDeviceNames.Count == 0)
3280 newMicIconStyle =
"GUIMicrophoneUnavailable".ToIdentifier();
3284 if (newMicIconStyle != micIconStyle)
3286 micIconStyle = newMicIconStyle;
3287 GUIStyle.Apply(micIcon, newMicIconStyle);
3290 micCheckTimer = MicCheckInterval;
3293 public override void Draw(
double deltaTime, GraphicsDevice graphics, SpriteBatch spriteBatch)
3295 if (backgroundSprite?.Texture ==
null) {
return; }
3296 graphics.Clear(Color.Black);
3297 spriteBatch.Begin(SpriteSortMode.Deferred, samplerState: GUI.SamplerState, rasterizerState:
GameMain.
ScissorTestEnable);
3298 GUI.DrawBackgroundSprite(spriteBatch, backgroundSprite, Color.White);
3299 GUI.Draw(Cam, spriteBatch);
3303 private PlayStyle? prevPlayStyle =
null;
3304 private bool? prevIsPublic =
null;
3310 PlayStyle playStyle = GameMain.NetworkMember.ServerSettings.PlayStyle;
3312 Sprite sprite = GUIStyle
3313 .GetComponentStyle($
"PlayStyleBanner.{playStyle}")?
3314 .GetSprite(GUIComponent.ComponentState.None);
3315 if (sprite is
null) {
return; }
3317 GUI.DrawBackgroundSprite(spriteBatch, sprite, Color.White, drawArea: component.
Rect);
3319 if (!prevPlayStyle.HasValue || playStyle != prevPlayStyle.Value)
3321 playstyleText.
Text = TextManager.Get($
"ServerTag.{playStyle}");
3322 playstyleText.
Color = sprite.SourceElement.GetAttributeColor(
"BannerColor") ?? Color.White;
3324 prevPlayStyle = playStyle;
3325 (playstyleText.
Parent as GUILayoutGroup)?.Recalculate();
3326 playstyleText.
ToolTip = TextManager.Get($
"ServerTagDescription.{playStyle}");
3328 if (!prevIsPublic.HasValue || GameMain.NetworkMember.ServerSettings.IsPublic != prevIsPublic.Value)
3330 publicOrPrivateText.
Text = GameMain.NetworkMember.ServerSettings.IsPublic ? TextManager.Get(
"PublicLobbyTag") : TextManager.Get(
"PrivateLobbyTag");
3332 (publicOrPrivateText.
Parent as GUILayoutGroup)?.Recalculate();
3333 prevIsPublic = GameMain.NetworkMember.ServerSettings.IsPublic;
3337 private static void DrawJobVariantItems(SpriteBatch spriteBatch, GUICustomComponent component, JobVariant jobPrefab,
int itemsPerRow)
3339 var itemIdentifiers = jobPrefab.Prefab.PreviewItems[jobPrefab.Variant]
3340 .Where(it => it.ShowPreview)
3341 .Select(it => it.ItemIdentifier)
3344 Point slotSize =
new Point(component.Rect.Height);
3345 int spacing = (int)(5 * GUI.Scale);
3346 int slotCount = itemIdentifiers.Count();
3347 int slotCountPerRow = Math.Min(slotCount, itemsPerRow);
3348 int rows = (int)Math.Max(Math.Ceiling(itemIdentifiers.Count() / (float)itemsPerRow), 1);
3350 float totalWidth = slotSize.X * slotCountPerRow + spacing * (slotCountPerRow - 1);
3351 float totalHeight = slotSize.Y * rows + spacing * (rows - 1);
3352 if (totalWidth > component.Rect.Width)
3354 slotSize =
new Point(
3355 Math.Min((
int)Math.Floor((slotSize.X - spacing) * (component.Rect.Width / totalWidth)),
3356 (
int)Math.Floor((slotSize.Y - spacing) * (component.Rect.Height / totalHeight))));
3360 LocalizedString tooltip =
null;
3361 foreach (Identifier itemIdentifier
in itemIdentifiers)
3363 if (!(MapEntityPrefab.Find(
null, identifier: itemIdentifier, showErrorMessages:
false) is ItemPrefab itemPrefab)) {
continue; }
3365 int row = (int)Math.Floor(i / (
float)slotCountPerRow);
3366 int slotsPerThisRow = Math.Min((slotCount - row * slotCountPerRow), slotCountPerRow);
3367 Vector2 slotPos =
new Vector2(
3368 component.Rect.Center.X + (slotSize.X + spacing) * (i % slotCountPerRow - slotsPerThisRow * 0.5f),
3369 component.Rect.Bottom - (rows * (slotSize.Y + spacing)) + (slotSize.Y + spacing) * row);
3372 Inventory.SlotSpriteSmall.Draw(spriteBatch, slotPos,
3373 scale: slotSize.X / (
float)Inventory.SlotSpriteSmall.SourceRect.Width,
3374 color: slotRect.Contains(PlayerInput.MousePosition) ? Color.White : Color.White * 0.6f);
3376 Sprite icon = itemPrefab.InventoryIcon ?? itemPrefab.Sprite;
3377 float iconScale = Math.Min(Math.Min(slotSize.X / icon.size.X, slotSize.Y / icon.size.Y), 2.0f) * 0.9f;
3378 icon.Draw(spriteBatch, slotPos + slotSize.ToVector2() * 0.5f, scale: iconScale);
3380 int count = jobPrefab.Prefab.PreviewItems[jobPrefab.Variant].Count(it => it.ShowPreview && it.ItemIdentifier == itemIdentifier);
3383 string itemCountText =
"x" + count;
3384 GUIStyle.Font.DrawString(spriteBatch, itemCountText, slotPos + slotSize.ToVector2() - GUIStyle.Font.MeasureString(itemCountText) - Vector2.UnitX * 5, Color.White);
3387 if (slotRect.Contains(PlayerInput.MousePosition))
3389 tooltipRect = slotRect;
3390 tooltip = itemPrefab.Name +
'\n' + itemPrefab.Description;
3394 if (!tooltip.IsNullOrEmpty())
3396 GUIComponent.DrawToolTip(spriteBatch, tooltip, tooltipRect);
3402 float prevSize = chatBox.BarSize;
3404 while (chatBox.Content.CountChildren > 60)
3406 chatBox.RemoveChild(chatBox.Content.Children.First());
3411 textColor: message.
Color,
3412 color: ((chatBox.CountChildren % 2) == 0) ? Color.Transparent : Color.Black * 0.1f,
3413 wrap:
true, font: GUIStyle.SmallFont)
3416 CanBeFocused =
false
3426 OnClick = GameMain.NetLobbyScreen.SelectPlayer,
3427 OnSecondaryClick = GameMain.NetLobbyScreen.ShowPlayerContextMenu
3439 if ((prevSize == 1.0f && chatBox.BarScroll == 0.0f) || (prevSize < 1.0f && chatBox.BarScroll == 1.0f))
3441 chatBox.BarScroll = 1.0f;
3445 private bool SelectJobPreferencesTab(
GUIButton button,
object userData)
3447 jobPreferencesButton.
Selected =
true;
3450 JobPreferenceContainer.Visible =
true;
3451 appearanceFrame.
Visible =
false;
3456 private bool SelectAppearanceTab(GUIButton button,
object _)
3458 jobPreferencesButton.
Selected =
false;
3461 JobPreferenceContainer.Visible =
false;
3462 appearanceFrame.
Visible =
true;
3466 var info = GameMain.Client.CharacterInfo ?? Character.Controlled?.Info;
3467 CharacterAppearanceCustomizationMenu?.Dispose();
3468 CharacterAppearanceCustomizationMenu =
new CharacterInfo.AppearanceCustomizationMenu(info, appearanceFrame)
3470 OnHeadSwitch = menu =>
3472 UpdateJobPreferences(info);
3473 SelectAppearanceTab(button, _);
3482 if (info?.
Head ==
null) {
return false; }
3486 characterConfig.
TagSet.Clear();
3487 characterConfig.TagSet.UnionWith(info.Head.Preset.TagSet);
3488 characterConfig.HairIndex = info.Head.HairIndex;
3489 characterConfig.BeardIndex = info.Head.BeardIndex;
3490 characterConfig.MoustacheIndex = info.Head.MoustacheIndex;
3491 characterConfig.FaceAttachmentIndex = info.Head.FaceAttachmentIndex;
3492 characterConfig.HairColor = info.Head.HairColor;
3493 characterConfig.FacialHairColor = info.Head.FacialHairColor;
3494 characterConfig.SkinColor = info.Head.SkinColor;
3499 CreateChangesPendingText();
3501 GameSettings.SaveCurrentConfig();
3505 private bool SwitchJob(
GUIButton _,
object obj)
3507 if (JobList ==
null ||
GameMain.
Client ==
null) {
return false; }
3509 int childIndex = JobList.SelectedIndex;
3510 var child = JobList.SelectedComponent;
3511 if (child ==
null) {
return false; }
3513 bool moveToNext = obj !=
null;
3515 var jobPrefab = (obj as JobVariant)?.Prefab;
3518 var existingChild = JobList.Content.FindChild(d => (d.UserData is JobVariant prefab) && (prefab.Prefab == jobPrefab));
3519 if (existingChild !=
null && obj !=
null)
3521 existingChild.UserData = prevObj;
3523 child.UserData = obj;
3525 for (
int i = 0; i < 2; i++)
3527 if (i < 2 && JobList.Content.GetChild(i).UserData ==
null)
3529 JobList.Content.GetChild(i).UserData = JobList.Content.GetChild(i + 1).UserData;
3530 JobList.Content.GetChild(i + 1).UserData =
null;
3534 UpdateJobPreferences(GameMain.Client.CharacterInfo ??
Character.Controlled?.Info);
3538 var emptyChild = JobList.Content.FindChild(c => c.UserData ==
null && c.CanBeFocused);
3539 if (emptyChild !=
null)
3541 JobList.Select(JobList.Content.GetChildIndex(emptyChild));
3546 if (JobSelectionFrame !=
null) { JobSelectionFrame.Visible =
false; }
3551 OpenJobSelection(child, child.UserData);
3557 private bool OpenJobSelection(GUIComponent _,
object __)
3559 if (JobSelectionFrame !=
null)
3561 JobSelectionFrame.Visible =
true;
3565 Point frameSize =
new Point(characterInfoFrame.
Rect.Width, (
int)(characterInfoFrame.
Rect.Height * 2 * 0.6f));
3566 JobSelectionFrame =
new GUIFrame(
new RectTransform(frameSize, GUI.Canvas,
Anchor.TopLeft)
3567 { AbsoluteOffset = new Point(characterInfoFrame.Rect.Right - frameSize.X, characterInfoFrame.Rect.Bottom) }, style:
"GUIFrameListBox");
3571 if (characterInfoFrame ==
null || JobSelectionFrame?.RectTransform ==
null) {
return; }
3572 Point size =
new Point(characterInfoFrame.
Rect.Width, (
int)(characterInfoFrame.
Rect.Height * 2 * 0.6f));
3573 JobSelectionFrame.RectTransform.Resize(size);
3574 JobSelectionFrame.RectTransform.AbsoluteOffset =
new Point(characterInfoFrame.
Rect.Right - size.X, characterInfoFrame.
Rect.Bottom);
3577 new GUIFrame(
new RectTransform(
new Vector2(1.25f, 1.25f), JobSelectionFrame.RectTransform, anchor:
Anchor.Center), style:
"OuterGlow", color: Color.Black)
3579 UserData =
"outerglow",
3580 CanBeFocused =
false
3583 var rows =
new GUILayoutGroup(
new RectTransform(Vector2.One, JobSelectionFrame.RectTransform)) { Stretch =
true };
3584 var row =
new GUILayoutGroup(
new RectTransform(Vector2.One, rows.RectTransform),
true);
3586 GUIButton jobButton =
null;
3588 var availableJobs = JobPrefab.Prefabs.Where(jobPrefab =>
3589 !jobPrefab.HiddenJob && jobPrefab.MaxNumber > 0 && JobList.Content.Children.All(c => c.UserData is not JobVariant prefab || prefab.Prefab != jobPrefab)
3590 ).Select(j =>
new JobVariant(j, 0));
3592 availableJobs = availableJobs.Concat(
3593 JobPrefab.Prefabs.Where(jobPrefab =>
3594 !jobPrefab.HiddenJob && jobPrefab.MaxNumber > 0 && JobList.Content.Children.Any(c => (c.UserData is JobVariant prefab) && prefab.Prefab == jobPrefab)
3595 ).Select(j => (JobVariant)JobList.Content.FindChild(c => (c.UserData is JobVariant prefab) && prefab.Prefab == j).UserData));
3597 availableJobs = availableJobs.ToList();
3601 foreach (var jobPrefab
in availableJobs)
3603 if (itemsInRow >= 3)
3605 row =
new GUILayoutGroup(
new RectTransform(Vector2.One, rows.RectTransform),
true);
3609 jobButton =
new GUIButton(
new RectTransform(
new Vector2(1.0f / 3.0f, 1.0f), row.RectTransform), style:
"ListBoxElementSquare")
3611 UserData = jobPrefab,
3612 OnClicked = (btn, usdt) =>
3614 if (btn.IsParentOf(GUI.MouseOn))
return false;
3615 return SwitchJob(btn, usdt);
3620 var images = AddJobSpritesToGUIComponent(jobButton, jobPrefab.Prefab, selectedByPlayer:
false);
3621 if (images !=
null && images.Length > 1)
3623 jobPrefab.Variant = Math.Min(jobPrefab.Variant, images.Length);
3624 int currVisible = jobPrefab.Variant;
3625 GUIButton currSelected =
null;
3626 for (
int variantIndex = 0; variantIndex < images.Length; variantIndex++)
3628 foreach (GUIImage image
in images[variantIndex])
3630 image.Visible = currVisible == variantIndex;
3633 var variantButton = CreateJobVariantButton(jobPrefab, variantIndex, images.Length, jobButton);
3634 variantButton.OnClicked = (btn, obj) =>
3636 if (currSelected !=
null) { currSelected.Selected =
false; }
3637 int k = ((JobVariant)obj).Variant;
3638 btn.Parent.UserData = obj;
3639 for (
int j = 0; j < images.Length; j++)
3641 foreach (GUIImage image
in images[j])
3643 image.Visible = k == j;
3647 currSelected.Selected =
true;
3651 if (currVisible == variantIndex)
3653 currSelected = variantButton;
3657 if (currSelected !=
null)
3659 currSelected.Selected =
true;
3667 private static GUIImage[][] AddJobSpritesToGUIComponent(GUIComponent parent, JobPrefab jobPrefab,
bool selectedByPlayer)
3669 GUIFrame innerFrame =
null;
3670 List<JobPrefab.OutfitPreview> outfitPreviews = jobPrefab.GetJobOutfitSprites(CharacterPrefab.HumanPrefab.CharacterInfoPrefab, useInventoryIcon:
true, out var maxDimensions);
3672 innerFrame =
new GUIFrame(
new RectTransform(Vector2.One * 0.85f, parent.RectTransform,
Anchor.Center), style:
null)
3674 CanBeFocused =
false
3677 GUIImage[][] retVal = Array.Empty<GUIImage[]>();
3678 if (outfitPreviews !=
null && outfitPreviews.Any())
3680 retVal =
new GUIImage[outfitPreviews.Count][];
3681 for (
int i = 0; i < outfitPreviews.Count; i++)
3683 JobPrefab.OutfitPreview outfitPreview = outfitPreviews[i];
3684 retVal[i] =
new GUIImage[outfitPreview.Sprites.Count];
3685 for (
int j = 0; j < outfitPreview.Sprites.Count; j++)
3687 Sprite sprite = outfitPreview.Sprites[j].sprite;
3688 Vector2 drawOffset = outfitPreview.Sprites[j].drawOffset;
3689 float aspectRatio = outfitPreview.Dimensions.Y / outfitPreview.Dimensions.X;
3690 retVal[i][j] =
new GUIImage(
new RectTransform(
new Vector2(0.7f / aspectRatio, 0.7f), innerFrame.RectTransform,
Anchor.Center)
3691 { RelativeOffset = drawOffset / outfitPreview.Dimensions }, sprite, scaleToFit:
true)
3693 PressedColor = Color.White,
3694 CanBeFocused =
false
3700 new GUIFrame(
new RectTransform(
new Vector2(1.0f, 0.35f), parent.RectTransform,
Anchor.BottomCenter), style:
"OuterGlow")
3702 Color = Color.Black,
3703 HoverColor = Color.Black,
3704 PressedColor = Color.Black,
3705 SelectedColor = Color.Black,
3706 CanBeFocused =
false
3709 var textBlock =
new GUITextBlock(
3710 innerFrame.CountChildren == 0 ?
3711 new RectTransform(Vector2.One, parent.RectTransform,
Anchor.Center) :
3712 new RectTransform(
new Vector2(selectedByPlayer ? 0.55f : 0.95f, 0.3f), parent.RectTransform,
Anchor.BottomCenter),
3713 jobPrefab.Name, wrap:
true, textAlignment: Alignment.BottomCenter)
3715 Padding = Vector4.Zero,
3716 HoverColor = Color.Transparent,
3717 SelectedColor = Color.Transparent,
3718 TextColor = jobPrefab.UIColor,
3719 HoverTextColor = Color.Lerp(jobPrefab.UIColor, Color.White, 0.5f),
3720 CanBeFocused =
false,
3721 AutoScaleHorizontal =
true
3723 textBlock.TextAlignment = textBlock.WrappedText.Contains(
'\n') ? Alignment.BottomCenter : Alignment.Center;
3724 textBlock.RectTransform.SizeChanged += () => { textBlock.TextScale = 1.0f; };
3731 if (modeIndex < 0 || modeIndex >= ModeList.Content.CountChildren) {
return; }
3735 ToggleCampaignMode(
false);
3738 var prevMode = ModeList.Content.GetChild(selectedModeIndex).UserData as
GameModePreset;
3740 if ((HighlightedModeIndex == selectedModeIndex || HighlightedModeIndex < 0) && ModeList.SelectedIndex != modeIndex) { ModeList.Select(modeIndex,
GUIListBox.
Force.Yes); }
3741 selectedModeIndex = modeIndex;
3746 UpdatePlayerFrame(
null);
3755 respawnModeSelection.
Refresh();
3756 RefreshGameModeContent();
3757 RefreshEnabledElements();
3762 if (modeIndex < 0 || modeIndex >= ModeList.Content.CountChildren) {
return; }
3764 HighlightedModeIndex = modeIndex;
3765 RefreshGameModeContent();
3766 RefreshEnabledElements();
3769 private void RefreshMissionTypes()
3771 for (
int i = 0; i < missionTypeTickBoxes.Length; i++)
3779 if (SelectedMode == GameModePreset.Mission)
3781 missionTypeTickBoxes[i].
Parent.
Visible = MissionPrefab.CoOpMissionClasses.ContainsKey(missionType);
3783 else if (SelectedMode == GameModePreset.PvP)
3785 missionTypeTickBoxes[i].
Parent.
Visible = MissionPrefab.PvPMissionClasses.ContainsKey(missionType);
3790 private void RefreshGameModeContent()
3792 if (GameMain.Client ==
null) {
return; }
3794 foreach (var subElement
in SubList.Content.Children)
3796 subElement.CanBeFocused =
true;
3797 foreach (var textBlock
in subElement.GetAllChildren<GUITextBlock>())
3799 textBlock.Enabled =
true;
3803 SubList.Content.RectTransform.SortChildren((rt1, rt2) =>
3805 SubmarineInfo s1 = rt1.GUIComponent.UserData as SubmarineInfo;
3806 SubmarineInfo s2 = rt2.GUIComponent.UserData as SubmarineInfo;
3807 return s1.Name.CompareTo(s2.Name);
3811 if (SelectedMode == GameModePreset.Mission || SelectedMode == GameModePreset.PvP)
3813 MissionTypeFrame.Visible =
true;
3814 CampaignFrame.Visible = CampaignSetupFrame.Visible =
false;
3815 RefreshMissionTypes();
3817 else if (SelectedMode == GameModePreset.MultiPlayerCampaign)
3819 MissionTypeFrame.Visible = autoRestartBox.
Parent.
Visible =
false;
3821 if (GameMain.GameSession?.GameMode is CampaignMode campaign && campaign.Map !=
null)
3824 CampaignFrame.Visible = QuitCampaignButton.Enabled = CampaignMode.AllowedToManageCampaign(
ClientPermissions.ManageRound);
3825 CampaignSetupFrame.Visible =
false;
3829 CampaignFrame.Visible =
false;
3830 CampaignSetupFrame.Visible =
true;
3833 CampaignSetupFrame.ClearChildren();
3834 new GUITextBlock(
new RectTransform(
new Vector2(0.8f, 0.5f), CampaignSetupFrame.RectTransform,
Anchor.Center),
3835 TextManager.Get(
"campaignstarting"), font: GUIStyle.SubHeadingFont, textAlignment: Alignment.Center, wrap:
true);
3839 if (CampaignSetupUI !=
null)
3841 foreach (var subElement
in SubList.Content.Children)
3843 var sub = subElement.UserData as SubmarineInfo;
3844 bool tooExpensive = sub.Price > CampaignSettings.CurrentSettings.InitialMoney;
3845 if (tooExpensive || !sub.IsCampaignCompatible)
3847 foreach (var textBlock
in subElement.GetAllChildren<GUITextBlock>())
3849 textBlock.DisabledTextColor = (textBlock.UserData as
string ==
"pricetext" && tooExpensive ? GUIStyle.Red : GUIStyle.TextColorNormal) * 0.7f;
3850 textBlock.Enabled =
false;
3854 SubList.Content.RectTransform.SortChildren((rt1, rt2) =>
3856 SubmarineInfo s1 = rt1.GUIComponent.UserData as SubmarineInfo;
3857 SubmarineInfo s2 = rt2.GUIComponent.UserData as SubmarineInfo;
3859 if (!s1.IsCampaignCompatible) { p1 += 100000; }
3861 if (!s2.IsCampaignCompatible) { p2 += 100000; }
3862 return p1.CompareTo(p2) * 100 + s1.Name.CompareTo(s2.Name);
3868 MissionTypeFrame.Visible = CampaignFrame.Visible = CampaignSetupFrame.Visible =
false;
3869 CampaignFrame.Visible = CampaignSetupFrame.Visible =
false;
3872 ReadyToStartBox.Parent.Visible = !GameMain.Client.GameStarted;
3873 RefreshStartButtonVisibility();
3878 if (
CampaignSetupUI !=
null && CampaignSetupFrame is { Visible:
true })
3881 StartButton.Visible =
3890 StartButton.Visible =
3901 if (campaignCharacterInfo !=
null)
3903 campaignCharacterInfo =
null;
3904 UpdatePlayerFrame(
null);
3907 CampaignCharacterDiscarded =
false;
3909 RefreshEnabledElements();
3918 string name = submarine?.
Name;
3919 bool displayed =
false;
3920 SubList.OnSelected -= VotableClicked;
3928 if (sub.Name == name)
3930 SubList.Select(sub);
3933 CreateSubPreview(sub);
3939 SubList.OnSelected += VotableClicked;
3942 CreateSubPreview(submarine);
3944 UpdateSubVisibility();
3947 private bool ViewJobInfo(
GUIButton button,
object obj)
3949 if (button.
UserData is not JobVariant jobPrefab) {
return false; }
3951 JobInfoFrame = jobPrefab.Prefab.CreateInfoFrame(out GUIComponent buttonContainer);
3952 GUIButton closeButton =
new GUIButton(
new RectTransform(
new Vector2(0.25f, 0.05f), buttonContainer.RectTransform, Anchor.BottomRight),
3953 TextManager.Get(
"Close"))
3955 OnClicked = CloseJobInfo
3957 JobInfoFrame.OnClicked = (btn, userdata) => {
if (GUI.MouseOn == btn || GUI.MouseOn == btn.TextBlock) CloseJobInfo(btn, userdata);
return true; };
3962 private bool CloseJobInfo(GUIButton button,
object obj)
3964 JobInfoFrame =
null;
3968 private void UpdateJobPreferences(CharacterInfo characterInfo)
3970 if (characterInfo ==
null) {
return; }
3972 GUICustomComponent characterIcon = JobPreferenceContainer.GetChild<GUICustomComponent>();
3973 JobPreferenceContainer.RemoveChild(characterIcon);
3974 characterInfo.CreateIcon(
new RectTransform(
new Vector2(1.0f, 0.4f), JobPreferenceContainer.RectTransform,
Anchor.TopCenter) { RelativeOffset =
new Vector2(0.0f, 0.025f) });
3976 GUIListBox listBox = JobPreferenceContainer.GetChild<GUIListBox>();
3980 List<MultiplayerPreferences.JobPreference> jobPreferences =
new List<MultiplayerPreferences.JobPreference>();
3982 bool disableNext =
false;
3983 for (
int i = 0; i < listBox.Content.CountChildren; i++)
3985 GUIComponent slot = listBox.Content.GetChild(i);
3987 slot.ClearChildren();
3989 slot.CanBeFocused = !disableNext;
3990 if (slot.UserData is JobVariant jobPrefab)
3992 var images = AddJobSpritesToGUIComponent(slot, jobPrefab.Prefab, selectedByPlayer:
true);
3993 for (
int variantIndex = 0; variantIndex < images.Length; variantIndex++)
3995 foreach (GUIImage image
in images[variantIndex])
3998 int selectedVariantIndex = Math.Min(jobPrefab.Variant, images.Length);
3999 image.Visible = images.Length == 1 || selectedVariantIndex == variantIndex;
4001 if (images.Length > 1)
4003 var variantButton = CreateJobVariantButton(jobPrefab, variantIndex, images.Length, slot);
4004 variantButton.OnClicked = (btn, obj) =>
4006 btn.Parent.UserData = obj;
4007 UpdateJobPreferences(characterInfo);
4014 new GUIButton(
new RectTransform(
new Vector2(0.15f), slot.RectTransform,
Anchor.BottomLeft, scaleBasis:
ScaleBasis.BothWidth) { RelativeOffset = new Vector2(0.075f) },
4015 style:
"GUIButtonInfo")
4017 UserData = jobPrefab,
4018 OnClicked = ViewJobInfo
4022 new GUIButton(
new RectTransform(
new Vector2(0.15f), slot.RectTransform,
Anchor.BottomRight, scaleBasis:
ScaleBasis.BothWidth) { RelativeOffset = new Vector2(0.075f) },
4023 style:
"GUICancelButton")
4026 OnClicked = (btn, obj) =>
4028 JobList.Select((
int)obj, GUIListBox.Force.Yes);
4029 SwitchJob(btn,
null);
4030 if (JobSelectionFrame !=
null) { JobSelectionFrame.Visible =
false; }
4037 jobPreferences.Add(
new MultiplayerPreferences.JobPreference(jobPrefab.Prefab.Identifier, jobPrefab.Variant));
4041 new GUITextBlock(
new RectTransform(
new Vector2(1.0f, 0.6f), slot.RectTransform), (i + 1).ToString(),
4042 textColor: Color.White * (disableNext ? 0.15f : 0.5f),
4043 textAlignment: Alignment.Center,
4044 font: GUIStyle.LargeFont)
4046 CanBeFocused =
false
4051 new GUITextBlock(
new RectTransform(
new Vector2(1.0f, 0.4f), slot.RectTransform,
Anchor.BottomCenter), TextManager.Get(
"clicktoselectjob"),
4052 font: GUIStyle.SmallFont,
4054 textAlignment: Alignment.Center)
4056 CanBeFocused =
false
4063 GameMain.Client.ForceNameAndJobUpdate();
4065 if (!MultiplayerPreferences.Instance.AreJobPreferencesEqual(jobPreferences))
4067 if (GameMain.GameSession?.IsRunning ??
false)
4069 TabMenu.PendingChanges =
true;
4070 CreateChangesPendingText();
4073 MultiplayerPreferences.Instance.JobPreferences.Clear();
4074 MultiplayerPreferences.Instance.JobPreferences.AddRange(jobPreferences);
4075 GameSettings.SaveCurrentConfig();
4079 private static GUIButton CreateJobVariantButton(JobVariant jobPrefab,
int variantIndex,
int variantCount, GUIComponent slot)
4081 float relativeSize = 0.15f;
4083 var btn =
new GUIButton(
new RectTransform(
new Vector2(relativeSize), slot.RectTransform,
Anchor.TopCenter, scaleBasis:
ScaleBasis.BothHeight)
4084 { RelativeOffset = new Vector2(relativeSize * 1.3f * (variantIndex - (variantCount - 1) / 2.0f), 0.02f) },
4085 (variantIndex + 1).ToString(), style:
"JobVariantButton")
4087 Selected = jobPrefab.Variant == variantIndex,
4088 UserData =
new JobVariant(jobPrefab.Prefab, variantIndex),
4099 public void Deconstruct(out
string name, out
string hash) { name = Name; hash = Hash; }
4101 private static bool StringsEqual(
string a,
string b)
4102 =>
string.Equals(a, b, StringComparison.OrdinalIgnoreCase);
4105 => StringsEqual(a.Name, b.Name) && StringsEqual(a.Hash, b.Hash);
4112 return HashCode.Combine(Name, Hash);
4118 Name == info.
Name &&
4126 public List<FailedSubInfo> FailedCampaignSubs =
new List<FailedSubInfo>();
4127 public List<FailedSubInfo> FailedOwnedSubs =
new List<FailedSubInfo>();
4131 UpdateSubVisibility();
4141 .FirstOrDefault(c => c.UserData is
SubmarineInfo s && s.
Name == subName && s.MD5Hash?.StringRepresentation == md5Hash)?
4147 if (subList == SubList)
4149 CreateSubPreview(sub);
4171 subDropDown.SelectItem(sub);
4180 if (subList == SubList)
4182 FailedSelectedSub =
null;
4186 FailedSelectedShuttle =
null;
4199 if (subList == SubList)
4205 FailedSelectedShuttle =
new FailedSubInfo(subName, md5Hash);
4211 errorMsg = TextManager.GetWithVariable(
"SubNotFoundError",
"[subname]", subName) +
" ";
4215 errorMsg = TextManager.GetWithVariable(
"SubLoadError",
"[subname]", subName) +
" ";
4217 if (textBlock !=
null) { textBlock.
TextColor = GUIStyle.Red; }
4221 errorMsg = TextManager.GetWithVariables(
"SubDoesntMatchError",
4222 (
"[subname]", sub.
Name),
4233 new GUIMessageBox(TextManager.Get(
"DownloadSubLabel"), errorMsg);
4255 if (purchasableSub !=
null)
4262 switch (deliveryData)
4265 FailedOwnedSubs.Add(fileInfo);
4268 FailedCampaignSubs.Add(fileInfo);
4281 RecalculateSubDescription();
4284 private void RecalculateSubDescription()
4286 var descriptionBox = subPreviewContainer?.
FindChild(
"descriptionbox", recursive:
true);
4287 if (descriptionBox !=
null && characterInfoFrame !=
null)
4290 if (Math.Abs(descriptionBox.Rect.Height - characterInfoFrame.
Rect.Height) < 80 * GUI.Scale)
4297 private readonly List<SubmarineInfo> visibilityMenuOrder =
new List<SubmarineInfo>();
4298 private void CreateSubmarineVisibilityMenu()
4300 var messageBox =
new GUIMessageBox(TextManager.Get(
"SubmarineVisibility"),
"",
4301 buttons: Array.Empty<LocalizedString>(),
4302 relativeSize:
new Vector2(0.75f, 0.75f));
4303 messageBox.Content.ChildAnchor =
Anchor.TopCenter;
4304 var columns =
new GUILayoutGroup(
new RectTransform(
new Vector2(1.0f, 0.9f), messageBox.Content.RectTransform), isHorizontal:
true);
4306 GUILayoutGroup createColumn(
float width)
4307 =>
new GUILayoutGroup(
new RectTransform(
new Vector2(width, 1.0f), columns.RectTransform))
4310 GUIListBox createColumnListBox(
string labelTag)
4312 var column = createColumn(0.45f);
4313 var label =
new GUITextBlock(
new RectTransform(
new Vector2(1.0f, 0.1f), column.RectTransform),
4314 TextManager.Get(labelTag), textAlignment: Alignment.Center);
4315 return new GUIListBox(
new RectTransform(
new Vector2(1.0f, 0.9f), column.RectTransform))
4317 CurrentSelectMode = GUIListBox.SelectMode.RequireShiftToSelectMultiple,
4318 CurrentDragMode = GUIListBox.DragMode.DragOutsideBox,
4319 HideDraggedElement =
true
4323 void handleDraggingAcrossLists(GUIListBox from, GUIListBox to)
4327 if (to.Rect.Contains(PlayerInput.MousePosition) && from.DraggedElement !=
null)
4330 var draggedElement = from.DraggedElement;
4332 var selected = from.AllSelected.ToList();
4333 selected.Sort((a, b) => from.Content.GetChildIndex(a) - from.Content.GetChildIndex(b));
4335 float oldCount = to.Content.CountChildren;
4336 float newCount = oldCount + selected.Count;
4338 var offset = draggedElement.RectTransform.AbsoluteOffset;
4339 offset += from.Content.Rect.Location;
4340 offset -= to.Content.Rect.Location;
4342 for (
int i = 0; i < selected.Count; i++)
4344 var c = selected[i];
4345 c.Parent.RemoveChild(c);
4346 c.RectTransform.Parent = to.Content.RectTransform;
4347 c.RectTransform.RepositionChildInHierarchy((
int)oldCount+i);
4350 from.DraggedElement =
null;
4352 from.RecalculateChildren();
4353 from.RectTransform.RecalculateScale(
true);
4354 to.RecalculateChildren();
4355 to.RectTransform.RecalculateScale(
true);
4356 to.Select(selected);
4359 draggedElement.RectTransform.AbsoluteOffset = offset;
4361 to.DraggedElement = draggedElement;
4363 to.BarScroll *= (oldCount / newCount);
4367 var visibleSubsList = createColumnListBox(
"VisibleSubmarines");
4368 var centerColumn = createColumn(0.1f);
4370 void centerSpacing()
4372 new GUIFrame(
new RectTransform(
new Vector2(1.0f, 0.4f), centerColumn.RectTransform), style:
null);
4375 GUIButton centerButton(
string style)
4377 new RectTransform(
new Vector2(1.0f, 0.1f), centerColumn.RectTransform),
4380 var hiddenSubsList = createColumnListBox(
"HiddenSubmarines");
4382 void addSubToList(SubmarineInfo sub, GUIListBox list)
4384 var modFrame =
new GUIFrame(
new RectTransform(
new Vector2(1.0f, 0.08f), list.Content.RectTransform),
4385 style:
"ListBoxElement")
4390 var frameContent =
new GUILayoutGroup(
new RectTransform(
new Vector2(0.95f, 0.9f), modFrame.RectTransform,
Anchor.Center), isHorizontal:
true, childAnchor:
Anchor.CenterLeft)
4393 RelativeSpacing = 0.02f
4396 var dragIndicator =
new GUIButton(
new RectTransform(
new Vector2(0.5f, 0.5f), frameContent.RectTransform, scaleBasis:
ScaleBasis.BothHeight),
4397 style:
"GUIDragIndicator")
4399 CanBeFocused =
false
4402 var subName =
new GUITextBlock(
new RectTransform(
new Vector2(0.6f, 1.0f), frameContent.RectTransform),
4403 text: sub.DisplayName)
4405 CanBeFocused =
false
4408 CreateSubmarineClassText(
4415 foreach (var sub
in GameMain.Client.ServerSubmarines
4416 .OrderBy(s => visibilityMenuOrder.Contains(s))
4417 .ThenBy(s => visibilityMenuOrder.IndexOf(s)))
4420 GameMain.Client.ServerSettings.HiddenSubs.Contains(sub.Name) ? hiddenSubsList : visibleSubsList);
4423 void onRearranged(GUIListBox listBox,
object userData)
4425 visibilityMenuOrder.Clear();
4426 visibilityMenuOrder.AddRange(visibleSubsList.Content.Children.Select(c => c.UserData as SubmarineInfo));
4427 visibilityMenuOrder.AddRange(hiddenSubsList.Content.Children.Select(c => c.UserData as SubmarineInfo));
4430 visibleSubsList.OnRearranged = onRearranged;
4431 hiddenSubsList.OnRearranged = onRearranged;
4433 void swapListItems(GUIListBox from, GUIListBox to)
4436 var selected = from.AllSelected.ToArray();
4437 int lastIndex = from.Content.GetChildIndex(selected.LastOrDefault());
4438 int nextIndex = lastIndex + 1;
4439 GUIComponent nextComponent =
null;
4440 if (lastIndex >= 0 && nextIndex < from.Content.CountChildren)
4442 nextComponent = from.Content.GetChild(nextIndex);
4444 foreach (var frame
in selected)
4446 frame.Parent.RemoveChild(frame);
4447 frame.RectTransform.Parent = to.Content.RectTransform;
4449 from.RecalculateChildren();
4450 from.RectTransform.RecalculateScale(
true);
4451 to.RecalculateChildren();
4452 to.RectTransform.RecalculateScale(
true);
4453 to.Select(selected);
4454 if (nextComponent !=
null) { from.Select(nextComponent.ToEnumerable()); }
4458 var visibleToHidden = centerButton(
"GUIButtonToggleRight");
4459 visibleToHidden.OnClicked = (button, o) =>
4461 swapListItems(visibleSubsList, hiddenSubsList);
4464 var hiddenToVisible = centerButton(
"GUIButtonToggleLeft");
4465 hiddenToVisible.OnClicked = (button, o) =>
4467 swapListItems(hiddenSubsList, visibleSubsList);
4473 =
new GUILayoutGroup(
new RectTransform(
new Vector2(0.7f, 0.1f), messageBox.Content.RectTransform),
4476 RelativeSpacing = 0.01f
4478 var cancelButton =
new GUIButton(
new RectTransform(
new Vector2(0.5f, 1.0f), buttonLayout.RectTransform),
4479 TextManager.Get(
"Cancel"))
4481 OnClicked = (button, o) =>
4487 var okButton =
new GUIButton(
new RectTransform(
new Vector2(0.5f, 1.0f), buttonLayout.RectTransform),
4488 TextManager.Get(
"OK"))
4490 OnClicked = (button, o) =>
4492 var hiddenSubs = GameMain.Client.ServerSettings.HiddenSubs;
4494 hiddenSubs.UnionWith(hiddenSubsList.Content.Children.Select(c => (c.UserData as SubmarineInfo).Name));
4501 new GUICustomComponent(
new RectTransform(Vector2.Zero, messageBox.RectTransform),
4502 onUpdate: (f, component) =>
4504 handleDraggingAcrossLists(visibleSubsList, hiddenSubsList);
4505 handleDraggingAcrossLists(hiddenSubsList, visibleSubsList);
4506 if (PlayerInput.PrimaryMouseButtonClicked()
4507 && !GUI.IsMouseOn(visibleToHidden)
4508 && !GUI.IsMouseOn(hiddenToVisible))
4510 if (!GUI.IsMouseOn(hiddenSubsList)
4511 || !hiddenSubsList.Content.IsParentOf(GUI.MouseOn))
4513 hiddenSubsList.Deselect();
4516 if (!GUI.IsMouseOn(visibleSubsList)
4517 || !visibleSubsList.Content.IsParentOf(GUI.MouseOn))
4519 visibleSubsList.Deselect();
4523 onDraw: (spriteBatch, component) =>
4525 visibleSubsList.DraggedElement?.DrawManually(spriteBatch,
true,
true);
4526 hiddenSubsList.DraggedElement?.DrawManually(spriteBatch,
true,
true);
4538 && (
string.IsNullOrEmpty(subSearchBox.
Text) || sub.DisplayName.Contains(subSearchBox.
Text, StringComparison.OrdinalIgnoreCase));
4544 CampaignCharacterDiscarded =
false;
static Character? Controlled
Stores information about the Character that is needed between rounds in the menu etc....
void CreateIcon(RectTransform rectT)
void RecreateHead(ImmutableHashSet< Identifier > tags, int hairIndex, int beardIndex, int moustacheIndex, int faceAttachmentIndex)
Character Character
Note: Can be null.
bool OmitJobInMenus
Can be used to disable displaying the job in any info panels
readonly ChatManager ChatManager
A class used for handling special key actions in chat boxes. For example tab completion or up/down ar...
static void RegisterKeys(GUITextBox element, ChatManager manager)
Registers special input actions to the selected input field
void Clear()
Call this function whenever we should stop doing special stuff and return normal behavior....
static CoroutineStatus Running
static CoroutineStatus Success
GUIComponent GetChild(int index)
virtual void RemoveChild(GUIComponent child)
void InheritTotalChildrenMinHeight()
Sets the minimum height of the transfrom to equal to the sum of the minimum heights of the children (...
GUIComponent GetChildByUserData(object obj)
virtual void ClearChildren()
GUIComponent FindChild(Func< GUIComponent, bool > predicate, bool recursive=false)
virtual RichString ToolTip
int GetChildIndex(GUIComponent child)
IEnumerable< GUIComponent > GetAllChildren()
Returns all child elements in the hierarchy.
RectTransform RectTransform
IEnumerable< GUIComponent > Children
GUIComponent that can be used to render custom content on the UI
bool HideElementsOutsideFrame
Vector2 MeasureString(LocalizedString str, bool removeExtraSpacing=false)
override void RemoveChild(GUIComponent child)
OnSelectedHandler OnSelected
GUIFrame Content
A frame that contains the contents of the listbox. The frame itself is not rendered.
void Select(object userData, Force force=Force.No, AutoScroll autoScroll=AutoScroll.Enabled)
OnValueChangedHandler? OnValueChanged
void Refresh()
Refresh the current selection, for example if there are conditions for which elements are valid,...
Func< T, bool >? ElementSelectionCondition
Are there some conditions for selecting a particular element?
void AddElement(T value, LocalizedString text, LocalizedString? tooltip=null)
void CalculateHeightFromText(int padding=0, bool removeExtraSpacing=false)
bool AutoScaleHorizontal
When enabled, the text is automatically scaled down to fit the textblock horizontally.
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...
List< ClickableArea > ClickableAreas
ImmutableArray< RichTextData >? RichTextData
TextBoxEvent OnDeselected
OnTextChangedHandler OnTextChanged
Don't set the Text property on delegates that register to this event, because modifying the Text will...
static GameSession?? GameSession
static NetLobbyScreen NetLobbyScreen
static RasterizerState ScissorTestEnable
static Lights.LightManager LightManager
static bool IsSingleplayer
static NetworkMember NetworkMember
static GameModePreset PvP
static GameModePreset MultiPlayerCampaign
readonly Identifier Identifier
SubmarineInfo SubmarineInfo
IEnumerable< Skill > GetSkills()
readonly LocalizedString Name
static readonly PrefabCollection< JobPrefab > Prefabs
readonly ImmutableDictionary< int, ImmutableArray< PreviewItem > > PreviewItems
Sprite GetPortrait(int randomSeed)
static LocationType Random(Random rand, int? zone=null, bool requireOutpost=false, Func< LocationType, bool > predicate=null)
Mersenne Twister based random
readonly string StringRepresentation
readonly string ShortRepresentation
static string GetShortHash(string fullHash)
static readonly HashSet< MissionType > HiddenMissionClasses
bool StartGameClicked(GUIButton button, object userdata)
readonly HashSet< Identifier > TagSet
static MultiplayerPreferences Instance
static void CreateModerationContextMenu(Client client)
GUITextBlock FileTransferProgressText
GUITickBox ReadyToStartBox
FailedSubInfo? FailedSelectedShuttle
List< JobVariant >? JobPreferences
void SetPlayerNameAndJobPreference(Client client)
static GUIButton JobInfoFrame
void SetSpectate(bool spectate)
void ToggleCampaignMode(bool enabled)
void TryDiscardCampaignCharacter(Action onYes)
void HighlightMode(int modeIndex)
void SelectMode(int modeIndex)
static void CreateChangesPendingFrame(GUIComponent parent)
CharacterInfo.AppearanceCustomizationMenu CharacterAppearanceCustomizationMenu
GUIButton QuitCampaignButton
void UpdateSubList(GUIComponent subList, IEnumerable< SubmarineInfo > submarines)
static void BanPlayer(Client client)
GUIFrame CampaignSetupFrame
static GUINumberInput CreateLabeledNumberInput(GUIComponent parent, string labelTag, int min, int max, string toolTipTag=null, GUIFont font=null)
SubmarineInfo SelectedSub
GUIFrame JobSelectionFrame
bool ToggleSpectate(GUITickBox tickBox)
FailedSubInfo? FailedSelectedSub
bool CampaignCharacterDiscarded
static GUITextBlock CreateSubHeader(string textTag, GUIComponent parent, string toolTipTag=null)
GUIButton SubVisibilityButton
void AddPlayer(Client client)
GUIComponent FileTransferFrame
GUIFrame MissionTypeFrame
MultiPlayerCampaignSetupUI CampaignSetupUI
void RefreshStartButtonVisibility()
void RefreshPlaystyleIcons()
void StopWaitingForStartRound()
GUIFrame JobPreferenceContainer
void SetPlayerSpeaking(Client client)
void SetMissionType(MissionType missionType)
static IEnumerable< CoroutineStatus > WaitForStartRound(GUIButton startButton)
SubmarineInfo SelectedShuttle
void ShowPlayerContextMenu(GUITextBlock component, GUITextBlock.ClickableArea area)
GameModePreset SelectedMode
GUIProgressBar FileTransferProgressBar
GUITextBlock FileTransferTitle
IReadOnlyList< SubmarineInfo > GetSubList()
void SetAutoRestart(bool enabled, float timer=0.0f)
bool SelectPlayer(Client selectedClient)
GUIButton ServerMessageButton
void SetCampaignCharacterInfo(CharacterInfo newCampaignCharacterInfo)
override void AddToGUIUpdateList()
By default, submits the screen's main GUIFrame and, if requested upon construction,...
GUILayoutGroup LogButtons
static GUIDropDown CreateLabeledDropdown(GUIComponent parent, string labelTag, int numElements, string toolTipTag=null)
void SetPlayerVoiceIconState(Client client, bool muted, bool mutedLocally)
static GUIComponent CreateLabeledSlider(GUIComponent parent, string headerTag, string valueLabelTag, string tooltipTag, out GUIScrollBar slider, out GUITextBlock label, float? step=null, Vector2? range=null)
void AssignComponentsToServerSettings()
static Client ExtractClientFromClickableArea(GUITextBlock.ClickableArea area)
void ShowSpectateButton()
void CreatePlayerFrame(GUIComponent parent, bool createPendingText=true, bool alwaysAllowEditing=false)
GUIListBox TeamPreferenceListBox
void UpdateSubVisibility()
void RefreshEnabledElements()
bool CheckIfCampaignSubMatches(SubmarineInfo serverSubmarine, SubmarineDeliveryData deliveryData)
bool TrySelectSub(string subName, string md5Hash, GUIListBox subList)
void NewChatMessage(ChatMessage message)
bool VotableClicked(GUIComponent component, object userData)
override void Draw(double deltaTime, GraphicsDevice graphics, SpriteBatch spriteBatch)
void RemovePlayer(Client client)
override void Update(double deltaTime)
void TryDisplayCampaignSubmarine(SubmarineInfo submarine)
static void KickPlayer(Client client)
GUITextBox CharacterNameBox
void SetAllowSpectating(bool allowSpectating)
void SelectPlayer(GUITextBlock component, GUITextBlock.ClickableArea area)
static string GetTimeStamp()
const float MaxVoiceChatBoost
static string SanitizeName(string name)
readonly HashSet< DebugConsole.Command > PermittedConsoleCommands
bool HasPermission(ClientPermissions permission)
CharacterTeamType PreferredTeam
void SetPermissions(ClientPermissions permissions, IEnumerable< Identifier > permittedConsoleCommands)
Option< AccountId > AccountId
The ID of the account used to authenticate this session. This value can be used as a persistent value...
readonly byte SessionId
An ID for this client for the current session. THIS IS NOT A PERSISTENT VALUE. DO NOT STORE THIS LONG...
ClientPermissions Permissions
IReadOnlyList< FileTransferIn > ActiveTransfers
void VoteForKick(Client votedClient)
void Vote(VoteType voteType, object data)
void RequestFile(FileTransferType fileType, string file, string fileHash)
bool TypingChatMessage(GUITextBox textBox, string text)
override IReadOnlyList< Client > ConnectedClients
void UpdateClientPermissions(Client targetClient)
bool HasPermission(ClientPermissions permission)
readonly FileReceiver FileReceiver
CharacterInfo CharacterInfo
void RequestSelectSub(SubmarineInfo sub, bool isShuttle)
Tell the server to select a submarine (permission required)
void RequestSelectMode(int modeIndex)
Tell the server to select a mode (permission required)
readonly List< SubmarineInfo > ServerSubmarines
override void UnbanPlayer(string playerName)
bool JoinOnGoingClicked(GUIButton button, object _)
void CreateKickReasonPrompt(string clientName, bool ban)
bool EnterChatMessage(GUITextBox textBox, string message)
bool SetReadyToStart(GUITickBox tickBox)
readonly LocalizedString Description
static readonly List< PermissionPreset > List
readonly HashSet< DebugConsole.Command > PermittedCommands
readonly ClientPermissions Permissions
readonly LocalizedString DisplayName
IEnumerable< Identifier > GetPlayStyleTags()
static ServerInfo FromServerEndpoints(ImmutableArray< Endpoint > endpoints, ServerSettings serverSettings)
float ReplaceCostPercentage
Percentage modifier for the cost of hiring a new character to replace a permanently killed one.
float SkillLossPercentageOnImmediateRespawn
How much more the skills drop towards the job's default skill levels when dying, in addition to Skill...
float SelectedLevelDifficulty
bool IronmanMode
This is an optional setting for permadeath mode. When it's enabled, a player client whose character d...
float SkillLossPercentageOnDeath
How much skills drop towards the job's default skill levels when dying
BotSpawnMode BotSpawnMode
bool AllowBotTakeoverOnPermadeath
Are players allowed to take over bots when permadeath is enabled?
int TraitorsMinPlayerCount
static IReadOnlyList< string > GetCaptureDeviceNames()
static VoipCapture Instance
static void UpdateVoiceIndicator(GUIImage soundIcon, float voipAmplitude, float deltaTime)
Prefab(ContentFile file, Identifier identifier)
static RichString Rich(LocalizedString str, Func< string, string >? postProcess=null)
LocalizedString DisplayName
LocalizedString Description
void CreatePreviewWindow(GUIComponent parent)
static IEnumerable< SubmarineInfo > SavedSubmarines
bool HasTag(SubmarineTag tag)
bool RequiredContentPackagesInstalled
void ResetVotes(IEnumerable< Client > connectedClients)
override bool Equals(object obj)
FailedSubInfo(string name, string hash)
override int GetHashCode()
void Deconstruct(out string name, out string hash)