Client LuaCsForBarotrauma
BarotraumaClient/ClientSource/GameSession/GameSession.cs
3 using Microsoft.Xna.Framework;
4 using Microsoft.Xna.Framework.Graphics;
5 using System;
6 
7 namespace Barotrauma
8 {
9  partial class GameSession
10  {
12  {
13  get;
14  private set;
15  }
16 
17  public static bool IsTabMenuOpen => GameMain.GameSession?.tabMenu != null;
18  public static TabMenu TabMenuInstance => GameMain.GameSession?.tabMenu;
19 
20  private TabMenu tabMenu;
21 
22  public bool ToggleTabMenu()
23  {
24  if (GameMain.NetworkMember != null && GameMain.NetLobbyScreen != null)
25  {
29  }
30  if (tabMenu == null && GameMode is not TutorialMode && !ConversationAction.IsDialogOpen)
31  {
32  tabMenu = new TabMenu();
33  HintManager.OnShowTabMenu();
34  }
35  else
36  {
37  tabMenu?.OnClose();
38  tabMenu = null;
40  }
41  return true;
42  }
43 
44  private GUILayoutGroup topLeftButtonGroup;
45  private GUIButton crewListButton, commandButton, tabMenuButton;
46  private GUIImage talentPointNotification;
47 
48  private GUIComponent deathChoiceInfoFrame, deathChoiceButtonContainer;
49  private GUITextBlock respawnInfoText;
50  private GUITickBox deathChoiceTickBox;
51  private GUIButton takeOverBotButton;
52  private GUIButton hrManagerButton;
54 
55  private GUIImage eventLogNotification;
56 
57  private Point prevTopLeftButtonsResolution;
58 
59  public bool AllowHrManagerBotTakeover => GameMain.NetworkMember?.ServerSettings is { RespawnMode: RespawnMode.Permadeath, IronmanMode: false }
61 
62  private void CreateTopLeftButtons()
63  {
64  if (topLeftButtonGroup != null)
65  {
66  topLeftButtonGroup.RectTransform.Parent = null;
67  topLeftButtonGroup = null;
68  crewListButton = commandButton = tabMenuButton = null;
69  }
70  topLeftButtonGroup = new GUILayoutGroup(HUDLayoutSettings.ToRectTransform(HUDLayoutSettings.ButtonAreaTop, GUI.Canvas), isHorizontal: true, childAnchor: Anchor.CenterLeft)
71  {
72  AbsoluteSpacing = HUDLayoutSettings.Padding,
73  CanBeFocused = false
74  };
75  int buttonHeight = GUI.IntScale(40);
76  Vector2 buttonSpriteSize = GUIStyle.GetComponentStyle("CrewListToggleButton").GetDefaultSprite().size;
77  int buttonWidth = (int)((buttonHeight / buttonSpriteSize.Y) * buttonSpriteSize.X);
78  Point buttonSize = new Point(buttonWidth, buttonHeight);
79  crewListButton = new GUIButton(new RectTransform(buttonSize, parent: topLeftButtonGroup.RectTransform), style: "CrewListToggleButton")
80  {
81  ToolTip = TextManager.GetWithVariable("hudbutton.crewlist", "[key]", GameSettings.CurrentConfig.KeyMap.KeyBindText(InputType.CrewOrders)),
82  OnClicked = (GUIButton btn, object userdata) =>
83  {
84  if (CrewManager == null) { return false; }
86  return true;
87  }
88  };
89  commandButton = new GUIButton(new RectTransform(buttonSize, parent: topLeftButtonGroup.RectTransform), style: "CommandButton")
90  {
91  ToolTip = TextManager.GetWithVariable("hudbutton.commandinterface", "[key]", GameSettings.CurrentConfig.KeyMap.KeyBindText(InputType.Command)),
92  OnClicked = (button, userData) =>
93  {
94  if (CrewManager == null) { return false; }
96  return true;
97  }
98  };
99  tabMenuButton = new GUIButton(new RectTransform(buttonSize, parent: topLeftButtonGroup.RectTransform), style: "TabMenuButton")
100  {
101  ToolTip = TextManager.GetWithVariable("hudbutton.tabmenu", "[key]", GameSettings.CurrentConfig.KeyMap.KeyBindText(InputType.InfoTab)),
102  OnClicked = (button, userData) => ToggleTabMenu()
103  };
104 
105  talentPointNotification = CreateNotificationIcon(tabMenuButton);
106  eventLogNotification = CreateNotificationIcon(tabMenuButton);
107 
108  // The visibility of the following contents of deathChoiceInfoFrame is controlled by SetRespawnInfo()
109 
110  deathChoiceInfoFrame = new GUIFrame(new RectTransform(new Vector2(0.5f, 1.0f), parent: topLeftButtonGroup.RectTransform)
111  { MaxSize = new Point(HUDLayoutSettings.ButtonAreaTop.Width / 3, int.MaxValue) }, style: null)
112  {
113  Visible = false
114  };
115  respawnInfoText = new GUITextBlock(new RectTransform(new Vector2(0.5f, 1.0f), deathChoiceInfoFrame.RectTransform), "", wrap: true);
116  deathChoiceButtonContainer = new GUILayoutGroup(new RectTransform(new Vector2(0.5f, 1.0f), deathChoiceInfoFrame.RectTransform, Anchor.CenterRight), isHorizontal: true, childAnchor: Anchor.CenterLeft)
117  {
118  AbsoluteSpacing = HUDLayoutSettings.Padding,
119  Stretch = true,
120  Visible = false
121  };
122 
123  takeOverBotButton = new GUIButton(new RectTransform(Vector2.One * 0.9f, deathChoiceButtonContainer.RectTransform, Anchor.Center),
124  TextManager.Get("takeoverbotquestionprompttakeoverbot"), style: "GUIButtonSmall")
125  {
126  OnClicked = (btn, userdata) =>
127  {
128  DeathPrompt.CreateTakeOverBotPanel();
129  return true;
130  }
131  };
132  takeOverBotButton.TextBlock.AutoScaleHorizontal = true;
133 
134  hrManagerButton = new GUIButton(new RectTransform(Vector2.One * 0.9f, deathChoiceButtonContainer.RectTransform, Anchor.Center),
135  TextManager.Get("npctitle.hrmanager"), style: "GUIButtonSmall")
136  {
137  OnClicked = (btn, userdata) =>
138  {
139  if (GameMain.GameSession?.Campaign is { } campaign)
140  {
141  campaign.ShowCampaignUI = true;
142  campaign.CampaignUI?.SelectTab(CampaignMode.InteractionType.Crew);
143  }
144  return true;
145  }
146  };
147  hrManagerButton.TextBlock.AutoScaleHorizontal = true;
148 
149  var questionText =
150  TextManager.GetWithVariable(
151  "respawnquestionprompt", "[percentage]",
152  ((int)Math.Round(RespawnManager.SkillLossPercentageOnImmediateRespawn)).ToString());
153  deathChoiceTickBox = new GUITickBox(new RectTransform(Vector2.One * 0.9f, deathChoiceButtonContainer.RectTransform, Anchor.Center),
154  TextManager.Get("respawnquestionpromptrespawn"))
155  {
156  ToolTip = questionText,
157  OnSelected = (tickbox) =>
158  {
159  GameMain.Client?.SendRespawnPromptResponse(waitForNextRoundRespawn: !tickbox.Selected);
160  return true;
161  }
162  };
163 
164  prevTopLeftButtonsResolution = new Point(GameMain.GraphicsWidth, GameMain.GraphicsHeight);
165  }
166 
167  public void AddToGUIUpdateList()
168  {
169  if (GUI.DisableHUD) { return; }
171  tabMenu?.AddToGUIUpdateList();
172  ObjectiveManager.AddToGUIUpdateList();
173 
174  if ((GameMode is not CampaignMode campaign || (!campaign.ForceMapUI && !campaign.ShowCampaignUI)) &&
175  !CoroutineManager.IsCoroutineRunning("LevelTransition") && !CoroutineManager.IsCoroutineRunning("SubmarineTransition"))
176  {
177  if (topLeftButtonGroup == null ||
178  prevTopLeftButtonsResolution.X != GameMain.GraphicsWidth || prevTopLeftButtonsResolution.Y != GameMain.GraphicsHeight)
179  {
180  CreateTopLeftButtons();
181  }
182  crewListButton.Selected = CrewManager != null && CrewManager.IsCrewMenuOpen;
184  commandButton.Enabled = CrewManager.CanIssueOrders;
185  tabMenuButton.Selected = IsTabMenuOpen;
186  topLeftButtonGroup.AddToGUIUpdateList();
187  }
188 
189  if (GameMain.NetworkMember != null)
190  {
193  }
194 
195  DeathPrompt?.AddToGUIUpdateList();
196  }
197 
198  public static GUIImage CreateNotificationIcon(GUIComponent parent, bool offset = true)
199  {
200  GUIImage indicator = new GUIImage(new RectTransform(new Vector2(0.45f), parent.RectTransform, anchor: Anchor.TopRight, scaleBasis: ScaleBasis.BothWidth), style: "TalentPointNotification")
201  {
202  Visible = false,
203  CanBeFocused = false
204  };
205  Point notificationSize = indicator.RectTransform.NonScaledSize;
206  if (offset)
207  {
208  indicator.RectTransform.AbsoluteOffset = new Point(-(notificationSize.X / 2), -(notificationSize.Y / 2));
209  }
210  return indicator;
211  }
212 
213  public void EnableEventLogNotificationIcon(bool enabled)
214  {
215  if (eventLogNotification == null) { return; }
216  if (!eventLogNotification.Visible && enabled)
217  {
218  eventLogNotification.Pulsate(Vector2.One, Vector2.One * 2, 1.0f);
219  }
220  eventLogNotification.Visible = enabled;
221  }
222 
223  public static void UpdateTalentNotificationIndicator(GUIImage indicator)
224  {
225  if (indicator == null) { return; }
226  indicator.Visible =
227  Character.Controlled?.Info != null &&
229  }
230 
231  public void HUDScaleChanged()
232  {
233  CreateTopLeftButtons();
235  }
236 
237  partial void UpdateProjSpecific(float deltaTime)
238  {
239  if (GUI.DisableHUD) { return; }
240 
241  if (tabMenu == null)
242  {
243  if (PlayerInput.KeyHit(InputType.InfoTab) && !(GUI.KeyboardDispatcher.Subscriber is GUITextBox))
244  {
245  ToggleTabMenu();
246  }
247  }
248  else
249  {
250  tabMenu.Update(deltaTime);
251  if ((PlayerInput.KeyHit(InputType.InfoTab) || PlayerInput.KeyHit(Microsoft.Xna.Framework.Input.Keys.Escape)) &&
252  !(GUI.KeyboardDispatcher.Subscriber is GUITextBox))
253  {
254  ToggleTabMenu();
255  }
256  }
257 
258  UpdateTalentNotificationIndicator(talentPointNotification);
259 
260  if (GameMain.NetworkMember != null)
261  {
262  GameMain.NetLobbyScreen?.CharacterAppearanceCustomizationMenu?.Update();
263  if (GameMain.NetLobbyScreen?.JobSelectionFrame != null)
264  {
265  if (GameMain.NetLobbyScreen.JobSelectionFrame != null && PlayerInput.PrimaryMouseButtonDown() && !GUI.IsMouseOn(GameMain.NetLobbyScreen.JobSelectionFrame))
266  {
267  GameMain.NetLobbyScreen.JobList.Deselect();
268  GameMain.NetLobbyScreen.JobSelectionFrame.Visible = false;
269  }
270  }
271  }
272 
273  HintManager.Update();
274  ObjectiveManager.VideoPlayer.Update();
275  }
276 
282  public void SetRespawnInfo(string text, Color textColor, bool waitForNextRoundRespawn, bool hideButtons = false)
283  {
284  if (topLeftButtonGroup == null) { return; }
285 
286  bool permadeathMode = GameMain.NetworkMember?.ServerSettings is { RespawnMode: RespawnMode.Permadeath };
287  bool ironmanMode = GameMain.NetworkMember is { ServerSettings: { RespawnMode: RespawnMode.Permadeath, IronmanMode: true } };
288 
289  bool hasRespawnOptions;
290  if (permadeathMode)
291  {
292  // In permadeath mode you can (in ironman, must) always at least wait, and possibly buy a new character from HR or take control of a bot
293  hasRespawnOptions = !ironmanMode &&
294  GameMain.Client is GameClient client && (client.CharacterInfo == null || client.CharacterInfo.PermanentlyDead);
295  }
296  else // "classic" respawn modes
297  {
298  //can choose between midround respawning with a penalty or waiting
299  //if we're in a non-outpost level, and either don't have an existing character or have already spawned during the round
300  //(otherwise, e.g. when joining a campaign in which we have an existing character, we can respawn mid-round "for free" and there's no reason to make a choice)
301  hasRespawnOptions = Level.Loaded?.Type != LevelData.LevelType.Outpost &&
302  (GameMain.Client is GameClient client && (client.CharacterInfo == null || client.HasSpawned));
303  }
304 
305  // Are the death choice elements shown at all, at least with the text?
306  deathChoiceInfoFrame.Visible = !text.IsNullOrEmpty() || hasRespawnOptions;
307  if (!deathChoiceInfoFrame.Visible) { return; }
308  respawnInfoText.Text = text;
309  respawnInfoText.TextColor = textColor;
310 
311  // Determine if we even bother considering showing the buttons
313  {
314  // Disable the button container in case it was left visible earlier
315  deathChoiceButtonContainer.Visible = false;
316  return;
317  }
318 
319  deathChoiceButtonContainer.Visible = hasRespawnOptions && !hideButtons;
320  if (deathChoiceButtonContainer.Visible)
321  {
322  hrManagerButton.Visible = AllowHrManagerBotTakeover;
323 
324  if (permadeathMode && ironmanMode)
325  {
326  takeOverBotButton.Visible = false;
327  deathChoiceTickBox.Visible = false;
328  deathChoiceTickBox.Selected = false;
329  }
330  else
331  {
332  takeOverBotButton.Visible = permadeathMode && GameMain.NetworkMember?.ServerSettings is { AllowBotTakeoverOnPermadeath: true };
333  deathChoiceTickBox.Visible = !permadeathMode;
334  deathChoiceTickBox.Selected = !waitForNextRoundRespawn;
335  }
336  }
337  }
338 
339  public void Draw(SpriteBatch spriteBatch)
340  {
341  GameMode?.Draw(spriteBatch);
342  }
343  }
344 }
Triggers a "conversation popup" with text and support for different branching options.
Responsible for keeping track of the characters in the player crew, saving and loading their orders,...
bool IsCrewMenuOpen
This property stores the preference in settings. Don't use for automatic logic. Use AutoShowCrewList(...
override bool Enabled
Definition: GUIButton.cs:27
GUITextBlock TextBlock
Definition: GUIButton.cs:11
void Pulsate(Vector2 startScale, Vector2 endScale, float duration)
virtual void AddToGUIUpdateList(bool ignoreChildren=false, int order=0)
RectTransform RectTransform
bool AutoScaleHorizontal
When enabled, the text is automatically scaled down to fit the textblock horizontally.
override bool Selected
Definition: GUITickBox.cs:18
static int GraphicsWidth
Definition: GameMain.cs:162
static GameSession?? GameSession
Definition: GameMain.cs:88
static NetLobbyScreen NetLobbyScreen
Definition: GameMain.cs:55
static int GraphicsHeight
Definition: GameMain.cs:168
static NetworkMember NetworkMember
Definition: GameMain.cs:190
static GameClient Client
Definition: GameMain.cs:188
virtual void Draw(SpriteBatch spriteBatch)
void SetRespawnInfo(string text, Color textColor, bool waitForNextRoundRespawn, bool hideButtons=false)
This method controls the content and visibility logic of the respawn-related GUI elements at the top ...
static GUIImage CreateNotificationIcon(GUIComponent parent, bool offset=true)
static bool IsLoadedFriendlyOutpost
Is there a loaded level set, and is it a friendly outpost (FriendlyNPC or Team1). Does not take reput...
CharacterInfo.AppearanceCustomizationMenu CharacterAppearanceCustomizationMenu
static float SkillLossPercentageOnImmediateRespawn
How much more the skills drop towards the job's default skill levels when dying, in addition to Skill...
Point AbsoluteOffset
Absolute in pixels but relative to the anchor point. Calculated away from the anchor point,...
RectTransform?? Parent
Point NonScaledSize
Size before scale multiplications.
void Update(float deltaTime)
Definition: TabMenu.cs:177
void AddToGUIUpdateList()
Definition: TabMenu.cs:249