Unstable 1.8.4.0

This commit is contained in:
Markus Isberg
2025-03-12 12:56:27 +00:00
parent a4c3e868e4
commit a4a3427e4e
627 changed files with 29860 additions and 10018 deletions
@@ -5,6 +5,7 @@ using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using Barotrauma.Networking;
namespace Barotrauma
{
@@ -19,7 +20,9 @@ namespace Barotrauma
protected GUIButton loadGameButton;
public Action<SubmarineInfo, string, string, CampaignSettings> StartNewGame;
public Action<string> LoadGame;
public delegate void LoadGameDelegate(string loadPath, Option<uint> backupIndex);
public LoadGameDelegate LoadGame;
protected enum CategoryFilter { All = 0, Vanilla = 1, Custom = 2 }
protected CategoryFilter subFilter = CategoryFilter.All;
@@ -142,6 +145,7 @@ namespace Barotrauma
public SettingValue<float> OxygenMultiplier;
public SettingValue<float> FuelMultiplier;
public SettingValue<float> MissionRewardMultiplier;
public SettingValue<float> ExperienceRewardMultiplier;
public SettingValue<float> ShopPriceMultiplier;
public SettingValue<float> ShipyardPriceMultiplier;
public SettingValue<float> RepairFailMultiplier;
@@ -164,6 +168,7 @@ namespace Barotrauma
OxygenMultiplier = OxygenMultiplier.GetValue(),
FuelMultiplier = FuelMultiplier.GetValue(),
MissionRewardMultiplier = MissionRewardMultiplier.GetValue(),
ExperienceRewardMultiplier = ExperienceRewardMultiplier.GetValue(),
ShopPriceMultiplier = ShopPriceMultiplier.GetValue(),
ShipyardPriceMultiplier = ShipyardPriceMultiplier.GetValue(),
RepairFailMultiplier = RepairFailMultiplier.GetValue(),
@@ -341,6 +346,19 @@ namespace Barotrauma
verticalSize,
OnValuesChanged);
// Experience reward multiplier
CampaignSettings.MultiplierSettings experienceMultiplierSettings = CampaignSettings.GetMultiplierSettings("ExperienceRewardMultiplier");
SettingValue<float> experienceMultiplier = CreateGUIFloatInputCarousel(
settingsList.Content,
TextManager.Get("campaignoption.experiencerewardmultiplier"),
TextManager.Get("campaignoption.experiencerewardmultiplier.tooltip"),
prevSettings.ExperienceRewardMultiplier,
valueStep: experienceMultiplierSettings.Step,
minValue: experienceMultiplierSettings.Min,
maxValue: experienceMultiplierSettings.Max,
verticalSize,
OnValuesChanged);
// Shop buying prices multiplier
CampaignSettings.MultiplierSettings shopPriceMultiplierSettings = CampaignSettings.GetMultiplierSettings("ShopPriceMultiplier");
SettingValue<float> shopPriceMultiplier = CreateGUIFloatInputCarousel(
@@ -498,6 +516,7 @@ namespace Barotrauma
oxygenMultiplier.SetValue(settings.OxygenMultiplier);
fuelMultiplier.SetValue(settings.FuelMultiplier);
rewardMultiplier.SetValue(settings.MissionRewardMultiplier);
experienceMultiplier.SetValue(settings.ExperienceRewardMultiplier);
shopPriceMultiplier.SetValue(settings.ShopPriceMultiplier);
shipyardPriceMultiplier.SetValue(settings.ShipyardPriceMultiplier);
repairFailMultiplier.SetValue(settings.RepairFailMultiplier);
@@ -527,6 +546,7 @@ namespace Barotrauma
OxygenMultiplier = oxygenMultiplier,
FuelMultiplier = fuelMultiplier,
MissionRewardMultiplier = rewardMultiplier,
ExperienceRewardMultiplier = experienceMultiplier,
ShopPriceMultiplier = shopPriceMultiplier,
ShipyardPriceMultiplier = shipyardPriceMultiplier,
RepairFailMultiplier = repairFailMultiplier,
@@ -821,5 +841,119 @@ namespace Barotrauma
return true;
}
protected void CreateBackupMenu(IEnumerable<SaveUtil.BackupIndexData> indexData, Action<SaveUtil.BackupIndexData> loadBackup)
{
var backupPopup = new GUIMessageBox("", "", new[] { TextManager.Get("Load"), TextManager.Get("Cancel") }, new Vector2(0.3f, 0.5f), minSize: new Point(500, 500));
GUILayoutGroup campaignSettingContent = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.8f), backupPopup.Content.RectTransform, Anchor.TopCenter));
GUIListBox backupList = new GUIListBox(new RectTransform(Vector2.One, campaignSettingContent.RectTransform));
bool isIronman = GameMain.NetworkMember?.ServerSettings is { IronmanModeActive: true };
if (!indexData.Any() || isIronman)
{
LocalizedString errorMsg = isIronman
? TextManager.Get("ironmanmodebackupdisclaimer")
: TextManager.Get("nobackups");
var errorBlock = new GUITextBlock(new RectTransform(Vector2.One, campaignSettingContent.RectTransform), errorMsg, font: GUIStyle.SubHeadingFont, textAlignment: Alignment.Center)
{
TextColor = GUIStyle.Red,
IgnoreLayoutGroups = true
};
if (errorBlock.Font.MeasureString(errorMsg).X > campaignSettingContent.Rect.Width)
{
errorBlock.Wrap = true;
errorBlock.SetTextPos();
}
}
if (!isIronman)
{
foreach (var data in indexData.OrderByDescending(static i => i.SaveTime))
{
GUIFrame indexFrame = new GUIFrame(
new RectTransform(new Vector2(1.0f, 1f / SaveUtil.MaxBackupCount), backupList.Content.RectTransform), style: "ListBoxElement")
{
UserData = data
};
GUILayoutGroup indexLayout = new GUILayoutGroup(
new RectTransform(Vector2.One, indexFrame.RectTransform),
isHorizontal: true,
childAnchor: Anchor.CenterLeft)
{
RelativeSpacing = 0.05f,
Stretch = true
};
GUILayoutGroup leftLayout = new GUILayoutGroup(new RectTransform(new Vector2(0.5f, 0.8f), indexLayout.RectTransform), childAnchor: Anchor.TopCenter)
{
RelativeSpacing = 0.05f,
Stretch = true
};
LocalizedString locationName = data.LocationType.IsEmpty || data.LocationNameIdentifier.IsEmpty ?
TextManager.Get("unknown") :
Location.GetName(data.LocationType, data.LocationNameFormatIndex, data.LocationNameIdentifier);
var locationNameBlock = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.5f), leftLayout.RectTransform), locationName, textAlignment: Alignment.CenterLeft)
{
TextColor = Color.White
};
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.5f), leftLayout.RectTransform), TextManager.Get($"savestate.{data.LevelType}"), textAlignment: Alignment.CenterLeft);
GUILayoutGroup rightLayout = new GUILayoutGroup(new RectTransform(new Vector2(0.5f, 0.8f), indexLayout.RectTransform), childAnchor: Anchor.TopCenter)
{
RelativeSpacing = 0.05f,
Stretch = true
};
TimeSpan difference = SerializableDateTime.UtcNow - data.SaveTime;
double totalMinutes = difference.TotalMinutes;
LocalizedString timeFormat = totalMinutes switch
{
< 1 => TextManager.Get("subeditor.savedjustnow"),
> 60 => TextManager.GetWithVariable("saveagehours", "[hours]", ((int)Math.Floor(difference.TotalHours)).ToString()),
_ => TextManager.GetWithVariable("subeditor.saveageminutes", "[minutes]", difference.Minutes.ToString())
};
new GUITextBlock(new RectTransform(Vector2.One, rightLayout.RectTransform), timeFormat, textAlignment: Alignment.CenterRight);
locationNameBlock.Text = ToolBox.LimitString(locationName, locationNameBlock.Font, locationNameBlock.Rect.Width);
}
}
backupList.AfterSelected = (selected, _) =>
{
// to my understanding, there's no way to unselect an item in a GUIListBox
// so no need to check if selected is null
backupPopup.Buttons[0].Enabled = true;
return true;
};
backupPopup.Buttons[1].OnClicked += (button, o) =>
{
backupPopup.Close();
return true;
};
backupPopup.Buttons[0].Enabled = false;
backupPopup.Buttons[0].OnClicked += (button, o) =>
{
if (backupList.SelectedComponent?.UserData is not SaveUtil.BackupIndexData selectedIndexData) { return false; }
backupPopup.Close();
loadBackup?.Invoke(selectedIndexData);
return true;
};
}
}
}
@@ -1,12 +1,16 @@
using Microsoft.Xna.Framework;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using Barotrauma.Networking;
namespace Barotrauma
{
class MultiPlayerCampaignSetupUI : CampaignSetupUI
{
private GUIButton rollbackSaveButton;
private GUIButton deleteMpSaveButton;
private int prevInitialMoney;
@@ -232,34 +236,140 @@ namespace Barotrauma
{
if (saveList.SelectedData is not CampaignMode.SaveInfo saveInfo) { return false; }
if (string.IsNullOrWhiteSpace(saveInfo.FilePath)) { return false; }
LoadGame?.Invoke(saveInfo.FilePath);
CoroutineManager.StartCoroutine(WaitForCampaignSetup(), "WaitForCampaignSetup");
if (saveInfo.RespawnMode != RespawnMode.None && saveInfo.RespawnMode != GameMain.NetworkMember?.ServerSettings?.RespawnMode)
{
var msgBox = new GUIMessageBox(TextManager.Get("Warning"),
TextManager.GetWithVariables("RespawnModeMismatch",
("[currentrespawnmode]", TextManager.Get($"respawnmode.{GameMain.NetworkMember?.ServerSettings?.RespawnMode}")),
("[savedrespawnmode]", TextManager.Get($"respawnmode.{saveInfo.RespawnMode}"))),
new LocalizedString[] { TextManager.Get("RespawnModeMismatch.GoBack"), TextManager.Get("RespawnModeMismatch.LoadAnyway") });
msgBox.Buttons[0].OnClicked = (button, obj) =>
{
msgBox.Close();
return true;
};
msgBox.Buttons[1].OnClicked = (button, obj) =>
{
msgBox.Close();
LoadSaveGame();
return true;
};
return false;
}
LoadSaveGame();
return true;
void LoadSaveGame()
{
LoadGame?.Invoke(saveInfo.FilePath, backupIndex: Option.None);
CoroutineManager.StartCoroutine(WaitForCampaignSetup(), "WaitForCampaignSetup");
}
},
Enabled = false
};
deleteMpSaveButton = new GUIButton(new RectTransform(new Vector2(0.45f, 0.12f), loadGameContainer.RectTransform, Anchor.BottomLeft),
TextManager.Get("Delete"), style: "GUIButtonSmall")
GUILayoutGroup leftButtonContainer = new GUILayoutGroup(new RectTransform(new Vector2(0.45f, 0.15f), loadGameContainer.RectTransform, Anchor.BottomLeft))
{
RelativeSpacing = 0.05f,
Stretch = true
};
rollbackSaveButton = new GUIButton(new RectTransform(new Vector2(1f, 0.5f), leftButtonContainer.RectTransform), TextManager.Get("rollbackbutton"), style: "GUIButtonSmallFreeScale")
{
Visible = false,
ToolTip = TextManager.Get("backuptooltip"),
OnClicked = ViewBackupSaveMenu
};
deleteMpSaveButton = new GUIButton(new RectTransform(new Vector2(1f, 0.5f), leftButtonContainer.RectTransform),
TextManager.Get("Delete"), style: "GUIButtonSmallFreeScale")
{
OnClicked = DeleteSave,
Visible = false
};
}
}
private bool ViewBackupSaveMenu(GUIButton button, object obj)
{
if (obj is not CampaignMode.SaveInfo saveInfo) { return false; }
if (string.IsNullOrWhiteSpace(saveInfo.FilePath)) { return false; }
if (GameMain.Client.IsServerOwner)
{
CreateBackupMenu(SaveUtil.GetIndexData(saveInfo.FilePath), index =>
{
LoadGame(saveInfo.FilePath, backupIndex: Option.Some(index.Index));
});
}
else
{
RequestBackupIndexData(saveInfo.FilePath);
}
return true;
}
private const string PleaseWaitUserData = "PleaseWaitPopup";
private void RequestBackupIndexData(string savePath)
{
if (GameMain.Client == null) { return; }
GUI.SetCursorWaiting();
var msgBox = new GUIMessageBox(TextManager.Get("CampaignStartingPleaseWait"), TextManager.Get("CampaignStarting"), new[] { TextManager.Get("Cancel") })
{
UserData = PleaseWaitUserData
};
msgBox.Buttons[0].OnClicked = (btn, obj) =>
{
GUI.ClearCursorWait();
return true;
};
IWriteMessage msg = new WriteOnlyMessage().WithHeader(ClientPacketHeader.REQUEST_BACKUP_INDICES);
msg.WriteString(savePath);
GameMain.Client?.ClientPeer?.Send(msg, DeliveryMethod.Reliable);
}
public void OnBackupIndicesReceived(IReadMessage message)
{
GUI.ClearCursorWait();
foreach (GUIComponent component in GUIMessageBox.MessageBoxes.Where(static mb => mb.UserData is PleaseWaitUserData).ToArray())
{
if (component is GUIMessageBox msgBox)
{
msgBox.Close();
}
}
string path = message.ReadString();
var indexData = INetSerializableStruct.Read<NetCollection<SaveUtil.BackupIndexData>>(message);
CreateBackupMenu(indexData, selectedIndex =>
{
LoadGame?.Invoke(path, backupIndex: Option.Some(selectedIndex.Index));
});
}
private bool SelectSaveFile(GUIComponent component, object obj)
{
if (obj is not CampaignMode.SaveInfo saveInfo) { return true; }
string fileName = saveInfo.FilePath;
loadGameButton.Enabled = true;
rollbackSaveButton.Visible = true;
deleteMpSaveButton.Visible = deleteMpSaveButton.Enabled = GameMain.Client.IsServerOwner;
deleteMpSaveButton.Enabled = GameMain.GameSession?.SavePath != fileName;
rollbackSaveButton.Enabled = deleteMpSaveButton.Enabled = GameMain.GameSession?.DataPath.LoadPath != fileName;
if (deleteMpSaveButton.Visible)
{
deleteMpSaveButton.UserData = saveInfo;
}
if (rollbackSaveButton.Visible)
{
rollbackSaveButton.UserData = saveInfo;
}
return true;
}
}
@@ -291,7 +291,7 @@ namespace Barotrauma
if (characterInfos.Count >= 3) { break; }
}
}
characterInfos.Sort((a, b) => Math.Sign(b.Job.MinKarma - a.Job.MinKarma));
characterInfos.Sort((a, b) => Math.Sign(a.Job.CampaignSetupUIOrder - b.Job.CampaignSetupUIOrder));
characterInfoColumns.ClearChildren();
CharacterMenus?.ForEach(m => m.Dispose());
@@ -632,7 +632,7 @@ namespace Barotrauma
saveFrame.GetChild<GUITextBlock>().TextColor = GUIStyle.Red;
continue;
}
if (docRoot.GetChildElement("multiplayercampaign") != null)
if (docRoot.GetAttributeBool("ismultiplayer", false))
{
//multiplayer campaign save in the wrong folder -> don't show the save
saveList.Content.RemoveChild(saveFrame);
@@ -653,8 +653,7 @@ namespace Barotrauma
{
if (saveList.SelectedData is not CampaignMode.SaveInfo saveInfo) { return false; }
if (string.IsNullOrWhiteSpace(saveInfo.FilePath)) { return false; }
LoadGame?.Invoke(saveInfo.FilePath);
LoadGame?.Invoke(saveInfo.FilePath, backupIndex: Option.None);
return true;
},
Enabled = false
@@ -685,6 +684,15 @@ namespace Barotrauma
string mapseed = docRoot.GetAttributeString("mapseed", "unknown");
Identifier locationNameIdentifier = docRoot.GetAttributeIdentifier("currentlocation", Identifier.Empty);
int locationNameFormatIndex = docRoot.GetAttributeInt("currentlocationnameformatindex", -1);
Identifier locationType = docRoot.GetAttributeIdentifier("locationtype", Identifier.Empty);
LevelData.LevelType levelType = docRoot.GetAttributeEnum("nextleveltype", LevelData.LevelType.LocationConnection);
LocalizedString locationName = locationType.IsEmpty || locationNameIdentifier.IsEmpty ?
LocalizedString.EmptyString :
Location.GetName(locationType, locationNameFormatIndex, locationNameIdentifier);
var saveFileFrame = new GUIFrame(
new RectTransform(new Vector2(0.45f, 0.6f), loadGameContainer.RectTransform, Anchor.TopRight)
{
@@ -708,6 +716,15 @@ namespace Barotrauma
RelativeOffset = new Vector2(0, 0.1f)
});
if (!locationName.IsNullOrEmpty())
{
new GUITextBlock(new RectTransform(new Vector2(1, 0), layoutGroup.RectTransform),
locationName, font: GUIStyle.SmallFont);
new GUITextBlock(new RectTransform(new Vector2(1, 0), layoutGroup.RectTransform),
TextManager.Get($"savestate.{levelType}"), font: GUIStyle.SmallFont);
//spacing
new GUIFrame(new RectTransform(new Vector2(0.0f, 0.05f), layoutGroup.RectTransform), style: null);
}
new GUITextBlock(new RectTransform(new Vector2(1, 0), layoutGroup.RectTransform),
$"{TextManager.Get("Submarine")} : {subName}", font: GUIStyle.SmallFont);
new GUITextBlock(new RectTransform(new Vector2(1, 0), layoutGroup.RectTransform),
@@ -715,15 +732,40 @@ namespace Barotrauma
new GUITextBlock(new RectTransform(new Vector2(1, 0), layoutGroup.RectTransform),
$"{TextManager.Get("MapSeed")} : {mapseed}", font: GUIStyle.SmallFont);
new GUIButton(new RectTransform(new Vector2(0.4f, 0.15f), saveFileFrame.RectTransform, Anchor.BottomCenter)
GUILayoutGroup buttonContainer = new GUILayoutGroup(new RectTransform(new Vector2(0.85f, 0.15f), saveFileFrame.RectTransform, Anchor.BottomCenter)
{
RelativeOffset = new Vector2(0, 0.1f)
}, TextManager.Get("Delete"), style: "GUIButtonSmall")
}, isHorizontal: true)
{
RelativeSpacing = 0.05f,
Stretch = true
};
new GUIButton(new RectTransform(new Vector2(0.5f, 1f), buttonContainer.RectTransform, Anchor.CenterLeft), TextManager.Get("Delete"), style: "GUIButtonSmall")
{
UserData = saveInfo,
OnClicked = DeleteSave
};
new GUIButton(new RectTransform(new Vector2(0.5f, 1f), buttonContainer.RectTransform, Anchor.CenterLeft), TextManager.Get("rollbackbutton"), style: "GUIButtonSmall")
{
UserData = saveInfo,
ToolTip = TextManager.Get("backuptooltip"),
OnClicked = ViewBackupMenu
};
return true;
}
private bool ViewBackupMenu(GUIButton btn, object obj)
{
if (obj is not CampaignMode.SaveInfo saveInfo) { return false; }
var indexData = SaveUtil.GetIndexData(saveInfo.FilePath);
CreateBackupMenu(indexData, index =>
{
LoadGame(saveInfo.FilePath, Option.Some(index.Index));
});
return true;
}