2 using Microsoft.Xna.Framework;
3 using Microsoft.Xna.Framework.Graphics;
5 using System.Collections.Generic;
6 using System.Collections.Immutable;
7 using System.Globalization;
14 private float crewListAnimDelay = 0.25f;
15 private float missionIconAnimDelay;
17 private const float JobColumnWidthPercentage = 0.1f;
18 private const float CharacterColumnWidthPercentage = 0.4f;
19 private const float StatusColumnWidthPercentage = 0.12f;
20 private const float KillColumnWidthPercentage = 0.1f;
21 private const float DeathColumnWidthPercentage = 0.1f;
23 private int jobColumnWidth, characterColumnWidth, statusColumnWidth, killColumnWidth, deathColumnWidth;
25 private readonly List<Mission> selectedMissions;
26 private readonly
Location startLocation, endLocation;
30 private readonly Dictionary<Identifier, float> initialFactionReputations =
new Dictionary<Identifier, float>();
40 this.gameMode = gameMode;
41 this.selectedMissions = selectedMissions.ToList();
42 this.startLocation = startLocation;
43 this.endLocation = endLocation;
46 foreach (
Faction faction
in campaignMode.Factions)
63 SoundPlayer.OverrideMusicType = (gameOver ?
"crewdead" :
"endround").ToIdentifier();
64 SoundPlayer.OverrideMusicDuration = 18.0f;
72 List<GUIComponent> rightPanels =
new List<GUIComponent>();
74 int minWidth = 400, minHeight = 350;
75 int padding = GUI.IntScale(25.0f);
88 TextManager.Get(
"crew"), textAlignment: Alignment.
TopLeft, font: GUIStyle.SubHeadingFont);
89 crewHeader.RectTransform.MinSize =
new Point(0, GUI.IntScale(crewHeader.Rect.Height * 2.0f));
92 if (traitorResults !=
null && traitorResults.Value.VotedAsTraitorClientSessionId > 0)
94 var traitorInfoPanel = CreateTraitorInfoPanel(crewList.Content, traitorResults.Value, crewListAnimDelay);
95 traitorInfoPanel.RectTransform.SetAsFirstChild();
96 var spacing =
new GUIFrame(
new RectTransform(
new Point(0, GUI.IntScale(20)), crewList.Content.RectTransform), style:
null);
97 spacing.RectTransform.RepositionChildInHierarchy(1);
105 rightPanels.Add(crewFrame2);
113 crewHeader2.RectTransform.MinSize =
new Point(0, GUI.IntScale(crewHeader2.Rect.Height * 2.0f));
131 if (!headerText.IsNullOrEmpty())
134 headerText, textAlignment: Alignment.BottomLeft, font: GUIStyle.LargeFont, wrap:
true);
140 if (campaignMode !=
null)
143 rightPanels.Add(reputationframe);
152 TextManager.Get(
"reputation"), textAlignment: Alignment.
TopLeft, font: GUIStyle.SubHeadingFont);
153 reputationHeader.RectTransform.MinSize =
new Point(0, GUI.IntScale(reputationHeader.Rect.Height * 2.0f));
164 RelativeSpacing = 0.03f
173 List<Mission> missionsToDisplay =
new List<Mission>(selectedMissions.Where(m => m.Prefab.ShowInMenus));
174 if (startLocation !=
null)
176 foreach (
Mission mission
in startLocation.SelectedMissions)
178 if (missionsToDisplay.Contains(mission)) {
continue; }
181 mission.
Locations.Contains(campaignMode?.Map.SelectedLocation))
183 missionsToDisplay.Add(mission);
190 Spacing = GUI.IntScale(15)
196 RelativeSpacing = 0.025f
200 missionContent.Recalculate();
202 if (!
string.IsNullOrWhiteSpace(endMessage))
205 TextManager.GetServerMessage(endMessage), wrap:
true)
211 float animDelay = missionIconAnimDelay;
212 foreach (
Mission mission
in missionsToDisplay)
214 var textContent =
new List<LocalizedString>();
216 if (selectedMissions.Contains(mission))
221 if (!repText.IsNullOrEmpty()) { textContent.Add(repText); }
232 string shareFormatted =
string.Format(CultureInfo.InvariantCulture,
"{0:N0}", share);
233 RichString yourShareString = TextManager.GetWithVariables(
"crewwallet.missionreward.get", (
"[money]", $
"{shareFormatted}"), (
"[share]", $
"{percentage}"));
234 textContent.Add(yourShareString);
242 if (!repText.IsNullOrEmpty()) { textContent.Add(repText); }
256 if (selectedMissions.Contains(mission))
263 if (!missionsToDisplay.Any())
267 RelativeSpacing = 0.025f,
271 GUIImage missionIcon =
new GUIImage(
new RectTransform(
new Point(missionContentHorizontal.Rect.Height), missionContentHorizontal.RectTransform), style:
"NoMissionIcon", scaleToFit:
true);
273 TextManager.Get(
"nomission"), font: GUIStyle.LargeFont);
276 gameSession?.EventManager?.EventLog?.CreateEventLogUI(missionList.Content, traitorResults);
284 missionFrameContent.Recalculate();
288 int panelSpacing = GUI.IntScale(20);
289 int totalHeight = crewFrame.Rect.Height + panelSpacing + missionframe.Rect.Height;
290 int totalWidth = crewFrame.Rect.Width;
293 missionframe.RectTransform.AbsoluteOffset =
new Point(0, crewFrame.Rect.Bottom + panelSpacing);
295 if (rightPanels.Any())
297 totalWidth = crewFrame.Rect.Width * 2 + panelSpacing;
298 if (headerTextBlock !=
null)
300 headerTextBlock.RectTransform.MinSize =
new Point(totalWidth, 0);
302 crewFrame.RectTransform.AbsoluteOffset =
new Point(-(crewFrame.Rect.Width + panelSpacing) / 2, crewFrame.RectTransform.AbsoluteOffset.Y);
303 foreach (var rightPanel
in rightPanels)
305 rightPanel.RectTransform.AbsoluteOffset =
new Point((rightPanel.Rect.Width + panelSpacing) / 2, crewFrame.RectTransform.AbsoluteOffset.Y);
318 foreach (
Faction faction
in campaignMode.Factions.OrderBy(f => f.Prefab.MenuOrder).ThenBy(f => f.Prefab.Name))
321 if (!initialFactionReputations.TryGetValue(faction.
Prefab.Identifier, out initialReputation))
323 DebugConsole.AddWarning($
"Could not determine reputation change for faction \"{faction.Prefab.Name}\" (faction was not present at the start of the round).");
325 var factionFrame = CreateReputationElement(
326 reputationList.Content,
329 faction.
Prefab.ShortDescription, faction.
Prefab.Description,
331 CreatePathUnlockElement(factionFrame, faction,
null);
334 float maxDescriptionHeight = 0.0f;
338 float descriptionHeight = descriptionElement.
TextSize.Y * 1.1f;
341 descriptionHeight += 1.25f * unlockInfoComponent.Rect.Height;
343 maxDescriptionHeight = Math.Max(maxDescriptionHeight, descriptionHeight);
350 descriptionElement.RectTransform.IsFixedSize =
true;
351 child.
RectTransform.
NonScaledSize =
new Point(child.
Rect.Width, headerElement.Rect.Height + descriptionElement.RectTransform.Parent.Children.Sum(c => c.Rect.Height + ((
GUILayoutGroup)descriptionElement.Parent).AbsoluteSpacing));
358 IEnumerable<LocationConnection> connectionsBetweenBiomes =
366 if (connectionsBetweenBiomes.Where(c => !c.Locked).Any(c =>
376 if (unlockEvent ==
null) {
continue; }
377 if (unlockEvent.Faction.IsEmpty)
379 if (location ==
null || gateLocation != location) {
continue; }
383 if (faction ==
null || faction.
Prefab.Identifier != unlockEvent.Faction) {
continue; }
386 if (unlockEvent !=
null)
390 if (!unlockEvent.Faction.IsEmpty)
395 float normalizedUnlockReputation = MathUtils.InverseLerp(unlockReputation.
MinReputation, unlockReputation.
MaxReputation, unlockEvent.UnlockPathReputation);
397 "lockedpathreputationrequirement",
399 (
"[biomename]", $
"‖color:gui.orange‖{connection.LevelData.Biome.DisplayName}‖end‖")));
400 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)) },
401 unlockText, style:
"GUIButtonRound", textAlignment: Alignment.Center, textColor: GUIStyle.TextColorNormal);
402 unlockInfoPanel.Color = Color.Lerp(unlockInfoPanel.Color, Color.Black, 0.8f);
403 unlockInfoPanel.UserData =
"unlockinfo";
404 if (unlockInfoPanel.TextSize.X > unlockInfoPanel.Rect.Width * 0.7f)
406 unlockInfoPanel.Font = GUIStyle.SmallFont;
415 var traitorCharacter = traitorResults.GetTraitorClient()?.Character;
418 traitorResults.VotedCorrectTraitor ?
419 traitorResults.ObjectiveSuccessful ?
"traitor.blameresult.correct.objectivesuccessful" :
"traitor.blameresult.correct.objectivefailed" :
420 "traitor.blameresult.failure";
422 var textContent =
new List<LocalizedString>()
424 TextManager.GetWithVariable(
"traitor.blameresult",
"[name]", traitorCharacter?.Name ??
"unknown"),
425 TextManager.Get(resultTag)
428 if (traitorResults.MoneyPenalty > 0)
431 TextManager.GetWithVariable(
432 "traitor.blameresult.failure.penalty",
434 TextManager.FormatCurrency(traitorResults.MoneyPenalty, includeCurrencySymbol:
false)));
437 var icon = GUIStyle.GetComponentStyle(
"TraitorMissionIcon")?.GetDefaultSprite();
443 difficultyIconCount: 0,
445 out GUIImage missionIcon);
453 int spacing = GUI.IntScale(5);
458 int iconSize = (int)(GUIStyle.SubHeadingFont.MeasureChar(
'T').Y + defaultLineHeight * 6);
463 AbsoluteSpacing = spacing,
471 HoverColor = iconColor,
472 SelectedColor = iconColor,
483 AbsoluteSpacing = spacing
488 List<RichString> contentStrings =
new List<RichString>(textContent.Select(t =>
RichString.
Rich(t)));
490 if (!header.IsNullOrEmpty())
493 missionNameString, font: GUIStyle.SubHeadingFont, wrap:
true);
494 nameText.RectTransform.MinSize =
new Point(0, (
int)nameText.TextSize.Y);
498 if (difficultyIconCount > 0)
506 for (
int i = 0; i < difficultyIconCount; i++)
510 CanBeFocused =
false,
511 Color = difficultyColor
517 foreach (var contentString
in contentStrings)
519 var text =
new GUITextBlock(
new RectTransform(
new Vector2(1.0f, 0.0f), missionTextGroup.RectTransform), contentString, wrap:
true);
520 text.RectTransform.MinSize =
new Point(0, (
int)text.TextSize.Y);
521 firstContentText ??= text;
523 if (difficultyIndicatorGroup !=
null && firstContentText !=
null)
526 difficultyIndicatorGroup.RectTransform.AbsoluteOffset =
new Point((
int)firstContentText.Padding.X, 0);
528 missionTextGroup.RectTransform.MinSize =
529 new Point(0, missionTextGroup.Children.Sum(c => c.Rect.Height + missionTextGroup.AbsoluteSpacing) - missionTextGroup.AbsoluteSpacing);
530 missionTextGroup.Recalculate();
531 content.RectTransform.MinSize =
new Point(0, Math.Max(missionTextGroup.Rect.Height, iconSize));
538 var children = container.
Children.ToList();
539 if (children.Count < 2) {
return; }
541 var lastChild = children.Last();
542 foreach (var child
in children)
544 if (child != lastChild)
546 var separator =
new GUIFrame(
new RectTransform(
new Vector2(0.5f, 0.1f), container.RectTransform), style:
"HorizontalLine");
547 separator.RectTransform.RepositionChildInHierarchy(container.GetChildIndex(child) + 1);
554 if (missionIcon ==
null) {
return; }
555 string style = success ?
"MissionCompletedIcon" :
"MissionFailedIcon";
557 if (
string.IsNullOrEmpty(style))
559 if (stateIcon !=
null)
566 bool wasVisible = stateIcon is { Visible:
true };
571 stateIcon.
FadeIn(delay, 0.15f);
572 stateIcon.
Pulsate(Vector2.One, Vector2.One * 1.5f, 1.0f + delay);
583 if (gameMode is PvPMode)
585 textTag =
"RoundSummaryRoundHasEnded";
589 textTag =
"RoundSummaryGameOver";
593 switch (transitionType)
595 case CampaignMode.TransitionType.LeaveLocation:
596 locationName = startLocation?.DisplayName;
597 textTag =
"RoundSummaryLeaving";
599 case CampaignMode.TransitionType.ProgressToNextLocation:
600 locationName = endLocation?.DisplayName;
601 textTag =
"RoundSummaryProgress";
603 case CampaignMode.TransitionType.ProgressToNextEmptyLocation:
604 locationName = endLocation?.DisplayName;
605 textTag =
"RoundSummaryProgressToEmptyLocation";
607 case CampaignMode.TransitionType.ReturnToPreviousLocation:
608 locationName = startLocation?.DisplayName;
609 textTag =
"RoundSummaryReturn";
611 case CampaignMode.TransitionType.ReturnToPreviousEmptyLocation:
612 locationName = startLocation?.DisplayName;
613 textTag =
"RoundSummaryReturnToEmptyLocation";
618 textTag =
"RoundSummaryRoundHasEnded";
622 textTag =
Submarine.MainSub.AtEndExit ?
"RoundSummaryProgress" :
"RoundSummaryReturn";
628 if (startLocation?.Biome !=
null && startLocation.Biome.IsEndBiome)
630 locationName ??= startLocation.DisplayName;
633 if (textTag ==
null) {
return ""; }
635 if (locationName ==
null)
637 DebugConsole.ThrowError($
"Error while creating round summary: could not determine destination location. Start location: {startLocation?.DisplayName ?? "null"}, end location: {endLocation?.DisplayName ?? "null"}");
638 locationName =
"[UNKNOWN]";
641 LocalizedString subName =
string.Empty;
642 SubmarineInfo currentOrPending = SubmarineSelection.CurrentOrPendingSubmarine();
643 if (currentOrPending !=
null)
645 subName = currentOrPending.DisplayName;
648 return TextManager.GetWithVariables(textTag, (
"[sub]", subName), (
"[location]", locationName));
651 private GUIListBox CreateCrewList(GUIComponent parent, IEnumerable<CharacterInfo> characterInfos, TraitorManager.TraitorResults? traitorResults)
653 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)
658 GUIButton jobButton =
new GUIButton(
new RectTransform(
new Vector2(JobColumnWidthPercentage, 1f), headerFrame.RectTransform), TextManager.Get(
"tabmenu.job"), style:
"GUIButtonSmallFreeScale");
659 GUIButton characterButton =
new GUIButton(
new RectTransform(
new Vector2(CharacterColumnWidthPercentage, 1f), headerFrame.RectTransform), TextManager.Get(
"name"), style:
"GUIButtonSmallFreeScale");
661 if (gameMode is PvPMode)
663 var killButton =
new GUIButton(
new RectTransform(
new Vector2(KillColumnWidthPercentage, 1f), headerFrame.RectTransform), TextManager.Get(
"killcount"), style:
"GUIButtonSmallFreeScale");
664 killColumnWidth = killButton.Rect.Width;
665 var deathButton =
new GUIButton(
new RectTransform(
new Vector2(DeathColumnWidthPercentage, 1f), headerFrame.RectTransform), TextManager.Get(
"deathcount"), style:
"GUIButtonSmallFreeScale");
666 deathColumnWidth = deathButton.Rect.Width;
669 GUIButton statusButton =
new GUIButton(
new RectTransform(
new Vector2(StatusColumnWidthPercentage, 1f), headerFrame.RectTransform), TextManager.Get(
"label.statuslabel"), style:
"GUIButtonSmallFreeScale");
671 foreach (var btn
in headerFrame.GetAllChildren<GUIButton>())
673 btn.TextBlock.Font = GUIStyle.HotkeyFont;
675 btn.CanBeFocused =
false;
678 jobColumnWidth = jobButton.Rect.Width;
679 characterColumnWidth = characterButton.Rect.Width;
680 statusColumnWidth = statusButton.Rect.Width;
682 GUIListBox crewList =
new GUIListBox(
new RectTransform(Vector2.One, parent.RectTransform))
684 Padding =
new Vector4(4, 10, 0, 0) * GUI.Scale,
685 AutoHideScrollBar =
false
687 crewList.ContentBackground.Color = Color.Transparent;
689 headerFrame.RectTransform.RelativeSize -=
new Vector2(crewList.ScrollBar.RectTransform.RelativeSize.X, 0.0f);
692 if (GameMain.NetworkMember !=
null)
694 foreach (CharacterInfo characterInfo
in characterInfos)
696 if (characterInfo ==
null) {
continue; }
697 Character character = characterInfo.Character;
698 Client ownerClient = GameMain.NetworkMember.ConnectedClients.FirstOrDefault(c => c.Character == character);
699 int killCount = 0, deathCount = 0;
700 foreach (var mission
in selectedMissions)
702 if (mission is not CombatMission combatMission) {
continue; }
703 killCount += ownerClient ==
null ? combatMission.GetBotKillCount(characterInfo) : combatMission.GetClientKillCount(ownerClient);
704 deathCount += ownerClient ==
null ? combatMission.GetBotDeathCount(characterInfo) : combatMission.GetClientDeathCount(ownerClient);
706 killCounts[characterInfo] = killCount;
707 deathCounts[characterInfo] = deathCount;
711 float delay = crewListAnimDelay;
712 foreach (CharacterInfo characterInfo
in characterInfos.OrderByDescending(ci => killCounts.GetValueOrDefault(ci)))
714 if (characterInfo ==
null) {
continue; }
715 CreateCharacterElement(characterInfo, crewList, traitorResults, delay);
716 delay += crewListAnimDelay;
718 missionIconAnimDelay = delay;
723 private readonly Dictionary<CharacterInfo, int> killCounts =
new();
724 private readonly Dictionary<CharacterInfo, int> deathCounts =
new();
727 private void CreateCharacterElement(CharacterInfo characterInfo, GUIListBox listBox, TraitorManager.TraitorResults? traitorResults,
float animDelay)
729 GUIFrame frame =
new GUIFrame(
new RectTransform(
new Point(listBox.Content.Rect.Width, GUI.IntScale(45)), listBox.Content.RectTransform), style:
"ListBoxElement")
731 CanBeFocused =
false,
732 UserData = characterInfo,
733 Color = (
Character.Controlled?.Info == characterInfo) ? TabMenu.OwnCharacterBGColor : Color.Transparent
736 var paddedFrame =
new GUILayoutGroup(
new RectTransform(
new Vector2(1.0f, 0.9f), frame.RectTransform,
Anchor.Center), isHorizontal:
true)
742 new GUICustomComponent(
new RectTransform(
new Point(jobColumnWidth, paddedFrame.Rect.Height), paddedFrame.RectTransform,
Anchor.Center), onDraw: (sb, component) => characterInfo.DrawJobIcon(sb, component.Rect))
744 ToolTip = characterInfo.Job.Name ??
"",
745 HoverColor = Color.White,
746 SelectedColor = Color.White
749 GUITextBlock characterNameBlock =
new GUITextBlock(
new RectTransform(
new Point(characterColumnWidth, paddedFrame.Rect.Height), paddedFrame.RectTransform),
750 ToolBox.LimitString(characterInfo.Name, GUIStyle.Font, characterColumnWidth), textAlignment: Alignment.Center, textColor: characterInfo.Job.Prefab.UIColor);
752 LocalizedString statusText = TextManager.Get(
"StatusOK");
753 Color statusColor = GUIStyle.Green;
755 Character character = characterInfo.Character;
756 if (character ==
null || character.IsDead)
758 if (character ==
null && characterInfo.IsNewHire && characterInfo.CauseOfDeath ==
null)
760 statusText = TextManager.Get(
"CampaignCrew.NewHire");
761 statusColor = GUIStyle.Blue;
763 else if (characterInfo.CauseOfDeath ==
null)
765 statusText = TextManager.Get(
"CauseOfDeathDescription.Unknown");
766 statusColor = Color.DarkRed;
768 else if (characterInfo.CauseOfDeath.Type ==
CauseOfDeathType.Affliction && characterInfo.CauseOfDeath.Affliction ==
null)
770 string errorMsg =
"Character \"[name]\" had an invalid cause of death (the type of the cause of death was Affliction, but affliction was not specified).";
771 DebugConsole.ThrowError(errorMsg.Replace(
"[name]", characterInfo.Name));
772 GameAnalyticsManager.AddErrorEventOnce(
"RoundSummary:InvalidCauseOfDeath", GameAnalyticsManager.ErrorSeverity.Error, errorMsg.Replace(
"[name]", characterInfo.SpeciesName.Value));
773 statusText = TextManager.Get(
"CauseOfDeathDescription.Unknown");
774 statusColor = GUIStyle.Red;
778 statusText = characterInfo.CauseOfDeath.Type ==
CauseOfDeathType.Affliction ?
779 characterInfo.CauseOfDeath.Affliction.CauseOfDeathDescription :
780 TextManager.Get(
"CauseOfDeathDescription." + characterInfo.CauseOfDeath.Type.ToString());
781 statusColor = Color.DarkRed;
786 if (character.IsUnconscious)
788 statusText = TextManager.Get(
"Unconscious");
789 statusColor = Color.DarkOrange;
791 else if (character.Vitality / character.MaxVitality < 0.8f)
793 statusText = TextManager.Get(
"Injured");
794 statusColor = Color.DarkOrange;
798 if (gameMode is PvPMode pvpMode)
800 new GUITextBlock(
new RectTransform(
new Point(killColumnWidth, paddedFrame.Rect.Height), paddedFrame.RectTransform),
801 killCounts.GetValueOrDefault(characterInfo).ToString(), textAlignment: Alignment.Center);
802 new GUITextBlock(
new RectTransform(
new Point(deathColumnWidth, paddedFrame.Rect.Height), paddedFrame.RectTransform),
803 deathCounts.GetValueOrDefault(characterInfo).ToString(), textAlignment: Alignment.Center);
806 GUITextBlock statusBlock =
new GUITextBlock(
new RectTransform(
new Point(statusColumnWidth, paddedFrame.Rect.Height), paddedFrame.RectTransform),
807 ToolBox.LimitString(statusText.Value, GUIStyle.Font, statusColumnWidth), textAlignment: Alignment.Center, textColor: statusColor, font: GUIStyle.SmallFont)
809 ToolTip = statusText.Value
812 frame.FadeIn(animDelay, 0.15f);
813 foreach (var child
in frame.GetAllChildren())
815 child.FadeIn(animDelay, 0.15f);
818 if (traitorResults.HasValue && GameMain.NetworkMember !=
null)
820 var clientVotedAsTraitor = traitorResults.Value.GetTraitorClient();
821 bool isTraitor = clientVotedAsTraitor !=
null && clientVotedAsTraitor.Character == character;
824 var img =
new GUIImage(
new RectTransform(
new Point(paddedFrame.Rect.Height), paddedFrame.RectTransform,
Anchor.CenterRight), style:
"TraitorVoteButton")
826 IgnoreLayoutGroups =
true,
827 ToolTip = TextManager.GetWithVariable(
"traitor.blameresult",
"[name]", characterInfo.Name)
829 img.FadeIn(1.0f + animDelay, 0.15f);
830 img.Pulsate(Vector2.One, Vector2.One * 1.5f, 1.5f + animDelay);
835 private static GUIFrame CreateReputationElement(GUIComponent parent,
836 LocalizedString name, Reputation reputation,
float initialReputation,
837 LocalizedString shortDescription, LocalizedString fullDescription, Sprite icon, Sprite backgroundPortrait, Color iconColor)
839 var factionFrame =
new GUIFrame(
new RectTransform(
new Vector2(1.0f, 0.1f), parent.RectTransform), style:
null);
841 if (backgroundPortrait !=
null)
843 new GUICustomComponent(
new RectTransform(Vector2.One, factionFrame.RectTransform), onDraw: (sb, customComponent) =>
845 backgroundPortrait.Draw(sb, customComponent.Rect.Center.ToVector2(), customComponent.Color, backgroundPortrait.size / 2, scale: customComponent.Rect.Width / backgroundPortrait.size.X);
848 HideElementsOutsideFrame =
true,
849 IgnoreLayoutGroups =
true,
850 Color = iconColor * 0.2f
854 var factionInfoHorizontal =
new GUILayoutGroup(
new RectTransform(
new Vector2(0.95f, 0.9f), factionFrame.RectTransform,
Anchor.Center), childAnchor:
Anchor.CenterRight, isHorizontal:
true)
856 AbsoluteSpacing = GUI.IntScale(5),
860 var factionIcon =
new GUIImage(
new RectTransform(Vector2.One * 0.7f, factionInfoHorizontal.RectTransform, scaleBasis:
ScaleBasis.Smallest), icon, scaleToFit:
true)
864 var factionTextContent =
new GUILayoutGroup(
new RectTransform(Vector2.One, factionInfoHorizontal.RectTransform))
866 AbsoluteSpacing = GUI.IntScale(10),
870 factionInfoHorizontal.Recalculate();
872 var header =
new GUITextBlock(
new RectTransform(
new Point(factionTextContent.Rect.Width, GUI.IntScale(40)), factionTextContent.RectTransform),
873 name, font: GUIStyle.SubHeadingFont)
875 Padding = Vector4.Zero,
878 header.RectTransform.IsFixedSize =
true;
880 var sliderHolder =
new GUILayoutGroup(
new RectTransform(
new Point((
int)(factionTextContent.Rect.Width * 0.8f), GUI.IntScale(20.0f)), factionTextContent.RectTransform),
881 childAnchor:
Anchor.CenterLeft, isHorizontal:
true)
883 RelativeSpacing = 0.05f,
886 sliderHolder.RectTransform.IsFixedSize =
true;
887 factionTextContent.Recalculate();
889 new GUICustomComponent(
new RectTransform(
new Vector2(0.8f, 1.0f), sliderHolder.RectTransform),
890 onDraw: (sb, customComponent) =>
DrawReputationBar(sb, customComponent.Rect, reputation.NormalizedValue, reputation.MinReputation, reputation.MaxReputation));
892 var reputationText =
new GUITextBlock(
new RectTransform(
new Vector2(0.5f, 1.0f), sliderHolder.RectTransform),
893 string.Empty, textAlignment: Alignment.CenterLeft, font: GUIStyle.SubHeadingFont);
894 SetReputationText(reputationText);
895 reputation?.OnReputationValueChanged.RegisterOverwriteExisting(
"RefreshRoundSummary".ToIdentifier(), _ =>
897 SetReputationText(reputationText);
900 void SetReputationText(GUITextBlock textBlock)
902 LocalizedString reputationText = Reputation.GetFormattedReputationText(reputation.NormalizedValue, reputation.Value, addColorTags:
true);
903 int reputationChange = (int)Math.Round(reputation.Value - initialReputation);
904 if (Math.Abs(reputationChange) > 0)
906 string changeText = $
"{(reputationChange > 0 ? "+
" : "") + reputationChange}";
907 string colorStr = XMLExtensions.ToStringHex(reputationChange > 0 ? GUIStyle.Green : GUIStyle.Red);
908 textBlock.Text = RichString.Rich($
"{reputationText} (‖color:{colorStr}‖{changeText}‖color:end‖)");
912 textBlock.Text = RichString.Rich(reputationText);
917 new GUIFrame(
new RectTransform(
new Vector2(1.0f, 0.0f), factionTextContent.RectTransform) { MinSize = new Point(0, GUI.IntScale(5)) }, style:
null);
919 var factionDescription =
new GUITextBlock(
new RectTransform(
new Vector2(0.8f, 0.6f), factionTextContent.RectTransform),
920 shortDescription, font: GUIStyle.SmallFont, wrap:
true)
922 UserData =
"description",
923 Padding = Vector4.Zero
925 if (shortDescription != fullDescription && !fullDescription.IsNullOrEmpty())
927 factionDescription.ToolTip = fullDescription;
931 new GUIFrame(
new RectTransform(
new Vector2(1.0f, 0.0f), factionTextContent.RectTransform) { MinSize = new Point(0, GUI.IntScale(5)) }, style:
null);
933 factionInfoHorizontal.Recalculate();
934 factionTextContent.Recalculate();
939 public static void DrawReputationBar(SpriteBatch sb, Rectangle rect,
float normalizedReputation,
float minReputation,
float maxReputation)
941 int segmentWidth = rect.Width / 5;
942 rect.Width = segmentWidth * 5;
943 for (
int i = 0; i < 5; i++)
946 GUI.DrawRectangle(sb,
new Rectangle(rect.X + (segmentWidth * i), rect.Y, segmentWidth, rect.Height), GUIStyle.ColorInventoryBackground, isFilled:
false);
948 GUI.DrawRectangle(sb, rect, GUIStyle.ColorInventoryBackground, isFilled:
false);
950 GUI.Arrow.Draw(sb,
new Vector2(rect.X + rect.Width * normalizedReputation, rect.Y), GUIStyle.ColorInventoryBackground, scale: GUI.Scale, spriteEffect: SpriteEffects.FlipVertically);
951 GUI.Arrow.Draw(sb,
new Vector2(rect.X + rect.Width * normalizedReputation, rect.Y), GUIStyle.TextColorNormal, scale: GUI.Scale * 0.8f, spriteEffect: SpriteEffects.FlipVertically);
953 GUI.DrawString(sb,
new Vector2(rect.X, rect.Bottom), ((
int)minReputation).ToString(), GUIStyle.TextColorNormal, font: GUIStyle.SmallFont);
954 string maxRepText = ((int)maxReputation).ToString();
955 Vector2 textSize = GUIStyle.SmallFont.MeasureString(maxRepText);
956 GUI.DrawString(sb,
new Vector2(rect.Right - textSize.X, rect.Bottom), maxRepText, GUIStyle.TextColorNormal, font: GUIStyle.SmallFont);
Biome(ContentXElement element, LevelGenerationParametersFile file)
IReadOnlyList< Faction > Factions
static Character? Controlled
static bool IsInWinningTeam(Character character)
static LocalizedString GetTeamName(CharacterTeamType teamID)
static CharacterTeamType? Winner
IEnumerable< Character > GetCharacters()
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)
GUIComponent GetChild(int index)
void Pulsate(Vector2 startScale, Vector2 endScale, float duration)
GUIComponent FindChild(Func< GUIComponent, bool > predicate, bool recursive=false)
void FadeIn(float wait, float duration, bool alsoChildren=false)
RectTransform RectTransform
IEnumerable< GUIComponent > Children
Vector2 MeasureChar(char c)
GUIFrame ContentBackground
A frame drawn behind the content of the listbox
GUIFrame Content
A frame that contains the contents of the listbox. The frame itself is not rendered.
static GameSession?? GameSession
static int GraphicsHeight
static bool IsMultiplayer
static NetworkMember NetworkMember
static ImmutableHashSet< Character > GetSessionCrewCharacters(CharacterType type)
Returns a list of crew characters currently in the game with a given filter.
IEnumerable< Mission > Missions
List< LocationConnection > Connections
Color GetDifficultyColor()
virtual LocalizedString FailureMessage
readonly MissionPrefab Prefab
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...
IEnumerable< LocalizedString > ShownMessages
virtual LocalizedString Name
virtual LocalizedString Description
RichString GetReputationRewardText()
int GetFinalReward(Submarine sub)
Get the final reward, taking talent bonuses into account if the mission has concluded and the talents...
virtual LocalizedString SuccessMessage
readonly Location[] Locations
readonly bool ShowInMenus
Reputation(CampaignMetadata metadata, Location location, Identifier identifier, int minReputation, int maxReputation, int initialReputation)
static Color GetReputationColor(float normalizedValue)
LocalizedString GetFormattedReputationText(bool addColorTags=false)
static RichString Rich(LocalizedString str, Func< string, string >? postProcess=null)
GUIFrame CreateSummaryFrame(GameSession gameSession, string endMessage, CampaignMode.TransitionType transitionType=CampaignMode.TransitionType.None, TraitorManager.TraitorResults? traitorResults=null)
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
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)
static Submarine MainSub
Note that this can be null in some situations, e.g. editors and missions that don't load a submarine.
@ Character
Characters only