Unstable 0.16.1.0

This commit is contained in:
Markus Isberg
2022-01-27 00:30:32 +09:00
parent 7d6421a548
commit b259af5911
161 changed files with 1913 additions and 638 deletions
@@ -132,6 +132,7 @@ namespace Barotrauma
// Exchange money
var itemValue = item.Quantity * buyValues[item.ItemPrefab];
campaign.Money -= itemValue;
GameAnalyticsManager.AddMoneySpentEvent(itemValue, GameAnalyticsManager.MoneySink.Store, item.ItemPrefab.Identifier);
Location.StoreCurrentBalance += itemValue;
if (removeFromCrate)
@@ -291,7 +292,7 @@ namespace Barotrauma
float floorPos = hull.Rect.Y - hull.Rect.Height;
Vector2 position = new Vector2(
hull.Rect.Width > 40 ? Rand.Range(hull.Rect.X + 20, hull.Rect.Right - 20) : hull.Rect.Center.X,
hull.Rect.Width > 40 ? Rand.Range(hull.Rect.X + 20f, hull.Rect.Right - 20f) : hull.Rect.Center.X,
floorPos);
//check where the actual floor structure is in case the bottom of the hull extends below it
@@ -37,7 +37,6 @@ namespace Barotrauma
{
IsSinglePlayer = isSinglePlayer;
conversationTimer = 5.0f;
InitProjectSpecific();
}
@@ -100,10 +99,10 @@ namespace Barotrauma
foreach (XElement characterElement in element.Elements())
{
if (!characterElement.Name.ToString().Equals("character", StringComparison.OrdinalIgnoreCase)) { continue; }
CharacterInfo characterInfo = new CharacterInfo(characterElement);
#if CLIENT
if (characterElement.GetAttributeBool("lastcontrolled", false)) { characterInfo.LastControlled = true; }
characterInfo.CrewListIndex = characterElement.GetAttributeInt("crewlistindex", -1);
#endif
characterInfos.Add(characterInfo);
foreach (XElement subElement in characterElement.Elements())
@@ -133,7 +132,7 @@ namespace Barotrauma
characterInfos.Remove(characterInfo);
}
public void AddCharacter(Character character)
public void AddCharacter(Character character, bool sortCrewList = true)
{
if (character.Removed)
{
@@ -155,7 +154,11 @@ namespace Barotrauma
characterInfos.Add(character.Info);
}
#if CLIENT
AddCharacterToCrewList(character);
var characterComponent = AddCharacterToCrewList(character);
if (sortCrewList)
{
SortCrewList();
}
if (character.CurrentOrders != null)
{
foreach (var order in character.CurrentOrders)
@@ -254,12 +257,16 @@ namespace Barotrauma
}
}
AddCharacter(character);
AddCharacter(character, sortCrewList: false);
#if CLIENT
if (IsSinglePlayer && (Character.Controlled == null || character.Info.LastControlled)) { Character.Controlled = character; }
#endif
}
#if CLIENT
if (IsSinglePlayer) { SortCrewList(); }
#endif
//longer delay in multiplayer to prevent the server from triggering NPC conversations while the players are still loading the round
conversationTimer = IsSinglePlayer ? Rand.Range(5.0f, 10.0f) : Rand.Range(45.0f, 60.0f);
}
@@ -14,7 +14,7 @@ namespace Barotrauma
public Faction(CampaignMetadata metadata, FactionPrefab prefab)
{
Prefab = prefab;
Reputation = new Reputation(metadata, $"faction.{prefab.Identifier}", prefab.MinReputation, prefab.MaxReputation, prefab.InitialReputation);
Reputation = new Reputation(metadata, this, prefab.MinReputation, prefab.MaxReputation, prefab.InitialReputation);
}
}
@@ -35,9 +35,22 @@ namespace Barotrauma
private set
{
if (MathUtils.NearlyEqual(Value, value)) { return; }
float prevValue = Value;
Metadata.SetValue(metaDataIdentifier, Math.Clamp(value, MinReputation, MaxReputation));
OnReputationValueChanged?.Invoke();
OnAnyReputationValueChanged?.Invoke();
#if CLIENT
int increase = (int)Value - (int)prevValue;
if (increase != 0 && Character.Controlled != null)
{
Character.Controlled.AddMessage(
TextManager.GetWithVariable("reputationgainnotification", "[reputationname]", Location?.Name ?? Faction.Prefab.Name),
increase > 0 ? GUI.Style.Green : GUI.Style.Red,
playSound: true, Identifier, increase, lifetime: 5.0f);
}
#endif
}
}
@@ -63,15 +76,32 @@ namespace Barotrauma
public Action OnReputationValueChanged;
public static Action OnAnyReputationValueChanged;
public Reputation(CampaignMetadata metadata, string identifier, int minReputation, int maxReputation, int initialReputation)
public readonly Faction Faction;
public readonly Location Location;
public Reputation(CampaignMetadata metadata, Location location, string identifier, int minReputation, int maxReputation, int initialReputation)
: this(metadata, null, location, identifier, minReputation, maxReputation, initialReputation)
{
}
public Reputation(CampaignMetadata metadata, Faction faction, int minReputation, int maxReputation, int initialReputation)
: this(metadata, faction, null, $"faction.{faction.Prefab.Identifier}", minReputation, maxReputation, initialReputation)
{
}
private Reputation(CampaignMetadata metadata, Faction faction, Location location, string identifier, int minReputation, int maxReputation, int initialReputation)
{
System.Diagnostics.Debug.Assert(metadata != null);
System.Diagnostics.Debug.Assert(faction != null || location != null);
Metadata = metadata;
Identifier = identifier.ToLowerInvariant();
metaDataIdentifier = $"reputation.{Identifier}";
MinReputation = minReputation;
MaxReputation = maxReputation;
InitialReputation = initialReputation;
Faction = faction;
Location = location;
}
public string GetReputationName()
@@ -78,6 +78,9 @@ namespace Barotrauma
//there can be no events before this time has passed during the 1st campaign round
const float FirstRoundEventDelay = 0.0f;
public double TotalPlayTime;
public int TotalPassedLevels;
public enum InteractionType { None, Talk, Examine, Map, Crew, Store, Repair, Upgrade, PurchaseSub, MedicalClinic }
public readonly CargoManager CargoManager;
@@ -92,7 +95,7 @@ namespace Barotrauma
public CampaignSettings Settings;
private List<Mission> extraMissions = new List<Mission>();
private readonly List<Mission> extraMissions = new List<Mission>();
public enum TransitionType
{
@@ -690,11 +693,13 @@ namespace Barotrauma
GameAnalyticsManager.AddProgressionEvent(
GameAnalyticsManager.ProgressionStatus.Complete,
Name ?? "none");
Preset?.Identifier ?? "none");
string eventId = "FinishCampaign:";
GameAnalyticsManager.AddDesignEvent(eventId + "Submarine:" + (Submarine.MainSub?.Info?.Name ?? "none"));
GameAnalyticsManager.AddDesignEvent(eventId + "CrewSize:" + (CrewManager?.CharacterInfos?.Count() ?? 0));
GameAnalyticsManager.AddDesignEvent(eventId + "Money", Money);
GameAnalyticsManager.AddDesignEvent(eventId + "Money", Money);
GameAnalyticsManager.AddDesignEvent(eventId + "Playtime", TotalPlayTime);
GameAnalyticsManager.AddDesignEvent(eventId + "PassedLevels", TotalPassedLevels);
}
protected virtual void EndCampaignProjSpecific() { }
@@ -707,12 +712,14 @@ namespace Barotrauma
location.RemoveHireableCharacter(characterInfo);
CrewManager.AddCharacterInfo(characterInfo);
Money -= characterInfo.Salary;
GameAnalyticsManager.AddMoneySpentEvent(characterInfo.Salary, GameAnalyticsManager.MoneySink.Crew, characterInfo.Job?.Prefab.Identifier ?? "unknown");
return true;
}
private void NPCInteract(Character npc, Character interactor)
{
if (!npc.AllowCustomInteract) { return; }
GameAnalyticsManager.AddDesignEvent("CampaignInteraction:" + Preset.Identifier + ":" + npc.CampaignInteractionType);
NPCInteractProjSpecific(npc, interactor);
string coroutineName = "DoCharacterWait." + (npc?.ID ?? Entity.NullEntityID);
if (!CoroutineManager.IsCoroutineRunning(coroutineName))
@@ -876,6 +883,19 @@ namespace Barotrauma
}
public abstract void Save(XElement element);
protected void LoadStats(XElement element)
{
TotalPlayTime = element.GetAttributeDouble(nameof(TotalPlayTime).ToLowerInvariant(), 0);
TotalPassedLevels = element.GetAttributeInt(nameof(TotalPassedLevels).ToLowerInvariant(), 0);
}
protected XElement SaveStats()
{
return new XElement("stats",
new XAttribute(nameof(TotalPlayTime).ToLowerInvariant(), TotalPlayTime),
new XAttribute(nameof(TotalPassedLevels).ToLowerInvariant(), TotalPassedLevels));
}
public void LogState()
{
@@ -126,6 +126,10 @@ namespace Barotrauma
{
case "campaignsettings":
Settings = new CampaignSettings(subElement);
#if CLIENT
GameMain.NetworkMember.ServerSettings.MaxMissionCount = Settings.MaxMissionCount;
GameMain.NetworkMember.ServerSettings.RadiationEnabled = Settings.RadiationEnabled;
#endif
break;
case "map":
if (map == null)
@@ -159,6 +163,9 @@ namespace Barotrauma
case "pets":
petsElement = subElement;
break;
case "stats":
LoadStats(subElement);
break;
#if SERVER
case "savedexperiencepoints":
foreach (XElement savedExp in subElement.Elements())
@@ -22,6 +22,8 @@ namespace Barotrauma
public double RoundStartTime;
public double TimeSpentCleaning, TimeSpentPainting;
private readonly List<Mission> missions = new List<Mission>();
public IEnumerable<Mission> Missions { get { return missions; } }
@@ -276,6 +278,7 @@ namespace Barotrauma
}
Campaign.Money -= cost;
GameAnalyticsManager.AddMoneySpentEvent(cost, GameAnalyticsManager.MoneySink.SubmarineSwitch, newSubmarine.Name);
((CampaignMode)GameMode).PendingSubmarineSwitch = newSubmarine;
return newSubmarine;
@@ -288,6 +291,7 @@ namespace Barotrauma
if (!OwnedSubmarines.Any(s => s.Name == newSubmarine.Name))
{
Campaign.Money -= newSubmarine.Price;
GameAnalyticsManager.AddMoneySpentEvent(newSubmarine.Price, GameAnalyticsManager.MoneySink.SubmarinePurchase, newSubmarine.Name);
OwnedSubmarines.Add(newSubmarine);
}
}
@@ -409,7 +413,7 @@ namespace Barotrauma
GameAnalyticsManager.AddProgressionEvent(
GameAnalyticsManager.ProgressionStatus.Start,
GameMode?.Name ?? "none");
GameMode?.Preset?.Identifier ?? "none");
string eventId = "StartRound:" + (GameMode?.Preset?.Identifier ?? "none") + ":";
GameAnalyticsManager.AddDesignEvent(eventId + "Submarine:" + (Submarine.MainSub?.Info?.Name ?? "none"));
@@ -419,17 +423,39 @@ namespace Barotrauma
{
GameAnalyticsManager.AddDesignEvent(eventId + "MissionType:" + (mission.Prefab.Type.ToString() ?? "none") + ":" + mission.Prefab.Identifier);
}
GameAnalyticsManager.AddDesignEvent(eventId + "LevelType:" + (Level.Loaded?.Type.ToString() ?? "none"));
if (Level.Loaded != null)
{
string levelId = Level.Loaded.Type == LevelData.LevelType.Outpost ?
Level.Loaded.StartOutpost?.Info?.OutpostGenerationParams?.Identifier :
Level.Loaded.GenerationParams?.Identifier;
GameAnalyticsManager.AddDesignEvent(eventId + "LevelType:" + Level.Loaded.Type.ToString() + ":" + (levelId ?? "null"));
}
GameAnalyticsManager.AddDesignEvent(eventId + "Biome:" + (Level.Loaded?.LevelData?.Biome?.Identifier ?? "none"));
#if CLIENT
if (GameMode is TutorialMode tutorialMode)
{
GameAnalyticsManager.AddDesignEvent(eventId + tutorialMode.Tutorial.Identifier);
if (GameMain.IsFirstLaunch)
{
GameAnalyticsManager.AddDesignEvent("FirstLaunch:" + eventId + tutorialMode.Tutorial.Identifier);
}
}
#endif
if (GameMode is CampaignMode campaignMode)
{
if (campaignMode.Map?.Radiation != null && campaignMode.Map.Radiation.Enabled)
{
GameAnalyticsManager.AddDesignEvent(eventId + "RadiationEnabled");
GameAnalyticsManager.AddDesignEvent(eventId + "Radiation:Enabled");
}
else
{
GameAnalyticsManager.AddDesignEvent(eventId + "RadiationDisabled");
GameAnalyticsManager.AddDesignEvent(eventId + "Radiation:Disabled");
}
bool firstTimeInBiome = Map != null && !Map.Connections.Any(c => c.Passed && c.Biome == LevelData.Biome);
if (firstTimeInBiome)
{
GameAnalyticsManager.AddDesignEvent(eventId + (Level.Loaded?.LevelData?.Biome?.Identifier ?? "none") + "Discovered:Playtime", campaignMode.TotalPlayTime);
GameAnalyticsManager.AddDesignEvent(eventId + (Level.Loaded?.LevelData?.Biome?.Identifier ?? "none") + "Discovered:PassedLevels", campaignMode.TotalPassedLevels);
}
}
@@ -759,38 +785,29 @@ namespace Barotrauma
GameMode?.End(transitionType);
EventManager?.EndRound();
StatusEffect.StopAll();
missions.Clear();
IsRunning = false;
bool success = false;
#if CLIENT
success = CrewManager.GetCharacters().Any(c => !c.IsDead);
bool success = CrewManager.GetCharacters().Any(c => !c.IsDead);
#else
success = GameMain.Server.ConnectedClients.Any(c => c.InGame && c.Character != null && !c.Character.IsDead);
bool success = GameMain.Server.ConnectedClients.Any(c => c.InGame && c.Character != null && !c.Character.IsDead);
#endif
double roundDuration = Timing.TotalTime - RoundStartTime;
GameAnalyticsManager.AddProgressionEvent(
success ? GameAnalyticsManager.ProgressionStatus.Complete : GameAnalyticsManager.ProgressionStatus.Fail,
GameMode?.Name ?? "none",
roundDuration);
string eventId = "EndRound:GameMode:" + (GameMode?.Name ?? "none") + ":";
GameAnalyticsManager.AddDesignEvent(eventId + "Submarine:" + (Submarine.MainSub?.Info?.Name ?? "none"), roundDuration);
GameAnalyticsManager.AddDesignEvent(eventId + "GameMode:" + (GameMode?.Name ?? "none"), roundDuration);
GameAnalyticsManager.AddDesignEvent(eventId + "CrewSize:" + (CrewManager?.CharacterInfos?.Count() ?? 0), roundDuration);
foreach (Mission mission in missions)
{
GameAnalyticsManager.AddDesignEvent(eventId + "MissionType:" + (mission.Prefab.Type.ToString() ?? "none") + ":" + mission.Prefab.Identifier + ":" + (mission.Completed ? "Completed" : "Failed"), roundDuration);
}
GameAnalyticsManager.AddDesignEvent(eventId + "LevelType:" + (Level.Loaded?.Type.ToString() ?? "none"), roundDuration);
GameAnalyticsManager.AddDesignEvent(eventId + "Biome:" + (Level.Loaded?.LevelData?.Biome?.Identifier ?? "none"), roundDuration);
string eventId = "EndRound:" + (GameMode?.Preset?.Identifier ?? "none") + ":";
LogEndRoundStats(eventId);
if (GameMode is CampaignMode campaignMode)
{
GameAnalyticsManager.AddDesignEvent(eventId + "MoneyEarned", campaignMode.Money - prevMoney);
campaignMode.TotalPlayTime += roundDuration;
}
#if CLIENT
HintManager.OnRoundEnded();
#endif
missions.Clear();
}
finally
{
@@ -798,6 +815,82 @@ namespace Barotrauma
}
}
public void LogEndRoundStats(string eventId)
{
double roundDuration = Timing.TotalTime - RoundStartTime;
GameAnalyticsManager.AddDesignEvent(eventId + "Submarine:" + (Submarine.MainSub?.Info?.Name ?? "none"), roundDuration);
GameAnalyticsManager.AddDesignEvent(eventId + "GameMode:" + (GameMode?.Name ?? "none"), roundDuration);
GameAnalyticsManager.AddDesignEvent(eventId + "CrewSize:" + (CrewManager?.CharacterInfos?.Count() ?? 0), roundDuration);
foreach (Mission mission in missions)
{
GameAnalyticsManager.AddDesignEvent(eventId + "MissionType:" + (mission.Prefab.Type.ToString() ?? "none") + ":" + mission.Prefab.Identifier + ":" + (mission.Completed ? "Completed" : "Failed"), roundDuration);
}
if (Level.Loaded != null)
{
string levelId = Level.Loaded.Type == LevelData.LevelType.Outpost ?
Level.Loaded.StartOutpost?.Info?.OutpostGenerationParams?.Identifier :
Level.Loaded.GenerationParams?.Identifier;
GameAnalyticsManager.AddDesignEvent(eventId + "LevelType:" + (Level.Loaded?.Type.ToString() ?? "none" + ":" + (levelId ?? "null")), roundDuration);
GameAnalyticsManager.AddDesignEvent(eventId + "Biome:" + (Level.Loaded?.LevelData?.Biome?.Identifier ?? "none"), roundDuration);
}
if (Submarine.MainSub != null)
{
Dictionary<ItemPrefab, int> submarineInventory = new Dictionary<ItemPrefab, int>();
foreach (Item item in Item.ItemList)
{
var rootContainer = item.GetRootContainer() ?? item;
if (rootContainer.Submarine?.Info == null || rootContainer.Submarine.Info.Type != SubmarineType.Player) { continue; }
if (rootContainer.Submarine != Submarine.MainSub && !Submarine.MainSub.DockedTo.Contains(rootContainer.Submarine)) { continue; }
var holdable = item.GetComponent<Holdable>();
if (holdable == null || holdable.Attached) { continue; }
var wire = item.GetComponent<Wire>();
if (wire != null && wire.Connections.Any(c => c != null)) { continue; }
if (!submarineInventory.ContainsKey(item.Prefab))
{
submarineInventory.Add(item.Prefab, 0);
}
submarineInventory[item.Prefab]++;
}
foreach (var subItem in submarineInventory)
{
GameAnalyticsManager.AddDesignEvent(eventId + "SubmarineInventory:" + subItem.Key.Identifier, subItem.Value);
}
}
foreach (Character c in GetSessionCrewCharacters())
{
foreach (var itemSelectedDuration in c.ItemSelectedDurations)
{
string characterType = "Unknown";
if (c.IsBot)
{
characterType = "Bot";
}
else if (c.IsPlayer)
{
characterType = "Player";
}
GameAnalyticsManager.AddDesignEvent("TimeSpentOnDevices:" + (GameMode?.Preset?.Identifier ?? "none") + ":" + characterType + ":" + (c.Info?.Job?.Prefab.Identifier ?? "NoJob") + ":" + itemSelectedDuration.Key.Identifier, itemSelectedDuration.Value);
}
}
#if CLIENT
if (GameMode is TutorialMode tutorialMode)
{
GameAnalyticsManager.AddDesignEvent(eventId + tutorialMode.Tutorial.Identifier);
if (GameMain.IsFirstLaunch)
{
GameAnalyticsManager.AddDesignEvent("FirstLaunch:" + eventId + tutorialMode.Tutorial.Identifier);
}
}
GameAnalyticsManager.AddDesignEvent(eventId + "TimeSpentCleaning", TimeSpentCleaning);
GameAnalyticsManager.AddDesignEvent(eventId + "TimeSpentPainting", TimeSpentPainting);
TimeSpentCleaning = TimeSpentPainting = 0.0;
#endif
}
public void KillCharacter(Character character)
{
#if CLIENT
@@ -102,7 +102,7 @@ namespace Barotrauma
{
Identifier = value.Identifier;
Strength = (ushort)Math.Ceiling(value.Strength);
Price = (ushort)(Strength * value.Prefab.HealCostMultiplier);
Price = (ushort)(value.Prefab.BaseHealCost + Strength * value.Prefab.HealCostMultiplier);
}
}
@@ -276,9 +276,15 @@ namespace Barotrauma
PendingHeals.Add(crewMember);
}
public static bool IsHealable(Affliction affliction)
{
return affliction.Prefab.HealableInMedicalClinic && affliction.Strength > GetShowTreshold(affliction);
static float GetShowTreshold(Affliction affliction) => Math.Max(0, Math.Min(affliction.Prefab.ShowIconToOthersThreshold, affliction.Prefab.ShowInHealthScannerThreshold));
}
private NetAffliction[] GetAllAfflictions(CharacterHealth health)
{
IEnumerable<Affliction> rawAfflictions = health.GetAllAfflictions().Where(a => !a.Prefab.IsBuff && a.Strength > GetShowTreshold(a));
IEnumerable<Affliction> rawAfflictions = health.GetAllAfflictions().Where(a => IsHealable(a));
List<NetAffliction> afflictions = new List<NetAffliction>();
@@ -289,7 +295,7 @@ namespace Barotrauma
{
afflictions.Remove(foundAffliction);
foundAffliction.Strength += (ushort)affliction.Strength;
foundAffliction.Price += (ushort)GetAdjustedPrice((int)(affliction.Prefab.HealCostMultiplier * affliction.Strength));
foundAffliction.Price += (ushort)GetAdjustedPrice(GetHealPrice(affliction));
newAffliction = foundAffliction;
}
else
@@ -303,7 +309,7 @@ namespace Barotrauma
return afflictions.ToArray();
static float GetShowTreshold(Affliction affliction) => Math.Max(0, Math.Min(affliction.Prefab.ShowIconToOthersThreshold, affliction.Prefab.ShowInHealthScannerThreshold));
static int GetHealPrice(Affliction affliction) => (int)(affliction.Prefab.BaseHealCost + (affliction.Prefab.HealCostMultiplier * affliction.Strength));
}
public int GetTotalCost() => PendingHeals.SelectMany(h => h.Afflictions).Aggregate(0, (current, affliction) => current + affliction.Price);
@@ -225,6 +225,7 @@ namespace Barotrauma
}
Campaign.Money -= price;
GameAnalyticsManager.AddMoneySpentEvent(price, GameAnalyticsManager.MoneySink.SubmarineUpgrade, prefab.Identifier);
PurchasedUpgrade? upgrade = FindMatchingUpgrade(prefab, category);
@@ -323,6 +324,7 @@ namespace Barotrauma
}
Campaign.Money -= price;
GameAnalyticsManager.AddMoneySpentEvent(price, GameAnalyticsManager.MoneySink.SubmarineWeapon, itemToInstall.Identifier);
foreach (Item itemToSwap in linkedItems)
{