Release 1.11.4.1 (Winter Update)

This commit is contained in:
Markus Isberg
2025-12-08 14:56:47 +00:00
parent 21e34e5cd8
commit 598966f200
121 changed files with 1614 additions and 819 deletions
@@ -230,7 +230,12 @@ namespace Barotrauma
if (!primaryMouseButtonHeld && !secondaryMouseButtonHeld && !doubleClicked && !secondaryDoubleClicked) { return; }
Vector2 position = cam.ScreenToWorld(PlayerInput.MousePosition);
Hull hull = FindHull(position);
Hull hull =
Screen.Selected is { IsEditor: true } ?
//use the unoptimized version in the editor to make sure newly placed hulls are found
//(FindHull uses the "EntityGrid" which is generated after loading the sub)
FindHullUnoptimized(position) :
FindHull(position);
if (hull == null || hull.IdFreed) { return; }
if (EditWater)
@@ -361,7 +366,7 @@ namespace Barotrauma
new Rectangle(drawRect.X, -drawRect.Y, rect.Width, rect.Height),
GUIStyle.Red * ((100.0f - OxygenPercentage) / 400.0f) * alpha, true, 0, (int)Math.Max(MathF.Ceiling(1.5f / Screen.Selected.Cam.Zoom), 1.0f));
if (GameMain.DebugDraw)
if (GameMain.DebugDraw && Screen.Selected?.Cam is { Zoom: > 0.5f })
{
GUIStyle.SmallFont.DrawString(spriteBatch, "Pressure: " + ((int)pressure - rect.Y).ToString() +
" - Oxygen: " + ((int)OxygenPercentage), new Vector2(drawRect.X + 5, -drawRect.Y + 5), Color.White);
@@ -0,0 +1,74 @@
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System;
namespace Barotrauma;
internal partial class LevelGenerationParams : PrefabWithUintIdentifier
{
/// <remarks>Doesn't call SpriteBatch.Begin and SpriteBatch.End; They must be called manually.</remarks>
public void DrawBackgrounds(SpriteBatch spriteBatch, Camera cam)
{
if (BackgroundTopSprite == null) { return; }
Vector2 backgroundPos = cam.WorldViewCenter.FlipY() * 0.05f;
int backgroundSize = (int)BackgroundTopSprite.size.Y;
if (backgroundPos.Y >= backgroundSize) { return; }
if (backgroundPos.Y < 0f)
{
BackgroundTopSprite.SourceRect = new Rectangle((int)backgroundPos.X, (int)backgroundPos.Y, backgroundSize, (int)Math.Min(-backgroundPos.Y, backgroundSize));
BackgroundTopSprite.DrawTiled(spriteBatch, Vector2.Zero, new Vector2(GameMain.GraphicsWidth, Math.Min(-backgroundPos.Y, GameMain.GraphicsHeight)),
color: BackgroundTextureColor);
}
if (-backgroundPos.Y < GameMain.GraphicsHeight && BackgroundSprite != null)
{
BackgroundSprite.SourceRect = new Rectangle((int)backgroundPos.X, (int)Math.Max(backgroundPos.Y, 0), backgroundSize, backgroundSize);
BackgroundSprite.DrawTiled(spriteBatch, (backgroundPos.Y < 0f) ? new Vector2(0f, (int)-backgroundPos.Y) : Vector2.Zero,
new Vector2(GameMain.GraphicsWidth, (int)Math.Min(Math.Ceiling(backgroundSize - backgroundPos.Y), backgroundSize)),
color: BackgroundTextureColor);
}
}
/// <remarks>Doesn't call SpriteBatch.Begin and SpriteBatch.End; They must be called manually.</remarks>
public void DrawWaterParticles(SpriteBatch spriteBatch, Camera cam, Vector2 offset)
{
if (WaterParticles == null || cam.Zoom <= 0.05f) { return; }
float textureScale = WaterParticleScale;
Vector2 textureSize = new Vector2(WaterParticles.Texture.Width, WaterParticles.Texture.Height);
Vector2 origin = new Vector2(cam.WorldView.X, -cam.WorldView.Y);
offset -= origin;
// Draw 4 layers of particles.
for (int i = 0; i < 4; i++)
{
float scale = 1f - i * 0.2f;
float alpha = MathUtils.InverseLerp(0.05f, 0.1f, cam.Zoom * scale);
if (alpha == 0f) { continue; }
Vector2 newOffset = offset * scale;
newOffset += cam.WorldView.Size.ToVector2() * (1f - scale) * 0.5f;
newOffset -= new Vector2(256f * i);
float newTextureScale = scale * textureScale;
Vector2 newSize = textureSize * scale;
while (newOffset.X <= -newSize.X) { newOffset.X += newSize.X; }
while (newOffset.X > 0f) { newOffset.X -= newSize.X; }
while (newOffset.Y <= -newSize.Y) { newOffset.Y += newSize.Y; }
while (newOffset.Y > 0f) { newOffset.Y -= newSize.Y; }
WaterParticles.DrawTiled(spriteBatch, origin + newOffset, cam.WorldView.Size.ToVector2() - newOffset,
color: WaterParticleColor * alpha, textureScale: new Vector2(newTextureScale));
}
}
public void UpdateWaterParticleOffset(ref Vector2 offset, Vector2 velocity, float deltaTime)
{
if (WaterParticles == null) { return; }
Vector2 waterTextureSize = WaterParticles.size * WaterParticleScale;
offset += velocity.FlipY() * WaterParticleScale * deltaTime;
offset.X %= waterTextureSize.X;
offset.Y %= waterTextureSize.Y;
}
}
@@ -234,15 +234,7 @@ namespace Barotrauma
WaterRenderer.Instance?.ScrollWater(waterParticleVelocity, deltaTime);
if (level.GenerationParams.WaterParticles != null)
{
Vector2 waterTextureSize = level.GenerationParams.WaterParticles.size * level.GenerationParams.WaterParticleScale;
waterParticleOffset += new Vector2(waterParticleVelocity.X, -waterParticleVelocity.Y) * level.GenerationParams.WaterParticleScale * deltaTime;
while (waterParticleOffset.X <= -waterTextureSize.X) { waterParticleOffset.X += waterTextureSize.X; }
while (waterParticleOffset.X >= waterTextureSize.X){ waterParticleOffset.X -= waterTextureSize.X; }
while (waterParticleOffset.Y <= -waterTextureSize.Y) { waterParticleOffset.Y += waterTextureSize.Y; }
while (waterParticleOffset.Y >= waterTextureSize.Y) { waterParticleOffset.Y -= waterTextureSize.Y; }
}
level.GenerationParams.UpdateWaterParticleOffset(ref waterParticleOffset, waterParticleVelocity, deltaTime);
}
public static VertexPositionColorTexture[] GetColoredVertices(VertexPositionTexture[] vertices, Color color)
@@ -274,36 +266,7 @@ namespace Barotrauma
ParticleManager particleManager = null)
{
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, SamplerState.LinearWrap);
Vector2 backgroundPos = cam.WorldViewCenter;
backgroundPos.Y = -backgroundPos.Y;
backgroundPos *= 0.05f;
if (level.GenerationParams.BackgroundTopSprite != null)
{
int backgroundSize = (int)level.GenerationParams.BackgroundTopSprite.size.Y;
if (backgroundPos.Y < backgroundSize)
{
if (backgroundPos.Y < 0)
{
var backgroundTop = level.GenerationParams.BackgroundTopSprite;
backgroundTop.SourceRect = new Rectangle((int)backgroundPos.X, (int)backgroundPos.Y, backgroundSize, (int)Math.Min(-backgroundPos.Y, backgroundSize));
backgroundTop.DrawTiled(spriteBatch, Vector2.Zero, new Vector2(GameMain.GraphicsWidth, Math.Min(-backgroundPos.Y, GameMain.GraphicsHeight)),
color: level.BackgroundTextureColor);
}
if (-backgroundPos.Y < GameMain.GraphicsHeight && level.GenerationParams.BackgroundSprite != null)
{
var background = level.GenerationParams.BackgroundSprite;
background.SourceRect = new Rectangle((int)backgroundPos.X, (int)Math.Max(backgroundPos.Y, 0), backgroundSize, backgroundSize);
background.DrawTiled(spriteBatch,
(backgroundPos.Y < 0) ? new Vector2(0.0f, (int)-backgroundPos.Y) : Vector2.Zero,
new Vector2(GameMain.GraphicsWidth, (int)Math.Min(Math.Ceiling(backgroundSize - backgroundPos.Y), backgroundSize)),
color: level.BackgroundTextureColor);
}
}
}
level.GenerationParams.DrawBackgrounds(spriteBatch, cam);
spriteBatch.End();
spriteBatch.Begin(SpriteSortMode.Deferred,
@@ -317,42 +280,7 @@ namespace Barotrauma
backgroundCreatureManager?.Draw(spriteBatch, cam);
}
if (level.GenerationParams.WaterParticles != null && cam.Zoom > 0.05f)
{
float textureScale = level.GenerationParams.WaterParticleScale;
Rectangle srcRect = new Rectangle(0, 0, 2048, 2048);
Vector2 origin = new Vector2(cam.WorldView.X, -cam.WorldView.Y);
Vector2 offset = -origin + waterParticleOffset;
while (offset.X <= -srcRect.Width * textureScale) offset.X += srcRect.Width * textureScale;
while (offset.X > 0.0f) offset.X -= srcRect.Width * textureScale;
while (offset.Y <= -srcRect.Height * textureScale) offset.Y += srcRect.Height * textureScale;
while (offset.Y > 0.0f) offset.Y -= srcRect.Height * textureScale;
for (int i = 0; i < 4; i++)
{
float scale = (1.0f - i * 0.2f);
//alpha goes from 1.0 to 0.0 when scale is in the range of 0.1 - 0.05
float alpha = (cam.Zoom * scale) < 0.1f ? (cam.Zoom * scale - 0.05f) * 20.0f : 1.0f;
if (alpha <= 0.0f) continue;
Vector2 offsetS = offset * scale
+ new Vector2(cam.WorldView.Width, cam.WorldView.Height) * (1.0f - scale) * 0.5f
- new Vector2(256.0f * i);
float texScale = scale * textureScale;
while (offsetS.X <= -srcRect.Width * texScale) offsetS.X += srcRect.Width * texScale;
while (offsetS.X > 0.0f) offsetS.X -= srcRect.Width * texScale;
while (offsetS.Y <= -srcRect.Height * texScale) offsetS.Y += srcRect.Height * texScale;
while (offsetS.Y > 0.0f) offsetS.Y -= srcRect.Height * texScale;
level.GenerationParams.WaterParticles.DrawTiled(
spriteBatch, origin + offsetS,
new Vector2(cam.WorldView.Width - offsetS.X, cam.WorldView.Height - offsetS.Y),
color: level.GenerationParams.WaterParticleColor * alpha, textureScale: new Vector2(texScale));
}
}
level.GenerationParams.DrawWaterParticles(spriteBatch, cam, waterParticleOffset);
GameMain.ParticleManager?.Draw(spriteBatch, inWater: true, inSub: false, ParticleBlendState.AlphaBlend, background: true);
@@ -89,7 +89,7 @@ namespace Barotrauma.Lights
}
private float pulseAmount;
[Editable(MinValueFloat = 0.0f, MaxValueFloat = 1.0f, DecimalCount = 2), Serialize(0.0f, IsPropertySaveable.Yes, description: "How much light pulsates (in Hz). 0 = not at all, 1 = alternates between full brightness and off.")]
[Editable(MinValueFloat = 0.0f, MaxValueFloat = 1.0f, DecimalCount = 2), Serialize(0.0f, IsPropertySaveable.Yes, description: "How much light pulsates. 0 = not at all, 1 = alternates between full brightness and off.")]
public float PulseAmount
{
get { return pulseAmount; }
@@ -397,7 +397,7 @@ namespace Barotrauma
}
if (!description.IsNullOrEmpty())
{
CreateTextWithIcon(description, locationTypeToDisplay.Sprite);
CreateTextWithIcon(description, iconSprite: locationTypeToDisplay.Sprite);
}
int highestSubTier = location.HighestSubmarineTierAvailable();
@@ -417,32 +417,29 @@ namespace Barotrauma
}
if (highestSubTier > 0)
{
CreateTextWithIcon(TextManager.GetWithVariable("advancedsub.all", "[tiernumber]", highestSubTier.ToString()), icon: null, style: "LocationOverlaySubmarineIcon");
CreateTextWithIcon(TextManager.GetWithVariable("advancedsub.all", "[tiernumber]", highestSubTier.ToString()), iconStyle: "LocationOverlaySubmarineIcon");
}
if (overrideTiers != null)
{
foreach (var (subClass, tier) in overrideTiers)
{
CreateTextWithIcon(TextManager.GetWithVariable($"advancedsub.{subClass}", "[tiernumber]", tier.ToString()), icon: null, style: "LocationOverlaySubmarineIcon");
CreateTextWithIcon(TextManager.GetWithVariable($"advancedsub.{subClass}", "[tiernumber]", tier.ToString()), iconStyle: "LocationOverlaySubmarineIcon");
}
}
CreateSpacing(10);
void CreateTextWithIcon(LocalizedString text, Sprite icon, string style = null)
void CreateTextWithIcon(LocalizedString text, Sprite iconSprite = null, string iconStyle = null)
{
var textHolder = new GUILayoutGroup(new RectTransform(new Point(content.Rect.Width, (int)GUIStyle.Font.MeasureString(text).Y), content.RectTransform), isHorizontal: true)
{
Stretch = true,
CanBeFocused = true
};
var guiIcon =
style == null ?
new GUIImage(new RectTransform(Vector2.One * 1.25f, textHolder.RectTransform, scaleBasis: ScaleBasis.BothHeight), icon) :
new GUIImage(new RectTransform(Vector2.One * 1.25f, textHolder.RectTransform, scaleBasis: ScaleBasis.BothHeight), style);
var textBlock = new GUITextBlock(new RectTransform(new Vector2(0.9f, 1.0f), textHolder.RectTransform), text);
textBlock.RectTransform.MinSize = new Point((int)textBlock.TextSize.X, 0);
textHolder.RectTransform.MinSize = new Point((int)textBlock.TextSize.X + guiIcon.Rect.Width, 0);
GUITextBlock textBox = new(new RectTransform(new Vector2(0.9f, 0f), content.RectTransform), text, wrap: true);
if (iconSprite == null && iconStyle == null) { return; }
float iconSize = GUIStyle.Font.LineHeight * 1.5f;
textBox.Padding = textBox.Padding with { X = iconSize + 5f };
RectTransform iconTF = new(new Point((int)iconSize), textBox.RectTransform, Anchor.CenterLeft) { IsFixedSize = true };
if (iconSprite != null) { new GUIImage(iconTF, iconSprite, scaleToFit: true); }
if (iconStyle != null) { new GUIImage(iconTF, iconStyle, scaleToFit: true); }
}
void CreateSpacing(int height)
@@ -486,10 +483,11 @@ namespace Barotrauma
CreateSpacing(20);
}
locationInfoOverlay.RectTransform.NonScaledSize =
new Point(
Math.Max(locationInfoOverlay.Rect.Width, (int)(content.Children.Max(c => c is GUITextBlock textBlock ? textBlock.TextSize.X : c.RectTransform.MinSize.X) * 1.2f)),
(int)(content.Children.Sum(c => c.Rect.Height) / content.RectTransform.RelativeSize.Y));
float childWidth = Math.Max(locationInfoOverlay.Rect.Width, content.Children.Max(c => c is GUITextBlock textBlock ? textBlock.TextSize.X + textBlock.Padding.X + textBlock.Padding.Z : c.RectTransform.MinSize.X));
childWidth = Math.Max(locationInfoOverlay.Rect.Width, childWidth);
float childHeight = content.Children.Sum(c => c.Rect.Height);
Vector2 childSize = new Vector2(childWidth, childHeight) / content.RectTransform.RelativeSize;
locationInfoOverlay.RectTransform.NonScaledSize = childSize.ToPoint();
}
partial void ClearAnimQueue()
@@ -34,6 +34,8 @@ namespace Barotrauma
//which entities have been selected for editing
public static HashSet<MapEntity> SelectedList { get; private set; } = new HashSet<MapEntity>();
private static List<Rectangle> oldRects = new List<Rectangle>();
private static Vector2 entityMovementNudge;
public static List<MapEntity> CopiedList = new List<MapEntity>();
@@ -267,7 +269,7 @@ namespace Barotrauma
i++;
}
highlightedEntities.Insert(i, e);
if (i == 0) highLightedEntity = e;
if (i == 0) { highLightedEntity = e; }
}
}
UpdateHighlighting(highlightedEntities);
@@ -278,10 +280,19 @@ namespace Barotrauma
if (GUI.KeyboardDispatcher.Subscriber == null)
{
Vector2 nudge = GetNudgeAmount();
if (nudge != Vector2.Zero)
Vector2 previousNudge = entityMovementNudge;
entityMovementNudge = GetNudgeAmount();
if (entityMovementNudge != Vector2.Zero)
{
foreach (MapEntity entityToNudge in SelectedList) { entityToNudge.Move(nudge); }
if (previousNudge == Vector2.Zero)
{
oldRects = SelectedList.Select(entity => entity.Rect).ToList();
}
foreach (MapEntity entityToNudge in SelectedList) { entityToNudge.Move(entityMovementNudge); }
}
else if (previousNudge != Vector2.Zero)
{
SubEditorScreen.StoreCommand(new TransformCommand(new List<MapEntity>(SelectedList), SelectedList.Select(entity => entity.Rect).ToList(), oldRects, resized: false));
}
}
else
@@ -352,7 +363,7 @@ namespace Barotrauma
}
}
SubEditorScreen.StoreCommand(new TransformCommand(new List<MapEntity>(SelectedList),SelectedList.Select(entity => entity.Rect).ToList(), oldRects, false));
SubEditorScreen.StoreCommand(new TransformCommand(new List<MapEntity>(SelectedList), SelectedList.Select(entity => entity.Rect).ToList(), oldRects, resized: false));
if (deposited.Any() && deposited.Any(entity => entity is Item))
{
var depositedItems = deposited.Where(entity => entity is Item).Cast<Item>().ToList();
@@ -508,7 +519,7 @@ namespace Barotrauma
selectionSize = Vector2.Zero;
selectionPos = Vector2.Zero;
}
public static Vector2 GetNudgeAmount(bool doHold = true)
{
Vector2 nudgeAmount = Vector2.Zero;
@@ -532,10 +543,10 @@ namespace Barotrauma
}
}
if (PlayerInput.KeyHit(Keys.Up)) nudgeAmount.Y = 1f;
if (PlayerInput.KeyHit(Keys.Down)) nudgeAmount.Y = -1f;
if (PlayerInput.KeyHit(Keys.Left)) nudgeAmount.X = -1f;
if (PlayerInput.KeyHit(Keys.Right)) nudgeAmount.X = 1f;
if (PlayerInput.KeyHit(Keys.Up)) { nudgeAmount.Y = 1f; }
if (PlayerInput.KeyHit(Keys.Down)) { nudgeAmount.Y = -1f; }
if (PlayerInput.KeyHit(Keys.Left)) { nudgeAmount.X = -1f;}
if (PlayerInput.KeyHit(Keys.Right)) { nudgeAmount.X = 1f; }
return nudgeAmount;
}
@@ -172,16 +172,19 @@ namespace Barotrauma
GUI.DrawRectangle(spriteBatch, drawPos - ExitPointSize.ToVector2() / 2, ExitPointSize.ToVector2(), Color.Cyan, thickness: 5);
}
GUIStyle.SmallFont.DrawString(spriteBatch,
ID.ToString(),
new Vector2(DrawPosition.X - 10, -DrawPosition.Y - 30),
color);
if (Tunnel?.Type != null)
if (Screen.Selected?.Cam is { Zoom: > 0.4f })
{
GUIStyle.SmallFont.DrawString(spriteBatch,
Tunnel.Type.ToString(),
new Vector2(DrawPosition.X - 10, -DrawPosition.Y - 45),
color);
ID.ToString(),
new Vector2(DrawPosition.X - 10, -DrawPosition.Y - 30),
color);
if (Tunnel?.Type != null)
{
GUIStyle.SmallFont.DrawString(spriteBatch,
Tunnel.Type.ToString(),
new Vector2(DrawPosition.X - 10, -DrawPosition.Y - 45),
color);
}
}
}