Merge branch 'dev' of https://github.com/Regalis11/Barotrauma.git into unstable-tests

This commit is contained in:
Evil Factory
2022-04-14 12:14:19 -03:00
43 changed files with 624 additions and 705 deletions

View File

@@ -551,8 +551,8 @@ namespace Barotrauma
{
bool hasOwner = inc.ReadBoolean();
int ownerId = hasOwner ? inc.ReadByte() : -1;
int balance = hasOwner ? inc.ReadInt32() : -1;
int rewardDistribution = hasOwner ? inc.ReadRangedInteger(0, 100) : -1;
int balance = inc.ReadInt32();
int rewardDistribution = inc.ReadRangedInteger(0, 100);
byte teamID = inc.ReadByte();
bool hasAi = inc.ReadBoolean();
Identifier infoSpeciesName = inc.ReadIdentifier();

View File

@@ -197,6 +197,14 @@ namespace Barotrauma.Transition
DebugConsole.ThrowError("There was an error transferring mods", t2.Exception.GetInnermost());
}
ContentPackageManager.LocalPackages.Refresh();
if (t2.TryGetResult(out string[] modsToEnable))
{
var newRegular = ContentPackageManager.EnabledPackages.Regular.ToList();
newRegular.AddRange(ContentPackageManager.LocalPackages.Regular
.Where(r => modsToEnable.Contains(r.Dir.CleanUpPathCrossPlatform(correctFilenameCase: false))));
newRegular = newRegular.Distinct().ToList();
ContentPackageManager.EnabledPackages.SetRegular(newRegular);
}
createSubMsgBox(TextManager.Get("Ugc.TransferComplete"), closable: true);
});
msgBox.Close();
@@ -287,19 +295,20 @@ namespace Barotrauma.Transition
&& !File.Exists(Path.Combine(folderName, readmeName));
}
private static async Task TransferMods(Dictionary<string, GUITickBox> pathTickboxMap)
private static async Task<string[]> TransferMods(Dictionary<string, GUITickBox> pathTickboxMap)
{
//WriteReadme(oldSubsPath); //can't do this because the old submarine discovery code is borked
WriteReadme(oldModsPath);
await Task.WhenAll(pathTickboxMap.Select(TransferMod));
var modsToEnable = (await Task.WhenAll(pathTickboxMap.Select(TransferMod))).OfType<string>().ToArray();
return modsToEnable;
}
private static Task TransferMod(KeyValuePair<string, GUITickBox> kvp)
private static Task<string?> TransferMod(KeyValuePair<string, GUITickBox> kvp)
=> TransferMod(kvp.Key, kvp.Value);
private static async Task TransferMod(string path, GUITickBox tickbox)
private static async Task<string?> TransferMod(string path, GUITickBox tickbox)
{
if (!tickbox.Selected) { return; }
if (!tickbox.Selected) { return null; }
string dirName = Path.GetFileNameWithoutExtension(path);
string destPath = Path.Combine(ContentPackage.LocalModsDir, dirName);
@@ -344,13 +353,15 @@ namespace Barotrauma.Transition
Directory.CreateDirectory(destPath);
File.Copy(path, Path.Combine(destPath, $"{dirName}.{(isSub ? "sub" : "xml")}"));
modProject.Save(Path.Combine(destPath, ContentPackage.FileListFileName));
await Task.Yield();
return destPath.CleanUpPathCrossPlatform(correctFilenameCase: false);
}
else
{
//copying a mod: we have a neat method for that!
await SteamManager.Workshop.CopyDirectory(path, Path.GetFileName(path), path, destPath);
return null;
}
}

View File

@@ -39,7 +39,7 @@ namespace Barotrauma
}
}
public void DebugDrawHUD(SpriteBatch spriteBatch, int y)
public void DebugDrawHUD(SpriteBatch spriteBatch, float y)
{
foreach (ScriptedEvent scriptedEvent in activeEvents.Where(ev => !ev.IsFinished && ev is ScriptedEvent).Cast<ScriptedEvent>())
{
@@ -50,20 +50,26 @@ namespace Barotrauma
float relativeMaxMonsterStrength = theoreticalMaxMonsterStrength * (GameMain.GameSession?.LevelData?.Difficulty ?? 0f) / 100;
float absoluteMonsterStrength = monsterStrength / theoreticalMaxMonsterStrength;
float relativeMonsterStrength = monsterStrength / relativeMaxMonsterStrength;
GUI.DrawString(spriteBatch, new Vector2(10, y), "EventManager", Color.White, Color.Black * 0.6f, 0, GUIStyle.SmallFont);
GUI.DrawString(spriteBatch, new Vector2(15, y + 20), "Event cooldown: " + (int)Math.Max(eventCoolDown, 0), Color.White, Color.Black * 0.6f, 0, GUIStyle.SmallFont);
GUI.DrawString(spriteBatch, new Vector2(15, y + 35), "Current intensity: " + (int)Math.Round(currentIntensity * 100), Color.Lerp(Color.White, GUIStyle.Red, currentIntensity), Color.Black * 0.6f, 0, GUIStyle.SmallFont);
GUI.DrawString(spriteBatch, new Vector2(15, y + 50), "Target intensity: " + (int)Math.Round(targetIntensity * 100), Color.Lerp(Color.White, GUIStyle.Red, targetIntensity), Color.Black * 0.6f, 0, GUIStyle.SmallFont);
GUI.DrawString(spriteBatch, new Vector2(15, y + 65), "Crew health: " + (int)Math.Round(avgCrewHealth * 100), Color.Lerp(GUIStyle.Red, GUIStyle.Green, avgCrewHealth), Color.Black * 0.6f, 0, GUIStyle.SmallFont);
GUI.DrawString(spriteBatch, new Vector2(15, y + 80), "Hull integrity: " + (int)Math.Round(avgHullIntegrity * 100), Color.Lerp(GUIStyle.Red, GUIStyle.Green, avgHullIntegrity), Color.Black * 0.6f, 0, GUIStyle.SmallFont);
GUI.DrawString(spriteBatch, new Vector2(15, y + 95), "Flooding amount: " + (int)Math.Round(floodingAmount * 100), Color.Lerp(GUIStyle.Green, GUIStyle.Red, floodingAmount), Color.Black * 0.6f, 0, GUIStyle.SmallFont);
GUI.DrawString(spriteBatch, new Vector2(15, y + 110), "Fire amount: " + (int)Math.Round(fireAmount * 100), Color.Lerp(GUIStyle.Green, GUIStyle.Red, fireAmount), Color.Black * 0.6f, 0, GUIStyle.SmallFont);
GUI.DrawString(spriteBatch, new Vector2(15, y + 125), "Enemy danger: " + (int)Math.Round(enemyDanger * 100), Color.Lerp(GUIStyle.Green, GUIStyle.Red, enemyDanger), Color.Black * 0.6f, 0, GUIStyle.SmallFont);
GUI.DrawString(spriteBatch, new Vector2(15, y + 140), "Current monster strength (total): " + (int)Math.Round(monsterStrength), Color.Lerp(GUIStyle.Green, GUIStyle.Red, relativeMonsterStrength), Color.Black * 0.6f, 0, GUIStyle.SmallFont);
GUI.DrawString(spriteBatch, new Vector2(15, y + 155), "Main events: " + (int)Math.Round(CumulativeMonsterStrengthMain), Color.White, Color.Black * 0.6f, 0, GUIStyle.SmallFont);
GUI.DrawString(spriteBatch, new Vector2(15, y + 170), "Ruin events: " + (int)Math.Round(CumulativeMonsterStrengthRuins), Color.White, Color.Black * 0.6f, 0, GUIStyle.SmallFont);
GUI.DrawString(spriteBatch, new Vector2(15, y + 185), "Wreck events: " + (int)Math.Round(CumulativeMonsterStrengthWrecks), Color.White, Color.Black * 0.6f, 0, GUIStyle.SmallFont);
GUI.DrawString(spriteBatch, new Vector2(10, y), "EventManager", Color.White, backgroundColor: Color.Black * 0.6f, font: GUIStyle.SmallFont);
DrawString("Event cooldown", Math.Max(eventCoolDown, 0), Color.White, spacing: 20);
DrawString("Current intensity", Math.Round(currentIntensity * 100), Color.Lerp(Color.White, GUIStyle.Red, currentIntensity));
DrawString("Target intensity", Math.Round(targetIntensity * 100), Color.Lerp(Color.White, GUIStyle.Red, targetIntensity));
DrawString("Crew health", Math.Round(avgCrewHealth * 100), Color.Lerp(GUIStyle.Red, GUIStyle.Green, avgCrewHealth));
DrawString("Hull integrity", Math.Round(avgHullIntegrity * 100), Color.Lerp(GUIStyle.Red, GUIStyle.Green, avgHullIntegrity));
DrawString("Flooding amount", Math.Round(floodingAmount * 100), Color.Lerp(GUIStyle.Green, GUIStyle.Red, floodingAmount));
DrawString("Fire amount", Math.Round(fireAmount * 100), Color.Lerp(GUIStyle.Green, GUIStyle.Red, fireAmount));
DrawString("Enemy danger", Math.Round(enemyDanger * 100), Color.Lerp(GUIStyle.Green, GUIStyle.Red, enemyDanger));
DrawString("Current monster strength (total)", Math.Round(monsterStrength), Color.Lerp(GUIStyle.Green, GUIStyle.Red, relativeMonsterStrength));
DrawString("Main events", Math.Round(CumulativeMonsterStrengthMain), Color.White);
DrawString("Ruin events", Math.Round(CumulativeMonsterStrengthRuins), Color.White);
DrawString("Wreck events", Math.Round(CumulativeMonsterStrengthWrecks), Color.White);
void DrawString(string text, double value, Color textColor, int spacing = 15)
{
y += GUI.AdjustForTextScale(spacing);
GUI.DrawString(spriteBatch, new Vector2(15, y), $"{text}: {(int)value}", textColor, backgroundColor: Color.Black * 0.6f, font: GUIStyle.SmallFont);
}
#if DEBUG
if (PlayerInput.KeyDown(Microsoft.Xna.Framework.Input.Keys.LeftAlt) &&
@@ -89,7 +95,7 @@ namespace Barotrauma
lastIntensityUpdate = (float)Timing.TotalTime;
}
Rectangle graphRect = new Rectangle(15, y + 240, (int)(200 * GUI.xScale), (int)(100 * GUI.yScale));
Rectangle graphRect = new Rectangle(15, (int)(y + GUI.AdjustForTextScale(55)), (int)(200 * GUI.xScale), (int)(100 * GUI.yScale));
bool isGraphHovered = graphRect.Contains(PlayerInput.MousePosition);
bool leftMousePressed = PlayerInput.PrimaryMouseButtonDown() || PlayerInput.PrimaryMouseButtonHeld();
bool rightMousePressed = PlayerInput.SecondaryMouseButtonHeld() || PlayerInput.SecondaryMouseButtonDown();
@@ -104,7 +110,9 @@ namespace Barotrauma
Color intensityColor = Color.Lerp(Color.White, GUIStyle.Red, currentIntensity);
if (isGraphHovered || isGraphSelected)
{
graphRect.Size = new Point(GameMain.GraphicsWidth - 30, (int)(GameMain.GraphicsHeight * 0.35f));
int padding = 15;
int graphHeight = Math.Min((int)(GameMain.GraphicsHeight * 0.35f), GameMain.GraphicsHeight - (graphRect.Top + 3 * padding));
graphRect.Size = new Point(GameMain.GraphicsWidth - 2 * padding, graphHeight);
intensityColor = Color.Red;
GUI.DrawRectangle(spriteBatch, graphRect, Color.Black * 0.95f, isFilled: true);
}
@@ -173,56 +181,58 @@ namespace Barotrauma
y += yStep;
}
int x = graphRect.X;
float adjustedYStep = GUI.AdjustForTextScale(15);
if (isCrewAway && crewAwayDuration < settings.FreezeDurationWhenCrewAway)
{
GUI.DrawString(spriteBatch, new Vector2(x, y), "Events frozen (crew away from sub): " + ToolBox.SecondsToReadableTime(settings.FreezeDurationWhenCrewAway - crewAwayDuration), Color.LightGreen * 0.8f, null, 0, GUIStyle.SmallFont);
y += 15;
y += adjustedYStep;
}
else if (crewAwayResetTimer > 0.0f)
{
GUI.DrawString(spriteBatch, new Vector2(x, y), "Events frozen (crew just returned to the sub): " + ToolBox.SecondsToReadableTime(crewAwayResetTimer), Color.LightGreen * 0.8f, null, 0, GUIStyle.SmallFont);
y += 15;
y += adjustedYStep;
}
else if (eventCoolDown > 0.0f)
{
GUI.DrawString(spriteBatch, new Vector2(x, y), "Event cooldown active: " + ToolBox.SecondsToReadableTime(eventCoolDown), Color.LightGreen * 0.8f, null, 0, GUIStyle.SmallFont);
y += 15;
y += adjustedYStep;
}
else if (currentIntensity > eventThreshold)
{
GUI.DrawString(spriteBatch, new Vector2(x, y),
"Intensity too high for new events: " + (int)(currentIntensity * 100) + "%/" + (int)(eventThreshold * 100) + "%", Color.LightGreen * 0.8f, null, 0, GUIStyle.SmallFont);
y += 15;
y += adjustedYStep;
}
adjustedYStep = GUI.AdjustForTextScale(12);
foreach (EventSet eventSet in pendingEventSets)
{
if (Submarine.MainSub == null) { break; }
GUI.DrawString(spriteBatch, new Vector2(x, y), "New event (ID " + eventSet.Identifier + ") after: ", Color.Orange * 0.8f, null, 0, GUIStyle.SmallFont);
y += 12;
y += adjustedYStep;
if (eventSet.PerCave)
{
GUI.DrawString(spriteBatch, new Vector2(x, y), " submarine near cave", Color.Orange * 0.8f, null, 0, GUIStyle.SmallFont);
y += 12;
y += adjustedYStep;
}
if (eventSet.PerWreck)
{
GUI.DrawString(spriteBatch, new Vector2(x, y), " submarine near the wreck", Color.Orange * 0.8f, null, 0, GUIStyle.SmallFont);
y += 12;
y += adjustedYStep;
}
if (eventSet.PerRuin)
{
GUI.DrawString(spriteBatch, new Vector2(x, y), " submarine near the ruins", Color.Orange * 0.8f, null, 0, GUIStyle.SmallFont);
y += 12;
y += adjustedYStep;
}
if (roundDuration < eventSet.MinMissionTime)
{
GUI.DrawString(spriteBatch, new Vector2(x, y),
" " + (int) (eventSet.MinDistanceTraveled * 100.0f) + "% travelled (current: " + (int) (distanceTraveled * 100.0f) + " %)",
((Submarine.MainSub == null || distanceTraveled < eventSet.MinDistanceTraveled) ? Color.Lerp(GUIStyle.Yellow, GUIStyle.Red, eventSet.MinDistanceTraveled - distanceTraveled) : GUIStyle.Green) * 0.8f, null, 0, GUIStyle.SmallFont);
y += 12;
y += adjustedYStep;
}
if (CurrentIntensity < eventSet.MinIntensity || CurrentIntensity > eventSet.MaxIntensity)
@@ -230,7 +240,7 @@ namespace Barotrauma
GUI.DrawString(spriteBatch, new Vector2(x, y),
" intensity between " + eventSet.MinIntensity.FormatDoubleDecimal() + " and " + eventSet.MaxIntensity.FormatDoubleDecimal(),
Color.Orange * 0.8f, null, 0, GUIStyle.SmallFont);
y += 12;
y += adjustedYStep;
}
if (roundDuration < eventSet.MinMissionTime)
@@ -240,7 +250,7 @@ namespace Barotrauma
Color.Lerp(GUIStyle.Yellow, GUIStyle.Red, (eventSet.MinMissionTime - roundDuration)), null, 0, GUIStyle.SmallFont);
}
y += 15;
y += GUI.AdjustForTextScale(15);
if (y > GameMain.GraphicsHeight * 0.9f)
{
@@ -252,11 +262,12 @@ namespace Barotrauma
GUI.DrawString(spriteBatch, new Vector2(x, y), "Current events: ", Color.White * 0.9f, null, 0, GUIStyle.SmallFont);
y += yStep;
adjustedYStep = GUI.AdjustForTextScale(18);
foreach (Event ev in activeEvents.Where(ev => !ev.IsFinished || PlayerInput.IsShiftDown()))
{
GUI.DrawString(spriteBatch, new Vector2(x + 5, y), ev.ToString(), (!ev.IsFinished ? Color.White : Color.Red) * 0.8f, null, 0, GUIStyle.SmallFont);
Rectangle rect = new Rectangle(new Point(x + 5, y), GUIStyle.SmallFont.MeasureString(ev.ToString()).ToPoint());
Rectangle rect = new Rectangle(new Point(x + 5, (int)y), GUIStyle.SmallFont.MeasureString(ev.ToString()).ToPoint());
Rectangle outlineRect = new Rectangle(rect.Location, rect.Size);
outlineRect.Inflate(4, 4);
@@ -281,7 +292,7 @@ namespace Barotrauma
}
}
y += 18;
y += adjustedYStep;
if (y > GameMain.GraphicsHeight * 0.9f)
{
y = graphRect.Bottom + yStep * 2;

View File

@@ -92,6 +92,7 @@ namespace Barotrauma
public static int IntScale(float f) => (int)(f * Scale);
public static int IntScaleFloor(float f) => (int)Math.Floor(f * Scale);
public static int IntScaleCeiling(float f) => (int)Math.Ceiling(f * Scale);
public static float AdjustForTextScale(float f) => f * GameSettings.CurrentConfig.Graphics.TextScale;
public static float HorizontalAspectRatio => GameMain.GraphicsWidth / (float)GameMain.GraphicsHeight;
public static float VerticalAspectRatio => GameMain.GraphicsHeight / (float)GameMain.GraphicsWidth;
public static float RelativeHorizontalAspectRatio => HorizontalAspectRatio / (ReferenceResolution.X / ReferenceResolution.Y);
@@ -299,15 +300,16 @@ namespace Barotrauma
return;
}
float startY = 10.0f;
if (GameMain.ShowFPS || GameMain.DebugDraw || GameMain.ShowPerf)
{
float y = 10.0f;
float y = startY;
DrawString(spriteBatch, new Vector2(10, y),
"FPS: " + Math.Round(GameMain.PerformanceCounter.AverageFramesPerSecond),
Color.White, Color.Black * 0.5f, 0, GUIStyle.SmallFont);
if (GameMain.GameSession != null && Timing.TotalTime > GameMain.GameSession.RoundStartTime + 1.0)
{
y += GameSettings.CurrentConfig.Graphics.TextScale * 15.0f;
y += AdjustForTextScale(15) * yScale;
DrawString(spriteBatch, new Vector2(10, y),
$"Physics: {GameMain.CurrentUpdateRate}",
(GameMain.CurrentUpdateRate < Timing.FixedUpdateRate) ? Color.Red : Color.White, Color.Black * 0.5f, 0, GUIStyle.SmallFont);
@@ -316,83 +318,88 @@ namespace Barotrauma
if (GameMain.ShowPerf)
{
int x = 400;
int y = 10;
float x = 400;
float y = startY;
DrawString(spriteBatch, new Vector2(x, y),
"Draw - Avg: " + GameMain.PerformanceCounter.DrawTimeGraph.Average().ToString("0.00") + " ms" +
" Max: " + GameMain.PerformanceCounter.DrawTimeGraph.LargestValue().ToString("0.00") + " ms",
GUIStyle.Green, Color.Black * 0.8f, font: GUIStyle.SmallFont);
y += 15;
GameMain.PerformanceCounter.DrawTimeGraph.Draw(spriteBatch, new Rectangle(x, y, 170, 50), color: GUIStyle.Green);
y += 50;
y += 15 * yScale;
GameMain.PerformanceCounter.DrawTimeGraph.Draw(spriteBatch, new Rectangle((int)x, (int)y, 170, 50), color: GUIStyle.Green);
y += 50 * yScale;
DrawString(spriteBatch, new Vector2(x, y),
"Update - Avg: " + GameMain.PerformanceCounter.UpdateTimeGraph.Average().ToString("0.00") + " ms" +
" Max: " + GameMain.PerformanceCounter.UpdateTimeGraph.LargestValue().ToString("0.00") + " ms",
Color.LightBlue, Color.Black * 0.8f, font: GUIStyle.SmallFont);
y += 15;
GameMain.PerformanceCounter.UpdateTimeGraph.Draw(spriteBatch, new Rectangle(x, y, 170, 50), color: Color.LightBlue);
y += 50;
y += 15 * yScale;
GameMain.PerformanceCounter.UpdateTimeGraph.Draw(spriteBatch, new Rectangle((int)x, (int)y, 170, 50), color: Color.LightBlue);
y += 50 * yScale;
foreach (string key in GameMain.PerformanceCounter.GetSavedIdentifiers)
{
float elapsedMillisecs = GameMain.PerformanceCounter.GetAverageElapsedMillisecs(key);
DrawString(spriteBatch, new Vector2(x, y),
key + ": " + elapsedMillisecs.ToString("0.00"),
Color.Lerp(Color.LightGreen, GUIStyle.Red, elapsedMillisecs / 10.0f), Color.Black * 0.5f, 0, GUIStyle.SmallFont);
y += 15;
y += 15 * yScale;
foreach (string childKey in GameMain.PerformanceCounter.GetSavedPartialIdentifiers(key))
{
elapsedMillisecs = GameMain.PerformanceCounter.GetPartialAverageElapsedMillisecs(key, childKey);
DrawString(spriteBatch, new Vector2(x + 15, y),
childKey + ": " + elapsedMillisecs.ToString("0.00"),
Color.Lerp(Color.LightGreen, GUIStyle.Red, elapsedMillisecs / 10.0f), Color.Black * 0.5f, 0, GUIStyle.SmallFont);
y += 15;
y += 15 * yScale;
}
}
if (Powered.Grids != null)
{
DrawString(spriteBatch, new Vector2(x, y), "Grids: " + Powered.Grids.Count, Color.LightGreen, Color.Black * 0.5f, 0, GUIStyle.SmallFont);
y += 15;
y += 15 * yScale;
}
if (Settings.EnableDiagnostics)
{
x += 20;
x += 20 * xScale;
DrawString(spriteBatch, new Vector2(x, y), "ContinuousPhysicsTime: " + GameMain.World.ContinuousPhysicsTime.TotalMilliseconds, Color.Lerp(Color.LightGreen, GUIStyle.Red, (float)GameMain.World.ContinuousPhysicsTime.TotalMilliseconds / 10.0f), Color.Black * 0.5f, 0, GUIStyle.SmallFont);
DrawString(spriteBatch, new Vector2(x, y + 15), "ControllersUpdateTime: " + GameMain.World.ControllersUpdateTime.TotalMilliseconds, Color.Lerp(Color.LightGreen, GUIStyle.Red, (float)GameMain.World.ControllersUpdateTime.TotalMilliseconds / 10.0f), Color.Black * 0.5f, 0, GUIStyle.SmallFont);
DrawString(spriteBatch, new Vector2(x, y + 30), "AddRemoveTime: " + GameMain.World.AddRemoveTime.TotalMilliseconds, Color.Lerp(Color.LightGreen, GUIStyle.Red, (float)GameMain.World.AddRemoveTime.TotalMilliseconds / 10.0f), Color.Black * 0.5f, 0, GUIStyle.SmallFont);
DrawString(spriteBatch, new Vector2(x, y + 45), "NewContactsTime: " + GameMain.World.NewContactsTime.TotalMilliseconds, Color.Lerp(Color.LightGreen, GUIStyle.Red, (float)GameMain.World.NewContactsTime.TotalMilliseconds / 10.0f), Color.Black * 0.5f, 0, GUIStyle.SmallFont);
DrawString(spriteBatch, new Vector2(x, y + 60), "ContactsUpdateTime: " + GameMain.World.ContactsUpdateTime.TotalMilliseconds, Color.Lerp(Color.LightGreen, GUIStyle.Red, (float)GameMain.World.ContactsUpdateTime.TotalMilliseconds / 10.0f), Color.Black * 0.5f, 0, GUIStyle.SmallFont);
DrawString(spriteBatch, new Vector2(x, y + 75), "SolveUpdateTime: " + GameMain.World.SolveUpdateTime.TotalMilliseconds, Color.Lerp(Color.LightGreen, GUIStyle.Red, (float)GameMain.World.SolveUpdateTime.TotalMilliseconds / 10.0f), Color.Black * 0.5f, 0, GUIStyle.SmallFont);
DrawString(spriteBatch, new Vector2(x, y + 15 * yScale), "ControllersUpdateTime: " + GameMain.World.ControllersUpdateTime.TotalMilliseconds, Color.Lerp(Color.LightGreen, GUIStyle.Red, (float)GameMain.World.ControllersUpdateTime.TotalMilliseconds / 10.0f), Color.Black * 0.5f, 0, GUIStyle.SmallFont);
DrawString(spriteBatch, new Vector2(x, y + 30 * yScale), "AddRemoveTime: " + GameMain.World.AddRemoveTime.TotalMilliseconds, Color.Lerp(Color.LightGreen, GUIStyle.Red, (float)GameMain.World.AddRemoveTime.TotalMilliseconds / 10.0f), Color.Black * 0.5f, 0, GUIStyle.SmallFont);
DrawString(spriteBatch, new Vector2(x, y + 45 * yScale), "NewContactsTime: " + GameMain.World.NewContactsTime.TotalMilliseconds, Color.Lerp(Color.LightGreen, GUIStyle.Red, (float)GameMain.World.NewContactsTime.TotalMilliseconds / 10.0f), Color.Black * 0.5f, 0, GUIStyle.SmallFont);
DrawString(spriteBatch, new Vector2(x, y + 60 * yScale), "ContactsUpdateTime: " + GameMain.World.ContactsUpdateTime.TotalMilliseconds, Color.Lerp(Color.LightGreen, GUIStyle.Red, (float)GameMain.World.ContactsUpdateTime.TotalMilliseconds / 10.0f), Color.Black * 0.5f, 0, GUIStyle.SmallFont);
DrawString(spriteBatch, new Vector2(x, y + 75 * yScale), "SolveUpdateTime: " + GameMain.World.SolveUpdateTime.TotalMilliseconds, Color.Lerp(Color.LightGreen, GUIStyle.Red, (float)GameMain.World.SolveUpdateTime.TotalMilliseconds / 10.0f), Color.Black * 0.5f, 0, GUIStyle.SmallFont);
}
}
if (GameMain.DebugDraw && !Submarine.Unloading && !(Screen.Selected is RoundSummaryScreen))
{
DrawString(spriteBatch, new Vector2(10, 25),
float y = startY + 15 * yScale;
DrawString(spriteBatch, new Vector2(10, y),
"Physics: " + GameMain.World.UpdateTime,
Color.White, Color.Black * 0.5f, 0, GUIStyle.SmallFont);
DrawString(spriteBatch, new Vector2(10, 40),
y += 15 * yScale;
DrawString(spriteBatch, new Vector2(10, y),
$"Bodies: {GameMain.World.BodyList.Count} ({GameMain.World.BodyList.Count(b => b != null && b.Awake && b.Enabled)} awake, {GameMain.World.BodyList.Count(b => b != null && b.Awake && b.BodyType == BodyType.Dynamic && b.Enabled)} dynamic)",
Color.White, Color.Black * 0.5f, 0, GUIStyle.SmallFont);
if (Screen.Selected.Cam != null)
{
DrawString(spriteBatch, new Vector2(10, 55),
y += 15 * yScale;
DrawString(spriteBatch, new Vector2(10, y),
"Camera pos: " + Screen.Selected.Cam.Position.ToPoint() + ", zoom: " + Screen.Selected.Cam.Zoom,
Color.White, Color.Black * 0.5f, 0, GUIStyle.SmallFont);
}
if (Submarine.MainSub != null)
{
DrawString(spriteBatch, new Vector2(10, 70),
y += 15 * yScale;
DrawString(spriteBatch, new Vector2(10, y),
"Sub pos: " + Submarine.MainSub.Position.ToPoint(),
Color.White, Color.Black * 0.5f, 0, GUIStyle.SmallFont);
}
DrawString(spriteBatch, new Vector2(10, 90),
y += 20 * yScale;
DrawString(spriteBatch, new Vector2(10, y),
"Particle count: " + GameMain.ParticleManager.ParticleCount + "/" + GameMain.ParticleManager.MaxParticles,
Color.Lerp(GUIStyle.Green, GUIStyle.Red, (GameMain.ParticleManager.ParticleCount / (float)GameMain.ParticleManager.MaxParticles)), Color.Black * 0.5f, 0, GUIStyle.SmallFont);
@@ -401,28 +408,29 @@ namespace Barotrauma
loadedSpritesText = "Loaded sprites: " + Sprite.LoadedSprites.Count() + "\n(" + Sprite.LoadedSprites.Select(s => s.FilePath).Distinct().Count() + " unique textures)";
loadedSpritesUpdateTime = DateTime.Now + new TimeSpan(0, 0, seconds: 5);
}
DrawString(spriteBatch, new Vector2(10, 115), loadedSpritesText, Color.White, Color.Black * 0.5f, 0, GUIStyle.SmallFont);
y += 25 * yScale;
DrawString(spriteBatch, new Vector2(10, y), loadedSpritesText, Color.White, Color.Black * 0.5f, 0, GUIStyle.SmallFont);
if (debugDrawSounds)
{
int y = 0;
DrawString(spriteBatch, new Vector2(500, y),
float soundTextY = 0;
DrawString(spriteBatch, new Vector2(500, soundTextY),
"Sounds (Ctrl+S to hide): ", Color.White, Color.Black * 0.5f, 0, GUIStyle.SmallFont);
y += 15;
soundTextY += 15 * yScale;
DrawString(spriteBatch, new Vector2(500, y),
DrawString(spriteBatch, new Vector2(500, soundTextY),
"Current playback amplitude: " + GameMain.SoundManager.PlaybackAmplitude.ToString(), Color.White, Color.Black * 0.5f, 0, GUIStyle.SmallFont);
y += 15;
soundTextY += 15 * yScale;
DrawString(spriteBatch, new Vector2(500, y),
DrawString(spriteBatch, new Vector2(500, soundTextY),
"Compressed dynamic range gain: " + GameMain.SoundManager.CompressionDynamicRangeGain.ToString(), Color.White, Color.Black * 0.5f, 0, GUIStyle.SmallFont);
y += 15;
soundTextY += 15 * yScale;
DrawString(spriteBatch, new Vector2(500, y),
DrawString(spriteBatch, new Vector2(500, soundTextY),
"Loaded sounds: " + GameMain.SoundManager.LoadedSoundCount + " (" + GameMain.SoundManager.UniqueLoadedSoundCount + " unique)", Color.White, Color.Black * 0.5f, 0, GUIStyle.SmallFont);
y += 15;
soundTextY += 15 * yScale;
for (int i = 0; i < SoundManager.SOURCE_COUNT; i++)
{
@@ -441,7 +449,7 @@ namespace Barotrauma
#if DEBUG
if (PlayerInput.GetKeyboardState.IsKeyDown(Keys.G))
{
if (PlayerInput.MousePosition.Y >= y && PlayerInput.MousePosition.Y <= y + 12)
if (PlayerInput.MousePosition.Y >= soundTextY && PlayerInput.MousePosition.Y <= soundTextY + 12)
{
GameMain.SoundManager.DebugSource(i);
}
@@ -470,8 +478,8 @@ namespace Barotrauma
}
}
DrawString(spriteBatch, new Vector2(500, y), soundStr, clr, Color.Black * 0.5f, 0, GUIStyle.SmallFont);
y += 15;
DrawString(spriteBatch, new Vector2(500, soundTextY), soundStr, clr, Color.Black * 0.5f, 0, GUIStyle.SmallFont);
soundTextY += 15 * yScale;
}
}
else
@@ -481,20 +489,22 @@ namespace Barotrauma
}
y += 185 * yScale;
if (debugDrawEvents)
{
DrawString(spriteBatch, new Vector2(10, 300),
DrawString(spriteBatch, new Vector2(10, y),
"Ctrl+E to hide EventManager debug info", Color.White, Color.Black * 0.5f, 0, GUIStyle.SmallFont);
GameMain.GameSession?.EventManager?.DebugDrawHUD(spriteBatch, 315);
GameMain.GameSession?.EventManager?.DebugDrawHUD(spriteBatch, y + 15 * yScale);
}
else
{
DrawString(spriteBatch, new Vector2(10, 300),
DrawString(spriteBatch, new Vector2(10, y),
"Ctrl+E to show EventManager debug info", Color.White, Color.Black * 0.5f, 0, GUIStyle.SmallFont);
}
if (GameMain.GameSession?.GameMode is CampaignMode campaignMode)
{
// TODO: TEST THIS
if (debugDrawMetadata)
{
string text = "Ctrl+M to hide campaign metadata debug info\n\n" +
@@ -502,10 +512,10 @@ namespace Barotrauma
$"Ctrl+2 to {(string.IsNullOrWhiteSpace(ignoredMetadataInfo[1]) ? "hide" : "show")} faction reputations, \n" +
$"Ctrl+3 to {(string.IsNullOrWhiteSpace(ignoredMetadataInfo[2]) ? "hide" : "show")} upgrade levels, \n" +
$"Ctrl+4 to {(string.IsNullOrWhiteSpace(ignoredMetadataInfo[3]) ? "hide" : "show")} upgrade prices";
var (x, y) = GUIStyle.SmallFont.MeasureString(text);
Vector2 pos = new Vector2(GameMain.GraphicsWidth - (x + 10), 300);
Vector2 textSize = GUIStyle.SmallFont.MeasureString(text);
Vector2 pos = new Vector2(GameMain.GraphicsWidth - (textSize.X + 10), 300);
DrawString(spriteBatch, pos, text, Color.White, Color.Black * 0.5f, 0, GUIStyle.SmallFont);
pos.Y += y + 8;
pos.Y += textSize.Y + 8;
campaignMode.CampaignMetadata?.DebugDraw(spriteBatch, pos, debugDrawMetadataOffset, ignoredMetadataInfo);
}
else

View File

@@ -1,9 +1,8 @@
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using Barotrauma.Items.Components;
using Barotrauma.Items.Components;
using Barotrauma.Networking;
using Microsoft.Xna.Framework;
using System.Collections.Generic;
using System.Linq;
namespace Barotrauma.Tutorials
{
@@ -14,8 +13,6 @@ namespace Barotrauma.Tutorials
private float shakeAmount = 20f;
// Room 2
private MotionSensor captain_equipmentObjectiveSensor;
private ItemContainer captain_equipmentCabinet;
private Door captain_firstDoor;
private LightComponent captain_firstDoorLight;
@@ -29,7 +26,6 @@ namespace Barotrauma.Tutorials
// Submarine
private MotionSensor captain_enteredSubmarineSensor;
private Steering captain_navConsole;
private CustomInterface captain_navConsoleCustomInterface;
private Sonar captain_sonar;
private Item captain_statusMonitor;
private Character captain_security;
@@ -136,8 +132,6 @@ namespace Barotrauma.Tutorials
captain_steerIconColor = steerOrder.Color;
// Room 2
captain_equipmentObjectiveSensor = Item.ItemList.Find(i => i.HasTag("captain_equipmentobjectivesensor")).GetComponent<MotionSensor>();
captain_equipmentCabinet = Item.ItemList.Find(i => i.HasTag("captain_equipmentcabinet")).GetComponent<ItemContainer>();
captain_firstDoor = Item.ItemList.Find(i => i.HasTag("captain_firstdoor")).GetComponent<Door>();
captain_firstDoorLight = Item.ItemList.Find(i => i.HasTag("captain_firstdoorlight")).GetComponent<LightComponent>();
@@ -148,9 +142,11 @@ namespace Barotrauma.Tutorials
captain_medicSpawnPos = Item.ItemList.Find(i => i.HasTag("captain_medicspawnpos")).WorldPosition;
tutorial_submarineDoor = Item.ItemList.Find(i => i.HasTag("tutorial_submarinedoor")).GetComponent<Door>();
tutorial_submarineDoorLight = Item.ItemList.Find(i => i.HasTag("tutorial_submarinedoorlight")).GetComponent<LightComponent>();
var medicInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, jobOrJobPrefab: JobPrefab.Get("medicaldoctor"));
var medicInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, jobOrJobPrefab: JobPrefab.Get("medicaldoctor"))
{
TeamID = CharacterTeamType.Team1
};
captain_medic = Character.Create(medicInfo, captain_medicSpawnPos, "medicaldoctor");
captain_medic.TeamID = CharacterTeamType.Team1;
captain_medic.GiveJobItems(null);
captain_medic.CanSpeak = captain_medic.AIController.Enabled = false;
SetDoorAccess(tutorial_submarineDoor, tutorial_submarineDoorLight, false);
@@ -159,7 +155,6 @@ namespace Barotrauma.Tutorials
captain_enteredSubmarineSensor = Item.ItemList.Find(i => i.HasTag("captain_enteredsubmarinesensor")).GetComponent<MotionSensor>();
tutorial_submarineReactor = Item.ItemList.Find(i => i.HasTag("engineer_submarinereactor")).GetComponent<Reactor>();
captain_navConsole = Item.ItemList.Find(i => i.HasTag("command")).GetComponent<Steering>();
captain_navConsoleCustomInterface = Item.ItemList.Find(i => i.HasTag("command")).GetComponent<CustomInterface>();
captain_sonar = captain_navConsole.Item.GetComponent<Sonar>();
captain_statusMonitor = Item.ItemList.Find(i => i.HasTag("captain_statusmonitor"));
@@ -171,19 +166,25 @@ namespace Barotrauma.Tutorials
SetDoorAccess(tutorial_lockedDoor_1, null, false);
SetDoorAccess(tutorial_lockedDoor_2, null, false);
var mechanicInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, jobOrJobPrefab: JobPrefab.Get("mechanic"));
var mechanicInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, jobOrJobPrefab: JobPrefab.Get("mechanic"))
{
TeamID = CharacterTeamType.Team1
};
captain_mechanic = Character.Create(mechanicInfo, WayPoint.GetRandom(SpawnType.Human, mechanicInfo.Job?.Prefab, Submarine.MainSub).WorldPosition, "mechanic");
captain_mechanic.TeamID = CharacterTeamType.Team1;
captain_mechanic.GiveJobItems();
var securityInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, jobOrJobPrefab: JobPrefab.Get("securityofficer"));
var securityInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, jobOrJobPrefab: JobPrefab.Get("securityofficer"))
{
TeamID = CharacterTeamType.Team1
};
captain_security = Character.Create(securityInfo, WayPoint.GetRandom(SpawnType.Human, securityInfo.Job?.Prefab, Submarine.MainSub).WorldPosition, "securityofficer");
captain_security.TeamID = CharacterTeamType.Team1;
captain_security.GiveJobItems();
var engineerInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, jobOrJobPrefab: JobPrefab.Get("engineer"));
var engineerInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, jobOrJobPrefab: JobPrefab.Get("engineer"))
{
TeamID = CharacterTeamType.Team1
};
captain_engineer = Character.Create(engineerInfo, WayPoint.GetRandom(SpawnType.Human, engineerInfo.Job?.Prefab, Submarine.MainSub).WorldPosition, "engineer");
captain_engineer.TeamID = CharacterTeamType.Team1;
captain_engineer.GiveJobItems();
captain_mechanic.CanSpeak = captain_security.CanSpeak = captain_engineer.CanSpeak = false;
@@ -252,6 +253,9 @@ namespace Barotrauma.Tutorials
yield return new WaitForSeconds(4f, false);
TriggerTutorialSegment(3, GameSettings.CurrentConfig.KeyMap.KeyBindText(InputType.Command));
GameMain.GameSession.CrewManager.AddCharacter(captain_engineer);
tutorial_submarineReactor.CanBeSelected = true;
//recreate autonomous objectives to make sure the engineer didn't abandon the operate reactor objective because it was not selectable
(captain_engineer.AIController as HumanAIController).ObjectiveManager.CreateAutonomousObjectives();
do
{
yield return null;
@@ -261,7 +265,6 @@ namespace Barotrauma.Tutorials
}
while (!HasOrder(captain_engineer, "operatereactor", "powerup"));
RemoveCompletedObjective(3);
tutorial_submarineReactor.CanBeSelected = true;
do { yield return null; } while (!tutorial_submarineReactor.IsActive); // Wait until reactor on
TriggerTutorialSegment(4);
while (ContentRunning) yield return null;

View File

@@ -4,8 +4,6 @@ using Microsoft.Xna.Framework;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
namespace Barotrauma.Tutorials
{
@@ -130,24 +128,32 @@ namespace Barotrauma.Tutorials
var patientHull2 = WayPoint.WayPointList.Find(wp => wp.IdCardDesc == "airlock").CurrentHull;
medBay = WayPoint.WayPointList.Find(wp => wp.IdCardDesc == "medbay").CurrentHull;
var assistantInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, jobOrJobPrefab: JobPrefab.Get("assistant"));
var assistantInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, jobOrJobPrefab: JobPrefab.Get("assistant"))
{
TeamID = CharacterTeamType.Team1
};
patient1 = Character.Create(assistantInfo, patientHull1.WorldPosition, "1");
patient1.TeamID = CharacterTeamType.Team1;
patient1.GiveJobItems(null);
patient1.CanSpeak = false;
patient1.Params.Health.BurnReduction = 0;
patient1.AddDamage(patient1.WorldPosition, new List<Affliction>() { new Affliction(AfflictionPrefab.Burn, 15.0f) }, stun: 0, playSound: false);
patient1.AIController.Enabled = false;
assistantInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, jobOrJobPrefab: JobPrefab.Get("assistant"));
assistantInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, jobOrJobPrefab: JobPrefab.Get("assistant"))
{
TeamID = CharacterTeamType.Team1
};
patient2 = Character.Create(assistantInfo, patientHull2.WorldPosition, "2");
patient2.TeamID = CharacterTeamType.Team1;
patient2.GiveJobItems(null);
patient2.CanSpeak = false;
patient2.AIController.Enabled = false;
var mechanicInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, jobOrJobPrefab: JobPrefab.Get("engineer"));
var mechanicInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, jobOrJobPrefab: JobPrefab.Get("engineer"))
{
TeamID = CharacterTeamType.Team1
};
var subPatient1 = Character.Create(mechanicInfo, WayPoint.GetRandom(SpawnType.Human, mechanicInfo.Job?.Prefab, Submarine.MainSub).WorldPosition, "3");
subPatient1.TeamID = CharacterTeamType.Team1;
subPatient1.Params.Health.BurnReduction = 0;
subPatient1.AddDamage(patient1.WorldPosition, new List<Affliction>() { new Affliction(AfflictionPrefab.Burn, 40.0f) }, stun: 0, playSound: false);
subPatients.Add(subPatient1);
@@ -157,9 +163,12 @@ namespace Barotrauma.Tutorials
subPatient2.AddDamage(patient1.WorldPosition, new List<Affliction>() { new Affliction(AfflictionPrefab.InternalDamage, 40.0f) }, stun: 0, playSound: false);
subPatients.Add(subPatient2);
var engineerInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, jobOrJobPrefab: JobPrefab.Get("engineer"));
var engineerInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, jobOrJobPrefab: JobPrefab.Get("engineer"))
{
TeamID = CharacterTeamType.Team1
};
var subPatient3 = Character.Create(securityInfo, WayPoint.GetRandom(SpawnType.Human, engineerInfo.Job?.Prefab, Submarine.MainSub).WorldPosition, "3");
subPatient3.TeamID = CharacterTeamType.Team1;
subPatient3.Params.Health.BurnReduction = 0;
subPatient3.AddDamage(patient1.WorldPosition, new List<Affliction>() { new Affliction(AfflictionPrefab.Burn, 20.0f) }, stun: 0, playSound: false);
subPatients.Add(subPatient3);

View File

@@ -25,20 +25,17 @@ namespace Barotrauma.Tutorials
private LightComponent engineer_firstDoorLight;
// Room 3
private MotionSensor engineer_reactorObjectiveSensor;
private Powered tutorial_oxygenGenerator;
private Reactor engineer_reactor;
private Door engineer_secondDoor;
private LightComponent engineer_secondDoorLight;
// Room 4
private MotionSensor engineer_repairJunctionBoxObjectiveSensor;
private Item engineer_brokenJunctionBox;
private Door engineer_thirdDoor;
private LightComponent engineer_thirdDoorLight;
// Room 5
private MotionSensor engineer_disconnectedJunctionBoxObjectiveSensor;
private PowerTransfer[] engineer_disconnectedJunctionBoxes;
private ConnectionPanel[] engineer_disconnectedConnectionPanels;
private Item engineer_wire_1;
@@ -169,7 +166,6 @@ namespace Barotrauma.Tutorials
SetDoorAccess(engineer_firstDoor, engineer_firstDoorLight, false);
// Room 3
engineer_reactorObjectiveSensor = Item.ItemList.Find(i => i.HasTag("engineer_reactorobjectivesensor")).GetComponent<MotionSensor>();
tutorial_oxygenGenerator = Item.ItemList.Find(i => i.HasTag("tutorial_oxygengenerator")).GetComponent<OxygenGenerator>();
engineer_reactor = Item.ItemList.Find(i => i.HasTag("engineer_reactor")).GetComponent<Reactor>();
engineer_reactor.FireDelay = engineer_reactor.MeltdownDelay = float.PositiveInfinity;
@@ -183,7 +179,6 @@ namespace Barotrauma.Tutorials
SetDoorAccess(engineer_secondDoor, engineer_secondDoorLight, false);
// Room 4
engineer_repairJunctionBoxObjectiveSensor = Item.ItemList.Find(i => i.HasTag("engineer_repairjunctionboxobjectivesensor")).GetComponent<MotionSensor>();
engineer_brokenJunctionBox = Item.ItemList.Find(i => i.HasTag("engineer_brokenjunctionbox"));
engineer_thirdDoor = Item.ItemList.Find(i => i.HasTag("engineer_thirddoor")).GetComponent<Door>();
engineer_thirdDoorLight = Item.ItemList.Find(i => i.HasTag("engineer_thirddoorlight")).GetComponent<LightComponent>();
@@ -194,8 +189,6 @@ namespace Barotrauma.Tutorials
SetDoorAccess(engineer_thirdDoor, engineer_thirdDoorLight, false);
// Room 5
engineer_disconnectedJunctionBoxObjectiveSensor = Item.ItemList.Find(i => i.HasTag("engineer_disconnectedjunctionboxobjectivesensor")).GetComponent<MotionSensor>();
engineer_disconnectedJunctionBoxes = new PowerTransfer[4];
engineer_disconnectedConnectionPanels = new ConnectionPanel[4];
@@ -255,7 +248,7 @@ namespace Barotrauma.Tutorials
public override IEnumerable<CoroutineStatus> UpdateState()
{
while (GameMain.Instance.LoadingScreenOpen) yield return null;
while (GameMain.Instance.LoadingScreenOpen) { yield return null; }
// Room 1
SoundPlayer.PlayDamageSound("StructureBlunt", 10, Character.Controlled.WorldPosition);
@@ -519,10 +512,10 @@ namespace Barotrauma.Tutorials
tutorial_oxygenGenerator.PowerConsumption = reactorLoads[i];
while (timer > 0)
{
yield return new WaitForSeconds(0.1f, false);
if (IsReactorPoweredUp(engineer_reactor))
yield return CoroutineStatus.Running;
if (CoroutineManager.DeltaTime > 0.0f && IsReactorPoweredUp(engineer_reactor))
{
timer -= 0.1f;
timer -= CoroutineManager.DeltaTime;
}
}
}

View File

@@ -437,7 +437,12 @@ namespace Barotrauma
foreach (GUIComponent child in reputationList.Content.Children)
{
var descriptionElement = child.FindChild("description", recursive: true) as GUITextBlock;
maxDescriptionHeight = Math.Max(maxDescriptionHeight, descriptionElement.TextSize.Y * 1.1f);
float descriptionHeight = descriptionElement.TextSize.Y * 1.1f;
if (child.FindChild("unlockinfo") is GUIComponent unlockInfoComponent)
{
descriptionHeight += 1.25f * unlockInfoComponent.Rect.Height;
}
maxDescriptionHeight = Math.Max(maxDescriptionHeight, descriptionHeight);
}
foreach (GUIComponent child in reputationList.Content.Children)
{
@@ -488,6 +493,7 @@ namespace Barotrauma
var unlockInfoPanel = new GUITextBlock(new RectTransform(new Vector2(0.8f, 0.0f), reputationFrame.RectTransform, Anchor.BottomCenter) { MinSize = new Point(0, GUI.IntScale(30)), AbsoluteOffset = new Point(0, GUI.IntScale(3)) },
unlockText, style: "GUIButtonRound", textAlignment: Alignment.Center, textColor: GUIStyle.TextColorNormal);
unlockInfoPanel.Color = Color.Lerp(unlockInfoPanel.Color, Color.Black, 0.8f);
unlockInfoPanel.UserData = "unlockinfo";
if (unlockInfoPanel.TextSize.X > unlockInfoPanel.Rect.Width * 0.7f)
{
unlockInfoPanel.Font = GUIStyle.SmallFont;

View File

@@ -667,7 +667,7 @@ namespace Barotrauma.Networking
if (ChildServerRelay.Process?.HasExited ?? true)
{
Disconnect();
if (!GUIMessageBox.MessageBoxes.Any(mb => (mb as GUIMessageBox).Text.Text == ChildServerRelay.CrashMessage))
if (!GUIMessageBox.MessageBoxes.Any(mb => (mb as GUIMessageBox)?.Text.Text == ChildServerRelay.CrashMessage))
{
var msgBox = new GUIMessageBox(TextManager.Get("ConnectionLost"), ChildServerRelay.CrashMessage);
msgBox.Buttons[0].OnClicked += ReturnToPreviousMenu;
@@ -2486,12 +2486,20 @@ namespace Barotrauma.Networking
public void RequestFile(FileTransferType fileType, string file, string fileHash)
{
DebugConsole.Log(
fileType == FileTransferType.CampaignSave ?
$"Sending a campaign file request to the server." :
$"Sending a file request to the server (type: {fileType}, path: {file ?? "null"}");
IWriteMessage msg = new WriteOnlyMessage();
msg.Write((byte)ClientPacketHeader.FILE_REQUEST);
msg.Write((byte)FileTransferMessageType.Initiate);
msg.Write((byte)fileType);
msg.Write(file ?? throw new ArgumentNullException(nameof(file)));
msg.Write(fileHash ?? throw new ArgumentNullException(nameof(fileHash)));
if (fileType != FileTransferType.CampaignSave)
{
msg.Write(file ?? throw new ArgumentNullException(nameof(file)));
msg.Write(fileHash ?? throw new ArgumentNullException(nameof(fileHash)));
}
clientPeer.Send(msg, DeliveryMethod.Reliable);
}

View File

@@ -262,11 +262,32 @@ namespace Barotrauma.CharacterEditor
FileSelection.OnFileSelected = (file) =>
{
string relativePath = Path.GetRelativePath(Environment.CurrentDirectory, Path.GetFullPath(file));
if (relativePath.StartsWith(ContentPackage.LocalModsDir))
{
string[] pathSplit = relativePath.Split('/', '\\');
string modDirName = $"{ContentPackage.LocalModsDir}/{pathSplit[1]}";
string selectedModDir
= (contentPackageDropDown.ListBox.SelectedData as ContentPackage)?.Dir.CleanUpPathCrossPlatform(correctFilenameCase: false)
?? "";
if (modDirName == selectedModDir)
{
relativePath = ContentPath.ModDirStr + "/" +
string.Join("/", pathSplit[2..]);
}
else
{
relativePath = string.Format(ContentPath.OtherModDirFmt,
pathSplit[1]) + "/" +
string.Join("/", pathSplit[2..]);
}
}
string destinationPath = relativePath;
//copy file to XML path if it's not located relative to the game's files
if (relativePath.StartsWith("..") ||
Path.GetPathRoot(Environment.CurrentDirectory) != Path.GetPathRoot(file))
//copy file to XML path if it's not located relative to the game's files
if (relativePath.StartsWith("..") ||
Path.GetPathRoot(Environment.CurrentDirectory) != Path.GetPathRoot(file))
{
destinationPath = Path.Combine(Path.GetDirectoryName(XMLPath), Path.GetFileName(file));
@@ -387,16 +408,20 @@ namespace Barotrauma.CharacterEditor
contentPackageDropDown.Flash();
return false;
}
string evaluatedTexturePath = ContentPath.FromRaw(
contentPackageDropDown.SelectedData as ContentPackage,
TexturePath).Value;
if (SourceCharacter?.SpeciesName != CharacterPrefab.HumanSpeciesName)
{
if (!File.Exists(TexturePath))
if (!File.Exists(evaluatedTexturePath))
{
GUI.AddMessage(GetCharacterEditorTranslation("TextureDoesNotExist"), GUIStyle.Red);
texturePathElement.Flash(GUIStyle.Red);
return false;
}
}
var path = Path.GetFileName(TexturePath);
var path = Path.GetFileName(evaluatedTexturePath);
if (!path.EndsWith(".png", StringComparison.OrdinalIgnoreCase))
{
GUI.AddMessage(TextManager.Get("WrongFileType"), GUIStyle.Red);
@@ -405,7 +430,7 @@ namespace Barotrauma.CharacterEditor
}
if (IsCopy)
{
SourceRagdoll.Texture = TexturePath;
SourceRagdoll.Texture = evaluatedTexturePath;
SourceRagdoll.CanEnterSubmarine = CanEnterSubmarine;
SourceRagdoll.CanWalk = CanWalk;
SourceRagdoll.Serialize();

View File

@@ -813,7 +813,7 @@ namespace Barotrauma
foreach (GUITextBlock tutorialText in tutorialList.Content.Children)
{
if (((Tutorial)tutorialText.UserData).Completed)
if (CompletedTutorials.Instance.Contains(((Tutorial)tutorialText.UserData).Identifier))
{
completedTutorials++;
}

View File

@@ -2566,27 +2566,30 @@ namespace Barotrauma
if (MainSub != null)
{
List<string> contentPacks = MainSub.Info.RequiredContentPackages.ToList();
List<string> allContentPacks = MainSub.Info.RequiredContentPackages.ToList();
foreach (ContentPackage contentPack in ContentPackageManager.AllPackages)
{
//don't show content packages that only define submarine files
//(it doesn't make sense to require another sub to be installed to install this one)
if (contentPack.Files.All(f => f is SubmarineFile)) { continue; }
if (contentPack.Files.All(f => f is SubmarineFile || f is ItemAssemblyFile)) { continue; }
if (!contentPacks.Contains(contentPack.Name))
if (!allContentPacks.Contains(contentPack.Name))
{
string altName = contentPack.AltNames.FirstOrDefault(n => contentPacks.Contains(n));
string altName = contentPack.AltNames.FirstOrDefault(n => allContentPacks.Contains(n));
if (!string.IsNullOrEmpty(altName))
{
MainSub.Info.RequiredContentPackages.Remove(altName);
MainSub.Info.RequiredContentPackages.Add(contentPack.Name);
contentPacks.Remove(altName);
if (MainSub.Info.RequiredContentPackages.Contains(altName))
{
MainSub.Info.RequiredContentPackages.Remove(altName);
MainSub.Info.RequiredContentPackages.Add(contentPack.Name);
}
allContentPacks.Remove(altName);
}
contentPacks.Add(contentPack.Name);
allContentPacks.Add(contentPack.Name);
}
}
foreach (string contentPackageName in contentPacks)
foreach (string contentPackageName in allContentPacks)
{
var cpTickBox = new GUITickBox(new RectTransform(new Vector2(0.2f, 0.2f), contentPackList.Content.RectTransform), contentPackageName, font: GUIStyle.SmallFont)
{

View File

@@ -1,10 +1,6 @@
#nullable enable
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Xml.Linq;
using Barotrauma.Extensions;
namespace Barotrauma
{
@@ -31,7 +27,10 @@ namespace Barotrauma
public void SaveTo(XElement element)
{
identifiers.ForEach(id => new XElement("Tutorial", new XAttribute("name", id.Value)));
foreach (var id in identifiers)
{
element.Add(new XElement("Tutorial", new XAttribute("name", id.Value)));
}
}
public bool Contains(Identifier identifier) => identifiers.Contains(identifier);

View File

@@ -34,9 +34,11 @@ namespace Barotrauma
public bool Contains(Identifier identifier) => identifiers.Contains(identifier);
public void Add(Identifier identifier) => identifiers.Add(identifier);
public void Remove(Identifier identifier) => identifiers.Remove(identifier);
public void Clear() => identifiers.Clear();
public static IgnoredHints Instance { get; private set; } = new IgnoredHints();
}
}

View File

@@ -655,7 +655,20 @@ namespace Barotrauma
new GUIButton(new RectTransform(new Vector2(1.0f, 1.0f), layout.RectTransform),
TextManager.Get("ResetInGameHints"), style: "GUIButtonSmall")
{
ToolTip = TextManager.Get("ResetInGameHintsTooltip")
OnClicked = (button, o) =>
{
var msgBox = new GUIMessageBox(TextManager.Get("ResetInGameHints"),
TextManager.Get("ResetInGameHintsTooltip"),
buttons: new[] { TextManager.Get("Yes"), TextManager.Get("No") });
msgBox.Buttons[0].OnClicked = (guiButton, o1) =>
{
IgnoredHints.Instance.Clear();
msgBox.Close();
return false;
};
msgBox.Buttons[1].OnClicked = msgBox.Close;
return false;
}
};
Spacer(layout);

View File

@@ -100,15 +100,17 @@ namespace Barotrauma.Steam
{
Color = GUIStyle.Green
};
itemDownloadProgress.ProgressGetter = () =>
{
float progress = 0.0f;
if (item.IsDownloading) { progress = item.DownloadAmount; }
else if (itemDownloadProgress.BarSize > 0.0f) { progress = 1.0f; }
var itemDownloadProgressUpdater = new GUICustomComponent(
new RectTransform(Vector2.Zero, msgBox.Content.RectTransform),
onUpdate: (f, component) =>
{
float progress = 0.0f;
if (item.IsDownloading) { progress = item.DownloadAmount; }
else if (itemDownloadProgress.BarSize > 0.0f) { progress = 1.0f; }
return Math.Max(itemDownloadProgress.BarSize,
MathHelper.Lerp(itemDownloadProgress.BarSize, progress, 0.05f));
};
itemDownloadProgress.BarSize = Math.Max(itemDownloadProgress.BarSize,
MathHelper.Lerp(itemDownloadProgress.BarSize, progress, 0.1f));
});
}
TaskPool.Add("DownloadItems", DownloadItems(itemsToDownload, msgBox), _ =>
{

View File

@@ -614,8 +614,18 @@ namespace Barotrauma.Steam
if (!SteamManager.IsInitialized)
{
tabContents[Tab.PopularMods].Button.Enabled = false;
}
CreateWorkshopItemList(content, out _, out popularModsList, onSelected: PopulateFrameWithItemInfo);
}
GUIFrame listFrame = new GUIFrame(new RectTransform((1.0f, 0.95f), content.RectTransform), style: null);
CreateWorkshopItemList(listFrame, out _, out popularModsList, onSelected: PopulateFrameWithItemInfo);
new GUIButton(new RectTransform((1.0f, 0.05f), content.RectTransform, Anchor.BottomLeft),
style: "GUIButtonSmall", text: TextManager.Get("FindModsButton"))
{
OnClicked = (button, o) =>
{
SteamManager.OverlayCustomURL($"https://steamcommunity.com/app/{SteamManager.AppID}/workshop/");
return false;
}
};
}
private void CreatePublishTab(out GUIListBox selfModsList)

View File

@@ -6,7 +6,7 @@
<RootNamespace>Barotrauma</RootNamespace>
<Authors>FakeFish, Undertow Games</Authors>
<Product>Barotrauma</Product>
<Version>0.17.9.0</Version>
<Version>0.17.10.0</Version>
<Copyright>Copyright © FakeFish 2018-2022</Copyright>
<Platforms>AnyCPU;x64</Platforms>
<AssemblyName>Barotrauma</AssemblyName>

View File

@@ -6,7 +6,7 @@
<RootNamespace>Barotrauma</RootNamespace>
<Authors>FakeFish, Undertow Games</Authors>
<Product>Barotrauma</Product>
<Version>0.17.9.0</Version>
<Version>0.17.10.0</Version>
<Copyright>Copyright © FakeFish 2018-2022</Copyright>
<Platforms>AnyCPU;x64</Platforms>
<AssemblyName>Barotrauma</AssemblyName>

View File

@@ -6,7 +6,7 @@
<RootNamespace>Barotrauma</RootNamespace>
<Authors>FakeFish, Undertow Games</Authors>
<Product>Barotrauma</Product>
<Version>0.17.9.0</Version>
<Version>0.17.10.0</Version>
<Copyright>Copyright © FakeFish 2018-2022</Copyright>
<Platforms>AnyCPU;x64</Platforms>
<AssemblyName>Barotrauma</AssemblyName>

View File

@@ -6,7 +6,7 @@
<RootNamespace>Barotrauma</RootNamespace>
<Authors>FakeFish, Undertow Games</Authors>
<Product>Barotrauma Dedicated Server</Product>
<Version>0.17.9.0</Version>
<Version>0.17.10.0</Version>
<Copyright>Copyright © FakeFish 2018-2022</Copyright>
<Platforms>AnyCPU;x64</Platforms>
<AssemblyName>DedicatedServer</AssemblyName>

View File

@@ -6,7 +6,7 @@
<RootNamespace>Barotrauma</RootNamespace>
<Authors>FakeFish, Undertow Games</Authors>
<Product>Barotrauma Dedicated Server</Product>
<Version>0.17.9.0</Version>
<Version>0.17.10.0</Version>
<Copyright>Copyright © FakeFish 2018-2022</Copyright>
<Platforms>AnyCPU;x64</Platforms>
<AssemblyName>DedicatedServer</AssemblyName>

View File

@@ -636,8 +636,6 @@ namespace Barotrauma
{
msg.Write(true);
msg.Write(ownerClient.ID);
msg.Write(Wallet.Balance);
msg.WriteRangedInteger(Wallet.RewardDistribution, 0, 100);
}
else if (GameMain.Server.Character == this)
{
@@ -648,7 +646,8 @@ namespace Barotrauma
{
msg.Write(false);
}
msg.Write(Wallet.Balance);
msg.WriteRangedInteger(Wallet.RewardDistribution, 0, 100);
msg.Write((byte)TeamID);
msg.Write(this is AICharacter);
msg.Write(info.SpeciesName);

View File

@@ -249,6 +249,8 @@ namespace Barotrauma
}
}
MoveDiscardedCharacterBalancesToBank();
characterData.ForEach(cd => cd.HasSpawned = false);
petsElement = new XElement("pets");
@@ -277,6 +279,21 @@ namespace Barotrauma
}
}
public void MoveDiscardedCharacterBalancesToBank()
{
foreach (var discardedCharacter in discardedCharacters)
{
if (discardedCharacter.WalletData != null)
{
var wallet =
Character.CharacterList.Find(c => c.Info == discardedCharacter.CharacterInfo)?.Wallet ??
new Wallet(Option<Character>.None(), discardedCharacter.WalletData);
Bank.Give(wallet.Balance);
}
}
discardedCharacters.Clear();
}
protected override IEnumerable<CoroutineStatus> DoLevelTransition(TransitionType transitionType, LevelData newLevel, Submarine leavingSub, bool mirror, List<TraitorMissionResult> traitorResults)
{
lastUpdateID++;
@@ -415,9 +432,20 @@ namespace Barotrauma
public bool CanPurchaseSub(SubmarineInfo info, Client client)
=> GetWallet(client).CanAfford(info.Price) && GetCampaignSubs().Contains(info);
private readonly List<CharacterCampaignData> discardedCharacters = new List<CharacterCampaignData>();
public void DiscardClientCharacterData(Client client)
{
characterData.RemoveAll(cd => cd.MatchesClient(client));
foreach (var data in characterData.ToList())
{
if (data.MatchesClient(client))
{
if (!discardedCharacters.Any(d => d.MatchesClient(client)))
{
discardedCharacters.Add(data);
}
characterData.Remove(data);
}
}
}
public CharacterCampaignData GetClientCharacterData(Client client)

View File

@@ -275,11 +275,6 @@ namespace Barotrauma.Networking
Array.Copy(transfer.Data, transfer.SentOffset, message.Buffer, chunkDestPos, sendByteCount);
transfer.SentOffset += sendByteCount;
if (transfer.SentOffset >= transfer.Data.Length)
{
transfer.SentOffset = transfer.KnownReceivedOffset;
transfer.WaitTimer = 1.0f;
}
peer.Send(message, transfer.Connection, DeliveryMethod.Unreliable, compressPastThreshold: false);
@@ -288,6 +283,12 @@ namespace Barotrauma.Networking
DebugConsole.Log($"Sending {sendByteCount} bytes of the file {transfer.FileName} ({transfer.SentOffset / 1000}/{transfer.Data.Length / 1000} kB sent)");
}
if (transfer.SentOffset >= transfer.Data.Length)
{
transfer.SentOffset = transfer.KnownReceivedOffset;
transfer.WaitTimer = 1.0f;
}
//try to increase the packet rate so large files get sent faster,
//this gets reset when packet loss or disorder sets in
transfer.PacketsPerUpdate = Math.Min(FileTransferOut.MaxPacketsPerUpdate,
@@ -330,7 +331,6 @@ namespace Barotrauma.Networking
byte transferId = inc.ReadByte();
var matchingTransfer = activeTransfers.Find(t => t.Connection == inc.Sender && t.ID == transferId);
if (matchingTransfer != null) CancelTransfer(matchingTransfer);
return;
}
else if (messageType == FileTransferMessageType.Data)
@@ -372,15 +372,22 @@ namespace Barotrauma.Networking
string fileHash = inc.ReadString();
var requestedSubmarine = SubmarineInfo.SavedSubmarines.FirstOrDefault(s => s.Name == fileName && s.MD5Hash.StringRepresentation == fileHash);
DebugConsole.Log($"Received a submarine file request from \"{client.Name}\" ({fileName}).");
if (requestedSubmarine != null)
{
if (activeTransfers.Any(t => t.Connection == inc.Sender && t.FilePath == requestedSubmarine.FilePath))
{
DebugConsole.Log($"Ignoring a submarine file request from \"{client.Name}\" ({fileName}) - already transferring.");
return;
}
StartTransfer(inc.Sender, FileTransferType.Submarine, requestedSubmarine.FilePath);
}
break;
case FileTransferType.CampaignSave:
if (GameMain.GameSession != null &&
!ActiveTransfers.Any(t => t.Connection == inc.Sender && t.FileType == FileTransferType.CampaignSave))
{
{
StartTransfer(inc.Sender, FileTransferType.CampaignSave, GameMain.GameSession.SavePath);
if (GameMain.GameSession?.GameMode is MultiPlayerCampaign campaign)
{
@@ -392,6 +399,8 @@ namespace Barotrauma.Networking
string modName = inc.ReadString();
Md5Hash modHash = Md5Hash.StringAsHash(inc.ReadString());
DebugConsole.Log($"Received a mod file request from \"{client.Name}\" ({modName}).");
if (!GameMain.Server.ServerSettings.AllowModDownloads) { return; }
if (!(GameMain.Server.ModSender is { Ready: true })) { return; }
@@ -402,6 +411,12 @@ namespace Barotrauma.Networking
string modCompressedPath = ModSender.GetCompressedModPath(mod);
if (!File.Exists(modCompressedPath)) { return; }
if (activeTransfers.Any(t => t.Connection == inc.Sender && t.FilePath == modCompressedPath))
{
DebugConsole.Log($"Ignoring a mod file request from \"{client.Name}\" ({modName}) - already transferring.");
return;
}
StartTransfer(inc.Sender, FileTransferType.Mod, modCompressedPath);
break;

View File

@@ -22,7 +22,15 @@ namespace Barotrauma.Networking
ContentPackageManager.EnabledPackages.All
.Where(p => p != ContentPackageManager.VanillaCorePackage && p.HasMultiplayerSyncedContent)
.Select(CompressMod)),
(t) => Ready = true);
t =>
{
var innermostException = t.Exception?.GetInnermost();
if (innermostException != null)
{
DebugConsole.ThrowError($"An error occurred when compressing mods", innermostException);
}
Ready = true;
});
}
public static string GetCompressedModPath(ContentPackage mod)

View File

@@ -326,6 +326,12 @@ namespace Barotrauma.Networking
}
UpdateClientPermissions(newClient);
//notify the client of everyone else's permissions
foreach (Client otherClient in connectedClients)
{
if (otherClient == newClient) { continue; }
CoroutineManager.StartCoroutine(SendClientPermissionsAfterClientListSynced(newClient, otherClient));
}
}
private void OnClientDisconnect(NetworkConnection connection, string disconnectMsg)

View File

@@ -517,6 +517,24 @@ namespace Barotrauma.Networking
}
}
if (permissions.HasFlag(Networking.ClientPermissions.ConsoleCommands))
{
foreach (XElement commandElement in clientElement.Elements())
{
if (!commandElement.Name.ToString().Equals("command", StringComparison.OrdinalIgnoreCase)) { continue; }
string commandName = commandElement.GetAttributeString("name", "");
DebugConsole.Command command = DebugConsole.FindCommand(commandName);
if (command == null)
{
DebugConsole.ThrowError("Error in " + ClientPermissionsFile + " - \"" + commandName + "\" is not a valid console command.");
continue;
}
permittedCommands.Add(command);
}
}
if (!string.IsNullOrEmpty(steamIdStr))
{
if (ulong.TryParse(steamIdStr, out ulong steamID))
@@ -607,18 +625,18 @@ namespace Barotrauma.Networking
if (matchingPreset == null)
{
clientElement.Add(new XAttribute("permissions", clientPermission.Permissions.ToString()));
if (clientPermission.Permissions.HasFlag(Networking.ClientPermissions.ConsoleCommands))
{
foreach (DebugConsole.Command command in clientPermission.PermittedCommands)
{
clientElement.Add(new XElement("command", new XAttribute("name", command.names[0])));
}
}
}
else
{
clientElement.Add(new XAttribute("preset", matchingPreset.Name));
}
if (clientPermission.Permissions.HasFlag(Networking.ClientPermissions.ConsoleCommands))
{
foreach (DebugConsole.Command command in clientPermission.PermittedCommands)
{
clientElement.Add(new XElement("command", new XAttribute("name", command.names[0])));
}
}
doc.Root.Add(clientElement);
}

View File

@@ -6,7 +6,7 @@
<RootNamespace>Barotrauma</RootNamespace>
<Authors>FakeFish, Undertow Games</Authors>
<Product>Barotrauma Dedicated Server</Product>
<Version>0.17.9.0</Version>
<Version>0.17.10.0</Version>
<Copyright>Copyright © FakeFish 2018-2022</Copyright>
<Platforms>AnyCPU;x64</Platforms>
<AssemblyName>DedicatedServer</AssemblyName>

View File

@@ -363,7 +363,7 @@ namespace Barotrauma
public List<Order> CurrentOrders => Info?.CurrentOrders;
public bool IsDismissed => GetCurrentOrderWithTopPriority() == null;
private readonly List<StatusEffect> statusEffects = new List<StatusEffect>();
private readonly Dictionary<ActionType, List<StatusEffect>> statusEffects = new Dictionary<ActionType, List<StatusEffect>>();
public Entity ViewTarget
{
@@ -1036,34 +1036,6 @@ namespace Barotrauma
newCharacter = new Character(prefab, position, seed, characterInfo, id, isRemotePlayer, ragdoll);
}
float healthRegen = newCharacter.Params.Health.ConstantHealthRegeneration;
if (healthRegen > 0)
{
AddDamageReduction("damage", healthRegen);
}
float eatingRegen = newCharacter.Params.Health.HealthRegenerationWhenEating;
if (eatingRegen > 0)
{
AddDamageReduction("damage", eatingRegen, ActionType.OnEating);
}
float burnReduction = newCharacter.Params.Health.BurnReduction;
if (burnReduction > 0)
{
AddDamageReduction("burn", burnReduction);
}
float bleedReduction = newCharacter.Params.Health.BleedingReduction;
if (bleedReduction > 0)
{
AddDamageReduction("bleeding", bleedReduction);
}
void AddDamageReduction(string affliction, float amount, ActionType actionType = ActionType.Always)
{
newCharacter.statusEffects.Add(StatusEffect.Load(
new XElement("StatusEffect", new XAttribute("type", actionType), new XAttribute("target", "Character"),
new XElement("ReduceAffliction", new XAttribute("identifier", affliction), new XAttribute("amount", amount))).FromPackage(null), $"automatic damage reduction ({affliction})"));
}
#if SERVER
if (GameMain.Server != null && Spawner != null && createNetworkEvent)
{
@@ -1144,7 +1116,15 @@ namespace Barotrauma
healthCommonness.Add(subElement.GetAttributeFloat("commonness", 1.0f));
break;
case "statuseffect":
statusEffects.Add(StatusEffect.Load(subElement, Name));
var statusEffect = StatusEffect.Load(subElement, Name);
if (statusEffect != null)
{
if (!statusEffects.ContainsKey(statusEffect.type))
{
statusEffects.Add(statusEffect.type, new List<StatusEffect>());
}
statusEffects[statusEffect.type].Add(statusEffect);
}
break;
}
}
@@ -3701,13 +3681,19 @@ namespace Barotrauma
otherLimb.body.ApplyLinearImpulse(targetLimb.LinearVelocity * targetLimb.Mass, maxVelocity: NetConfig.MaxPhysicsBodyVelocity * 0.5f);
if (attacker != null)
{
foreach (var statusEffect in statusEffects)
if (statusEffects.TryGetValue(ActionType.OnSevered, out var statusEffectList))
{
if (statusEffect.type == ActionType.OnSevered) { statusEffect.SetUser(attacker); }
foreach (var statusEffect in statusEffectList)
{
statusEffect.SetUser(attacker);
}
}
foreach (var statusEffect in targetLimb.StatusEffects)
if (targetLimb.StatusEffects.TryGetValue(ActionType.OnSevered, out var limbStatusEffectList))
{
if (statusEffect.type == ActionType.OnSevered) { statusEffect.SetUser(attacker); }
foreach (var statusEffect in limbStatusEffectList)
{
statusEffect.SetUser(attacker);
}
}
}
ApplyStatusEffects(ActionType.OnSevered, 1.0f);
@@ -3909,9 +3895,17 @@ namespace Barotrauma
private readonly List<ISerializableEntity> targets = new List<ISerializableEntity>();
public void ApplyStatusEffects(ActionType actionType, float deltaTime)
{
foreach (StatusEffect statusEffect in statusEffects)
if (actionType == ActionType.OnEating)
{
float eatingRegen = Params.Health.HealthRegenerationWhenEating;
if (eatingRegen > 0)
{
CharacterHealth.ReduceAfflictionOnAllLimbs("damage".ToIdentifier(), eatingRegen * deltaTime);
}
}
if (!statusEffects.TryGetValue(actionType, out var statusEffectList)) { return; }
foreach (StatusEffect statusEffect in statusEffectList)
{
if (statusEffect.type != actionType) { continue; }
if (statusEffect.type == ActionType.OnDamaged)
{
if (!statusEffect.HasRequiredAfflictions(LastDamage)) { continue; }

View File

@@ -328,16 +328,13 @@ namespace Barotrauma
public Limb GetAfflictionLimb(Affliction affliction)
{
foreach (KeyValuePair<Affliction, LimbHealth> kvp in afflictions)
if (afflictions.TryGetValue(affliction, out LimbHealth limbHealth))
{
if (kvp.Key == affliction)
if (limbHealth == null) { return null; }
int limbHealthIndex = limbHealths.IndexOf(limbHealth);
foreach (Limb limb in Character.AnimController.Limbs)
{
int limbHealthIndex = limbHealths.IndexOf(kvp.Value);
foreach (Limb limb in Character.AnimController.Limbs)
{
if (limb.HealthIndex == limbHealthIndex) { return limb; }
}
return null;
if (limb.HealthIndex == limbHealthIndex) { return limb; }
}
}
return null;
@@ -510,8 +507,8 @@ namespace Barotrauma
amount -= matchingAffliction.Strength;
matchingAffliction.Strength = 0.0f;
matchingAfflictions.RemoveAt(i);
if (i == 0) i = matchingAfflictions.Count;
if (i > 0) reduceAmount += surplus / i;
if (i == 0) { i = matchingAfflictions.Count; }
if (i > 0) { reduceAmount += surplus / i; }
SteamAchievementManager.OnAfflictionRemoved(matchingAffliction, Character);
}
else
@@ -798,6 +795,8 @@ namespace Barotrauma
Character.StackSpeedMultiplier(1f + Character.GetStatValue(StatTypes.WalkingSpeed));
}
UpdateDamageReductions(deltaTime);
if (!Character.GodMode)
{
UpdateLimbAfflictionOverlays();
@@ -828,6 +827,25 @@ namespace Barotrauma
}
}
private void UpdateDamageReductions(float deltaTime)
{
float healthRegen = Character.Params.Health.ConstantHealthRegeneration;
if (healthRegen > 0)
{
ReduceAfflictionOnAllLimbs("damage".ToIdentifier(), healthRegen * deltaTime);
}
float burnReduction = Character.Params.Health.BurnReduction;
if (burnReduction > 0)
{
ReduceAfflictionOnAllLimbs("burn".ToIdentifier(), burnReduction * deltaTime);
}
float bleedingReduction = Character.Params.Health.BleedingReduction;
if (bleedingReduction > 0)
{
ReduceAfflictionOnAllLimbs("bleeding".ToIdentifier(), bleedingReduction * deltaTime);
}
}
private void UpdateOxygen(float deltaTime)
{
if (!Character.NeedsOxygen) { return; }
@@ -909,28 +927,14 @@ namespace Barotrauma
// We need to use another list of the afflictions when we call the status effects triggered by afflictions,
// because those status effects may add or remove other afflictions while iterating the collection.
private readonly List<(Affliction affliction, Limb limb)> afflictionsCopy = new List<(Affliction affliction, Limb limb)>();
private readonly List<Affliction> afflictionsCopy = new List<Affliction>();
public void ApplyAfflictionStatusEffects(ActionType type)
{
afflictionsCopy.Clear();
foreach (KeyValuePair<Affliction, LimbHealth> kvp in afflictions)
afflictionsCopy.AddRange(afflictions.Keys);
foreach (Affliction affliction in afflictionsCopy)
{
var affliction = kvp.Key;
var limbHealth = kvp.Value;
Limb targetLimb = null;
if (limbHealth != null)
{
int healthIndex = limbHealths.IndexOf(limbHealth);
targetLimb =
Character.AnimController.Limbs.LastOrDefault(l => !l.IsSevered && !l.Hidden && l.HealthIndex == healthIndex) ??
Character.AnimController.MainLimb;
}
afflictionsCopy.Add((affliction, GetAfflictionLimb(affliction)));
}
foreach ((Affliction affliction, Limb limb) in afflictionsCopy)
{
affliction.ApplyStatusEffects(type, 1.0f, this, targetLimb: limb);
affliction.ApplyStatusEffects(type, 1.0f, this, targetLimb: GetAfflictionLimb(affliction));
}
}

View File

@@ -584,9 +584,9 @@ namespace Barotrauma
private set;
}
private readonly List<StatusEffect> statusEffects = new List<StatusEffect>();
private readonly Dictionary<ActionType, List<StatusEffect>> statusEffects = new Dictionary<ActionType, List<StatusEffect>>();
public IEnumerable<StatusEffect> StatusEffects { get { return statusEffects; } }
public Dictionary<ActionType, List<StatusEffect>> StatusEffects { get { return statusEffects; } }
public Limb(Ragdoll ragdoll, Character character, LimbParams limbParams)
{
@@ -662,7 +662,15 @@ namespace Barotrauma
DamageModifiers.Add(new DamageModifier(subElement, character.Name));
break;
case "statuseffect":
statusEffects.Add(StatusEffect.Load(subElement, Name));
var statusEffect = StatusEffect.Load(subElement, Name);
if (statusEffect != null)
{
if (!statusEffects.ContainsKey(statusEffect.type))
{
statusEffects.Add(statusEffect.type, new List<StatusEffect>());
}
statusEffects[statusEffect.type].Add(statusEffect);
}
break;
}
}
@@ -1159,9 +1167,9 @@ namespace Barotrauma
private readonly List<ISerializableEntity> targets = new List<ISerializableEntity>();
public void ApplyStatusEffects(ActionType actionType, float deltaTime)
{
foreach (StatusEffect statusEffect in statusEffects)
if (!statusEffects.TryGetValue(actionType, out var statusEffectList)) { return; }
foreach (StatusEffect statusEffect in statusEffectList)
{
if (statusEffect.type != actionType) { continue; }
if (statusEffect.type == ActionType.OnDamaged)
{
if (!statusEffect.HasRequiredAfflictions(character.LastDamage)) { continue; }

View File

@@ -481,16 +481,16 @@ namespace Barotrauma
public bool UseHealthWindow { get; set; }
[Serialize(0f, IsPropertySaveable.Yes, description: "How easily the character heals from the bleeding wounds. Default 0 (no extra healing)."), Editable(MinValueFloat = 0, MaxValueFloat = 100, DecimalCount = 2)]
public float BleedingReduction { get; private set; }
public float BleedingReduction { get; set; }
[Serialize(0f, IsPropertySaveable.Yes, description: "How easily the character heals from the burn wounds. Default 0 (no extra healing)."), Editable(MinValueFloat = 0, MaxValueFloat = 100, DecimalCount = 2)]
public float BurnReduction { get; private set; }
public float BurnReduction { get; set; }
[Serialize(0f, IsPropertySaveable.Yes), Editable(MinValueFloat = 0, MaxValueFloat = 10, DecimalCount = 2)]
public float ConstantHealthRegeneration { get; private set; }
public float ConstantHealthRegeneration { get; set; }
[Serialize(0f, IsPropertySaveable.Yes), Editable(MinValueFloat = 0, MaxValueFloat = 100, DecimalCount = 2)]
public float HealthRegenerationWhenEating { get; private set; }
public float HealthRegenerationWhenEating { get; set; }
[Serialize(false, IsPropertySaveable.Yes), Editable]
public bool StunImmunity { get; set; }

View File

@@ -250,9 +250,9 @@ namespace Barotrauma
}
}
//Load the UI files first. This is to allow the game to render
//the text in the loading screen as soon as possible.
var priorityFiles = getFilesToLoad(f => f is UIStyleFile);
//Load the UI and text files first. This is to allow the game
//to render the text in the loading screen as soon as possible.
var priorityFiles = getFilesToLoad(f => f is UIStyleFile || f is TextFile);
var remainder = getFilesToLoad(f => !priorityFiles.Contains(f));

View File

@@ -206,7 +206,7 @@ namespace Barotrauma
var campaign = MultiPlayerCampaign.StartNew(seed ?? ToolBox.RandomSeed(8), selectedSub, settings);
if (selectedSub != null)
{
campaign.Bank.TryDeduct(selectedSub.Price);
campaign.Bank.Deduct(selectedSub.Price);
campaign.Bank.Balance = Math.Max(campaign.Bank.Balance, MultiPlayerCampaign.MinimumInitialMoney);
}
return campaign;

View File

@@ -161,7 +161,7 @@ namespace Barotrauma.Items.Components
/// </summary>
public override float GetCurrentPowerConsumption(Connection connection = null)
{
if (connection != this.powerIn)
if (connection != this.powerIn || !IsActive)
{
return 0;
}

View File

@@ -67,7 +67,7 @@ namespace Barotrauma.Items.Components
/// </summary>
public override float GetCurrentPowerConsumption(Connection connection = null)
{
if (connection != this.powerIn)
if (connection != this.powerIn || !IsActive)
{
return 0;
}

View File

@@ -179,7 +179,7 @@ namespace Barotrauma.Items.Components
public override float GetCurrentPowerConsumption(Connection connection = null)
{
//There shouldn't be other power connections to this
if (connection != this.powerIn)
if (connection != this.powerIn || !IsActive)
{
return 0;
}

View File

@@ -138,7 +138,11 @@ namespace Barotrauma.Items.Components
{
get
{
if (powerIn != null)
if (PoweredByTinkering)
{
return 1.0f;
}
else if (powerIn != null)
{
if (powerIn?.Grid != null) { return powerIn.Grid.Voltage; }
}
@@ -154,6 +158,22 @@ namespace Barotrauma.Items.Components
}
}
public bool PoweredByTinkering
{
get
{
if (this is PowerContainer) { return false; }
foreach (Repairable repairable in Item.Repairables)
{
if (repairable.IsTinkering && repairable.TinkeringPowersDevices)
{
return true;
}
}
return false;
}
}
[Editable, Serialize(true, IsPropertySaveable.Yes, description: "Can the item be damaged by electomagnetic pulses.")]
public bool VulnerableToEMP
{
@@ -459,19 +479,12 @@ namespace Barotrauma.Items.Components
if (powered.powerIn != null && powered.powerOut != powered.powerIn)
{
//Get the new load for the connection
float currLoad;
if (powered.Item.GetComponent<Repairable>() is Repairable repairable && repairable.IsTinkering && repairable.TinkeringPowersDevices && !(powered is PowerContainer))
{
currLoad = 0.0f;
}
else
{
currLoad = powered.GetCurrentPowerConsumption(powered.powerIn);
}
float currLoad = powered.GetCurrentPowerConsumption(powered.powerIn);
//If its a load update its grid load
if (currLoad >= 0)
{
if (powered.PoweredByTinkering) { currLoad = 0.0f; }
powered.CurrPowerConsumption = currLoad;
if (powered.powerIn.Grid != null)
{

View File

@@ -75,7 +75,8 @@ namespace Barotrauma
public class RequiredItemByIdentifier : RequiredItem
{
public readonly Identifier ItemPrefabIdentifier;
public ItemPrefab ItemPrefab => ItemPrefab.Prefabs[ItemPrefabIdentifier];
public ItemPrefab ItemPrefab => ItemPrefab.Prefabs.TryGet(ItemPrefabIdentifier, out var prefab) ? prefab
: MapEntityPrefab.FindByName(ItemPrefabIdentifier.Value) as ItemPrefab ?? throw new Exception($"No ItemPrefab with identifier or name \"{ItemPrefabIdentifier}\"");
public override UInt32 UintIdentifier { get; }
public override IEnumerable<ItemPrefab> ItemPrefabs => ItemPrefab.ToEnumerable();

View File

@@ -1,4 +1,3 @@
using Lidgren.Network;
using Microsoft.Xna.Framework;
using System;
using System.Collections.Generic;
@@ -257,7 +256,7 @@ namespace Barotrauma.Networking
public void WritePermissions(IWriteMessage msg)
{
msg.Write(ID);
msg.Write((UInt16)Permissions);
msg.WriteRangedInteger((int)Permissions, 0, (int)ClientPermissions.All);
if (HasPermission(ClientPermissions.ConsoleCommands))
{
msg.Write((UInt16)PermittedConsoleCommands.Count);
@@ -269,8 +268,7 @@ namespace Barotrauma.Networking
}
public static void ReadPermissions(IReadMessage inc, out ClientPermissions permissions, out List<DebugConsole.Command> permittedCommands)
{
UInt16 permissionsInt = inc.ReadUInt16();
int permissionsInt = inc.ReadRangedInteger(0, (int)ClientPermissions.All);
permissions = ClientPermissions.None;
permittedCommands = new List<DebugConsole.Command>();
try
@@ -298,9 +296,7 @@ namespace Barotrauma.Networking
public void ReadPermissions(IReadMessage inc)
{
ClientPermissions permissions = ClientPermissions.None;
List<DebugConsole.Command> permittedCommands = new List<DebugConsole.Command>();
ReadPermissions(inc, out permissions, out permittedCommands);
ReadPermissions(inc, out ClientPermissions permissions, out List<DebugConsole.Command> permittedCommands);
SetPermissions(permissions, permittedCommands);
}

View File

@@ -14,7 +14,7 @@ namespace Barotrauma.IO
private static readonly ImmutableArray<Identifier> unwritableDirs = new[] { "Content".ToIdentifier() }.ToImmutableArray();
private static readonly ImmutableArray<Identifier> unwritableExtensions = new[]
{
".pdb", ".com", ".scr", ".dylib", ".so", ".a", ".app", //executables and libraries (.exe, .dll and .json handled separately in CanWrite)
".exe", ".dll", ".json", ".pdb", ".com", ".scr", ".dylib", ".so", ".a", ".app", //executables and libraries
".bat", ".sh", //shell scripts
}.ToIdentifiers().ToImmutableArray();
@@ -39,10 +39,6 @@ namespace Barotrauma.IO
if (!isDirectory)
{
Identifier extension = System.IO.Path.GetExtension(path).Replace(" ", "").ToIdentifier();
if (unwritableExtensions.Any(e => e == extension))
{
return false;
}
bool pathStartsWith(string prefix)
=> path.StartsWith(prefix, StringComparison.OrdinalIgnoreCase);
@@ -53,7 +49,7 @@ namespace Barotrauma.IO
&& !pathStartsWith(tempDownloadDir)
&& !pathStartsWith(workshopStagingDir)
#endif
&& (extension == ".dll" || extension == ".exe" || extension == ".json"))
&& unwritableExtensions.Any(e => e == extension))
{
return false;
}

View File

@@ -1,429 +1,44 @@
---------------------------------------------------------------------------------------------------------
v0.17.9.0
v0.17.10.0
---------------------------------------------------------------------------------------------------------
Changes (unstable only):
- Added tickboxes to select/deselect items in bulk in the mod transfer screen + added button to skip the mod transfer screen.
- Move grabbed body wallet funds to the campaign bank instead of the personal wallet.
- Made items sold go into the personal wallet instead of campaign bank.
- Added a server log line for buying items from the store.
Fixes (unstable only):
- Fixed local mod write time not always being correct.
- Fixed new outpost events using the same event sprite.
- Fixed "captive souls" event not giving a reward.
- Fixed conversation hanging on an option in the "explosive mishap" event.
- Spawn mudraptor eggs instead of an adult mudraptor in the "occupational hazards" event.
- Fixed latter half of the "occupational hazards" event not triggering correctly.
- Fixed vending machines stealing your money if you don't have x2 of the price of the item.
- Fixed some missions that spawn multiple monsters having incorrect/inaccurate sonar labels (e.g. giant spineling mission displaying "giant spineling" on the small ones too, same for the crawler broodmother mission).
- Fixed wallet failing to sync when the server has been modified to support more than 16 players per server.
- Fixed error when receiving a multiplayer campaign sync message while downloading mods.
- Fixed sub editor's wiring panel listing the wires in a random order.
- Fixed z-fighting plants in colonies.
- Fixed "-0 mk" popup when someone adds something to the store cart.
- Fixed "Failed to parse the string "GUI.ITEMQUALITYCOLORGOOD" to Color" errors.
- 2nd attempt to fix a null reference exception when a client joins a server where a round is running with respawns disabled.
- Fixed errors when attempting to publish a mod with exe files.
- Fixed inability to set the salary distribution to certain values (e.g. 5%, 10%, 15%).
- Fixed spectate button still not appearing if the round starts while you're downloading mods from the server, and the other way around, spectate button still being visible if the round ends.
- Fixed stores becoming unusable after items have been sold in multiplayer.
- Fixed tiny faction icons in the round summary.
- Fixed some structure/item sprites sometimes failing to load, making them appear invisible in-game.
---------------------------------------------------------------------------------------------------------
v0.17.8.0
---------------------------------------------------------------------------------------------------------
Changes (unstable only):
- Remove flipping in water while aiming (with the changes introduced to aiming in the previous versions, aiming works even better without it).
Fixes (unstable only):
- Fixed languages being in random order in the initial language selection screen.
- Fixed power grid going crazy client-side when junction boxes break.
- Fixed crashing when clicking on a dead player in the tab menu.
- Fixed spectate button not appearing if the round starts while waiting for mods to download.
- Fixed disabling a submarine mod not actually disabling the sub.
- Fixed host server menu layout changing every time you open it, and the server exe dropdown having a different size than the rest of the elements.
---------------------------------------------------------------------------------------------------------
v0.17.7.0
---------------------------------------------------------------------------------------------------------
Changes:
- Water no longer dirties up walls.
- New store (and sub editor) categories: weapon, medical, diving, and fuel. Reorganized the items into categories.
- Disabled store category buttons for categories that contain no items.
Changes (unstable only):
- Content package errors are logged in the debug console when enabling a mod that has errors, + listed in tooltips in the Mods tab.
- Updated sprites for the wallet related features.
- Personal wallet balance now shows in the bottom right character portrait.
- Latcher: new sounds and minor tweaks.
Fixes (unstable only):
- Fixed crashing when pressing the "retry" button in the pause menu when the outpost store interface is open.
- Fixed crashing when opening the Mods tab when not connected to Steam.
- Fixed structures not using the name defined in xml when the name can't be found in loca files.
- Fixed inability to start additional votes when another vote is running.
- Fixed buying from outpost vendors requiring sell permissions.
- Fixed clients with the ManagePermissions being able to edit the host's permissions (didn't actually do anything, but the menu still showed up).
- Fixed inability to repair beacon station devices after the beacon is activated.
- Fixed tiny plus/minus buttons in spawnpoint editing menu.
- Fixed vomiting sounds not playing.
- Fixed some mods failing to extract after being downloaded from the server.
- Fixed crashing when deleting a Workshop item that has music-related errors.
- Fixed submarine editor listing recently disabled subs in the Load menu.
- Fixed certain old mods not having their paths corrected properly when installed through the Workshop or transferred from the Mods folder.
- Optimized file transfers.
- Disabled unsupported resolutions in the settings menu.
- Fixed crashing in event editor when loading prefabs or projects.
- Fixed ping and wallet columns switching places in tab menu when a character dies.
- Fixed "Lots!" text appearing too eagerly when playing on lower resolutions.
- Fixed monsters using fast swim parameters when they swim slowly.
- Fixed human head sometimes shaking while aiming.
Fixes:
- Fixed occasional performance dips when spineling spikes get stuck to the sub's exterior walls.
- Fixed item assemblies getting misaligned with the grid after saving.
- Fixed "Shell A 18" not aligning with the other shell pieces.
- Fixed "Deep Sea Slayer" talent not affecting explosive harpoons.
- Fixed welding tool's, plasma cutter's and watering can's particle effects getting "clamped" to the edges of the hull they're inside.
- Fixed permission icon in the client list not updating mid-round.
- Fixed "lock default wires" server setting not affecting docked subs.
- Fixed Dugong's small pumps working without power.
- Fixed buttons in structure editing menu using a different style than other types of entities in the sub editor.
- Fixed items flagged as "HiddenInGame" being considered interactable and therefore e.g. valid repair targets.
- Fixed some (hopefully for good) issues bots still had with ladders.
- Fixed outpost guards not arresting the offender when it's very far from them.
- Fixed bots sometimes failing to navigate back to the sub (when they are on the other side of the sub than where the hatch is).
Modding:
- Level editor no longer attempts to save the vanilla content.
---------------------------------------------------------------------------------------------------------
v0.17.6.0
---------------------------------------------------------------------------------------------------------
Changes:
- Buffed ethanol's and tobacco's effects.
- Renamed "details" to "manage" and "permissions" to "rank" in the client management context menu to make them a little more clear.
- Added an indicator for when players are downloading files from the server to the player list in the lobby.
- Adjustments, tweaks, and polish for the new abyss monster, now called "Latcher". Updated texture.
- Adjusted the kill hammerhead missions.
- Changes to character aiming behavior.
- Giant Spineling doesn't flee anymore when being shot with coilgun, chaingun, or small arms.
Changes (unstable only):
- Added separate icons for mods that you've published and mods that you've subscribed to.
- Added a button to the prompt asking you to download mods from the server that will subscribe to missing Workshop items.
- Added a context menu to the items in the Installed Mods tab.
- Added a button to update all mods that are out of date.
- Added a search box to the locked mods list.
- Added a search box to the required mods list in the submarine editor.
- Double-clicking now enables/disables items in the Installed Mods tab.
Fixes:
- Fixed swimming characters sometimes being unable to stand up on stairs/platforms even if the water is shallow enough.
- Fixed guitar and harmonica being rendered on top of the water effect.
- Fixed guitar, harmonica, accordion and captains pipe having neutral buoyancy.
- Fixed mid-round joining clients not seeing subs purchased during that round.
- Fixed research station being repairable by clicking on it instead of pressing E.
- Fixed medical curtains disappearing before they're off-screen.
- Fixed karma preset being forced to default when starting a new server.
- Fixed calyxanide not damaging the "naturally spawning" husks.
- Fixed Herja's rear motion detector being connected to an incorrect display, and the bottom turret display having an incorrect text.
- Fixed crash caused by selection not being cleared when autocompleting or running a console command.
- Waypointfixes on abandoned outpost modules, some regular outpost modules, and Winterhalter.
- Fixed bots occasionally getting stuck while climbing ladders connecting outpost modules.
- Fixes to waypoint generator, mainly on stairs.
- Fixed a null reference exception when a bot is dismissed while being told to follow the player and still in the combat state.
- Fixed Giant Spineling targeting doors after being attacked, which it shouldn't do by design. Might affect other creatures too.
Fixes (unstable only):
- Fixes and improvements to colony modules.
- Fixed items in vending machines not being displayed as "out of stock" client-side, fixed money getting deducted when trying to buy an item that's out of stock.
- Fixed crashing on startup if the selected language cannot be found (e.g. if you've previously used a modded language and no longer have that mod installed).
- Fixed chat messages about money transfer votes not showing up.
- Fixed voting not finishing until the timer has elapsed even if there's already enough yes/no votes.
- Fixed vitality multipliers not working (e.g. damage to the head not having a bigger effect than damage to the limbs).
- Fixed "create level object" crashing the level editor.
- Fixed crashing when trying to save a sub with whitespace at the end of the name.
- Fixed sub editor's tag picker not working.
- Fixed event sprites not appearing.
- Fixed submarine switching not working.
- Fixed crew list and chatbox refusing to stay closed.
- Fixed character names being in upper case when using the health scanner.
- Fixed explosive coilgun ammo not being sold by armory merchants.
- Fixed physicorium not being sold at research outposts.
- Fixed issues with store interface displaying incorrect information.
- Fixed issues with buying items in multiplayer campaign.
- Fixed issues with generating daily specials and requested goods for campaign stores.
- Fixed double title in mod download prompt.
- Fixed mod transfer skipping item assemblies.
- Waypoint fixes on new colony modules.
---------------------------------------------------------------------------------------------------------
v0.17.5.0
---------------------------------------------------------------------------------------------------------
Changes:
- Changed server browser tooltips: list all missing mods instead of just missing ones that aren't available from the workshop.
- Players without the permission to access the bank can request money from the bank (approved by vote).
- Modified Selkie emergency hatch: can only use it if the shuttle is flooded.
- Added limits to how many items a vending machine can dispense and adjusted what's available in them (unstable only).
- Reworked campaign permissions: removed BuyItems and CampaignStore permissions (no longer needed, everyone can buy), added ManageMap and ManageHires permissions, ManageCampaign allows gives you all the other campaign-related permissions.
- Adjusted the amount of colonies in cold caverns.
- Added a prompt to allow modders to automatically transfer their mods and submarines from before v0.17 to the new LocalMods folder.
- Disabled loading submarines from the Submarines folder, as it has been rendered obsolete by this change.
- Removed submarine download confirmation prompt. All subs that are required to play in a server will be downloaded automatically, which shouldn't be a problem since they're only stored temporarily.
- Swapped the sides of server log and character info in multiplayer tab menu.
- Doubled the rate limit for medical clinic which should reduce "No response from server" errors.
- Rebalance mudraptors: slightly more health, less damage at head.
- Reduce the probability for the coilgun to dismember limbs (or break armor).
- Crawler: adjust the vitality multipliers of hands and tail from 50% to 75%.
Fixes:
- Fixed multiplayer campaign saves with semicolons or pipes in their name causing "path to a save file was empty" errors in the server lobby.
- Fixed performance drops in multiplayer when someone attacks the outpost NPCs and causes the reputation to drop.
- Moved the showperf view to the right to prevent it from overlapping with the crew list.
- Fixed status monitor's electrical view and item finder not showing items in docked subs.
- The sound of crowbaring a door open can't be heard from other subs.
- Fixed "a gaze into the abyss" achievement working unreliably. The achievement didn't unlock until you returned to 50% of the crush depth, which isn't possible in some levels (e.g. if the level starts at 3500 m and crush depth at 5000 m). Now it's unlocked if you get to 500 m above the crush depth or to the end of the level.
- Fixed certain achievements (last man standing, lone sailor, finishing a round with a specific job) not unlocking if you're in a docked sub instead of the main sub at the end of the round.
- Readjusted all sitting animations so that they characters shouldn't twitch anymore while sitting.
Fixes (unstable only):
- Fixed mods list being configurable outside of the main menu.
- Misc fixes to colonies (added vents, wired docking ports, adjusted misaligned stairs, fixed a bunch of gap and draw order issues).
- Fixed outpost generator sometimes placing a hallway between modules connected by stairs in colonies.
- Fixed crashing when saving a sub.
- Fixed cargo missions sometimes displaying an incorrect number of crates in the description.
- Hide the "sufficient skills to fabricate"/"insufficient skills to fabricate" labels on the vending machines.
- Decrease the number of daily specials and requested goods for merchants to account for the multiple vendors.
- Fixed crash in Mission.GetSalaryEligibleCrew when taking control of a bot in the multiplayer campaign.
- Fixed tab menu blocking all other UI elements.
- Readjusted amount of materials in abyss islands.
- Fixed wallet UI being accessible in all multiplayer game modes.
- Fixed flashlights emitting sparks.
- Flipped the confirm and reset buttons in wallet UI.
- Added a new column to multiplayer tab menu that shows the amount of money the player has in their wallet.
- Added psychosis and hallucination reduction to pipe tobacco, cigars and ethanol, rather than just giving psychosis resistance.
- Reduced base price of tobacco products (pipe tobacco and cigars)
Modding:
- Option to make missions force a ruin in the level if there isn't one.
- Character editor: don't check the validity of the texture path when copying humans (because the path is not valid and will be parsed later). Allows creating custom human characters by copying the vanilla human (even though they are not fully supported).
---------------------------------------------------------------------------------------------------------
v0.17.4.0
---------------------------------------------------------------------------------------------------------
Changes:
- Split outposts stores into several different vendors who sell different types of items.
- Made DockingPort.ApplyEffectsOnDocking editable in the sub editor.
- Some UX improvements in the installed mods lists (unstable only).
- Items can be purchased from vending machines using the personal wallet (WIP).
Fixes:
- Attempt to fix a crash in AIObjectiveExtinguishFire.
- Fixed bots not being able to repair leaks between rooms (leaks that are not in the outer walls).
- Fixed "deep sea slayer" always giving you a 50% buff to harpoons regardless if you're inside or not.
- Fixed text scale not being taken into account on scrolling text displays.
Fixes (unstable only):
- Fixed Workshop items not getting uninstalled when they're removed through the Publish tab.
- Fixed mods being disabled when they're updated.
- Fixed the weird sitting animation for the new office chair.
- Fixed a race condition in Workshop item installer.
- Mod list filter works when coming back from looking at an installed mod's info.
- Fixed new submarines being disabled upon restart.
- Fixed stat types being displayed incorrectly in talent tooltips (e.g. "stattypenames.repairspeed" instead of "Repair Speed").
- Fixed crashing when selecting a client who's not controlling a character in the tab menu.
- Fixed ContentPackageManager.Init failing if more than 100 mods are enabled.
- Fixed structures' "use drop shadow" setting being forced on in the sub editor.
- Fixed tutorials being in a random order in the main menu and some of the tutorials spawning the character with an incorrect job.
- Raised the file transfer size limit for mods from 50 MB to 500 MB.
- Fixed the new abyss monster's tongue sometimes sliding and deattaching from the sub.
- Fixed ServerSettings.MonsterEnabled not syncing correctly in a modded server.
- Fixed crashing when selecting something in the "allow attaching to" dropdown of a module's saving prompt.
- Fixed group names not showing up in the sub editor's "Send selection to group..." context menu.
- Fixed crashing when trying to load a save that contains locations not present in the current content package(s).
- Fixed crashing if a mod adds locations that don't have any name formats specified.
- Fixed crash when saving, immediately deleting, and resaving Unnamed.sub.
- Fixed ai target overrides not working, because only the definitions in the variant file were used. Fixes e.g. Mudraptor Veteran not targeting anything but Tigerthreshers.
Modding:
- Fixed "targetcontaineditem" still not working correctly.
- Fixed crashing when trying to remove fog of war at the very edges of the campaign map. Doesn't affect the vanilla game because there's enough padding at the edges of the map.
---------------------------------------------------------------------------------------------------------
v0.17.3.0
---------------------------------------------------------------------------------------------------------
Changes:
- A new abyss monster (placeholder art and sounds, name pending)
Changes and additions:
- Overhauled colonies: completely new modules, improved layouts, new structures and items, new events.
- Split outposts stores into several different vendors who sell different types of items.
- New store (and sub editor) categories: weapon, medical, diving, and fuel. Reorganized the items into categories.
- Adjusted the amount of colonies in Cold Caverns.
- Added personal wallets. Everyone in the crew now has their personal wallet that they can use to purchase whatever they wish in outposts. The host (or people with campaign management permissions) can distribute a portion of the mission rewards to the crew or transfer money from the shared funds to the players.
- Reworked campaign permissions: removed BuyItems and CampaignStore permissions (no longer needed, since everyone can buy), added ManageMap and ManageHires permissions, ManageCampaign allows gives you all the other campaign-related permissions.
- Items can be purchased from outpost vending machines using the personal wallet.
- Reworked the power distribution logic. Should fix unstability and inconsistencies in power grids involving relays and batteries.
- Adjustments to reactors and supercapacitors to prevent the increased supercapacitor loads from crippling the subs on default recharge rates: slightly increased Humpback reactor output and decreased the default recharge rate of the capacitors, reduced recharge rates in the 3 new subs and set the supercapacitor efficiency to match the rest of the subs.
- Throw an error in debug and unstable builds if beacon station becomes inactive after it's been activated (hopefully helps us diagnose why beacon missions sometimes fail after the beacon's been activated).
- Reimplemented ServerExecutable to be usable in non-core packages. Now, players must select a server executable from a dropdown in the "Host server" menu if multiple are available.
- Ballast flora improvements: improved damage visuals, branches die when cut from the root, the flora regenerates health at a rate relative to it's size.
- Made text displays and terminals craftable/attachable/detachable.
- Made Concat component's separator field editable mid-round.
- Made Deadeye Carbine fire in bursts.
- Animation adjustment: The head now rotates towards the mouse cursor while aiming or swimming.
- Swim animation adjustment: The body now rotates towards the aim target also when the character is moving, and not only while staying still. Moving while not facing the movement direction results in reduced movement speed.
- Set the bottom hole probability to 0 in Cold Caverns, which reduces the size and the frequency of holes in the level bottom.
- Adjusted the probabilities for spawning the Thalamus in the wrecks.
- Added a (WIP) difficulty hierarchy for the abyss monsters. Easier monsters should spawn more frequently on an easier difficulty level, the harder should spawn more frequently on higher difficulty levels. Currently the new abyss monster is defined as the easiest, and Endworm the hardest. Charybdis is in between.
Fixes:
- Re-filled Typhon 2 oxygen tank shelves.
- Fixed spawnpoint editing panel being too small on large resolutions.
- Fixed inability to equip one-handed items when there's a suitable container in the other hand (e.g. flashlight when there's a storage container in the other hand).
- Cargo missions don't require the cargo to be inside a hull: being in the sub is enough. Fixes inability to complete cargo missions with unconventional subs where the cargo is stored outside hulls.
- Fixed non-equipped items that can't be put into a duffel bag disappearing when a character despawns.
- Fixed incorrect animation parameters being used for swimming while wearing a regular diving suit.
- Fixed projectiles sometimes staying attached to the target even when they are far from it.
- Fixed monsters sometimes trying to follow targets after losing the track of them even when they should be falling back from them (according to the after attack behavior).
- Fixed monsters sometimes using the after attack behavior of the current attack even when the cooldown of that attack is not active.
- Fixed monsters sometimes being unable to target the submarine, because their attack was incorrectly considered invalid.
- Fixed fractal guardians fleeing to a shelter immediatedly after taking some damage when they have targeted the guardian pod once and have not changed the target yet (e.g. if you shoot a guardian that is returning from the pod and if it has not yet spotted you).
Fixes (unstable only):
- Fixed text scale slider not working.
- Fixed audio capture and output settings changes not being applied until the game was restarted.
- Fixed numerous circumstances where the Publish tab could cause a crash or softlock.
- Fixed creating and deleting item assemblies in the submarine editor.
- Fixed deleting submarines in the submarine editor.
- Trimmed down the filenames of mods transferred from the server to the clients.
- Fixed ballast flora's damage visualizations (particles, branches shaking, healthbar) not working in multiplayer (unstable only).
- Fixed occasional "invalid SetAttackTarget/ExecuteAttack" errors in multiplayer (unstable only).
- Fixed clients not taking control off the previous character properly when using freecam, preventing the character from moving if another player or AI takes control of it (unstable only).
- Fixed "event data was of the wrong type" error when characters spawn with items with depleted condition in their inventory (unstable only).
- Fixed incorrect power displayed on the reactor when unwired (unstable only).
- Fixed devices not powering down if they're disconnected from the grid when their voltage has been set above 0. Could be reproduced by powering up the sub in mp campaign, entering a new level and disconnecting e.g. the oxygen generator from the grid (unstable).
- Fixed hidden subs resetting client-side when restarting a server (unstable only).
- Randomize character appearance in server lobby if it hasn't been set (= when launching the game or v0.17 for the first time). Unstable only.
Modding:
- ItemContainers apply the OnContaining effects even when the item is broken. Doesn't affect any vanilla items.
- Ropes attached to limbs now automatically snap when another attack is chosen.
- Ropes can now be set to break from the end instead of always breaking from the middle (see the new abyss monster for an example).
- Ropes can be set to break if they are in too steep angle to the target.
- Projectiles always stick permanently unless a stick duration is defined.
- Characters (with deformable sprites) can be set to be drawn after (on top of) other characters. Normally characters are drawn in the order of spawning.
- AI Triggers can now be permanent.
- Added a generic damage threshold that currently defines how much damage the character needs to take from a single hit to hit the avoiding and releasing captured targets.
- Added a support for multiple identifiers and types in the limb health definitions.
- Added a support for min range for ranged attacks.
- Fixed monsters not being able to shoot faster than every ~1.5 second if they change the attacking limb.
- Added new after attack behaviors: Reverse and ReverseUntilCanAttack.
---------------------------------------------------------------------------------------------------------
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
---------------------------------------------------------------------------------------------------------
Changes:
- Added personal wallets. Everyone in the crew now has their personal wallet that they can use to purchase whatever they wish in outposts. The host (or people with campaign management permissions) can distribute a portion of the mission rewards to the crew or transfer money from the shared funds to the players.
- Characters spawn at a spawnpoint appopriate for their job when using the console command "spawn [job] inside".
- Added "low_oxygen" output to oxygen detectors.
- Beacon missions can spawn other types of monsters than just crawlers.
- Made supercapacitors take some damage when they're being charged faster than 70%.
- Increased Orca 2's reactor output.
- Adjustments to mission distribution: only easy missions at the beginning of the campaign, moved some of the more difficult missions later into the campaign.
- Made Not Component's ContinuousOutput property editable in-game.
- Show warnings when saving a sub in the sub editor if any of the entity counts (walls, items, lights, etc) are very high, don't allow saving if the light counts are above the upper limits.
- Visual/layout mprovements to the Workshop menu.
- Added "power_value_out" and "load_value_out" connections to relays, batteries and supercapacitors.
- Increased SMG Magazine's capacity to 21 to make it divisible with the Deadeye Carbine's 3-bullet bursts (unstable only).
- Made molochs, abyss monsters and fractal guardians immune to poisons.
- Boosted the structure damage from the small crawler eggs from 150 to 200.
- Adjusted structure and item damage for coilgun ammunition: piercing 50% less damage, exploding 100% more damage (from explosions), physicorium 50% more damage.
- Don't populate the abyss in difficulty levels 0 to 10 in single mission mode.
- Revisited endworm: the armor now breaks less easily, reduced the change of cutting the worm towards the head, adjusted the bleeding speed.
Fixes:
- Attempt to fix occasional performance drops in the store interface.
- Fixed clients seeing a blank server lobby if they join when a round is running with respawning disabled.
- Fixed arithmetic and trigonometric components not passing the sender of the signal forwards, preventing e.g. helm skill from boosting engines if the signal goes through a component.
- Fixed occasional crashes when transitioning between levels with showperf enabled in multiplayer campaign.
- Fixed wearables not affecting movement speed when godmode is on.
- Fixed disconnected players preventing talents that require everyone to survive from working (e.g. "Field Medic", "Bootcamp").
- Fixed workshop menu's "popular mods" and "publish" tabs being usable when not connected to Steam (unstable only).
- Fixed text displays' depth being forced to 0.85, causing draw order issues in older subs (unstable only).
- Fixes periscopes not focusing on turrets if there's certain components (e.g. arithmetic components) between them.
- Fixed crashing when trying to use the "dumpeventtexts" command with no arguments or a disallowed path.
- Made smoke detectors a little more sensitive (should fix small fires sometimes not being detected even if they're in the same room).
- Fixed reactor sometimes not catching fire again if you start overheating it again immediately after a fire.
- Fixed broken batteries consuming power (unstable only).
- Fixed sub editor test mode spawning the crew in an inconsistent order, sometimes causing the player to start as someone else than the captain (unstable only).
- Fixed recycling a non-empty SMG magazine dropping the bullet inside it on the floor.
- Fixed "Trusted Captain" and "Esteemed Captain" giving medals even when no missions have been completed.
- Fixed small pump's ballast flora infection sprite (unstable only).
- Fixed text colors being broken in campaign map tooltips (unstable only).
- Fixed text colors not working in texts forced to upper case (e.g. reputation texts in the round summary). Unstable only.
- Fixed EntitySpawnerComponent's SpawnAreaOffset.Y being inverted.
- Fixed gaps generating incorrectly on "Shell A 70 Degrees".
- Fixed items powered by battery cells not working correctly (certain devices like handheld sonar beacons never powering up, and items staying powered indefinitely when you put in a battery and take it out). Unstable only.
- Fixed turret lights starting in an incorrect rotation in the sub editor.
- Fixed "commander" talent still not correctly giving the buff (giving orders that a character already had didn't move the buff). Unstable only.
- Fixed nav terminals sometimes determining which docking port the docking button controls incorrectly (specifically, when the correct docking port is also connected to other ports).
- Fixed campaign saves being considered incompatible if you install some new custom subs (unstable only).
- Fixed an exploit in the depleted fuel SMG magazine recipe.
- Fixed reactor gauges' background sticking out from the gauges when selecting a reactor in the editor.
- Fixed projectiles bouncing off subs without doing any damage (unstable only).
- Fixed crashing when clicking a turret in the sub upgrade menu's submarine preview (unstable only).
- Fixed character variants failing to load animations from the base character (unstable only).
- Fixed deltatime being applied twice to affliction reductions, making meds do practically nothing (unstable only).
- Fixed order of the command menu changing on each launch (unstable only).
- Fixed talent options switching places on each launch (unstable only).
- Fixed submarine upgrades and factions in the round summary switching places on each launch (unstable only).
- Fixed texture compression causing the preview image saving to fail when dragging and dropping the preview image into the save screen via file explorer (unstable only).
- Fixed disguises not working in multiplayer (unstable only).
- Fixed server host getting stuck in a lobby creation loop if their server crashes (unstable only).
- Fixed fractal guardians fleeing to the shelter immediatedly after taking some damage when they have targeted the guardian pod once and have not changed the target yet (e.g. if you shoot a guardian that is returning from the pod and if it has not yet spotted you).
- Fixed Crawler Broodmother regenerating really fast while eating. Broodmother no longer eats her own eggs.
- Fixed monsters not being able to target items (unstable only).
- Fixed spinelings accidentally killing each other with their spikes.
- Fixed "error loading a previously saved order" errors when transitioning between levels (unstable only).
- Fixed burn being ignored in the damagemodifier of Charybdis' head. The jaw worked correctly. Affects pulse laser damage for example.
AI:
- Adjusted bot behavior around ballast flora: priority of some objectives now drops to 0 when the target's been claimed by ballast flora, items claimed by ballast flora aren't valid targets for some objectives anymore.
- Made bot healing dialog reflect if CPR was performed or not.
- Fixed security from the player's own crew attacking the player in multiplayer when the player attacks someone in an outpost.
- Fix bots not ignoring items marked to be "Hidden In Game".
- Bots prefer not to take diving suits off in rooms marged with the "IsWetRoom" flag.
- Docking ports are now automatically considered as "wet rooms".
- Fixed bots trying to target through doors and walls even though there's no line of sight between the end node and the target.
- Added some dialogue to bots when they get infected with the husk infection.
Modding:
- Fixed clients not gaining control of the final stage of a husk affliction when "controlhusk" is enabled.
- When using a mod that doesn't set the InitialCount of any job, choose the first 3 jobs as the starting crew. Otherwise the crew customization menu will be empty and starting the campaign will lead to an immediate game over.
- Made it possible for attack StatusEffects to target the character doing the attack instead of the limb by using "Parent" as the target type.
- Using RemoveCharacter on a limb removes the character that limb belongs to.
- Fixed editing human character in the character editor sometimes making the inventory inaccessible.
- Fixed character editor crashing when trying to copy a character (unstable only).
---------------------------------------------------------------------------------------------------------
v0.17.0.0
---------------------------------------------------------------------------------------------------------
- Modified Selkie emergency hatch: can only use it if the shuttle is flooded.
- Reduce the probability for the coilgun to dismember limbs (or break armor).
- Removed submarine download confirmation prompt. All subs that are required to play in a server will be downloaded automatically, which shouldn't be a problem since they're only stored temporarily.
- Buffed ethanol's and tobacco's effects.
- Renamed "details" to "manage" and "permissions" to "rank" in the client management context menu to make them a little more clear.
- Changes to character aiming behavior.
- Water no longer dirties up walls.
- Disabled store category buttons for categories that contain no items.
Modding:
- An extensive rewrite of how the game handles content packages and loading content. Addresses a ton of issues, inconsistencies and usability issues regarding modding.
@@ -436,18 +51,51 @@ Modding:
- The Workshop preview images are no longer saved into the game folder, fixing the folder gradually growing in size as you use browse mods in the Workshop menu.
- Switching languages no longer requires restarting the game.
- Music can be overridden by identifiers.
- Reimplemented ServerExecutable to be usable in non-core packages. Now, players must select a server executable from a dropdown in the "Host server" menu if multiple are available.
- Character gender and ethnicity are no longer hard-coded: modders can use any kind of arbitrary tags to categorize character sprites.- Option to set the condition of an item spawned with status effects.
- Added new "accessiblebyowner" property to inventories. Allows making a character able to access their inventory even when "accessiblewhenalive" is false.
- Fixed clients not gaining control of the final stage of a husk affliction when "controlhusk" is enabled.
- When using a mod that doesn't set the InitialCount of any job, choose the first 3 jobs as the starting crew. Otherwise the crew customization menu will be empty and starting the campaign will lead to an immediate game over.
- Made it possible for attack StatusEffects to target the character doing the attack instead of the limb by using "Parent" as the target type.
- Using RemoveCharacter on a limb removes the character that limb belongs to.
- Fixed editing human character in the character editor sometimes making the inventory inaccessible.
- Fixed character editor crashing when trying to copy a character (unstable only).
- ItemContainers apply the OnContaining effects even when the item is broken. Doesn't affect any vanilla items.
- Ropes attached to limbs now automatically snap when another attack is chosen.
- Ropes can now be set to break from the end instead of always breaking from the middle (see the new abyss monster for an example).
- Ropes can be set to break if they are in too steep angle to the target.
- Projectiles always stick permanently unless a stick duration is defined.
- Characters (with deformable sprites) can be set to be drawn after (on top of) other characters. Normally characters are drawn in the order of spawning.
- AI Triggers can now be permanent.
- Added a generic damage threshold that currently defines how much damage the character needs to take from a single hit to hit the avoiding and releasing captured targets.
- Added a support for multiple identifiers and types in the limb health definitions.
- Added a support for min range for ranged attacks.
- Fixed monsters not being able to shoot faster than every ~1.5 second if they change the attacking limb.
- Added new after attack behaviors: Reverse and ReverseUntilCanAttack.
- Fixed "targetcontaineditem" still not working correctly.
- Fixed crashing when trying to remove fog of war at the very edges of the campaign map. Doesn't affect the vanilla game because there's enough padding at the edges of the map.
- Made DockingPort.ApplyEffectsOnDocking editable in the sub editor.
- Option to make missions force a ruin in the level if there isn't one.
- Character editor: don't check the validity of the texture path when copying humans (because the path is not valid and will be parsed later). Allows creating custom human characters by copying the vanilla human (even though they are not fully supported).
- Level editor no longer attempts to save the vanilla content.
Changes and additions:
- Reworked the power distribution logic. Should fix unstability and inconsistencies in power grids involving relays and batteries.
- Ballast flora improvements: improved damage visuals, branches die when cut from the root, the flora regenerates health at a rate relative to it's size.
- Made text displays and terminals craftable/attachable/detachable.
- Made Concat component's separator field editable mid-round.
- Made Deadeye Carbine fire in bursts.
- Characters spawn at a spawnpoint appopriate for their job when using the console command "spawn [job] inside".
- Added "low_oxygen" output to oxygen detectors.
- Beacon missions can spawn other types of monsters than just crawlers.
Monsters:
- Added Latcher, a new abyss monster.
- Added a difficulty hierarchy for the abyss monsters. Easier monsters should spawn more frequently on an easier difficulty level, the harder should spawn more frequently on higher difficulty levels. Currently the new abyss monster is defined as the easiest, and Endworm the hardest. Charybdis is in between.
- Revisited endworm: the armor now breaks less easily, reduced the change of cutting the worm towards the head, adjusted the bleeding speed.
- 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.
- Made molochs, abyss monsters and fractal guardians immune to poisons.
- Fixed monsters sometimes trying to follow targets after losing the track of them even when they should be falling back from them (according to the after attack behavior).
- Fixed monsters sometimes using the after attack behavior of the current attack even when the cooldown of that attack is not active.
- Fixed monsters sometimes being unable to target the submarine, because their attack was incorrectly considered invalid.
- Fixed fractal guardians fleeing to a shelter immediatedly after taking some damage when they have targeted the guardian pod once and have not changed the target yet (e.g. if you shoot a guardian that is returning from the pod and if it has not yet spotted you).
- Adjusted the probabilities for spawning the Thalamus in the wrecks.
- Rebalanced mudraptors: slightly more health, less damage at head.
- Crawler: adjusted the vitality multipliers of hands and tail from 50% to 75%.
- Fixed Giant Spineling targeting doors after being attacked, which it shouldn't do by design. Might affect other creatures too.
- Fixed calyxanide not damaging the "naturally spawning" husks.
- Giant Spineling doesn't flee anymore when being shot with coilgun, chaingun, or small arms.
- Adjusted the kill hammerhead missions.
Balance:
- Increased the price of calyxanide to make it more in line with the price of husk eggs.
@@ -462,6 +110,24 @@ AI:
- Fixed bots still sometimes getting stuck when trying to get something from or put something to secure lockers.
- Fixed bots acting weird while trying to use underwater scooters inside.
- Fixed bots failing to heal characters in a docked sub/shuttle.
- Adjusted bot behavior around ballast flora: priority of some objectives now drops to 0 when the target's been claimed by ballast flora, items claimed by ballast flora aren't valid targets for some objectives anymore.
- Made bot healing dialog reflect if CPR was performed or not.
- Fixed security from the player's own crew attacking the player in multiplayer when the player attacks someone in an outpost.
- Fix bots not ignoring items marked to be "Hidden In Game".
- Bots prefer not to take diving suits off in rooms marged with the "IsWetRoom" flag.
- Docking ports are now automatically considered as "wet rooms".
- Fixed bots trying to target through doors and walls even though there's no line of sight between the end node and the target.
- Added some dialogue to bots when they get infected with the husk infection.
- 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.
- Attempt to fix a crash in AIObjectiveExtinguishFire.
- Fixed bots not being able to repair leaks between rooms (leaks that are not in the outer walls).
- Waypoint fixes on abandoned outpost modules, some regular outpost modules, and Winterhalter.
- Fixed bots occasionally getting stuck while climbing ladders connecting outpost modules.
- Fixes to waypoint generator, mainly on stairs.
- Fixed a null reference exception when a bot is dismissed while being told to follow the player and still in the combat state.
- Fixed items flagged as "HiddenInGame" being considered interactable and therefore e.g. valid repair targets.
- Fixed outpost guards not arresting the offender when it's very far from them.
- Fixed bots sometimes failing to navigate back to the sub (when they are on the other side of the sub than where the hatch is).
Talents:
- Fix to yet another issue that sometimes prevented unlocking additional talents after unlocking "All-seeing Eye".
@@ -470,6 +136,10 @@ Talents:
- Fixed "Mass Production" talent allowing you to power devices by tinkering.
- Fixed "Pyromaniac" giving 39.9% damage resistance instead of 40%.
- Fixed ability to tinker indefinitely by interrupting the tinkering by switching to repairing the item.
- Fixed "Trusted Captain" and "Esteemed Captain" giving medals even when no missions have been completed.
- Fixed disconnected players preventing talents that require everyone to survive from working (e.g. "Field Medic", "Bootcamp").
- Fixed "Deep Sea Slayer" always giving you a 50% buff to harpoons regardless if you're inside or not.
- Fixed "Deep Sea Slayer" talent not affecting explosive harpoons.
Fixes:
- Fixed monsters being able to attack with practically no cooldown when they're taking constant damage from a player.
@@ -493,6 +163,64 @@ Fixes:
- Fixed dropped signal components being drawn behind devices (now they're only drawn behind devices when attached to a wall).
- Fixed SMGs autofilled into the subs sometimes spawning without magazines.
- Fixed misaligned "Label Number 6" decal.
- Attempt to fix occasional performance drops in the store interface.
- Fixed clients seeing a blank server lobby if they join when a round is running with respawning disabled.
- Fixed arithmetic and trigonometric components not passing the sender of the signal forwards, preventing e.g. helm skill from boosting engines if the signal goes through a component.
- Fixed occasional crashes when transitioning between levels with showperf enabled in multiplayer campaign.
- Fixed wearables not affecting movement speed when godmode is on.
- Fixes periscopes not focusing on turrets if there's certain components (e.g. arithmetic components) between them.
- Fixed crashing when trying to use the "dumpeventtexts" command with no arguments or a disallowed path.
- Made smoke detectors a little more sensitive (should fix small fires sometimes not being detected even if they're in the same room).
- Fixed reactor sometimes not catching fire again if you start overheating it again immediately after a fire.
- Fixed recycling a non-empty SMG magazine dropping the bullet inside it on the floor.
- Fixed EntitySpawnerComponent's SpawnAreaOffset.Y being inverted.
- Fixed gaps generating incorrectly on "Shell A 70 Degrees".
- Fixed items powered by battery cells not working correctly (certain devices like handheld sonar beacons never powering up, and items staying powered indefinitely when you put in a battery and take it out). Unstable only.
- Fixed turret lights starting in an incorrect rotation in the sub editor.
- Fixed "commander" talent still not correctly giving the buff (giving orders that a character already had didn't move the buff). Unstable only.
- Fixed nav terminals sometimes determining which docking port the docking button controls incorrectly (specifically, when the correct docking port is also connected to other ports).
- Fixed an exploit in the depleted fuel SMG magazine recipe.
- Fixed reactor gauges' background sticking out from the gauges when selecting a reactor in the editor.
- Fixed fractal guardians fleeing to the shelter immediatedly after taking some damage when they have targeted the guardian pod once and have not changed the target yet (e.g. if you shoot a guardian that is returning from the pod and if it has not yet spotted you).
- Fixed Crawler Broodmother regenerating really fast while eating. Broodmother no longer eats her own eggs.
- Fixed spinelings accidentally killing each other with their spikes.
- Fixed burn being ignored in the damagemodifier of Charybdis' head. The jaw worked correctly. Affects pulse laser damage for example.
- 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.
- Fixed text scale not being taken into account on scrolling text displays.
- Re-filled Typhon 2 oxygen tank shelves.
- Fixed spawnpoint editing panel being too small on large resolutions.
- Fixed inability to equip one-handed items when there's a suitable container in the other hand (e.g. flashlight when there's a storage container in the other hand).
- Cargo missions don't require the cargo to be inside a hull: being in the sub is enough. Fixes inability to complete cargo missions with unconventional subs where the cargo is stored outside hulls.
- Fixed non-equipped items that can't be put into a duffel bag disappearing when a character despawns.
- Fixed incorrect animation parameters being used for swimming while wearing a regular diving suit.
- Fixed projectiles sometimes staying attached to the target even when they are far from it.
- Fixed multiplayer campaign saves with semicolons or pipes in their name causing "path to a save file was empty" errors in the server lobby.
- Fixed performance drops in multiplayer when someone attacks the outpost NPCs and causes the reputation to drop.
- Moved the showperf view to the right to prevent it from overlapping with the crew list.
- Fixed status monitor's electrical view and item finder not showing items in docked subs.
- The sound of crowbaring a door open can't be heard from other subs.
- Fixed "a gaze into the abyss" achievement working unreliably. The achievement didn't unlock until you returned to 50% of the crush depth, which isn't possible in some levels (e.g. if the level starts at 3500 m and crush depth at 5000 m). Now it's unlocked if you get to 500 m above the crush depth or to the end of the level.
- Fixed certain achievements (last man standing, lone sailor, finishing a round with a specific job) not unlocking if you're in a docked sub instead of the main sub at the end of the round.
- Readjusted all sitting animations so that they characters shouldn't twitch anymore while sitting.
- Doubled the rate limit for medical clinic which should reduce "No response from server" errors.
- Fixed swimming characters sometimes being unable to stand up on stairs/platforms even if the water is shallow enough.
- Fixed guitar and harmonica being rendered on top of the water effect.
- Fixed guitar, harmonica, accordion and captains pipe having neutral buoyancy.
- Fixed mid-round joining clients not seeing subs purchased during that round.
- Fixed research station being repairable by clicking on it instead of pressing E.
- Fixed medical curtains disappearing before they're off-screen.
- Fixed karma preset being forced to default when starting a new server.
- Fixed Herja's rear motion detector being connected to an incorrect display, and the bottom turret display having an incorrect text.
- Fixed crash caused by selection not being cleared when autocompleting or running a console command.
- Fixed occasional performance dips when spineling spikes get stuck to the sub's exterior walls.
- Fixed item assemblies getting misaligned with the grid after saving.
- Fixed "Shell A 18" not aligning with the other shell pieces.
- Fixed welding tool's, plasma cutter's and watering can's particle effects getting "clamped" to the edges of the hull they're inside.
- Fixed permission icon in the client list not updating mid-round.
- Fixed "lock default wires" server setting not affecting docked subs.
- Fixed Dugong's small pumps working without power.
- Fixed buttons in structure editing menu using a different style than other types of entities in the sub editor.
---------------------------------------------------------------------------------------------------------
v0.16.7.0