public override void Save(XElement element)
        {
            XElement modeElement = new XElement("SinglePlayerCampaign",
                                                new XAttribute("money", Money),
                                                new XAttribute("cheatsenabled", CheatsEnabled));

            //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)
            {
                if (c.Info == null)
                {
                    continue;
                }
                if (c.IsDead)
                {
                    CrewManager.RemoveCharacterInfo(c.Info);
                }
                c.Info.LastControlled = c == lastControlledCharacter;
                c.Info.HealthData     = new XElement("health");
                c.CharacterHealth.Save(c.Info.HealthData);
                if (c.Inventory != null)
                {
                    c.Info.InventoryData = new XElement("inventory");
                    c.SaveInventory(c.Inventory, c.Info.InventoryData);
                    c.Inventory?.DeleteAllItems();
                }
            }

            CrewManager.Save(modeElement);
            CampaignMetadata.Save(modeElement);
            Map.Save(modeElement);
            CargoManager?.SavePurchasedItems(modeElement);
            UpgradeManager?.SavePendingUpgrades(modeElement, UpgradeManager?.PendingUpgrades);
            element.Add(modeElement);
        }
        public override void Start()
        {
            base.Start();
            CargoManager.CreatePurchasedItems();
            UpgradeManager.ApplyUpgrades();
            UpgradeManager.SanityCheckUpgrades(Submarine.MainSub);

            if (!savedOnStart)
            {
                GUI.SetSavingIndicatorState(true);
                SaveUtil.SaveGame(GameMain.GameSession.SavePath);
                savedOnStart = true;
            }

            crewDead = false;
            endTimer = 5.0f;
            CrewManager.InitSinglePlayerRound();
            if (petsElement != null)
            {
                PetBehavior.LoadPets(petsElement);
            }
            CrewManager.LoadActiveOrders();

            GUI.DisableSavingIndicatorDelayed();
        }
예제 #3
0
        public SinglePlayerMode(GameModePreset preset, object param)
            : base(preset, param)
        {
            CargoManager = new CargoManager();

            endShiftButton           = new GUIButton(new Rectangle(GameMain.GraphicsWidth - 220, 20, 200, 25), "End shift", null, Alignment.TopLeft, Alignment.Center, "");
            endShiftButton.Font      = GUI.SmallFont;
            endShiftButton.OnClicked = TryEndShift;

            for (int i = 0; i < 3; i++)
            {
                JobPrefab jobPrefab = null;
                switch (i)
                {
                case 0:
                    jobPrefab = JobPrefab.List.Find(jp => jp.Name == "Captain");
                    break;

                case 1:
                    jobPrefab = JobPrefab.List.Find(jp => jp.Name == "Engineer");
                    break;

                case 2:
                    jobPrefab = JobPrefab.List.Find(jp => jp.Name == "Mechanic");
                    break;
                }

                CharacterInfo characterInfo =
                    new CharacterInfo(Character.HumanConfigFile, "", Gender.None, jobPrefab);
                CrewManager.characterInfos.Add(characterInfo);
            }
        }
예제 #4
0
        public void ServerRead(NetBuffer msg, Client sender)
        {
            UInt16 selectedLocIndex   = msg.ReadUInt16();
            UInt16 purchasedItemCount = msg.ReadUInt16();

            List <PurchasedItem> purchasedItems = new List <PurchasedItem>();

            for (int i = 0; i < purchasedItemCount; i++)
            {
                UInt16 itemPrefabIndex = msg.ReadUInt16();
                UInt16 itemQuantity    = msg.ReadUInt16();
                purchasedItems.Add(new PurchasedItem(MapEntityPrefab.List[itemPrefabIndex] as ItemPrefab, itemQuantity));
            }

            if (!sender.HasPermission(ClientPermissions.ManageCampaign))
            {
                DebugConsole.ThrowError("Client \"" + sender.Name + "\" does not have a permission to manage the campaign");
                return;
            }

            Map.SelectLocation(selectedLocIndex == UInt16.MaxValue ? -1 : selectedLocIndex);

            List <PurchasedItem> currentItems = new List <PurchasedItem>(CargoManager.PurchasedItems);

            foreach (PurchasedItem pi in currentItems)
            {
                CargoManager.SellItem(pi.itemPrefab, pi.quantity);
            }

            foreach (PurchasedItem pi in purchasedItems)
            {
                CargoManager.PurchaseItem(pi.itemPrefab, pi.quantity);
            }
        }
        /// <summary>
        /// Loads a previously saved single player campaign from XML
        /// </summary>
        private SinglePlayerCampaign(XElement element) : base(GameModePreset.SinglePlayerCampaign)
        {
            IsFirstRound = false;

            foreach (XElement subElement in element.Elements())
            {
                switch (subElement.Name.ToString().ToLowerInvariant())
                {
                case "crew":
                    GameMain.GameSession.CrewManager = new CrewManager(subElement, true);
                    break;

                case "map":
                    map = Map.Load(this, subElement);
                    break;

                case "metadata":
                    CampaignMetadata = new CampaignMetadata(this, subElement);
                    break;

                case "cargo":
                    CargoManager.LoadPurchasedItems(subElement);
                    break;

                case "pendingupgrades":
                    UpgradeManager = new UpgradeManager(this, subElement, isSingleplayer: true);
                    break;
                }
            }

            CampaignMetadata ??= new CampaignMetadata(this);

            UpgradeManager ??= new UpgradeManager(this);

            InitCampaignData();

            InitUI();

            Money         = element.GetAttributeInt("money", 0);
            CheatsEnabled = element.GetAttributeBool("cheatsenabled", false);
            if (CheatsEnabled)
            {
                DebugConsole.CheatsEnabled = true;
#if USE_STEAM
                if (!SteamAchievementManager.CheatsEnabled)
                {
                    SteamAchievementManager.CheatsEnabled = true;
                    new GUIMessageBox("Cheats enabled", "Cheat commands have been enabled on the campaign. You will not receive Steam Achievements until you restart the game.");
                }
#endif
            }

            if (map == null)
            {
                throw new System.Exception("Failed to load the campaign save file (saved with an older, incompatible version of Barotrauma).");
            }

            savedOnStart = true;
        }
예제 #6
0
        public override void Start()
        {
            base.Start();

            if (GameMain.Server != null)
            {
                CargoManager.CreateItems();
            }

            lastUpdateID++;
        }
        public override void Save(XElement element)
        {
            element.Add(new XAttribute("campaignid", CampaignID));
            XElement modeElement = new XElement("MultiPlayerCampaign",
                                                new XAttribute("money", Money),
                                                new XAttribute("purchasedlostshuttles", PurchasedLostShuttles),
                                                new XAttribute("purchasedhullrepairs", PurchasedHullRepairs),
                                                new XAttribute("purchaseditemrepairs", PurchasedItemRepairs),
                                                new XAttribute("cheatsenabled", CheatsEnabled));

            CampaignMetadata?.Save(modeElement);
            Map.Save(modeElement);
            CargoManager?.SavePurchasedItems(modeElement);
            UpgradeManager?.SavePendingUpgrades(modeElement, UpgradeManager?.PendingUpgrades);

            if (petsElement != null)
            {
                modeElement.Add(petsElement);
            }

            // save bots
            CrewManager.SaveMultiplayer(modeElement);

            // save available submarines
            XElement availableSubsElement = new XElement("AvailableSubs");

            for (int i = 0; i < GameMain.NetLobbyScreen.CampaignSubmarines.Count; i++)
            {
                availableSubsElement.Add(new XElement("Sub", new XAttribute("name", GameMain.NetLobbyScreen.CampaignSubmarines[i].Name)));
            }
            modeElement.Add(availableSubsElement);

            element.Add(modeElement);

            //save character data to a separate file
            string    characterDataPath = GetCharacterDataSavePath();
            XDocument characterDataDoc  = new XDocument(new XElement("CharacterData"));

            foreach (CharacterCampaignData cd in characterData)
            {
                characterDataDoc.Root.Add(cd.Save());
            }
            try
            {
                characterDataDoc.SaveSafe(characterDataPath);
            }
            catch (Exception e)
            {
                DebugConsole.ThrowError("Saving multiplayer campaign characters to \"" + characterDataPath + "\" failed!", e);
            }

            lastSaveID++;
            DebugConsole.Log("Campaign saved, save ID " + lastSaveID);
        }
예제 #8
0
        public override void Start()
        {
            CargoManager.CreateItems();

            if (!savedOnStart)
            {
                SaveUtil.SaveGame(GameMain.GameSession.SavePath);
                savedOnStart = true;
            }

            endTimer = 5.0f;

            isRunning = true;

            CrewManager.StartRound();
        }
        public override void Start()
        {
            base.Start();
            CargoManager.CreateItems();

            if (!savedOnStart)
            {
                SaveUtil.SaveGame(GameMain.GameSession.SavePath);
                savedOnStart = true;
            }

            crewDead  = false;
            endTimer  = 5.0f;
            isRunning = true;
            CrewManager.InitSinglePlayerRound();
        }
        public override void Start()
        {
            base.Start();
            CargoManager.CreatePurchasedItems();
            UpgradeManager.ApplyUpgrades();
            UpgradeManager.SanityCheckUpgrades(Submarine.MainSub);

            if (!savedOnStart)
            {
                SaveUtil.SaveGame(GameMain.GameSession.SavePath);
                savedOnStart = true;
            }

            crewDead = false;
            endTimer = 5.0f;
            CrewManager.InitSinglePlayerRound();
        }
예제 #11
0
        public override void Save(XElement element)
        {
            XElement modeElement = new XElement("SinglePlayerCampaign",
                                                new XAttribute("money", Money),
                                                new XAttribute("purchasedlostshuttles", PurchasedLostShuttles),
                                                new XAttribute("purchasedhullrepairs", PurchasedHullRepairs),
                                                new XAttribute("purchaseditemrepairs", PurchasedItemRepairs),
                                                new XAttribute("cheatsenabled", CheatsEnabled));

            modeElement.Add(Settings.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)
            {
                if (c.Info == null)
                {
                    continue;
                }
                if (c.IsDead)
                {
                    CrewManager.RemoveCharacterInfo(c.Info);
                }
                c.Info.LastControlled = c == lastControlledCharacter;
                c.Info.HealthData     = new XElement("health");
                c.CharacterHealth.Save(c.Info.HealthData);
                if (c.Inventory != null)
                {
                    c.Info.InventoryData = new XElement("inventory");
                    c.SaveInventory();
                    c.Inventory?.DeleteAllItems();
                }
                c.Info.SaveOrderData();
            }

            petsElement = new XElement("pets");
            PetBehavior.SavePets(petsElement);
            modeElement.Add(petsElement);

            CrewManager.Save(modeElement);
            CampaignMetadata.Save(modeElement);
            Map.Save(modeElement);
            CargoManager?.SavePurchasedItems(modeElement);
            UpgradeManager?.Save(modeElement);
            element.Add(modeElement);
        }
예제 #12
0
 public CampaignMode(GameModePreset preset, object param)
     : base(preset, param)
 {
     Money        = InitialMoney;
     CargoManager = new CargoManager(this);
 }
예제 #13
0
 protected CampaignMode(GameModePreset preset)
     : base(preset)
 {
     Money        = InitialMoney;
     CargoManager = new CargoManager(this);
 }
        public override void Save(XElement element)
        {
            XElement modeElement = new XElement("SinglePlayerCampaign",
                                                // Refunds the money when save & quitting from the map if there are items selected in the store
                                                new XAttribute("money", Money + (CargoManager != null ? CargoManager.GetTotalItemCost() : 0)),
                                                new XAttribute("cheatsenabled", CheatsEnabled));

            CrewManager.Save(modeElement);
            Map.Save(modeElement);
            element.Add(modeElement);
        }
예제 #15
0
        public void ServerRead(IReadMessage msg, Client sender)
        {
            UInt16 selectedLocIndex      = msg.ReadUInt16();
            byte   selectedMissionIndex  = msg.ReadByte();
            bool   purchasedHullRepairs  = msg.ReadBoolean();
            bool   purchasedItemRepairs  = msg.ReadBoolean();
            bool   purchasedLostShuttles = msg.ReadBoolean();
            UInt16 purchasedItemCount    = msg.ReadUInt16();

            List <PurchasedItem> purchasedItems = new List <PurchasedItem>();

            for (int i = 0; i < purchasedItemCount; i++)
            {
                string itemPrefabIdentifier = msg.ReadString();
                int    itemQuantity         = msg.ReadRangedInteger(0, CargoManager.MaxQuantity);
                purchasedItems.Add(new PurchasedItem(ItemPrefab.Prefabs[itemPrefabIdentifier], itemQuantity));
            }

            if (!sender.HasPermission(ClientPermissions.ManageCampaign))
            {
                DebugConsole.ThrowError("Client \"" + sender.Name + "\" does not have a permission to manage the campaign");
                return;
            }

            if (purchasedHullRepairs != this.PurchasedHullRepairs)
            {
                if (purchasedHullRepairs && Money >= HullRepairCost)
                {
                    this.PurchasedHullRepairs = true;
                    Money -= HullRepairCost;
                }
                else if (!purchasedHullRepairs)
                {
                    this.PurchasedHullRepairs = false;
                    Money += HullRepairCost;
                }
            }
            if (purchasedItemRepairs != this.PurchasedItemRepairs)
            {
                if (purchasedItemRepairs && Money >= ItemRepairCost)
                {
                    this.PurchasedItemRepairs = true;
                    Money -= ItemRepairCost;
                }
                else if (!purchasedItemRepairs)
                {
                    this.PurchasedItemRepairs = false;
                    Money += ItemRepairCost;
                }
            }
            if (purchasedLostShuttles != this.PurchasedLostShuttles)
            {
                if (GameMain.GameSession?.SubmarineInfo != null &&
                    GameMain.GameSession.SubmarineInfo.LeftBehindSubDockingPortOccupied)
                {
                    GameMain.Server.SendDirectChatMessage(TextManager.FormatServerMessage("ReplaceShuttleDockingPortOccupied"), sender, ChatMessageType.MessageBox);
                }
                else if (purchasedLostShuttles && Money >= ShuttleReplaceCost)
                {
                    this.PurchasedLostShuttles = true;
                    Money -= ShuttleReplaceCost;
                }
                else if (!purchasedItemRepairs)
                {
                    this.PurchasedLostShuttles = false;
                    Money += ShuttleReplaceCost;
                }
            }

            Map.SelectLocation(selectedLocIndex == UInt16.MaxValue ? -1 : selectedLocIndex);
            if (Map.SelectedLocation == null)
            {
                Map.SelectRandomLocation(preferUndiscovered: true);
            }
            if (Map.SelectedConnection != null)
            {
                Map.SelectMission(selectedMissionIndex);
            }

            List <PurchasedItem> currentItems = new List <PurchasedItem>(CargoManager.PurchasedItems);

            foreach (PurchasedItem pi in currentItems)
            {
                CargoManager.SellItem(pi, pi.Quantity);
            }

            foreach (PurchasedItem pi in purchasedItems)
            {
                CargoManager.PurchaseItem(pi.ItemPrefab, pi.Quantity);
            }
        }
예제 #16
0
        public void ServerRead(IReadMessage msg, Client sender)
        {
            UInt16 currentLocIndex  = msg.ReadUInt16();
            UInt16 selectedLocIndex = msg.ReadUInt16();

            byte       selectedMissionCount   = msg.ReadByte();
            List <int> selectedMissionIndices = new List <int>();

            for (int i = 0; i < selectedMissionCount; i++)
            {
                selectedMissionIndices.Add(msg.ReadByte());
            }

            bool purchasedHullRepairs  = msg.ReadBoolean();
            bool purchasedItemRepairs  = msg.ReadBoolean();
            bool purchasedLostShuttles = msg.ReadBoolean();

            UInt16 buyCrateItemCount           = msg.ReadUInt16();
            List <PurchasedItem> buyCrateItems = new List <PurchasedItem>();

            for (int i = 0; i < buyCrateItemCount; i++)
            {
                string itemPrefabIdentifier = msg.ReadString();
                int    itemQuantity         = msg.ReadRangedInteger(0, CargoManager.MaxQuantity);
                buyCrateItems.Add(new PurchasedItem(ItemPrefab.Prefabs[itemPrefabIdentifier], itemQuantity));
            }

            UInt16 purchasedItemCount           = msg.ReadUInt16();
            List <PurchasedItem> purchasedItems = new List <PurchasedItem>();

            for (int i = 0; i < purchasedItemCount; i++)
            {
                string itemPrefabIdentifier = msg.ReadString();
                int    itemQuantity         = msg.ReadRangedInteger(0, CargoManager.MaxQuantity);
                purchasedItems.Add(new PurchasedItem(ItemPrefab.Prefabs[itemPrefabIdentifier], itemQuantity));
            }

            UInt16          soldItemCount = msg.ReadUInt16();
            List <SoldItem> soldItems     = new List <SoldItem>();

            for (int i = 0; i < soldItemCount; i++)
            {
                string itemPrefabIdentifier = msg.ReadString();
                UInt16 id       = msg.ReadUInt16();
                bool   removed  = msg.ReadBoolean();
                byte   sellerId = msg.ReadByte();
                soldItems.Add(new SoldItem(ItemPrefab.Prefabs[itemPrefabIdentifier], id, removed, sellerId));
            }

            ushort purchasedUpgradeCount = msg.ReadUInt16();
            List <PurchasedUpgrade> purchasedUpgrades = new List <PurchasedUpgrade>();

            for (int i = 0; i < purchasedUpgradeCount; i++)
            {
                string        upgradeIdentifier = msg.ReadString();
                UpgradePrefab prefab            = UpgradePrefab.Find(upgradeIdentifier);

                string          categoryIdentifier = msg.ReadString();
                UpgradeCategory category           = UpgradeCategory.Find(categoryIdentifier);

                int upgradeLevel = msg.ReadByte();

                if (category == null || prefab == null)
                {
                    continue;
                }
                purchasedUpgrades.Add(new PurchasedUpgrade(prefab, category, upgradeLevel));
            }

            ushort purchasedItemSwapCount = msg.ReadUInt16();
            List <PurchasedItemSwap> purchasedItemSwaps = new List <PurchasedItemSwap>();

            for (int i = 0; i < purchasedItemSwapCount; i++)
            {
                UInt16 itemToRemoveID = msg.ReadUInt16();
                Item   itemToRemove   = Entity.FindEntityByID(itemToRemoveID) as Item;

                string     itemToInstallIdentifier = msg.ReadString();
                ItemPrefab itemToInstall           = string.IsNullOrEmpty(itemToInstallIdentifier) ? null : ItemPrefab.Find(string.Empty, itemToInstallIdentifier);

                if (itemToRemove == null)
                {
                    continue;
                }

                purchasedItemSwaps.Add(new PurchasedItemSwap(itemToRemove, itemToInstall));
            }

            if (!AllowedToManageCampaign(sender))
            {
                DebugConsole.ThrowError("Client \"" + sender.Name + "\" does not have a permission to manage the campaign");
                return;
            }

            Location location            = Map.CurrentLocation;
            int      hullRepairCost      = location?.GetAdjustedMechanicalCost(HullRepairCost) ?? HullRepairCost;
            int      itemRepairCost      = location?.GetAdjustedMechanicalCost(ItemRepairCost) ?? ItemRepairCost;
            int      shuttleRetrieveCost = location?.GetAdjustedMechanicalCost(ShuttleReplaceCost) ?? ShuttleReplaceCost;

            if (purchasedHullRepairs != this.PurchasedHullRepairs)
            {
                if (purchasedHullRepairs && Money >= hullRepairCost)
                {
                    this.PurchasedHullRepairs = true;
                    Money -= hullRepairCost;
                }
                else if (!purchasedHullRepairs)
                {
                    this.PurchasedHullRepairs = false;
                    Money += hullRepairCost;
                }
            }
            if (purchasedItemRepairs != this.PurchasedItemRepairs)
            {
                if (purchasedItemRepairs && Money >= itemRepairCost)
                {
                    this.PurchasedItemRepairs = true;
                    Money -= itemRepairCost;
                }
                else if (!purchasedItemRepairs)
                {
                    this.PurchasedItemRepairs = false;
                    Money += itemRepairCost;
                }
            }
            if (purchasedLostShuttles != this.PurchasedLostShuttles)
            {
                if (GameMain.GameSession?.SubmarineInfo != null &&
                    GameMain.GameSession.SubmarineInfo.LeftBehindSubDockingPortOccupied)
                {
                    GameMain.Server.SendDirectChatMessage(TextManager.FormatServerMessage("ReplaceShuttleDockingPortOccupied"), sender, ChatMessageType.MessageBox);
                }
                else if (purchasedLostShuttles && Money >= shuttleRetrieveCost)
                {
                    this.PurchasedLostShuttles = true;
                    Money -= shuttleRetrieveCost;
                }
                else if (!purchasedItemRepairs)
                {
                    this.PurchasedLostShuttles = false;
                    Money += shuttleRetrieveCost;
                }
            }

            if (currentLocIndex < Map.Locations.Count && Map.AllowDebugTeleport)
            {
                Map.SetLocation(currentLocIndex);
            }

            Map.SelectLocation(selectedLocIndex == UInt16.MaxValue ? -1 : selectedLocIndex);
            if (Map.SelectedLocation == null)
            {
                Map.SelectRandomLocation(preferUndiscovered: true);
            }
            if (Map.SelectedConnection != null)
            {
                Map.SelectMission(selectedMissionIndices);
            }

            CheckTooManyMissions(Map.CurrentLocation, sender);

            List <PurchasedItem> currentBuyCrateItems = new List <PurchasedItem>(CargoManager.ItemsInBuyCrate);

            currentBuyCrateItems.ForEach(i => CargoManager.ModifyItemQuantityInBuyCrate(i.ItemPrefab, -i.Quantity));
            buyCrateItems.ForEach(i => CargoManager.ModifyItemQuantityInBuyCrate(i.ItemPrefab, i.Quantity));

            CargoManager.SellBackPurchasedItems(new List <PurchasedItem>(CargoManager.PurchasedItems));
            CargoManager.PurchaseItems(purchasedItems, false);

            // for some reason CargoManager.SoldItem is never cleared by the server, I've added a check to SellItems that ignores all
            // sold items that are removed so they should be discarded on the next message
            CargoManager.BuyBackSoldItems(new List <SoldItem>(CargoManager.SoldItems));
            CargoManager.SellItems(soldItems);

            foreach (var(prefab, category, _) in purchasedUpgrades)
            {
                UpgradeManager.PurchaseUpgrade(prefab, category);

                // unstable logging
                int price = prefab.Price.GetBuyprice(UpgradeManager.GetUpgradeLevel(prefab, category), Map?.CurrentLocation);
                int level = UpgradeManager.GetUpgradeLevel(prefab, category);
                GameServer.Log($"SERVER: Purchased level {level} {category.Identifier}.{prefab.Identifier} for {price}", ServerLog.MessageType.ServerMessage);
            }

            foreach (var purchasedItemSwap in purchasedItemSwaps)
            {
                if (purchasedItemSwap.ItemToInstall == null)
                {
                    UpgradeManager.CancelItemSwap(purchasedItemSwap.ItemToRemove);
                }
                else
                {
                    UpgradeManager.PurchaseItemSwap(purchasedItemSwap.ItemToRemove, purchasedItemSwap.ItemToInstall);
                }
            }
            foreach (Item item in Item.ItemList)
            {
                if (item.PendingItemSwap != null && !purchasedItemSwaps.Any(it => it.ItemToRemove == item))
                {
                    UpgradeManager.CancelItemSwap(item);
                    item.PendingItemSwap = null;
                }
            }
        }
예제 #17
0
        /// <summary>
        /// Loads the campaign from an XML element. Creates the map if it hasn't been created yet, otherwise updates the state of the map.
        /// </summary>
        private void Load(XElement element)
        {
            Money = element.GetAttributeInt("money", 0);
            PurchasedLostShuttles = element.GetAttributeBool("purchasedlostshuttles", false);
            PurchasedHullRepairs  = element.GetAttributeBool("purchasedhullrepairs", false);
            PurchasedItemRepairs  = element.GetAttributeBool("purchaseditemrepairs", false);
            CheatsEnabled         = element.GetAttributeBool("cheatsenabled", false);
            if (CheatsEnabled)
            {
                DebugConsole.CheatsEnabled = true;
#if USE_STEAM
                if (!SteamAchievementManager.CheatsEnabled)
                {
                    SteamAchievementManager.CheatsEnabled = true;
#if CLIENT
                    new GUIMessageBox("Cheats enabled", "Cheat commands have been enabled on the server. You will not receive Steam Achievements until you restart the game.");
#else
                    DebugConsole.NewMessage("Cheat commands have been enabled.", Color.Red);
#endif
                }
#endif
            }

#if SERVER
            List <SubmarineInfo> availableSubs = new List <SubmarineInfo>();
            List <SubmarineInfo> sourceList    = new List <SubmarineInfo>();
            sourceList.AddRange(SubmarineInfo.SavedSubmarines);
#endif

            foreach (XElement subElement in element.Elements())
            {
                switch (subElement.Name.ToString().ToLowerInvariant())
                {
                case "campaignsettings":
                    Settings = new CampaignSettings(subElement);
                    break;

                case "map":
                    if (map == null)
                    {
                        //map not created yet, loading this campaign for the first time
                        map = Map.Load(this, subElement, Settings);
                    }
                    else
                    {
                        //map already created, update it
                        //if we're not downloading the initial save file (LastSaveID > 0),
                        //show notifications about location type changes
                        map.LoadState(subElement, LastSaveID > 0);
                    }
                    break;

                case "metadata":
                    CampaignMetadata = new CampaignMetadata(this, subElement);
                    break;

                case "upgrademanager":
                case "pendingupgrades":
                    UpgradeManager = new UpgradeManager(this, subElement, isSingleplayer: false);
                    break;

                case "bots" when GameMain.NetworkMember != null && GameMain.NetworkMember.IsServer:
                    CrewManager.HasBots = subElement.GetAttributeBool("hasbots", false);
                    CrewManager.AddCharacterElements(subElement);
                    CrewManager.ActiveOrdersElement = subElement.GetChildElement("activeorders");
                    break;

                case "cargo":
                    CargoManager?.LoadPurchasedItems(subElement);
                    break;

                case "pets":
                    petsElement = subElement;
                    break;

#if SERVER
                case "availablesubs":
                    foreach (XElement availableSub in subElement.Elements())
                    {
                        string        subName     = availableSub.GetAttributeString("name", "");
                        SubmarineInfo matchingSub = sourceList.Find(s => s.Name == subName);
                        if (matchingSub != null)
                        {
                            availableSubs.Add(matchingSub);
                        }
                    }
                    break;
#endif
                }
            }

            CampaignMetadata ??= new CampaignMetadata(this);
            UpgradeManager ??= new UpgradeManager(this);

            InitCampaignData();
#if SERVER
            // Fallback if using a save with no available subs assigned, use vanilla submarines
            if (availableSubs.Count == 0)
            {
                GameMain.NetLobbyScreen.CampaignSubmarines.AddRange(sourceList.FindAll(s => s.IsCampaignCompatible && s.IsVanillaSubmarine()));
            }

            GameMain.NetLobbyScreen.CampaignSubmarines = availableSubs;

            characterData.Clear();
            string characterDataPath = GetCharacterDataSavePath();
            if (!File.Exists(characterDataPath))
            {
                DebugConsole.ThrowError($"Failed to load the character data for the campaign. Could not find the file \"{characterDataPath}\".");
            }
            else
            {
                var characterDataDoc = XMLExtensions.TryLoadXml(characterDataPath);
                if (characterDataDoc?.Root == null)
                {
                    return;
                }
                foreach (XElement subElement in characterDataDoc.Root.Elements())
                {
                    characterData.Add(new CharacterCampaignData(subElement));
                }
            }
#endif
        }
        public void ServerRead(NetBuffer msg, Client sender)
        {
            UInt16 selectedLocIndex     = msg.ReadUInt16();
            byte   selectedMissionIndex = msg.ReadByte();
            bool   purchasedHullRepairs = msg.ReadBoolean();
            bool   purchasedItemRepairs = msg.ReadBoolean();
            UInt16 purchasedItemCount   = msg.ReadUInt16();

            List <PurchasedItem> purchasedItems = new List <PurchasedItem>();

            for (int i = 0; i < purchasedItemCount; i++)
            {
                UInt16 itemPrefabIndex = msg.ReadUInt16();
                UInt16 itemQuantity    = msg.ReadUInt16();
                purchasedItems.Add(new PurchasedItem(MapEntityPrefab.List[itemPrefabIndex] as ItemPrefab, itemQuantity));
            }

            if (!sender.HasPermission(ClientPermissions.ManageCampaign))
            {
                DebugConsole.ThrowError("Client \"" + sender.Name + "\" does not have a permission to manage the campaign");
                return;
            }

            if (purchasedHullRepairs != this.PurchasedHullRepairs)
            {
                if (purchasedHullRepairs && Money >= HullRepairCost)
                {
                    this.PurchasedHullRepairs = true;
                    Money -= HullRepairCost;
                }
                else if (!purchasedHullRepairs)
                {
                    this.PurchasedHullRepairs = false;
                    Money += HullRepairCost;
                }
            }
            if (purchasedItemRepairs != this.PurchasedItemRepairs)
            {
                if (purchasedItemRepairs && Money >= ItemRepairCost)
                {
                    this.PurchasedItemRepairs = true;
                    Money -= ItemRepairCost;
                }
                else if (!purchasedItemRepairs)
                {
                    this.PurchasedItemRepairs = false;
                    Money += ItemRepairCost;
                }
            }

            Map.SelectLocation(selectedLocIndex == UInt16.MaxValue ? -1 : selectedLocIndex);
            if (Map.SelectedConnection != null)
            {
                Map.SelectMission(selectedMissionIndex);
            }

            List <PurchasedItem> currentItems = new List <PurchasedItem>(CargoManager.PurchasedItems);

            foreach (PurchasedItem pi in currentItems)
            {
                CargoManager.SellItem(pi, pi.Quantity);
            }

            foreach (PurchasedItem pi in purchasedItems)
            {
                CargoManager.PurchaseItem(pi.ItemPrefab, pi.Quantity);
            }
        }