Build 0.18.5.0

This commit is contained in:
Markus Isberg
2022-06-03 22:29:04 +09:00
parent 64db1a6a44
commit 6be757a45b
72 changed files with 869 additions and 439 deletions

View File

@@ -266,7 +266,7 @@ namespace Barotrauma
disguisedSkinColor = idCard.StoredOwnerAppearance.SkinColor;
}
partial void LoadAttachmentSprites(bool omitJob)
partial void LoadAttachmentSprites()
{
if (attachmentSprites == null)
{
@@ -280,14 +280,6 @@ namespace Barotrauma
Head.BeardElement?.GetChildElements("sprite").ForEach(s => attachmentSprites.Add(new WearableSprite(s, WearableType.Beard)));
Head.MoustacheElement?.GetChildElements("sprite").ForEach(s => attachmentSprites.Add(new WearableSprite(s, WearableType.Moustache)));
Head.HairElement?.GetChildElements("sprite").ForEach(s => attachmentSprites.Add(new WearableSprite(s, WearableType.Hair)));
if (omitJob)
{
JobPrefab.NoJobElement?.GetChildElement("PortraitClothing")?.GetChildElements("sprite").ForEach(s => attachmentSprites.Add(new WearableSprite(s, WearableType.JobIndicator)));
}
else
{
Job?.Prefab.ClothingElement?.GetChildElements("sprite").ForEach(s => attachmentSprites.Add(new WearableSprite(s, WearableType.JobIndicator)));
}
}
// Doesn't work if the head's source rect does not start at 0,0.

View File

@@ -651,6 +651,8 @@ namespace Barotrauma
GameMain.LightManager.LosEnabled = true;
GameMain.LightManager.LosAlpha = 1f;
GameMain.NetLobbyScreen.CampaignCharacterDiscarded = false;
character.memInput.Clear();
character.memState.Clear();
character.memLocalState.Clear();

View File

@@ -172,6 +172,7 @@ namespace Barotrauma
isOpen = false;
GUI.ForceMouseOn(null);
textBox.Deselect();
SoundPlayer.PlayUISound(GUISoundType.Select);
}
if (isOpen)
@@ -209,7 +210,7 @@ namespace Barotrauma
isOpen = !isOpen;
if (isOpen)
{
textBox.Select();
textBox.Select(ignoreSelectSound: true);
AddToGUIUpdateList();
}
else
@@ -217,6 +218,7 @@ namespace Barotrauma
GUI.ForceMouseOn(null);
textBox.Deselect();
}
SoundPlayer.PlayUISound(GUISoundType.Select);
}
private static bool IsCommandPermitted(string command, GameClient client)

View File

@@ -81,6 +81,8 @@ namespace Barotrauma
public const int ToggleButtonWidthRaw = 30;
private int popupMessageOffset;
private GUIDropDown ChatModeDropDown { get; set; }
public ChatBox(GUIComponent parent, bool isSinglePlayer)
{
this.IsSinglePlayer = isSinglePlayer;
@@ -226,7 +228,53 @@ namespace Barotrauma
// ---------------------------------------------------------------------------------------------
InputBox = new GUITextBox(new RectTransform(new Vector2(1.0f, 0.125f), hideableElements.RectTransform, Anchor.BottomLeft),
var bottomContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.125f), hideableElements.RectTransform, Anchor.BottomLeft), isHorizontal: true)
{
Stretch = true
};
var dropdownRt = new RectTransform(new Vector2(0.1f, 1.0f), bottomContainer.RectTransform)
{
// The chat mode selection dropdown will take a maximum of 45% of the horizontal space
MaxSize = new Point((int)(0.45f * bottomContainer.RectTransform.NonScaledSize.X), int.MaxValue)
};
var chatModes = new ChatMode[] { ChatMode.Local, ChatMode.Radio };
ChatModeDropDown = new GUIDropDown(dropdownRt, elementCount: chatModes.Length, dropAbove: true)
{
OnSelected = (component, userdata) =>
{
GameMain.ActiveChatMode = (ChatMode)userdata;
if (InputBox != null && InputBox.Text.StartsWith(RadioChatString) && GameMain.ActiveChatMode == ChatMode.Local)
{
string text = InputBox.Text;
InputBox.Text = text.Remove(0, RadioChatString.Length);
}
return true;
}
};
float longestDropDownOption = 0.0f;
foreach (ChatMode mode in chatModes)
{
var text = TextManager.Get($"chatmode.{mode}");
ChatModeDropDown.AddItem(text, userData: mode);
if (ChatModeDropDown.ListBox.Content.GetChildByUserData(mode) is GUITextBlock textBlock)
{
if (textBlock.TextSize.X > longestDropDownOption)
{
longestDropDownOption = textBlock.TextSize.X;
}
}
}
ChatModeDropDown.SelectItem(GameMain.ActiveChatMode);
float minDropDownWidth = longestDropDownOption + ChatModeDropDown.Padding.X +
(ChatModeDropDown.DropDownIcon?.RectTransform.NonScaledSize.X ?? 0) +
(ChatModeDropDown.DropDownIcon?.RectTransform.AbsoluteOffset.X ?? 0) * 2;
ChatModeDropDown.RectTransform.MinSize = new Point(
Math.Max((int)minDropDownWidth, ChatModeDropDown.RectTransform.MinSize.X),
ChatModeDropDown.RectTransform.MinSize.Y);
InputBox = new GUITextBox(new RectTransform(new Vector2(0.9f, 1.0f), bottomContainer.RectTransform),
style: "ChatTextBox")
{
OverflowClip = true,
@@ -248,8 +296,6 @@ namespace Barotrauma
CloseAfterMessageSent = false;
}
}
//gui.Text = "";
};
var chatSendButton = new GUIButton(new RectTransform(new Vector2(1.0f, 0.7f), InputBox.RectTransform, Anchor.CenterRight, scaleBasis: ScaleBasis.BothHeight), style: "GUIButtonToggleRight");
@@ -306,6 +352,10 @@ namespace Barotrauma
{
textColor = ChatMessage.MessageColor[(int)ChatMessageType.Private];
}
else if (GameMain.ActiveChatMode == ChatMode.Radio)
{
textColor = ChatMessage.MessageColor[(int)ChatMessageType.Radio];
}
else
{
textColor = ChatMessage.MessageColor[(int)ChatMessageType.Default];
@@ -550,6 +600,25 @@ namespace Barotrauma
showNewMessagesButton.Visible = false;
}
if (PlayerInput.KeyHit(InputType.ToggleChatMode) && GUI.KeyboardDispatcher.Subscriber == null && Screen.Selected == GameMain.GameScreen)
{
try
{
var mode = GameMain.ActiveChatMode switch
{
ChatMode.Local => ChatMode.Radio,
ChatMode.Radio => ChatMode.Local,
_ => throw new NotImplementedException()
};
ChatModeDropDown.SelectItem(mode);
// TODO: Play a sound?
}
catch (NotImplementedException)
{
DebugConsole.ThrowError($"Error toggling chat mode: not implemented for current mode \"{GameMain.ActiveChatMode}\"");
}
}
if (ToggleButton != null)
{
ToggleButton.Selected = ToggleOpen;
@@ -700,5 +769,70 @@ namespace Barotrauma
}
}
}
public void ApplySelectionInputs() => ApplySelectionInputs(InputBox, true, ChatKeyStates.GetChatKeyStates());
public struct ChatKeyStates
{
public bool ActiveChatKeyHit { get; set; }
public bool LocalChatKeyHit { get; set; }
public bool RadioChatKeyHit { get; set; }
public bool AnyHit => ActiveChatKeyHit || LocalChatKeyHit || RadioChatKeyHit;
private ChatKeyStates(bool active, bool local, bool radio)
{
ActiveChatKeyHit = active;
LocalChatKeyHit = local;
RadioChatKeyHit = radio;
}
public static ChatKeyStates GetChatKeyStates()
{
return new ChatKeyStates(PlayerInput.KeyHit(InputType.ActiveChat),
PlayerInput.KeyHit(InputType.Chat),
PlayerInput.KeyHit(InputType.RadioChat) && (Character.Controlled == null || Character.Controlled.SpeechImpediment < 100));
}
public (bool active, bool local, bool radio) Deconstruct()
{
return (ActiveChatKeyHit, LocalChatKeyHit, RadioChatKeyHit);
}
}
public void ApplySelectionInputs(GUITextBox inputBox, bool selectInputBox, ChatKeyStates chatKeyStates)
{
inputBox ??= InputBox;
var (activeChatKeyHit, localChatKeyHit, radioChatKeyHit) = chatKeyStates.Deconstruct();
if (localChatKeyHit || (activeChatKeyHit && GameMain.ActiveChatMode == ChatMode.Local))
{
ChatModeDropDown.SelectItem(ChatMode.Local);
inputBox.AddToGUIUpdateList();
GUIFrame.Flash(Color.DarkGreen, 0.5f);
if (!ToggleOpen)
{
CloseAfterMessageSent = !ToggleOpen;
ToggleOpen = true;
}
if (selectInputBox)
{
inputBox.Select(inputBox.Text.Length);
}
}
else if (radioChatKeyHit || (activeChatKeyHit && GameMain.ActiveChatMode == ChatMode.Radio))
{
ChatModeDropDown.SelectItem(ChatMode.Radio);
inputBox.AddToGUIUpdateList();
GUIFrame.Flash(Color.YellowGreen, 0.5f);
if (!ToggleOpen)
{
CloseAfterMessageSent = !ToggleOpen;
ToggleOpen = true;
}
if (selectInputBox)
{
inputBox.Select(inputBox.Text.Length);
}
}
}
}
}

View File

@@ -183,6 +183,10 @@ namespace Barotrauma
Width = null;
Height = null;
GetSize(Element);
foreach (var childStyle in ChildStyles.Values)
{
childStyle.RefreshSize();
}
}
private void GetSize(XElement element)

View File

@@ -356,7 +356,7 @@ namespace Barotrauma
GUIStyle.Green, Color.Black * 0.8f, font: GUIStyle.SmallFont);
y += yStep;
GameMain.PerformanceCounter.DrawTimeGraph.Draw(spriteBatch, new Rectangle((int)x, (int)y, 170, 50), color: GUIStyle.Green);
y += yStep * 3;
y += yStep * 4;
DrawString(spriteBatch, new Vector2(x, y),
"Update - Avg: " + GameMain.PerformanceCounter.UpdateTimeGraph.Average().ToString("0.00") + " ms" +
@@ -364,39 +364,33 @@ namespace Barotrauma
Color.LightBlue, Color.Black * 0.8f, font: GUIStyle.SmallFont);
y += yStep;
GameMain.PerformanceCounter.UpdateTimeGraph.Draw(spriteBatch, new Rectangle((int)x, (int)y, 170, 50), color: Color.LightBlue);
y += yStep * 3;
foreach (string key in GameMain.PerformanceCounter.GetSavedIdentifiers)
y += yStep * 4;
foreach (string key in GameMain.PerformanceCounter.GetSavedIdentifiers.OrderBy(i => i))
{
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 += yStep;
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 += yStep;
}
}
int categoryDepth = key.Count(c => c == ':');
//color the more fine-grained counters red more easily (ok for the whole Update to take a longer time than specific part of the update)
float runningSlowThreshold = 10.0f / categoryDepth;
DrawString(spriteBatch, new Vector2(x + categoryDepth * 15, y),
key.Split(':').Last() + ": " + elapsedMillisecs.ToString("0.00"),
ToolBox.GradientLerp(elapsedMillisecs / runningSlowThreshold, Color.LightGreen, GUIStyle.Yellow, GUIStyle.Orange, GUIStyle.Red, Color.Magenta), Color.Black * 0.5f, 0, GUIStyle.SmallFont);
y += yStep;
}
if (Powered.Grids != null)
{
DrawString(spriteBatch, new Vector2(x, y), "Grids: " + Powered.Grids.Count, Color.LightGreen, Color.Black * 0.5f, 0, GUIStyle.SmallFont);
y += yStep;
}
if (Settings.EnableDiagnostics)
{
x += yStep * 2;
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 + yStep), "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 + yStep * 2), "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 + yStep * 3), "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 + yStep * 4), "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 + yStep * 5), "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), "ContinuousPhysicsTime: " + GameMain.World.ContinuousPhysicsTime.TotalMilliseconds.ToString("0.00"), 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 + yStep), "ControllersUpdateTime: " + GameMain.World.ControllersUpdateTime.TotalMilliseconds.ToString("0.00"), 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 + yStep * 2), "AddRemoveTime: " + GameMain.World.AddRemoveTime.TotalMilliseconds.ToString("0.00"), 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 + yStep * 3), "NewContactsTime: " + GameMain.World.NewContactsTime.TotalMilliseconds.ToString("0.00"), 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 + yStep * 4), "ContactsUpdateTime: " + GameMain.World.ContactsUpdateTime.TotalMilliseconds.ToString("0.00"), 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 + yStep * 5), "SolveUpdateTime: " + GameMain.World.SolveUpdateTime.TotalMilliseconds.ToString("0.00"), Color.Lerp(Color.LightGreen, GUIStyle.Red, (float)GameMain.World.SolveUpdateTime.TotalMilliseconds / 10.0f), Color.Black * 0.5f, 0, GUIStyle.SmallFont);
}
}

View File

@@ -111,6 +111,11 @@ namespace Barotrauma
set { textBlock.SelectedTextColor = value; }
}
public Color DisabledTextColor
{
get { return textBlock.DisabledTextColor; }
}
public override float FlashTimer
{
get { return Frame.FlashTimer; }

View File

@@ -160,6 +160,10 @@ namespace Barotrauma
listBox.ToolTip = value;
}
}
public GUIImage DropDownIcon => icon;
public Vector4 Padding => button.TextBlock.Padding;
public GUIDropDown(RectTransform rectT, LocalizedString text = null, int elementCount = 4, string style = "", bool selectMultiple = false, bool dropAbove = false, Alignment textAlignment = Alignment.CenterLeft) : base(style, rectT)
{

View File

@@ -352,7 +352,7 @@ namespace Barotrauma
caretPosDirty = false;
}
public void Select(int forcedCaretIndex = -1)
public void Select(int forcedCaretIndex = -1, bool ignoreSelectSound = false)
{
skipUpdate = true;
if (memento.Current == null)
@@ -362,10 +362,11 @@ namespace Barotrauma
CaretIndex = forcedCaretIndex == - 1 ? textBlock.GetCaretIndexFromScreenPos(PlayerInput.MousePosition) : forcedCaretIndex;
CalculateCaretPos();
ClearSelection();
bool wasSelected = selected;
selected = true;
GUI.KeyboardDispatcher.Subscriber = this;
OnSelected?.Invoke(this, Keys.None);
if (PlaySoundOnSelect)
if (!wasSelected && PlaySoundOnSelect && !ignoreSelectSound)
{
SoundPlayer.PlayUISound(GUISoundType.Select);
}

View File

@@ -1,6 +1,7 @@
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System;
using System.Linq;
namespace Barotrauma
{
@@ -122,7 +123,17 @@ namespace Barotrauma
//horizontal slices at the corners of the screen for health bar and affliction icons
int afflictionAreaHeight = (int)(50 * GUI.Scale);
int healthBarWidth = (int)(BottomRightInfoArea.Width * 1.3f);
int healthBarWidth = BottomRightInfoArea.Width;
var healthBarChildStyles = GUIStyle.GetComponentStyle("CharacterHealthBar")?.ChildStyles;
if (healthBarChildStyles!= null && healthBarChildStyles.TryGetValue("GUIFrame".ToIdentifier(), out var style))
{
if (style.Sprites.TryGetValue(GUIComponent.ComponentState.None, out var uiSprites) && uiSprites.FirstOrDefault() is { } uiSprite)
{
// The default health bar uses a sliced sprite so let's make sure the health bar area is calculated accordingly
healthBarWidth += (int)(uiSprite.NonSliceSize.X * Math.Min(GUI.Scale, 1f));
}
}
int healthBarHeight = (int)(50f * GUI.Scale);
HealthBarArea = new Rectangle(BottomRightInfoArea.Right - healthBarWidth + (int)Math.Floor(1 / GUI.Scale), BottomRightInfoArea.Y - healthBarHeight + GUI.IntScale(10), healthBarWidth, healthBarHeight);
AfflictionAreaLeft = new Rectangle(HealthBarArea.X, HealthBarArea.Y - Padding - afflictionAreaHeight, HealthBarArea.Width, afflictionAreaHeight);

View File

@@ -2208,7 +2208,7 @@ namespace Barotrauma
}
updateStopwatch.Stop();
GameMain.PerformanceCounter.AddPartialElapsedTicks("GameSessionUpdate", "StoreUpdate", updateStopwatch.ElapsedTicks);
GameMain.PerformanceCounter.AddElapsedTicks("Update:GameSession:Store", updateStopwatch.ElapsedTicks);
}
}
}

View File

@@ -1858,14 +1858,18 @@ namespace Barotrauma
});
GUILayoutGroup nameLayout = new GUILayoutGroup(new RectTransform(new Vector2(0.3f, 1f), talentInfoLayoutGroup.RectTransform)) { RelativeSpacing = 0.05f };
Vector2 nameSize = GUIStyle.SubHeadingFont.MeasureString(info.Name);
GUITextBlock nameBlock = new GUITextBlock(new RectTransform(Vector2.One, nameLayout.RectTransform), info.Name, font: GUIStyle.SubHeadingFont) { TextColor = job.Prefab.UIColor };
GUITextBlock nameBlock = new GUITextBlock(new RectTransform(Vector2.One, nameLayout.RectTransform), info.Name, font: GUIStyle.SubHeadingFont);
nameBlock.RectTransform.NonScaledSize = nameSize.Pad(nameBlock.Padding).ToPoint();
Vector2 jobSize = GUIStyle.SmallFont.MeasureString(job.Name);
GUITextBlock jobBlock = new GUITextBlock(new RectTransform(Vector2.One, nameLayout.RectTransform), job.Name, font: GUIStyle.SmallFont) { TextColor = job.Prefab.UIColor };
jobBlock.RectTransform.NonScaledSize = jobSize.Pad(jobBlock.Padding).ToPoint();
if (!info.OmitJobInMenus)
{
nameBlock.TextColor = job.Prefab.UIColor;
Vector2 jobSize = GUIStyle.SmallFont.MeasureString(job.Name);
GUITextBlock jobBlock = new GUITextBlock(new RectTransform(Vector2.One, nameLayout.RectTransform), job.Name, font: GUIStyle.SmallFont) { TextColor = job.Prefab.UIColor };
jobBlock.RectTransform.NonScaledSize = jobSize.Pad(jobBlock.Padding).ToPoint();
}
LocalizedString traitString = TextManager.AddPunctuation(':', TextManager.Get("PersonalityTrait"), TextManager.Get("personalitytrait." + info.PersonalityTrait.Name.Replace(" ", "")));
Vector2 traitSize = GUIStyle.SmallFont.MeasureString(traitString);
@@ -1876,7 +1880,8 @@ namespace Barotrauma
if (!(GameMain.NetworkMember is null))
{
GUIButton newCharacterBox = new GUIButton(new RectTransform(new Vector2(0.675f, 1f), talentsOutsideTreeFrame.RectTransform, Anchor.TopLeft), text: GameMain.NetLobbyScreen.CampaignCharacterDiscarded ? TextManager.Get("settings") : TextManager.Get("createnew"))
GUIButton newCharacterBox = new GUIButton(new RectTransform(new Vector2(0.675f, 1f), talentsOutsideTreeFrame.RectTransform, Anchor.TopLeft),
text: GameMain.NetLobbyScreen.CampaignCharacterDiscarded ? TextManager.Get("settings") : TextManager.Get("createnew"))
{
IgnoreLayoutGroups = true
};
@@ -1915,7 +1920,7 @@ namespace Barotrauma
{
OnClicked = (button, o) =>
{
GameMain.Client?.SendCharacterInfo();
GameMain.Client?.SendCharacterInfo(GameMain.Client.PendingName);
characterSettingsFrame!.Visible = false;
talentFrameMain.Visible = true;
return true;

View File

@@ -27,6 +27,11 @@ namespace Barotrauma
set;
}
/// <summary>
/// The size of fixed area around the slice area
/// </summary>
public Point NonSliceSize { get; set; }
public bool MaintainAspectRatio
{
get;
@@ -72,6 +77,7 @@ namespace Barotrauma
maxBorderScale = element.GetAttributeFloat("minborderscale", 10.0f);
Rectangle slice = new Rectangle((int)sliceVec.X, (int)sliceVec.Y, (int)(sliceVec.Z - sliceVec.X), (int)(sliceVec.W - sliceVec.Y));
NonSliceSize = new Point(Sprite.SourceRect.Width - slice.Width, Sprite.SourceRect.Height - slice.Height);
Slices = new Rectangle[9];

View File

@@ -202,6 +202,8 @@ namespace Barotrauma
public static bool CancelQuickStart;
#endif
public static ChatMode ActiveChatMode { get; set; } = ChatMode.Radio;
public GameMain(string[] args)
{
Content.RootDirectory = "Content";
@@ -924,7 +926,7 @@ namespace Barotrauma
updateCount++;
sw.Stop();
PerformanceCounter.AddElapsedTicks("Update total", sw.ElapsedTicks);
PerformanceCounter.AddElapsedTicks("Update", sw.ElapsedTicks);
PerformanceCounter.UpdateTimeGraph.Update(sw.ElapsedTicks * 1000.0f / (float)Stopwatch.Frequency);
}
@@ -1026,7 +1028,7 @@ namespace Barotrauma
}
sw.Stop();
PerformanceCounter.AddElapsedTicks("Draw total", sw.ElapsedTicks);
PerformanceCounter.AddElapsedTicks("Draw", sw.ElapsedTicks);
PerformanceCounter.DrawTimeGraph.Update(sw.ElapsedTicks * 1000.0f / (float)Stopwatch.Frequency);
}

View File

@@ -147,9 +147,10 @@ namespace Barotrauma
string msgCommand = ChatMessage.GetChatMessageCommand(text, out string msg);
// add to local history
ChatBox.ChatManager.Store(text);
WifiComponent headset = null;
ChatMessageType messageType =
((msgCommand == "r" || msgCommand == "radio") && ChatMessage.CanUseRadio(Character.Controlled, out headset)) ? ChatMessageType.Radio : ChatMessageType.Default;
bool isUsingRadioMode = GameMain.ActiveChatMode == ChatMode.Radio;
bool containsRadioCommand = msgCommand == "r" || msgCommand == "radio";
bool canUseRadio = ChatMessage.CanUseRadio(Character.Controlled, out WifiComponent headset);
ChatMessageType messageType = ((isUsingRadioMode && msgCommand == "") || containsRadioCommand) && canUseRadio ? ChatMessageType.Radio : ChatMessageType.Default;
AddSinglePlayerChatMessage(
Character.Controlled.Info.Name,
msg, messageType,
@@ -1553,40 +1554,9 @@ namespace Barotrauma
{
ChatBox.Update(deltaTime);
ChatBox.InputBox.Visible = Character.Controlled != null;
if (!DebugConsole.IsOpen && ChatBox.InputBox.Visible && GUI.KeyboardDispatcher.Subscriber == null)
if (!DebugConsole.IsOpen && ChatBox.InputBox.Visible && GUI.KeyboardDispatcher.Subscriber == null && !ChatBox.InputBox.Selected)
{
if (PlayerInput.KeyHit(InputType.Chat) && !ChatBox.InputBox.Selected)
{
ChatBox.InputBox.AddToGUIUpdateList();
ChatBox.GUIFrame.Flash(Color.DarkGreen, 0.5f);
if (!ChatBox.ToggleOpen)
{
ChatBox.CloseAfterMessageSent = !ChatBox.ToggleOpen;
ChatBox.ToggleOpen = true;
}
ChatBox.InputBox.Select(ChatBox.InputBox.Text.Length);
}
if (PlayerInput.KeyHit(InputType.RadioChat) && !ChatBox.InputBox.Selected)
{
if (Character.Controlled == null || Character.Controlled.SpeechImpediment < 100)
{
ChatBox.InputBox.AddToGUIUpdateList();
ChatBox.GUIFrame.Flash(Color.YellowGreen, 0.5f);
if (!ChatBox.ToggleOpen)
{
ChatBox.CloseAfterMessageSent = !ChatBox.ToggleOpen;
ChatBox.ToggleOpen = true;
}
if (!ChatBox.InputBox.Text.StartsWith(ChatBox.RadioChatString))
{
ChatBox.InputBox.Text = ChatBox.RadioChatString;
}
ChatBox.InputBox.Select(ChatBox.InputBox.Text.Length);
}
}
ChatBox.ApplySelectionInputs();
}
}

View File

@@ -35,11 +35,7 @@ namespace Barotrauma
}
}
if (CrewManager.ChatBox != null)
{
CrewManager.ChatBox.Update(deltaTime);
}
CrewManager.ChatBox?.Update(deltaTime);
CrewManager.UpdateReports();
}

View File

@@ -43,6 +43,31 @@ namespace Barotrauma.Items.Components
corners[2] = center + new Vector2(shadowSize.X, shadowSize.Y) / 2;
corners[3] = center + new Vector2(shadowSize.X, -shadowSize.Y) / 2;
if (IsHorizontal)
{
if (item.FlippedX)
{
Vector2 itemCenter = new Vector2(item.Rect.Center.X, item.Rect.Y - item.Rect.Height / 2);
for (int i = 0; i < corners.Length; i++)
{
corners[i].X = itemCenter.X * 2 - corners[i].X;
}
Array.Reverse(corners);
}
}
else
{
if (item.FlippedY)
{
Vector2 itemCenter = new Vector2(item.Rect.Center.X, item.Rect.Y - item.Rect.Height / 2);
for (int i = 0; i < corners.Length; i++)
{
corners[i].Y = itemCenter.Y * 2 - corners[i].Y;
}
Array.Reverse(corners);
}
}
return corners;
}
@@ -163,69 +188,67 @@ namespace Barotrauma.Items.Components
if (stuck > 0.0f && weldedSprite != null)
{
Vector2 weldSpritePos = new Vector2(item.Rect.Center.X, item.Rect.Y - item.Rect.Height / 2.0f) + shakePos;
if (item.Submarine != null) weldSpritePos += item.Submarine.DrawPosition;
if (item.Submarine != null) { weldSpritePos += item.Submarine.DrawPosition; }
weldSpritePos.Y = -weldSpritePos.Y;
weldedSprite.Draw(spriteBatch,
weldSpritePos, item.SpriteColor * (stuck / 100.0f), scale: item.Scale);
}
if (openState >= 1.0f)
{
return;
}
if (openState >= 1.0f) { return; }
Vector2 pos;
if (IsHorizontal)
{
Vector2 pos = new Vector2(item.Rect.X, item.Rect.Y - item.Rect.Height / 2) + shakePos;
if (item.Submarine != null) pos += item.Submarine.DrawPosition;
pos.Y = -pos.Y;
if (brokenSprite == null || !IsBroken)
{
spriteBatch.Draw(doorSprite.Texture, pos,
new Rectangle((int) (doorSprite.SourceRect.X + doorSprite.size.X * openState),
(int) doorSprite.SourceRect.Y,
(int) (doorSprite.size.X * (1.0f - openState)), (int) doorSprite.size.Y),
color, 0.0f, doorSprite.Origin, item.Scale, SpriteEffects.None, doorSprite.Depth);
}
if (brokenSprite != null && item.Health < item.MaxCondition)
{
Vector2 scale = scaleBrokenSprite ? new Vector2(1.0f, 1.0f - item.Health / item.MaxCondition) : Vector2.One;
float alpha = fadeBrokenSprite ? 1.0f - item.Health / item.MaxCondition : 1.0f;
spriteBatch.Draw(brokenSprite.Texture, pos,
new Rectangle((int)(brokenSprite.SourceRect.X + brokenSprite.size.X * openState), brokenSprite.SourceRect.Y,
(int)(brokenSprite.size.X * (1.0f - openState)), (int)brokenSprite.size.Y),
color * alpha, 0.0f, brokenSprite.Origin, scale * item.Scale, SpriteEffects.None,
brokenSprite.Depth);
}
pos = new Vector2(item.Rect.X, item.Rect.Y - item.Rect.Height / 2);
if (item.FlippedX) { pos.X += (int)(doorSprite.size.X * item.Scale * openState); }
}
else
{
Vector2 pos = new Vector2(item.Rect.Center.X, item.Rect.Y) + shakePos;
if (item.Submarine != null) pos += item.Submarine.DrawPosition;
pos.Y = -pos.Y;
if (brokenSprite == null || !IsBroken)
{
spriteBatch.Draw(doorSprite.Texture, pos,
new Rectangle(doorSprite.SourceRect.X,
(int) (doorSprite.SourceRect.Y + doorSprite.size.Y * openState),
(int) doorSprite.size.X, (int) (doorSprite.size.Y * (1.0f - openState))),
color, 0.0f, doorSprite.Origin, item.Scale, SpriteEffects.None, doorSprite.Depth);
}
if (brokenSprite != null && item.Health < item.MaxCondition)
{
Vector2 scale = scaleBrokenSprite ? new Vector2(1.0f - item.Health / item.MaxCondition, 1.0f) : Vector2.One;
float alpha = fadeBrokenSprite ? 1.0f - item.Health / item.MaxCondition : 1.0f;
spriteBatch.Draw(brokenSprite.Texture, pos,
new Rectangle(brokenSprite.SourceRect.X, (int)(brokenSprite.SourceRect.Y + brokenSprite.size.Y * openState),
(int)brokenSprite.size.X, (int)(brokenSprite.size.Y * (1.0f - openState))),
color * alpha, 0.0f, brokenSprite.Origin, scale * item.Scale, SpriteEffects.None, brokenSprite.Depth);
}
pos = new Vector2(item.Rect.Center.X, item.Rect.Y);
if (item.FlippedY) { pos.Y -= (int)(doorSprite.size.Y * item.Scale * openState); }
}
pos += shakePos;
if (item.Submarine != null) { pos += item.Submarine.DrawPosition; }
pos.Y = -pos.Y;
if (brokenSprite == null || !IsBroken)
{
spriteBatch.Draw(doorSprite.Texture, pos,
getSourceRect(doorSprite, openState, IsHorizontal),
color, 0.0f, doorSprite.Origin, item.Scale, item.SpriteEffects, doorSprite.Depth);
}
if (brokenSprite != null && item.Health < item.MaxCondition)
{
Vector2 scale = scaleBrokenSprite ? new Vector2(1.0f, 1.0f - item.Health / item.MaxCondition) : Vector2.One;
float alpha = fadeBrokenSprite ? 1.0f - item.Health / item.MaxCondition : 1.0f;
spriteBatch.Draw(brokenSprite.Texture, pos,
getSourceRect(brokenSprite, openState, IsHorizontal),
color * alpha, 0.0f, brokenSprite.Origin, scale * item.Scale, item.SpriteEffects,
brokenSprite.Depth);
}
static Rectangle getSourceRect(Sprite sprite, float openState, bool horizontal)
{
if (horizontal)
{
return new Rectangle(
(int)(sprite.SourceRect.X + sprite.size.X * openState),
sprite.SourceRect.Y,
(int)(sprite.size.X * (1.0f - openState)),
(int)sprite.size.Y);
}
else
{
return new Rectangle(
sprite.SourceRect.X,
(int)(sprite.SourceRect.Y + sprite.size.Y * openState),
(int)sprite.size.X,
(int)(sprite.size.Y * (1.0f - openState)));
}
}
}
partial void OnFailedToOpen()

View File

@@ -116,12 +116,6 @@ namespace Barotrauma.Items.Components
loadAttachments(Attachments, disguisedBeardElement, WearableType.Beard);
loadAttachments(Attachments, disguisedMoustacheElement, WearableType.Moustache);
loadAttachments(Attachments, disguisedHairElement, WearableType.Hair);
loadAttachments(Attachments,
characterInfo.OmitJobInPortraitClothing
? JobPrefab.NoJobElement?.GetChildElement("PortraitClothing")
: JobPrefab?.ClothingElement,
WearableType.JobIndicator);
}
HairColor = hairColor;

View File

@@ -1,55 +1,61 @@
using Barotrauma.Networking;
using Barotrauma.RuinGeneration;
using Barotrauma.Sounds;
using Barotrauma.Items.Components;
using Barotrauma.Networking;
using FarseerPhysics;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Immutable;
using Barotrauma.IO;
using System.Linq;
using System.Xml.Linq;
using Barotrauma.Items.Components;
namespace Barotrauma
{
partial class Submarine : Entity, IServerPositionSync
{
public static Vector2 MouseToWorldGrid(Camera cam, Submarine sub)
{
Vector2 position = PlayerInput.MousePosition;
position = cam.ScreenToWorld(position);
Vector2 worldGridPos = VectorToWorldGrid(position);
if (sub != null)
{
worldGridPos.X += sub.Position.X % GridSize.X;
worldGridPos.Y += sub.Position.Y % GridSize.Y;
}
return worldGridPos;
}
//drawing ----------------------------------------------------
private static readonly HashSet<Submarine> visibleSubs = new HashSet<Submarine>();
private static double prevCullTime;
private static Rectangle prevCullArea;
/// <summary>
/// Interval at which we force culled entites to be updated, regardless if the camera has moved
/// </summary>
private const float CullInterval = 0.25f;
/// <summary>
/// Margin applied around the view area when culling entities (i.e. entities that are this far outside the view are still considered visible)
/// </summary>
private const int CullMargin = 500;
/// <summary>
/// Update entity culling when any corner of the view has moved more than this
/// </summary>
private const int CullMoveThreshold = 50;
public static void CullEntities(Camera cam)
{
Rectangle camView = cam.WorldView;
camView = new Rectangle(camView.X - CullMargin, camView.Y + CullMargin, camView.Width + CullMargin * 2, camView.Height + CullMargin * 2);
if (Math.Abs(camView.X - prevCullArea.X) < CullMoveThreshold &&
Math.Abs(camView.Y - prevCullArea.Y) < CullMoveThreshold &&
Math.Abs(camView.Right - prevCullArea.Right) < CullMoveThreshold &&
Math.Abs(camView.Bottom - prevCullArea.Bottom) < CullMoveThreshold &&
prevCullTime > Timing.TotalTime - CullInterval)
{
return;
}
visibleSubs.Clear();
foreach (Submarine sub in Loaded)
{
if (Level.Loaded != null && sub.WorldPosition.Y < Level.MaxEntityDepth) { continue; }
int margin = 500;
Rectangle worldBorders = new Rectangle(
sub.VisibleBorders.X + (int)sub.WorldPosition.X - margin,
sub.VisibleBorders.Y + (int)sub.WorldPosition.Y + margin,
sub.VisibleBorders.Width + margin * 2,
sub.VisibleBorders.Height + margin * 2);
sub.VisibleBorders.X + (int)sub.WorldPosition.X,
sub.VisibleBorders.Y + (int)sub.WorldPosition.Y,
sub.VisibleBorders.Width,
sub.VisibleBorders.Height);
if (RectsOverlap(worldBorders, cam.WorldView))
if (RectsOverlap(worldBorders, camView))
{
visibleSubs.Add(sub);
}
@@ -64,16 +70,22 @@ namespace Barotrauma
visibleEntities.Clear();
}
Rectangle worldView = cam.WorldView;
foreach (MapEntity entity in MapEntity.mapEntityList)
{
if (entity.Submarine != null)
{
if (!visibleSubs.Contains(entity.Submarine)) { continue; }
}
if (entity.IsVisible(worldView)) { visibleEntities.Add(entity); }
if (entity.IsVisible(camView)) { visibleEntities.Add(entity); }
}
prevCullArea = camView;
prevCullTime = Timing.TotalTime;
}
public static void ForceVisibilityRecheck()
{
prevCullTime = 0;
}
public static void Draw(SpriteBatch spriteBatch, bool editing = false)
@@ -148,7 +160,7 @@ namespace Barotrauma
{
if (predicate != null)
{
if (!predicate(e)) continue;
if (!predicate(e)) { continue; }
}
float drawDepth = structure.GetDrawDepth();
int i = 0;
@@ -679,6 +691,22 @@ namespace Barotrauma
return GameMain.LightManager.Lights.Count(l => l.CastShadows && !l.IsBackground) - disabledItemLightCount;
}
public static Vector2 MouseToWorldGrid(Camera cam, Submarine sub)
{
Vector2 position = PlayerInput.MousePosition;
position = cam.ScreenToWorld(position);
Vector2 worldGridPos = VectorToWorldGrid(position);
if (sub != null)
{
worldGridPos.X += sub.Position.X % GridSize.X;
worldGridPos.Y += sub.Position.Y % GridSize.Y;
}
return worldGridPos;
}
public void ClientReadPosition(IReadMessage msg, float sendingTime)
{
var posInfo = PhysicsBody.ClientRead(msg, sendingTime, parentDebugName: Info.Name);

View File

@@ -10,14 +10,15 @@ namespace Barotrauma.Networking
{
msg.Write((byte)ClientNetObject.CHAT_MESSAGE);
msg.Write(NetStateID);
msg.Write((byte)Type);
msg.WriteRangedInteger((int)Type, 0, Enum.GetValues(typeof(ChatMessageType)).Length - 1);
msg.WriteRangedInteger((int)ChatMode, 0, Enum.GetValues(typeof(ChatMode)).Length - 1);
msg.Write(Text);
}
public static void ClientRead(IReadMessage msg)
{
UInt16 id = msg.ReadUInt16();
ChatMessageType type = (ChatMessageType)msg.ReadByte();
ChatMessageType type = (ChatMessageType)msg.ReadRangedInteger(0, Enum.GetValues(typeof(ChatMessageType)).Length - 1);
PlayerConnectionChangeType changeType = PlayerConnectionChangeType.None;
string txt = "";
string styleSetting = string.Empty;

View File

@@ -1831,7 +1831,8 @@ namespace Barotrauma.Networking
GameMain.GameScreen.Select();
AddChatMessage($"ServerMessage.HowToCommunicate~[chatbutton]={GameSettings.CurrentConfig.KeyMap.KeyBindText(InputType.Chat)}~[radiobutton]={GameSettings.CurrentConfig.KeyMap.KeyBindText(InputType.RadioChat)}", ChatMessageType.Server);
// TODO: Re-enable the server message once it's been edited and translated
//AddChatMessage($"ServerMessage.HowToCommunicate~[chatbutton]={GameSettings.CurrentConfig.KeyMap.KeyBindText(InputType.Chat)}~[radiobutton]={GameSettings.CurrentConfig.KeyMap.KeyBindText(InputType.RadioChat)}", ChatMessageType.Server);
yield return CoroutineStatus.Success;
}
@@ -2503,6 +2504,7 @@ namespace Barotrauma.Networking
message,
type,
gameStarted && myCharacter != null ? myCharacter : null);
chatMessage.ChatMode = GameMain.ActiveChatMode;
lastQueueChatMsgID++;
chatMessage.NetStateID = lastQueueChatMsgID;
@@ -2788,19 +2790,21 @@ namespace Barotrauma.Networking
GameMain.GameSession = null;
}
public void SendCharacterInfo()
public void SendCharacterInfo(string newName = null)
{
IWriteMessage msg = new WriteOnlyMessage();
msg.Write((byte)ClientPacketHeader.UPDATE_CHARACTERINFO);
WriteCharacterInfo(msg);
WriteCharacterInfo(msg, newName);
msg.Write((byte)ServerNetObject.END_OF_MESSAGE);
clientPeer?.Send(msg, DeliveryMethod.Reliable);
}
public void WriteCharacterInfo(IWriteMessage msg)
public void WriteCharacterInfo(IWriteMessage msg, string newName = null)
{
msg.Write(characterInfo == null);
if (characterInfo == null) return;
if (characterInfo == null) { return; }
msg.Write(newName ?? string.Empty);
msg.Write((byte)characterInfo.Head.Preset.TagSet.Count);
foreach (Identifier tag in characterInfo.Head.Preset.TagSet)
@@ -3284,10 +3288,8 @@ namespace Barotrauma.Networking
{
if (GUI.KeyboardDispatcher.Subscriber == null)
{
bool chatKeyHit = PlayerInput.KeyHit(InputType.Chat);
bool radioKeyHit = PlayerInput.KeyHit(InputType.RadioChat) && (Character.Controlled == null || Character.Controlled.SpeechImpediment < 100);
if (chatKeyHit || radioKeyHit)
var chatKeyStates = ChatBox.ChatKeyStates.GetChatKeyStates();
if (chatKeyStates.AnyHit)
{
if (msgBox.Selected)
{
@@ -3298,34 +3300,8 @@ namespace Barotrauma.Networking
{
if (Screen.Selected == GameMain.GameScreen)
{
if (chatKeyHit)
{
msgBox.AddToGUIUpdateList();
ChatBox.GUIFrame.Flash(Color.DarkGreen, 0.5f);
if (!chatBox.ToggleOpen)
{
ChatBox.CloseAfterMessageSent = !ChatBox.ToggleOpen;
ChatBox.ToggleOpen = true;
}
}
if (radioKeyHit)
{
msgBox.AddToGUIUpdateList();
ChatBox.GUIFrame.Flash(Color.YellowGreen, 0.5f);
if (!chatBox.ToggleOpen)
{
ChatBox.CloseAfterMessageSent = !ChatBox.ToggleOpen;
ChatBox.ToggleOpen = true;
}
if (!msgBox.Text.StartsWith(ChatBox.RadioChatString))
{
msgBox.Text = ChatBox.RadioChatString;
}
}
ChatBox.ApplySelectionInputs(msgBox, false, chatKeyStates);
}
msgBox.Select(msgBox.Text.Length);
}
}

View File

@@ -1,4 +1,6 @@
namespace Barotrauma.Networking
using System;
namespace Barotrauma.Networking
{
partial class OrderChatMessage : ChatMessage
{
@@ -6,7 +8,7 @@
{
msg.Write((byte)ClientNetObject.CHAT_MESSAGE);
msg.Write(NetStateID);
msg.Write((byte)ChatMessageType.Order);
msg.WriteRangedInteger((int)ChatMessageType.Order, 0, Enum.GetValues(typeof(ChatMessageType)).Length - 1);
WriteOrder(msg);
}
}

View File

@@ -227,20 +227,10 @@ namespace Barotrauma.Networking
bool allowEnqueue = overrideSound != null;
if (GameMain.WindowActive && SettingsMenu.Instance is null)
{
ForceLocal = captureTimer > 0 ? ForceLocal : GameSettings.CurrentConfig.Audio.UseLocalVoiceByDefault;
bool pttDown = false;
if ((PlayerInput.KeyDown(InputType.Voice) || PlayerInput.KeyDown(InputType.LocalVoice)) &&
GUI.KeyboardDispatcher.Subscriber == null)
bool pttDown = PlayerInput.KeyDown(InputType.Voice) && GUI.KeyboardDispatcher.Subscriber == null;
if (pttDown || captureTimer <= 0)
{
pttDown = true;
if (PlayerInput.KeyDown(InputType.LocalVoice))
{
ForceLocal = true;
}
else
{
ForceLocal = false;
}
ForceLocal = GameMain.ActiveChatMode == ChatMode.Local;
}
if (GameSettings.CurrentConfig.Audio.VoiceSetting == VoiceMode.Activity)
{
@@ -257,7 +247,6 @@ namespace Barotrauma.Networking
}
}
}
if (allowEnqueue || captureTimer > 0)
{
LastEnqueueAudio = DateTime.Now;

View File

@@ -205,7 +205,10 @@ namespace Barotrauma
SettingCarouselElement<GameDifficulty> prevDifficulty = difficultyOptions.FirstOrNull(element => element.Value == prevSettings.Difficulty) ?? difficultyOptions[1];
SettingValue<GameDifficulty> difficultyInput = CreateSelectionCarousel(settingsList.Content, TextManager.Get("leveldifficulty"), TextManager.Get("leveldifficultyexplanation"), prevDifficulty, verticalSize, difficultyOptions);
SettingValue<int> maxMissionCountInput = CreateGUINumberInputCarousel(settingsList.Content, TextManager.Get("maxmissioncount"), TextManager.Get("maxmissioncounttooltip"), prevSettings.MaxMissionCount, valueStep: 1, verticalSize);
SettingValue<int> maxMissionCountInput = CreateGUINumberInputCarousel(settingsList.Content, TextManager.Get("maxmissioncount"), TextManager.Get("maxmissioncounttooltip"),
prevSettings.MaxMissionCount,
valueStep: 1, minValue: CampaignSettings.MinMissionCountLimit, maxValue: CampaignSettings.MaxMissionCountLimit,
verticalSize);
presetDropdown.OnSelected = (selected, o) =>
{
@@ -231,7 +234,7 @@ namespace Barotrauma
};
// Create a number input with plus and minus buttons because for some reason the default GUINumberInput buttons don't work when in a GUIMessageBox
static SettingValue<int> CreateGUINumberInputCarousel(GUIComponent parent, LocalizedString description, LocalizedString tooltip, int defaultValue, int valueStep, float verticalSize)
static SettingValue<int> CreateGUINumberInputCarousel(GUIComponent parent, LocalizedString description, LocalizedString tooltip, int defaultValue, int valueStep, int minValue, int maxValue, float verticalSize)
{
GUILayoutGroup inputContainer = CreateSettingBase(parent, description, tooltip, horizontalSize: 0.55f, verticalSize: verticalSize);
@@ -243,7 +246,9 @@ namespace Barotrauma
GUINumberInput numberInput = new GUINumberInput(new RectTransform(Vector2.One, inputContainer.RectTransform, Anchor.Center), NumberType.Int, textAlignment: Alignment.Center, style: "GUITextBox",
hidePlusMinusButtons: true)
{
IntValue = defaultValue
IntValue = defaultValue,
MinValueInt = minValue,
MaxValueInt = maxValue
};
inputContainer.RectTransform.Parent.MinSize = new Point(0, numberInput.RectTransform.MinSize.Y);
GUIButton plusButton = new GUIButton(new RectTransform(Vector2.One, inputContainer.RectTransform, scaleBasis: ScaleBasis.BothHeight), style: "GUIPlusButton", textAlignment: Alignment.Center)

View File

@@ -126,7 +126,7 @@ namespace Barotrauma
DrawMap(graphics, spriteBatch, deltaTime);
sw.Stop();
GameMain.PerformanceCounter.AddElapsedTicks("DrawMap", sw.ElapsedTicks);
GameMain.PerformanceCounter.AddElapsedTicks("Draw:Map", sw.ElapsedTicks);
sw.Restart();
spriteBatch.Begin(SpriteSortMode.Deferred, null, GUI.SamplerState, null, GameMain.ScissorTestEnable);
@@ -165,7 +165,7 @@ namespace Barotrauma
spriteBatch.End();
sw.Stop();
GameMain.PerformanceCounter.AddElapsedTicks("DrawHUD", sw.ElapsedTicks);
GameMain.PerformanceCounter.AddElapsedTicks("Draw:HUD", sw.ElapsedTicks);
sw.Restart();
}
@@ -178,6 +178,9 @@ namespace Barotrauma
GameMain.ParticleManager.UpdateTransforms();
Stopwatch sw = new Stopwatch();
sw.Start();
GameMain.LightManager.ObstructVision =
Character.Controlled != null &&
Character.Controlled.ObstructVision &&
@@ -185,6 +188,10 @@ namespace Barotrauma
GameMain.LightManager.UpdateObstructVision(graphics, spriteBatch, cam, Character.Controlled?.CursorWorldPosition ?? Vector2.Zero);
sw.Stop();
GameMain.PerformanceCounter.AddElapsedTicks("Draw:Map:LOS", sw.ElapsedTicks);
sw.Restart();
//------------------------------------------------------------------------
graphics.SetRenderTarget(renderTarget);
graphics.Clear(Color.Transparent);
@@ -196,9 +203,17 @@ namespace Barotrauma
Submarine.DrawPaintedColors(spriteBatch, false);
spriteBatch.End();
sw.Stop();
GameMain.PerformanceCounter.AddElapsedTicks("Draw:Map:BackStructures", sw.ElapsedTicks);
sw.Restart();
graphics.SetRenderTarget(null);
GameMain.LightManager.RenderLightMap(graphics, spriteBatch, cam, renderTarget);
sw.Stop();
GameMain.PerformanceCounter.AddElapsedTicks("Draw:Map:Lighting", sw.ElapsedTicks);
sw.Restart();
//------------------------------------------------------------------------
graphics.SetRenderTarget(renderTargetBackground);
if (Level.Loaded == null)
@@ -228,6 +243,10 @@ namespace Barotrauma
spriteBatch.Draw(renderTarget, new Rectangle(0, 0, GameMain.GraphicsWidth, GameMain.GraphicsHeight), Color.White);
spriteBatch.End();
sw.Stop();
GameMain.PerformanceCounter.AddElapsedTicks("Draw:Map:BackLevel", sw.ElapsedTicks);
sw.Restart();
//----------------------------------------------------------------------------
//Start drawing to the normal render target (stuff that can't be seen through the LOS effect)
@@ -248,6 +267,10 @@ namespace Barotrauma
}
spriteBatch.End();
sw.Stop();
GameMain.PerformanceCounter.AddElapsedTicks("Draw:Map:BackCharactersItems", sw.ElapsedTicks);
sw.Restart();
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, null, DepthStencilState.None, null, null, cam.Transform);
DrawDeformed(firstPass: true);
DrawDeformed(firstPass: false);
@@ -266,8 +289,16 @@ namespace Barotrauma
}
}
sw.Stop();
GameMain.PerformanceCounter.AddElapsedTicks("Draw:Map:DeformableCharacters", sw.ElapsedTicks);
sw.Restart();
Level.Loaded?.DrawFront(spriteBatch, cam);
sw.Stop();
GameMain.PerformanceCounter.AddElapsedTicks("Draw:Map:FrontLevel", sw.ElapsedTicks);
sw.Restart();
//draw the rendertarget and particles that are only supposed to be drawn in water into renderTargetWater
graphics.SetRenderTarget(renderTargetWater);
@@ -302,6 +333,10 @@ namespace Barotrauma
WaterRenderer.Instance.RenderAir(graphics, cam, renderTarget, Cam.ShaderTransform);
graphics.DepthStencilState = DepthStencilState.None;
sw.Stop();
GameMain.PerformanceCounter.AddElapsedTicks("Draw:Map:FrontParticles", sw.ElapsedTicks);
sw.Restart();
spriteBatch.Begin(SpriteSortMode.Immediate,
BlendState.NonPremultiplied, SamplerState.LinearWrap,
null, null,
@@ -310,10 +345,18 @@ namespace Barotrauma
Submarine.DrawDamageable(spriteBatch, damageEffect, false);
spriteBatch.End();
sw.Stop();
GameMain.PerformanceCounter.AddElapsedTicks("Draw:Map:FrontDamageable", sw.ElapsedTicks);
sw.Restart();
spriteBatch.Begin(SpriteSortMode.BackToFront, BlendState.NonPremultiplied, null, DepthStencilState.None, null, null, cam.Transform);
Submarine.DrawFront(spriteBatch, false, null);
spriteBatch.End();
sw.Stop();
GameMain.PerformanceCounter.AddElapsedTicks("Draw:Map:FrontStructuresItems", sw.ElapsedTicks);
sw.Restart();
//draw additive particles that are inside a sub
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Additive, null, DepthStencilState.Default, null, null, cam.Transform);
GameMain.ParticleManager.Draw(spriteBatch, true, true, Particles.ParticleBlendState.Additive);
@@ -349,6 +392,10 @@ namespace Barotrauma
}
spriteBatch.End();
sw.Stop();
GameMain.PerformanceCounter.AddElapsedTicks("Draw:Map:FrontMisc", sw.ElapsedTicks);
sw.Restart();
if (GameMain.LightManager.LosEnabled && GameMain.LightManager.LosMode != LosMode.None && Lights.LightManager.ViewTarget != null)
{
GameMain.LightManager.LosEffect.CurrentTechnique = GameMain.LightManager.LosEffect.Techniques["LosShader"];
@@ -457,6 +504,10 @@ namespace Barotrauma
GUI.DrawRectangle(spriteBatch, new Rectangle(0, 0, GameMain.GraphicsWidth, GameMain.GraphicsHeight), Color.Lerp(Color.TransparentBlack, Color.Black, fadeToBlackState), isFilled: true);
spriteBatch.End();
}
sw.Stop();
GameMain.PerformanceCounter.AddElapsedTicks("Draw:Map:PostProcess", sw.ElapsedTicks);
sw.Restart();
}
partial void UpdateProjSpecific(double deltaTime)

View File

@@ -110,7 +110,7 @@ namespace Barotrauma
public bool CampaignCharacterDiscarded
{
get;
private set;
set;
}
//elements that can only be used by the host
@@ -1253,9 +1253,6 @@ namespace Barotrauma
CharacterAppearanceCustomizationMenu?.Dispose();
JobSelectionFrame = null;
/*foreach (Sprite sprite in jobPreferenceSprites) { sprite.Remove(); }
jobPreferenceSprites.Clear();*/
}
public override void Select()
@@ -1417,7 +1414,7 @@ namespace Barotrauma
characterInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, GameMain.Client.Name, null);
characterInfo.RecreateHead(MultiplayerPreferences.Instance);
GameMain.Client.CharacterInfo = characterInfo;
characterInfo.OmitJobInPortraitClothing = false;
characterInfo.OmitJobInMenus = true;
}
parent.ClearChildren();

View File

@@ -1870,7 +1870,8 @@ namespace Barotrauma
}
addSubAndSaveModProject(modProject, savePath, fileListPath);
}
else if (MainSub?.Info != null
else if (MainSub?.Info?.FilePath != null
&& MainSub.Info.Name != null
&& MainSub.Info.FilePath.StartsWith(ContentPackage.LocalModsDir)
&& MainSub.Info.Name.Equals(name, StringComparison.InvariantCultureIgnoreCase))
{
@@ -2321,7 +2322,7 @@ namespace Barotrauma
};
new GUITextBlock(new RectTransform(new Vector2(0.6f, 1.0f), beaconMinDifficultyGroup.RectTransform),
TextManager.Get("minleveldifficulty"), textAlignment: Alignment.CenterLeft, wrap: true);
new GUINumberInput(new RectTransform(new Vector2(0.4f, 1.0f), beaconMinDifficultyGroup.RectTransform), NumberType.Int)
var numInput = new GUINumberInput(new RectTransform(new Vector2(0.4f, 1.0f), beaconMinDifficultyGroup.RectTransform), NumberType.Int)
{
IntValue = (int)(MainSub?.Info?.BeaconStationInfo?.MinLevelDifficulty ?? 0),
MinValueInt = 0,
@@ -2331,13 +2332,14 @@ namespace Barotrauma
MainSub.Info.BeaconStationInfo.MinLevelDifficulty = numberInput.IntValue;
}
};
beaconMinDifficultyGroup.RectTransform.MaxSize = numInput.TextBox.RectTransform.MaxSize;
var beaconMaxDifficultyGroup = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.25f), beaconSettingsContainer.RectTransform), isHorizontal: true)
{
Stretch = true
};
new GUITextBlock(new RectTransform(new Vector2(0.6f, 1.0f), beaconMaxDifficultyGroup.RectTransform),
TextManager.Get("maxleveldifficulty"), textAlignment: Alignment.CenterLeft, wrap: true);
new GUINumberInput(new RectTransform(new Vector2(0.4f, 1.0f), beaconMaxDifficultyGroup.RectTransform), NumberType.Int)
numInput = new GUINumberInput(new RectTransform(new Vector2(0.4f, 1.0f), beaconMaxDifficultyGroup.RectTransform), NumberType.Int)
{
IntValue = (int)(MainSub?.Info?.BeaconStationInfo?.MaxLevelDifficulty ?? 100),
MinValueInt = 0,
@@ -2347,7 +2349,7 @@ namespace Barotrauma
MainSub.Info.BeaconStationInfo.MaxLevelDifficulty = numberInput.IntValue;
}
};
beaconMaxDifficultyGroup.RectTransform.MaxSize = numInput.TextBox.RectTransform.MaxSize;
new GUITickBox(new RectTransform(new Vector2(1.0f, 0.25f), beaconSettingsContainer.RectTransform), TextManager.Get("allowdamagedwalls"))
{
Selected = MainSub?.Info?.BeaconStationInfo?.AllowDamagedWalls ?? true,
@@ -2545,6 +2547,10 @@ namespace Barotrauma
{
MainSub.Info.OutpostModuleInfo ??= new OutpostModuleInfo(MainSub.Info);
}
else if (type == SubmarineType.BeaconStation)
{
MainSub.Info.BeaconStationInfo ??= new BeaconStationInfo(MainSub.Info);
}
previewImageButtonHolder.Children.ForEach(c => c.Enabled = type != SubmarineType.OutpostModule);
outpostSettingsContainer.Visible = type == SubmarineType.OutpostModule;

View File

@@ -1,6 +1,7 @@
#nullable enable
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Globalization;
using System.Linq;
using Barotrauma.Extensions;
@@ -36,6 +37,8 @@ namespace Barotrauma
public readonly WorkshopMenu WorkshopMenu;
private static readonly ImmutableHashSet<InputType> LegacyInputTypes = new List<InputType>() { InputType.Chat, InputType.RadioChat }.ToImmutableHashSet();
public static SettingsMenu Create(RectTransform mainParent)
{
Instance?.Close();
@@ -392,6 +395,9 @@ namespace Barotrauma
Label(audio, TextManager.Get("MusicVolume"), GUIStyle.SubHeadingFont);
Slider(audio, (0, 1), 101, Percentage, unsavedConfig.Audio.MusicVolume, (v) => unsavedConfig.Audio.MusicVolume = v);
Label(audio, TextManager.Get("UiSoundVolume"), GUIStyle.SubHeadingFont);
Slider(audio, (0, 1), 101, Percentage, unsavedConfig.Audio.UiVolume, (v) => unsavedConfig.Audio.UiVolume = v);
Tickbox(audio, TextManager.Get("MuteOnFocusLost"), TextManager.Get("MuteOnFocusLostTooltip"), unsavedConfig.Audio.MuteOnFocusLost, (v) => unsavedConfig.Audio.MuteOnFocusLost = v);
Tickbox(audio, TextManager.Get("DynamicRangeCompression"), TextManager.Get("DynamicRangeCompressionTooltip"), unsavedConfig.Audio.DynamicRangeCompressionEnabled, (v) => unsavedConfig.Audio.DynamicRangeCompressionEnabled = v);
Spacer(audio);
@@ -481,10 +487,14 @@ namespace Barotrauma
HashSet<GUIButton> inputButtons = new HashSet<GUIButton>();
Action<KeyOrMouse>? currentSetter = null;
void addInputToRow(GUILayoutGroup currRow, LocalizedString labelText, Func<LocalizedString> valueNameGetter, Action<KeyOrMouse> valueSetter)
void addInputToRow(GUILayoutGroup currRow, LocalizedString labelText, Func<LocalizedString> valueNameGetter, Action<KeyOrMouse> valueSetter, bool isLegacyBind = false)
{
var inputFrame = new GUIFrame(new RectTransform((0.5f, 1.0f), currRow.RectTransform),
style: null);
if (isLegacyBind)
{
labelText = TextManager.GetWithVariable("legacyitemformat", "[name]", labelText);
}
var label = new GUITextBlock(new RectTransform((0.6f, 1.0f), inputFrame.RectTransform), labelText,
font: GUIStyle.SmallFont) {ForceUpperCase = ForceUpperCase.Yes};
var inputBox = new GUIButton(
@@ -515,6 +525,12 @@ namespace Barotrauma
return true;
}
};
if (isLegacyBind)
{
label.TextColor = Color.Lerp(label.TextColor, label.DisabledTextColor, 0.5f);
inputBox.Color = Color.Lerp(inputBox.Color, inputBox.DisabledColor, 0.5f);
inputBox.TextColor = Color.Lerp(inputBox.TextColor, label.DisabledTextColor, 0.5f);
}
inputButtons.Add(inputBox);
}
@@ -594,7 +610,8 @@ namespace Barotrauma
currRow,
TextManager.Get($"InputType.{input}"),
() => unsavedConfig.KeyMap.Bindings[input].Name,
(v) => unsavedConfig.KeyMap = unsavedConfig.KeyMap.WithBinding(input, v));
(v) => unsavedConfig.KeyMap = unsavedConfig.KeyMap.WithBinding(input, v),
LegacyInputTypes.Contains(input));
}
}
@@ -609,30 +626,29 @@ namespace Barotrauma
var input = unsavedConfig.InventoryKeyMap.Bindings[currIndex];
addInputToRow(
currRow,
TextManager.GetWithVariable("inventoryslotkeybind", "[slotnumber]", (currIndex+1).ToString(CultureInfo.InvariantCulture)),
TextManager.GetWithVariable("inventoryslotkeybind", "[slotnumber]", (currIndex + 1).ToString(CultureInfo.InvariantCulture)),
() => unsavedConfig.InventoryKeyMap.Bindings[currIndex].Name,
(v) => unsavedConfig.InventoryKeyMap = unsavedConfig.InventoryKeyMap.WithBinding(currIndex, v));
}
}
GUILayoutGroup resetControlsHolder =
new GUILayoutGroup(new RectTransform((1.75f, 0.1f), layout.RectTransform), isHorizontal: true)
new GUILayoutGroup(new RectTransform((1.75f, 0.1f), layout.RectTransform), isHorizontal: true, childAnchor: Anchor.Center)
{
RelativeSpacing = 0.1f
};
var defaultBindingsButton =
new GUIButton(new RectTransform(new Vector2(0.45f, 1.0f), resetControlsHolder.RectTransform),
TextManager.Get("SetDefaultBindings"), style: "GUIButtonSmall")
TextManager.Get("Reset"), style: "GUIButtonSmall")
{
ToolTip = TextManager.Get("SetDefaultBindingsTooltip")
};
var legacyBindingsButton =
new GUIButton(new RectTransform(new Vector2(0.45f, 1.0f), resetControlsHolder.RectTransform),
TextManager.Get("SetLegacyBindings"), style: "GUIButtonSmall")
{
ToolTip = TextManager.Get("SetLegacyBindingsTooltip")
ToolTip = TextManager.Get("SetDefaultBindingsTooltip"),
OnClicked = (btn, userdata) =>
{
unsavedConfig.InventoryKeyMap = GameSettings.Config.InventoryKeyMapping.GetDefault();
unsavedConfig.KeyMap = GameSettings.Config.KeyMapping.GetDefault();
return true;
}
};
}

View File

@@ -705,7 +705,7 @@ namespace Barotrauma.Sounds
public void ApplySettings()
{
SetCategoryGainMultiplier("default", GameSettings.CurrentConfig.Audio.SoundVolume, 0);
SetCategoryGainMultiplier("ui", GameSettings.CurrentConfig.Audio.SoundVolume, 0);
SetCategoryGainMultiplier("ui", GameSettings.CurrentConfig.Audio.UiVolume, 0);
SetCategoryGainMultiplier("waterambience", GameSettings.CurrentConfig.Audio.SoundVolume, 0);
SetCategoryGainMultiplier("music", GameSettings.CurrentConfig.Audio.MusicVolume, 0);
SetCategoryGainMultiplier("voip", Math.Min(GameSettings.CurrentConfig.Audio.VoiceChatVolume, 1.0f), 0);

View File

@@ -6,7 +6,7 @@
<RootNamespace>Barotrauma</RootNamespace>
<Authors>FakeFish, Undertow Games</Authors>
<Product>Barotrauma</Product>
<Version>0.18.4.0</Version>
<Version>0.18.5.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.18.4.0</Version>
<Version>0.18.5.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.18.4.0</Version>
<Version>0.18.5.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.18.4.0</Version>
<Version>0.18.5.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.18.4.0</Version>
<Version>0.18.5.0</Version>
<Copyright>Copyright © FakeFish 2018-2022</Copyright>
<Platforms>AnyCPU;x64</Platforms>
<AssemblyName>DedicatedServer</AssemblyName>

View File

@@ -10,7 +10,8 @@ namespace Barotrauma.Networking
c.KickAFKTimer = 0.0f;
UInt16 ID = msg.ReadUInt16();
ChatMessageType type = (ChatMessageType)msg.ReadByte();
ChatMessageType type = (ChatMessageType)msg.ReadRangedInteger(0, Enum.GetValues(typeof(ChatMessageType)).Length - 1);
ChatMode chatMode = (ChatMode)msg.ReadRangedInteger(0, Enum.GetValues(typeof(ChatMode)).Length - 1);
string txt;
Character orderTargetCharacter = null;
@@ -172,7 +173,7 @@ namespace Barotrauma.Networking
}
else
{
GameMain.Server.SendChatMessage(txt, null, c);
GameMain.Server.SendChatMessage(txt, senderClient: c, chatMode: chatMode);
}
}
@@ -203,7 +204,7 @@ namespace Barotrauma.Networking
{
msg.Write((byte)ServerNetObject.CHAT_MESSAGE);
msg.Write(NetStateID);
msg.Write((byte)Type);
msg.WriteRangedInteger((int)Type, 0, Enum.GetValues(typeof(ChatMessageType)).Length - 1);
msg.Write((byte)ChangeType);
msg.Write(Text);

View File

@@ -2696,6 +2696,24 @@ namespace Barotrauma.Networking
if (newName == c.Name) { return false; }
if (IsNameValid(c, newName))
{
string oldName = c.Name;
c.Name = newName;
c.Connection.Name = newName;
SendChatMessage($"ServerMessage.NameChangeSuccessful~[oldname]={oldName}~[newname]={newName}", ChatMessageType.Server);
return true;
}
else
{
return false;
}
}
private bool IsNameValid(Client c, string newName)
{
newName = Client.SanitizeName(newName);
if (c.Connection != OwnerConnection)
{
if (!Client.IsValidName(newName, serverSettings))
@@ -2723,9 +2741,6 @@ namespace Barotrauma.Networking
return false;
}
SendChatMessage($"ServerMessage.NameChangeSuccessful~[oldname]={c.Name}~[newname]={newName}", ChatMessageType.Server);
c.Name = newName;
c.Connection.Name = newName;
return true;
}
@@ -2967,7 +2982,7 @@ namespace Barotrauma.Networking
/// <summary>
/// Add the message to the chatbox and pass it to all clients who can receive it
/// </summary>
public void SendChatMessage(string message, ChatMessageType? type = null, Client senderClient = null, Character senderCharacter = null, PlayerConnectionChangeType changeType = PlayerConnectionChangeType.None)
public void SendChatMessage(string message, ChatMessageType? type = null, Client senderClient = null, Character senderCharacter = null, PlayerConnectionChangeType changeType = PlayerConnectionChangeType.None, ChatMode chatMode = ChatMode.None)
{
string senderName = "";
@@ -3023,6 +3038,10 @@ namespace Barotrauma.Networking
type = ChatMessageType.Private;
}
else if (chatMode == ChatMode.Radio)
{
type = ChatMessageType.Radio;
}
else
{
type = ChatMessageType.Default;
@@ -3051,7 +3070,6 @@ namespace Barotrauma.Networking
{
senderCharacter = senderClient.Character;
senderName = senderCharacter == null ? senderClient.Name : senderCharacter.Name;
if (type == ChatMessageType.Private)
{
if (senderCharacter != null && !senderCharacter.IsDead || targetClient.Character != null && !targetClient.Character.IsDead)
@@ -3512,6 +3530,20 @@ namespace Barotrauma.Networking
return;
}
string newName = message.ReadString();
if (string.IsNullOrEmpty(newName))
{
newName = sender.Name;
}
else
{
newName = Client.SanitizeName(newName);
if (!IsNameValid(sender, newName))
{
newName = sender.Name;
}
}
int tagCount = message.ReadByte();
HashSet<Identifier> tagSet = new HashSet<Identifier>();
for (int i = 0; i < tagCount; i++)
@@ -3539,7 +3571,7 @@ namespace Barotrauma.Networking
}
}
sender.CharacterInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, sender.Name);
sender.CharacterInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, newName);
sender.CharacterInfo.RecreateHead(tagSet.ToImmutableHashSet(), hairIndex, beardIndex, moustacheIndex, faceAttachmentIndex);
sender.CharacterInfo.Head.SkinColor = skinColor;
sender.CharacterInfo.Head.HairColor = hairColor;

View File

@@ -1,4 +1,6 @@
namespace Barotrauma.Networking
using System;
namespace Barotrauma.Networking
{
partial class OrderChatMessage : ChatMessage
{
@@ -6,7 +8,7 @@
{
msg.Write((byte)ServerNetObject.CHAT_MESSAGE);
msg.Write(NetStateID);
msg.Write((byte)ChatMessageType.Order);
msg.WriteRangedInteger((int)ChatMessageType.Order, 0, Enum.GetValues(typeof(ChatMessageType)).Length - 1);
msg.Write(SenderName);
msg.Write(SenderClient != null);
if (SenderClient != null)

View File

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

View File

@@ -2,8 +2,8 @@
<CampaignSettingPresets>
<CampaignSettingDefinitions>
<StartingBalanceAmount high="10000" medium="8500" low="6000" />
<ExtraEventManagerDifficulty easy="-15.0" normal="0.0" hard="20.0" hellish="60.0" />
<LevelDifficultyMultiplier easy="0.6" normal="1.0" hard="1.6" hellish="10.0" />
<ExtraEventManagerDifficulty easy="-15.0" medium="0.0" hard="20.0" hellish="60.0" />
<LevelDifficultyMultiplier easy="0.6" medium="1.0" hard="1.6" hellish="10.0" />
</CampaignSettingDefinitions>
<CampaignSettings
presetname="Easy"

View File

@@ -2,7 +2,6 @@
using Barotrauma.Items.Components;
using System.Collections.Generic;
using System.Linq;
using System;
namespace Barotrauma
{
@@ -48,6 +47,9 @@ namespace Barotrauma
protected override bool Filter(Item target)
{
System.Diagnostics.Debug.Assert(target.GetComponent<Pickable>() is { } pickable && !pickable.IsAttached, "Invalid target in AIObjectiveCleanUpItems - the the objective should only be checking pickable, non-attached items.");
System.Diagnostics.Debug.Assert(target.Prefab.PreferredContainers.Any(), "Invalid target in AIObjectiveCleanUpItems - the the objective should only be checking items that have preferred containers defined.");
// If the target was selected as a valid target, we'll have to accept it so that the objective can be completed.
// The validity changes when a character picks the item up.
if (!IsValidTarget(target, character, checkInventory: true)) { return Objectives.ContainsKey(target) && IsItemInsideValidSubmarine(target, character); }
@@ -57,7 +59,7 @@ namespace Barotrauma
return true;
}
protected override IEnumerable<Item> GetList() => Item.ItemList;
protected override IEnumerable<Item> GetList() => Item.CleanableItems;
protected override AIObjective ObjectiveConstructor(Item item)
=> new AIObjectiveCleanupItem(item, character, objectiveManager, priorityModifier: PriorityModifier)
@@ -102,9 +104,6 @@ namespace Barotrauma
}
if (character != null && !IsItemInsideValidSubmarine(item, character)) { return false; }
if (item.HasBallastFloraInHull) { return false; }
var pickable = item.GetComponent<Pickable>();
if (pickable == null) { return false; }
if (pickable is Holdable h && h.Attachable && h.Attached) { return false; }
var wire = item.GetComponent<Wire>();
if (wire != null)
{
@@ -118,10 +117,6 @@ namespace Barotrauma
return false;
}
}
if (item.Prefab.PreferredContainers.None())
{
return false;
}
if (!checkInventory)
{
return true;

View File

@@ -488,7 +488,7 @@ namespace Barotrauma
if (hull != null)
{
itemsToClean.Clear();
foreach (Item item in Item.ItemList)
foreach (Item item in Item.CleanableItems)
{
if (item.CurrentHull != hull) { continue; }
if (AIObjectiveCleanupItems.IsValidTarget(item, character, checkInventory: true, allowUnloading: false) && !ignoredItems.Contains(item))

View File

@@ -39,12 +39,21 @@ namespace Barotrauma
{
TargetContainers.Add(targetContainer);
}
else
{
foreach (Item item in Item.ItemList)
{
if (!OrderPrefab.TargetItemsMatchItem(TargetContainerTags, item)) { continue; }
TargetContainers.Add(item);
}
}
TargetCondition = option == "turretammo" ? ItemCondition.Empty : ItemCondition.Full;
}
protected override bool Filter(Item target)
{
if (!IsValidTarget(target, character, TargetContainerTags, TargetCondition)) { return false; }
//don't pass TargetContainerTags to the method (no need to filter by tags anymore, it's already done when populating TargetContainers)
if (!IsValidTarget(target, character, null, TargetCondition)) { return false; }
if (target.CurrentHull == null || target.CurrentHull.FireSources.Count > 0) { return false; }
if (Character.CharacterList.Any(c => c.CurrentHull == target.CurrentHull && !HumanAIController.IsFriendly(c) && HumanAIController.IsActive(c))) { return false; }
return true;
@@ -52,8 +61,7 @@ namespace Barotrauma
public static bool IsValidTarget(Item item, Character character, ImmutableArray<Identifier>? targetContainerTags = null, ItemCondition? targetCondition = null)
{
if (item == null) { return false; }
if (item.Removed) { return false; }
if (item == null || item.Removed) { return false; }
if (targetContainerTags.HasValue && !OrderPrefab.TargetItemsMatchItem(targetContainerTags.Value, item)) { return false; }
if (!(item.GetComponent<ItemContainer>() is ItemContainer container)) { return false; }
if (container.Inventory == null) { return false; }
@@ -88,7 +96,7 @@ namespace Barotrauma
}
}
protected override IEnumerable<Item> GetList() => TargetContainers.Any() ? TargetContainers : Item.ItemList;
protected override IEnumerable<Item> GetList() => TargetContainers;
protected override AIObjective ObjectiveConstructor(Item target)
=> new AIObjectiveLoadItem(target, TargetContainerTags, TargetCondition, Option, character, objectiveManager, PriorityModifier);

View File

@@ -13,7 +13,7 @@ namespace Barotrauma
public override bool KeepDivingGearOn => true;
public override bool AllowAutomaticItemUnequipping => true;
private IEnumerable<Pump> pumpList;
private List<Pump> pumpList;
public AIObjectivePumpWater(Character character, AIObjectiveManager objectiveManager, Identifier option, float priorityModifier = 1)
: base(character, objectiveManager, priorityModifier, option) { }
@@ -26,13 +26,8 @@ namespace Barotrauma
protected override bool Filter(Pump pump)
{
if (pump == null) { return false; }
if (pump.Item.IgnoreByAI(character)) { return false; }
if (!pump.Item.IsInteractable(character)) { return false; }
if (pump.Item.HasTag("ballast")) { return false; }
if (pump.Item.Submarine == null) { return false; }
if (pump.Item.CurrentHull == null) { return false; }
if (pump.Item.Submarine.TeamID != character.TeamID) { return false; }
if (pump.IsAutoControlled) { return false; }
if (pump.Item.ConditionPercentage <= 0) { return false; }
if (pump.Item.CurrentHull.FireSources.Count > 0) { return false; }
@@ -50,7 +45,16 @@ namespace Barotrauma
if (pumpList == null)
{
if (character == null || character.Submarine == null) { return Array.Empty<Pump>(); }
pumpList = character.Submarine.GetItems(true).Select(i => i.GetComponent<Pump>()).Where(p => p != null);
pumpList = new List<Pump>();
foreach (Item item in character.Submarine.GetItems(true))
{
var pump = item.GetComponent<Pump>();
if (pump == null || pump.Item.Submarine == null || pump.Item.CurrentHull == null) { continue; }
if (pump.Item.Submarine.TeamID != character.TeamID) { continue; }
if (pump.Item.HasTag("ballast")) { continue; }
pumpList.Add(pump);
}
}
return pumpList;
}

View File

@@ -136,7 +136,7 @@ namespace Barotrauma
return MathHelper.Lerp(0, 100, MathHelper.Clamp(damagePriority * successFactor, 0, 1));
}
protected override IEnumerable<Item> GetList() => Item.ItemList;
protected override IEnumerable<Item> GetList() => Item.RepairableItems;
protected override AIObjective ObjectiveConstructor(Item item)
=> new AIObjectiveRepairItem(character, item, objectiveManager, priorityModifier: PriorityModifier, isPriority: item == PrioritizedItem);
@@ -156,6 +156,9 @@ namespace Barotrauma
if (character.IsOnPlayerTeam && item.Submarine.Info.IsOutpost) { return false; }
if (!character.Submarine.IsEntityFoundOnThisSub(item, includingConnectedSubs: true)) { return false; }
if (item.Repairables.None()) { return false; }
System.Diagnostics.Debug.Assert(item.Repairables.Any(), "Invalid target in AIObjectiveRepairItems - the objective should only be checking items that have a Repairable component (Item.RepairableItems)");
return true;
}
}

View File

@@ -356,7 +356,10 @@ namespace Barotrauma
}
}
public bool OmitJobInPortraitClothing;
/// <summary>
/// Can be used to disable displaying the job in any info panels
/// </summary>
public bool OmitJobInMenus;
private Sprite portrait;
public Sprite Portrait
@@ -434,7 +437,7 @@ namespace Barotrauma
{
if (attachmentSprites == null)
{
LoadAttachmentSprites(OmitJobInPortraitClothing);
LoadAttachmentSprites();
}
return attachmentSprites;
}
@@ -1092,7 +1095,7 @@ namespace Barotrauma
private static IEnumerable<float> GetWeights(IEnumerable<ContentXElement> elements) => elements.Select(h => h.GetAttributeFloat("commonness", 1f));
partial void LoadAttachmentSprites(bool omitJob);
partial void LoadAttachmentSprites();
private int CalculateSalary()
{

View File

@@ -79,7 +79,6 @@ namespace Barotrauma
/// </summary>
public static IReadOnlyDictionary<Identifier, float> ItemRepairPriorities => _itemRepairPriorities;
public static ContentXElement NoJobElement;
public static JobPrefab Get(string identifier)
{
if (Prefabs.ContainsKey(identifier))
@@ -213,7 +212,7 @@ namespace Barotrauma
public SkillPrefab PrimarySkill => Skills?.FirstOrDefault(s => s.IsPrimarySkill);
public ContentXElement Element { get; private set; }
public ContentXElement ClothingElement { get; private set; }
public int Variants { get; private set; }
public JobPrefab(ContentXElement element, JobsFile file) : base(file, element.GetAttributeIdentifier("identifier", ""))
@@ -288,9 +287,6 @@ namespace Barotrauma
Variants = variant;
Skills.Sort((x,y) => y.LevelRange.Start.CompareTo(x.LevelRange.Start));
// Disabled on purpose, TODO: remove all references?
//ClothingElement = element.GetChildElement("PortraitClothing");
}
public static JobPrefab Random(Rand.RandSync sync, Func<JobPrefab, bool> predicate = null) => Prefabs.GetRandom(p => !p.HiddenJob && (predicate == null || predicate(p)), sync);

View File

@@ -121,7 +121,7 @@ namespace Barotrauma
return folder.CleanUpPathCrossPlatform(correctFilenameCase: true);
}
public static T GetDefaultRagdollParams<T>(Identifier speciesName) where T : RagdollParams, new() => GetRagdollParams<T>(speciesName, GetDefaultFileName(speciesName));
public static T GetDefaultRagdollParams<T>(Identifier speciesName) where T : RagdollParams, new() => GetRagdollParams<T>(speciesName);
/// <summary>
/// If the file name is left null, default file is selected. If fails, will select the default file. Note: Use the filename without the extensions, don't use the full path!

View File

@@ -22,11 +22,7 @@ namespace Barotrauma
{
foreach (var element in mainElement.Elements())
{
if (element.NameAsIdentifier() == "nojob")
{
JobPrefab.NoJobElement ??= element;
}
else if (element.NameAsIdentifier() == "ItemRepairPriorities")
if (element.NameAsIdentifier() == "ItemRepairPriorities")
{
foreach (var subElement in element.Elements())
{

View File

@@ -177,4 +177,11 @@ namespace Barotrauma
Int,
Float
}
public enum ChatMode
{
None,
Local,
Radio
}
}

View File

@@ -1028,13 +1028,14 @@ namespace Barotrauma
var itemsToTransfer = new List<(Item item, Item container)>();
if (PendingSubmarineSwitch != null)
{
var connectedSubs = currentSub.GetConnectedSubs().Where(s => s.Info.Type == SubmarineType.Player).ToHashSet();
// Remove items from the old sub
foreach (Item item in Item.ItemList)
{
if (item.Removed) { continue; }
if (item.NonInteractable) { continue; }
if (item.HiddenInGame) { continue; }
if (item.Submarine != currentSub) { continue; }
if (!connectedSubs.Contains(item.Submarine)) { continue; }
if (item.Prefab.DontTransferBetweenSubs) { continue; }
if (item.GetRootInventoryOwner() is Character) { continue; }
if (item.GetComponent<Holdable>() == null && item.GetComponent<Wearable>() == null && item.GetComponent<Projectile>() == null) { continue; }
@@ -1058,9 +1059,10 @@ namespace Barotrauma
{
// Load the new sub
var newSub = new Submarine(PendingSubmarineSwitch);
var connectedSubs = newSub.GetConnectedSubs().Where(s => s.Info.Type == SubmarineType.Player).ToHashSet();
// Move the transferred items
List<ItemContainer> availableContainers = Item.ItemList
.Where(it => it.Submarine == newSub && it.HasTag("crate") && !it.NonInteractable && !it.HiddenInGame && !it.Removed)
.Where(it => connectedSubs.Contains(it.Submarine) && it.HasTag("crate") && !it.NonInteractable && !it.HiddenInGame && !it.Removed)
.Select(it => it.GetComponent<ItemContainer>())
.Where(c => c != null)
.ToList();
@@ -1070,7 +1072,7 @@ namespace Barotrauma
item.Submarine = newSub;
if (item.Container == null)
{
newContainer = newSub.FindContainerFor(item, onlyPrimary: true, checkTransferConditions: true);
newContainer = newSub.FindContainerFor(item, onlyPrimary: true, checkTransferConditions: true, allowConnectedSubs: true);
}
if (item.Container == null && (newContainer == null || !newContainer.OwnInventory.TryPutItem(item, user: null, createNetworkEvent: false)))
{
@@ -1086,7 +1088,8 @@ namespace Barotrauma
var cargoContainer = CargoManager.GetOrCreateCargoContainerFor(item.Prefab, spawnHull, ref availableContainers);
if (cargoContainer == null || !cargoContainer.Inventory.TryPutItem(item, user: null, createNetworkEvent: false))
{
item.SetTransform(wp.SimPosition, 0.0f, findNewHull: false, setPrevTransform: false);
Vector2 simPos = ConvertUnits.ToSimUnits(CargoManager.GetCargoPos(spawnHull, item.Prefab));
item.SetTransform(simPos, 0.0f, findNewHull: false, setPrevTransform: false);
}
}
else

View File

@@ -71,12 +71,22 @@ namespace Barotrauma
public float GetFloat(Identifier identifier)
{
return values.TryGetValue(identifier, out Either<int, float> value) && value.TryGet(out float range) ? range : 0.0f;
float range = 0;
if (!values.TryGetValue(identifier, out Either<int, float> value) || !value.TryGet(out range))
{
DebugConsole.ThrowError($"CampaignSettings: Can't find value for {identifier}");
}
return range;
}
public int GetInt(Identifier identifier)
{
return values.TryGetValue(identifier, out Either<int, float> value) && value.TryGet(out int integer) ? integer : 0;
int integer = 0;
if (!values.TryGetValue(identifier, out Either<int, float> value) || !value.TryGet(out integer))
{
DebugConsole.ThrowError($"CampaignSettings: Can't find value for {identifier}");
}
return integer;
}
}
}

View File

@@ -13,13 +13,14 @@ namespace Barotrauma
SelectNextCharacter,
SelectPreviousCharacter,
Voice,
LocalVoice,
Deselect,
Shoot,
Command,
TakeOneFromInventorySlot,
TakeHalfFromInventorySlot,
NextFireMode,
PreviousFireMode
PreviousFireMode,
ActiveChat,
ToggleChatMode,
}
}

View File

@@ -270,7 +270,11 @@ namespace Barotrauma.Items.Components
{
Body?.SetTransform(Body.SimPosition + ConvertUnits.ToSimUnits(amount), 0.0f);
}
if (linkedGap != null)
{
RefreshLinkedGap();
linkedGap.Rect = item.Rect;
}
#if CLIENT
UpdateConvexHulls();
#endif

View File

@@ -41,6 +41,8 @@ namespace Barotrauma.Items.Components
private Character prevEquipper;
public override bool IsAttached => Attached;
private bool attachable, attached, attachedByDefault;
private Voronoi2.VoronoiCell attachTargetCell;
private PhysicsBody body;
@@ -71,6 +73,7 @@ namespace Barotrauma.Items.Components
set
{
attached = value;
item.CheckCleanable();
item.SetActiveSprite();
}
}

View File

@@ -4,7 +4,6 @@ using Microsoft.Xna.Framework;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
namespace Barotrauma.Items.Components
{
@@ -20,6 +19,8 @@ namespace Barotrauma.Items.Components
private CoroutineHandle pickingCoroutine;
public virtual bool IsAttached => false;
public List<InvSlotType> AllowedSlots
{
get { return allowedSlots; }

View File

@@ -94,7 +94,7 @@ namespace Barotrauma.Items.Components
get; set;
}
[Serialize(true, IsPropertySaveable.No, description: "Can the item hit broken doors.")]
[Serialize(true, IsPropertySaveable.No, description: "Can the item hit doors.")]
public bool HitItems { get; set; }
[Serialize(false, IsPropertySaveable.No, description: "Can the item hit broken doors.")]

View File

@@ -187,7 +187,7 @@ namespace Barotrauma.Items.Components
[Serialize(false, IsPropertySaveable.No)]
public bool RemoveContainedItemsOnDeconstruct { get; set; }
private readonly ImmutableArray<SlotRestrictions> slotRestrictions;
private ImmutableArray<SlotRestrictions> slotRestrictions;
readonly List<ISerializableEntity> targets = new List<ISerializableEntity>();
@@ -215,13 +215,21 @@ namespace Barotrauma.Items.Components
public override bool RecreateGUIOnResolutionChange => true;
public List<RelatedItem> ContainableItems { get; }
public List<RelatedItem> ContainableItems { get; private set; }
public ItemContainer(Item item, ContentXElement element)
: base(item, element)
{
LoadContainableRestrictions(element);
InitProjSpecific(element);
}
public void LoadContainableRestrictions(ContentXElement element)
{
int totalCapacity = capacity;
ContainableItems?.Clear();
foreach (var subElement in element.Elements())
{
switch (subElement.Name.ToString().ToLowerInvariant())
@@ -242,7 +250,7 @@ namespace Barotrauma.Items.Components
}
}
Inventory = new ItemInventory(item, this, totalCapacity, SlotsPerRow);
List<SlotRestrictions> newSlotRestrictions = new List<SlotRestrictions>(totalCapacity);
for (int i = 0; i < capacity; i++)
{
@@ -253,7 +261,7 @@ namespace Barotrauma.Items.Components
foreach (var subElement in element.Elements())
{
if (subElement.Name.ToString().ToLowerInvariant() != "subcontainer") { continue; }
int subCapacity = subElement.GetAttributeInt("capacity", 1);
int subMaxStackSize = subElement.GetAttributeInt("maxstacksize", maxStackSize);
@@ -281,7 +289,6 @@ namespace Barotrauma.Items.Components
capacity = totalCapacity;
slotRestrictions = newSlotRestrictions.ToImmutableArray();
System.Diagnostics.Debug.Assert(totalCapacity == slotRestrictions.Length);
InitProjSpecific(element);
}
public int GetMaxStackSize(int slotIndex)

View File

@@ -114,6 +114,20 @@ namespace Barotrauma.Items.Components
private set;
} = true;
[Serialize(false, IsPropertySaveable.No)]
public bool NonInteractableWhenFlippedX
{
get;
set;
}
[Serialize(false, IsPropertySaveable.No)]
public bool NonInteractableWhenFlippedY
{
get;
set;
}
public Controller(Item item, ContentXElement element)
: base(item, element)
{
@@ -571,6 +585,18 @@ namespace Barotrauma.Items.Components
}
}
public override void OnItemLoaded()
{
if (item.FlippedX && NonInteractableWhenFlippedX)
{
item.NonInteractable = true;
}
else if (item.FlippedY && NonInteractableWhenFlippedY)
{
item.NonInteractable = true;
}
}
public override void Reset()
{
base.Reset();

View File

@@ -435,7 +435,7 @@ namespace Barotrauma.Items.Components
#if CLIENT
sw.Stop();
GameMain.PerformanceCounter.AddElapsedTicks("GridUpdate", sw.ElapsedTicks);
GameMain.PerformanceCounter.AddElapsedTicks("Update:Power", sw.ElapsedTicks);
sw.Restart();
#endif
@@ -592,7 +592,7 @@ namespace Barotrauma.Items.Components
#if CLIENT
sw.Stop();
GameMain.PerformanceCounter.AddElapsedTicks("PowerUpdate", sw.ElapsedTicks);
GameMain.PerformanceCounter.AddElapsedTicks("Update:Power", sw.ElapsedTicks);
#endif
}

View File

@@ -17,7 +17,6 @@ namespace Barotrauma
Beard,
Moustache,
FaceAttachment,
JobIndicator,
Husk,
Herpes
}
@@ -128,7 +127,6 @@ namespace Barotrauma
case WearableType.Beard:
case WearableType.Moustache:
case WearableType.FaceAttachment:
case WearableType.JobIndicator:
case WearableType.Husk:
case WearableType.Herpes:
Limb = LimbType.Head;

View File

@@ -29,6 +29,20 @@ namespace Barotrauma
public static IReadOnlyCollection<Item> DangerousItems { get { return dangerousItems; } }
private static readonly List<Item> repairableItems = new List<Item>();
/// <summary>
/// Items that have one more more Repairable component
/// </summary>
public static IReadOnlyCollection<Item> RepairableItems => repairableItems;
private static readonly List<Item> cleanableItems = new List<Item>();
/// <summary>
/// Items that may potentially need to be cleaned up (pickable, not attached to a wall, and not inside a valid container)
/// </summary>
public static IReadOnlyCollection<Item> CleanableItems => cleanableItems;
public new ItemPrefab Prefab => base.Prefab as ItemPrefab;
public static bool ShowLinks = true;
@@ -186,6 +200,7 @@ namespace Barotrauma
if (value != container)
{
container = value;
CheckCleanable();
SetActiveSprite();
}
}
@@ -1009,10 +1024,9 @@ namespace Barotrauma
InsertToList();
ItemList.Add(this);
if (Prefab.IsDangerous)
{
dangerousItems.Add(this);
}
if (Prefab.IsDangerous) { dangerousItems.Add(this); }
if (Repairables.Any()) { repairableItems.Add(this); }
CheckCleanable();
DebugConsole.Log("Created " + Name + " (" + ID + ")");
@@ -1022,6 +1036,9 @@ namespace Barotrauma
ApplyStatusEffects(ActionType.OnSpawn, 1.0f);
Components.ForEach(c => c.ApplyStatusEffects(ActionType.OnSpawn, 1.0f));
RecalculateConditionValues();
#if CLIENT
Submarine.ForceVisibilityRecheck();
#endif
}
partial void InitProjSpecific();
@@ -1150,6 +1167,7 @@ namespace Barotrauma
drawableComponents.Add(drawable);
hasComponentsToDraw = true;
#if CLIENT
Submarine.ForceVisibilityRecheck();
cachedVisibleExtents = null;
#endif
}
@@ -1281,6 +1299,27 @@ namespace Barotrauma
partial void SetActiveSpriteProjSpecific();
/// <summary>
/// Recheck if the item needs to be included in the list of cleanable items
/// </summary>
public void CheckCleanable()
{
var pickable = GetComponent<Pickable>();
if (pickable != null && !pickable.IsAttached &&
Prefab.PreferredContainers.Any() &&
(container == null || container.HasTag("allowcleanup")))
{
if (!cleanableItems.Contains(this))
{
cleanableItems.Add(this);
}
}
else
{
cleanableItems.Remove(this);
}
}
public override void Move(Vector2 amount, bool ignoreContacts = false)
{
if (!MathUtils.IsValid(amount))
@@ -2526,7 +2565,7 @@ namespace Barotrauma
ic.WasUsed = true;
#if CLIENT
ic.PlaySound(ActionType.OnUse, character);
#endif
#endif
ic.ApplyStatusEffects(ActionType.OnUse, deltaTime, character, targetLimb);
if (ic.DeleteOnUse) { remove = true; }
@@ -2704,6 +2743,9 @@ namespace Barotrauma
}
SetContainedItemPositions();
#if CLIENT
Submarine.ForceVisibilityRecheck();
#endif
}
public void Equip(Character character)
@@ -3368,8 +3410,7 @@ namespace Barotrauma
{
ic.ShallowRemove();
}
ItemList.Remove(this);
dangerousItems.Remove(this);
RemoveFromLists();
if (body != null)
{
@@ -3427,8 +3468,8 @@ namespace Barotrauma
ic.GuiFrame = null;
#endif
}
ItemList.Remove(this);
dangerousItems.Remove(this);
RemoveFromLists();
if (body != null)
{
@@ -3461,6 +3502,14 @@ namespace Barotrauma
RemoveProjSpecific();
}
private void RemoveFromLists()
{
ItemList.Remove(this);
dangerousItems.Remove(this);
repairableItems.Remove(this);
cleanableItems.Remove(this);
}
partial void RemoveProjSpecific();
public static void RemoveByPrefab(ItemPrefab prefab)

View File

@@ -463,6 +463,15 @@ namespace Barotrauma.MapCreatures.Behavior
}
}
if (root == null)
{
Branches.ForEach(b => b.DisconnectedFromRoot = true);
}
else
{
CheckDisconnectedFromRoot();
}
void LoadBranch(XElement branchElement, IdRemap idRemap)
{
Vector2 pos = branchElement.GetAttributeVector2("pos", Vector2.Zero);
@@ -649,9 +658,10 @@ namespace Barotrauma.MapCreatures.Behavior
toBeRemoved.Clear();
foreach (BallastFloraBranch branch in Branches)
{
if (branch.ParentBranch != null && (branch.ParentBranch.DisconnectedFromRoot || branch.ParentBranch.Health <= 0.0f))
if (branch.ParentBranch == null || branch.ParentBranch.DisconnectedFromRoot || branch.ParentBranch.Health <= 0.0f)
{
float speed = MathHelper.Lerp(5.0f, 0.1f, branch.ParentBranch.Health / branch.ParentBranch.MaxHealth);
float parentHealth = branch.ParentBranch == null ? 0.0f : branch.ParentBranch.Health / branch.ParentBranch.MaxHealth;
float speed = MathHelper.Lerp(5.0f, 0.1f, parentHealth);
DamageBranch(branch, speed * speed * deltaTime, AttackType.CutFromRoot);
}
if (branch.Health <= 0.0f)
@@ -1071,6 +1081,25 @@ namespace Barotrauma.MapCreatures.Behavior
}
}
private void CheckDisconnectedFromRoot()
{
bool foundDisconnected;
do
{
foundDisconnected = false;
foreach (BallastFloraBranch branch in Branches)
{
if (branch.ParentBranch == null || branch.DisconnectedFromRoot) { continue; }
if (branch.ParentBranch.Removed || branch.ParentBranch.DisconnectedFromRoot)
{
branch.DisconnectedFromRoot = true;
foundDisconnected = true;
}
}
} while (foundDisconnected);
}
public void RemoveBranch(BallastFloraBranch branch)
{
bool isClient = GameMain.NetworkMember != null && GameMain.NetworkMember.IsClient;
@@ -1081,20 +1110,7 @@ namespace Barotrauma.MapCreatures.Behavior
Branches.Remove(branch);
branch.Removed = true;
bool foundDisconnected = false;
do
{
foundDisconnected = false;
foreach (BallastFloraBranch otherBranch in Branches)
{
if (otherBranch.ParentBranch == null || otherBranch.DisconnectedFromRoot) { continue; }
if (otherBranch.ParentBranch.Removed || otherBranch.ParentBranch.DisconnectedFromRoot)
{
otherBranch.DisconnectedFromRoot = true;
foundDisconnected = true;
}
}
} while (foundDisconnected);
CheckDisconnectedFromRoot();
bodies.ForEachMod(body =>
{

View File

@@ -4056,7 +4056,11 @@ namespace Barotrauma
string beaconStationName = System.IO.Path.GetFileNameWithoutExtension(contentFile.Path.Value);
BeaconStation = SpawnSubOnPath(beaconStationName, contentFile, SubmarineType.BeaconStation);
if (BeaconStation == null) { return; }
if (BeaconStation == null)
{
LevelData.HasBeaconStation = false;
return;
}
Item sonarItem = Item.ItemList.Find(it => it.Submarine == BeaconStation && it.GetComponent<Sonar>() != null);
if (sonarItem == null)
@@ -4072,6 +4076,11 @@ namespace Barotrauma
if (!LevelData.HasBeaconStation) { return; }
if (GameMain.NetworkMember?.IsClient ?? false) { return; }
if (BeaconStation == null)
{
throw new InvalidOperationException("Failed to prepare beacon station (no beacon station in the level).");
}
List<Item> beaconItems = Item.ItemList.FindAll(it => it.Submarine == BeaconStation);
Item reactorItem = beaconItems.Find(it => it.GetComponent<Reactor>() != null);

View File

@@ -567,6 +567,10 @@ namespace Barotrauma
/// </summary>
public static void UpdateAll(float deltaTime, Camera cam)
{
#if CLIENT
var sw = new System.Diagnostics.Stopwatch();
sw.Start();
#endif
foreach (Hull hull in Hull.HullList)
{
hull.Update(deltaTime, cam);
@@ -594,6 +598,11 @@ namespace Barotrauma
gapUpdateTimer = 0;
}
#if CLIENT
sw.Stop();
GameMain.PerformanceCounter.AddElapsedTicks("Update:MapEntity:Misc", sw.ElapsedTicks);
sw.Restart();
#endif
Powered.UpdatePower(deltaTime);
foreach (Item item in Item.ItemList)
{
@@ -602,6 +611,11 @@ namespace Barotrauma
UpdateAllProjSpecific(deltaTime);
#if CLIENT
sw.Stop();
GameMain.PerformanceCounter.AddElapsedTicks("Update:MapEntity:Items", sw.ElapsedTicks);
sw.Restart();
#endif
Spawner?.Update();
}

View File

@@ -1857,15 +1857,23 @@ namespace Barotrauma
public void RefreshOutdoorNodes() => OutdoorNodes.ForEach(n => n?.Waypoint?.FindHull());
public Item FindContainerFor(Item item, bool onlyPrimary, bool checkTransferConditions = false)
public Item FindContainerFor(Item item, bool onlyPrimary, bool checkTransferConditions = false, bool allowConnectedSubs = false)
{
var potentialContainers = new List<Item>();
var connectedSubs = GetConnectedSubs().Where(s => s.Info.Type == SubmarineType.Player).ToHashSet();
Item selectedContainer = null;
foreach (Item potentialContainer in Item.ItemList)
{
if (potentialContainer.Removed) { continue; }
if (potentialContainer.NonInteractable) { continue; }
if (potentialContainer.HiddenInGame) { continue; }
if (potentialContainer.Submarine != this) { continue; }
if (allowConnectedSubs)
{
if (!connectedSubs.Contains(potentialContainer.Submarine)) { continue; }
}
else
{
if (potentialContainer.Submarine != this) { continue; }
}
if (potentialContainer == item) { continue; }
if (potentialContainer.Condition <= 0) { continue; }
if (potentialContainer.OwnInventory == null) { continue; }
@@ -1875,13 +1883,15 @@ namespace Barotrauma
if (!potentialContainer.OwnInventory.CanBePut(item)) { continue; }
if (!container.ShouldBeContained(item, out _)) { continue; }
if (!item.Prefab.IsContainerPreferred(item, container, out bool isPreferencesDefined, out bool isSecondary, checkTransferConditions: checkTransferConditions) || !isPreferencesDefined || onlyPrimary && isSecondary) { continue; }
potentialContainers.Add(potentialContainer);
if (!isSecondary)
if (potentialContainer.Submarine == this && !isSecondary)
{
break;
//valid primary container in the same sub -> perfect, let's use that one
return potentialContainer;
}
selectedContainer = potentialContainer;
}
return potentialContainers.LastOrDefault();
return selectedContainer;
}
}
}

View File

@@ -117,6 +117,8 @@ namespace Barotrauma.Networking
set;
}
public ChatMode ChatMode { get; set; } = ChatMode.None;
protected ChatMessage(string senderName, string text, ChatMessageType type, Character sender, Client client, PlayerConnectionChangeType changeType = PlayerConnectionChangeType.None, Color? textColor = null)
{
Text = text;

View File

@@ -23,7 +23,6 @@ namespace Barotrauma
private readonly Dictionary<string, Queue<long>> elapsedTicks = new Dictionary<string, Queue<long>>();
private readonly Dictionary<string, long> avgTicksPerFrame = new Dictionary<string, long>();
private readonly Dictionary<string, Dictionary<string, TickInfo>> partialTickInfos = new Dictionary<string, Dictionary<string, TickInfo>>();
#if CLIENT
internal Graph UpdateTimeGraph = new Graph(500), DrawTimeGraph = new Graph(500);
@@ -43,20 +42,6 @@ namespace Barotrauma
}
}
private readonly List<string> tempSavedPartialIdentifiers = new List<string>();
public IReadOnlyList<string> GetSavedPartialIdentifiers(string parentIdentifier)
{
lock (mutex)
{
tempSavedPartialIdentifiers.Clear();
if (partialTickInfos.TryGetValue(parentIdentifier, out var tickInfos))
{
tempSavedPartialIdentifiers.AddRange(tickInfos.Keys);
}
}
return tempSavedPartialIdentifiers;
}
public void AddElapsedTicks(string identifier, long ticks)
{
lock (mutex)
@@ -72,29 +57,6 @@ namespace Barotrauma
}
}
public void AddPartialElapsedTicks(string parentIdentifier, string identifier, long ticks)
{
lock (mutex)
{
if (!partialTickInfos.TryGetValue(parentIdentifier, out var tickInfos))
{
tickInfos = new Dictionary<string, TickInfo>();
partialTickInfos.Add(parentIdentifier, tickInfos);
}
if (!tickInfos.TryGetValue(identifier, out var tickInfo))
{
tickInfo = new TickInfo();
tickInfos.Add(identifier, tickInfo);
}
tickInfo.ElapsedTicks.Enqueue(ticks);
if (tickInfo.ElapsedTicks.Count > MaximumSamples)
{
tickInfo.ElapsedTicks.Dequeue();
tickInfo.AvgTicksPerFrame = (long)tickInfo.ElapsedTicks.Average(i => i);
}
}
}
public float GetAverageElapsedMillisecs(string identifier)
{
long ticksPerFrame = 0;
@@ -105,18 +67,6 @@ namespace Barotrauma
return ticksPerFrame * 1000.0f / Stopwatch.Frequency;
}
public float GetPartialAverageElapsedMillisecs(string parentIdentifier, string identifier)
{
long ticksPerFrame = 0;
lock (mutex)
{
if (!partialTickInfos.TryGetValue(parentIdentifier, out var tickInfos)) { return 0.0f; }
if (!tickInfos.TryGetValue(identifier, out var tickInfo)) { return 0.0f; }
ticksPerFrame = tickInfo.AvgTicksPerFrame;
}
return ticksPerFrame * 1000.0f / Stopwatch.Frequency;
}
public bool Update(double deltaTime)
{
if (deltaTime == 0.0f) { return false; }

View File

@@ -149,19 +149,19 @@ namespace Barotrauma
#if CLIENT
sw.Stop();
GameMain.PerformanceCounter.AddElapsedTicks("GameSessionUpdate", sw.ElapsedTicks);
GameMain.PerformanceCounter.AddElapsedTicks("Update:GameSession", sw.ElapsedTicks);
sw.Restart();
GameMain.ParticleManager.Update((float)deltaTime);
sw.Stop();
GameMain.PerformanceCounter.AddElapsedTicks("ParticleUpdate", sw.ElapsedTicks);
GameMain.PerformanceCounter.AddElapsedTicks("Update:Particles", sw.ElapsedTicks);
sw.Restart();
if (Level.Loaded != null) Level.Loaded.Update((float)deltaTime, cam);
sw.Stop();
GameMain.PerformanceCounter.AddElapsedTicks("LevelUpdate", sw.ElapsedTicks);
GameMain.PerformanceCounter.AddElapsedTicks("Update:Level", sw.ElapsedTicks);
if (Character.Controlled != null)
{
@@ -193,7 +193,7 @@ namespace Barotrauma
#if CLIENT
sw.Stop();
GameMain.PerformanceCounter.AddElapsedTicks("CharacterUpdate", sw.ElapsedTicks);
GameMain.PerformanceCounter.AddElapsedTicks("Update:Character", sw.ElapsedTicks);
sw.Restart();
#endif
@@ -201,7 +201,7 @@ namespace Barotrauma
#if CLIENT
sw.Stop();
GameMain.PerformanceCounter.AddElapsedTicks("StatusEffectUpdate", sw.ElapsedTicks);
GameMain.PerformanceCounter.AddElapsedTicks("Update:StatusEffects", sw.ElapsedTicks);
sw.Restart();
if (Character.Controlled != null &&
@@ -253,7 +253,7 @@ namespace Barotrauma
#if CLIENT
sw.Stop();
GameMain.PerformanceCounter.AddElapsedTicks("MapEntityUpdate", sw.ElapsedTicks);
GameMain.PerformanceCounter.AddElapsedTicks("Update:MapEntity", sw.ElapsedTicks);
sw.Restart();
#endif
Character.UpdateAnimAll((float)deltaTime);
@@ -266,7 +266,7 @@ namespace Barotrauma
#if CLIENT
sw.Stop();
GameMain.PerformanceCounter.AddElapsedTicks("AnimUpdate", sw.ElapsedTicks);
GameMain.PerformanceCounter.AddElapsedTicks("Update:Ragdolls", sw.ElapsedTicks);
sw.Restart();
#endif
@@ -277,7 +277,7 @@ namespace Barotrauma
#if CLIENT
sw.Stop();
GameMain.PerformanceCounter.AddElapsedTicks("SubmarineUpdate", sw.ElapsedTicks);
GameMain.PerformanceCounter.AddElapsedTicks("Update:Submarine", sw.ElapsedTicks);
sw.Restart();
#endif
@@ -297,7 +297,7 @@ namespace Barotrauma
#if CLIENT
sw.Stop();
GameMain.PerformanceCounter.AddElapsedTicks("Physics", sw.ElapsedTicks);
GameMain.PerformanceCounter.AddElapsedTicks("Update:Physics", sw.ElapsedTicks);
#endif
UpdateProjSpecific(deltaTime);

View File

@@ -1119,7 +1119,12 @@ namespace Barotrauma
itemComponent.SetRequiredItems(element, allowEmpty: true);
break;
}
}
}
if (itemComponent is ItemContainer itemContainer &&
(componentElement.GetChildElement("containable") != null || componentElement.GetChildElement("subcontainer") != null))
{
itemContainer.LoadContainableRestrictions(componentElement);
}
}
}
}

View File

@@ -226,6 +226,7 @@ namespace Barotrauma
{
MusicVolume = 0.3f,
SoundVolume = 0.5f,
UiVolume = 0.3f,
VoiceChatVolume = 0.5f,
VoiceChatCutoffPrevention = 0,
MicrophoneVolume = 5,
@@ -234,7 +235,6 @@ namespace Barotrauma
UseDirectionalVoiceChat = true,
VoipAttenuationEnabled = true,
VoiceSetting = VoiceMode.PushToTalk,
UseLocalVoiceByDefault = false,
DisableVoiceChatFilters = false
};
return audioSettings;
@@ -249,6 +249,7 @@ namespace Barotrauma
public float MusicVolume;
public float SoundVolume;
public float UiVolume;
public float VoiceChatVolume;
public int VoiceChatCutoffPrevention;
public float MicrophoneVolume;
@@ -264,7 +265,6 @@ namespace Barotrauma
public string VoiceCaptureDevice;
public float NoiseGateThreshold;
public bool UseLocalVoiceByDefault;
public bool DisableVoiceChatFilters;
}
@@ -286,12 +286,13 @@ namespace Barotrauma
{ InputType.Aim, MouseButton.SecondaryMouse },
{ InputType.InfoTab, Keys.Tab },
{ InputType.Chat, Keys.T },
{ InputType.RadioChat, Keys.R },
{ InputType.Chat, Keys.None },
{ InputType.RadioChat, Keys.None },
{ InputType.ActiveChat, Keys.T },
{ InputType.CrewOrders, Keys.C },
{ InputType.Voice, Keys.V },
{ InputType.LocalVoice, Keys.B },
{ InputType.ToggleChatMode, Keys.R },
{ InputType.Command, MouseButton.MiddleMouse },
{ InputType.PreviousFireMode, MouseButton.MouseWheelDown },
{ InputType.NextFireMode, MouseButton.MouseWheelUp },
@@ -332,17 +333,35 @@ namespace Barotrauma
if (!bindings.ContainsKey(inputType)) { bindings.Add(inputType, defaultBindings[inputType]); }
}
bool playerConfigContainsNewChatBinds = false;
foreach (XElement element in elements)
{
foreach (XAttribute attribute in element.Attributes())
{
if (Enum.TryParse(attribute.Name.LocalName, out InputType result))
{
if (!playerConfigContainsNewChatBinds)
{
playerConfigContainsNewChatBinds = result == InputType.ActiveChat;
}
bindings[result] = element.GetAttributeKeyOrMouse(attribute.Name.LocalName, bindings[result]);
}
}
}
// Clear the old chat binds for configs saved before the introduction of the new chat binds
if (!playerConfigContainsNewChatBinds)
{
if (bindings.ContainsKey(InputType.Chat))
{
bindings[InputType.Chat] = Keys.None;
}
if (bindings.ContainsKey(InputType.RadioChat))
{
bindings[InputType.RadioChat] = Keys.None;
}
}
Bindings = bindings.ToImmutableDictionary();
}

View File

@@ -157,7 +157,7 @@ namespace Barotrauma
/// Should the item spawn even if the container can't contain items of this type
/// </summary>
public readonly bool SpawnIfCantBeContained;
public readonly float Speed;
public readonly float Impulse;
public readonly float Rotation;
public readonly int Count;
public readonly float Spread;
@@ -198,7 +198,7 @@ namespace Barotrauma
SpawnIfInventoryFull = element.GetAttributeBool("spawnifinventoryfull", false);
SpawnIfCantBeContained = element.GetAttributeBool("spawnifcantbecontained", true);
Speed = element.GetAttributeFloat("speed", 0.0f);
Impulse = element.GetAttributeFloat("impulse", element.GetAttributeFloat("speed", 0.0f));
Condition = MathHelper.Clamp(element.GetAttributeFloat("condition", 1.0f), 0.0f, 1.0f);
@@ -1708,7 +1708,7 @@ namespace Barotrauma
throw new NotImplementedException("Spawn rotation type not implemented: " + chosenItemSpawnInfo.RotationType);
}
body.SetTransform(newItem.SimPosition, rotation);
body.ApplyLinearImpulse(Rand.Vector(1) * chosenItemSpawnInfo.Speed);
body.ApplyLinearImpulse(Rand.Vector(1) * chosenItemSpawnInfo.Impulse);
}
}
newItem.Condition = newItem.MaxCondition * chosenItemSpawnInfo.Condition;

View File

@@ -1,3 +1,38 @@
---------------------------------------------------------------------------------------------------------
v0.18.5.0
---------------------------------------------------------------------------------------------------------
Chat improvements:
- Chat mode (radio/local) can be toggled using a dropdown next to the chat box or with a dedicated "ToggleChatMode" keybind (R by default).
- Voice chat now has only one push-to-talk keybind (V by default) which respects the selected chat mode.
- There's now a dedicated "ActiveChat" keybind (T by default) to open the chat using the currently active chat mode.
- If you want to keep the chat keybinds the way they were (separate keybinds for local and radio), you can rebind the "Chat" and "RadioChat" inputs back to T and R and the new "ToggleChatMode" and "ActiveChat" inputs to something else.
Changes:
- Optimized bot AIs: in particular, the cleanup, repair, pump water and load items objectives. Should significantly improve performance when the bots are doing these objectives when there's a large number of items in the sub.
- Optimized entity culling logic (determines which items/structures are currently visible in the screen).
- Optimized a bunch of textures.
- Improved the performance statistics view that's enabled with the "showperf" console command: more fine-grained stats and easier-to-read visuals.
- Added UI volume slider.
- Depth charges can be stored in coilgun ammo shelves.
Fixes:
- Fixed ballast flora branches that have been disconnected from the root not being considered disconnected after a level transition (allowing them to keep growing).
- Fixed "set default bindings" not doing anything in the settings menu.
- Fixed door/hatch gaps not getting moved when snapping to grid in the sub editor.
- Vertically mirrored beds can't be laid on.
- Fixed wrecked reactors being forced to non-interactable even if made interactable in the sub editor.
Unstable only:
- Fixed crashing when you try to edit beacon station settings on a station you haven't saved yet.
- Fixed level difficulties being incorrect in the "normal" difficulty setting (levels were set to the minimum difficulty of the biome, instead of a linear increase across the biome).
- Misc fixes and improvements to the new beacon stations.
- Fixed "max missions per round" value not being restricted in the UI.
- Fixed items not getting transferred to/from linked subs.
Modding:
- Doors and hatches can now be mirrored in the sub editor (making them open from top to bottom, or from right to left).
---------------------------------------------------------------------------------------------------------
v0.18.4.0
---------------------------------------------------------------------------------------------------------
@@ -12,6 +47,7 @@ Unstable only:
- Fixed sprite editor crashing if you try to reload a texture twice.
- Fixed drone/shuttles getting left behind in the outpost when you buy and switch to a sub that has a one.
- Fixed crashing when closing the submarine preview window.
- Disallowed mirroring beds vertically.
Changes:
- Added some new campaign settings: starting balance, amount of starting items and difficulty.
@@ -19,13 +55,17 @@ Changes:
- Made the descriptions of some materials (that used to just say "useful for crafting") more descriptive.
- Increased oxygen generator output in some vanilla subs.
- Made handheld sonar beacon sound less grating.
- Disallowed mirroring beds vertically.
- The client who initiated a vote cannot take part in that vote (except if they're the only client who can vote, in which case the vote automatically passes).
- Made flashlight flicker before the battery runs out.
- Added some lootable money to corpses found in wrecks.
- Removed the small equipment indicators next to the character portrait.
- Added a bunch of new UI sounds (tickbox toggling, confirming transactions, increase/decrease sounds for number inputs, cart sound for adding/removing items in store interfaces, selecting/clicking components, sliders and modlist).
- Optimized many status effects by making them only execute once per second instead of every frame (most importantly, diving suits and volatile fuel rods).
- Optimized talents: buffs are applied to characters periodically instead of every frame.
- Optimized the logic that bots use to determine the safety of hulls.
- Optimized items: stop updating items that don't need to be updated more aggressively.
- Weapon holders now use the tag "mountableweapon" instead of "weapon" to determine which items can be placed in them. Allows tagging non-weapon items as mountable in the holder, without making bots consider it a weapon due to the "weapon" tag. Also allows to keep some weapons not-mountable.
- Ammunition Shelf can now also store Depth Charges ("depthchargeammo" tag added)
Fixes:
- Split campaign state networking messages into multiple ones. Previously all the campaign-related data (map state, reputation, upgrades, purchased items, selected missions) was included in the same message, and whenever anything in the data changed, the server would send all of it to clients. This would cause performance and bandwidth issues in some situations, for example when reputation was changing rapidly.