Build 0.18.9.0

This commit is contained in:
Markus Isberg
2022-06-14 04:14:47 +09:00
parent 4f5a3bf8b9
commit 856f894203
39 changed files with 459 additions and 377 deletions
@@ -26,6 +26,7 @@ namespace Barotrauma
protected override bool Filter(Pump pump)
{
if (pump?.Item == null || pump.Item.Removed) { return false; }
if (pump.Item.IgnoreByAI(character)) { return false; }
if (!pump.Item.IsInteractable(character)) { return false; }
if (pump.IsAutoControlled) { return false; }
@@ -2526,5 +2526,15 @@ namespace Barotrauma
ThrowError("Saving debug console log to " + filePath + " failed", e);
}
}
public static void DeactivateCheats()
{
#if CLIENT
GameMain.DebugDraw = false;
GameMain.LightManager.LightingEnabled = true;
#endif
Hull.EditWater = false;
Hull.EditFire = false;
}
}
}
@@ -408,6 +408,14 @@ namespace Barotrauma
bool isPrefabSuitable(EventPrefab e)
=> e.BiomeIdentifier.IsEmpty ||
e.BiomeIdentifier == level.LevelData?.Biome?.Identifier;
foreach (var subEventPrefab in eventSet.EventPrefabs)
{
foreach (Identifier missingId in subEventPrefab.GetMissingIdentifiers())
{
DebugConsole.ThrowError($"Error in event set \"{eventSet.Identifier}\" ({eventSet.ContentFile?.ContentPackage?.Name ?? "null"}) - could not find an event prefab with the identifier \"{missingId}\".");
}
}
var suitablePrefabSubsets = eventSet.EventPrefabs.Where(
e => e.EventPrefabs.Any(isPrefabSuitable)).ToArray();
@@ -142,11 +142,15 @@ namespace Barotrauma
{
foreach (var id in (Identifier[])PrefabOrIdentifier)
{
yield return EventPrefab.Prefabs[id];
if (EventPrefab.Prefabs.TryGet(id, out EventPrefab prefab))
{
yield return prefab;
}
}
}
}
}
public readonly float? SelfCommonness;
public float Commonness => SelfCommonness ?? EventPrefabs.MaxOrNull(p => p.Commonness) ?? 0.0f;
@@ -159,6 +163,20 @@ namespace Barotrauma
commonness = Commonness;
probability = Probability;
}
public IEnumerable<Identifier> GetMissingIdentifiers()
{
if (PrefabOrIdentifier.TryCast<Identifier[]>(out var ids))
{
foreach (var id in ids)
{
if (!EventPrefab.Prefabs.ContainsKey(id))
{
yield return id;
}
}
}
}
}
public readonly ImmutableArray<SubEventPrefab> EventPrefabs;
@@ -125,10 +125,6 @@ namespace Barotrauma
if (!AllTargetsEliminated()) { return; }
State = 1;
break;
case 1:
if (!Submarine.MainSub.AtEndExit && !Submarine.MainSub.AtStartExit) { return; }
State = 2;
break;
}
}
@@ -166,11 +162,16 @@ namespace Barotrauma
public override void End()
{
if (State == 2)
bool exitingLevel = GameMain.GameSession?.GameMode is CampaignMode campaign ?
campaign.GetAvailableTransition() != CampaignMode.TransitionType.None :
Submarine.MainSub is { } sub && (sub.AtEndExit || sub.AtStartExit);
if (State > 0 && exitingLevel)
{
GiveReward();
completed = true;
}
failed = !completed && State > 0;
}
}
@@ -3,7 +3,6 @@ using Microsoft.Xna.Framework;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
namespace Barotrauma
{
@@ -23,15 +22,16 @@ namespace Barotrauma
private int calculatedReward;
private int maxItemCount;
private Submarine sub;
private Submarine currentSub;
private SubmarineInfo nextRoundSubInfo;
private readonly List<CargoMission> previouslySelectedMissions = new List<CargoMission>();
public override LocalizedString Description
{
get
{
if (Submarine.MainSub != sub)
if ((GameMain.GameSession?.Campaign?.PendingSubmarineSwitch ?? Submarine.MainSub?.Info) != nextRoundSubInfo)
{
string rewardText = $"‖color:gui.orange‖{string.Format(System.Globalization.CultureInfo.InvariantCulture, "{0:N0}", GetReward(Submarine.MainSub))}‖end‖";
if (descriptionWithoutReward != null) { description = descriptionWithoutReward.Replace("[reward]", rewardText); }
@@ -43,7 +43,8 @@ namespace Barotrauma
public CargoMission(MissionPrefab prefab, Location[] locations, Submarine sub)
: base(prefab, locations, sub)
{
this.sub = sub;
this.currentSub = sub;
this.nextRoundSubInfo = sub?.Info;
itemConfig = prefab.ConfigElement.GetChildElement("Items");
requiredDeliveryAmount = Math.Min(prefab.ConfigElement.GetAttributeFloat("requireddeliveryamount", 0.98f), 1.0f);
//this can get called between rounds when the client receives a campaign save
@@ -57,39 +58,13 @@ namespace Barotrauma
private void DetermineCargo()
{
if (this.sub == null || itemConfig == null)
if (this.currentSub == null || itemConfig == null)
{
calculatedReward = Prefab.Reward;
return;
}
itemsToSpawn.Clear();
List<(ItemContainer container, int freeSlots)> containers = sub.GetCargoContainers();
containers.Sort((c1, c2) => { return c2.container.Capacity.CompareTo(c1.container.Capacity); });
previouslySelectedMissions.Clear();
if (GameMain.GameSession?.StartLocation?.SelectedMissions != null)
{
bool isPriorMission = true;
foreach (Mission mission in GameMain.GameSession.StartLocation.SelectedMissions)
{
if (!(mission is CargoMission otherMission)) { continue; }
if (mission == this) { isPriorMission = false; }
previouslySelectedMissions.Add(otherMission);
if (!isPriorMission) { continue; }
foreach (var (element, container) in otherMission.itemsToSpawn)
{
for (int i = 0; i < containers.Count; i++)
{
if (containers[i].container == container)
{
containers[i] = (containers[i].container, containers[i].freeSlots - 1);
break;
}
}
}
}
}
maxItemCount = 0;
foreach (var subElement in itemConfig.Elements())
@@ -98,18 +73,85 @@ namespace Barotrauma
maxItemCount += maxCount;
}
for (int i = 0; i < containers.Count; i++)
var pendingSubInfo = GameMain.GameSession?.Campaign?.PendingSubmarineSwitch;
if (pendingSubInfo != null && pendingSubInfo != currentSub.Info)
{
foreach (var subElement in itemConfig.Elements())
//if we've got a submarine switch pending, calculate the amount of cargo based on it's cargo capacity
//TODO: this isn't guaranteed to be accurate, because we don't take existing items in the new sub's cargo containers
//or items that might get transferred in them into account
maxItemCount = Math.Min(maxItemCount, pendingSubInfo.CargoCapacity);
previouslySelectedMissions.Clear();
if (GameMain.GameSession?.StartLocation?.SelectedMissions != null)
{
int maxCount = subElement.GetAttributeInt("maxcount", 10);
if (itemsToSpawn.Count(it => it.element == subElement) >= maxCount) { continue; }
ItemPrefab itemPrefab = FindItemPrefab(subElement);
while (containers[i].freeSlots > 0 && containers[i].container.Inventory.CanBePut(itemPrefab))
bool isPriorMission = true;
foreach (Mission mission in GameMain.GameSession.StartLocation.SelectedMissions)
{
containers[i] = (containers[i].container, containers[i].freeSlots - 1);
itemsToSpawn.Add((subElement, containers[i].container));
if (itemsToSpawn.Count(it => it.element == subElement) >= maxCount) { break; }
if (!(mission is CargoMission otherMission)) { continue; }
if (mission == this) { isPriorMission = false; }
previouslySelectedMissions.Add(otherMission);
if (!isPriorMission) { continue; }
maxItemCount -= otherMission.itemsToSpawn.Count;
}
}
for (int i = 0; i < maxItemCount; i++)
{
foreach (var subElement in itemConfig.Elements())
{
int maxCount = subElement.GetAttributeInt("maxcount", 10);
if (itemsToSpawn.Count(it => it.element == subElement) >= maxCount) { continue; }
ItemPrefab itemPrefab = FindItemPrefab(subElement);
while (itemsToSpawn.Count < maxItemCount)
{
itemsToSpawn.Add((subElement, null));
if (itemsToSpawn.Count(it => it.element == subElement) >= maxCount) { break; }
}
}
}
maxItemCount = Math.Max(0, maxItemCount);
nextRoundSubInfo = pendingSubInfo;
}
else
{
List<(ItemContainer container, int freeSlots)> containers = currentSub.GetCargoContainers();
containers.Sort((c1, c2) => { return c2.container.Capacity.CompareTo(c1.container.Capacity); });
previouslySelectedMissions.Clear();
if (GameMain.GameSession?.StartLocation?.SelectedMissions != null)
{
bool isPriorMission = true;
foreach (Mission mission in GameMain.GameSession.StartLocation.SelectedMissions)
{
if (!(mission is CargoMission otherMission)) { continue; }
if (mission == this) { isPriorMission = false; }
previouslySelectedMissions.Add(otherMission);
if (!isPriorMission) { continue; }
foreach (var (element, container) in otherMission.itemsToSpawn)
{
for (int i = 0; i < containers.Count; i++)
{
if (containers[i].container == container)
{
containers[i] = (containers[i].container, containers[i].freeSlots - 1);
break;
}
}
}
}
}
for (int i = 0; i < containers.Count; i++)
{
foreach (var subElement in itemConfig.Elements())
{
int maxCount = subElement.GetAttributeInt("maxcount", 10);
if (itemsToSpawn.Count(it => it.element == subElement) >= maxCount) { continue; }
ItemPrefab itemPrefab = FindItemPrefab(subElement);
while (containers[i].freeSlots > 0 && containers[i].container.Inventory.CanBePut(itemPrefab))
{
containers[i] = (containers[i].container, containers[i].freeSlots - 1);
itemsToSpawn.Add((subElement, containers[i].container));
if (itemsToSpawn.Count(it => it.element == subElement) >= maxCount) { break; }
}
}
}
}
@@ -135,7 +177,7 @@ namespace Barotrauma
}
if (rewardPerCrate.HasValue && rewardPerCrate < 0) { rewardPerCrate = null; }
string rewardText = $"‖color:gui.orange‖{string.Format(System.Globalization.CultureInfo.InvariantCulture, "{0:N0}", GetReward(sub))}‖end‖";
string rewardText = $"‖color:gui.orange‖{string.Format(System.Globalization.CultureInfo.InvariantCulture, "{0:N0}", GetReward(currentSub))}‖end‖";
if (descriptionWithoutReward != null) { description = descriptionWithoutReward.Replace("[reward]", rewardText); }
}
@@ -167,18 +209,26 @@ namespace Barotrauma
}
}
}
if (sub != this.sub || missionsChanged)
var pendingSubInfo = GameMain.GameSession?.Campaign?.PendingSubmarineSwitch;
if (pendingSubInfo != null && nextRoundSubInfo != pendingSubInfo)
{
this.sub = sub;
this.nextRoundSubInfo = pendingSubInfo;
DetermineCargo();
}
else if (sub != this.currentSub || missionsChanged)
{
this.currentSub = sub;
this.nextRoundSubInfo = sub.Info;
DetermineCargo();
}
return calculatedReward;
}
private void InitItems()
{
this.sub = Submarine.MainSub;
this.currentSub = Submarine.MainSub;
DetermineCargo();
items.Clear();
@@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
namespace Barotrauma
{
@@ -507,6 +507,8 @@ namespace Barotrauma
}
}
public TransitionType GetAvailableTransition() => GetAvailableTransition(out _, out _);
/// <summary>
/// Which submarine is at a position where it can leave the level and enter another one (if any).
/// </summary>
@@ -622,8 +622,6 @@ namespace Barotrauma
return;
}
var originalSubPos = Submarine.WorldPosition;
if (level.StartOutpost != null)
{
//start by placing the sub below the outpost
@@ -706,7 +704,7 @@ namespace Barotrauma
if (!ls.LoadSub || ls.Sub.DockedTo.Contains(Submarine)) { continue; }
if (Submarine.Info.LeftBehindDockingPortIDs.Contains(ls.OriginalLinkedToID)) { continue; }
if (ls.Sub.Info.SubmarineElement.Attribute("location") != null) { continue; }
ls.Sub.SetPosition(ls.Sub.WorldPosition + (Submarine.WorldPosition - originalSubPos));
ls.SetPositionRelativeToMainSub();
}
}
@@ -30,7 +30,7 @@ namespace Barotrauma.Items.Components
class SlotRestrictions
{
public readonly int MaxStackSize;
public readonly List<RelatedItem> ContainableItems;
public List<RelatedItem> ContainableItems;
public SlotRestrictions(int maxStackSize, List<RelatedItem> containableItems)
{
@@ -187,7 +187,7 @@ namespace Barotrauma.Items.Components
[Serialize(false, IsPropertySaveable.No)]
public bool RemoveContainedItemsOnDeconstruct { get; set; }
private ImmutableArray<SlotRestrictions> slotRestrictions;
private readonly ImmutableArray<SlotRestrictions> slotRestrictions;
readonly List<ISerializableEntity> targets = new List<ISerializableEntity>();
@@ -215,21 +215,13 @@ namespace Barotrauma.Items.Components
public override bool RecreateGUIOnResolutionChange => true;
public List<RelatedItem> ContainableItems { get; private set; }
public List<RelatedItem> ContainableItems { get; }
public ItemContainer(Item item, ContentXElement element)
: base(item, element)
{
LoadContainableRestrictions(element);
InitProjSpecific(element);
}
public void LoadContainableRestrictions(ContentXElement element)
{
int totalCapacity = capacity;
ContainableItems?.Clear();
foreach (var subElement in element.Elements())
{
switch (subElement.Name.ToString().ToLowerInvariant())
@@ -250,7 +242,7 @@ namespace Barotrauma.Items.Components
}
}
Inventory = new ItemInventory(item, this, totalCapacity, SlotsPerRow);
List<SlotRestrictions> newSlotRestrictions = new List<SlotRestrictions>(totalCapacity);
for (int i = 0; i < capacity; i++)
{
@@ -261,7 +253,7 @@ namespace Barotrauma.Items.Components
foreach (var subElement in element.Elements())
{
if (subElement.Name.ToString().ToLowerInvariant() != "subcontainer") { continue; }
int subCapacity = subElement.GetAttributeInt("capacity", 1);
int subMaxStackSize = subElement.GetAttributeInt("maxstacksize", maxStackSize);
@@ -289,6 +281,28 @@ namespace Barotrauma.Items.Components
capacity = totalCapacity;
slotRestrictions = newSlotRestrictions.ToImmutableArray();
System.Diagnostics.Debug.Assert(totalCapacity == slotRestrictions.Length);
InitProjSpecific(element);
}
public void ReloadContainableRestrictions(ContentXElement element)
{
int containableIndex = 0;
foreach (var subElement in element.GetChildElements("containable"))
{
RelatedItem containable = RelatedItem.Load(subElement, returnEmpty: false, parentDebugName: item.Name);
if (containable == null)
{
DebugConsole.ThrowError("Error when loading containable restrictions for \"" + item.Name + "\" - containable with no identifiers.");
continue;
}
ContainableItems[containableIndex] = containable;
containableIndex++;
if (containableIndex >= ContainableItems.Count) { break; }
}
for (int i = 0; i < capacity; i++)
{
slotRestrictions[i].ContainableItems = ContainableItems;
}
}
public int GetMaxStackSize(int slotIndex)
@@ -846,6 +846,10 @@ namespace Barotrauma.Items.Components
}
else if (target.Body.UserData is Limb limb)
{
if (!FriendlyFire && User != null && limb.character.IsFriendly(User))
{
return false;
}
// when hitting limbs with piercing ammo, don't lose as much speed
if (MaxTargetsToHit > 1)
{
@@ -460,13 +460,14 @@ namespace Barotrauma.MapCreatures.Behavior
{
if (parentBranchId > -1)
{
if (parentBranchId < Branches.Count)
var parentBranch = Branches.Find(b => b.ID == parentBranchId);
if (parentBranch == null)
{
branch.ParentBranch = Branches[parentBranchId];
DebugConsole.AddWarning($"Error while loading ballast flora: couldn't find a parent branch with the ID {parentBranchId}");
}
else
{
DebugConsole.AddWarning($"Error while loading ballast flora: parent branch ID {parentBranchId} out of range (total {Branches.Count} branches)");
branch.ParentBranch = parentBranch;
}
}
}
@@ -790,7 +791,8 @@ namespace Barotrauma.MapCreatures.Behavior
MaxHealth = RootHealth,
Health = RootHealth,
IsRoot = true,
CurrentHull = Parent
CurrentHull = Parent,
ID = CreateID()
};
Branches.Add(root);
@@ -1015,14 +1017,6 @@ namespace Barotrauma.MapCreatures.Behavior
public void DamageBranch(BallastFloraBranch branch, float amount, AttackType type, Character? attacker = null)
{
float damage = amount;
if (damage > 0)
{
damage = Math.Min(damage, branch.Health);
}
else
{
damage = Math.Max(damage, branch.Health - branch.MaxHealth);
}
if (type != AttackType.Other && type != AttackType.CutFromRoot)
{
@@ -1081,6 +1075,14 @@ namespace Barotrauma.MapCreatures.Behavior
}
}
if (damage > 0)
{
damage = Math.Min(damage, branch.Health);
}
else
{
damage = Math.Max(damage, branch.Health - branch.MaxHealth);
}
branch.Health -= damage;
#if SERVER
@@ -1,12 +1,11 @@
using Barotrauma.Items.Components;
using Barotrauma.Extensions;
using Barotrauma.Items.Components;
using Microsoft.Xna.Framework;
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Xml.Linq;
using Barotrauma.IO;
using Barotrauma.Extensions;
using System.Collections.Immutable;
namespace Barotrauma
{
@@ -82,6 +81,8 @@ namespace Barotrauma
private XElement saveElement;
private Vector2? positionRelativeToMainSub;
public override bool Linkable
{
get
@@ -256,6 +257,15 @@ namespace Barotrauma
}
}
public void SetPositionRelativeToMainSub()
{
if (positionRelativeToMainSub.HasValue)
{
Sub.SetPosition(Submarine.WorldPosition + positionRelativeToMainSub.Value);
}
positionRelativeToMainSub = null;
}
public override void OnMapLoaded()
{
if (!loadSub) { return; }
@@ -317,7 +327,19 @@ namespace Barotrauma
{
if (worldPos == Vector2.Zero)
{
DebugConsole.ThrowError("Something went wrong when loading a linked submarine - the save didn't include either a world position or a linked port for the submarine.");
Vector2 relativePos = saveElement.GetAttributeVector2("posrelativetomainsub", Vector2.Zero);
if (relativePos != Vector2.Zero)
{
positionRelativeToMainSub = relativePos;
}
else
{
DebugConsole.ThrowError("Something went wrong when loading a linked submarine - the save didn't include a world position, a linked port or position relative to the main sub.");
}
}
else
{
sub.Submarine = Submarine;
}
return;
}
@@ -469,8 +491,9 @@ namespace Barotrauma
}
else
{
if (saveElement.Attribute("location") != null) saveElement.Attribute("location").Remove();
if (saveElement.Attribute("worldpos") != null) saveElement.Attribute("worldpos").Remove();
if (saveElement.Attribute("location") != null) { saveElement.Attribute("location").Remove(); }
if (saveElement.Attribute("worldpos") != null) { saveElement.Attribute("worldpos").Remove(); }
saveElement.SetAttributeValue("posrelativetomainsub", XMLExtensions.Vector2ToString(sub.WorldPosition - Submarine.WorldPosition));
}
saveElement.SetAttributeValue("pos", XMLExtensions.Vector2ToString(Position - Submarine.HiddenSubPosition));
}
@@ -79,7 +79,6 @@ namespace Barotrauma
public override void Deselect()
{
base.Deselect();
#if CLIENT
var config = GameSettings.CurrentConfig;
config.CrewMenuOpen = CrewManager.PreferCrewMenuOpen;
@@ -88,6 +87,10 @@ namespace Barotrauma
GameSettings.SaveCurrentConfig();
GameMain.SoundManager.SetCategoryMuffle("default", false);
GUI.ClearMessages();
if (GameMain.GameSession?.GameMode is TestGameMode)
{
DebugConsole.DeactivateCheats();
}
#endif
}
@@ -1128,7 +1128,7 @@ namespace Barotrauma
if (itemComponent is ItemContainer itemContainer &&
(componentElement.GetChildElement("containable") != null || componentElement.GetChildElement("subcontainer") != null))
{
itemContainer.LoadContainableRestrictions(componentElement);
itemContainer.ReloadContainableRestrictions(componentElement);
}
}
}
@@ -492,7 +492,11 @@ namespace Barotrauma
#if CLIENT
if (setGraphicsMode)
{
GameMain.Instance.ApplyGraphicsSettings();
GameMain.Instance.ApplyGraphicsSettings(recalculateFontsAndStyles: true);
}
else if (textScaleChanged)
{
GUIStyle.RecalculateFonts();
}
if (audioOutputChanged)
@@ -505,17 +509,6 @@ namespace Barotrauma
VoipCapture.ChangeCaptureDevice(currentConfig.Audio.VoiceCaptureDevice);
}
if (textScaleChanged || resolutionChanged)
{
foreach (var font in GUIStyle.Fonts.Values)
{
font.Prefabs.ForEach(p => p.LoadFont());
}
foreach (var componentStyle in GUIStyle.ComponentStyles)
{
componentStyle.RefreshSize();
}
}
if (hudScaleChanged)
{
HUDLayoutSettings.CreateAreas();
@@ -40,10 +40,14 @@ namespace Barotrauma
}
}
private static void AddInternal(string name, Task task, Action<Task, object> onCompletion, object userdata)
private static void AddInternal(string name, Task task, Action<Task, object> onCompletion, object userdata, bool addIfFound = true)
{
lock (taskActions)
{
if (!addIfFound)
{
if (taskActions.Any(t => t.Name == name)) { return; }
}
if (taskActions.Count >= MaxTasks)
{
throw new Exception(
@@ -59,6 +63,10 @@ namespace Barotrauma
{
AddInternal(name, task, (Task t, object obj) => { onCompletion?.Invoke(t); }, null);
}
public static void AddIfNotFound(string name, Task task, Action<Task> onCompletion)
{
AddInternal(name, task, (Task t, object obj) => { onCompletion?.Invoke(t); }, null, addIfFound: false);
}
public static void Add<U>(string name, Task task, U userdata, Action<Task, U> onCompletion) where U : class
{