Build 1.1.4.0

This commit is contained in:
Markus Isberg
2023-03-31 18:40:44 +03:00
parent efba17e0ff
commit 9470edead3
483 changed files with 17487 additions and 8548 deletions
@@ -1,5 +1,4 @@
using Barotrauma.Extensions;
using Barotrauma.Items.Components;
using Barotrauma.Networking;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
@@ -16,8 +15,6 @@ namespace Barotrauma
protected bool crewDead;
protected Color overlayColor;
protected LocalizedString overlayText, overlayTextBottom;
protected Color overlayTextColor;
protected Sprite overlaySprite;
private TransitionType prevCampaignUIAutoOpenType;
@@ -30,7 +27,13 @@ namespace Barotrauma
protected GUIFrame campaignUIContainer;
public CampaignUI CampaignUI;
public static CancellationTokenSource StartRoundCancellationToken { get; private set; }
public SlideshowPlayer SlideshowPlayer
{
get;
protected set;
}
private CancellationTokenSource startRoundCancellationToken;
public bool ForceMapUI
{
@@ -59,10 +62,19 @@ namespace Barotrauma
{
chatBox.ToggleOpen = wasChatBoxOpen;
}
if (!value && CampaignUI?.SelectedTab == InteractionType.PurchaseSub)
if (!value)
{
SubmarinePreview.Close();
switch (CampaignUI?.SelectedTab)
{
case InteractionType.PurchaseSub:
SubmarinePreview.Close();
break;
case InteractionType.MedicalClinic:
CampaignUI.MedicalClinic?.OnDeselected();
break;
}
}
showCampaignUI = value;
}
}
@@ -77,6 +89,7 @@ namespace Barotrauma
{
foreach (Mission mission in Missions.ToList())
{
if (!mission.Prefab.ShowStartMessage) { continue; }
new GUIMessageBox(
RichString.Rich(mission.Prefab.IsSideObjective ? TextManager.AddPunctuation(':', TextManager.Get("sideobjective"), mission.Name) : mission.Name),
RichString.Rich(mission.Description), Array.Empty<LocalizedString>(), type: GUIMessageBox.Type.InGame, icon: mission.Prefab.Icon)
@@ -108,6 +121,23 @@ namespace Barotrauma
{
return AllowedToManageCampaign(ClientPermissions.ManageMoney);
}
protected GUIButton CreateEndRoundButton()
{
int buttonWidth = (int)(450 * GUI.xScale * (GUI.IsUltrawide ? 3.0f : 1.0f));
int buttonHeight = (int)(40 * GUI.yScale);
var rectT = HUDLayoutSettings.ToRectTransform(new Rectangle((GameMain.GraphicsWidth / 2), HUDLayoutSettings.ButtonAreaTop.Center.Y, buttonWidth, buttonHeight), GUI.Canvas);
rectT.Pivot = Pivot.Center;
return new GUIButton(rectT, TextManager.Get("EndRound"), textAlignment: Alignment.Center, style: "EndRoundButton")
{
Pulse = true,
TextBlock =
{
Shadow = true,
AutoScaleHorizontal = true
}
};
}
public override void Draw(SpriteBatch spriteBatch)
{
@@ -123,32 +153,10 @@ namespace Barotrauma
{
GUI.DrawRectangle(spriteBatch, new Rectangle(0, 0, GameMain.GraphicsWidth, GameMain.GraphicsHeight), overlayColor, isFilled: true);
}
if (!overlayText.IsNullOrEmpty() && overlayTextColor.A > 0)
{
var backgroundSprite = GUIStyle.GetComponentStyle("CommandBackground").GetDefaultSprite();
Vector2 centerPos = new Vector2(GameMain.GraphicsWidth, GameMain.GraphicsHeight) / 2;
LocalizedString wrappedText = ToolBox.WrapText(overlayText, GameMain.GraphicsWidth / 3, GUIStyle.Font);
Vector2 textSize = GUIStyle.Font.MeasureString(wrappedText);
Vector2 textPos = centerPos - textSize / 2;
backgroundSprite.Draw(spriteBatch,
centerPos,
Color.White * (overlayTextColor.A / 255.0f),
origin: backgroundSprite.size / 2,
rotate: 0.0f,
scale: new Vector2(GameMain.GraphicsWidth / 2 / backgroundSprite.size.X, textSize.Y / backgroundSprite.size.Y * 1.5f));
GUI.DrawString(spriteBatch, textPos + Vector2.One, wrappedText, Color.Black * (overlayTextColor.A / 255.0f));
GUI.DrawString(spriteBatch, textPos, wrappedText, overlayTextColor);
if (!overlayTextBottom.IsNullOrEmpty())
{
Vector2 bottomTextPos = centerPos + new Vector2(0.0f, textSize.Y / 2 + 40 * GUI.Scale) - GUIStyle.Font.MeasureString(overlayTextBottom) / 2;
GUI.DrawString(spriteBatch, bottomTextPos + Vector2.One, overlayTextBottom.Value, Color.Black * (overlayTextColor.A / 255.0f));
GUI.DrawString(spriteBatch, bottomTextPos, overlayTextBottom.Value, overlayTextColor);
}
}
}
SlideshowPlayer?.DrawManually(spriteBatch);
if (GUI.DisableHUD || GUI.DisableUpperHUD || ForceMapUI || CoroutineManager.IsCoroutineRunning("LevelTransition"))
{
endRoundButton.Visible = false;
@@ -157,7 +165,7 @@ namespace Barotrauma
}
if (Submarine.MainSub == null || Level.Loaded == null) { return; }
endRoundButton.Visible = false;
bool allowEndingRound = false;
var availableTransition = GetAvailableTransition(out _, out Submarine leavingSub);
LocalizedString buttonText = "";
switch (availableTransition)
@@ -168,12 +176,12 @@ namespace Barotrauma
{
string textTag = availableTransition == TransitionType.ProgressToNextLocation ? "EnterLocation" : "EnterEmptyLocation";
buttonText = TextManager.GetWithVariable(textTag, "[locationname]", Level.Loaded.EndLocation?.Name ?? "[ERROR]");
endRoundButton.Visible = !ForceMapUI && !ShowCampaignUI;
allowEndingRound = !ForceMapUI && !ShowCampaignUI;
}
break;
case TransitionType.LeaveLocation:
buttonText = TextManager.GetWithVariable("LeaveLocation", "[locationname]", Level.Loaded.StartLocation?.Name ?? "[ERROR]");
endRoundButton.Visible = !ForceMapUI && !ShowCampaignUI;
allowEndingRound = !ForceMapUI && !ShowCampaignUI;
break;
case TransitionType.ReturnToPreviousLocation:
case TransitionType.ReturnToPreviousEmptyLocation:
@@ -181,31 +189,27 @@ namespace Barotrauma
{
string textTag = availableTransition == TransitionType.ReturnToPreviousLocation ? "EnterLocation" : "EnterEmptyLocation";
buttonText = TextManager.GetWithVariable(textTag, "[locationname]", Level.Loaded.StartLocation?.Name ?? "[ERROR]");
endRoundButton.Visible = !ForceMapUI && !ShowCampaignUI;
allowEndingRound = !ForceMapUI && !ShowCampaignUI;
}
break;
case TransitionType.None:
default:
if (Level.Loaded.Type == LevelData.LevelType.Outpost &&
!Level.Loaded.IsEndBiome &&
(Character.Controlled?.Submarine?.Info.Type == SubmarineType.Player || (Character.Controlled?.CurrentHull?.OutpostModuleTags.Contains("airlock".ToIdentifier()) ?? false)))
{
buttonText = TextManager.GetWithVariable("LeaveLocation", "[locationname]", Level.Loaded.StartLocation?.Name ?? "[ERROR]");
endRoundButton.Visible = !ForceMapUI && !ShowCampaignUI;
}
else
{
endRoundButton.Visible = false;
allowEndingRound = !ForceMapUI && !ShowCampaignUI;
}
break;
}
if (Level.IsLoadedOutpost && !ObjectiveManager.AllActiveObjectivesCompleted())
{
endRoundButton.Visible = false;
allowEndingRound = false;
}
if (ReadyCheckButton != null) { ReadyCheckButton.Visible = allowEndingRound; }
if (ReadyCheckButton != null) { ReadyCheckButton.Visible = endRoundButton.Visible; }
endRoundButton.Visible = allowEndingRound && Character.Controlled is { IsIncapacitated: false };
if (endRoundButton.Visible)
{
if (!AllowedToManageCampaign(ClientPermissions.ManageMap))
@@ -259,11 +263,11 @@ namespace Barotrauma
GUI.ClearCursorWait();
StartRoundCancellationToken = new CancellationTokenSource();
startRoundCancellationToken = new CancellationTokenSource();
var loadTask = Task.Run(async () =>
{
await Task.Yield();
Rand.ThreadId = Thread.CurrentThread.ManagedThreadId;
Rand.ThreadId = Environment.CurrentManagedThreadId;
try
{
GameMain.GameSession.StartRound(newLevel, mirrorLevel: mirror, startOutpost: GetPredefinedStartOutpost());
@@ -273,7 +277,8 @@ namespace Barotrauma
roundSummaryScreen.LoadException = e;
}
Rand.ThreadId = 0;
}, StartRoundCancellationToken.Token);
startRoundCancellationToken = null;
}, startRoundCancellationToken.Token);
TaskPool.Add("AsyncCampaignStartRound", loadTask, (t) =>
{
overlayColor = Color.Transparent;
@@ -283,6 +288,21 @@ namespace Barotrauma
return loadTask;
}
public void CancelStartRound()
{
startRoundCancellationToken?.Cancel();
}
public void ThrowIfStartRoundCancellationRequested()
{
if (startRoundCancellationToken != null &&
startRoundCancellationToken.Token.IsCancellationRequested)
{
startRoundCancellationToken.Token.ThrowIfCancellationRequested();
startRoundCancellationToken = null;
}
}
protected SubmarineInfo GetPredefinedStartOutpost()
{
if (Map?.CurrentLocation?.Type?.GetForcedOutpostGenerationParams() is OutpostGenerationParams parameters && !parameters.OutpostFilePath.IsNullOrEmpty())
@@ -316,10 +336,15 @@ namespace Barotrauma
goto default;
default:
ShowCampaignUI = true;
CampaignUI.SelectTab(npc.CampaignInteractionType, storeIdentifier: npc.MerchantIdentifier);
CampaignUI.SelectTab(npc.CampaignInteractionType, npc);
CampaignUI.UpgradeStore?.RequestRefresh();
break;
}
if (npc.AIController is HumanAIController humanAi && humanAi.IsInHostileFaction())
{
npc.Speak(TextManager.Get("dialoglowrepcampaigninteraction").Value, identifier: "dialoglowrepcampaigninteraction".ToIdentifier(), minDurationBetweenSimilar: 60.0f);
}
}
public override void AddToGUIUpdateList()
@@ -125,38 +125,25 @@ namespace Barotrauma
private void CreateButtons()
{
int buttonHeight = (int) (GUI.Scale * 40),
buttonWidth = GUI.IntScale(450),
buttonCenter = buttonHeight / 2,
screenMiddle = GameMain.GraphicsWidth / 2;
endRoundButton = new GUIButton(HUDLayoutSettings.ToRectTransform(new Rectangle(screenMiddle - buttonWidth / 2, HUDLayoutSettings.ButtonAreaTop.Center.Y - buttonCenter, buttonWidth, buttonHeight), GUI.Canvas),
TextManager.Get("EndRound"), textAlignment: Alignment.Center, style: "EndRoundButton")
endRoundButton = CreateEndRoundButton();
endRoundButton.OnClicked = (btn, userdata) =>
{
Pulse = true,
TextBlock =
{
Shadow = true,
AutoScaleHorizontal = true
},
OnClicked = (btn, userdata) =>
{
TryEndRoundWithFuelCheck(
onConfirm: () => GameMain.Client.RequestStartRound(),
onReturnToMapScreen: () =>
{
ShowCampaignUI = true;
if (CampaignUI == null) { InitCampaignUI(); }
CampaignUI.SelectTab(InteractionType.Map);
});
return true;
}
TryEndRoundWithFuelCheck(
onConfirm: () => GameMain.Client.RequestStartRound(),
onReturnToMapScreen: () =>
{
ShowCampaignUI = true;
if (CampaignUI == null) { InitCampaignUI(); }
CampaignUI.SelectTab(InteractionType.Map);
});
return true;
};
int readyButtonHeight = buttonHeight;
int readyButtonWidth = (int) (GUI.Scale * 50);
ReadyCheckButton = new GUIButton(HUDLayoutSettings.ToRectTransform(new Rectangle(screenMiddle + (buttonWidth / 2) + GUI.IntScale(16), HUDLayoutSettings.ButtonAreaTop.Center.Y - buttonCenter, readyButtonWidth, readyButtonHeight), GUI.Canvas),
int readyButtonWidth = (int)(GUI.Scale * 50 * (GUI.IsUltrawide ? 3.0f : 1.0f));
int readyButtonHeight = (int)(GUI.Scale * 40);
int readyButtonCenter = readyButtonHeight / 2,
screenMiddle = GameMain.GraphicsWidth / 2;
ReadyCheckButton = new GUIButton(HUDLayoutSettings.ToRectTransform(new Rectangle(screenMiddle + (endRoundButton.Rect.Width / 2) + GUI.IntScale(16), HUDLayoutSettings.ButtonAreaTop.Center.Y - readyButtonCenter, readyButtonWidth, readyButtonHeight), GUI.Canvas),
style: "RepairBuyButton")
{
ToolTip = TextManager.Get("ReadyCheck.Tooltip"),
@@ -216,51 +203,35 @@ namespace Barotrauma
}
Character prevControlled = Character.Controlled;
if (prevControlled?.AIController != null)
{
prevControlled.AIController.Enabled = false;
}
GUI.DisableHUD = true;
if (IsFirstRound)
{
Character.Controlled = null;
if (SlideshowPrefab.Prefabs.TryGet("campaignstart".ToIdentifier(), out var slideshow))
{
SlideshowPlayer = new SlideshowPlayer(GUICanvas.Instance, slideshow);
}
Character.Controlled = null;
prevControlled?.ClearInputs();
overlayColor = Color.LightGray;
overlaySprite = Map.CurrentLocation.Type.GetPortrait(Map.CurrentLocation.PortraitId);
overlayTextColor = Color.Transparent;
overlayText = TextManager.GetWithVariables("campaignstart",
("xxxx", Map.CurrentLocation.Name), ("yyyy", TextManager.Get($"submarineclass.{Submarine.MainSub.Info.SubmarineClass}")));
float fadeInDuration = 1.0f;
float textDuration = 10.0f;
float timer = 0.0f;
while (timer < textDuration)
{
if (GameMain.GameSession == null || Screen.Selected != GameMain.GameScreen)
{
GUI.DisableHUD = false;
yield return CoroutineStatus.Success;
}
// Try to grab the controlled here to prevent inputs, assigned late on multiplayer
if (Character.Controlled != null)
{
prevControlled = Character.Controlled;
Character.Controlled = null;
prevControlled.ClearInputs();
}
GameMain.GameScreen.Cam.Freeze = true;
overlayTextColor = Color.Lerp(Color.Transparent, Color.White, (timer - 1.0f) / fadeInDuration);
timer = Math.Min(timer + CoroutineManager.DeltaTime, textDuration);
yield return CoroutineStatus.Running;
}
var outpost = GameMain.GameSession.Level.StartOutpost;
var borders = outpost.GetDockedBorders();
borders.Location += outpost.WorldPosition.ToPoint();
GameMain.GameScreen.Cam.Position = new Vector2(borders.X + borders.Width / 2, borders.Y - borders.Height / 2);
float startZoom = 0.8f /
((float)Math.Max(borders.Width, borders.Height) / (float)GameMain.GameScreen.Cam.Resolution.X);
GameMain.GameScreen.Cam.MinZoom = Math.Min(startZoom, GameMain.GameScreen.Cam.MinZoom);
GameMain.GameScreen.Cam.Zoom = GameMain.GameScreen.Cam.MinZoom = Math.Min(startZoom, GameMain.GameScreen.Cam.MinZoom);
while (SlideshowPlayer != null && !SlideshowPlayer.LastTextShown)
{
GUI.PreventPauseMenuToggle = true;
yield return CoroutineStatus.Running;
}
GUI.PreventPauseMenuToggle = false;
prevControlled ??= Character.Controlled;
GameMain.LightManager.LosAlpha = 0.0f;
var transition = new CameraTransition(prevControlled, GameMain.GameScreen.Cam,
null, null,
fadeOut: false,
@@ -272,16 +243,6 @@ namespace Barotrauma
AllowInterrupt = true,
RemoveControlFromCharacter = false
};
fadeInDuration = 1.0f;
timer = 0.0f;
overlayTextColor = Color.Transparent;
overlayText = "";
while (timer < fadeInDuration)
{
overlayColor = Color.Lerp(Color.LightGray, Color.Transparent, timer / fadeInDuration);
timer += CoroutineManager.DeltaTime;
yield return CoroutineStatus.Running;
}
overlayColor = Color.Transparent;
while (transition.Running)
{
@@ -385,7 +346,7 @@ namespace Barotrauma
overlayColor = Color.Transparent;
if (DateTime.Now > timeOut) { GameMain.NetLobbyScreen.Select(); }
if (!(Screen.Selected is RoundSummaryScreen))
if (Screen.Selected is not RoundSummaryScreen)
{
if (continueButton != null)
{
@@ -409,6 +370,8 @@ namespace Barotrauma
base.Update(deltaTime);
SlideshowPlayer?.UpdateManually(deltaTime);
if (PlayerInput.SecondaryMouseButtonClicked() ||
PlayerInput.KeyHit(Microsoft.Xna.Framework.Input.Keys.Escape))
{
@@ -442,7 +405,8 @@ namespace Barotrauma
CampaignUI.SelectTab(InteractionType.Map);
}
}
else
//end biome is handled by the server (automatic transition without a map screen when the end of the level is reached)
else if (!Level.Loaded.IsEndBiome)
{
//wasn't initially docked (sub doesn't have a docking port?)
// -> choose a destination when the sub is far enough from the start outpost
@@ -467,11 +431,17 @@ namespace Barotrauma
}
}
public override void UpdateWhilePaused(float deltaTime)
{
SlideshowPlayer?.UpdateManually(deltaTime);
}
public override void End(TransitionType transitionType = TransitionType.None)
{
base.End(transitionType);
ForceMapUI = ShowCampaignUI = false;
SlideshowPlayer?.Finish();
// remove all event dialogue boxes
GUIMessageBox.MessageBoxes.ForEachMod(mb =>
{
@@ -501,7 +471,8 @@ namespace Barotrauma
{
GUIMessageBox.MessageBoxes.Remove(GUIMessageBox.VisibleBox);
}
CoroutineManager.StartCoroutine(DoEndCampaignCameraTransition(), "DoEndCampaignCameraTransition");
GameMain.CampaignEndScreen.Select();
GUI.DisableHUD = false;
GameMain.CampaignEndScreen.OnFinished = () =>
{
GameMain.NetLobbyScreen.Select();
@@ -510,32 +481,6 @@ namespace Barotrauma
};
}
private IEnumerable<CoroutineStatus> DoEndCampaignCameraTransition()
{
Character controlled = Character.Controlled;
if (controlled != null)
{
controlled.AIController.Enabled = false;
}
GUI.DisableHUD = true;
ISpatialEntity endObject = Level.Loaded.LevelObjectManager.GetAllObjects().FirstOrDefault(obj => obj.Prefab.SpawnPos == LevelObjectPrefab.SpawnPosType.LevelEnd);
var transition = new CameraTransition(endObject ?? Submarine.MainSub, GameMain.GameScreen.Cam,
null, Alignment.Center,
fadeOut: true,
panDuration: 10,
startZoom: null, endZoom: 0.2f);
while (transition.Running)
{
yield return CoroutineStatus.Running;
}
GameMain.CampaignEndScreen.Select();
GUI.DisableHUD = false;
yield return CoroutineStatus.Success;
}
public void ClientWrite(IWriteMessage msg)
{
System.Diagnostics.Debug.Assert(map.Locations.Count < UInt16.MaxValue);
@@ -844,8 +789,6 @@ namespace Barotrauma
{
DebugConsole.Log("Received campaign update (Reputation)");
UInt16 id = msg.ReadUInt16();
float? reputation = null;
if (msg.ReadBoolean()) { reputation = msg.ReadSingle(); }
Dictionary<Identifier, float> factionReps = new Dictionary<Identifier, float>();
byte factionsCount = msg.ReadByte();
for (int i = 0; i < factionsCount; i++)
@@ -854,11 +797,6 @@ namespace Barotrauma
}
if (ShouldApply(NetFlags.Reputation, id, requireUpToDateSave: true))
{
if (reputation.HasValue)
{
campaign.Map.CurrentLocation.Reputation.SetReputation(reputation.Value);
campaign?.CampaignUI?.UpgradeStore?.RequestRefresh();
}
foreach (var (identifier, rep) in factionReps)
{
Faction faction = campaign.Factions.FirstOrDefault(f => f.Prefab.Identifier == identifier);
@@ -871,6 +809,7 @@ namespace Barotrauma
DebugConsole.ThrowError($"Received an update for a faction that doesn't exist \"{identifier}\".");
}
}
campaign?.CampaignUI?.UpgradeStore?.RequestRefresh();
}
}
if (requiredFlags.HasFlag(NetFlags.CharacterInfo))
@@ -995,7 +934,9 @@ namespace Barotrauma
if (firedCharacter != null) { CrewManager.FireCharacter(firedCharacter); }
}
if (map?.CurrentLocation?.HireManager != null && CampaignUI?.CrewManagement != null)
if (map?.CurrentLocation?.HireManager != null && CampaignUI?.CrewManagement != null &&
/*can't apply until we have the latest save file*/
!NetIdUtils.IdMoreRecent(pendingSaveID, LastSaveID))
{
CampaignUI.CrewManagement.SetHireables(map.CurrentLocation, availableHires);
if (hiredCharacters.Any()) { CampaignUI.CrewManagement.ValidateHires(hiredCharacters); }
@@ -1010,25 +951,20 @@ namespace Barotrauma
foreach (NetWalletTransaction transaction in update.Transactions)
{
WalletInfo info = transaction.Info;
switch (transaction.CharacterID)
if (transaction.CharacterID.TryUnwrap(out var charID))
{
case Some<ushort> { Value: var charID }:
{
Character targetCharacter = Character.CharacterList?.FirstOrDefault(c => c.ID == charID);
if (targetCharacter is null) { break; }
Wallet wallet = targetCharacter.Wallet;
Character targetCharacter = Character.CharacterList?.FirstOrDefault(c => c.ID == charID);
if (targetCharacter is null) { break; }
Wallet wallet = targetCharacter.Wallet;
wallet.Balance = info.Balance;
wallet.RewardDistribution = info.RewardDistribution;
TryInvokeEvent(wallet, transaction.ChangedData, info);
break;
}
case None<ushort> _:
{
Bank.Balance = info.Balance;
TryInvokeEvent(Bank, transaction.ChangedData, info);
break;
}
wallet.Balance = info.Balance;
wallet.RewardDistribution = info.RewardDistribution;
TryInvokeEvent(wallet, transaction.ChangedData, info);
}
else
{
Bank.Balance = info.Balance;
TryInvokeEvent(Bank, transaction.ChangedData, info);
}
}
@@ -1043,7 +979,7 @@ namespace Barotrauma
public override bool TryPurchase(Client client, int price)
{
if (!AllowedToManageCampaign(ClientPermissions.ManageCampaign))
if (!AllowedToManageCampaign(ClientPermissions.ManageMoney))
{
return PersonalWallet.TryDeduct(price);
}
@@ -12,7 +12,13 @@ namespace Barotrauma
public override bool Paused
{
get { return ForceMapUI || CoroutineManager.IsCoroutineRunning("LevelTransition") || ShowCampaignUI && CampaignUI.SelectedTab == InteractionType.Map; }
get
{
return
ForceMapUI || CoroutineManager.IsCoroutineRunning("LevelTransition") ||
ShowCampaignUI && CampaignUI.SelectedTab == InteractionType.Map ||
(SlideshowPlayer != null && !SlideshowPlayer.LastTextShown);
}
}
public override void UpdateWhilePaused(float deltaTime)
@@ -31,6 +37,8 @@ namespace Barotrauma
}
}
SlideshowPlayer?.UpdateManually(deltaTime);
CrewManager.ChatBox?.Update(deltaTime);
CrewManager.UpdateReports();
}
@@ -77,9 +85,9 @@ namespace Barotrauma
/// </summary>
private SinglePlayerCampaign(string mapSeed, CampaignSettings settings) : base(GameModePreset.SinglePlayerCampaign, settings)
{
CampaignMetadata = new CampaignMetadata(this);
UpgradeManager = new UpgradeManager(this);
Settings = settings;
InitFactions();
map = new Map(this, mapSeed);
foreach (JobPrefab jobPrefab in JobPrefab.Prefabs)
{
@@ -89,7 +97,6 @@ namespace Barotrauma
CrewManager.AddCharacterInfo(new CharacterInfo(CharacterPrefab.HumanSpeciesName, jobOrJobPrefab: jobPrefab, variant: variant));
}
}
InitCampaignData();
InitUI();
}
@@ -99,6 +106,17 @@ namespace Barotrauma
private SinglePlayerCampaign(XElement element) : base(GameModePreset.SinglePlayerCampaign, CampaignSettings.Empty)
{
IsFirstRound = false;
foreach (var subElement in element.Elements())
{
switch (subElement.Name.ToString().ToLowerInvariant())
{
case "metadata":
CampaignMetadata.Load(subElement);
break;
}
}
InitFactions();
foreach (var subElement in element.Elements())
{
@@ -114,9 +132,6 @@ namespace Barotrauma
case "map":
map = Map.Load(this, subElement);
break;
case "metadata":
CampaignMetadata = new CampaignMetadata(this, subElement);
break;
case "cargo":
CargoManager.LoadPurchasedItems(subElement);
break;
@@ -133,14 +148,14 @@ namespace Barotrauma
case "stats":
LoadStats(subElement);
break;
case "eventmanager":
GameMain.GameSession.EventManager.Load(subElement);
break;
}
}
CampaignMetadata ??= new CampaignMetadata(this);
UpgradeManager ??= new UpgradeManager(this);
InitCampaignData();
InitUI();
//backwards compatibility for saves made prior to the addition of personal wallets
@@ -198,28 +213,14 @@ namespace Barotrauma
{
StartRound = () => { TryEndRound(); }
};
}
private void CreateEndRoundButton()
{
int buttonHeight = (int)(GUI.Scale * 40);
int buttonWidth = GUI.IntScale(450);
endRoundButton = new GUIButton(HUDLayoutSettings.ToRectTransform(new Rectangle((GameMain.GraphicsWidth / 2) - (buttonWidth / 2), HUDLayoutSettings.ButtonAreaTop.Center.Y - (buttonHeight / 2), buttonWidth, buttonHeight), GUI.Canvas),
TextManager.Get("EndRound"), textAlignment: Alignment.Center, style: "EndRoundButton")
endRoundButton = CreateEndRoundButton();
endRoundButton.OnClicked = (btn, userdata) =>
{
Pulse = true,
TextBlock =
{
Shadow = true,
AutoScaleHorizontal = true
},
OnClicked = (btn, userdata) =>
{
TryEndRoundWithFuelCheck(
onConfirm: () => TryEndRound(),
onReturnToMapScreen: () => { ShowCampaignUI = true; CampaignUI.SelectTab(InteractionType.Map); });
return true;
}
TryEndRoundWithFuelCheck(
onConfirm: () => TryEndRound(),
onReturnToMapScreen: () => { ShowCampaignUI = true; CampaignUI.SelectTab(InteractionType.Map); });
return true;
};
}
@@ -265,7 +266,6 @@ namespace Barotrauma
private IEnumerable<CoroutineStatus> DoLoadInitialLevel(LevelData level, bool mirror)
{
GameMain.GameSession.StartRound(level, mirrorLevel: mirror, startOutpost: GetPredefinedStartOutpost());
GameMain.GameScreen.Select();
@@ -296,34 +296,9 @@ namespace Barotrauma
if (IsFirstRound || showCampaignResetText)
{
overlayColor = Color.LightGray;
overlaySprite = Map.CurrentLocation.Type.GetPortrait(Map.CurrentLocation.PortraitId);
overlayTextColor = Color.Transparent;
overlayText = TextManager.GetWithVariables(showCampaignResetText ? "campaignend4" : "campaignstart",
("xxxx", Map.CurrentLocation.Name),
("yyyy", TextManager.Get("submarineclass." + Submarine.MainSub.Info.SubmarineClass)));
LocalizedString pressAnyKeyText = TextManager.Get("pressanykey");
float fadeInDuration = 2.0f;
float textDuration = 10.0f;
float timer = 0.0f;
while (true)
if (SlideshowPrefab.Prefabs.TryGet("campaignstart".ToIdentifier(), out var slideshow))
{
if (timer > fadeInDuration)
{
overlayTextBottom = pressAnyKeyText;
if (PlayerInput.GetKeyboardState.GetPressedKeys().Length > 0 || PlayerInput.PrimaryMouseButtonClicked())
{
break;
}
}
if (GameMain.GameSession == null)
{
GUI.DisableHUD = false;
yield return CoroutineStatus.Success;
}
overlayTextColor = Color.Lerp(Color.Transparent, Color.White, (timer - 1.0f) / fadeInDuration);
timer = Math.Min(timer + CoroutineManager.DeltaTime, textDuration);
yield return CoroutineStatus.Running;
SlideshowPlayer = new SlideshowPlayer(GUICanvas.Instance, slideshow);
}
var outpost = GameMain.GameSession.Level.StartOutpost;
var borders = outpost.GetDockedBorders();
@@ -331,7 +306,13 @@ namespace Barotrauma
GameMain.GameScreen.Cam.Position = new Vector2(borders.X + borders.Width / 2, borders.Y - borders.Height / 2);
float startZoom = 0.8f /
((float)Math.Max(borders.Width, borders.Height) / (float)GameMain.GameScreen.Cam.Resolution.X);
GameMain.GameScreen.Cam.MinZoom = Math.Min(startZoom, GameMain.GameScreen.Cam.MinZoom);
GameMain.GameScreen.Cam.Zoom = GameMain.GameScreen.Cam.MinZoom = Math.Min(startZoom, GameMain.GameScreen.Cam.MinZoom);
while (SlideshowPlayer != null && !SlideshowPlayer.LastTextShown)
{
GUI.PreventPauseMenuToggle = true;
yield return CoroutineStatus.Running;
}
GUI.PreventPauseMenuToggle = false;
var transition = new CameraTransition(prevControlled, GameMain.GameScreen.Cam,
null, null,
fadeOut: false,
@@ -343,17 +324,6 @@ namespace Barotrauma
AllowInterrupt = true,
RemoveControlFromCharacter = false
};
fadeInDuration = 1.0f;
timer = 0.0f;
overlayTextColor = Color.Transparent;
overlayText = "";
while (timer < fadeInDuration)
{
overlayColor = Color.Lerp(Color.LightGray, Color.Transparent, timer / fadeInDuration);
timer += CoroutineManager.DeltaTime;
yield return CoroutineStatus.Running;
}
overlayColor = Color.Transparent;
while (transition.Running)
{
yield return CoroutineStatus.Running;
@@ -440,61 +410,68 @@ namespace Barotrauma
TotalPassedLevels++;
break;
case TransitionType.ProgressToNextEmptyLocation:
Map.Visit(Map.CurrentLocation);
TotalPassedLevels++;
break;
case TransitionType.End:
EndCampaign();
IsFirstRound = true;
break;
}
Map.ProgressWorld(transitionType, GameMain.GameSession.RoundDuration);
var endTransition = new CameraTransition(Submarine.MainSub, GameMain.GameScreen.Cam, null,
transitionType == TransitionType.LeaveLocation ? Alignment.BottomCenter : Alignment.Center,
fadeOut: false,
panDuration: EndTransitionDuration);
Map.ProgressWorld(this, transitionType, GameMain.GameSession.RoundDuration);
GUI.ClearMessages();
Location portraitLocation = Map.SelectedLocation ?? Map.CurrentLocation;
overlaySprite = portraitLocation.Type.GetPortrait(portraitLocation.PortraitId);
float fadeOutDuration = endTransition.PanDuration;
float t = 0.0f;
while (t < fadeOutDuration || endTransition.Running)
{
t += CoroutineManager.DeltaTime;
overlayColor = Color.Lerp(Color.Transparent, Color.White, t / fadeOutDuration);
yield return CoroutineStatus.Running;
}
overlayColor = Color.White;
yield return CoroutineStatus.Running;
//--------------------------------------
if (success)
if (transitionType != TransitionType.End)
{
GameMain.GameSession.SubmarineInfo = new SubmarineInfo(GameMain.GameSession.Submarine);
SaveUtil.SaveGame(GameMain.GameSession.SavePath);
}
else
{
PendingSubmarineSwitch = null;
EnableRoundSummaryGameOverState();
}
var endTransition = new CameraTransition(Submarine.MainSub, GameMain.GameScreen.Cam, null,
transitionType == TransitionType.LeaveLocation ? Alignment.BottomCenter : Alignment.Center,
fadeOut: false,
panDuration: EndTransitionDuration);
CrewManager?.ClearCurrentOrders();
//--------------------------------------
SelectSummaryScreen(roundSummary, newLevel, mirror, () =>
{
GameMain.GameScreen.Select();
if (continueButton != null)
Location portraitLocation = Map.SelectedLocation ?? Map.CurrentLocation;
overlaySprite = portraitLocation.Type.GetPortrait(portraitLocation.PortraitId);
float fadeOutDuration = endTransition.PanDuration;
float t = 0.0f;
while (t < fadeOutDuration || endTransition.Running)
{
continueButton.Visible = true;
t += CoroutineManager.DeltaTime;
overlayColor = Color.Lerp(Color.Transparent, Color.White, t / fadeOutDuration);
yield return CoroutineStatus.Running;
}
overlayColor = Color.White;
yield return CoroutineStatus.Running;
//--------------------------------------
if (success)
{
GameMain.GameSession.SubmarineInfo = new SubmarineInfo(GameMain.GameSession.Submarine);
SaveUtil.SaveGame(GameMain.GameSession.SavePath);
}
else
{
PendingSubmarineSwitch = null;
EnableRoundSummaryGameOverState();
}
GUI.DisableHUD = false;
GUI.ClearCursorWait();
overlayColor = Color.Transparent;
});
CrewManager?.ClearCurrentOrders();
SelectSummaryScreen(roundSummary, newLevel, mirror, () =>
{
GameMain.GameScreen.Select();
if (continueButton != null)
{
continueButton.Visible = true;
}
GUI.DisableHUD = false;
GUI.ClearCursorWait();
overlayColor = Color.Transparent;
});
}
GUI.SetSavingIndicatorState(false);
yield return CoroutineStatus.Success;
@@ -502,7 +479,10 @@ namespace Barotrauma
protected override void EndCampaignProjSpecific()
{
CoroutineManager.StartCoroutine(DoEndCampaignCameraTransition(), "DoEndCampaignCameraTransition");
GameMain.GameSession.SubmarineInfo = new SubmarineInfo(GameMain.GameSession.Submarine);
SaveUtil.SaveGame(GameMain.GameSession.SavePath);
GameMain.CampaignEndScreen.Select();
GUI.DisableHUD = false;
GameMain.CampaignEndScreen.OnFinished = () =>
{
showCampaignResetText = true;
@@ -511,39 +491,14 @@ namespace Barotrauma
};
}
private IEnumerable<CoroutineStatus> DoEndCampaignCameraTransition()
{
if (Character.Controlled != null)
{
Character.Controlled.AIController.Enabled = false;
Character.Controlled = null;
}
GUI.DisableHUD = true;
ISpatialEntity endObject = Level.Loaded.LevelObjectManager.GetAllObjects().FirstOrDefault(obj => obj.Prefab.SpawnPos == LevelObjectPrefab.SpawnPosType.LevelEnd);
var transition = new CameraTransition(endObject ?? Submarine.MainSub, GameMain.GameScreen.Cam,
null, Alignment.Center,
fadeOut: true,
panDuration: 10,
startZoom: null, endZoom: 0.2f);
while (transition.Running)
{
yield return CoroutineStatus.Running;
}
GameMain.GameSession.SubmarineInfo = new SubmarineInfo(GameMain.GameSession.Submarine);
SaveUtil.SaveGame(GameMain.GameSession.SavePath);
GameMain.CampaignEndScreen.Select();
GUI.DisableHUD = false;
yield return CoroutineStatus.Success;
}
public override void Update(float deltaTime)
{
if (CoroutineManager.IsCoroutineRunning("LevelTransition") || CoroutineManager.IsCoroutineRunning("SubmarineTransition") || gameOver) { return; }
base.Update(deltaTime);
SlideshowPlayer?.UpdateManually(deltaTime);
Map?.Radiation?.UpdateRadiation(deltaTime);
if (PlayerInput.SecondaryMouseButtonClicked() ||
@@ -594,11 +549,19 @@ namespace Barotrauma
CampaignUI.SelectTab(InteractionType.Map);
}
}
else if (Level.Loaded.IsEndBiome)
{
var transitionType = GetAvailableTransition(out _, out Submarine leavingSub);
if (transitionType == TransitionType.ProgressToNextLocation)
{
LoadNewLevel();
}
}
else
{
//wasn't initially docked (sub doesn't have a docking port?)
// -> choose a destination when the sub is far enough from the start outpost
if (!Submarine.MainSub.AtStartExit)
if (!Submarine.MainSub.AtStartExit && !Level.Loaded.StartOutpost.ExitPoints.Any())
{
ForceMapUI = true;
CampaignUI.SelectTab(InteractionType.Map);
@@ -608,11 +571,11 @@ namespace Barotrauma
else
{
var transitionType = GetAvailableTransition(out _, out Submarine leavingSub);
if (transitionType == TransitionType.End)
if (Level.Loaded.IsEndBiome && transitionType == TransitionType.ProgressToNextLocation)
{
EndCampaign();
LoadNewLevel();
}
if (transitionType == TransitionType.ProgressToNextLocation &&
else if (transitionType == TransitionType.ProgressToNextLocation &&
Level.Loaded.EndOutpost != null && Level.Loaded.EndOutpost.DockedTo.Contains(leavingSub))
{
LoadNewLevel();
@@ -725,6 +688,11 @@ namespace Barotrauma
modeElement.Add(Settings.Save());
modeElement.Add(SaveStats());
if (GameMain.GameSession?.EventManager != null)
{
modeElement.Add(GameMain.GameSession?.EventManager.Save());
}
//save and remove all items that are in someone's inventory so they don't get included in the sub file as well
foreach (Character c in Character.CharacterList)
{