Unstable 0.17.2.0
This commit is contained in:
+3
-1
@@ -162,7 +162,9 @@ namespace Barotrauma
|
||||
CloseEnough = reach,
|
||||
DialogueIdentifier = Leak.FlowTargetHull != null ? "dialogcannotreachleak".ToIdentifier() : Identifier.Empty,
|
||||
TargetName = Leak.FlowTargetHull?.DisplayName,
|
||||
requiredCondition = () => Leak.Submarine == character.Submarine,
|
||||
requiredCondition = () =>
|
||||
Leak.Submarine == character.Submarine &&
|
||||
(Leak.FlowTargetHull != null && character.CurrentHull == Leak.FlowTargetHull || character.CanSeeTarget(Leak)),
|
||||
// The Go To objective can be abandoned if the leak is fixed (in which case we don't want to use the dialogue)
|
||||
SpeakCannotReachCondition = () => !CheckObjectiveSpecific()
|
||||
},
|
||||
|
||||
@@ -21,13 +21,25 @@ namespace Barotrauma
|
||||
public CharacterInfoPrefab(ContentXElement headsElement, XElement varsElement, XElement menuCategoryElement, XElement pronounsElement)
|
||||
{
|
||||
Heads = headsElement.Elements().Select(e => new CharacterInfo.HeadPreset(this, e)).ToImmutableArray();
|
||||
VarTags = varsElement.Elements()
|
||||
.Select(e =>
|
||||
(e.GetAttributeIdentifier("var", ""),
|
||||
e.GetAttributeIdentifierArray("tags", Array.Empty<Identifier>()).ToImmutableHashSet()))
|
||||
.ToImmutableDictionary();
|
||||
MenuCategoryVar = menuCategoryElement.GetAttributeIdentifier("var", Identifier.Empty);
|
||||
Pronouns = pronounsElement.GetAttributeIdentifier("vars", Identifier.Empty);
|
||||
if (varsElement != null)
|
||||
{
|
||||
VarTags = varsElement.Elements()
|
||||
.Select(e =>
|
||||
(e.GetAttributeIdentifier("var", ""),
|
||||
e.GetAttributeIdentifierArray("tags", Array.Empty<Identifier>()).ToImmutableHashSet()))
|
||||
.ToImmutableDictionary();
|
||||
}
|
||||
else
|
||||
{
|
||||
VarTags = new[]
|
||||
{
|
||||
("GENDER".ToIdentifier(),
|
||||
new[] { "female".ToIdentifier(), "male".ToIdentifier() }.ToImmutableHashSet())
|
||||
}.ToImmutableDictionary();
|
||||
}
|
||||
|
||||
MenuCategoryVar = menuCategoryElement?.GetAttributeIdentifier("var", Identifier.Empty) ?? "GENDER".ToIdentifier();
|
||||
Pronouns = pronounsElement?.GetAttributeIdentifier("vars", Identifier.Empty) ?? "GENDER".ToIdentifier();
|
||||
}
|
||||
public string ReplaceVars(string str, CharacterInfo.HeadPreset headPreset)
|
||||
{
|
||||
@@ -135,7 +147,13 @@ namespace Barotrauma
|
||||
public string Tags
|
||||
{
|
||||
get { return string.Join(",", TagSet); }
|
||||
private set { TagSet = value.Split(",").Select(s => s.ToIdentifier()).ToImmutableHashSet(); }
|
||||
private set
|
||||
{
|
||||
TagSet = value.Split(",")
|
||||
.Select(s => s.ToIdentifier())
|
||||
.Where(id => !id.IsEmpty)
|
||||
.ToImmutableHashSet();
|
||||
}
|
||||
}
|
||||
|
||||
[Serialize("0,0", IsPropertySaveable.No)]
|
||||
@@ -149,6 +167,20 @@ namespace Barotrauma
|
||||
{
|
||||
characterInfoPrefab = charInfoPrefab;
|
||||
SerializableProperties = SerializableProperty.DeserializeProperties(this, element);
|
||||
DetermineTagsFromLegacyFormat(element);
|
||||
}
|
||||
|
||||
private void DetermineTagsFromLegacyFormat(XElement element)
|
||||
{
|
||||
void addTag(string tag)
|
||||
=> TagSet = TagSet.Add(tag.ToIdentifier());
|
||||
|
||||
string headId = element.GetAttributeString("id", "");
|
||||
string gender = element.GetAttributeString("gender", "");
|
||||
string race = element.GetAttributeString("race", "");
|
||||
if (!headId.IsNullOrEmpty()) { addTag($"head{headId}"); }
|
||||
if (!gender.IsNullOrEmpty()) { addTag(gender); }
|
||||
if (!race.IsNullOrEmpty()) { addTag(race); }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -438,12 +470,37 @@ namespace Barotrauma
|
||||
public readonly ImmutableArray<(Color Color, float Commonness)> FacialHairColors;
|
||||
public readonly ImmutableArray<(Color Color, float Commonness)> SkinColors;
|
||||
|
||||
private void GetName(ContentPath namesFile, Rand.RandSync randSync, out string name)
|
||||
private void GetName(Rand.RandSync randSync, out string name)
|
||||
{
|
||||
XDocument doc = XMLExtensions.TryLoadXml(namesFile);
|
||||
name = doc.Root.GetAttributeString("format", "");
|
||||
var nameElement = CharacterConfigElement.GetChildElement("names") ?? CharacterConfigElement.GetChildElement("name");
|
||||
ContentPath namesXmlFile = nameElement?.GetAttributeContentPath("path") ?? ContentPath.Empty;
|
||||
XElement namesXml = null;
|
||||
if (!namesXmlFile.IsNullOrEmpty()) //names.xml is defined
|
||||
{
|
||||
XDocument doc = XMLExtensions.TryLoadXml(namesXmlFile);
|
||||
namesXml = doc.Root;
|
||||
}
|
||||
else //the legacy firstnames.txt/lastnames.txt shit is defined
|
||||
{
|
||||
namesXml = new XElement("names", new XAttribute("format", "[firstname] [lastname]"));
|
||||
var firstNamesPath = ReplaceVars(nameElement.GetAttributeContentPath("firstname")?.Value ?? "");
|
||||
var lastNamesPath = ReplaceVars(nameElement.GetAttributeContentPath("lastname")?.Value ?? "");
|
||||
if (File.Exists(firstNamesPath) && File.Exists(lastNamesPath))
|
||||
{
|
||||
var firstNames = File.ReadAllLines(firstNamesPath);
|
||||
var lastNames = File.ReadAllLines(lastNamesPath);
|
||||
namesXml.Add(firstNames.Select(n => new XElement("firstname", new XAttribute("value", n))));
|
||||
namesXml.Add(lastNames.Select(n => new XElement("lastname", new XAttribute("value", n))));
|
||||
}
|
||||
else //the files don't exist, just fall back to the vanilla names
|
||||
{
|
||||
XDocument doc = XMLExtensions.TryLoadXml("Content/Characters/Human/names.xml");
|
||||
namesXml = doc.Root;
|
||||
}
|
||||
}
|
||||
name = namesXml.GetAttributeString("format", "");
|
||||
Dictionary<Identifier, List<string>> entries = new Dictionary<Identifier, List<string>>();
|
||||
foreach (var subElement in doc.Root.Elements())
|
||||
foreach (var subElement in namesXml.Elements())
|
||||
{
|
||||
Identifier elemName = subElement.NameAsIdentifier();
|
||||
if (!entries.ContainsKey(elemName))
|
||||
@@ -477,8 +534,21 @@ namespace Barotrauma
|
||||
// talent-relevant values
|
||||
public int MissionsCompletedSinceDeath = 0;
|
||||
|
||||
private static bool ElementHasSpecifierTags(XElement element)
|
||||
=> element.GetAttributeBool("specifiertags",
|
||||
element.GetAttributeBool("genders",
|
||||
element.GetAttributeBool("races", false)));
|
||||
|
||||
// Used for creating the data
|
||||
public CharacterInfo(Identifier speciesName, string name = "", string originalName = "", Either<Job, JobPrefab> jobOrJobPrefab = null, string ragdollFileName = null, int variant = 0, Rand.RandSync randSync = Rand.RandSync.Unsynced, Identifier npcIdentifier = default)
|
||||
public CharacterInfo(
|
||||
Identifier speciesName,
|
||||
string name = "",
|
||||
string originalName = "",
|
||||
Either<Job, JobPrefab> jobOrJobPrefab = null,
|
||||
string ragdollFileName = null,
|
||||
int variant = 0,
|
||||
Rand.RandSync randSync = Rand.RandSync.Unsynced,
|
||||
Identifier npcIdentifier = default)
|
||||
{
|
||||
JobPrefab jobPrefab = null;
|
||||
Job job = null;
|
||||
@@ -494,7 +564,7 @@ namespace Barotrauma
|
||||
CharacterConfigElement = CharacterPrefab.FindBySpeciesName(SpeciesName)?.ConfigElement;
|
||||
if (CharacterConfigElement == null) { return; }
|
||||
// TODO: support for variants
|
||||
HasSpecifierTags = CharacterConfigElement.GetAttributeBool("specifiertags", false);
|
||||
HasSpecifierTags = ElementHasSpecifierTags(CharacterConfigElement);
|
||||
if (HasSpecifierTags)
|
||||
{
|
||||
HairColors = CharacterConfigElement.GetAttributeTupleArray("haircolors", new (Color, float)[] { (Color.WhiteSmoke, 100f) }).ToImmutableArray();
|
||||
@@ -537,12 +607,7 @@ namespace Barotrauma
|
||||
|
||||
public string GetRandomName(Rand.RandSync randSync)
|
||||
{
|
||||
string name = "";
|
||||
var nameElement = CharacterConfigElement.GetChildElement("names");
|
||||
if (nameElement != null)
|
||||
{
|
||||
GetName(nameElement.GetAttributeContentPath("path") ?? ContentPath.Empty, randSync, out name);
|
||||
}
|
||||
GetName(randSync, out string name);
|
||||
|
||||
return name;
|
||||
}
|
||||
@@ -623,7 +688,7 @@ namespace Barotrauma
|
||||
if (element == null) { return; }
|
||||
// TODO: support for variants
|
||||
CharacterConfigElement = element;
|
||||
HasSpecifierTags = CharacterConfigElement.GetAttributeBool("specifiertags", false);
|
||||
HasSpecifierTags = ElementHasSpecifierTags(CharacterConfigElement);
|
||||
if (HasSpecifierTags)
|
||||
{
|
||||
RecreateHead(
|
||||
@@ -647,7 +712,7 @@ namespace Barotrauma
|
||||
var nameElement = CharacterConfigElement.GetChildElement("names");
|
||||
if (nameElement != null)
|
||||
{
|
||||
GetName(nameElement.GetAttributeContentPath("path") ?? ContentPath.Empty, Rand.RandSync.ServerAndClient, out Name);
|
||||
GetName(Rand.RandSync.ServerAndClient, out Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ namespace Barotrauma
|
||||
var menuCategoryElement = ConfigElement.GetChildElement("MenuCategory");
|
||||
var pronounsElement = ConfigElement.GetChildElement("Pronouns");
|
||||
|
||||
if (headsElement != null && varsElement != null && menuCategoryElement != null && pronounsElement != null)
|
||||
if (headsElement != null)
|
||||
{
|
||||
CharacterInfoPrefab = new CharacterInfoPrefab(headsElement, varsElement, menuCategoryElement, pronounsElement);
|
||||
}
|
||||
|
||||
@@ -380,20 +380,24 @@ namespace Barotrauma
|
||||
public string Tags
|
||||
{
|
||||
get { return string.Join(',', TagSet); }
|
||||
private set { TagSet = value.Split(',').ToIdentifiers().ToImmutableHashSet(); }
|
||||
private set
|
||||
{
|
||||
TagSet = value.Split(',')
|
||||
.ToIdentifiers()
|
||||
.Where(id => !id.IsEmpty)
|
||||
.ToImmutableHashSet();
|
||||
}
|
||||
}
|
||||
|
||||
public ImmutableHashSet<Identifier> TagSet { get; private set; }
|
||||
|
||||
public SoundParams(ContentXElement element, CharacterParams character) : base(element, character)
|
||||
{
|
||||
HashSet<Identifier> tags = TagSet.ToHashSet();
|
||||
Identifier genderFallback = element.GetAttributeIdentifier("gender", "");
|
||||
if (genderFallback != Identifier.Empty && genderFallback != "None")
|
||||
{
|
||||
tags.Add(genderFallback);
|
||||
TagSet = TagSet.Add(genderFallback);
|
||||
}
|
||||
TagSet = tags.ToImmutableHashSet();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -446,7 +446,7 @@ namespace Barotrauma
|
||||
#elif CLIENT
|
||||
return characters;
|
||||
#endif
|
||||
static bool IsAlive(Character c) { return c.Info != null && !c.IsDead; }
|
||||
static bool IsAlive(Character c) { return c?.Info != null && !c.IsDead; }
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -58,7 +58,7 @@ namespace Barotrauma
|
||||
IsEquipped = new bool[capacity];
|
||||
SlotTypes = new InvSlotType[capacity];
|
||||
|
||||
AccessibleWhenAlive = element.GetAttributeBool("accessiblewhenalive", false);
|
||||
AccessibleWhenAlive = element.GetAttributeBool("accessiblewhenalive", character.Info != null);
|
||||
AccessibleByOwner = element.GetAttributeBool("accessiblebyowner", AccessibleWhenAlive);
|
||||
|
||||
string[] slotTypeNames = ParseSlotTypes(element);
|
||||
|
||||
@@ -370,7 +370,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
public Item GetFocusTarget()
|
||||
{
|
||||
var positionOut = item.Connections.Find(c => c.Name == "position_out");
|
||||
var positionOut = item.Connections?.Find(c => c.Name == "position_out");
|
||||
if (positionOut == null) { return null; }
|
||||
|
||||
item.SendSignal(new Signal(MathHelper.ToDegrees(targetRotation).ToString("G", CultureInfo.InvariantCulture), sender: user), positionOut);
|
||||
|
||||
@@ -57,7 +57,7 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
|
||||
[Editable, Serialize(true, IsPropertySaveable.Yes, description: "Should structures cast shadows when light from this light source hits them. " +
|
||||
"Disabling shadows increases the performance of the game, and is recommended for lights with a short range.", alwaysUseInstanceValues: true)]
|
||||
"Disabling shadows increases the performance of the game, and is recommended for lights with a short range. Lights that are set to be drawn behind subs don't cast shadows, regardless of this setting.", alwaysUseInstanceValues: true)]
|
||||
public bool CastShadows
|
||||
{
|
||||
get { return castShadows; }
|
||||
|
||||
@@ -407,8 +407,6 @@ namespace Barotrauma
|
||||
Loaded = this;
|
||||
Generating = true;
|
||||
|
||||
Rand.Tracker.Reset();
|
||||
Rand.Tracker.Active = true;
|
||||
EqualityCheckValues.Clear();
|
||||
EntitiesBeforeGenerate = GetEntities().ToList();
|
||||
EntityCountBeforeGenerate = EntitiesBeforeGenerate.Count();
|
||||
@@ -1305,8 +1303,6 @@ namespace Barotrauma
|
||||
//assign an ID to make entity events work
|
||||
//ID = FindFreeID();
|
||||
Generating = false;
|
||||
Rand.Tracker.Active = false;
|
||||
File.WriteAllLines(GameMain.NetworkMember is { IsServer: true } ? "serverrng.txt" : "clientrng.txt", Rand.Tracker.LogMsgs);
|
||||
}
|
||||
|
||||
private List<Point> GeneratePathNodes(Point startPosition, Point endPosition, Rectangle pathBorders, Tunnel parentTunnel, float variance)
|
||||
@@ -2443,7 +2439,6 @@ namespace Barotrauma
|
||||
fixedResources.Add((itemPrefab, fixedQuantityResourceInfo));
|
||||
}
|
||||
}
|
||||
levelResources.Sort((x, y) => x.commonness.CompareTo(y.commonness));
|
||||
|
||||
DebugConsole.Log("Generating level resources...");
|
||||
var allValidLocations = GetAllValidClusterLocations();
|
||||
@@ -2473,29 +2468,33 @@ namespace Barotrauma
|
||||
|
||||
//place some of the least common resources in the abyss
|
||||
AbyssResources.Clear();
|
||||
for (int j = 0; j < levelResources.Count && j < 5; j++)
|
||||
{
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
var (itemPrefab, commonness) = levelResources[j];
|
||||
var location = allValidLocations.GetRandom(l =>
|
||||
{
|
||||
if (l.Cell == null || l.Edge == null) { return false; }
|
||||
if (l.EdgeCenter.Y > AbyssArea.Bottom) { return false; }
|
||||
l.InitializeResources();
|
||||
return l.Resources.Count <= GetMaxResourcesOnEdge(itemPrefab, l, out _);
|
||||
}, randSync: Rand.RandSync.ServerAndClient);
|
||||
|
||||
if (location.Cell == null || location.Edge == null) { break; }
|
||||
int clusterSize = Rand.Range(GenerationParams.ResourceClusterSizeRange.X, GenerationParams.ResourceClusterSizeRange.Y + 1, Rand.RandSync.ServerAndClient);
|
||||
PlaceResources(itemPrefab, clusterSize, location, out var abyssResources);
|
||||
var abyssClusterLocation = new ClusterLocation(location.Cell, location.Edge, initializeResourceList: true);
|
||||
abyssClusterLocation.Resources.AddRange(abyssResources);
|
||||
AbyssResources.Add(abyssClusterLocation);
|
||||
var locationIndex = allValidLocations.FindIndex(l => l.Equals(location));
|
||||
allValidLocations.RemoveAt(locationIndex);
|
||||
}
|
||||
}
|
||||
int abyssClusterCount = (int)MathHelper.Lerp(GenerationParams.AbyssResourceClustersMin, GenerationParams.AbyssResourceClustersMax, Difficulty / 100.0f);
|
||||
|
||||
for (int i = 0; i < abyssClusterCount; i++)
|
||||
{
|
||||
//use inverse commonness to select the abyss resources (the rarest ones are the most common in the abyss)
|
||||
var selectedPrefab = ToolBox.SelectWeightedRandom(
|
||||
levelResources.Select(it => it.itemPrefab).ToList(),
|
||||
levelResources.Select(it => it.commonness <= 0.0f ? 0.0f : 1.0f / it.commonness).ToList(),
|
||||
Rand.RandSync.ServerAndClient);
|
||||
var location = allValidLocations.GetRandom(l =>
|
||||
{
|
||||
if (l.Cell == null || l.Edge == null) { return false; }
|
||||
if (l.EdgeCenter.Y > AbyssArea.Bottom) { return false; }
|
||||
l.InitializeResources();
|
||||
return l.Resources.Count <= GetMaxResourcesOnEdge(selectedPrefab, l, out _);
|
||||
}, randSync: Rand.RandSync.ServerAndClient);
|
||||
|
||||
if (location.Cell == null || location.Edge == null) { break; }
|
||||
int clusterSize = Rand.Range(GenerationParams.ResourceClusterSizeRange.X, GenerationParams.ResourceClusterSizeRange.Y + 1, Rand.RandSync.ServerAndClient);
|
||||
PlaceResources(selectedPrefab, clusterSize, location, out var abyssResources);
|
||||
var abyssClusterLocation = new ClusterLocation(location.Cell, location.Edge, initializeResourceList: true);
|
||||
abyssClusterLocation.Resources.AddRange(abyssResources);
|
||||
AbyssResources.Add(abyssClusterLocation);
|
||||
var locationIndex = allValidLocations.FindIndex(l => l.Equals(location));
|
||||
allValidLocations.RemoveAt(locationIndex);
|
||||
}
|
||||
|
||||
PathPoints.Clear();
|
||||
nextPathPointId = 0;
|
||||
@@ -2603,7 +2602,14 @@ namespace Barotrauma
|
||||
|
||||
#if DEBUG
|
||||
DebugConsole.NewMessage("Level resources spawned: " + itemCount + "\n" +
|
||||
"Spawn points containing resources: " + PathPoints.Where(p => p.ClusterLocations.Any()).Count() + "/" + PathPoints.Count);
|
||||
" Spawn points containing resources: " + PathPoints.Where(p => p.ClusterLocations.Any()).Count() + "/" + PathPoints.Count + "\n" +
|
||||
" Total value: "+ PathPoints.Sum(p => p.ClusterLocations.Sum(c => c.Resources.Sum(r => r.Prefab.DefaultPrice?.Price ?? 0)))+" mk");
|
||||
if (AbyssResources.Count > 0)
|
||||
{
|
||||
|
||||
DebugConsole.NewMessage("Abyss resources spawned: " + AbyssResources.Sum(a => a.Resources.Count) + "\n" +
|
||||
" Total value: " + AbyssResources.Sum(c => c.Resources.Sum(r => r.Prefab.DefaultPrice?.Price ?? 0)) + " mk");
|
||||
}
|
||||
#endif
|
||||
|
||||
DebugConsole.Log("Level resources generated");
|
||||
|
||||
@@ -387,6 +387,20 @@ namespace Barotrauma
|
||||
set;
|
||||
}
|
||||
|
||||
[Serialize(3, IsPropertySaveable.Yes, description: "Minimum number of resource clusters in the abyss (the actual number is picked between min and max according to the level difficulty)"), Editable(MinValueInt = 0, MaxValueInt = 1000)]
|
||||
public int AbyssResourceClustersMin
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
[Serialize(20, IsPropertySaveable.Yes, description: "Maximum number of resource clusters in the abyss (the actual number is picked between min and max according to the level difficulty)"), Editable(MinValueInt = 0, MaxValueInt = 1000)]
|
||||
public int AbyssResourceClustersMax
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
[Serialize(-300000, IsPropertySaveable.Yes, description: "How far below the level the sea floor is placed."), Editable(MinValueFloat = Level.MaxEntityDepth, MaxValueFloat = 0.0f)]
|
||||
public int SeaFloorDepth
|
||||
{
|
||||
|
||||
@@ -11,38 +11,6 @@ namespace Barotrauma
|
||||
{
|
||||
public static class Rand
|
||||
{
|
||||
[Obsolete("TODO: remove")]
|
||||
public static class Tracker
|
||||
{
|
||||
private readonly static List<string> logMsgs = new List<string>();
|
||||
public static IReadOnlyList<string> LogMsgs => logMsgs;
|
||||
|
||||
public static bool Active = false;
|
||||
|
||||
public static void Reset()
|
||||
{
|
||||
logMsgs.Clear();
|
||||
Active = false;
|
||||
}
|
||||
|
||||
public static void RegisterCall(int stDepth=4)
|
||||
{
|
||||
if (!Active) { return; }
|
||||
var st = new StackTrace(skipFrames: 2, fNeedFileInfo: true);
|
||||
var frames = st.GetFrames();
|
||||
string msg = string.Join("; ",
|
||||
frames.Take(stDepth).Select(f =>
|
||||
$"{Path.GetFileNameWithoutExtension(f.GetFileName())}:{f.GetFileLineNumber()}"));
|
||||
logMsgs.Add(msg);
|
||||
}
|
||||
|
||||
public static void Log(string msg)
|
||||
{
|
||||
if (!Active) { return; }
|
||||
logMsgs.Add(msg);
|
||||
}
|
||||
}
|
||||
|
||||
public enum RandSync
|
||||
{
|
||||
Unsynced, //not synced, used for unimportant details like minor particle properties
|
||||
@@ -81,8 +49,6 @@ namespace Barotrauma
|
||||
public static int ThreadId = 0;
|
||||
private static void CheckRandThreadSafety(RandSync sync)
|
||||
{
|
||||
if (sync == RandSync.ServerAndClient) { Tracker.RegisterCall(); }
|
||||
|
||||
if (ThreadId != 0 && sync == RandSync.Unsynced)
|
||||
{
|
||||
if (System.Threading.Thread.CurrentThread.ManagedThreadId != ThreadId)
|
||||
|
||||
@@ -1,3 +1,24 @@
|
||||
---------------------------------------------------------------------------------------------------------
|
||||
v0.17.2.0
|
||||
---------------------------------------------------------------------------------------------------------
|
||||
|
||||
Changes:
|
||||
- Adjusted abyss resource spawning: less resources per level, the number of resources is relative to the difficulty, the spawned resources aren't guaranteed to always be the 5 least common alien materials.
|
||||
- Increased maximum number of lights from 300 to 600 (unstable only).
|
||||
- Backwards compatibility with human mods made before modding refactor (unstable only).
|
||||
|
||||
Fixes:
|
||||
- Fixed server crash in GetSalaryEligibleCrew (unstable only).
|
||||
- Fixed crashing in Controller.GetFocusTarget (unstable only).
|
||||
- Fixed "Tried to access crew wallets in singleplayer" error at the end of the round (unstable only).
|
||||
- Fixed selling items taking money instead of giving it (unstable only).
|
||||
- Fixed lights that are drawn behind subs counting as shadow-casting in the sub editor.
|
||||
- Fixed server host creating 2 disconnect message boxes if the server crashes.
|
||||
- Deactivate certain cheats when leaving an editor. Fixes ability to use certain cheat commands in an editor (which is now allowed without having to enable cheats) and then switch back to the game (unstable only).
|
||||
|
||||
AI:
|
||||
- Fixed bots sometimes getting stuck to doors when they are trying to fix a hull behind it. Happened because the goto objective was completed before the bot could open the door.
|
||||
|
||||
---------------------------------------------------------------------------------------------------------
|
||||
v0.17.1.0
|
||||
---------------------------------------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user