v0.13.0.11
This commit is contained in:
@@ -205,6 +205,7 @@ namespace Barotrauma
|
||||
var item = new Item(itemPrefab, validContainer.Key.Item.Position, validContainer.Key.Item.Submarine)
|
||||
{
|
||||
SpawnedInOutpost = validContainer.Key.Item.SpawnedInOutpost,
|
||||
AllowStealing = validContainer.Key.Item.AllowStealing,
|
||||
OriginalModuleIndex = validContainer.Key.Item.OriginalModuleIndex,
|
||||
OriginalContainerID = validContainer.Key.Item.ID
|
||||
};
|
||||
|
||||
@@ -172,15 +172,15 @@ namespace Barotrauma
|
||||
|
||||
public void CreatePurchasedItems()
|
||||
{
|
||||
CreateItems(PurchasedItems);
|
||||
CreateItems(PurchasedItems, Submarine.MainSub);
|
||||
OnPurchasedItemsChanged?.Invoke();
|
||||
}
|
||||
|
||||
public static void CreateItems(List<PurchasedItem> itemsToSpawn)
|
||||
public static void CreateItems(List<PurchasedItem> itemsToSpawn, Submarine sub)
|
||||
{
|
||||
if (itemsToSpawn.Count == 0) { return; }
|
||||
|
||||
WayPoint wp = WayPoint.GetRandom(SpawnType.Cargo, null, Submarine.MainSub);
|
||||
WayPoint wp = WayPoint.GetRandom(SpawnType.Cargo, null, sub);
|
||||
if (wp == null)
|
||||
{
|
||||
DebugConsole.ThrowError("The submarine must have a waypoint marked as Cargo for bought items to be placed correctly!");
|
||||
@@ -188,25 +188,27 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
Hull cargoRoom = Hull.FindHull(wp.WorldPosition);
|
||||
|
||||
if (cargoRoom == null)
|
||||
{
|
||||
DebugConsole.ThrowError("A waypoint marked as Cargo must be placed inside a room!");
|
||||
return;
|
||||
}
|
||||
|
||||
#if CLIENT
|
||||
new GUIMessageBox("", TextManager.GetWithVariable("CargoSpawnNotification", "[roomname]", cargoRoom.DisplayName, true), new string[0], type: GUIMessageBox.Type.InGame, iconStyle: "StoreShoppingCrateIcon");
|
||||
#else
|
||||
foreach (Client client in GameMain.Server.ConnectedClients)
|
||||
if (sub == Submarine.MainSub)
|
||||
{
|
||||
ChatMessage msg = ChatMessage.Create("",
|
||||
TextManager.ContainsTag(cargoRoom.RoomName) ? $"CargoSpawnNotification~[roomname]=§{cargoRoom.RoomName}" : $"CargoSpawnNotification~[roomname]={cargoRoom.RoomName}",
|
||||
ChatMessageType.ServerMessageBoxInGame, null);
|
||||
msg.IconStyle = "StoreShoppingCrateIcon";
|
||||
GameMain.Server.SendDirectChatMessage(msg, client);
|
||||
}
|
||||
#if CLIENT
|
||||
new GUIMessageBox("", TextManager.GetWithVariable("CargoSpawnNotification", "[roomname]", cargoRoom.DisplayName, true), new string[0], type: GUIMessageBox.Type.InGame, iconStyle: "StoreShoppingCrateIcon");
|
||||
#else
|
||||
foreach (Client client in GameMain.Server.ConnectedClients)
|
||||
{
|
||||
ChatMessage msg = ChatMessage.Create("",
|
||||
TextManager.ContainsTag(cargoRoom.RoomName) ? $"CargoSpawnNotification~[roomname]=§{cargoRoom.RoomName}" : $"CargoSpawnNotification~[roomname]={cargoRoom.RoomName}",
|
||||
ChatMessageType.ServerMessageBoxInGame, null);
|
||||
msg.IconStyle = "StoreShoppingCrateIcon";
|
||||
GameMain.Server.SendDirectChatMessage(msg, client);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
List<ItemContainer> availableContainers = new List<ItemContainer>();
|
||||
ItemPrefab containerPrefab = null;
|
||||
|
||||
@@ -71,10 +71,13 @@ namespace Barotrauma
|
||||
else if (!isUnignoreOrder)
|
||||
{
|
||||
ActiveOrders.Add(new Pair<Order, float?>(order, fadeOutTime));
|
||||
#if CLIENT
|
||||
HintManager.OnActiveOrderAdded(order);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MatchesTarget(Entity existingTarget, Entity newTarget)
|
||||
static bool MatchesTarget(Entity existingTarget, Entity newTarget)
|
||||
{
|
||||
if (existingTarget == newTarget) { return true; }
|
||||
if (existingTarget is Hull existingHullTarget && newTarget is Hull newHullTarget)
|
||||
@@ -145,7 +148,13 @@ namespace Barotrauma
|
||||
}
|
||||
#if CLIENT
|
||||
AddCharacterToCrewList(character);
|
||||
AddCurrentOrderIcon(character, character.CurrentOrder, character.CurrentOrderOption);
|
||||
if (character.CurrentOrders != null)
|
||||
{
|
||||
foreach (var order in character.CurrentOrders)
|
||||
{
|
||||
AddCurrentOrderIcon(character, order);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (character.AIController is HumanAIController humanAI)
|
||||
{
|
||||
@@ -175,7 +184,7 @@ namespace Barotrauma
|
||||
List<WayPoint> spawnWaypoints = null;
|
||||
List<WayPoint> mainSubWaypoints = WayPoint.SelectCrewSpawnPoints(characterInfos, Submarine.MainSub).ToList();
|
||||
|
||||
if (Level.IsLoadedOutpost)
|
||||
if (Level.IsLoadedOutpost && Submarine.Loaded.Any(s => s.Info.Type == SubmarineType.Outpost && (s.Info.OutpostGenerationParams?.SpawnCrewInsideOutpost ?? false)))
|
||||
{
|
||||
spawnWaypoints = WayPoint.WayPointList.FindAll(wp =>
|
||||
wp.SpawnType == SpawnType.Human &&
|
||||
@@ -236,6 +245,21 @@ namespace Barotrauma
|
||||
conversationTimer = IsSinglePlayer ? Rand.Range(5.0f, 10.0f) : Rand.Range(45.0f, 60.0f);
|
||||
}
|
||||
|
||||
public void RenameCharacter(CharacterInfo characterInfo, string newName)
|
||||
{
|
||||
int identifier = characterInfo.GetIdentifierUsingOriginalName();
|
||||
var match = characterInfos.FirstOrDefault(ci => ci.GetIdentifierUsingOriginalName() == identifier);
|
||||
if (match == null)
|
||||
{
|
||||
DebugConsole.ThrowError($"Tried to rename an invalid crew member ({identifier})");
|
||||
return;
|
||||
}
|
||||
match.Rename(newName);
|
||||
RenameCharacterProjSpecific(match);
|
||||
}
|
||||
|
||||
partial void RenameCharacterProjSpecific(CharacterInfo characterInfo);
|
||||
|
||||
public void FireCharacter(CharacterInfo characterInfo)
|
||||
{
|
||||
RemoveCharacterInfo(characterInfo);
|
||||
@@ -247,7 +271,8 @@ namespace Barotrauma
|
||||
{
|
||||
if (order.Second.HasValue) { order.Second -= deltaTime; }
|
||||
}
|
||||
ActiveOrders.RemoveAll(o => o.Second.HasValue && o.Second <= 0.0f);
|
||||
ActiveOrders.RemoveAll(o => (o.Second.HasValue && o.Second <= 0.0f) ||
|
||||
(o.First.TargetEntity != null && o.First.TargetEntity.Removed));
|
||||
|
||||
UpdateConversations(deltaTime);
|
||||
UpdateProjectSpecific(deltaTime);
|
||||
@@ -270,6 +295,7 @@ namespace Barotrauma
|
||||
|
||||
private void UpdateConversations(float deltaTime)
|
||||
{
|
||||
if (GameMain.GameSession?.GameMode?.Preset == GameModePreset.TestMode) { return; }
|
||||
if (GameMain.NetworkMember != null && GameMain.NetworkMember.ServerSettings.DisableBotConversations) { return; }
|
||||
|
||||
conversationTimer -= deltaTime;
|
||||
@@ -287,7 +313,7 @@ namespace Barotrauma
|
||||
{
|
||||
foreach (Character npc in Character.CharacterList)
|
||||
{
|
||||
if (npc.TeamID != CharacterTeamType.FriendlyNPC || npc.CurrentHull == null || npc.IsIncapacitated) { continue; }
|
||||
if ((npc.TeamID != CharacterTeamType.FriendlyNPC && npc.TeamID != CharacterTeamType.None) || npc.CurrentHull == null || npc.IsIncapacitated) { continue; }
|
||||
if (npc.AIController is HumanAIController humanAI && (humanAI.ObjectiveManager.IsCurrentObjective<AIObjectiveFindSafety>() || humanAI.ObjectiveManager.IsCurrentObjective<AIObjectiveCombat>()))
|
||||
{
|
||||
continue;
|
||||
@@ -298,19 +324,35 @@ namespace Barotrauma
|
||||
{
|
||||
List<Character> availableSpeakers = new List<Character>() { npc, player };
|
||||
List<string> dialogFlags = new List<string>() { "OutpostNPC", "EnterOutpost" };
|
||||
if (GameMain.GameSession?.GameMode is CampaignMode campaignMode && campaignMode.Map?.CurrentLocation?.Reputation != null)
|
||||
if (GameMain.GameSession?.GameMode is CampaignMode campaignMode)
|
||||
{
|
||||
float normalizedReputation = MathUtils.InverseLerp(
|
||||
campaignMode.Map.CurrentLocation.Reputation.MinReputation,
|
||||
campaignMode.Map.CurrentLocation.Reputation.MaxReputation,
|
||||
campaignMode.Map.CurrentLocation.Reputation.Value);
|
||||
if (normalizedReputation < 0.2f)
|
||||
if (campaignMode.Map?.CurrentLocation?.Type?.Identifier.Equals("abandoned", StringComparison.OrdinalIgnoreCase) ?? false)
|
||||
{
|
||||
dialogFlags.Add("LowReputation");
|
||||
if (npc.TeamID == CharacterTeamType.None)
|
||||
{
|
||||
dialogFlags.Remove("OutpostNPC");
|
||||
dialogFlags.Add("Bandit");
|
||||
}
|
||||
else if (npc.TeamID == CharacterTeamType.FriendlyNPC)
|
||||
{
|
||||
dialogFlags.Remove("OutpostNPC");
|
||||
dialogFlags.Add("Hostage");
|
||||
}
|
||||
}
|
||||
else if (normalizedReputation > 0.8f)
|
||||
else if (campaignMode.Map?.CurrentLocation?.Reputation != null)
|
||||
{
|
||||
dialogFlags.Add("HighReputation");
|
||||
float normalizedReputation = MathUtils.InverseLerp(
|
||||
campaignMode.Map.CurrentLocation.Reputation.MinReputation,
|
||||
campaignMode.Map.CurrentLocation.Reputation.MaxReputation,
|
||||
campaignMode.Map.CurrentLocation.Reputation.Value);
|
||||
if (normalizedReputation < 0.2f)
|
||||
{
|
||||
dialogFlags.Add("LowReputation");
|
||||
}
|
||||
else if (normalizedReputation > 0.8f)
|
||||
{
|
||||
dialogFlags.Add("HighReputation");
|
||||
}
|
||||
}
|
||||
}
|
||||
pendingConversationLines.AddRange(NPCConversation.CreateRandom(availableSpeakers, dialogFlags));
|
||||
|
||||
@@ -144,7 +144,7 @@ namespace Barotrauma
|
||||
new XAttribute("value", valueStr),
|
||||
new XAttribute("type", value?.GetType())));
|
||||
}
|
||||
#if DEBUG || UNSTABLE
|
||||
#if DEBUG
|
||||
DebugConsole.Log(element.ToString());
|
||||
#endif
|
||||
modeElement.Add(element);
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
using System;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
class Reputation
|
||||
{
|
||||
public const float HostileThreshold = 0.1f;
|
||||
public const float HostileThreshold = 0.2f;
|
||||
public const float ReputationLossPerNPCDamage = 0.1f;
|
||||
public const float ReputationLossPerStolenItemPrice = 0.01f;
|
||||
public const float ReputationLossPerWallDamage = 0.1f;
|
||||
@@ -52,5 +53,71 @@ namespace Barotrauma
|
||||
MaxReputation = maxReputation;
|
||||
InitialReputation = initialReputation;
|
||||
}
|
||||
|
||||
public string GetReputationName()
|
||||
{
|
||||
return GetReputationName(NormalizedValue);
|
||||
}
|
||||
|
||||
public static string GetReputationName(float normalizedValue)
|
||||
{
|
||||
if (normalizedValue < HostileThreshold)
|
||||
{
|
||||
return TextManager.Get("reputationverylow");
|
||||
}
|
||||
else if (normalizedValue < 0.4f)
|
||||
{
|
||||
return TextManager.Get("reputationlow");
|
||||
}
|
||||
else if (normalizedValue < 0.6f)
|
||||
{
|
||||
return TextManager.Get("reputationneutral");
|
||||
}
|
||||
else if (normalizedValue < 0.8f)
|
||||
{
|
||||
return TextManager.Get("reputationhigh");
|
||||
}
|
||||
return TextManager.Get("reputationveryhigh");
|
||||
}
|
||||
|
||||
#if CLIENT
|
||||
public static Color GetReputationColor(float normalizedValue)
|
||||
{
|
||||
if (normalizedValue < HostileThreshold)
|
||||
{
|
||||
return GUI.Style.ColorReputationVeryLow;
|
||||
}
|
||||
else if (normalizedValue < 0.4f)
|
||||
{
|
||||
return GUI.Style.ColorReputationLow;
|
||||
}
|
||||
else if (normalizedValue < 0.6f)
|
||||
{
|
||||
return GUI.Style.ColorReputationNeutral;
|
||||
}
|
||||
else if (normalizedValue < 0.8f)
|
||||
{
|
||||
return GUI.Style.ColorReputationHigh;
|
||||
}
|
||||
return GUI.Style.ColorReputationVeryHigh;
|
||||
}
|
||||
public string GetFormattedReputationText(bool addColorTags = false)
|
||||
{
|
||||
return GetFormattedReputationText(NormalizedValue, Value, addColorTags);
|
||||
}
|
||||
|
||||
public static string GetFormattedReputationText(float normalizedValue, float value, bool addColorTags = false)
|
||||
{
|
||||
string reputationName = GetReputationName(normalizedValue);
|
||||
string formattedReputation = TextManager.GetWithVariables("reputationformat",
|
||||
new string[] { "[reputationname]", "[reputationvalue]" },
|
||||
new string[] { reputationName, ((int)Math.Round(value)).ToString() });
|
||||
if (addColorTags)
|
||||
{
|
||||
formattedReputation = $"‖color:{XMLExtensions.ColorToString(GetReputationColor(normalizedValue))}‖{formattedReputation}‖end‖";
|
||||
}
|
||||
return formattedReputation;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -5,9 +5,40 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
using Barotrauma.Networking;
|
||||
using Barotrauma.Extensions;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
internal struct CampaignSettings
|
||||
{
|
||||
public static CampaignSettings Empty = new CampaignSettings();
|
||||
|
||||
// Anything that uses this field I wasn't sure if actually needed the proper campaign settings to be passed down
|
||||
public static CampaignSettings Unsure = Empty;
|
||||
public bool RadiationEnabled { get; set; }
|
||||
|
||||
public CampaignSettings(IReadMessage inc)
|
||||
{
|
||||
RadiationEnabled = inc.ReadBoolean();
|
||||
}
|
||||
|
||||
public CampaignSettings(XElement element)
|
||||
{
|
||||
RadiationEnabled = element.GetAttributeBool(nameof(RadiationEnabled).ToLower(), true);
|
||||
}
|
||||
|
||||
public void Serialize(IWriteMessage msg)
|
||||
{
|
||||
msg.Write(RadiationEnabled);
|
||||
}
|
||||
|
||||
public XElement Save()
|
||||
{
|
||||
return new XElement(nameof(CampaignSettings), new XAttribute(nameof(RadiationEnabled).ToLower(), RadiationEnabled));
|
||||
}
|
||||
}
|
||||
|
||||
abstract partial class CampaignMode : GameMode
|
||||
{
|
||||
const int MaxMoney = int.MaxValue / 2; //about 1 billion
|
||||
@@ -31,6 +62,10 @@ namespace Barotrauma
|
||||
|
||||
protected XElement petsElement;
|
||||
|
||||
public CampaignSettings Settings;
|
||||
|
||||
private List<Mission> extraMissions = new List<Mission>();
|
||||
|
||||
public enum TransitionType
|
||||
{
|
||||
None,
|
||||
@@ -74,11 +109,22 @@ namespace Barotrauma
|
||||
get { return map; }
|
||||
}
|
||||
|
||||
public override Mission Mission
|
||||
public override IEnumerable<Mission> Missions
|
||||
{
|
||||
get
|
||||
{
|
||||
return Map.CurrentLocation?.SelectedMission;
|
||||
if (Map.CurrentLocation?.SelectedMission != null)
|
||||
{
|
||||
if (Map.CurrentLocation.SelectedMission.Locations[0] == Map.CurrentLocation.SelectedMission.Locations[1] ||
|
||||
Map.CurrentLocation.SelectedMission.Locations.Contains(Map.SelectedLocation))
|
||||
{
|
||||
yield return Map.CurrentLocation.SelectedMission;
|
||||
}
|
||||
}
|
||||
foreach (Mission mission in extraMissions)
|
||||
{
|
||||
yield return mission;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,28 +152,26 @@ namespace Barotrauma
|
||||
/// The location that's displayed as the "current one" in the map screen. Normally the current outpost or the location at the start of the level,
|
||||
/// but when selecting the next destination at the end of the level at an uninhabited location we use the location at the end
|
||||
/// </summary>
|
||||
public Location CurrentDisplayLocation
|
||||
public Location GetCurrentDisplayLocation()
|
||||
{
|
||||
get
|
||||
if (Level.Loaded?.EndLocation != null && !Level.Loaded.Generating &&
|
||||
Level.Loaded.Type == LevelData.LevelType.LocationConnection &&
|
||||
GetAvailableTransition(out _, out _) == TransitionType.ProgressToNextEmptyLocation)
|
||||
{
|
||||
if (Level.Loaded?.EndLocation != null && !Level.Loaded.Generating &&
|
||||
Level.Loaded.Type == LevelData.LevelType.LocationConnection &&
|
||||
GetAvailableTransition(out _, out _) == TransitionType.ProgressToNextEmptyLocation)
|
||||
{
|
||||
return Level.Loaded.EndLocation;
|
||||
}
|
||||
return Level.Loaded?.StartLocation ?? Map.CurrentLocation;
|
||||
return Level.Loaded.EndLocation;
|
||||
}
|
||||
return Level.Loaded?.StartLocation ?? Map.CurrentLocation;
|
||||
}
|
||||
|
||||
public List<Submarine> GetSubsToLeaveBehind(Submarine leavingSub)
|
||||
{
|
||||
//leave subs behind if they're not docked to the leaving sub and not at the same exit
|
||||
return Submarine.Loaded.FindAll(s =>
|
||||
s != leavingSub &&
|
||||
!leavingSub.DockedTo.Contains(s) &&
|
||||
s.Info.Type == SubmarineType.Player &&
|
||||
(s.AtEndPosition != leavingSub.AtEndPosition || s.AtStartPosition != leavingSub.AtStartPosition));
|
||||
return Submarine.Loaded.FindAll(sub =>
|
||||
sub != leavingSub &&
|
||||
!leavingSub.DockedTo.Contains(sub) &&
|
||||
sub.Info.Type == SubmarineType.Player &&
|
||||
sub != GameMain.NetworkMember?.RespawnManager?.RespawnShuttle &&
|
||||
(sub.AtEndExit != leavingSub.AtEndExit || sub.AtStartExit != leavingSub.AtStartExit));
|
||||
}
|
||||
|
||||
public override void Start()
|
||||
@@ -135,7 +179,9 @@ namespace Barotrauma
|
||||
base.Start();
|
||||
dialogLastSpoken.Clear();
|
||||
characterOutOfBoundsTimer.Clear();
|
||||
|
||||
#if CLIENT
|
||||
prevCampaignUIAutoOpenType = TransitionType.None;
|
||||
#endif
|
||||
if (PurchasedHullRepairs)
|
||||
{
|
||||
foreach (Structure wall in Structure.WallList)
|
||||
@@ -185,6 +231,67 @@ namespace Barotrauma
|
||||
/// </summary>
|
||||
public event Action BeforeLevelLoading;
|
||||
|
||||
|
||||
public override void AddExtraMissions(LevelData levelData)
|
||||
{
|
||||
extraMissions.Clear();
|
||||
|
||||
var currentLocation = Map.CurrentLocation;
|
||||
if (levelData.Type == LevelData.LevelType.Outpost)
|
||||
{
|
||||
//if there's an available mission that takes place in the outpost, select it
|
||||
var availableMissionsInLocation = currentLocation.AvailableMissions.Where(m => m.Locations[0] == currentLocation && m.Locations[1] == currentLocation);
|
||||
if (availableMissionsInLocation.Any())
|
||||
{
|
||||
currentLocation.SelectedMission = availableMissionsInLocation.FirstOrDefault();
|
||||
}
|
||||
else
|
||||
{
|
||||
currentLocation.SelectedMission = null;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//if we had selected a mission that takes place in the outpost, deselect it when leaving the outpost
|
||||
if (currentLocation.SelectedMission?.Locations[0] == currentLocation &&
|
||||
currentLocation.SelectedMission?.Locations[1] == currentLocation)
|
||||
{
|
||||
currentLocation.SelectedMission = null;
|
||||
}
|
||||
|
||||
if (levelData.HasBeaconStation && !levelData.IsBeaconActive)
|
||||
{
|
||||
var beaconMissionPrefabs = MissionPrefab.List.FindAll(m => m.Tags.Any(t => t.Equals("beaconnoreward", StringComparison.OrdinalIgnoreCase)));
|
||||
if (beaconMissionPrefabs.Any())
|
||||
{
|
||||
Random rand = new MTRandom(ToolBox.StringToInt(levelData.Seed));
|
||||
var beaconMissionPrefab = beaconMissionPrefabs.GetRandom(rand);
|
||||
if (!Missions.Any(m => m.Prefab.Type == beaconMissionPrefab.Type))
|
||||
{
|
||||
extraMissions.Add(beaconMissionPrefab.Instantiate(Map.SelectedConnection.Locations));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (levelData.HasHuntingGrounds)
|
||||
{
|
||||
var huntingGroundsMissionPrefabs = MissionPrefab.List.FindAll(m => m.Tags.Any(t => t.Equals("huntinggroundsnoreward", StringComparison.OrdinalIgnoreCase)));
|
||||
if (!huntingGroundsMissionPrefabs.Any())
|
||||
{
|
||||
DebugConsole.AddWarning("Could not find a hunting grounds mission for the level. No mission with the tag \"huntinggroundsnoreward\" found.");
|
||||
}
|
||||
else
|
||||
{
|
||||
Random rand = new MTRandom(ToolBox.StringToInt(levelData.Seed));
|
||||
var huntingGroundsMissionPrefab = huntingGroundsMissionPrefabs.GetRandom(rand);
|
||||
if (!Missions.Any(m => m.Prefab.Tags.Any(t => t.Equals("huntinggrounds", StringComparison.OrdinalIgnoreCase))))
|
||||
{
|
||||
extraMissions.Add(huntingGroundsMissionPrefab.Instantiate(Map.SelectedConnection.Locations));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void LoadNewLevel()
|
||||
{
|
||||
if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsClient)
|
||||
@@ -215,8 +322,8 @@ namespace Barotrauma
|
||||
"(current location: " + (map.CurrentLocation?.Name ?? "null") + ", " +
|
||||
"selected location: " + (map.SelectedLocation?.Name ?? "null") + ", " +
|
||||
"leaving sub: " + (leavingSub?.Info?.Name ?? "null") + ", " +
|
||||
"at start: " + (leavingSub?.AtStartPosition.ToString() ?? "null") + ", " +
|
||||
"at end: " + (leavingSub?.AtEndPosition.ToString() ?? "null") + ")\n" +
|
||||
"at start: " + (leavingSub?.AtStartExit.ToString() ?? "null") + ", " +
|
||||
"at end: " + (leavingSub?.AtEndExit.ToString() ?? "null") + ")\n" +
|
||||
Environment.StackTrace.CleanupStackTrace());
|
||||
return;
|
||||
}
|
||||
@@ -227,8 +334,8 @@ namespace Barotrauma
|
||||
"current location: " + (map.CurrentLocation?.Name ?? "null") + ", " +
|
||||
"selected location: " + (map.SelectedLocation?.Name ?? "null") + ", " +
|
||||
"leaving sub: " + (leavingSub?.Info?.Name ?? "null") + ", " +
|
||||
"at start: " + (leavingSub?.AtStartPosition.ToString() ?? "null") + ", " +
|
||||
"at end: " + (leavingSub?.AtEndPosition.ToString() ?? "null") + ")\n" +
|
||||
"at start: " + (leavingSub?.AtStartExit.ToString() ?? "null") + ", " +
|
||||
"at end: " + (leavingSub?.AtEndExit.ToString() ?? "null") + ")\n" +
|
||||
Environment.StackTrace.CleanupStackTrace());
|
||||
return;
|
||||
}
|
||||
@@ -239,8 +346,8 @@ namespace Barotrauma
|
||||
" (current location: " + (map.CurrentLocation?.Name ?? "null") + ", " +
|
||||
"selected location: " + (map.SelectedLocation?.Name ?? "null") + ", " +
|
||||
"leaving sub: " + (leavingSub?.Info?.Name ?? "null") + ", " +
|
||||
"at start: " + (leavingSub?.AtStartPosition.ToString() ?? "null") + ", " +
|
||||
"at end: " + (leavingSub?.AtEndPosition.ToString() ?? "null") + ", " +
|
||||
"at start: " + (leavingSub?.AtStartExit.ToString() ?? "null") + ", " +
|
||||
"at end: " + (leavingSub?.AtEndExit.ToString() ?? "null") + ", " +
|
||||
"transition type: " + availableTransition + ")");
|
||||
|
||||
IsFirstRound = false;
|
||||
@@ -277,7 +384,7 @@ namespace Barotrauma
|
||||
//currently travelling from location to another
|
||||
if (Level.Loaded.Type == LevelData.LevelType.LocationConnection)
|
||||
{
|
||||
if (leavingSub.AtEndPosition)
|
||||
if (leavingSub.AtEndExit)
|
||||
{
|
||||
if (Map.EndLocation != null &&
|
||||
map.SelectedLocation == Map.EndLocation &&
|
||||
@@ -303,15 +410,15 @@ namespace Barotrauma
|
||||
return TransitionType.ProgressToNextEmptyLocation;
|
||||
}
|
||||
}
|
||||
else if (leavingSub.AtStartPosition)
|
||||
else if (leavingSub.AtStartExit)
|
||||
{
|
||||
if (map.CurrentLocation.Type.HasOutpost && Level.Loaded.StartOutpost != null)
|
||||
{
|
||||
nextLevel = map.CurrentLocation.LevelData;
|
||||
return TransitionType.ReturnToPreviousLocation;
|
||||
}
|
||||
else if (map.SelectedLocation != null && map.SelectedLocation != map.CurrentLocation && !map.CurrentLocation.Type.HasOutpost &&
|
||||
(Level.Loaded.LevelData != map.SelectedConnection.LevelData))
|
||||
else if (map.SelectedLocation != null && map.SelectedLocation != map.CurrentLocation && !map.CurrentLocation.Type.HasOutpost &&
|
||||
map.SelectedConnection != null && Level.Loaded.LevelData != map.SelectedConnection.LevelData)
|
||||
{
|
||||
nextLevel = map.SelectedConnection.LevelData;
|
||||
return TransitionType.LeaveLocation;
|
||||
@@ -358,12 +465,15 @@ namespace Barotrauma
|
||||
leavingSubAtStart ??= Submarine.MainSub;
|
||||
leavingSubAtEnd ??= Submarine.MainSub;
|
||||
}
|
||||
int playersInSubAtStart = leavingSubAtStart == null ? 0 :
|
||||
int playersInSubAtStart = leavingSubAtStart == null || !leavingSubAtStart.AtStartExit ? 0 :
|
||||
leavingPlayers.Count(c => c.Submarine == leavingSubAtStart || leavingSubAtStart.DockedTo.Contains(c.Submarine) || (Level.Loaded.StartOutpost != null && c.Submarine == Level.Loaded.StartOutpost));
|
||||
int playersInSubAtEnd = leavingSubAtEnd == null ? 0 :
|
||||
int playersInSubAtEnd = leavingSubAtEnd == null || !leavingSubAtEnd.AtEndExit ? 0 :
|
||||
leavingPlayers.Count(c => c.Submarine == leavingSubAtEnd || leavingSubAtEnd.DockedTo.Contains(c.Submarine) || (Level.Loaded.EndOutpost != null && c.Submarine == Level.Loaded.EndOutpost));
|
||||
|
||||
if (playersInSubAtStart == 0 && playersInSubAtEnd == 0) { return null; }
|
||||
if (playersInSubAtStart == 0 && playersInSubAtEnd == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return playersInSubAtStart > playersInSubAtEnd ? leavingSubAtStart : leavingSubAtEnd;
|
||||
|
||||
@@ -371,7 +481,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (Level.Loaded.StartOutpost == null)
|
||||
{
|
||||
Submarine closestSub = Submarine.FindClosest(Level.Loaded.StartPosition, ignoreOutposts: true);
|
||||
Submarine closestSub = Submarine.FindClosest(Level.Loaded.StartExitPosition, ignoreOutposts: true, ignoreRespawnShuttle: true, teamType: leavingPlayers.FirstOrDefault()?.TeamID);
|
||||
return closestSub.DockedTo.Contains(Submarine.MainSub) ? Submarine.MainSub : closestSub;
|
||||
}
|
||||
else
|
||||
@@ -380,13 +490,14 @@ namespace Barotrauma
|
||||
if (Level.Loaded.StartOutpost.DockedTo.Any())
|
||||
{
|
||||
var dockedSub = Level.Loaded.StartOutpost.DockedTo.FirstOrDefault();
|
||||
if (dockedSub == GameMain.NetworkMember?.RespawnManager?.RespawnShuttle) { return null; }
|
||||
return dockedSub.DockedTo.Contains(Submarine.MainSub) ? Submarine.MainSub : dockedSub;
|
||||
}
|
||||
|
||||
//nothing docked, check if there's a sub close enough to the outpost and someone inside the outpost
|
||||
if (Level.Loaded.Type == LevelData.LevelType.LocationConnection && !leavingPlayers.Any(s => s.Submarine == Level.Loaded.StartOutpost)) { return null; }
|
||||
Submarine closestSub = Submarine.FindClosest(Level.Loaded.StartOutpost.WorldPosition, ignoreOutposts: true);
|
||||
if (closestSub == null || !closestSub.AtStartPosition) { return null; }
|
||||
Submarine closestSub = Submarine.FindClosest(Level.Loaded.StartOutpost.WorldPosition, ignoreOutposts: true, ignoreRespawnShuttle: true, teamType: leavingPlayers.FirstOrDefault()?.TeamID);
|
||||
if (closestSub == null || !closestSub.AtStartExit) { return null; }
|
||||
return closestSub.DockedTo.Contains(Submarine.MainSub) ? Submarine.MainSub : closestSub;
|
||||
}
|
||||
}
|
||||
@@ -398,7 +509,7 @@ namespace Barotrauma
|
||||
|
||||
if (Level.Loaded.EndOutpost == null)
|
||||
{
|
||||
Submarine closestSub = Submarine.FindClosest(Level.Loaded.EndPosition, ignoreOutposts: true);
|
||||
Submarine closestSub = Submarine.FindClosest(Level.Loaded.EndExitPosition, ignoreOutposts: true, ignoreRespawnShuttle: true, teamType: leavingPlayers.FirstOrDefault()?.TeamID);
|
||||
return closestSub.DockedTo.Contains(Submarine.MainSub) ? Submarine.MainSub : closestSub;
|
||||
}
|
||||
else
|
||||
@@ -407,13 +518,14 @@ namespace Barotrauma
|
||||
if (Level.Loaded.EndOutpost.DockedTo.Any())
|
||||
{
|
||||
var dockedSub = Level.Loaded.EndOutpost.DockedTo.FirstOrDefault();
|
||||
if (dockedSub == GameMain.NetworkMember?.RespawnManager?.RespawnShuttle) { return null; }
|
||||
return dockedSub.DockedTo.Contains(Submarine.MainSub) ? Submarine.MainSub : dockedSub;
|
||||
}
|
||||
|
||||
//nothing docked, check if there's a sub close enough to the outpost and someone inside the outpost
|
||||
if (Level.Loaded.Type == LevelData.LevelType.LocationConnection && !leavingPlayers.Any(s => s.Submarine == Level.Loaded.EndOutpost)) { return null; }
|
||||
Submarine closestSub = Submarine.FindClosest(Level.Loaded.EndOutpost.WorldPosition, ignoreOutposts: true);
|
||||
if (closestSub == null || !closestSub.AtEndPosition) { return null; }
|
||||
Submarine closestSub = Submarine.FindClosest(Level.Loaded.EndOutpost.WorldPosition, ignoreOutposts: true, ignoreRespawnShuttle: true, teamType: leavingPlayers.FirstOrDefault()?.TeamID);
|
||||
if (closestSub == null || !closestSub.AtEndExit) { return null; }
|
||||
return closestSub.DockedTo.Contains(Submarine.MainSub) ? Submarine.MainSub : closestSub;
|
||||
}
|
||||
}
|
||||
@@ -425,16 +537,19 @@ namespace Barotrauma
|
||||
foreach (Item item in Item.ItemList)
|
||||
{
|
||||
if (!item.SpawnedInOutpost || item.OriginalModuleIndex < 0) { continue; }
|
||||
if ((!(item.GetRootInventoryOwner()?.Submarine?.Info?.IsOutpost ?? false)) || item.Submarine == null || !item.Submarine.Info.IsOutpost)
|
||||
var owner = item.GetRootInventoryOwner();
|
||||
if ((!(owner?.Submarine?.Info?.IsOutpost ?? false)) || (owner is Character character && character.TeamID == CharacterTeamType.Team1) || item.Submarine == null || !item.Submarine.Info.IsOutpost)
|
||||
{
|
||||
takenItems.Add(item);
|
||||
}
|
||||
}
|
||||
map.CurrentLocation.RegisterTakenItems(takenItems);
|
||||
|
||||
map.CurrentLocation.AddToStock(CargoManager.SoldItems);
|
||||
CargoManager.ClearSoldItemsProjSpecific();
|
||||
map.CurrentLocation.RemoveFromStock(CargoManager.PurchasedItems);
|
||||
if (map != null && CargoManager != null)
|
||||
{
|
||||
map.CurrentLocation.RegisterTakenItems(takenItems);
|
||||
map.CurrentLocation.AddToStock(CargoManager.SoldItems);
|
||||
CargoManager.ClearSoldItemsProjSpecific();
|
||||
map.CurrentLocation.RemoveFromStock(CargoManager.PurchasedItems);
|
||||
}
|
||||
if (GameMain.NetworkMember == null)
|
||||
{
|
||||
CargoManager.ClearItemsInBuyCrate();
|
||||
@@ -444,11 +559,11 @@ namespace Barotrauma
|
||||
{
|
||||
if (GameMain.NetworkMember.IsServer)
|
||||
{
|
||||
CargoManager.ClearItemsInBuyCrate();
|
||||
CargoManager?.ClearItemsInBuyCrate();
|
||||
}
|
||||
else if (GameMain.NetworkMember.IsClient)
|
||||
{
|
||||
CargoManager.ClearItemsInSellCrate();
|
||||
CargoManager?.ClearItemsInSellCrate();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -480,7 +595,7 @@ namespace Barotrauma
|
||||
{
|
||||
CrewManager.RemoveCharacterInfo(ci);
|
||||
}
|
||||
ci?.ResetCurrentOrder();
|
||||
ci?.ClearCurrentOrders();
|
||||
}
|
||||
|
||||
foreach (DockingPort port in DockingPort.List)
|
||||
@@ -502,14 +617,30 @@ namespace Barotrauma
|
||||
{
|
||||
connection.Difficulty = MathHelper.Lerp(connection.Difficulty, 100.0f, 0.25f);
|
||||
connection.LevelData.Difficulty = connection.Difficulty;
|
||||
connection.LevelData.IsBeaconActive = false;
|
||||
connection.LevelData.HasHuntingGrounds = connection.LevelData.OriginallyHadHuntingGrounds;
|
||||
}
|
||||
foreach (Location location in Map.Locations)
|
||||
{
|
||||
if (location.Type != location.OriginalType)
|
||||
{
|
||||
location.ChangeType(location.OriginalType);
|
||||
location.PendingLocationTypeChange = null;
|
||||
}
|
||||
location.CreateStore(force: true);
|
||||
location.ClearMissions();
|
||||
location.Discovered = false;
|
||||
}
|
||||
Map.SetLocation(Map.Locations.IndexOf(Map.StartLocation));
|
||||
Map.SelectLocation(-1);
|
||||
if (Map.Radiation != null)
|
||||
{
|
||||
Map.Radiation.Amount = Map.Radiation.Params.StartingRadiation;
|
||||
}
|
||||
foreach (Location location in Map.Locations)
|
||||
{
|
||||
location.TurnsInRadiation = 0;
|
||||
}
|
||||
EndCampaignProjSpecific();
|
||||
|
||||
if (CampaignMetadata != null)
|
||||
@@ -523,14 +654,12 @@ namespace Barotrauma
|
||||
|
||||
public bool TryHireCharacter(Location location, CharacterInfo characterInfo)
|
||||
{
|
||||
if (characterInfo == null) { return false; }
|
||||
if (Money < characterInfo.Salary) { return false; }
|
||||
|
||||
characterInfo.IsNewHire = true;
|
||||
|
||||
location.RemoveHireableCharacter(characterInfo);
|
||||
CrewManager.AddCharacterInfo(characterInfo);
|
||||
Money -= characterInfo.Salary;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -552,18 +681,14 @@ namespace Barotrauma
|
||||
HumanAIController humanAI = npc.AIController as HumanAIController;
|
||||
if (humanAI == null) { yield return CoroutineStatus.Failure; }
|
||||
|
||||
OrderInfo? prevSpeakerOrder = null;
|
||||
if (humanAI.CurrentOrder != null)
|
||||
{
|
||||
prevSpeakerOrder = new OrderInfo(humanAI.CurrentOrder, humanAI.CurrentOrderOption);
|
||||
}
|
||||
var waitOrder = Order.PrefabList.Find(o => o.Identifier.Equals("wait", StringComparison.OrdinalIgnoreCase));
|
||||
humanAI.SetOrder(waitOrder, option: string.Empty, orderGiver: null, speak: false);
|
||||
humanAI.SetForcedOrder(waitOrder, string.Empty, null);
|
||||
var waitObjective = humanAI.ObjectiveManager.ForcedOrder;
|
||||
humanAI.FaceTarget(interactor);
|
||||
|
||||
while (!npc.Removed && !interactor.Removed &&
|
||||
Vector2.DistanceSquared(npc.WorldPosition, interactor.WorldPosition) < 300.0f * 300.0f &&
|
||||
humanAI.CurrentOrder == waitOrder &&
|
||||
humanAI.ObjectiveManager.ForcedOrder == waitObjective &&
|
||||
humanAI.AllowCampaignInteraction() &&
|
||||
!interactor.IsIncapacitated)
|
||||
{
|
||||
@@ -574,17 +699,7 @@ namespace Barotrauma
|
||||
ShowCampaignUI = false;
|
||||
#endif
|
||||
|
||||
if (humanAI.CurrentOrder == waitOrder)
|
||||
{
|
||||
if (prevSpeakerOrder != null)
|
||||
{
|
||||
humanAI.SetOrder(prevSpeakerOrder.Value.Order, prevSpeakerOrder.Value.OrderOption, orderGiver: null, speak: false);
|
||||
}
|
||||
else
|
||||
{
|
||||
humanAI.SetOrder(null, string.Empty, orderGiver: null, speak: false);
|
||||
}
|
||||
}
|
||||
humanAI.ClearForcedOrder();
|
||||
yield return CoroutineStatus.Success;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
class CoOpMode : MissionMode
|
||||
{
|
||||
public CoOpMode(GameModePreset preset, MissionPrefab missionPrefab) : base(preset, ValidateMissionPrefab(missionPrefab, MissionPrefab.CoOpMissionClasses)) { }
|
||||
public CoOpMode(GameModePreset preset, IEnumerable<MissionPrefab> missionPrefabs) : base(preset, ValidateMissionPrefabs(missionPrefabs, MissionPrefab.CoOpMissionClasses)) { }
|
||||
|
||||
public CoOpMode(GameModePreset preset, MissionType missionType, string seed) : base(preset, ValidateMissionType(missionType, MissionPrefab.CoOpMissionClasses), seed) { }
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
@@ -16,9 +17,9 @@ namespace Barotrauma
|
||||
get { return GameMain.GameSession?.CrewManager; }
|
||||
}
|
||||
|
||||
public virtual Mission Mission
|
||||
public virtual IEnumerable<Mission> Missions
|
||||
{
|
||||
get { return null; }
|
||||
get { return Enumerable.Empty<Mission>(); }
|
||||
}
|
||||
|
||||
public bool IsSinglePlayer
|
||||
@@ -54,6 +55,8 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
public virtual void ShowStartMessage() { }
|
||||
|
||||
public virtual void AddExtraMissions(LevelData levelData) { }
|
||||
|
||||
public virtual void AddToGUIUpdateList()
|
||||
{
|
||||
|
||||
@@ -5,37 +5,43 @@ namespace Barotrauma
|
||||
{
|
||||
abstract partial class MissionMode : GameMode
|
||||
{
|
||||
private readonly Mission mission;
|
||||
private readonly List<Mission> missions = new List<Mission>();
|
||||
|
||||
public override Mission Mission
|
||||
public override IEnumerable<Mission> Missions
|
||||
{
|
||||
get
|
||||
{
|
||||
return mission;
|
||||
return missions;
|
||||
}
|
||||
}
|
||||
|
||||
public MissionMode(GameModePreset preset, MissionPrefab missionPrefab)
|
||||
public MissionMode(GameModePreset preset, IEnumerable<MissionPrefab> missionPrefabs)
|
||||
: base(preset)
|
||||
{
|
||||
Location[] locations = { GameMain.GameSession.StartLocation, GameMain.GameSession.EndLocation };
|
||||
mission = missionPrefab.Instantiate(locations);
|
||||
foreach (MissionPrefab missionPrefab in missionPrefabs)
|
||||
{
|
||||
missions.Add(missionPrefab.Instantiate(locations));
|
||||
}
|
||||
}
|
||||
|
||||
public MissionMode(GameModePreset preset, MissionType missionType, string seed)
|
||||
: base(preset)
|
||||
{
|
||||
Location[] locations = { GameMain.GameSession.StartLocation, GameMain.GameSession.EndLocation };
|
||||
mission = Mission.LoadRandom(locations, seed, false, missionType);
|
||||
missions.Add(Mission.LoadRandom(locations, seed, false, missionType));
|
||||
}
|
||||
|
||||
protected static MissionPrefab ValidateMissionPrefab(MissionPrefab missionPrefab, Dictionary<MissionType, Type> missionClasses)
|
||||
protected static IEnumerable<MissionPrefab> ValidateMissionPrefabs(IEnumerable<MissionPrefab> missionPrefabs, Dictionary<MissionType, Type> missionClasses)
|
||||
{
|
||||
if (ValidateMissionType(missionPrefab.Type, missionClasses) != missionPrefab.Type)
|
||||
foreach (MissionPrefab missionPrefab in missionPrefabs)
|
||||
{
|
||||
throw new InvalidOperationException("Cannot start gamemode with mission type " + missionPrefab.Type);
|
||||
if (ValidateMissionType(missionPrefab.Type, missionClasses) != missionPrefab.Type)
|
||||
{
|
||||
throw new InvalidOperationException("Cannot start gamemode with mission type " + missionPrefab.Type);
|
||||
}
|
||||
}
|
||||
return missionPrefab;
|
||||
return missionPrefabs;
|
||||
}
|
||||
|
||||
protected static MissionType ValidateMissionType(MissionType missionType, Dictionary<MissionType, Type> missionClasses)
|
||||
|
||||
+7
-3
@@ -59,13 +59,14 @@ namespace Barotrauma
|
||||
InitCampaignData();
|
||||
}
|
||||
|
||||
public static MultiPlayerCampaign StartNew(string mapSeed, SubmarineInfo selectedSub)
|
||||
public static MultiPlayerCampaign StartNew(string mapSeed, SubmarineInfo selectedSub, CampaignSettings settings)
|
||||
{
|
||||
MultiPlayerCampaign campaign = new MultiPlayerCampaign();
|
||||
//only the server generates the map, the clients load it from a save file
|
||||
if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsServer)
|
||||
{
|
||||
campaign.map = new Map(campaign, mapSeed);
|
||||
campaign.map = new Map(campaign, mapSeed, settings);
|
||||
campaign.Settings = settings;
|
||||
}
|
||||
campaign.InitProjSpecific();
|
||||
return campaign;
|
||||
@@ -128,11 +129,14 @@ namespace Barotrauma
|
||||
{
|
||||
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);
|
||||
map = Map.Load(this, subElement, Settings);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
using Barotrauma.Networking;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
class PvPMode : MissionMode
|
||||
{
|
||||
public PvPMode(GameModePreset preset, MissionPrefab missionPrefab) : base(preset, ValidateMissionPrefab(missionPrefab, MissionPrefab.PvPMissionClasses)) { }
|
||||
public PvPMode(GameModePreset preset, IEnumerable<MissionPrefab> missionPrefabs) : base(preset, ValidateMissionPrefabs(missionPrefabs, MissionPrefab.PvPMissionClasses)) { }
|
||||
|
||||
public PvPMode(GameModePreset preset, MissionType missionType, string seed) : base(preset, ValidateMissionType(missionType, MissionPrefab.PvPMissionClasses), seed) { }
|
||||
|
||||
|
||||
@@ -22,7 +22,8 @@ namespace Barotrauma
|
||||
|
||||
public double RoundStartTime;
|
||||
|
||||
public Mission Mission { get; private set; }
|
||||
private readonly List<Mission> missions = new List<Mission>();
|
||||
public IEnumerable<Mission> Missions { get { return missions; } }
|
||||
|
||||
public CharacterTeamType? WinningTeam;
|
||||
|
||||
@@ -102,29 +103,28 @@ namespace Barotrauma
|
||||
/// <summary>
|
||||
/// Start a new GameSession. Will be saved to the specified save path (if playing a game mode that can be saved).
|
||||
/// </summary>
|
||||
public GameSession(SubmarineInfo submarineInfo, string savePath, GameModePreset gameModePreset, string seed = null, MissionType missionType = MissionType.None)
|
||||
public GameSession(SubmarineInfo submarineInfo, string savePath, GameModePreset gameModePreset, CampaignSettings settings, string seed = null, MissionType missionType = MissionType.None)
|
||||
: this(submarineInfo)
|
||||
{
|
||||
this.SavePath = savePath;
|
||||
CrewManager = new CrewManager(gameModePreset != null && gameModePreset.IsSinglePlayer);
|
||||
GameMode = InstantiateGameMode(gameModePreset, seed, submarineInfo, missionType: missionType);
|
||||
GameMode = InstantiateGameMode(gameModePreset, seed, submarineInfo, settings, missionType: missionType);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Start a new GameSession with a specific pre-selected mission.
|
||||
/// </summary>
|
||||
public GameSession(SubmarineInfo submarineInfo, GameModePreset gameModePreset, string seed = null, MissionPrefab missionPrefab = null)
|
||||
public GameSession(SubmarineInfo submarineInfo, GameModePreset gameModePreset, string seed = null, IEnumerable<MissionPrefab> missionPrefabs = null)
|
||||
: this(submarineInfo)
|
||||
{
|
||||
CrewManager = new CrewManager(gameModePreset != null && gameModePreset.IsSinglePlayer);
|
||||
GameMode = InstantiateGameMode(gameModePreset, seed, submarineInfo, missionPrefab: missionPrefab);
|
||||
GameMode = InstantiateGameMode(gameModePreset, seed, submarineInfo, CampaignSettings.Empty, missionPrefabs: missionPrefabs);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Load a game session from the specified XML document. The session will be saved to the specified path.
|
||||
/// </summary>
|
||||
public GameSession(SubmarineInfo submarineInfo, List<SubmarineInfo> ownedSubmarines, XDocument doc, string saveFile)
|
||||
: this(submarineInfo, ownedSubmarines)
|
||||
public GameSession(SubmarineInfo submarineInfo, List<SubmarineInfo> ownedSubmarines, XDocument doc, string saveFile) : this(submarineInfo, ownedSubmarines)
|
||||
{
|
||||
this.SavePath = saveFile;
|
||||
GameMain.GameSession = this;
|
||||
@@ -158,23 +158,23 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
private GameMode InstantiateGameMode(GameModePreset gameModePreset, string seed, SubmarineInfo selectedSub, MissionPrefab missionPrefab = null, MissionType missionType = MissionType.None)
|
||||
private GameMode InstantiateGameMode(GameModePreset gameModePreset, string seed, SubmarineInfo selectedSub, CampaignSettings settings, IEnumerable<MissionPrefab> missionPrefabs = null, MissionType missionType = MissionType.None)
|
||||
{
|
||||
if (gameModePreset.GameModeType == typeof(CoOpMode))
|
||||
{
|
||||
return missionPrefab != null ?
|
||||
new CoOpMode(gameModePreset, missionPrefab) :
|
||||
return missionPrefabs != null ?
|
||||
new CoOpMode(gameModePreset, missionPrefabs) :
|
||||
new CoOpMode(gameModePreset, missionType, seed ?? ToolBox.RandomSeed(8));
|
||||
}
|
||||
else if (gameModePreset.GameModeType == typeof(PvPMode))
|
||||
{
|
||||
return missionPrefab != null ?
|
||||
new PvPMode(gameModePreset, missionPrefab) :
|
||||
return missionPrefabs != null ?
|
||||
new PvPMode(gameModePreset, missionPrefabs) :
|
||||
new PvPMode(gameModePreset, missionType, seed ?? ToolBox.RandomSeed(8));
|
||||
}
|
||||
else if (gameModePreset.GameModeType == typeof(MultiPlayerCampaign))
|
||||
{
|
||||
var campaign = MultiPlayerCampaign.StartNew(seed ?? ToolBox.RandomSeed(8), selectedSub);
|
||||
var campaign = MultiPlayerCampaign.StartNew(seed ?? ToolBox.RandomSeed(8), selectedSub, settings);
|
||||
if (campaign != null && selectedSub != null)
|
||||
{
|
||||
campaign.Money = Math.Max(MultiPlayerCampaign.MinimumInitialMoney, campaign.Money - selectedSub.Price);
|
||||
@@ -184,7 +184,7 @@ namespace Barotrauma
|
||||
#if CLIENT
|
||||
else if (gameModePreset.GameModeType == typeof(SinglePlayerCampaign))
|
||||
{
|
||||
var campaign = SinglePlayerCampaign.StartNew(seed ?? ToolBox.RandomSeed(8), selectedSub);
|
||||
var campaign = SinglePlayerCampaign.StartNew(seed ?? ToolBox.RandomSeed(8), selectedSub, settings);
|
||||
if (campaign != null && selectedSub != null)
|
||||
{
|
||||
campaign.Money = Math.Max(SinglePlayerCampaign.MinimumInitialMoney, campaign.Money - selectedSub.Price);
|
||||
@@ -210,7 +210,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
private void CreateDummyLocations()
|
||||
private void CreateDummyLocations(LocationType? forceLocationType = null)
|
||||
{
|
||||
dummyLocations = new Location[2];
|
||||
|
||||
@@ -227,7 +227,7 @@ namespace Barotrauma
|
||||
MTRandom rand = new MTRandom(ToolBox.StringToInt(seed));
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
dummyLocations[i] = Location.CreateRandom(new Vector2((float)rand.NextDouble() * 10000.0f, (float)rand.NextDouble() * 10000.0f), null, rand, requireOutpost: true);
|
||||
dummyLocations[i] = Location.CreateRandom(new Vector2((float)rand.NextDouble() * 10000.0f, (float)rand.NextDouble() * 10000.0f), null, rand, requireOutpost: true, forceLocationType: forceLocationType);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -282,9 +282,38 @@ namespace Barotrauma
|
||||
(OwnedSubmarines != null && OwnedSubmarines.Any(os => os.Name == query.Name));
|
||||
}
|
||||
|
||||
public bool IsCurrentLocationRadiated()
|
||||
{
|
||||
if (Map?.CurrentLocation == null || Campaign == null) { return false; }
|
||||
|
||||
bool isRadiated = Map.CurrentLocation.IsRadiated();
|
||||
|
||||
if (Level.Loaded?.EndLocation is { } endLocation)
|
||||
{
|
||||
isRadiated |= endLocation.IsRadiated();
|
||||
}
|
||||
|
||||
return isRadiated;
|
||||
}
|
||||
|
||||
public void StartRound(string levelSeed, float? difficulty = null)
|
||||
{
|
||||
StartRound(LevelData.CreateRandom(levelSeed, difficulty));
|
||||
LevelData randomLevel = null;
|
||||
foreach (Mission mission in Missions.Union(GameMode.Missions))
|
||||
{
|
||||
MissionPrefab missionPrefab = mission.Prefab;
|
||||
if (missionPrefab != null &&
|
||||
missionPrefab.AllowedLocationTypes.Any() &&
|
||||
!missionPrefab.AllowedConnectionTypes.Any())
|
||||
{
|
||||
LocationType locationType = LocationType.List.FirstOrDefault(lt => missionPrefab.AllowedLocationTypes.Any(m => m.Equals(lt.Identifier, StringComparison.OrdinalIgnoreCase)));
|
||||
CreateDummyLocations(locationType);
|
||||
randomLevel = LevelData.CreateRandom(levelSeed, difficulty, requireOutpost: true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
randomLevel ??= LevelData.CreateRandom(levelSeed, difficulty);
|
||||
StartRound(randomLevel);
|
||||
}
|
||||
|
||||
public void StartRound(LevelData levelData, bool mirrorLevel = false, SubmarineInfo startOutpost = null, SubmarineInfo endOutpost = null)
|
||||
@@ -307,12 +336,6 @@ namespace Barotrauma
|
||||
|
||||
LevelData = levelData;
|
||||
|
||||
if (GameMode is CampaignMode campaignMode && GameMode.Mission != null &&
|
||||
LevelData != null && LevelData.Type == LevelData.LevelType.Outpost)
|
||||
{
|
||||
campaignMode.Map.CurrentLocation.SelectedMission = null;
|
||||
}
|
||||
|
||||
Submarine.Unload();
|
||||
Submarine = Submarine.MainSub = new Submarine(SubmarineInfo);
|
||||
foreach (Submarine sub in Submarine.GetConnectedSubs())
|
||||
@@ -332,6 +355,19 @@ namespace Barotrauma
|
||||
Submarine.MainSubs[1] = new Submarine(SubmarineInfo, true);
|
||||
}
|
||||
|
||||
if (GameMain.NetworkMember?.ServerSettings?.LockAllDefaultWires ?? false)
|
||||
{
|
||||
foreach (Item item in Item.ItemList)
|
||||
{
|
||||
if (item.Submarine == Submarine.MainSubs[0] ||
|
||||
(Submarine.MainSubs[1] != null && item.Submarine == Submarine.MainSubs[1]))
|
||||
{
|
||||
Wire wire = item.GetComponent<Wire>();
|
||||
if (wire != null && !wire.NoAutoLock && wire.Connections.Any(c => c != null)) { wire.Locked = true; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Level level = null;
|
||||
if (levelData != null)
|
||||
{
|
||||
@@ -340,11 +376,6 @@ namespace Barotrauma
|
||||
|
||||
InitializeLevel(level);
|
||||
|
||||
GameAnalyticsManager.AddDesignEvent("Submarine:" + Submarine.Info.Name);
|
||||
GameAnalyticsManager.AddDesignEvent("Level", ToolBox.StringToInt(levelData?.Seed ?? "[NO_LEVEL]"));
|
||||
GameAnalyticsManager.AddProgressionEvent(GameAnalyticsSDK.Net.EGAProgressionStatus.Start,
|
||||
GameMode.Preset.Identifier, (Mission == null ? "None" : Mission.GetType().ToString()));
|
||||
|
||||
#if CLIENT
|
||||
if (GameMode is CampaignMode) { SteamAchievementManager.OnBiomeDiscovered(levelData.Biome); }
|
||||
|
||||
@@ -354,7 +385,7 @@ namespace Barotrauma
|
||||
existingRoundSummary.ContinueButton.Visible = true;
|
||||
}
|
||||
|
||||
RoundSummary = new RoundSummary(Submarine.Info, GameMode, Mission, StartLocation, EndLocation);
|
||||
RoundSummary = new RoundSummary(Submarine.Info, GameMode, Missions, StartLocation, EndLocation);
|
||||
|
||||
if (!(GameMode is TutorialMode) && !(GameMode is TestGameMode))
|
||||
{
|
||||
@@ -363,7 +394,16 @@ namespace Barotrauma
|
||||
{
|
||||
GUI.AddMessage(levelData.Biome.DisplayName, Color.Lerp(Color.CadetBlue, Color.DarkRed, levelData.Difficulty / 100.0f), 5.0f, playSound: false);
|
||||
GUI.AddMessage(TextManager.AddPunctuation(':', TextManager.Get("Destination"), EndLocation.Name), Color.CadetBlue, playSound: false);
|
||||
GUI.AddMessage(TextManager.AddPunctuation(':', TextManager.Get("Mission"), (Mission == null ? TextManager.Get("None") : Mission.Name)), Color.CadetBlue, playSound: false);
|
||||
if (missions.Count > 1)
|
||||
{
|
||||
string joinedMissionNames = string.Join(", ", missions.Select(m => m.Name));
|
||||
GUI.AddMessage(TextManager.AddPunctuation(':', TextManager.Get("Mission"), joinedMissionNames), Color.CadetBlue, playSound: false);
|
||||
}
|
||||
else
|
||||
{
|
||||
var mission = missions.FirstOrDefault();
|
||||
GUI.AddMessage(TextManager.AddPunctuation(':', TextManager.Get("Mission"), mission?.Name ?? TextManager.Get("None")), Color.CadetBlue, playSound: false);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -372,6 +412,8 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
GUI.PreventPauseMenuToggle = false;
|
||||
|
||||
HintManager.OnRoundStarted();
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -383,6 +425,7 @@ namespace Barotrauma
|
||||
|
||||
#if CLIENT
|
||||
GameMain.LightManager.LosEnabled = GameMain.Client == null || GameMain.Client.CharacterInfo != null;
|
||||
if (GameMain.LightManager.LosEnabled) { GameMain.LightManager.LosAlpha = 1f; }
|
||||
if (GameMain.Client == null) GameMain.LightManager.LosMode = GameMain.Config.LosMode;
|
||||
#endif
|
||||
LevelData = level?.LevelData;
|
||||
@@ -400,16 +443,18 @@ namespace Barotrauma
|
||||
|
||||
Entity.Spawner = new EntitySpawner();
|
||||
|
||||
if (GameMode.Mission != null) { Mission = GameMode.Mission; }
|
||||
if (GameMode != null) { GameMode.Start(); }
|
||||
if (GameMode.Mission != null)
|
||||
missions.Clear();
|
||||
GameMode.AddExtraMissions(LevelData);
|
||||
missions.AddRange(GameMode.Missions);
|
||||
GameMode.Start();
|
||||
foreach (Mission mission in missions)
|
||||
{
|
||||
int prevEntityCount = Entity.GetEntities().Count();
|
||||
Mission.Start(Level.Loaded);
|
||||
mission.Start(Level.Loaded);
|
||||
if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsClient && Entity.GetEntities().Count() != prevEntityCount)
|
||||
{
|
||||
DebugConsole.ThrowError(
|
||||
"Entity count has changed after starting a mission as a client. " +
|
||||
$"Entity count has changed after starting a mission ({mission.Prefab.Identifier}) as a client. " +
|
||||
"The clients should not instantiate entities themselves when starting the mission," +
|
||||
" but instead the server should inform the client of the spawned entities using Mission.ServerWriteInitial.");
|
||||
}
|
||||
@@ -433,13 +478,6 @@ namespace Barotrauma
|
||||
}
|
||||
if (GameMode is MultiPlayerCampaign mpCampaign)
|
||||
{
|
||||
if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsServer)
|
||||
{
|
||||
mpCampaign.CargoManager.CreatePurchasedItems();
|
||||
#if SERVER
|
||||
mpCampaign.SendCrewState(false, null);
|
||||
#endif
|
||||
}
|
||||
mpCampaign.UpgradeManager.ApplyUpgrades();
|
||||
mpCampaign.UpgradeManager.SanityCheckUpgrades(Submarine);
|
||||
}
|
||||
@@ -514,7 +552,7 @@ namespace Barotrauma
|
||||
{
|
||||
Submarine.SetPosition(spawnPos);
|
||||
myPort.Dock(outPostPort);
|
||||
myPort.Lock(true);
|
||||
myPort.Lock(isNetworkMessage: true, applyEffects: false);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -531,7 +569,7 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
Submarine.SetPosition(Submarine.FindSpawnPos(level.StartPosition, verticalMoveDir: 1));
|
||||
Submarine.SetPosition(Submarine.FindSpawnPos(level.StartPosition));
|
||||
Submarine.NeutralizeBallast();
|
||||
Submarine.EnableMaintainPosition();
|
||||
}
|
||||
@@ -553,21 +591,33 @@ namespace Barotrauma
|
||||
{
|
||||
EventManager?.Update(deltaTime);
|
||||
GameMode?.Update(deltaTime);
|
||||
Mission?.Update(deltaTime);
|
||||
|
||||
//backwards for loop because the missions may get completed and removed from the list in Update()
|
||||
for (int i = missions.Count - 1; i >= 0; i--)
|
||||
{
|
||||
missions[i].Update(deltaTime);
|
||||
}
|
||||
UpdateProjSpecific(deltaTime);
|
||||
}
|
||||
|
||||
public Mission GetMission(int index)
|
||||
{
|
||||
if (index < 0 || index >= missions.Count) { return null; }
|
||||
return missions[index];
|
||||
}
|
||||
|
||||
public int GetMissionIndex(Mission mission)
|
||||
{
|
||||
return missions.IndexOf(mission);
|
||||
}
|
||||
|
||||
partial void UpdateProjSpecific(float deltaTime);
|
||||
|
||||
public void EndRound(string endMessage, List<TraitorMissionResult> traitorResults = null, CampaignMode.TransitionType transitionType = CampaignMode.TransitionType.None)
|
||||
{
|
||||
if (Mission != null) { Mission.End(); }
|
||||
GameAnalyticsManager.AddProgressionEvent(
|
||||
(Mission == null || Mission.Completed) ? GameAnalyticsSDK.Net.EGAProgressionStatus.Complete : GameAnalyticsSDK.Net.EGAProgressionStatus.Fail,
|
||||
GameMode.Preset.Identifier,
|
||||
Mission == null ? "None" : Mission.GetType().ToString());
|
||||
|
||||
foreach (Mission mission in missions)
|
||||
{
|
||||
mission.End();
|
||||
}
|
||||
#if CLIENT
|
||||
if (GUI.PauseMenuOpen)
|
||||
{
|
||||
@@ -593,8 +643,12 @@ namespace Barotrauma
|
||||
GameMode?.End(transitionType);
|
||||
EventManager?.EndRound();
|
||||
StatusEffect.StopAll();
|
||||
Mission = null;
|
||||
missions.Clear();
|
||||
IsRunning = false;
|
||||
|
||||
#if CLIENT
|
||||
HintManager.OnRoundEnded();
|
||||
#endif
|
||||
}
|
||||
|
||||
public void KillCharacter(Character character)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
@@ -39,5 +39,12 @@ namespace Barotrauma
|
||||
AvailableCharacters.ForEach(c => c.Remove());
|
||||
AvailableCharacters.Clear();
|
||||
}
|
||||
|
||||
public void RenameCharacter(CharacterInfo characterInfo, string newName)
|
||||
{
|
||||
if (characterInfo == null || string.IsNullOrEmpty(newName)) { return; }
|
||||
AvailableCharacters.FirstOrDefault(ci => ci == characterInfo)?.Rename(newName);
|
||||
PendingHires.FirstOrDefault(ci => ci == characterInfo)?.Rename(newName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,7 +104,8 @@ namespace Barotrauma
|
||||
/// </remarks>
|
||||
/// <param name="prefab"></param>
|
||||
/// <param name="category"></param>
|
||||
public void PurchaseUpgrade(UpgradePrefab prefab, UpgradeCategory category)
|
||||
/// <param name="force"></param>
|
||||
public void PurchaseUpgrade(UpgradePrefab prefab, UpgradeCategory category, bool force = false)
|
||||
{
|
||||
if (!CanUpgradeSub())
|
||||
{
|
||||
@@ -136,6 +137,11 @@ namespace Barotrauma
|
||||
});
|
||||
}
|
||||
|
||||
if (force)
|
||||
{
|
||||
price = 0;
|
||||
}
|
||||
|
||||
if (Campaign.Money > price)
|
||||
{
|
||||
if (GameMain.NetworkMember == null || GameMain.NetworkMember.IsServer)
|
||||
@@ -154,7 +160,7 @@ namespace Barotrauma
|
||||
PurchasedUpgrade? upgrade = FindMatchingUpgrade(prefab, category);
|
||||
|
||||
#if CLIENT
|
||||
DebugLog($"CLIENT: Purchased level {GetUpgradeLevel(prefab, category) + 1} {category.Name}.{prefab.Name} for ${price}", GUI.Style.Orange);
|
||||
DebugLog($"CLIENT: Purchased level {GetUpgradeLevel(prefab, category) + 1} {category.Name}.{prefab.Name} for {price}", GUI.Style.Orange);
|
||||
#endif
|
||||
|
||||
if (upgrade == null)
|
||||
@@ -689,7 +695,7 @@ namespace Barotrauma
|
||||
|
||||
public static void DebugLog(string msg, Color? color = null)
|
||||
{
|
||||
#if UNSTABLE || DEBUG
|
||||
#if DEBUG
|
||||
DebugConsole.NewMessage(msg, color ?? Color.GreenYellow);
|
||||
#else
|
||||
DebugConsole.Log(msg);
|
||||
|
||||
Reference in New Issue
Block a user