Client LuaCsForBarotrauma
RoundSummary.cs
1 using Microsoft.Xna.Framework;
2 using Microsoft.Xna.Framework.Graphics;
3 using System;
4 using System.Collections.Generic;
5 using System.Collections.Immutable;
6 using System.Globalization;
7 using System.Linq;
8 
9 namespace Barotrauma
10 {
12  {
13  private float crewListAnimDelay = 0.25f;
14  private float missionIconAnimDelay;
15 
16  private const float jobColumnWidthPercentage = 0.11f;
17  private const float characterColumnWidthPercentage = 0.44f;
18  private const float statusColumnWidthPercentage = 0.45f;
19 
20  private int jobColumnWidth, characterColumnWidth, statusColumnWidth;
21 
22  private readonly List<Mission> selectedMissions;
23  private readonly Location startLocation, endLocation;
24 
25  private readonly GameMode gameMode;
26 
27  private readonly Dictionary<Identifier, float> initialFactionReputations = new Dictionary<Identifier, float>();
28 
29  public GUILayoutGroup ButtonArea { get; private set; }
30 
31  public GUIButton ContinueButton { get; private set; }
32 
33  public GUIComponent Frame { get; private set; }
34 
35  public RoundSummary(GameMode gameMode, IEnumerable<Mission> selectedMissions, Location startLocation, Location endLocation)
36  {
37  this.gameMode = gameMode;
38  this.selectedMissions = selectedMissions.ToList();
39  this.startLocation = startLocation;
40  this.endLocation = endLocation;
41  if (gameMode is CampaignMode campaignMode)
42  {
43  foreach (Faction faction in campaignMode.Factions)
44  {
45  initialFactionReputations.Add(faction.Prefab.Identifier, faction.Reputation.Value);
46  }
47  }
48  }
49 
50  public GUIFrame CreateSummaryFrame(GameSession gameSession, string endMessage, CampaignMode.TransitionType transitionType = CampaignMode.TransitionType.None, TraitorManager.TraitorResults? traitorResults = null)
51  {
52  bool singleplayer = GameMain.NetworkMember == null;
53  bool gameOver =
54  gameSession.GameMode.IsSinglePlayer ?
55  gameSession.CrewManager.GetCharacters().All(c => c.IsDead || c.IsIncapacitated) :
56  gameSession.CrewManager.GetCharacters().All(c => c.IsDead || c.IsIncapacitated || c.IsBot);
57 
58  if (!singleplayer)
59  {
60  SoundPlayer.OverrideMusicType = (gameOver ? "crewdead" : "endround").ToIdentifier();
61  SoundPlayer.OverrideMusicDuration = 18.0f;
62  }
63 
64  GUIFrame background = new GUIFrame(new RectTransform(GUI.Canvas.RelativeSize, GUI.Canvas, Anchor.Center), style: "GUIBackgroundBlocker")
65  {
66  UserData = this
67  };
68 
69  List<GUIComponent> rightPanels = new List<GUIComponent>();
70 
71  int minWidth = 400, minHeight = 350;
72  int padding = GUI.IntScale(25.0f);
73 
74  //crew panel -------------------------------------------------------------------------------
75 
76  GUIFrame crewFrame = new GUIFrame(new RectTransform(new Vector2(0.35f, 0.4f), background.RectTransform, Anchor.TopCenter, minSize: new Point(minWidth, minHeight)));
77  GUIFrame crewFrameInner = new GUIFrame(new RectTransform(new Point(crewFrame.Rect.Width - padding * 2, crewFrame.Rect.Height - padding * 2), crewFrame.RectTransform, Anchor.Center), style: "InnerFrame");
78 
79  var crewContent = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.95f), crewFrameInner.RectTransform, Anchor.Center))
80  {
81  Stretch = true
82  };
83 
84  var crewHeader = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), crewContent.RectTransform),
85  TextManager.Get("crew"), textAlignment: Alignment.TopLeft, font: GUIStyle.SubHeadingFont);
86  crewHeader.RectTransform.MinSize = new Point(0, GUI.IntScale(crewHeader.Rect.Height * 2.0f));
87 
88  var crewList = CreateCrewList(crewContent, gameSession.CrewManager.GetCharacterInfos().Where(c => c.TeamID != CharacterTeamType.Team2), traitorResults);
89  if (traitorResults != null && traitorResults.Value.VotedAsTraitorClientSessionId > 0)
90  {
91  var traitorInfoPanel = CreateTraitorInfoPanel(crewList.Content, traitorResults.Value, crewListAnimDelay);
92  traitorInfoPanel.RectTransform.SetAsFirstChild();
93  var spacing = new GUIFrame(new RectTransform(new Point(0, GUI.IntScale(20)), crewList.Content.RectTransform), style: null);
94  spacing.RectTransform.RepositionChildInHierarchy(1);
95  }
96 
97  //another crew frame for the 2nd team in combat missions
98  if (gameSession.Missions.Any(m => m is CombatMission))
99  {
100  crewHeader.Text = CombatMission.GetTeamName(CharacterTeamType.Team1);
101  GUIFrame crewFrame2 = new GUIFrame(new RectTransform(crewFrame.RectTransform.RelativeSize, background.RectTransform, Anchor.TopCenter, minSize: new Point(minWidth, minHeight)));
102  rightPanels.Add(crewFrame2);
103  GUIFrame crewFrameInner2 = new GUIFrame(new RectTransform(new Point(crewFrame2.Rect.Width - padding * 2, crewFrame2.Rect.Height - padding * 2), crewFrame2.RectTransform, Anchor.Center), style: "InnerFrame");
104  var crewContent2 = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.95f), crewFrameInner2.RectTransform, Anchor.Center))
105  {
106  Stretch = true
107  };
108  var crewHeader2 = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), crewContent2.RectTransform),
109  CombatMission.GetTeamName(CharacterTeamType.Team2), textAlignment: Alignment.TopLeft, font: GUIStyle.SubHeadingFont);
110  crewHeader2.RectTransform.MinSize = new Point(0, GUI.IntScale(crewHeader2.Rect.Height * 2.0f));
111  CreateCrewList(crewContent2, gameSession.CrewManager.GetCharacterInfos().Where(c => c.TeamID == CharacterTeamType.Team2), traitorResults);
112  }
113 
114  //header -------------------------------------------------------------------------------
115 
116  LocalizedString headerText = GetHeaderText(gameOver, transitionType);
117  GUITextBlock headerTextBlock = null;
118  if (!headerText.IsNullOrEmpty())
119  {
120  headerTextBlock = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.5f), crewFrame.RectTransform, Anchor.TopLeft, Pivot.BottomLeft),
121  headerText, textAlignment: Alignment.BottomLeft, font: GUIStyle.LargeFont, wrap: true);
122  }
123 
124  //reputation panel -------------------------------------------------------------------------------
125 
126  var campaignMode = gameMode as CampaignMode;
127  if (campaignMode != null)
128  {
129  GUIFrame reputationframe = new GUIFrame(new RectTransform(crewFrame.RectTransform.RelativeSize, background.RectTransform, Anchor.TopCenter, minSize: crewFrame.RectTransform.MinSize));
130  rightPanels.Add(reputationframe);
131  GUIFrame reputationframeInner = new GUIFrame(new RectTransform(new Point(reputationframe.Rect.Width - padding * 2, reputationframe.Rect.Height - padding * 2), reputationframe.RectTransform, Anchor.Center), style: "InnerFrame");
132 
133  var reputationContent = new GUILayoutGroup(new RectTransform(new Vector2(0.98f, 0.95f), reputationframeInner.RectTransform, Anchor.Center))
134  {
135  Stretch = true
136  };
137 
138  var reputationHeader = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), reputationContent.RectTransform),
139  TextManager.Get("reputation"), textAlignment: Alignment.TopLeft, font: GUIStyle.SubHeadingFont);
140  reputationHeader.RectTransform.MinSize = new Point(0, GUI.IntScale(reputationHeader.Rect.Height * 2.0f));
141 
142  CreateReputationInfoPanel(reputationContent, campaignMode);
143  }
144 
145  //mission panel -------------------------------------------------------------------------------
146 
147  GUIFrame missionframe = new GUIFrame(new RectTransform(new Vector2(0.5f, 0.4f), background.RectTransform, Anchor.TopCenter, minSize: new Point(minWidth, minHeight / 4)));
148  GUILayoutGroup missionFrameContent = new GUILayoutGroup(new RectTransform(new Point(missionframe.Rect.Width - padding * 2, missionframe.Rect.Height - padding * 2), missionframe.RectTransform, Anchor.Center))
149  {
150  Stretch = true,
151  RelativeSpacing = 0.03f
152  };
153  GUIFrame missionframeInner = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.9f), missionFrameContent.RectTransform, Anchor.Center), style: "InnerFrame");
154 
155  var missionContent = new GUILayoutGroup(new RectTransform(new Vector2(0.98f, 0.93f), missionframeInner.RectTransform, Anchor.Center))
156  {
157  Stretch = true
158  };
159 
160  List<Mission> missionsToDisplay = new List<Mission>(selectedMissions.Where(m => m.Prefab.ShowInMenus));
161  if (startLocation != null)
162  {
163  foreach (Mission mission in startLocation.SelectedMissions)
164  {
165  if (missionsToDisplay.Contains(mission)) { continue; }
166  if (!mission.Prefab.ShowInMenus) { continue; }
167  if (mission.Locations[0] == mission.Locations[1] ||
168  mission.Locations.Contains(campaignMode?.Map.SelectedLocation))
169  {
170  missionsToDisplay.Add(mission);
171  }
172  }
173  }
174 
175  GUIListBox missionList = new GUIListBox(new RectTransform(Vector2.One, missionContent.RectTransform, Anchor.Center))
176  {
177  Spacing = GUI.IntScale(15)
178  };
179  missionList.ContentBackground.Color = Color.Transparent;
180 
181  ButtonArea = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.1f), missionFrameContent.RectTransform, Anchor.BottomCenter), isHorizontal: true, childAnchor: Anchor.BottomRight)
182  {
183  RelativeSpacing = 0.025f
184  };
185 
186  missionFrameContent.Recalculate();
187  missionContent.Recalculate();
188 
189  if (!string.IsNullOrWhiteSpace(endMessage))
190  {
191  var endText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), missionList.Content.RectTransform),
192  TextManager.GetServerMessage(endMessage), wrap: true)
193  {
194  CanBeFocused = false
195  };
196  }
197 
198  float animDelay = missionIconAnimDelay;
199  foreach (Mission mission in missionsToDisplay)
200  {
201  var textContent = new List<LocalizedString>();
202 
203  if (selectedMissions.Contains(mission))
204  {
205  textContent.Add(mission.Completed ? mission.SuccessMessage : mission.FailureMessage);
206 
207  var repText = mission.GetReputationRewardText();
208  if (!repText.IsNullOrEmpty()) { textContent.Add(repText); }
209 
210  int totalReward = mission.GetFinalReward(Submarine.MainSub);
211  if (totalReward > 0)
212  {
213  textContent.Add(mission.GetMissionRewardText(Submarine.MainSub));
214  if (GameMain.IsMultiplayer && Character.Controlled is { } controlled && mission.Completed)
215  {
216  var (share, percentage, _) = Mission.GetRewardShare(controlled.Wallet.RewardDistribution, GameSession.GetSessionCrewCharacters(CharacterType.Player).Where(c => c != controlled), Option<int>.Some(totalReward));
217  if (share > 0)
218  {
219  string shareFormatted = string.Format(CultureInfo.InvariantCulture, "{0:N0}", share);
220  RichString yourShareString = TextManager.GetWithVariables("crewwallet.missionreward.get", ("[money]", $"{shareFormatted}"), ("[share]", $"{percentage}"));
221  textContent.Add(yourShareString);
222  }
223  }
224  }
225  }
226  else
227  {
228  var repText = mission.GetReputationRewardText();
229  if (!repText.IsNullOrEmpty()) { textContent.Add(repText); }
230  textContent.Add(mission.GetMissionRewardText(Submarine.MainSub));
231  textContent.Add(mission.Description);
232  textContent.AddRange(mission.ShownMessages);
233  }
234 
236  missionList.Content,
237  mission.Name,
238  textContent,
239  mission.Difficulty ?? 0,
240  mission.Prefab.Icon, mission.Prefab.IconColor,
241  out GUIImage missionIcon);
242 
243  if (selectedMissions.Contains(mission))
244  {
245  UpdateMissionStateIcon(mission.Completed, missionIcon, animDelay);
246  animDelay += 0.25f;
247  }
248  }
249 
250  if (!missionsToDisplay.Any())
251  {
252  var missionContentHorizontal = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.4f), missionList.Content.RectTransform), childAnchor: Anchor.TopLeft, isHorizontal: true)
253  {
254  RelativeSpacing = 0.025f,
255  Stretch = true,
256  CanBeFocused = true
257  };
258  GUIImage missionIcon = new GUIImage(new RectTransform(new Point(missionContentHorizontal.Rect.Height), missionContentHorizontal.RectTransform), style: "NoMissionIcon", scaleToFit: true);
259  new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), missionContentHorizontal.RectTransform),
260  TextManager.Get("nomission"), font: GUIStyle.LargeFont);
261  }
262 
263  gameSession?.EventManager?.EventLog?.CreateEventLogUI(missionList.Content, traitorResults);
264 
265  AddSeparators(missionList.Content);
266 
267  ContinueButton = new GUIButton(new RectTransform(new Vector2(0.25f, 1.0f), ButtonArea.RectTransform), TextManager.Get("Close"));
270 
271  missionFrameContent.Recalculate();
272 
273  // set layout -------------------------------------------------------------------
274 
275  int panelSpacing = GUI.IntScale(20);
276  int totalHeight = crewFrame.Rect.Height + panelSpacing + missionframe.Rect.Height;
277  int totalWidth = crewFrame.Rect.Width;
278 
279  crewFrame.RectTransform.AbsoluteOffset = new Point(0, (GameMain.GraphicsHeight - totalHeight) / 2);
280  missionframe.RectTransform.AbsoluteOffset = new Point(0, crewFrame.Rect.Bottom + panelSpacing);
281 
282  if (rightPanels.Any())
283  {
284  totalWidth = crewFrame.Rect.Width * 2 + panelSpacing;
285  if (headerTextBlock != null)
286  {
287  headerTextBlock.RectTransform.MinSize = new Point(totalWidth, 0);
288  }
289  crewFrame.RectTransform.AbsoluteOffset = new Point(-(crewFrame.Rect.Width + panelSpacing) / 2, crewFrame.RectTransform.AbsoluteOffset.Y);
290  foreach (var rightPanel in rightPanels)
291  {
292  rightPanel.RectTransform.AbsoluteOffset = new Point((rightPanel.Rect.Width + panelSpacing) / 2, crewFrame.RectTransform.AbsoluteOffset.Y);
293  }
294  }
295 
296  Frame = background;
297  return background;
298  }
299 
300  public void CreateReputationInfoPanel(GUIComponent parent, CampaignMode campaignMode)
301  {
302  GUIListBox reputationList = new GUIListBox(new RectTransform(Vector2.One, parent.RectTransform));
303  reputationList.ContentBackground.Color = Color.Transparent;
304 
305  foreach (Faction faction in campaignMode.Factions.OrderBy(f => f.Prefab.MenuOrder).ThenBy(f => f.Prefab.Name))
306  {
307  float initialReputation = faction.Reputation.Value;
308  if (!initialFactionReputations.TryGetValue(faction.Prefab.Identifier, out initialReputation))
309  {
310  DebugConsole.AddWarning($"Could not determine reputation change for faction \"{faction.Prefab.Name}\" (faction was not present at the start of the round).");
311  }
312  var factionFrame = CreateReputationElement(
313  reputationList.Content,
314  faction.Prefab.Name,
315  faction.Reputation, initialReputation,
316  faction.Prefab.ShortDescription, faction.Prefab.Description,
317  faction.Prefab.Icon, faction.Prefab.BackgroundPortrait, faction.Prefab.IconColor);
318  CreatePathUnlockElement(factionFrame, faction, null);
319  }
320 
321  float maxDescriptionHeight = 0.0f;
322  foreach (GUIComponent child in reputationList.Content.Children)
323  {
324  var descriptionElement = child.FindChild("description", recursive: true) as GUITextBlock;
325  float descriptionHeight = descriptionElement.TextSize.Y * 1.1f;
326  if (child.FindChild("unlockinfo") is GUIComponent unlockInfoComponent)
327  {
328  descriptionHeight += 1.25f * unlockInfoComponent.Rect.Height;
329  }
330  maxDescriptionHeight = Math.Max(maxDescriptionHeight, descriptionHeight);
331  }
332  foreach (GUIComponent child in reputationList.Content.Children)
333  {
334  var headerElement = child.FindChild("header", recursive: true) as GUITextBlock;
335  var descriptionElement = child.FindChild("description", recursive: true) as GUITextBlock;
336  descriptionElement.RectTransform.NonScaledSize = new Point(descriptionElement.Rect.Width, (int)maxDescriptionHeight);
337  descriptionElement.RectTransform.IsFixedSize = true;
338  child.RectTransform.NonScaledSize = new Point(child.Rect.Width, headerElement.Rect.Height + descriptionElement.RectTransform.Parent.Children.Sum(c => c.Rect.Height + ((GUILayoutGroup)descriptionElement.Parent).AbsoluteSpacing));
339  }
340 
341  void CreatePathUnlockElement(GUIComponent reputationFrame, Faction faction, Location location)
342  {
343  if (GameMain.GameSession?.Campaign?.Map == null) { return; }
344 
345  IEnumerable<LocationConnection> connectionsBetweenBiomes =
346  GameMain.GameSession.Campaign.Map.Connections.Where(c => c.Locations[0].Biome != c.Locations[1].Biome);
347 
348  foreach (LocationConnection connection in connectionsBetweenBiomes)
349  {
350  if (!connection.Locked || (!connection.Locations[0].Discovered && !connection.Locations[1].Discovered)) { continue; }
351 
352  //don't show the "reputation required to unlock" text if another connection between the biomes has already been unlocked
353  if (connectionsBetweenBiomes.Where(c => !c.Locked).Any(c =>
354  (c.Locations[0].Biome == connection.Locations[0].Biome && c.Locations[1].Biome == connection.Locations[1].Biome) ||
355  (c.Locations[1].Biome == connection.Locations[0].Biome && c.Locations[0].Biome == connection.Locations[1].Biome)))
356  {
357  continue;
358  }
359 
360  var gateLocation = connection.Locations[0].IsGateBetweenBiomes ? connection.Locations[0] : connection.Locations[1];
361  var unlockEvent = EventPrefab.GetUnlockPathEvent(gateLocation.LevelData.Biome.Identifier, gateLocation.Faction);
362 
363  if (unlockEvent == null) { continue; }
364  if (unlockEvent.Faction.IsEmpty)
365  {
366  if (location == null || gateLocation != location) { continue; }
367  }
368  else
369  {
370  if (faction == null || faction.Prefab.Identifier != unlockEvent.Faction) { continue; }
371  }
372 
373  if (unlockEvent != null)
374  {
375  Reputation unlockReputation = gateLocation.Reputation;
376  Faction unlockFaction = null;
377  if (!unlockEvent.Faction.IsEmpty)
378  {
379  unlockFaction = GameMain.GameSession.Campaign.Factions.Find(f => f.Prefab.Identifier == unlockEvent.Faction);
380  unlockReputation = unlockFaction?.Reputation;
381  }
382  float normalizedUnlockReputation = MathUtils.InverseLerp(unlockReputation.MinReputation, unlockReputation.MaxReputation, unlockEvent.UnlockPathReputation);
383  RichString unlockText = RichString.Rich(TextManager.GetWithVariables(
384  "lockedpathreputationrequirement",
385  ("[reputation]", Reputation.GetFormattedReputationText(normalizedUnlockReputation, unlockEvent.UnlockPathReputation, addColorTags: true)),
386  ("[biomename]", $"‖color:gui.orange‖{connection.LevelData.Biome.DisplayName}‖end‖")));
387  var unlockInfoPanel = new GUITextBlock(new RectTransform(new Vector2(0.8f, 0.0f), reputationFrame.RectTransform, Anchor.BottomCenter) { MinSize = new Point(0, GUI.IntScale(30)), AbsoluteOffset = new Point(0, GUI.IntScale(3)) },
388  unlockText, style: "GUIButtonRound", textAlignment: Alignment.Center, textColor: GUIStyle.TextColorNormal);
389  unlockInfoPanel.Color = Color.Lerp(unlockInfoPanel.Color, Color.Black, 0.8f);
390  unlockInfoPanel.UserData = "unlockinfo";
391  if (unlockInfoPanel.TextSize.X > unlockInfoPanel.Rect.Width * 0.7f)
392  {
393  unlockInfoPanel.Font = GUIStyle.SmallFont;
394  }
395  }
396  }
397  }
398  }
399 
400  private static GUIComponent CreateTraitorInfoPanel(GUIComponent parent, TraitorManager.TraitorResults traitorResults, float iconAnimDelay)
401  {
402  var traitorCharacter = traitorResults.GetTraitorClient()?.Character;
403 
404  string resultTag =
405  traitorResults.VotedCorrectTraitor ?
406  traitorResults.ObjectiveSuccessful ? "traitor.blameresult.correct.objectivesuccessful" : "traitor.blameresult.correct.objectivefailed" :
407  "traitor.blameresult.failure";
408 
409  var textContent = new List<LocalizedString>()
410  {
411  TextManager.GetWithVariable("traitor.blameresult", "[name]", traitorCharacter?.Name ?? "unknown"),
412  TextManager.Get(resultTag)
413  };
414 
415  if (traitorResults.MoneyPenalty > 0)
416  {
417  textContent.Add(
418  TextManager.GetWithVariable(
419  "traitor.blameresult.failure.penalty",
420  "[money]",
421  TextManager.FormatCurrency(traitorResults.MoneyPenalty, includeCurrencySymbol: false)));
422  }
423 
424  var icon = GUIStyle.GetComponentStyle("TraitorMissionIcon")?.GetDefaultSprite();
425 
426  var content = CreateMissionEntry(
427  parent,
428  string.Empty,
429  textContent,
430  difficultyIconCount: 0,
431  icon, GUIStyle.Red,
432  out GUIImage missionIcon);
433  UpdateMissionStateIcon(traitorResults.VotedCorrectTraitor, missionIcon, iconAnimDelay);
434  return content;
435  }
436 
437  public static GUIComponent CreateMissionEntry(GUIComponent parent, LocalizedString header, List<LocalizedString> textContent, int difficultyIconCount,
438  Sprite icon, Color iconColor, out GUIImage missionIcon)
439  {
440  int spacing = GUI.IntScale(5);
441 
442  int defaultLineHeight = (int)GUIStyle.Font.MeasureChar('T').Y;
443 
444  //make the icon big enough for header + some lines of text
445  int iconSize = (int)(GUIStyle.SubHeadingFont.MeasureChar('T').Y + defaultLineHeight * 6);
446 
447  GUILayoutGroup content = new GUILayoutGroup(new RectTransform(new Point(parent.Rect.Width, iconSize), parent.RectTransform), isHorizontal: true)
448  {
449  Stretch = true,
450  AbsoluteSpacing = spacing,
451  CanBeFocused = true
452  };
453  if (icon != null)
454  {
455  missionIcon = new GUIImage(new RectTransform(new Point(iconSize), content.RectTransform), icon, null, true)
456  {
457  Color = iconColor,
458  HoverColor = iconColor,
459  SelectedColor = iconColor,
460  CanBeFocused = false
461  };
462  missionIcon.RectTransform.IsFixedSize = true;
463  }
464  else
465  {
466  missionIcon = null;
467  }
468  GUILayoutGroup missionTextGroup = new GUILayoutGroup(new RectTransform(new Vector2(0.744f, 0f), content.RectTransform, Anchor.CenterLeft), childAnchor: Anchor.TopLeft)
469  {
470  AbsoluteSpacing = spacing
471  };
472  content.Recalculate();
473 
474  RichString missionNameString = RichString.Rich(header);
475  List<RichString> contentStrings = new List<RichString>(textContent.Select(t => RichString.Rich(t)));
476 
477  if (!header.IsNullOrEmpty())
478  {
479  var nameText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), missionTextGroup.RectTransform),
480  missionNameString, font: GUIStyle.SubHeadingFont, wrap: true);
481  nameText.RectTransform.MinSize = new Point(0, (int)nameText.TextSize.Y);
482  }
483 
484  GUILayoutGroup difficultyIndicatorGroup = null;
485  if (difficultyIconCount > 0)
486  {
487  difficultyIndicatorGroup = new GUILayoutGroup(new RectTransform(new Point(missionTextGroup.Rect.Width, defaultLineHeight), parent: missionTextGroup.RectTransform), isHorizontal: true, childAnchor: Anchor.CenterLeft)
488  {
489  AbsoluteSpacing = 1
490  };
491  difficultyIndicatorGroup.RectTransform.MinSize = new Point(0, defaultLineHeight);
492  var difficultyColor = Mission.GetDifficultyColor(difficultyIconCount);
493  for (int i = 0; i < difficultyIconCount; i++)
494  {
495  new GUIImage(new RectTransform(Vector2.One, difficultyIndicatorGroup.RectTransform, scaleBasis: ScaleBasis.Smallest), "DifficultyIndicator", scaleToFit: true)
496  {
497  CanBeFocused = false,
498  Color = difficultyColor
499  };
500  }
501  }
502 
503  GUITextBlock firstContentText = null;
504  foreach (var contentString in contentStrings)
505  {
506  var text = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), missionTextGroup.RectTransform), contentString, wrap: true);
507  text.RectTransform.MinSize = new Point(0, (int)text.TextSize.Y);
508  firstContentText ??= text;
509  }
510  if (difficultyIndicatorGroup != null && firstContentText != null)
511  {
512  //make the icons align with the text content
513  difficultyIndicatorGroup.RectTransform.AbsoluteOffset = new Point((int)firstContentText.Padding.X, 0);
514  }
515  missionTextGroup.RectTransform.MinSize =
516  new Point(0, missionTextGroup.Children.Sum(c => c.Rect.Height + missionTextGroup.AbsoluteSpacing) - missionTextGroup.AbsoluteSpacing);
517  missionTextGroup.Recalculate();
518  content.RectTransform.MinSize = new Point(0, Math.Max(missionTextGroup.Rect.Height, iconSize));
519 
520  return content;
521  }
522 
523  public static void AddSeparators(GUIComponent container)
524  {
525  var children = container.Children.ToList();
526  if (children.Count < 2) { return; }
527 
528  var lastChild = children.Last();
529  foreach (var child in children)
530  {
531  if (child != lastChild)
532  {
533  var separator = new GUIFrame(new RectTransform(new Vector2(0.5f, 0.1f), container.RectTransform), style: "HorizontalLine");
534  separator.RectTransform.RepositionChildInHierarchy(container.GetChildIndex(child) + 1);
535  }
536  }
537  }
538 
539  public static void UpdateMissionStateIcon(bool success, GUIImage missionIcon, float delay = 0.5f)
540  {
541  if (missionIcon == null) { return; }
542  string style = success ? "MissionCompletedIcon" : "MissionFailedIcon";
543  GUIImage stateIcon = missionIcon.GetChild<GUIImage>();
544  if (string.IsNullOrEmpty(style))
545  {
546  if (stateIcon != null)
547  {
548  stateIcon.Visible = false;
549  }
550  }
551  else
552  {
553  bool wasVisible = stateIcon is { Visible: true };
554  stateIcon ??= new GUIImage(new RectTransform(Vector2.One, missionIcon.RectTransform, Anchor.Center), style, scaleToFit: true);
555  stateIcon.Visible = true;
556  if (!wasVisible)
557  {
558  stateIcon.FadeIn(delay, 0.15f);
559  stateIcon.Pulsate(Vector2.One, Vector2.One * 1.5f, 1.0f + delay);
560  }
561  }
562  }
563 
564 
565  private LocalizedString GetHeaderText(bool gameOver, CampaignMode.TransitionType transitionType)
566  {
567  LocalizedString locationName = Submarine.MainSub is { AtEndExit: true } ? endLocation?.DisplayName : startLocation?.DisplayName;
568 
569  string textTag;
570  if (gameOver)
571  {
572  textTag = "RoundSummaryGameOver";
573  }
574  else
575  {
576  switch (transitionType)
577  {
578  case CampaignMode.TransitionType.LeaveLocation:
579  locationName = startLocation?.DisplayName;
580  textTag = "RoundSummaryLeaving";
581  break;
582  case CampaignMode.TransitionType.ProgressToNextLocation:
583  locationName = endLocation?.DisplayName;
584  textTag = "RoundSummaryProgress";
585  break;
586  case CampaignMode.TransitionType.ProgressToNextEmptyLocation:
587  locationName = endLocation?.DisplayName;
588  textTag = "RoundSummaryProgressToEmptyLocation";
589  break;
590  case CampaignMode.TransitionType.ReturnToPreviousLocation:
591  locationName = startLocation?.DisplayName;
592  textTag = "RoundSummaryReturn";
593  break;
594  case CampaignMode.TransitionType.ReturnToPreviousEmptyLocation:
595  locationName = startLocation?.DisplayName;
596  textTag = "RoundSummaryReturnToEmptyLocation";
597  break;
598  default:
599  textTag = Submarine.MainSub.AtEndExit ? "RoundSummaryProgress" : "RoundSummaryReturn";
600  break;
601  }
602  }
603 
604  if (startLocation?.Biome != null && startLocation.Biome.IsEndBiome)
605  {
606  locationName ??= startLocation.DisplayName;
607  }
608 
609  if (textTag == null) { return ""; }
610 
611  if (locationName == null)
612  {
613  DebugConsole.ThrowError($"Error while creating round summary: could not determine destination location. Start location: {startLocation?.DisplayName ?? "null"}, end location: {endLocation?.DisplayName ?? "null"}");
614  locationName = "[UNKNOWN]";
615  }
616 
617  LocalizedString subName = string.Empty;
618  SubmarineInfo currentOrPending = SubmarineSelection.CurrentOrPendingSubmarine();
619  if (currentOrPending != null)
620  {
621  subName = currentOrPending.DisplayName;
622  }
623 
624  return TextManager.GetWithVariables(textTag, ("[sub]", subName), ("[location]", locationName));
625  }
626 
627  private GUIListBox CreateCrewList(GUIComponent parent, IEnumerable<CharacterInfo> characterInfos, TraitorManager.TraitorResults? traitorResults)
628  {
629  var headerFrame = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.0f), parent.RectTransform, Anchor.TopCenter, minSize: new Point(0, (int)(30 * GUI.Scale))) { }, isHorizontal: true)
630  {
631  AbsoluteSpacing = 2
632  };
633  GUIButton jobButton = new GUIButton(new RectTransform(new Vector2(0f, 1f), headerFrame.RectTransform), TextManager.Get("tabmenu.job"), style: "GUIButtonSmallFreeScale");
634  GUIButton characterButton = new GUIButton(new RectTransform(new Vector2(0f, 1f), headerFrame.RectTransform), TextManager.Get("name"), style: "GUIButtonSmallFreeScale");
635  GUIButton statusButton = new GUIButton(new RectTransform(new Vector2(0f, 1f), headerFrame.RectTransform), TextManager.Get("label.statuslabel"), style: "GUIButtonSmallFreeScale");
636 
637  float sizeMultiplier = 1.0f;
638  //sizeMultiplier = (headerFrame.Rect.Width - headerFrame.AbsoluteSpacing * (headerFrame.CountChildren - 1)) / (float)headerFrame.Rect.Width;
639 
640  jobButton.RectTransform.RelativeSize = new Vector2(jobColumnWidthPercentage * sizeMultiplier, 1f);
641  characterButton.RectTransform.RelativeSize = new Vector2(characterColumnWidthPercentage * sizeMultiplier, 1f);
642  statusButton.RectTransform.RelativeSize = new Vector2(statusColumnWidthPercentage * sizeMultiplier, 1f);
643 
644  jobButton.TextBlock.Font = characterButton.TextBlock.Font = statusButton.TextBlock.Font = GUIStyle.HotkeyFont;
645  jobButton.CanBeFocused = characterButton.CanBeFocused = statusButton.CanBeFocused = false;
646  jobButton.TextBlock.ForceUpperCase = characterButton.TextBlock.ForceUpperCase = statusButton.ForceUpperCase = ForceUpperCase.Yes;
647 
648  jobColumnWidth = jobButton.Rect.Width;
649  characterColumnWidth = characterButton.Rect.Width;
650  statusColumnWidth = statusButton.Rect.Width;
651 
652  GUIListBox crewList = new GUIListBox(new RectTransform(Vector2.One, parent.RectTransform))
653  {
654  Padding = new Vector4(4, 10, 0, 0) * GUI.Scale,
655  AutoHideScrollBar = false
656  };
657  crewList.ContentBackground.Color = Color.Transparent;
658 
659  headerFrame.RectTransform.RelativeSize -= new Vector2(crewList.ScrollBar.RectTransform.RelativeSize.X, 0.0f);
660 
661  float delay = crewListAnimDelay;
662  foreach (CharacterInfo characterInfo in characterInfos)
663  {
664  if (characterInfo == null) { continue; }
665  CreateCharacterElement(characterInfo, crewList, traitorResults, delay);
666  delay += crewListAnimDelay;
667  }
668  missionIconAnimDelay = delay;
669 
670  return crewList;
671  }
672 
673  private void CreateCharacterElement(CharacterInfo characterInfo, GUIListBox listBox, TraitorManager.TraitorResults? traitorResults, float animDelay)
674  {
675  GUIFrame frame = new GUIFrame(new RectTransform(new Point(listBox.Content.Rect.Width, GUI.IntScale(45)), listBox.Content.RectTransform), style: "ListBoxElement")
676  {
677  CanBeFocused = false,
678  UserData = characterInfo,
679  Color = (Character.Controlled?.Info == characterInfo) ? TabMenu.OwnCharacterBGColor : Color.Transparent
680  };
681 
682  var paddedFrame = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.9f), frame.RectTransform, Anchor.Center), isHorizontal: true)
683  {
684  AbsoluteSpacing = 2,
685  Stretch = true
686  };
687 
688  new GUICustomComponent(new RectTransform(new Point(jobColumnWidth, paddedFrame.Rect.Height), paddedFrame.RectTransform, Anchor.Center), onDraw: (sb, component) => characterInfo.DrawJobIcon(sb, component.Rect))
689  {
690  ToolTip = characterInfo.Job.Name ?? "",
691  HoverColor = Color.White,
692  SelectedColor = Color.White
693  };
694 
695  GUITextBlock characterNameBlock = new GUITextBlock(new RectTransform(new Point(characterColumnWidth, paddedFrame.Rect.Height), paddedFrame.RectTransform),
696  ToolBox.LimitString(characterInfo.Name, GUIStyle.Font, characterColumnWidth), textAlignment: Alignment.Center, textColor: characterInfo.Job.Prefab.UIColor);
697 
698  LocalizedString statusText = TextManager.Get("StatusOK");
699  Color statusColor = GUIStyle.Green;
700 
701  Character character = characterInfo.Character;
702  if (character == null || character.IsDead)
703  {
704  if (character == null && characterInfo.IsNewHire && characterInfo.CauseOfDeath == null)
705  {
706  statusText = TextManager.Get("CampaignCrew.NewHire");
707  statusColor = GUIStyle.Blue;
708  }
709  else if (characterInfo.CauseOfDeath == null)
710  {
711  statusText = TextManager.Get("CauseOfDeathDescription.Unknown");
712  statusColor = Color.DarkRed;
713  }
714  else if (characterInfo.CauseOfDeath.Type == CauseOfDeathType.Affliction && characterInfo.CauseOfDeath.Affliction == null)
715  {
716  string errorMsg = "Character \"[name]\" had an invalid cause of death (the type of the cause of death was Affliction, but affliction was not specified).";
717  DebugConsole.ThrowError(errorMsg.Replace("[name]", characterInfo.Name));
718  GameAnalyticsManager.AddErrorEventOnce("RoundSummary:InvalidCauseOfDeath", GameAnalyticsManager.ErrorSeverity.Error, errorMsg.Replace("[name]", characterInfo.SpeciesName.Value));
719  statusText = TextManager.Get("CauseOfDeathDescription.Unknown");
720  statusColor = GUIStyle.Red;
721  }
722  else
723  {
724  statusText = characterInfo.CauseOfDeath.Type == CauseOfDeathType.Affliction ?
725  characterInfo.CauseOfDeath.Affliction.CauseOfDeathDescription :
726  TextManager.Get("CauseOfDeathDescription." + characterInfo.CauseOfDeath.Type.ToString());
727  statusColor = Color.DarkRed;
728  }
729  }
730  else
731  {
732  if (character.IsUnconscious)
733  {
734  statusText = TextManager.Get("Unconscious");
735  statusColor = Color.DarkOrange;
736  }
737  else if (character.Vitality / character.MaxVitality < 0.8f)
738  {
739  statusText = TextManager.Get("Injured");
740  statusColor = Color.DarkOrange;
741  }
742  }
743 
744  GUITextBlock statusBlock = new GUITextBlock(new RectTransform(new Point(statusColumnWidth, paddedFrame.Rect.Height), paddedFrame.RectTransform),
745  ToolBox.LimitString(statusText.Value, GUIStyle.Font, characterColumnWidth), textAlignment: Alignment.Center, textColor: statusColor);
746 
747  frame.FadeIn(animDelay, 0.15f);
748  foreach (var child in frame.GetAllChildren())
749  {
750  child.FadeIn(animDelay, 0.15f);
751  }
752 
753  if (traitorResults.HasValue && GameMain.NetworkMember != null)
754  {
755  var clientVotedAsTraitor = traitorResults.Value.GetTraitorClient();
756  bool isTraitor = clientVotedAsTraitor != null && clientVotedAsTraitor.Character == character;
757  if (isTraitor)
758  {
759  var img = new GUIImage(new RectTransform(new Point(paddedFrame.Rect.Height), paddedFrame.RectTransform, Anchor.CenterRight), style: "TraitorVoteButton")
760  {
761  IgnoreLayoutGroups = true,
762  ToolTip = TextManager.GetWithVariable("traitor.blameresult", "[name]", characterInfo.Name)
763  };
764  img.FadeIn(1.0f + animDelay, 0.15f);
765  img.Pulsate(Vector2.One, Vector2.One * 1.5f, 1.5f + animDelay);
766  }
767  }
768  }
769 
770  private static GUIFrame CreateReputationElement(GUIComponent parent,
771  LocalizedString name, Reputation reputation, float initialReputation,
772  LocalizedString shortDescription, LocalizedString fullDescription, Sprite icon, Sprite backgroundPortrait, Color iconColor)
773  {
774  var factionFrame = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.1f), parent.RectTransform), style: null);
775 
776  if (backgroundPortrait != null)
777  {
778  new GUICustomComponent(new RectTransform(Vector2.One, factionFrame.RectTransform), onDraw: (sb, customComponent) =>
779  {
780  backgroundPortrait.Draw(sb, customComponent.Rect.Center.ToVector2(), customComponent.Color, backgroundPortrait.size / 2, scale: customComponent.Rect.Width / backgroundPortrait.size.X);
781  })
782  {
783  HideElementsOutsideFrame = true,
784  IgnoreLayoutGroups = true,
785  Color = iconColor * 0.2f
786  };
787  }
788 
789  var factionInfoHorizontal = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.9f), factionFrame.RectTransform, Anchor.Center), childAnchor: Anchor.CenterRight, isHorizontal: true)
790  {
791  AbsoluteSpacing = GUI.IntScale(5),
792  Stretch = true
793  };
794 
795  var factionIcon = new GUIImage(new RectTransform(Vector2.One * 0.7f, factionInfoHorizontal.RectTransform, scaleBasis: ScaleBasis.Smallest), icon, scaleToFit: true)
796  {
797  Color = iconColor
798  };
799  var factionTextContent = new GUILayoutGroup(new RectTransform(Vector2.One, factionInfoHorizontal.RectTransform))
800  {
801  AbsoluteSpacing = GUI.IntScale(10),
802  Stretch = true
803  };
804 
805  factionInfoHorizontal.Recalculate();
806 
807  var header = new GUITextBlock(new RectTransform(new Point(factionTextContent.Rect.Width, GUI.IntScale(40)), factionTextContent.RectTransform),
808  name, font: GUIStyle.SubHeadingFont)
809  {
810  Padding = Vector4.Zero,
811  UserData = "header"
812  };
813  header.RectTransform.IsFixedSize = true;
814 
815  var sliderHolder = new GUILayoutGroup(new RectTransform(new Point((int)(factionTextContent.Rect.Width * 0.8f), GUI.IntScale(20.0f)), factionTextContent.RectTransform),
816  childAnchor: Anchor.CenterLeft, isHorizontal: true)
817  {
818  RelativeSpacing = 0.05f,
819  Stretch = true
820  };
821  sliderHolder.RectTransform.IsFixedSize = true;
822  factionTextContent.Recalculate();
823 
824  new GUICustomComponent(new RectTransform(new Vector2(0.8f, 1.0f), sliderHolder.RectTransform),
825  onDraw: (sb, customComponent) => DrawReputationBar(sb, customComponent.Rect, reputation.NormalizedValue, reputation.MinReputation, reputation.MaxReputation));
826 
827  var reputationText = new GUITextBlock(new RectTransform(new Vector2(0.5f, 1.0f), sliderHolder.RectTransform),
828  string.Empty, textAlignment: Alignment.CenterLeft, font: GUIStyle.SubHeadingFont);
829  SetReputationText(reputationText);
830  reputation?.OnReputationValueChanged.RegisterOverwriteExisting("RefreshRoundSummary".ToIdentifier(), _ =>
831  {
832  SetReputationText(reputationText);
833  });
834 
835  void SetReputationText(GUITextBlock textBlock)
836  {
837  LocalizedString reputationText = Reputation.GetFormattedReputationText(reputation.NormalizedValue, reputation.Value, addColorTags: true);
838  int reputationChange = (int)Math.Round(reputation.Value - initialReputation);
839  if (Math.Abs(reputationChange) > 0)
840  {
841  string changeText = $"{(reputationChange > 0 ? "+" : "") + reputationChange}";
842  string colorStr = XMLExtensions.ToStringHex(reputationChange > 0 ? GUIStyle.Green : GUIStyle.Red);
843  textBlock.Text = RichString.Rich($"{reputationText} (‖color:{colorStr}‖{changeText}‖color:end‖)");
844  }
845  else
846  {
847  textBlock.Text = RichString.Rich(reputationText);
848  }
849  }
850 
851  //spacing
852  new GUIFrame(new RectTransform(new Vector2(1.0f, 0.0f), factionTextContent.RectTransform) { MinSize = new Point(0, GUI.IntScale(5)) }, style: null);
853 
854  var factionDescription = new GUITextBlock(new RectTransform(new Vector2(0.8f, 0.6f), factionTextContent.RectTransform),
855  shortDescription, font: GUIStyle.SmallFont, wrap: true)
856  {
857  UserData = "description",
858  Padding = Vector4.Zero
859  };
860  if (shortDescription != fullDescription && !fullDescription.IsNullOrEmpty())
861  {
862  factionDescription.ToolTip = fullDescription;
863  }
864 
865  //spacing
866  new GUIFrame(new RectTransform(new Vector2(1.0f, 0.0f), factionTextContent.RectTransform) { MinSize = new Point(0, GUI.IntScale(5)) }, style: null);
867 
868  factionInfoHorizontal.Recalculate();
869  factionTextContent.Recalculate();
870 
871  return factionFrame;
872  }
873 
874  public static void DrawReputationBar(SpriteBatch sb, Rectangle rect, float normalizedReputation, float minReputation, float maxReputation)
875  {
876  int segmentWidth = rect.Width / 5;
877  rect.Width = segmentWidth * 5;
878  for (int i = 0; i < 5; i++)
879  {
880  GUI.DrawRectangle(sb, new Rectangle(rect.X + (segmentWidth * i), rect.Y, segmentWidth, rect.Height), Reputation.GetReputationColor(i / 5.0f), isFilled: true);
881  GUI.DrawRectangle(sb, new Rectangle(rect.X + (segmentWidth * i), rect.Y, segmentWidth, rect.Height), GUIStyle.ColorInventoryBackground, isFilled: false);
882  }
883  GUI.DrawRectangle(sb, rect, GUIStyle.ColorInventoryBackground, isFilled: false);
884 
885  GUI.Arrow.Draw(sb, new Vector2(rect.X + rect.Width * normalizedReputation, rect.Y), GUIStyle.ColorInventoryBackground, scale: GUI.Scale, spriteEffect: SpriteEffects.FlipVertically);
886  GUI.Arrow.Draw(sb, new Vector2(rect.X + rect.Width * normalizedReputation, rect.Y), GUIStyle.TextColorNormal, scale: GUI.Scale * 0.8f, spriteEffect: SpriteEffects.FlipVertically);
887 
888  GUI.DrawString(sb, new Vector2(rect.X, rect.Bottom), ((int)minReputation).ToString(), GUIStyle.TextColorNormal, font: GUIStyle.SmallFont);
889  string maxRepText = ((int)maxReputation).ToString();
890  Vector2 textSize = GUIStyle.SmallFont.MeasureString(maxRepText);
891  GUI.DrawString(sb, new Vector2(rect.Right - textSize.X, rect.Bottom), maxRepText, GUIStyle.TextColorNormal, font: GUIStyle.SmallFont);
892  }
893  }
894 }
Biome(ContentXElement element, LevelGenerationParametersFile file)
Definition: Biome.cs:35
static LocalizedString GetTeamName(CharacterTeamType teamID)
IEnumerable< CharacterInfo > GetCharacterInfos()
Note: this only returns AI characters' infos in multiplayer. The infos are used to manage hiring/firi...
static EventPrefab GetUnlockPathEvent(Identifier biomeIdentifier, Faction faction)
Definition: EventPrefab.cs:138
FactionPrefab Prefab
Definition: Factions.cs:18
Reputation Reputation
Definition: Factions.cs:17
GUIComponent GetChild(int index)
Definition: GUIComponent.cs:54
void Pulsate(Vector2 startScale, Vector2 endScale, float duration)
virtual GUIFont Font
GUIComponent FindChild(Func< GUIComponent, bool > predicate, bool recursive=false)
Definition: GUIComponent.cs:95
void FadeIn(float wait, float duration, bool alsoChildren=false)
virtual Rectangle Rect
RectTransform RectTransform
IEnumerable< GUIComponent > Children
Definition: GUIComponent.cs:29
Vector2 MeasureChar(char c)
Definition: GUIPrefab.cs:289
GUIFrame ContentBackground
A frame drawn behind the content of the listbox
Definition: GUIListBox.cs:28
GUIFrame Content
A frame that contains the contents of the listbox. The frame itself is not rendered.
Definition: GUIListBox.cs:33
static GameSession?? GameSession
Definition: GameMain.cs:88
static int GraphicsHeight
Definition: GameMain.cs:168
static bool IsMultiplayer
Definition: GameMain.cs:35
static NetworkMember NetworkMember
Definition: GameMain.cs:190
static ImmutableHashSet< Character > GetSessionCrewCharacters(CharacterType type)
Returns a list of crew characters currently in the game with a given filter.
bool IsGateBetweenBiomes
Definition: Location.cs:512
List< LocationConnection > Connections
virtual RichString GetMissionRewardText(Submarine sub)
Returns the full reward text of the mission (e.g. "Reward: 2,000 mk" or "Reward: 500 mk x 2 (out of m...
int GetFinalReward(Submarine sub)
Get the final reward, taking talent bonuses into account if the mission has concluded and the talents...
Vector2 RelativeSize
Relative to the parent rect.
Point?? MinSize
Min size in pixels. Does not affect scaling.
Point NonScaledSize
Size before scale multiplications.
bool IsFixedSize
If false, the element will resize if the parent is resized (with the children). If true,...
float??????? Value
Definition: Reputation.cs:44
Reputation(CampaignMetadata metadata, Location location, Identifier identifier, int minReputation, int maxReputation, int initialReputation)
Definition: Reputation.cs:128
static Color GetReputationColor(float normalizedValue)
Definition: Reputation.cs:179
LocalizedString GetFormattedReputationText(bool addColorTags=false)
Definition: Reputation.cs:199
static RichString Rich(LocalizedString str, Func< string, string >? postProcess=null)
Definition: RichString.cs:67
GUIFrame CreateSummaryFrame(GameSession gameSession, string endMessage, CampaignMode.TransitionType transitionType=CampaignMode.TransitionType.None, TraitorManager.TraitorResults? traitorResults=null)
Definition: RoundSummary.cs:50
void CreateReputationInfoPanel(GUIComponent parent, CampaignMode campaignMode)
static void DrawReputationBar(SpriteBatch sb, Rectangle rect, float normalizedReputation, float minReputation, float maxReputation)
static void AddSeparators(GUIComponent container)
static void UpdateMissionStateIcon(bool success, GUIImage missionIcon, float delay=0.5f)
GUILayoutGroup ButtonArea
Definition: RoundSummary.cs:29
static GUIComponent CreateMissionEntry(GUIComponent parent, LocalizedString header, List< LocalizedString > textContent, int difficultyIconCount, Sprite icon, Color iconColor, out GUIImage missionIcon)
RoundSummary(GameMode gameMode, IEnumerable< Mission > selectedMissions, Location startLocation, Location endLocation)
Definition: RoundSummary.cs:35
CharacterType
Definition: Enums.cs:685