Unstable 1.1.14.0

This commit is contained in:
Markus Isberg
2023-10-02 16:43:54 +03:00
parent 94f5a93a0c
commit cf8f0de659
606 changed files with 21906 additions and 11456 deletions
@@ -34,6 +34,8 @@ namespace Barotrauma
private bool _isCrewMenuOpen = true;
private Point crewListEntrySize;
private readonly List<GUITickBox> traitorButtons = new List<GUITickBox>();
/// <summary>
/// Present only in single player games. In multiplayer. The chatbox is found from GameSession.Client.
/// </summary>
@@ -95,6 +97,7 @@ namespace Barotrauma
{
CanBeFocused = false
};
crewArea.RectTransform.NonScaledSize = HUDLayoutSettings.CrewArea.Size;
// AbsoluteOffset is set in UpdateProjectSpecific based on crewListOpenState
crewList = new GUIListBox(new RectTransform(Vector2.One, crewArea.RectTransform), style: null, isScrollBarOnDefaultSide: false)
@@ -193,7 +196,7 @@ namespace Barotrauma
};
}
var reports = OrderPrefab.Prefabs.Where(o => o.IsReport && o.SymbolSprite != null && !o.Hidden).OrderBy(o => o.Identifier).ToArray();
var reports = OrderPrefab.Prefabs.Where(o => o.IsVisibleAsReportButton).OrderBy(o => o.Identifier).ToArray();
if (reports.None())
{
DebugConsole.ThrowError("No valid orders for report buttons found! Cannot create report buttons. The orders for the report buttons must have 'targetallcharacters' attribute enabled and a valid 'symbolsprite' defined.");
@@ -225,7 +228,8 @@ namespace Barotrauma
//report buttons
foreach (OrderPrefab orderPrefab in reports)
{
if (!orderPrefab.IsReport || orderPrefab.SymbolSprite == null || orderPrefab.Hidden) { continue; }
if (!orderPrefab.IsVisibleAsReportButton) { continue; }
var btn = new GUIButton(new RectTransform(Vector2.One, parent.RectTransform, scaleBasis: isHorizontal ? ScaleBasis.BothHeight : ScaleBasis.BothWidth), style: null)
{
OnClicked = (button, userData) =>
@@ -366,7 +370,7 @@ namespace Barotrauma
}
}
int iconsVisible = isJobIconVisible ? 5 : 4;
int iconsVisible = isJobIconVisible ? 6 : 5;
var nameRelativeWidth = 1.0f
// Start padding
- paddingRelativeWidth
@@ -412,7 +416,6 @@ namespace Barotrauma
{
AllowMouseWheelScroll = false,
CurrentDragMode = GUIListBox.DragMode.DragWithinBox,
HideChildrenOutsideFrame = false,
KeepSpaceForScrollBar = false,
OnRearranged = OnOrdersRearranged,
ScrollBarVisible = false,
@@ -438,13 +441,13 @@ namespace Barotrauma
Stretch = false
};
var extraIconFrame = new GUIFrame(new RectTransform(new Vector2(0.8f * iconRelativeWidth, 0.8f), layoutGroup.RectTransform), style: null)
var extraIconFrame = new GUIFrame(new RectTransform(new Vector2(0.8f * iconRelativeWidth * 2, 0.8f), layoutGroup.RectTransform), style: null)
{
CanBeFocused = false,
UserData = "extraicons"
};
var soundIconParent = new GUIFrame(new RectTransform(Vector2.One, extraIconFrame.RectTransform), style: null)
var soundIconParent = new GUIFrame(new RectTransform(new Vector2(0.8f), extraIconFrame.RectTransform, Anchor.CenterLeft, scaleBasis: ScaleBasis.Smallest), style: null)
{
CanBeFocused = false,
UserData = "soundicons",
@@ -469,16 +472,6 @@ namespace Barotrauma
Visible = false
};
if (character.IsBot)
{
new GUIFrame(new RectTransform(Vector2.One, extraIconFrame.RectTransform), style: null)
{
CanBeFocused = false,
UserData = "objectiveicon",
Visible = false
};
}
new GUIButton(new RectTransform(new Point((int)commandButtonAbsoluteHeight), background.RectTransform), style: "CrewListCommandButton")
{
ToolTip = TextManager.Get("inputtype.command"),
@@ -489,6 +482,44 @@ namespace Barotrauma
return true;
}
};
if (character.IsBot)
{
new GUIFrame(new RectTransform(Vector2.One, extraIconFrame.RectTransform, scaleBasis: ScaleBasis.Smallest), style: null)
{
CanBeFocused = false,
UserData = "objectiveicon",
Visible = false
};
}
else if (GameMain.GameSession is { TraitorsEnabled: true } && GameMain.Client != null && character != Character.Controlled)
{
Client targetClient = GameMain.Client.ConnectedClients.FirstOrDefault(c => c.Character == character);
if (targetClient != null)
{
if (OrderPrefab.Prefabs.TryGet("reporttraitor", out OrderPrefab order))
{
var voteTraitorBtn = new GUITickBox(new RectTransform(Vector2.One, extraIconFrame.RectTransform, Anchor.CenterRight, scaleBasis: ScaleBasis.Smallest), label: string.Empty, style: "TraitorVoteButton")
{
UserData = character,
ToolTip =
RichString.Rich(
$"‖color:{XMLExtensions.ToStringHex(GUIStyle.TextColorBright)}‖{TextManager.Get("traitor.blamebutton")}‖color:end‖\n"
+ TextManager.Get("traitor.blamebutton.tooltip")),
OnSelected = (GUITickBox obj) =>
{
foreach (var traitorBtn in traitorButtons)
{
//deselect other traitor buttons
if (traitorBtn != obj) { traitorBtn.SetSelected(false, callOnSelected: false); }
}
GameMain.Client?.Vote(VoteType.Traitor, obj.Selected ? targetClient : null);
return true;
}
};
traitorButtons.Add(voteTraitorBtn);
}
}
}
return background;
}
@@ -498,6 +529,7 @@ namespace Barotrauma
if (crewList?.Content.GetChildByUserData(character) is { } component)
{
crewList.RemoveChild(component);
traitorButtons.RemoveAll(t => t.IsChildOf(component, recursive: true));
}
}
@@ -1204,7 +1236,7 @@ namespace Barotrauma
}
}
crewArea.Visible = !(GameMain.GameSession?.GameMode is CampaignMode campaign) || (!campaign.ForceMapUI && !campaign.ShowCampaignUI);
crewArea.Visible = GameMain.GameSession?.GameMode is not CampaignMode campaign || (!campaign.ForceMapUI && !campaign.ShowCampaignUI);
guiFrame.AddToGUIUpdateList();
}
@@ -1371,7 +1403,8 @@ namespace Barotrauma
if (PlayerInput.KeyDown(InputType.Command) &&
(GUI.KeyboardDispatcher.Subscriber == null || (GUI.KeyboardDispatcher.Subscriber is GUIComponent component && (component == crewList || component.IsChildOf(crewList)))) &&
commandFrame == null && !clicklessSelectionActive && CanIssueOrders && !(GameMain.GameSession?.Campaign?.ShowCampaignUI ?? false))
commandFrame == null && !clicklessSelectionActive && CanIssueOrders && !(GameMain.GameSession?.Campaign?.ShowCampaignUI ?? false) &&
Character.Controlled?.SelectedItem?.Prefab is not { DisableCommandMenuWhenSelected: true })
{
if (PlayerInput.IsShiftDown())
{
@@ -1556,6 +1589,12 @@ namespace Barotrauma
{
if (characterComponent.UserData is Character character)
{
if (character.Removed)
{
characterComponent.Visible = false;
continue;
}
characterComponent.Visible = Character.Controlled == null || Character.Controlled.TeamID == character.TeamID;
if (character.TeamID == CharacterTeamType.FriendlyNPC && Character.Controlled != null &&
(character.CurrentHull == Character.Controlled.CurrentHull || Vector2.DistanceSquared(Character.Controlled.WorldPosition, character.WorldPosition) < 500.0f * 500.0f))
@@ -1632,6 +1671,8 @@ namespace Barotrauma
}
}
traitorButtons.ForEach(btn => btn.Visible = Character.Controlled is { IsDead: false } && btn.UserData as Character != Character.Controlled);
crewArea.RectTransform.AbsoluteOffset = Vector2.SmoothStep(
new Vector2(-crewArea.Rect.Width - HUDLayoutSettings.Padding, 0.0f),
Vector2.Zero,
@@ -2395,7 +2436,7 @@ namespace Barotrauma
if (!(GetTargetSubmarine() is { } sub)) { return; }
shortcutNodes.Clear();
var subItems = sub.GetItems(false);
if (CanFitMoreNodes() && subItems.Find(i => i.HasTag("reactor") && i.IsPlayerTeamInteractable)?.GetComponent<Reactor>() is Reactor reactor)
if (CanFitMoreNodes() && subItems.Find(i => i.HasTag(Tags.Reactor) && i.IsPlayerTeamInteractable)?.GetComponent<Reactor>() is Reactor reactor)
{
float reactorOutput = -reactor.CurrPowerConsumption;
// If player is not an engineer AND the reactor is not powered up AND nobody is using the reactor
@@ -2414,7 +2455,7 @@ namespace Barotrauma
// If player is not a captain AND nobody is using the nav terminal AND the nav terminal is powered up
// --> Create shortcut node for Steer order
if (CanFitMoreNodes() && ShouldDelegateOrder("steer") && IsNonDuplicateOrderPrefab(OrderPrefab.Prefabs["steer"]) &&
subItems.Find(i => i.HasTag("navterminal") && i.IsPlayerTeamInteractable) is Item nav && characters.None(c => c.SelectedItem == nav) &&
subItems.Find(i => i.HasTag(Tags.NavTerminal) && i.IsPlayerTeamInteractable) is Item nav && characters.None(c => c.SelectedItem == nav) &&
nav.GetComponent<Steering>() is Steering steering && steering.Voltage > steering.MinVoltage)
{
var order = new Order(OrderPrefab.Prefabs["steer"], steering.Item, steering);
@@ -157,11 +157,15 @@ namespace Barotrauma
SlideshowPlayer?.DrawManually(spriteBatch);
if (GUI.DisableHUD || GUI.DisableUpperHUD || ForceMapUI || CoroutineManager.IsCoroutineRunning("LevelTransition"))
if (GUI.DisableHUD || GUI.DisableUpperHUD || ForceMapUI ||
CoroutineManager.IsCoroutineRunning("LevelTransition"))
{
endRoundButton.Visible = false;
if (ReadyCheckButton != null) { ReadyCheckButton.Visible = false; }
return;
if (ReadyCheckButton != null)
{
ReadyCheckButton.Visible = false;
}
return;
}
if (Submarine.MainSub == null || Level.Loaded == null) { return; }
@@ -216,11 +220,15 @@ namespace Barotrauma
}
break;
}
if (Level.IsLoadedOutpost && !ObjectiveManager.AllActiveObjectivesCompleted())
if (Level.IsLoadedOutpost &&
(!ObjectiveManager.AllActiveObjectivesCompleted() && this is not MultiPlayerCampaign))
{
allowEndingRound = false;
}
if (ReadyCheckButton != null) { ReadyCheckButton.Visible = allowEndingRound; }
if (ReadyCheckButton != null)
{
ReadyCheckButton.Visible = allowEndingRound && GameMain.GameSession != null && GameMain.GameSession.RoundDuration > 10.0f;
}
endRoundButton.Visible = allowEndingRound && Character.Controlled is { IsIncapacitated: false };
if (endRoundButton.Visible)
@@ -384,8 +392,11 @@ namespace Barotrauma
protected void TryEndRoundWithFuelCheck(Action onConfirm, Action onReturnToMapScreen)
{
Submarine.MainSub.CheckFuel();
SubmarineInfo nextSub = PendingSubmarineSwitch ?? Submarine.MainSub.Info;
bool lowFuel = nextSub.Name == Submarine.MainSub.Info.Name ? Submarine.MainSub.Info.LowFuel : nextSub.LowFuel;
bool lowFuel = Submarine.MainSub.Info.LowFuel;
if (PendingSubmarineSwitch != null)
{
lowFuel = TransferItemsOnSubSwitch ? (lowFuel && PendingSubmarineSwitch.LowFuel) : PendingSubmarineSwitch.LowFuel;
}
if (Level.IsLoadedFriendlyOutpost && lowFuel && CargoManager.PurchasedItems.None(i => i.Value.Any(pi => pi.ItemPrefab.Tags.Contains("reactorfuel"))))
{
var extraConfirmationBox =
@@ -433,11 +444,21 @@ namespace Barotrauma
{
GUIMessageBox.MessageBoxes.RemoveAll(mb => mb.UserData is RoundSummary);
}
#if DEBUG
if (GUI.KeyboardDispatcher.Subscriber == null && PlayerInput.KeyHit(Microsoft.Xna.Framework.Input.Keys.M))
{
if (GUIMessageBox.MessageBoxes.Any()) { GUIMessageBox.MessageBoxes.Remove(GUIMessageBox.MessageBoxes.Last()); }
GUIFrame summaryFrame = GameMain.GameSession.RoundSummary.CreateSummaryFrame(GameMain.GameSession, "");
GUIMessageBox.MessageBoxes.Add(summaryFrame);
GameMain.GameSession.RoundSummary.ContinueButton.OnClicked = (_, __) => { GUIMessageBox.MessageBoxes.Remove(summaryFrame); return true; };
}
#endif
if (ShowCampaignUI || ForceMapUI)
{
CampaignUI?.Update(deltaTime);
}
}
}
}
@@ -284,7 +284,7 @@ namespace Barotrauma
yield return CoroutineStatus.Success;
}
protected override IEnumerable<CoroutineStatus> DoLevelTransition(TransitionType transitionType, LevelData newLevel, Submarine leavingSub, bool mirror, List<TraitorMissionResult> traitorResults = null)
protected override IEnumerable<CoroutineStatus> DoLevelTransition(TransitionType transitionType, LevelData newLevel, Submarine leavingSub, bool mirror)
{
yield return CoroutineStatus.Success;
}
@@ -1014,9 +1014,9 @@ namespace Barotrauma
public void LoadState(string filePath)
{
DebugConsole.Log($"Loading save file for an existing game session ({filePath})");
SaveUtil.DecompressToDirectory(filePath, SaveUtil.TempPath, null);
SaveUtil.DecompressToDirectory(filePath, SaveUtil.TempPath);
string gamesessionDocPath = Path.Combine(SaveUtil.TempPath, "gamesession.xml");
string gamesessionDocPath = Path.Combine(SaveUtil.TempPath, SaveUtil.GameSessionFileName);
XDocument doc = XMLExtensions.TryLoadXml(gamesessionDocPath);
if (doc == null)
{
@@ -368,7 +368,7 @@ namespace Barotrauma
yield return CoroutineStatus.Success;
}
protected override IEnumerable<CoroutineStatus> DoLevelTransition(TransitionType transitionType, LevelData newLevel, Submarine leavingSub, bool mirror, List<TraitorMissionResult> traitorResults = null)
protected override IEnumerable<CoroutineStatus> DoLevelTransition(TransitionType transitionType, LevelData newLevel, Submarine leavingSub, bool mirror)
{
NextLevel = newLevel;
bool success = CrewManager.GetCharacters().Any(c => !c.IsDead);
@@ -382,7 +382,7 @@ namespace Barotrauma
// Event history must be registered before ending the round or it will be cleared
GameMain.GameSession.EventManager.RegisterEventHistory();
}
GameMain.GameSession.EndRound("", traitorResults, transitionType);
GameMain.GameSession.EndRound("", transitionType);
var continueButton = GameMain.GameSession.RoundSummary?.ContinueButton;
RoundSummary roundSummary = null;
if (GUIMessageBox.VisibleBox?.UserData is RoundSummary)
@@ -513,17 +513,6 @@ namespace Barotrauma
}
}
#if DEBUG
if (GUI.KeyboardDispatcher.Subscriber == null && PlayerInput.KeyHit(Microsoft.Xna.Framework.Input.Keys.M))
{
if (GUIMessageBox.MessageBoxes.Any()) { GUIMessageBox.MessageBoxes.Remove(GUIMessageBox.MessageBoxes.Last()); }
GUIFrame summaryFrame = GameMain.GameSession.RoundSummary.CreateSummaryFrame(GameMain.GameSession, "", null);
GUIMessageBox.MessageBoxes.Add(summaryFrame);
GameMain.GameSession.RoundSummary.ContinueButton.OnClicked = (_, __) => { GUIMessageBox.MessageBoxes.Remove(summaryFrame); return true; };
}
#endif
if (ShowCampaignUI || ForceMapUI)
{
Character.DisableControls = true;
@@ -8,7 +8,7 @@ namespace Barotrauma.Tutorials
{
enum AutoPlayVideo { Yes, No };
enum TutorialSegmentType { MessageBox, InfoBox, Objective };
enum SegmentType { MessageBox, InfoBox, Objective };
sealed class Tutorial
{
@@ -108,7 +108,7 @@ namespace Barotrauma.Tutorials
GameMain.GameSession.StartRound(LevelSeed);
}
GameMain.GameSession.EventManager.ActiveEvents.Clear();
GameMain.GameSession.EventManager.ClearEvents();
GameMain.GameSession.EventManager.Enabled = true;
GameMain.GameScreen.Select();
@@ -1,5 +1,4 @@
using Barotrauma.Tutorials;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
namespace Barotrauma
@@ -15,8 +14,6 @@ namespace Barotrauma
public static bool IsTabMenuOpen => GameMain.GameSession?.tabMenu != null;
public static TabMenu TabMenuInstance => GameMain.GameSession?.tabMenu;
private float prevHudScale;
private TabMenu tabMenu;
public bool ToggleTabMenu()
@@ -27,7 +24,7 @@ namespace Barotrauma
GameMain.NetLobbyScreen.CharacterAppearanceCustomizationMenu = null;
if (GameMain.NetLobbyScreen.JobSelectionFrame != null) { GameMain.NetLobbyScreen.JobSelectionFrame.Visible = false; }
}
if (tabMenu == null && !(GameMode is TutorialMode) && !ConversationAction.IsDialogOpen)
if (tabMenu == null && GameMode is not TutorialMode && !ConversationAction.IsDialogOpen)
{
tabMenu = new TabMenu();
HintManager.OnShowTabMenu();
@@ -49,6 +46,8 @@ namespace Barotrauma
private GUITextBlock respawnInfoText;
private GUITickBox respawnTickBox;
private GUIImage eventLogNotification;
private void CreateTopLeftButtons()
{
if (topLeftButtonGroup != null)
@@ -96,7 +95,8 @@ namespace Barotrauma
OnClicked = (button, userData) => ToggleTabMenu()
};
talentPointNotification = CreateTalentIconNotification(tabMenuButton);
talentPointNotification = CreateNotificationIcon(tabMenuButton);
eventLogNotification = CreateNotificationIcon(tabMenuButton);
GameMain.Instance.ResolutionChanged += CreateTopLeftButtons;
@@ -121,7 +121,6 @@ namespace Barotrauma
return true;
}
};
prevHudScale = GameSettings.CurrentConfig.Graphics.HUDScale;
}
public void AddToGUIUpdateList()
@@ -152,7 +151,7 @@ namespace Barotrauma
}
}
public static GUIImage CreateTalentIconNotification(GUIComponent parent, bool offset = true)
public static GUIImage CreateNotificationIcon(GUIComponent parent, bool offset = true)
{
GUIImage indicator = new GUIImage(new RectTransform(new Vector2(0.45f), parent.RectTransform, anchor: Anchor.TopRight, scaleBasis: ScaleBasis.BothWidth), style: "TalentPointNotification")
{
@@ -167,19 +166,22 @@ namespace Barotrauma
return indicator;
}
public void EnableEventLogNotificationIcon(bool enabled)
{
if (eventLogNotification == null) { return; }
if (!eventLogNotification.Visible && enabled)
{
eventLogNotification.Pulsate(Vector2.One, Vector2.One * 2, 1.0f);
}
eventLogNotification.Visible = enabled;
}
public static void UpdateTalentNotificationIndicator(GUIImage indicator)
{
if (indicator != null)
{
if (Character.Controlled?.Info == null)
{
indicator.Visible = false;
}
else
{
indicator.Visible = Character.Controlled.Info.GetAvailableTalentPoints() > 0 && !Character.Controlled.HasUnlockedAllTalents();
}
}
if (indicator == null) { return; }
indicator.Visible =
Character.Controlled?.Info != null &&
Character.Controlled.Info.GetAvailableTalentPoints() > 0 && !Character.Controlled.HasUnlockedAllTalents();
}
public void HUDScaleChanged()
@@ -1,7 +1,6 @@
using Barotrauma.Extensions;
using Barotrauma.IO;
using Barotrauma.Items.Components;
using Barotrauma.Tutorials;
using Microsoft.Xna.Framework;
using System;
using System.Collections.Generic;
@@ -152,8 +151,8 @@ namespace Barotrauma
}
// onstartedinteracting.turretperiscope
if (item.HasTag("periscope") &&
item.GetConnectedComponents<Turret>().FirstOrDefault(t => t.Item.HasTag("turret")) is Turret)
if (item.HasTag(Tags.Periscope) &&
item.GetConnectedComponents<Turret>().FirstOrDefault(t => t.Item.HasTag(Tags.Turret)) is Turret)
{
if (DisplayHint($"{hintIdentifierBase}.turretperiscope".ToIdentifier(),
variables: new[]
@@ -175,6 +174,17 @@ namespace Barotrauma
}
}
public static void OnStartRepairing(Character character, Repairable repairable)
{
if (repairable.ForceDeteriorationTimer > 0.0f && !character.IsTraitor)
{
CoroutineManager.Invoke(() =>
{
DisplayHint($"repairingsabotageditem".ToIdentifier());
}, delay: 5.0f);
}
}
private static void CheckIsInteracting()
{
if (!CanDisplayHints()) { return; }
@@ -182,7 +192,7 @@ namespace Barotrauma
if (Character.Controlled.SelectedItem.GetComponent<Reactor>() is Reactor reactor && reactor.PowerOn &&
Character.Controlled.SelectedItem.OwnInventory?.AllItems is IEnumerable<Item> containedItems &&
containedItems.Count(i => i.HasTag("reactorfuel")) > 1)
containedItems.Count(i => i.HasTag(Tags.Fuel)) > 1)
{
if (DisplayHint("onisinteracting.reactorwithextrarods".ToIdentifier())) { return; }
}
@@ -210,7 +220,7 @@ namespace Barotrauma
{
if (item.CurrentHull == null) { continue; }
if (item.GetComponent<Pump>() == null) { continue; }
if (!item.HasTag("ballast") && !item.CurrentHull.RoomName.Contains("ballast", StringComparison.OrdinalIgnoreCase)) { continue; }
if (!item.HasTag(Tags.Ballast) && !item.CurrentHull.RoomName.Contains("ballast", StringComparison.OrdinalIgnoreCase)) { continue; }
BallastHulls.Add(item.CurrentHull);
}
}
@@ -246,8 +256,14 @@ namespace Barotrauma
});
}
if (GameMain.GameSession is { TraitorsEnabled: true })
{
DisplayHint("traitorsonboard".ToIdentifier());
DisplayHint("traitorsonboard2".ToIdentifier());
}
yield return CoroutineStatus.Success;
}
}
public static void OnRoundEnded()
@@ -395,8 +411,8 @@ namespace Barotrauma
if (DisplayHint($"onobtaineditem.{tag}".ToIdentifier())) { return; }
}
if ((item.HasTag("geneticmaterial") && character.Inventory.FindItemByTag("geneticdevice".ToIdentifier(), recursive: true) != null) ||
(item.HasTag("geneticdevice") && character.Inventory.FindItemByTag("geneticmaterial".ToIdentifier(), recursive: true) != null))
if ((item.HasTag(Tags.GeneticMaterial) && character.Inventory.FindItemByTag(Tags.GeneticMaterial, recursive: true) != null) ||
(item.HasTag(Tags.GeneticDevice) && character.Inventory.FindItemByTag(Tags.GeneticDevice, recursive: true) != null))
{
if (DisplayHint($"geneticmaterial.useinstructions".ToIdentifier())) { return; }
}
@@ -437,6 +453,14 @@ namespace Barotrauma
});
}
public static void OnRadioJammed(Item radioItem)
{
if (!CanDisplayHints()) { return; }
if (radioItem?.ParentInventory is not CharacterInventory characterInventory) { return; }
if (characterInventory.Owner != Character.Controlled) { return; }
DisplayHint("radiojammed".ToIdentifier());
}
public static void OnReactorOutOfFuel(Reactor reactor)
{
if (!CanDisplayHints()) { return; }
@@ -450,6 +474,13 @@ namespace Barotrauma
});
}
public static void OnAssignedAsTraitor()
{
if (!CanDisplayHints()) { return; }
DisplayHint("assignedastraitor".ToIdentifier());
DisplayHint("assignedastraitor2".ToIdentifier());
}
public static void OnAvailableTransition(CampaignMode.TransitionType transitionType)
{
if (!CanDisplayHints()) { return; }
@@ -556,7 +587,7 @@ namespace Barotrauma
private static void CheckIfDivingGearOutOfOxygen()
{
if (!CanDisplayHints()) { return; }
var divingGear = Character.Controlled.GetEquippedItem("diving", InvSlotType.OuterClothes);
var divingGear = Character.Controlled.GetEquippedItem(Tags.DivingGear, InvSlotType.OuterClothes);
if (divingGear?.OwnInventory == null) { return; }
if (divingGear.GetContainedItemConditionPercentage() > 0.0f) { return; }
DisplayHint("ondivinggearoutofoxygen".ToIdentifier(), onUpdate: () =>
@@ -599,7 +630,7 @@ namespace Barotrauma
if (adjacentHull.WaterPercentage > 75 && !BallastHulls.Contains(adjacentHull) && DisplayHint("onadjacenthull.highwaterpercentage".ToIdentifier())) { return; }
}
static bool IsWearingDivingSuit() => Character.Controlled.GetEquippedItem("deepdiving", InvSlotType.OuterClothes) is Item;
static bool IsWearingDivingSuit() => Character.Controlled.GetEquippedItem(Tags.HeavyDivingGear, InvSlotType.OuterClothes) is Item;
}
static bool IsOnFriendlySub() => Character.Controlled.Submarine is Submarine sub && (sub.TeamID == Character.Controlled.TeamID || sub.TeamID == CharacterTeamType.FriendlyNPC);
@@ -49,7 +49,7 @@ static class ObjectiveManager
public Identifier ParentId { get; set; }
public TutorialSegmentType SegmentType { get; private set; }
public SegmentType SegmentType { get; private set; }
public static Segment CreateInfoBoxSegment(Identifier id, Identifier objectiveTextTag, AutoPlayVideo autoPlayVideo, Text textContent = default, Video videoContent = default)
{
@@ -69,31 +69,31 @@ static class ObjectiveManager
private Segment(Identifier id, Identifier objectiveTextTag, AutoPlayVideo autoPlayVideo, Text textContent = default, Video videoContent = default)
{
Id = id;
ObjectiveText = TextManager.ParseInputTypes(TextManager.Get(objectiveTextTag));
ObjectiveText = TextManager.ParseInputTypes(TextManager.Get(objectiveTextTag).Fallback(objectiveTextTag.Value));
AutoPlayVideo = autoPlayVideo;
TextContent = textContent;
VideoContent = videoContent;
SegmentType = TutorialSegmentType.InfoBox;
SegmentType = SegmentType.InfoBox;
}
private Segment(Identifier id, Identifier objectiveTextTag, Action onClickObjective)
{
Id = id;
ObjectiveText = TextManager.ParseInputTypes(TextManager.Get(objectiveTextTag));
ObjectiveText = TextManager.ParseInputTypes(TextManager.Get(objectiveTextTag).Fallback(objectiveTextTag.Value));
OnClickObjective = onClickObjective;
SegmentType = TutorialSegmentType.MessageBox;
SegmentType = SegmentType.MessageBox;
}
private Segment(Identifier id, Identifier objectiveTextTag)
{
Id = id;
ObjectiveText = TextManager.ParseInputTypes(TextManager.Get(objectiveTextTag));
SegmentType = TutorialSegmentType.Objective;
ObjectiveText = TextManager.ParseInputTypes(TextManager.Get(objectiveTextTag).Fallback(objectiveTextTag.Value));
SegmentType = SegmentType.Objective;
}
public void ConnectMessageBox(Segment messageBoxSegment)
{
SegmentType = TutorialSegmentType.MessageBox;
SegmentType = SegmentType.MessageBox;
OnClickObjective = messageBoxSegment.OnClickObjective;
}
}
@@ -139,9 +139,9 @@ static class ObjectiveManager
VideoPlayer.AddToGUIUpdateList(order: 100);
}
public static void TriggerTutorialSegment(Segment segment, bool connectObjective = false)
public static void TriggerSegment(Segment segment, bool connectObjective = false)
{
if (segment.SegmentType != TutorialSegmentType.InfoBox)
if (segment.SegmentType != SegmentType.InfoBox)
{
activeObjectives.Add(segment);
AddToObjectiveList(segment, connectObjective);
@@ -153,15 +153,15 @@ static class ObjectiveManager
ActiveContentSegment = segment;
var title = TextManager.Get(segment.Id);
LocalizedString tutorialText = TextManager.GetFormatted(segment.TextContent.Tag);
tutorialText = TextManager.ParseInputTypes(tutorialText);
LocalizedString text = TextManager.GetFormatted(segment.TextContent.Tag).Fallback(segment.TextContent.Tag.Value);
text = TextManager.ParseInputTypes(text);
switch (segment.AutoPlayVideo)
{
case AutoPlayVideo.Yes:
infoBox = CreateInfoFrame(
title,
tutorialText,
text,
segment.TextContent.Width,
segment.TextContent.Height,
segment.TextContent.Anchor,
@@ -171,7 +171,7 @@ static class ObjectiveManager
case AutoPlayVideo.No:
infoBox = CreateInfoFrame(
title,
tutorialText,
text,
segment.TextContent.Width,
segment.TextContent.Height,
segment.TextContent.Anchor,
@@ -182,31 +182,54 @@ static class ObjectiveManager
}
}
public static void CompleteTutorialSegment(Identifier segmentId)
public static void CompleteSegment(Identifier segmentId)
{
if (GetActiveObjective(segmentId) is not Segment segment || !segment.CanBeCompleted || segment.IsCompleted)
{
return;
}
if (!MarkSegmentCompleted(segment))
CompleteSegment(segment, failed: false);
}
public static void FailSegment(Identifier segmentId)
{
if (GetActiveObjective(segmentId) is not Segment segment)
{
return;
}
CompleteSegment(segment, failed: true);
}
private static void CompleteSegment(Segment segment, bool failed = false)
{
if (failed)
{
if (!MarkSegmentFailed(segment)) { return; }
}
else
{
if (!MarkSegmentCompleted(segment)) { return; }
}
if (GameMain.GameSession?.GameMode is TutorialMode tutorialMode)
{
GameAnalyticsManager.AddDesignEvent($"Tutorial:{tutorialMode.Tutorial?.Identifier}:{segmentId}:Completed");
}
else if (GameMain.GameSession?.GameMode is CampaignMode campaign)
{
GameAnalyticsManager.AddDesignEvent($"Tutorial:CampaignMode:{segmentId}:Completed");
campaign?.CampaignMetadata?.SetValue(segmentId, true);
GameAnalyticsManager.AddDesignEvent($"Tutorial:{tutorialMode.Tutorial?.Identifier}:{segment.Id}:{(failed ? "Failed" : "Completed")}");
}
}
public static bool MarkSegmentCompleted(Segment segment, bool flash = true)
private static bool MarkSegmentCompleted(Segment segment, bool flash = true)
{
return MarkSegment(segment, "ObjectiveIndicatorCompleted", flash, flashColor: GUIStyle.Green);
}
private static bool MarkSegmentFailed(Segment segment, bool flash = true)
{
return MarkSegment(segment, "MissionFailedIcon", flash, flashColor: GUIStyle.Red);
}
private static bool MarkSegment(Segment segment, string iconStyleName, bool flash, Color flashColor)
{
segment.IsCompleted = true;
if (GUIStyle.GetComponentStyle("ObjectiveIndicatorCompleted") is GUIComponentStyle style)
if (GUIStyle.GetComponentStyle(iconStyleName) is GUIComponentStyle style)
{
if (segment.ObjectiveStateIndicator.Style == style)
{
@@ -216,21 +239,17 @@ static class ObjectiveManager
}
if (flash)
{
segment.ObjectiveStateIndicator.Parent.Flash(color: GUIStyle.Green, flashDuration: 0.35f, useRectangleFlash: true);
}
segment.ObjectiveStateIndicator.Parent.Flash(color: flashColor, flashDuration: 0.35f, useRectangleFlash: true);
}
segment.ObjectiveButton.OnClicked = null;
segment.ObjectiveButton.CanBeFocused = false;
return true;
}
public static void RemoveTutorialSegment(Identifier segmentId)
public static void RemoveSegment(Identifier segmentId)
{
if (GetActiveObjective(segmentId) is not Segment segment)
{
if (GameMain.GameSession?.GameMode is TutorialMode tutorialMode)
{
DebugConsole.AddWarning($"Warning: tried to remove the tutorial segment \"{segmentId}\" in tutorial \"{tutorialMode.Tutorial?.Identifier}\" but it isn't active!");
}
return;
}
segment.ObjectiveStateIndicator.FadeOut(ObjectiveComponentAnimationTime, false);
@@ -400,10 +419,10 @@ static class ObjectiveManager
void SetButtonBehavior(Segment segment)
{
segment.ObjectiveButton.CanBeFocused = segment.SegmentType != TutorialSegmentType.Objective;
segment.ObjectiveButton.CanBeFocused = segment.SegmentType != SegmentType.Objective;
segment.ObjectiveButton.OnClicked = (GUIButton btn, object userdata) =>
{
if (segment.SegmentType == TutorialSegmentType.InfoBox)
if (segment.SegmentType == SegmentType.InfoBox)
{
if (segment.AutoPlayVideo == AutoPlayVideo.Yes)
{
@@ -414,7 +433,7 @@ static class ObjectiveManager
ShowSegmentText(segment);
}
}
else if (segment.SegmentType == TutorialSegmentType.MessageBox)
else if (segment.SegmentType == SegmentType.MessageBox)
{
segment.OnClickObjective?.Invoke();
}
@@ -438,8 +457,8 @@ static class ObjectiveManager
ContentRunning = true;
ActiveContentSegment = segment;
infoBox = CreateInfoFrame(
TextManager.Get(segment.Id),
TextManager.Get(segment.TextContent.Tag),
TextManager.Get(segment.Id).Fallback(segment.Id.Value),
TextManager.Get(segment.TextContent.Tag).Fallback(segment.TextContent.Tag.Value),
segment.TextContent.Width,
segment.TextContent.Height,
segment.TextContent.Anchor,
@@ -10,12 +10,12 @@ namespace Barotrauma
{
internal partial class ReadyCheck
{
private static LocalizedString readyCheckBody(string name) => string.IsNullOrWhiteSpace(name) ? TextManager.Get("readycheck.serverbody") : TextManager.GetWithVariable("readycheck.body", "[player]", name);
private static LocalizedString ReadyCheckBody(string name) => string.IsNullOrWhiteSpace(name) ? TextManager.Get("readycheck.serverbody") : TextManager.GetWithVariable("readycheck.body", "[player]", name);
private static LocalizedString readyCheckStatus(int ready, int total) => TextManager.GetWithVariables("readycheck.readycount",
private static LocalizedString ReadyCheckStatus(int ready, int total) => TextManager.GetWithVariables("readycheck.readycount",
("[ready]", ready.ToString()),
("[total]", total.ToString()));
private static LocalizedString readyCheckPleaseWait(int seconds) => TextManager.GetWithVariable("readycheck.pleasewait", "[seconds]", seconds.ToString());
private static LocalizedString ReadyCheckPleaseWait(int seconds) => TextManager.GetWithVariable("readycheck.pleasewait", "[seconds]", seconds.ToString());
private static readonly LocalizedString readyCheckHeader = TextManager.Get("ReadyCheck.Title");
@@ -42,7 +42,7 @@ namespace Barotrauma
{
Vector2 relativeSize = new Vector2(0.2f / GUI.AspectRatioAdjustment, 0.15f);
Point minSize = new Point(300, 200);
msgBox = new GUIMessageBox(readyCheckHeader, readyCheckBody(author), new[] { yesButton, noButton }, relativeSize, minSize, type: GUIMessageBox.Type.Vote) { UserData = PromptData, Draggable = true };
msgBox = new GUIMessageBox(readyCheckHeader, ReadyCheckBody(author), new[] { yesButton, noButton }, relativeSize, minSize, type: GUIMessageBox.Type.Vote) { UserData = PromptData, Draggable = true };
GUILayoutGroup contentLayout = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.125f), msgBox.Content.RectTransform), childAnchor: Anchor.Center);
new GUIProgressBar(new RectTransform(new Vector2(0.8f, 1f), contentLayout.RectTransform), 0.0f, GUIStyle.Orange) { UserData = TimerData };
@@ -82,9 +82,15 @@ namespace Barotrauma
GUIListBox listBox = new GUIListBox(new RectTransform(new Vector2(1f, 0.8f), resultsBox.Content.RectTransform)) { UserData = UserListData };
foreach (var (id, _) in Clients)
foreach (var (id, status) in Clients)
{
Client? client = GameMain.Client.ConnectedClients.FirstOrDefault(c => c.SessionId == id);
if (client == null)
{
string list = GameMain.Client.ConnectedClients.Aggregate("Available clients:\n", (current, c) => current + $"{c.SessionId}: {c.Name}\n");
DebugConsole.AddWarning($"Client ID {id} was reported in ready check but was not found.\n" + list.TrimEnd('\n'));
continue;
}
GUIFrame container = new GUIFrame(new RectTransform(new Vector2(1f, 0.15f), listBox.Content.RectTransform), style: "ListBoxElement") { UserData = id };
GUILayoutGroup frame = new GUILayoutGroup(new RectTransform(Vector2.One, container.RectTransform), isHorizontal: true) { Stretch = true };
@@ -92,11 +98,6 @@ namespace Barotrauma
JobPrefab? jobPrefab = client?.Character?.Info?.Job?.Prefab;
if (client == null)
{
string list = GameMain.Client.ConnectedClients.Aggregate("Available clients:\n", (current, c) => current + $"{c.SessionId}: {c.Name}\n");
DebugConsole.ThrowError($"Client ID {id} was reported in ready check but was not found.\n" + list.TrimEnd('\n'));
}
if (jobPrefab?.Icon != null)
{
@@ -105,7 +106,8 @@ namespace Barotrauma
}
new GUITextBlock(new RectTransform(new Vector2(0.75f, 1), frame.RectTransform), client?.Name ?? $"Unknown ID {id}", jobPrefab?.UIColor ?? Color.White, textAlignment: Alignment.Center) { AutoScaleHorizontal = true };
new GUIImage(new RectTransform(new Point(height, height), frame.RectTransform), null, scaleToFit: true) { UserData = ReadySpriteData };
var statusIcon = new GUIImage(new RectTransform(new Point(height, height), frame.RectTransform), null, scaleToFit: true) { UserData = ReadySpriteData };
UpdateStatusIcon(statusIcon, status);
}
resultsBox.Buttons[0].OnClicked = delegate
@@ -214,10 +216,7 @@ namespace Barotrauma
case ReadyCheckState.Update:
ReadyStatus newState = (ReadyStatus)inc.ReadByte();
byte targetId = inc.ReadByte();
if (crewManager.ActiveReadyCheck != null)
{
crewManager.ActiveReadyCheck?.UpdateState(targetId, newState);
}
crewManager.ActiveReadyCheck?.UpdateState(targetId, newState);
break;
case ReadyCheckState.End:
ushort count = inc.ReadUInt16();
@@ -242,7 +241,7 @@ namespace Barotrauma
int readyCount = Clients.Count(static pair => pair.Value == ReadyStatus.Yes);
int totalCount = Clients.Count;
GameMain.Client.AddChatMessage(ChatMessage.Create(string.Empty, readyCheckStatus(readyCount, totalCount).Value, ChatMessageType.Server, null));
GameMain.Client.AddChatMessage(ChatMessage.Create(string.Empty, ReadyCheckStatus(readyCount, totalCount).Value, ChatMessageType.Server, null));
}
private void UpdateState(byte id, ReadyStatus status)
@@ -253,31 +252,28 @@ namespace Barotrauma
}
if (resultsBox == null || resultsBox.Closed || !GUIMessageBox.MessageBoxes.Contains(resultsBox)) { return; }
if (resultsBox.Content.FindChild(UserListData) is not GUIListBox userList) { return; }
// for some reason FindChild doesn't work here?
foreach (GUIComponent child in userList.Content.Children)
var child = userList.Content.FindChild(id);
if (child?.GetChild<GUILayoutGroup>().FindChild(ReadySpriteData) is not GUIImage image) { return; }
UpdateStatusIcon(image, status);
}
private static void UpdateStatusIcon(GUIImage image, ReadyStatus status)
{
string style;
switch (status)
{
if (child.UserData is not byte b || b != id) { continue; }
if (child.GetChild<GUILayoutGroup>().FindChild(ReadySpriteData) is not GUIImage image) { continue; }
string style;
switch (status)
{
case ReadyStatus.Yes:
style = "MissionCompletedIcon";
break;
case ReadyStatus.No:
style = "MissionFailedIcon";
break;
default:
return;
}
image.ApplyStyle(GUIStyle.GetComponentStyle(style));
case ReadyStatus.Yes:
style = "MissionCompletedIcon";
break;
case ReadyStatus.No:
style = "MissionFailedIcon";
break;
default:
return;
}
image.ApplyStyle(GUIStyle.GetComponentStyle(style));
}
private static void SendState(ReadyStatus status)
@@ -303,7 +299,7 @@ namespace Barotrauma
return;
}
GUIMessageBox msgBox = new GUIMessageBox(readyCheckHeader, readyCheckPleaseWait((ReadyCheckCooldown - DateTime.Now).Seconds), new[] { closeButton });
GUIMessageBox msgBox = new GUIMessageBox(readyCheckHeader, ReadyCheckPleaseWait((ReadyCheckCooldown - DateTime.Now).Seconds), new[] { closeButton });
msgBox.Buttons[0].OnClicked = delegate
{
msgBox.Close();
@@ -10,6 +10,9 @@ namespace Barotrauma
{
class RoundSummary
{
private float crewListAnimDelay = 0.25f;
private float missionIconAnimDelay;
private const float jobColumnWidthPercentage = 0.11f;
private const float characterColumnWidthPercentage = 0.44f;
private const float statusColumnWidthPercentage = 0.45f;
@@ -44,7 +47,7 @@ namespace Barotrauma
}
}
public GUIFrame CreateSummaryFrame(GameSession gameSession, string endMessage, List<TraitorMissionResult> traitorResults, CampaignMode.TransitionType transitionType = CampaignMode.TransitionType.None)
public GUIFrame CreateSummaryFrame(GameSession gameSession, string endMessage, CampaignMode.TransitionType transitionType = CampaignMode.TransitionType.None, TraitorManager.TraitorResults? traitorResults = null)
{
bool singleplayer = GameMain.NetworkMember == null;
bool gameOver =
@@ -70,7 +73,7 @@ namespace Barotrauma
//crew panel -------------------------------------------------------------------------------
GUIFrame crewFrame = new GUIFrame(new RectTransform(new Vector2(0.35f, 0.45f), background.RectTransform, Anchor.TopCenter, minSize: new Point(minWidth, minHeight)));
GUIFrame crewFrame = new GUIFrame(new RectTransform(new Vector2(0.35f, 0.4f), background.RectTransform, Anchor.TopCenter, minSize: new Point(minWidth, minHeight)));
GUIFrame crewFrameInner = new GUIFrame(new RectTransform(new Point(crewFrame.Rect.Width - padding * 2, crewFrame.Rect.Height - padding * 2), crewFrame.RectTransform, Anchor.Center), style: "InnerFrame");
var crewContent = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.95f), crewFrameInner.RectTransform, Anchor.Center))
@@ -82,7 +85,14 @@ namespace Barotrauma
TextManager.Get("crew"), textAlignment: Alignment.TopLeft, font: GUIStyle.SubHeadingFont);
crewHeader.RectTransform.MinSize = new Point(0, GUI.IntScale(crewHeader.Rect.Height * 2.0f));
CreateCrewList(crewContent, gameSession.CrewManager.GetCharacterInfos().Where(c => c.TeamID != CharacterTeamType.Team2));
var crewList = CreateCrewList(crewContent, gameSession.CrewManager.GetCharacterInfos().Where(c => c.TeamID != CharacterTeamType.Team2), traitorResults);
if (traitorResults != null && traitorResults.Value.VotedAsTraitorClientSessionId > 0)
{
var traitorInfoPanel = CreateTraitorInfoPanel(crewList.Content, traitorResults.Value, crewListAnimDelay);
traitorInfoPanel.RectTransform.SetAsFirstChild();
var spacing = new GUIFrame(new RectTransform(new Point(0, GUI.IntScale(20)), crewList.Content.RectTransform), style: null);
spacing.RectTransform.RepositionChildInHierarchy(1);
}
//another crew frame for the 2nd team in combat missions
if (gameSession.Missions.Any(m => m is CombatMission))
@@ -98,7 +108,7 @@ namespace Barotrauma
var crewHeader2 = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), crewContent2.RectTransform),
CombatMission.GetTeamName(CharacterTeamType.Team2), textAlignment: Alignment.TopLeft, font: GUIStyle.SubHeadingFont);
crewHeader2.RectTransform.MinSize = new Point(0, GUI.IntScale(crewHeader2.Rect.Height * 2.0f));
CreateCrewList(crewContent2, gameSession.CrewManager.GetCharacterInfos().Where(c => c.TeamID == CharacterTeamType.Team2));
CreateCrewList(crewContent2, gameSession.CrewManager.GetCharacterInfos().Where(c => c.TeamID == CharacterTeamType.Team2), traitorResults);
}
//header -------------------------------------------------------------------------------
@@ -111,71 +121,6 @@ namespace Barotrauma
headerText, textAlignment: Alignment.BottomLeft, font: GUIStyle.LargeFont, wrap: true);
}
//traitor panel -------------------------------------------------------------------------------
if (traitorResults != null && traitorResults.Any())
{
GUIFrame traitorframe = new GUIFrame(new RectTransform(crewFrame.RectTransform.RelativeSize, background.RectTransform, Anchor.TopCenter, minSize: crewFrame.RectTransform.MinSize));
rightPanels.Add(traitorframe);
GUIFrame traitorframeInner = new GUIFrame(new RectTransform(new Point(traitorframe.Rect.Width - padding * 2, traitorframe.Rect.Height - padding * 2), traitorframe.RectTransform, Anchor.Center), style: "InnerFrame");
var traitorContent = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.95f), traitorframeInner.RectTransform, Anchor.Center))
{
Stretch = true
};
var traitorHeader = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), traitorContent.RectTransform),
TextManager.Get("traitors"), font: GUIStyle.SubHeadingFont);
traitorHeader.RectTransform.MinSize = new Point(0, GUI.IntScale(traitorHeader.Rect.Height * 2.0f));
GUIListBox listBox = CreateCrewList(traitorContent, traitorResults.SelectMany(tr => tr.Characters.Select(c => c.Info)));
foreach (var traitorResult in traitorResults)
{
var traitorMission = TraitorMissionPrefab.Prefabs.Find(t => t.Identifier == traitorResult.MissionIdentifier);
if (traitorMission == null) { continue; }
//spacing
new GUIFrame(new RectTransform(new Point(listBox.Content.Rect.Width, GUI.IntScale(25)), listBox.Content.RectTransform), style: null);
var traitorResultHorizontal = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.3f), listBox.Content.RectTransform), childAnchor: Anchor.CenterLeft, isHorizontal: true)
{
RelativeSpacing = 0.05f,
Stretch = true
};
new GUIImage(new RectTransform(new Point(traitorResultHorizontal.Rect.Height), traitorResultHorizontal.RectTransform), traitorMission.Icon, scaleToFit: true)
{
Color = traitorMission.IconColor
};
LocalizedString traitorMessage = TextManager.GetServerMessage(traitorResult.EndMessage);
if (!traitorMessage.IsNullOrEmpty())
{
var textContent = new GUILayoutGroup(new RectTransform(Vector2.One, traitorResultHorizontal.RectTransform))
{
RelativeSpacing = 0.025f
};
var traitorStatusText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), textContent.RectTransform),
TextManager.Get(traitorResult.Success ? "missioncompleted" : "missionfailed"),
textColor: traitorResult.Success ? GUIStyle.Green : GUIStyle.Red, font: GUIStyle.SubHeadingFont);
var traitorMissionInfo = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), textContent.RectTransform),
traitorMessage, font: GUIStyle.SmallFont, wrap: true);
traitorResultHorizontal.Recalculate();
traitorStatusText.CalculateHeightFromText();
traitorMissionInfo.CalculateHeightFromText();
traitorStatusText.RectTransform.MinSize = new Point(0, traitorStatusText.Rect.Height);
traitorMissionInfo.RectTransform.MinSize = new Point(0, traitorMissionInfo.Rect.Height);
textContent.RectTransform.MaxSize = new Point(int.MaxValue, (int)((traitorStatusText.Rect.Height + traitorMissionInfo.Rect.Height) * 1.2f));
traitorResultHorizontal.RectTransform.MinSize = new Point(0, traitorStatusText.RectTransform.MinSize.Y + traitorMissionInfo.RectTransform.MinSize.Y);
}
}
}
//reputation panel -------------------------------------------------------------------------------
var campaignMode = gameMode as CampaignMode;
@@ -185,7 +130,7 @@ namespace Barotrauma
rightPanels.Add(reputationframe);
GUIFrame reputationframeInner = new GUIFrame(new RectTransform(new Point(reputationframe.Rect.Width - padding * 2, reputationframe.Rect.Height - padding * 2), reputationframe.RectTransform, Anchor.Center), style: "InnerFrame");
var reputationContent = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.95f), reputationframeInner.RectTransform, Anchor.Center))
var reputationContent = new GUILayoutGroup(new RectTransform(new Vector2(0.98f, 0.95f), reputationframeInner.RectTransform, Anchor.Center))
{
Stretch = true
};
@@ -199,15 +144,15 @@ namespace Barotrauma
//mission panel -------------------------------------------------------------------------------
GUIFrame missionframe = new GUIFrame(new RectTransform(new Vector2(0.39f, 0.3f), background.RectTransform, Anchor.TopCenter, minSize: new Point(minWidth, minHeight / 4)));
GUIFrame missionframe = new GUIFrame(new RectTransform(new Vector2(0.5f, 0.4f), background.RectTransform, Anchor.TopCenter, minSize: new Point(minWidth, minHeight / 4)));
GUILayoutGroup missionFrameContent = new GUILayoutGroup(new RectTransform(new Point(missionframe.Rect.Width - padding * 2, missionframe.Rect.Height - padding * 2), missionframe.RectTransform, Anchor.Center))
{
Stretch = true,
RelativeSpacing = 0.05f
RelativeSpacing = 0.03f
};
GUIFrame missionframeInner = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.9f), missionFrameContent.RectTransform, Anchor.Center), style: "InnerFrame");
var missionContent = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.93f), missionframeInner.RectTransform, Anchor.Center))
var missionContent = new GUILayoutGroup(new RectTransform(new Vector2(0.98f, 0.93f), missionframeInner.RectTransform, Anchor.Center))
{
Stretch = true
};
@@ -227,16 +172,9 @@ namespace Barotrauma
}
}
if (missionsToDisplay.Any())
{
var missionHeader = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), missionContent.RectTransform),
TextManager.Get(missionsToDisplay.Count > 1 ? "Missions" : "Mission"), textAlignment: Alignment.TopLeft, font: GUIStyle.SubHeadingFont);
missionHeader.RectTransform.MinSize = new Point(0, (int)(missionHeader.Rect.Height * 1.2f));
}
GUIListBox missionList = new GUIListBox(new RectTransform(Vector2.One, missionContent.RectTransform, Anchor.Center))
{
Padding = new Vector4(4, 10, 0, 0) * GUI.Scale
Spacing = GUI.IntScale(15)
};
missionList.ContentBackground.Color = Color.Transparent;
@@ -255,120 +193,76 @@ namespace Barotrauma
{
CanBeFocused = false
};
endText.RectTransform.MinSize = new Point(0, endText.Rect.Height);
var line = new GUIFrame(new RectTransform(new Vector2(0.5f, 0.1f), missionList.Content.RectTransform), style: "HorizontalLine");
line.RectTransform.NonScaledSize = new Point(line.Rect.Width, GUI.IntScale(5.0f));
}
foreach (Mission displayedMission in missionsToDisplay)
float animDelay = missionIconAnimDelay;
foreach (Mission mission in missionsToDisplay)
{
var missionContentHorizontal = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.8f), missionList.Content.RectTransform), childAnchor: Anchor.CenterLeft, isHorizontal: true)
{
RelativeSpacing = 0.025f,
Stretch = true
};
var textContent = new List<LocalizedString>();
LocalizedString missionMessage =
selectedMissions.Contains(displayedMission) ?
displayedMission.Completed ? displayedMission.SuccessMessage : displayedMission.FailureMessage :
displayedMission.Description;
GUIImage missionIcon = new GUIImage(new RectTransform(new Point((int)(missionContentHorizontal.Rect.Height)), missionContentHorizontal.RectTransform), displayedMission.Prefab.Icon, scaleToFit: true)
if (selectedMissions.Contains(mission))
{
Color = displayedMission.Prefab.IconColor,
HoverColor = displayedMission.Prefab.IconColor,
SelectedColor = displayedMission.Prefab.IconColor
};
missionIcon.RectTransform.MinSize = new Point((int)(missionContentHorizontal.Rect.Height * 0.9f));
if (selectedMissions.Contains(displayedMission))
{
new GUIImage(new RectTransform(Vector2.One, missionIcon.RectTransform), displayedMission.Completed ? "MissionCompletedIcon" : "MissionFailedIcon", scaleToFit: true);
}
textContent.Add(mission.Completed ? mission.SuccessMessage : mission.FailureMessage);
var missionTextContent = new GUILayoutGroup(new RectTransform(new Vector2(0.8f, 1.0f), missionContentHorizontal.RectTransform))
{
AbsoluteSpacing = GUI.IntScale(5)
};
missionContentHorizontal.Recalculate();
var missionNameTextBlock = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), missionTextContent.RectTransform),
displayedMission.Name, font: GUIStyle.SubHeadingFont);
if (displayedMission.Difficulty.HasValue)
{
var groupSize = missionNameTextBlock.Rect.Size;
groupSize.X -= (int)(missionNameTextBlock.Padding.X + missionNameTextBlock.Padding.Z);
var indicatorGroup = new GUILayoutGroup(new RectTransform(groupSize, missionTextContent.RectTransform) { AbsoluteOffset = new Point((int)missionNameTextBlock.Padding.X, 0) },
isHorizontal: true, childAnchor: Anchor.CenterLeft)
{
AbsoluteSpacing = 1
};
var difficultyColor = displayedMission.GetDifficultyColor();
for (int i = 0; i < displayedMission.Difficulty; i++)
{
new GUIImage(new RectTransform(Vector2.One, indicatorGroup.RectTransform, scaleBasis: ScaleBasis.Smallest) { IsFixedSize = true }, "DifficultyIndicator", scaleToFit: true)
{
CanBeFocused = false,
Color = difficultyColor
};
}
}
var repText = mission.GetReputationRewardText();
if (!repText.IsNullOrEmpty()) { textContent.Add(repText); }
var missionDescription = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), missionTextContent.RectTransform),
RichString.Rich(missionMessage), wrap: true);
if (selectedMissions.Contains(displayedMission))
{
RichString reputationText = displayedMission.GetReputationRewardText();
if (!reputationText.IsNullOrEmpty())
{
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), missionTextContent.RectTransform), reputationText, wrap: true);
}
int totalReward = displayedMission.GetFinalReward(Submarine.MainSub);
int totalReward = mission.GetFinalReward(Submarine.MainSub);
if (totalReward > 0)
{
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), missionTextContent.RectTransform), RichString.Rich(displayedMission.GetMissionRewardText(Submarine.MainSub)));
if (GameMain.IsMultiplayer && Character.Controlled is { } controlled && displayedMission.Completed)
textContent.Add(mission.GetMissionRewardText(Submarine.MainSub));
if (GameMain.IsMultiplayer && Character.Controlled is { } controlled && mission.Completed)
{
var (share, percentage, _) = Mission.GetRewardShare(controlled.Wallet.RewardDistribution, GameSession.GetSessionCrewCharacters(CharacterType.Player).Where(c => c != controlled), Option<int>.Some(totalReward));
if (share > 0)
{
string shareFormatted = string.Format(CultureInfo.InvariantCulture, "{0:N0}", share);
RichString yourShareString = RichString.Rich(TextManager.GetWithVariables("crewwallet.missionreward.get", ("[money]", $"{shareFormatted}"), ("[share]", $"{percentage}")));
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), missionTextContent.RectTransform), yourShareString);
RichString yourShareString = TextManager.GetWithVariables("crewwallet.missionreward.get", ("[money]", $"{shareFormatted}"), ("[share]", $"{percentage}"));
textContent.Add(yourShareString);
}
}
}
}
if (displayedMission != missionsToDisplay.Last())
else
{
var spacing = new GUIFrame(new RectTransform(new Vector2(1.0f, 1.0f), missionList.Content.RectTransform) { MaxSize = new Point(int.MaxValue, GUI.IntScale(15)) }, style: null);
new GUIFrame(new RectTransform(new Vector2(0.8f, 1.0f), spacing.RectTransform, Anchor.Center) { RelativeOffset = new Vector2(0.1f, 0.0f) }, "HorizontalLine");
var repText = mission.GetReputationRewardText();
if (!repText.IsNullOrEmpty()) { textContent.Add(repText); }
textContent.Add(mission.GetMissionRewardText(Submarine.MainSub));
textContent.Add(mission.Description);
textContent.AddRange(mission.ShownMessages);
}
foreach (GUIComponent child in missionTextContent.Children)
CreateMissionEntry(
missionList.Content,
mission.Name,
textContent,
mission.Difficulty ?? 0,
mission.Prefab.Icon, mission.Prefab.IconColor,
out GUIImage missionIcon);
if (selectedMissions.Contains(mission))
{
child.RectTransform.IsFixedSize = true;
UpdateMissionStateIcon(mission.Completed, missionIcon, animDelay);
animDelay += 0.25f;
}
missionTextContent.RectTransform.MinSize = new Point(0, missionTextContent.Children.Sum(c => c.Rect.Height + missionTextContent.AbsoluteSpacing));
missionContentHorizontal.RectTransform.MinSize = new Point(0, (int)(missionTextContent.Rect.Height / missionTextContent.RectTransform.RelativeSize.Y));
}
if (!missionsToDisplay.Any())
{
var missionContentHorizontal = new GUILayoutGroup(new RectTransform(Vector2.One, missionList.Content.RectTransform), childAnchor: Anchor.TopLeft, isHorizontal: true)
var missionContentHorizontal = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.4f), missionList.Content.RectTransform), childAnchor: Anchor.TopLeft, isHorizontal: true)
{
RelativeSpacing = 0.025f,
Stretch = true
Stretch = true,
CanBeFocused = true
};
GUIImage missionIcon = new GUIImage(new RectTransform(new Point((int)(missionContentHorizontal.Rect.Height * 0.7f)), missionContentHorizontal.RectTransform), style: "NoMissionIcon", scaleToFit: true);
missionIcon.RectTransform.MinSize = new Point((int)(missionContentHorizontal.Rect.Height * 0.7f));
GUIImage missionIcon = new GUIImage(new RectTransform(new Point(missionContentHorizontal.Rect.Height), missionContentHorizontal.RectTransform), style: "NoMissionIcon", scaleToFit: true);
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), missionContentHorizontal.RectTransform),
TextManager.Get("nomission"), font: GUIStyle.LargeFont);
}
/*missionContentHorizontal.Recalculate();
missionContent.Recalculate();
missionIcon.RectTransform.MinSize = new Point(0, missionContentHorizontal.Rect.Height);
missionTextContent.RectTransform.MaxSize = new Point(int.MaxValue, missionIcon.Rect.Width);*/
gameSession?.EventManager?.EventLog?.CreateEventLogUI(missionList.Content, traitorResults);
AddSeparators(missionList.Content);
ContinueButton = new GUIButton(new RectTransform(new Vector2(0.25f, 1.0f), ButtonArea.RectTransform), TextManager.Get("Close"));
ButtonArea.RectTransform.NonScaledSize = new Point(ButtonArea.Rect.Width, ContinueButton.Rect.Height);
@@ -405,10 +299,7 @@ namespace Barotrauma
public void CreateReputationInfoPanel(GUIComponent parent, CampaignMode campaignMode)
{
GUIListBox reputationList = new GUIListBox(new RectTransform(Vector2.One, parent.RectTransform))
{
Padding = new Vector4(4, 10, 0, 0) * GUI.Scale
};
GUIListBox reputationList = new GUIListBox(new RectTransform(Vector2.One, parent.RectTransform));
reputationList.ContentBackground.Color = Color.Transparent;
foreach (Faction faction in campaignMode.Factions.OrderBy(f => f.Prefab.MenuOrder).ThenBy(f => f.Prefab.Name))
@@ -506,6 +397,171 @@ namespace Barotrauma
}
}
private static GUIComponent CreateTraitorInfoPanel(GUIComponent parent, TraitorManager.TraitorResults traitorResults, float iconAnimDelay)
{
var traitorCharacter = traitorResults.GetTraitorClient()?.Character;
string resultTag =
traitorResults.VotedCorrectTraitor ?
traitorResults.ObjectiveSuccessful ? "traitor.blameresult.correct.objectivesuccessful" : "traitor.blameresult.correct.objectivefailed" :
"traitor.blameresult.failure";
var textContent = new List<LocalizedString>()
{
TextManager.GetWithVariable("traitor.blameresult", "[name]", traitorCharacter?.Name ?? "unknown"),
TextManager.Get(resultTag)
};
if (traitorResults.MoneyPenalty > 0)
{
textContent.Add(
TextManager.GetWithVariable(
"traitor.blameresult.failure.penalty",
"[money]",
TextManager.FormatCurrency(traitorResults.MoneyPenalty, includeCurrencySymbol: false)));
}
var icon = GUIStyle.GetComponentStyle("TraitorMissionIcon")?.GetDefaultSprite();
var content = CreateMissionEntry(
parent,
string.Empty,
textContent,
difficultyIconCount: 0,
icon, GUIStyle.Red,
out GUIImage missionIcon);
UpdateMissionStateIcon(traitorResults.VotedCorrectTraitor, missionIcon, iconAnimDelay);
return content;
}
public static GUIComponent CreateMissionEntry(GUIComponent parent, LocalizedString header, List<LocalizedString> textContent, int difficultyIconCount,
Sprite icon, Color iconColor, out GUIImage missionIcon)
{
int spacing = GUI.IntScale(5);
int defaultLineHeight = (int)GUIStyle.Font.MeasureChar('T').Y;
//make the icon big enough for header + some lines of text
int iconSize = (int)(GUIStyle.SubHeadingFont.MeasureChar('T').Y + defaultLineHeight * 6);
GUILayoutGroup content = new GUILayoutGroup(new RectTransform(new Point(parent.Rect.Width, iconSize), parent.RectTransform), isHorizontal: true)
{
Stretch = true,
AbsoluteSpacing = spacing,
CanBeFocused = true
};
if (icon != null)
{
missionIcon = new GUIImage(new RectTransform(new Point(iconSize), content.RectTransform), icon, null, true)
{
Color = iconColor,
HoverColor = iconColor,
SelectedColor = iconColor,
CanBeFocused = false
};
missionIcon.RectTransform.IsFixedSize = true;
}
else
{
missionIcon = null;
}
GUILayoutGroup missionTextGroup = new GUILayoutGroup(new RectTransform(new Vector2(0.744f, 0f), content.RectTransform, Anchor.CenterLeft), childAnchor: Anchor.TopLeft)
{
AbsoluteSpacing = spacing
};
content.Recalculate();
RichString missionNameString = RichString.Rich(header);
List<RichString> contentStrings = new List<RichString>(textContent.Select(t => RichString.Rich(t)));
if (!header.IsNullOrEmpty())
{
var nameText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), missionTextGroup.RectTransform),
missionNameString, font: GUIStyle.SubHeadingFont, wrap: true);
nameText.RectTransform.MinSize = new Point(0, (int)nameText.TextSize.Y);
}
GUILayoutGroup difficultyIndicatorGroup = null;
if (difficultyIconCount > 0)
{
difficultyIndicatorGroup = new GUILayoutGroup(new RectTransform(new Point(missionTextGroup.Rect.Width, defaultLineHeight), parent: missionTextGroup.RectTransform), isHorizontal: true, childAnchor: Anchor.CenterLeft)
{
AbsoluteSpacing = 1
};
difficultyIndicatorGroup.RectTransform.MinSize = new Point(0, defaultLineHeight);
var difficultyColor = Mission.GetDifficultyColor(difficultyIconCount);
for (int i = 0; i < difficultyIconCount; i++)
{
new GUIImage(new RectTransform(Vector2.One, difficultyIndicatorGroup.RectTransform, scaleBasis: ScaleBasis.Smallest), "DifficultyIndicator", scaleToFit: true)
{
CanBeFocused = false,
Color = difficultyColor
};
}
}
GUITextBlock firstContentText = null;
foreach (var contentString in contentStrings)
{
var text = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), missionTextGroup.RectTransform), contentString, wrap: true);
text.RectTransform.MinSize = new Point(0, (int)text.TextSize.Y);
firstContentText ??= text;
}
if (difficultyIndicatorGroup != null && firstContentText != null)
{
//make the icons align with the text content
difficultyIndicatorGroup.RectTransform.AbsoluteOffset = new Point((int)firstContentText.Padding.X, 0);
}
missionTextGroup.RectTransform.MinSize =
new Point(0, missionTextGroup.Children.Sum(c => c.Rect.Height + missionTextGroup.AbsoluteSpacing) - missionTextGroup.AbsoluteSpacing);
missionTextGroup.Recalculate();
content.RectTransform.MinSize = new Point(0, Math.Max(missionTextGroup.Rect.Height, iconSize));
return content;
}
public static void AddSeparators(GUIComponent container)
{
var children = container.Children.ToList();
if (children.Count < 2) { return; }
var lastChild = children.Last();
foreach (var child in children)
{
if (child != lastChild)
{
var separator = new GUIFrame(new RectTransform(new Vector2(0.5f, 0.1f), container.RectTransform), style: "HorizontalLine");
separator.RectTransform.RepositionChildInHierarchy(container.GetChildIndex(child) + 1);
}
}
}
public static void UpdateMissionStateIcon(bool success, GUIImage missionIcon, float delay = 0.5f)
{
if (missionIcon == null) { return; }
string style = success ? "MissionCompletedIcon" : "MissionFailedIcon";
GUIImage stateIcon = missionIcon.GetChild<GUIImage>();
if (string.IsNullOrEmpty(style))
{
if (stateIcon != null)
{
stateIcon.Visible = false;
}
}
else
{
bool wasVisible = stateIcon is { Visible: true };
stateIcon ??= new GUIImage(new RectTransform(Vector2.One, missionIcon.RectTransform, Anchor.Center), style, scaleToFit: true);
stateIcon.Visible = true;
if (!wasVisible)
{
stateIcon.FadeIn(delay, 0.15f);
stateIcon.Pulsate(Vector2.One, Vector2.One * 1.5f, 1.0f + delay);
}
}
}
private LocalizedString GetHeaderText(bool gameOver, CampaignMode.TransitionType transitionType)
{
string locationName = Submarine.MainSub is { AtEndExit: true } ? endLocation?.Name : startLocation?.Name;
@@ -568,7 +624,7 @@ namespace Barotrauma
return TextManager.GetWithVariables(textTag, ("[sub]", subName), ("[location]", locationName));
}
private GUIListBox CreateCrewList(GUIComponent parent, IEnumerable<CharacterInfo> characterInfos)
private GUIListBox CreateCrewList(GUIComponent parent, IEnumerable<CharacterInfo> characterInfos, TraitorManager.TraitorResults? traitorResults)
{
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)
{
@@ -602,16 +658,19 @@ namespace Barotrauma
headerFrame.RectTransform.RelativeSize -= new Vector2(crewList.ScrollBar.RectTransform.RelativeSize.X, 0.0f);
float delay = crewListAnimDelay;
foreach (CharacterInfo characterInfo in characterInfos)
{
if (characterInfo == null) { continue; }
CreateCharacterElement(characterInfo, crewList);
CreateCharacterElement(characterInfo, crewList, traitorResults, delay);
delay += crewListAnimDelay;
}
missionIconAnimDelay = delay;
return crewList;
}
private void CreateCharacterElement(CharacterInfo characterInfo, GUIListBox listBox)
private void CreateCharacterElement(CharacterInfo characterInfo, GUIListBox listBox, TraitorManager.TraitorResults? traitorResults, float animDelay)
{
GUIFrame frame = new GUIFrame(new RectTransform(new Point(listBox.Content.Rect.Width, GUI.IntScale(45)), listBox.Content.RectTransform), style: "ListBoxElement")
{
@@ -684,9 +743,31 @@ namespace Barotrauma
GUITextBlock statusBlock = new GUITextBlock(new RectTransform(new Point(statusColumnWidth, paddedFrame.Rect.Height), paddedFrame.RectTransform),
ToolBox.LimitString(statusText.Value, GUIStyle.Font, characterColumnWidth), textAlignment: Alignment.Center, textColor: statusColor);
frame.FadeIn(animDelay, 0.15f);
foreach (var child in frame.GetAllChildren())
{
child.FadeIn(animDelay, 0.15f);
}
if (traitorResults.HasValue && GameMain.NetworkMember != null)
{
var clientVotedAsTraitor = traitorResults.Value.GetTraitorClient();
bool isTraitor = clientVotedAsTraitor != null && clientVotedAsTraitor.Character == character;
if (isTraitor)
{
var img = new GUIImage(new RectTransform(new Point(paddedFrame.Rect.Height), paddedFrame.RectTransform, Anchor.CenterRight), style: "TraitorVoteButton")
{
IgnoreLayoutGroups = true,
ToolTip = TextManager.GetWithVariable("traitor.blameresult", "[name]", characterInfo.Name)
};
img.FadeIn(1.0f + animDelay, 0.15f);
img.Pulsate(Vector2.One, Vector2.One * 1.5f, 1.5f + animDelay);
}
}
}
private GUIFrame CreateReputationElement(GUIComponent parent,
private static GUIFrame CreateReputationElement(GUIComponent parent,
LocalizedString name, Reputation reputation, float initialReputation,
LocalizedString shortDescription, LocalizedString fullDescription, Sprite icon, Sprite backgroundPortrait, Color iconColor)
{