diff --git a/Barotrauma/BarotraumaClient/Source/GUI/GUI.cs b/Barotrauma/BarotraumaClient/Source/GUI/GUI.cs index e5b69cf47..17d991505 100644 --- a/Barotrauma/BarotraumaClient/Source/GUI/GUI.cs +++ b/Barotrauma/BarotraumaClient/Source/GUI/GUI.cs @@ -156,8 +156,12 @@ namespace Barotrauma if (spMode != null) { button = new GUIButton(new Rectangle(0, y, 0, 30), "Load previous", Alignment.CenterX, "", pauseMenu); - button.OnClicked += TogglePauseMenu; - button.OnClicked += GameMain.GameSession.LoadPrevious; + button.OnClicked += (btn, userData) => + { + TogglePauseMenu(btn, userData); + GameMain.GameSession.LoadPrevious(); + return true; + }; y += 60; } diff --git a/Barotrauma/BarotraumaClient/Source/GameSession/GameModes/SinglePlayerCampaign.cs b/Barotrauma/BarotraumaClient/Source/GameSession/GameModes/SinglePlayerCampaign.cs index 4b1ace179..5520396e5 100644 --- a/Barotrauma/BarotraumaClient/Source/GameSession/GameModes/SinglePlayerCampaign.cs +++ b/Barotrauma/BarotraumaClient/Source/GameSession/GameModes/SinglePlayerCampaign.cs @@ -219,8 +219,13 @@ namespace Barotrauma summaryScreen.RemoveChild(summaryScreen.children.Find(c => c is GUIButton)); var okButton = new GUIButton(new Rectangle(-120, 0, 100, 30), "Load game", Alignment.BottomRight, "", summaryScreen); - okButton.OnClicked += GameMain.GameSession.LoadPrevious; - okButton.OnClicked += (GUIButton button, object obj) => { GUIMessageBox.MessageBoxes.Remove(GUIMessageBox.VisibleBox); return true; }; + okButton.OnClicked += (GUIButton button, object obj) => + { + GameMain.GameSession.LoadPrevious(); + GameMain.LobbyScreen.Select(); + GUIMessageBox.MessageBoxes.Remove(GUIMessageBox.VisibleBox); + return true; + }; var quitButton = new GUIButton(new Rectangle(0, 0, 100, 30), "Quit", Alignment.BottomRight, "", summaryScreen); quitButton.OnClicked += GameMain.LobbyScreen.QuitToMainMenu; @@ -322,7 +327,7 @@ namespace Barotrauma GameMain.GameSession.CrewManager = new CrewManager(subElement); break; case "map": - campaign.map = Map.Load(subElement); + campaign.map = Map.LoadNew(subElement); break; } } diff --git a/Barotrauma/BarotraumaClient/Source/GameSession/GameSession.cs b/Barotrauma/BarotraumaClient/Source/GameSession/GameSession.cs index e63c9b25a..14f414a04 100644 --- a/Barotrauma/BarotraumaClient/Source/GameSession/GameSession.cs +++ b/Barotrauma/BarotraumaClient/Source/GameSession/GameSession.cs @@ -15,17 +15,6 @@ namespace Barotrauma get { return roundSummary; } } - public bool LoadPrevious(GUIButton button, object obj) - { - Submarine.Unload(); - - SaveUtil.LoadGame(savePath); - - GameMain.LobbyScreen.Select(); - - return true; - } - private bool ToggleInfoFrame(GUIButton button, object obj) { if (infoFrame == null) diff --git a/Barotrauma/BarotraumaClient/Source/Map/Map/Map.cs b/Barotrauma/BarotraumaClient/Source/Map/Map/Map.cs index c2a04f8f1..08985029d 100644 --- a/Barotrauma/BarotraumaClient/Source/Map/Map/Map.cs +++ b/Barotrauma/BarotraumaClient/Source/Map/Map/Map.cs @@ -11,6 +11,8 @@ namespace Barotrauma private static Texture2D iceCraters; private static Texture2D iceCrack; + private Location highlightedLocation; + public void Update(float deltaTime, Rectangle rect, float scale = 1.0f) { Vector2 rectCenter = new Vector2(rect.Center.X, rect.Center.Y); diff --git a/Barotrauma/BarotraumaClient/Source/Networking/GameClient.cs b/Barotrauma/BarotraumaClient/Source/Networking/GameClient.cs index fed309c87..b1298ebeb 100644 --- a/Barotrauma/BarotraumaClient/Source/Networking/GameClient.cs +++ b/Barotrauma/BarotraumaClient/Source/Networking/GameClient.cs @@ -1118,15 +1118,11 @@ namespace Barotrauma.Networking if (GameMain.GameSession.Submarine == null) { var gameSessionDoc = SaveUtil.LoadGameSessionDoc(GameMain.GameSession.SavePath); - string subPath = Path.Combine(SaveUtil.TempPath, ToolBox.GetAttributeString(gameSessionDoc.Root, "submarine", "")) + ".sub"; - + string subPath = Path.Combine(SaveUtil.TempPath, ToolBox.GetAttributeString(gameSessionDoc.Root, "submarine", "")) + ".sub"; GameMain.GameSession.Submarine = new Submarine(subPath, ""); } - else - { - SaveUtil.DecompressToDirectory(GameMain.GameSession.SavePath, SaveUtil.TempPath, null); - } + SaveUtil.LoadGame(GameMain.GameSession.SavePath, GameMain.GameSession); break; } } diff --git a/Barotrauma/BarotraumaClient/Source/Networking/GameServer.cs b/Barotrauma/BarotraumaClient/Source/Networking/GameServer.cs index 3b99be540..6179ce559 100644 --- a/Barotrauma/BarotraumaClient/Source/Networking/GameServer.cs +++ b/Barotrauma/BarotraumaClient/Source/Networking/GameServer.cs @@ -201,6 +201,15 @@ namespace Barotrauma.Networking void FinishUPnP() { upnpBox.Close(null, null); + + if (server.UPnP.Status == UPnPStatus.NotAvailable) + { + new GUIMessageBox("Error", "UPnP not available"); + } + else if (server.UPnP.Status == UPnPStatus.Discovering) + { + new GUIMessageBox("Error", "UPnP discovery timed out"); + } } public bool StartGameClicked(GUIButton button, object obj) diff --git a/Barotrauma/BarotraumaClient/Source/Screens/NetLobbyScreen.cs b/Barotrauma/BarotraumaClient/Source/Screens/NetLobbyScreen.cs index 3b0b72e9d..7374d0ce2 100644 --- a/Barotrauma/BarotraumaClient/Source/Screens/NetLobbyScreen.cs +++ b/Barotrauma/BarotraumaClient/Source/Screens/NetLobbyScreen.cs @@ -1181,6 +1181,10 @@ namespace Barotrauma var moneyText = new GUITextBlock(new Rectangle(120,0,200,20), "Money", "", Alignment.BottomLeft, Alignment.TopLeft, campaignContainer); moneyText.TextGetter = campaignUI.GetMoney; + + var restartText = new GUITextBlock(new Rectangle(-250, -20, 100, 30), "", "", Alignment.BottomRight, Alignment.BottomLeft, campaignContainer); + restartText.Font = GUI.SmallFont; + restartText.TextGetter = AutoRestartText; } modeList.Select(2, true); } diff --git a/Barotrauma/BarotraumaShared/Source/GameSession/GameModes/MultiplayerCampaign.cs b/Barotrauma/BarotraumaShared/Source/GameSession/GameModes/MultiplayerCampaign.cs index 4db6bb58c..cd284012f 100644 --- a/Barotrauma/BarotraumaShared/Source/GameSession/GameModes/MultiplayerCampaign.cs +++ b/Barotrauma/BarotraumaShared/Source/GameSession/GameModes/MultiplayerCampaign.cs @@ -73,7 +73,8 @@ namespace Barotrauma setupBox.Close(); - GameMain.NetLobbyScreen.ToggleCampaignMode(true); + GameMain.NetLobbyScreen.ToggleCampaignMode(true); + campaign.Map.SelectRandomLocation(true); SaveUtil.SaveGame(GameMain.GameSession.SavePath); campaign.LastSaveID++; }; @@ -86,7 +87,8 @@ namespace Barotrauma setupBox.Close(); - GameMain.NetLobbyScreen.ToggleCampaignMode(true); + GameMain.NetLobbyScreen.ToggleCampaignMode(true); + campaign.Map.SelectRandomLocation(true); }; var cancelButton = new GUIButton(new Rectangle(0,0,120,30), "Cancel", Alignment.BottomLeft, "", setupBox.InnerFrame); @@ -123,6 +125,7 @@ namespace Barotrauma campaign.SetDelegates(); GameMain.NetLobbyScreen.ToggleCampaignMode(true); + GameMain.GameSession.Map.SelectRandomLocation(true); SaveUtil.SaveGame(GameMain.GameSession.SavePath); campaign.LastSaveID++; @@ -145,6 +148,7 @@ namespace Barotrauma SaveUtil.LoadGame(saveFiles[saveIndex]); ((MultiplayerCampaign)GameMain.GameSession.GameMode).LastSaveID++; GameMain.NetLobbyScreen.ToggleCampaignMode(true); + GameMain.GameSession.Map.SelectRandomLocation(true); DebugConsole.NewMessage("Campaign loaded!", Color.Cyan); }); @@ -179,118 +183,103 @@ namespace Barotrauma { isRunning = false; - if (GameMain.Server != null) + if (GameMain.Client != null) { - lastUpdateID++; + GameMain.GameSession.EndRound(""); + return; + } + + lastUpdateID++; - bool success = - GameMain.Server.ConnectedClients.Any(c => c.inGame && c.Character != null && !c.Character.IsDead) || - (GameMain.Server.Character != null && !GameMain.Server.Character.IsDead); + bool success = + GameMain.Server.ConnectedClients.Any(c => c.inGame && c.Character != null && !c.Character.IsDead) || + (GameMain.Server.Character != null && !GameMain.Server.Character.IsDead); - /*if (success) + /*if (success) + { + if (subsToLeaveBehind == null || leavingSub == null) { - if (subsToLeaveBehind == null || leavingSub == null) + DebugConsole.ThrowError("Leaving submarine not selected -> selecting the closest one"); + + leavingSub = GetLeavingSub(); + + subsToLeaveBehind = GetSubsToLeaveBehind(leavingSub); + } + }*/ + + GameMain.GameSession.EndRound(""); + + //TODO: save player inventories between mp campaign rounds + + //remove all items that are in someone's inventory + foreach (Character c in Character.CharacterList) + { + if (c.Inventory == null) continue; + foreach (Item item in c.Inventory.Items) + { + if (item != null) item.Remove(); + } + } + + if (success) + { + bool atEndPosition = Submarine.MainSub.AtEndPosition; + + /*if (leavingSub != Submarine.MainSub && !leavingSub.DockedTo.Contains(Submarine.MainSub)) + { + Submarine.MainSub = leavingSub; + + GameMain.GameSession.Submarine = leavingSub; + + foreach (Submarine sub in subsToLeaveBehind) { - DebugConsole.ThrowError("Leaving submarine not selected -> selecting the closest one"); - - leavingSub = GetLeavingSub(); - - subsToLeaveBehind = GetSubsToLeaveBehind(leavingSub); + MapEntity.mapEntityList.RemoveAll(e => e.Submarine == sub && e is LinkedSubmarine); + LinkedSubmarine.CreateDummy(leavingSub, sub); } }*/ - GameMain.GameSession.EndRound(""); - - //TODO: save player inventories between mp campaign rounds - - //remove all items that are in someone's inventory - foreach (Character c in Character.CharacterList) + if (atEndPosition) { - if (c.Inventory == null) continue; - foreach (Item item in c.Inventory.Items) - { - if (item != null) item.Remove(); - } + Map.MoveToNextLocation(); + + //select a random location to make sure we've got some destination + //to head towards even if the host/clients don't select anything + map.SelectRandomLocation(true); } - if (success) - { - bool atEndPosition = Submarine.MainSub.AtEndPosition; - - /*if (leavingSub != Submarine.MainSub && !leavingSub.DockedTo.Contains(Submarine.MainSub)) - { - Submarine.MainSub = leavingSub; - - GameMain.GameSession.Submarine = leavingSub; - - foreach (Submarine sub in subsToLeaveBehind) - { - MapEntity.mapEntityList.RemoveAll(e => e.Submarine == sub && e is LinkedSubmarine); - LinkedSubmarine.CreateDummy(leavingSub, sub); - } - }*/ - - if (atEndPosition) - { - Map.MoveToNextLocation(); - } - - SaveUtil.SaveGame(GameMain.GameSession.SavePath); - } - - if (!success) - { -#if CLIENT - var summaryScreen = GUIMessageBox.VisibleBox; - if (summaryScreen != null) - { - summaryScreen = summaryScreen.children[0]; - summaryScreen.RemoveChild(summaryScreen.children.Find(c => c is GUIButton)); - - var okButton = new GUIButton(new Rectangle(-120, 0, 100, 30), "Load game", Alignment.BottomRight, "", summaryScreen); - okButton.OnClicked += GameMain.GameSession.LoadPrevious; - okButton.OnClicked += (GUIButton button, object obj) => { GUIMessageBox.MessageBoxes.Remove(GUIMessageBox.VisibleBox); return true; }; - - var quitButton = new GUIButton(new Rectangle(0, 0, 100, 30), "Quit", Alignment.BottomRight, "", summaryScreen); - quitButton.OnClicked += GameMain.LobbyScreen.QuitToMainMenu; - quitButton.OnClicked += (GUIButton button, object obj) => { GUIMessageBox.MessageBoxes.Remove(GUIMessageBox.VisibleBox); return true; }; - } -#endif - } - } - else - { - GameMain.GameSession.EndRound(""); + SaveUtil.SaveGame(GameMain.GameSession.SavePath); } } - public static MultiplayerCampaign Load(XElement element) + public static MultiplayerCampaign LoadNew(XElement element) { MultiplayerCampaign campaign = new MultiplayerCampaign(GameModePreset.list.Find(gm => gm.Name == "Campaign"), null); + campaign.Load(element); + campaign.SetDelegates(); + + return campaign; + } + + public void Load(XElement element) + { + Money = ToolBox.GetAttributeInt(element, "money", 0); foreach (XElement subElement in element.Elements()) { switch (subElement.Name.ToString().ToLowerInvariant()) { case "map": - campaign.map = Map.Load(subElement); + if (map == null) + { + map = Map.LoadNew(subElement); + } + else + { + map.Load(subElement); + } break; } } - - campaign.Money = ToolBox.GetAttributeInt(element, "money", 0); - - //backwards compatibility with older save files - if (campaign.map == null) - { - string mapSeed = ToolBox.GetAttributeString(element, "mapseed", "a"); - campaign.GenerateMap(mapSeed); - campaign.map.SetLocation(ToolBox.GetAttributeInt(element, "currentlocation", 0)); - } - - campaign.SetDelegates(); - - return campaign; } public override void Save(XElement element) diff --git a/Barotrauma/BarotraumaShared/Source/GameSession/GameSession.cs b/Barotrauma/BarotraumaShared/Source/GameSession/GameSession.cs index 6ccc38afe..78a8941bb 100644 --- a/Barotrauma/BarotraumaShared/Source/GameSession/GameSession.cs +++ b/Barotrauma/BarotraumaShared/Source/GameSession/GameSession.cs @@ -10,7 +10,7 @@ namespace Barotrauma public readonly EventManager EventManager; - public readonly GameMode GameMode; + public GameMode GameMode; //two locations used as the start and end in the MP mode private Location[] dummyLocations; @@ -51,19 +51,19 @@ namespace Barotrauma public Location StartLocation { - get + get { if (Map != null) return Map.CurrentLocation; - if (dummyLocations==null) + if (dummyLocations == null) { CreateDummyLocations(); } - return dummyLocations[0]; + return dummyLocations[0]; } } - + public Location EndLocation { get @@ -118,12 +118,11 @@ namespace Barotrauma Submarine.MainSub = submarine; GameMain.GameSession = this; - selectedSub.Name = ToolBox.GetAttributeString(doc.Root, "submarine", selectedSub.Name); - #if CLIENT CrewManager = new CrewManager(); #endif + foreach (XElement subElement in doc.Root.Elements()) { switch (subElement.Name.ToString().ToLowerInvariant()) @@ -135,11 +134,10 @@ namespace Barotrauma break; #endif case "multiplayercampaign": - GameMode = MultiplayerCampaign.Load(subElement); + GameMode = MultiplayerCampaign.LoadNew(subElement); break; } } - } private void CreateDummyLocations() @@ -162,6 +160,12 @@ namespace Barotrauma dummyLocations[i] = Location.CreateRandom(new Vector2((float)rand.NextDouble() * 10000.0f, (float)rand.NextDouble() * 10000.0f)); } } + + public void LoadPrevious() + { + Submarine.Unload(); + SaveUtil.LoadGame(savePath); + } public void StartRound(string levelSeed, bool loadSecondSub = false) { @@ -297,5 +301,31 @@ namespace Barotrauma } } + public void Load(XElement saveElement) + { + foreach (XElement subElement in saveElement.Elements()) + { + switch (subElement.Name.ToString().ToLowerInvariant()) + { +#if CLIENT + case "gamemode": //legacy support + case "singleplayercampaign": + GameMode = SinglePlayerCampaign.Load(subElement); + break; +#endif + case "multiplayercampaign": + MultiplayerCampaign mpCampaign = GameMode as MultiplayerCampaign; + if (mpCampaign == null) + { + DebugConsole.ThrowError("Error while loading a save file: the save file is for a multiplayer campaign but the current gamemode is "+GameMode.GetType().ToString()); + break; + } + + mpCampaign.Load(subElement); + break; + } + } + } + } } diff --git a/Barotrauma/BarotraumaShared/Source/Map/Map/Map.cs b/Barotrauma/BarotraumaShared/Source/Map/Map/Map.cs index 3118ef848..57eebfd0c 100644 --- a/Barotrauma/BarotraumaShared/Source/Map/Map/Map.cs +++ b/Barotrauma/BarotraumaShared/Source/Map/Map/Map.cs @@ -24,8 +24,6 @@ namespace Barotrauma private Location currentLocation; private Location selectedLocation; - private Location highlightedLocation; - private LocationConnection selectedConnection; public Action OnLocationSelected; @@ -66,35 +64,6 @@ namespace Barotrauma get { return locations; } } - public static Map Load(XElement element) - { - string mapSeed = ToolBox.GetAttributeString(element, "seed", "a"); - - int size = ToolBox.GetAttributeInt(element, "size", 1000); - Map map = new Map(mapSeed, size); - - map.SetLocation(ToolBox.GetAttributeInt(element, "currentlocation", 0)); - - string discoveredStr = ToolBox.GetAttributeString(element, "discovered", ""); - - string[] discoveredStrs = discoveredStr.Split(','); - for (int i = 0; i < discoveredStrs.Length; i++) - { - int index = -1; - if (int.TryParse(discoveredStrs[i], out index)) map.locations[index].Discovered = true; - } - - string passedStr = ToolBox.GetAttributeString(element, "passed", ""); - string[] passedStrs = passedStr.Split(','); - for (int i = 0; i < passedStrs.Length; i++) - { - int index = -1; - if (int.TryParse(passedStrs[i], out index)) map.connections[index].Passed = true; - } - - return map; - } - public Map(string seed, int size) { this.seed = seed; @@ -410,6 +379,54 @@ namespace Barotrauma OnLocationSelected?.Invoke(selectedLocation, selectedConnection); } + public void SelectRandomLocation(bool preferUndiscovered) + { + List nextLocations = currentLocation.Connections.Select(c => c.OtherLocation(currentLocation)).ToList(); + List undiscoveredLocations = nextLocations.FindAll(l => !l.Discovered); + + if (undiscoveredLocations.Count > 0 && preferUndiscovered) + { + SelectLocation(undiscoveredLocations[Rand.Int(undiscoveredLocations.Count, Rand.RandSync.Unsynced)]); + } + else + { + SelectLocation(nextLocations[Rand.Int(nextLocations.Count, Rand.RandSync.Unsynced)]); + } + } + + public static Map LoadNew(XElement element) + { + string mapSeed = ToolBox.GetAttributeString(element, "seed", "a"); + + int size = ToolBox.GetAttributeInt(element, "size", 1000); + Map map = new Map(mapSeed, size); + map.Load(element); + + return map; + } + + public void Load(XElement element) + { + SetLocation(ToolBox.GetAttributeInt(element, "currentlocation", 0)); + + string discoveredStr = ToolBox.GetAttributeString(element, "discovered", ""); + + string[] discoveredStrs = discoveredStr.Split(','); + for (int i = 0; i < discoveredStrs.Length; i++) + { + int index = -1; + if (int.TryParse(discoveredStrs[i], out index)) locations[index].Discovered = true; + } + + string passedStr = ToolBox.GetAttributeString(element, "passed", ""); + string[] passedStrs = passedStr.Split(','); + for (int i = 0; i < passedStrs.Length; i++) + { + int index = -1; + if (int.TryParse(passedStrs[i], out index)) connections[index].Passed = true; + } + } + public void Save(XElement element) { XElement mapElement = new XElement("map"); diff --git a/Barotrauma/BarotraumaShared/Source/Networking/GameServer.cs b/Barotrauma/BarotraumaShared/Source/Networking/GameServer.cs index fa3bac2b8..f34ccc704 100644 --- a/Barotrauma/BarotraumaShared/Source/Networking/GameServer.cs +++ b/Barotrauma/BarotraumaShared/Source/Networking/GameServer.cs @@ -190,17 +190,6 @@ namespace Barotrauma.Networking } FinishUPnP(); - -#if CLIENT - if (server.UPnP.Status == UPnPStatus.NotAvailable) - { - new GUIMessageBox("Error", "UPnP not available"); - } - else if (server.UPnP.Status == UPnPStatus.Discovering) - { - new GUIMessageBox("Error", "UPnP discovery timed out"); - } -#endif } if (isPublic) @@ -376,9 +365,9 @@ namespace Barotrauma.Networking (myCharacter == null || myCharacter.IsDead || myCharacter.IsUnconscious); //restart if all characters are dead or submarine is at the end of the level - if ((autoRestart && isCrewDead) - || - (EndRoundAtLevelEnd && Submarine.MainSub != null && Submarine.MainSub.AtEndPosition && Submarine.MainSubs[1]==null)) + if ((autoRestart && isCrewDead) + || + (EndRoundAtLevelEnd && Submarine.MainSub != null && Submarine.MainSub.AtEndPosition && Submarine.MainSubs[1] == null)) { if (AutoRestart && isCrewDead) { diff --git a/Barotrauma/BarotraumaShared/Source/Utils/SaveUtil.cs b/Barotrauma/BarotraumaShared/Source/Utils/SaveUtil.cs index 825554fe0..97c08c2fe 100644 --- a/Barotrauma/BarotraumaShared/Source/Utils/SaveUtil.cs +++ b/Barotrauma/BarotraumaShared/Source/Utils/SaveUtil.cs @@ -6,7 +6,7 @@ using System.Xml.Linq; namespace Barotrauma { - public partial class SaveUtil + partial class SaveUtil { public static string SaveFolder = "Data" + Path.DirectorySeparatorChar + "Saves"; public static string MultiplayerSaveFolder = "Data" + Path.DirectorySeparatorChar + "Saves" + Path.DirectorySeparatorChar + "Multiplayer"; @@ -92,6 +92,13 @@ namespace Barotrauma GameMain.GameSession = new GameSession(selectedSub, filePath, doc); } + public static void LoadGame(string filePath, GameSession gameSession) + { + DecompressToDirectory(filePath, TempPath, null); + XDocument doc = ToolBox.TryLoadXml(Path.Combine(TempPath, "gamesession.xml")); + gameSession.Load(doc.Root); + } + public static XDocument LoadGameSessionDoc(string filePath) { string tempPath = Path.Combine(SaveFolder, "temp"); @@ -110,8 +117,6 @@ namespace Barotrauma public static void DeleteSave(string filePath) { - //filePath = Path.Combine(SaveFolder, filePath + ".save"); - try { File.Delete(filePath);