Build 0.20.10.0

This commit is contained in:
Markus Isberg
2022-12-05 19:48:59 +02:00
parent 31d2dc658e
commit 9d2f160314
55 changed files with 335 additions and 3511 deletions
@@ -174,9 +174,9 @@ namespace Barotrauma
Character.DisableControls = true;
if (PlayerInput.KeyHit(Keys.Tab))
if (PlayerInput.KeyHit(Keys.Tab) && !textBox.IsIMEActive)
{
textBox.Text = AutoComplete(textBox.Text, increment: string.IsNullOrEmpty(currentAutoCompletedCommand) ? 0 : 1 );
textBox.Text = AutoComplete(textBox.Text, increment: string.IsNullOrEmpty(currentAutoCompletedCommand) ? 0 : 1 );
}
if (PlayerInput.KeyDown(Keys.LeftControl) || PlayerInput.KeyDown(Keys.RightControl))
@@ -1,72 +1,18 @@
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
using System;
using System.Runtime.InteropServices;
using System.Text;
namespace EventInput
{
public class CharacterEventArgs : EventArgs
public readonly record struct CharacterEventArgs(char Character, long Param)
{
private readonly char character;
private readonly long lParam;
public CharacterEventArgs(char character, long lParam)
{
this.character = character;
this.lParam = lParam;
}
public char Character
{
get { return character; }
}
public long Param
{
get { return lParam; }
}
public long RepeatCount
{
get { return lParam & 0xffff; }
}
public bool ExtendedKey
{
get { return (lParam & (1 << 24)) > 0; }
}
public bool AltPressed
{
get { return (lParam & (1 << 29)) > 0; }
}
public bool PreviousState
{
get { return (lParam & (1 << 30)) > 0; }
}
public bool TransitionState
{
get { return (lParam & (1 << 31)) > 0; }
}
public long RepeatCount => Param & 0xffff;
public bool ExtendedKey => (Param & (1 << 24)) > 0;
public bool AltPressed => (Param & (1 << 29)) > 0;
public bool PreviousState => (Param & (1 << 30)) > 0;
public bool TransitionState => (Param & (1 << 31)) > 0;
}
public class KeyEventArgs : EventArgs
{
private Keys keyCode;
public KeyEventArgs(Keys keyCode)
{
this.keyCode = keyCode;
}
public Keys KeyCode
{
get { return keyCode; }
}
}
public readonly record struct KeyEventArgs(Keys KeyCode, char Character);
public delegate void CharEnteredHandler(object sender, CharacterEventArgs e);
public delegate void KeyEventHandler(object sender, KeyEventArgs e);
@@ -89,14 +35,11 @@ namespace EventInput
/// </summary>
public static event KeyEventHandler KeyUp;
#if !WINDOWS
/// <summary>
/// Raised when the user is editing text and IME is in progress.
/// Windows build uses ImeSharp instead because SDL2's IME implementation is broken on Windows (https://github.com/libsdl-org/SDL/issues/2243)
/// </summary>
public static event EditingTextHandler EditingText;
#endif
static bool initialized;
@@ -110,11 +53,10 @@ namespace EventInput
{
return;
}
window.TextInput += ReceiveInput;
#if !WINDOWS
window.KeyDown += ReceiveKeyDown;
window.TextEditing += ReceiveTextEditing;
#endif
initialized = true;
}
@@ -122,15 +64,17 @@ namespace EventInput
private static void ReceiveInput(object sender, TextInputEventArgs e)
{
OnCharEntered(e.Character);
KeyDown?.Invoke(sender, new KeyEventArgs(e.Key));
}
#if !WINDOWS
private static void ReceiveKeyDown(object sender, TextInputEventArgs e)
{
KeyDown?.Invoke(sender, new KeyEventArgs(e.Key, e.Character));
}
private static void ReceiveTextEditing(object sender, TextEditingEventArgs e)
{
EditingText?.Invoke(sender, e);
}
#endif
public static void OnCharEntered(char character)
{
@@ -10,11 +10,7 @@ namespace EventInput
void ReceiveTextInput(string text);
void ReceiveCommandInput(char command);
void ReceiveSpecialInput(Keys key);
#if !WINDOWS
/// Windows build uses ImeSharp instead because SDL2's IME implementation is broken on Windows (https://github.com/libsdl-org/SDL/issues/2243)
void ReceiveEditingInput(string text, int start);
#endif
void ReceiveEditingInput(string text, int start, int length);
bool Selected { get; set; } //or Focused
}
@@ -26,59 +22,27 @@ namespace EventInput
EventInput.Initialize(window);
EventInput.CharEntered += EventInput_CharEntered;
EventInput.KeyDown += EventInput_KeyDown;
#if !WINDOWS
EventInput.EditingText += EventInput_TextEditing;
#endif
/*
* SDL by default starts in a state where it accepts IME inputs
* this is bad because this blocks keybinds since the IME thinks
* it's typing in a text box and not forwarding keybinds to the game.
*/
TextInput.StopTextInput();
GameMain.ResetIMEWorkaround();
}
#if !WINDOWS
public void EventInput_TextEditing(object sender, TextEditingEventArgs e)
{
_subscriber?.ReceiveEditingInput(e.Text, e.Start);
_subscriber?.ReceiveEditingInput(e.Text, e.Start, e.Length);
}
#endif
public void EventInput_KeyDown(object sender, KeyEventArgs e)
{
_subscriber?.ReceiveSpecialInput(e.KeyCode);
if (char.IsControl(e.Character))
{
_subscriber?.ReceiveCommandInput(e.Character);
}
}
void EventInput_CharEntered(object sender, CharacterEventArgs e)
{
if (_subscriber == null)
return;
if (char.IsControl(e.Character))
{
_subscriber.ReceiveCommandInput(e.Character);
// Doesn't work as expected. Not sure why this should be run in a separate thread.
//#if WINDOWS
// //ctrl-v
// if (e.Character == 0x16) // 22
// {
// //XNA runs in Multiple Thread Apartment state, which cannot recieve clipboard
// Thread thread = new Thread(PasteThread);
// thread.SetApartmentState(ApartmentState.STA);
// thread.Start();
// thread.Join();
// _subscriber.ReceiveTextInput(_pasteResult);
// }
// else
// {
// _subscriber.ReceiveCommandInput(e.Character);
// }
//#else
// _subscriber.ReceiveCommandInput(e.Character);
//#endif
}
else
{
_subscriber.ReceiveTextInput(e.Character);
}
_subscriber?.ReceiveTextInput(e.Character);
}
IKeyboardSubscriber _subscriber;
@@ -97,8 +61,9 @@ namespace EventInput
if (value is GUITextBox box)
{
TextInput.SetTextInputRect(box.Rect);
TextInput.SetTextInputRect(box.MouseRect);
TextInput.StartTextInput();
TextInput.SetTextInputRect(box.MouseRect);
}
_subscriber = value;
@@ -1261,10 +1261,6 @@ namespace Barotrauma
UpdateMessages(deltaTime);
UpdateSavingIndicator(deltaTime);
}
#if WINDOWS
GUITextBox.UpdateIME();
#endif
}
public static void UpdateGUIMessageBoxesOnly(float deltaTime)
@@ -111,10 +111,7 @@ namespace Barotrauma
}
public void ReceiveTextInput(string text) { }
public void ReceiveCommandInput(char command) { }
#if !WINDOWS
public void ReceiveEditingInput(string text, int start) { }
#endif
public void ReceiveEditingInput(string text, int start, int length) { }
public void ReceiveSpecialInput(Keys key)
{
@@ -125,9 +122,7 @@ namespace Barotrauma
listBox.ReceiveSpecialInput(key);
GUI.KeyboardDispatcher.Subscriber = this;
break;
case Keys.Enter:
case Keys.Space:
case Keys.Escape:
default:
GUI.KeyboardDispatcher.Subscriber = null;
break;
}
@@ -1347,10 +1347,7 @@ namespace Barotrauma
}
public void ReceiveTextInput(string text) { }
public void ReceiveCommandInput(char command) { }
#if !WINDOWS
public void ReceiveEditingInput(string text, int start) { }
#endif
public void ReceiveEditingInput(string text, int start, int length) { }
public void ReceiveSpecialInput(Keys key)
{
@@ -1368,9 +1365,7 @@ namespace Barotrauma
case Keys.Right:
if (isHorizontal && AllowArrowKeyScroll) { SelectNext(playSelectSound: PlaySelectSound.Yes); }
break;
case Keys.Enter:
case Keys.Space:
case Keys.Escape:
default:
GUI.KeyboardDispatcher.Subscriber = null;
break;
}
@@ -223,24 +223,24 @@ namespace Barotrauma
public ScalableFont GetFontForStr(string str) =>
Prefabs.ActivePrefab.GetFontForCategory(TextManager.GetSpeciallyHandledCategories(str));
public void DrawString(SpriteBatch sb, LocalizedString text, Vector2 position, Color color, float rotation, Vector2 origin, Vector2 scale, SpriteEffects se, float layerDepth)
public void DrawString(SpriteBatch sb, LocalizedString text, Vector2 position, Color color, float rotation, Vector2 origin, Vector2 scale, SpriteEffects spriteEffects, float layerDepth)
{
DrawString(sb, text.Value, position, color, rotation, origin, scale, se, layerDepth);
DrawString(sb, text.Value, position, color, rotation, origin, scale, spriteEffects, layerDepth);
}
public void DrawString(SpriteBatch sb, string text, Vector2 position, Color color, float rotation, Vector2 origin, Vector2 scale, SpriteEffects se, float layerDepth)
public void DrawString(SpriteBatch sb, string text, Vector2 position, Color color, float rotation, Vector2 origin, Vector2 scale, SpriteEffects spriteEffects, float layerDepth)
{
GetFontForStr(text).DrawString(sb, text, position, color, rotation, origin, scale, se, layerDepth);
GetFontForStr(text).DrawString(sb, text, position, color, rotation, origin, scale, spriteEffects, layerDepth);
}
public void DrawString(SpriteBatch sb, LocalizedString text, Vector2 position, Color color, float rotation, Vector2 origin, float scale, SpriteEffects se, float layerDepth, Alignment alignment = Alignment.TopLeft)
public void DrawString(SpriteBatch sb, LocalizedString text, Vector2 position, Color color, float rotation, Vector2 origin, float scale, SpriteEffects spriteEffects, float layerDepth, Alignment alignment = Alignment.TopLeft)
{
DrawString(sb, text.Value, position, color, rotation, origin, scale, se, layerDepth, alignment);
DrawString(sb, text.Value, position, color, rotation, origin, scale, spriteEffects, layerDepth, alignment);
}
public void DrawString(SpriteBatch sb, string text, Vector2 position, Color color, float rotation, Vector2 origin, float scale, SpriteEffects se, float layerDepth, Alignment alignment = Alignment.TopLeft, ForceUpperCase forceUpperCase = Barotrauma.ForceUpperCase.Inherit)
public void DrawString(SpriteBatch sb, string text, Vector2 position, Color color, float rotation, Vector2 origin, float scale, SpriteEffects spriteEffects, float layerDepth, Alignment alignment = Alignment.TopLeft, ForceUpperCase forceUpperCase = Barotrauma.ForceUpperCase.Inherit)
{
GetFontForStr(text).DrawString(sb, text, position, color, rotation, origin, scale, se, layerDepth, alignment, forceUpperCase);
GetFontForStr(text).DrawString(sb, text, position, color, rotation, origin, scale, spriteEffects, layerDepth, alignment, forceUpperCase);
}
public void DrawString(SpriteBatch sb, LocalizedString text, Vector2 position, Color color, ForceUpperCase forceUpperCase = Barotrauma.ForceUpperCase.Inherit, bool italics = false)
@@ -253,9 +253,9 @@ namespace Barotrauma
GetFontForStr(text).DrawString(sb, text, position, color, forceUpperCase, italics);
}
public void DrawStringWithColors(SpriteBatch sb, string text, Vector2 position, Color color, float rotation, Vector2 origin, float scale, SpriteEffects se, float layerDepth, in ImmutableArray<RichTextData>? richTextData, int rtdOffset = 0, Alignment alignment = Alignment.TopLeft, ForceUpperCase forceUpperCase = Barotrauma.ForceUpperCase.Inherit)
public void DrawStringWithColors(SpriteBatch sb, string text, Vector2 position, Color color, float rotation, Vector2 origin, float scale, SpriteEffects spriteEffects, float layerDepth, in ImmutableArray<RichTextData>? richTextData, int rtdOffset = 0, Alignment alignment = Alignment.TopLeft, ForceUpperCase forceUpperCase = Barotrauma.ForceUpperCase.Inherit)
{
GetFontForStr(text).DrawStringWithColors(sb, text, position, color, rotation, origin, scale, se, layerDepth, richTextData, rtdOffset, alignment, forceUpperCase);
GetFontForStr(text).DrawStringWithColors(sb, text, position, color, rotation, origin, scale, spriteEffects, layerDepth, richTextData, rtdOffset, alignment, forceUpperCase);
}
public Vector2 MeasureString(LocalizedString str, bool removeExtraSpacing = false)
@@ -256,6 +256,8 @@ namespace Barotrauma
private readonly IMEPreviewTextHandler imePreviewTextHandler;
public bool IsIMEActive => imePreviewTextHandler is { HasText: true };
public GUITextBox(RectTransform rectT, string text = "", Color? textColor = null, GUIFont font = null,
Alignment textAlignment = Alignment.Left, bool wrap = false, string style = "", Color? color = null, bool createClearButton = false, bool createPenIcon = true)
: base(style, rectT)
@@ -574,6 +576,7 @@ namespace Barotrauma
{
CaretIndex = Math.Min(Text.Length, CaretIndex + input.Length);
OnTextChanged?.Invoke(this, Text);
imePreviewTextHandler?.Reset();
}
}
@@ -602,10 +605,12 @@ namespace Barotrauma
public void ReceiveCommandInput(char command)
{
if (Text == null) Text = "";
if (IsIMEActive) { return; }
if (Text == null) { Text = ""; }
// Prevent alt gr from triggering any of these as that combination is often needed for special characters
if (PlayerInput.IsAltDown()) return;
if (PlayerInput.IsAltDown()) { return; }
switch (command)
{
@@ -678,21 +683,22 @@ namespace Barotrauma
break;
}
}
#if !WINDOWS
public void ReceiveEditingInput(string text, int start)
public void ReceiveEditingInput(string text, int start, int length)
{
if (string.IsNullOrEmpty(text))
{
if (start is 0) { imePreviewTextHandler.Reset(); }
imePreviewTextHandler.Reset();
return;
}
imePreviewTextHandler.UpdateText(text, start);
imePreviewTextHandler.UpdateText(text, start, length);
}
#endif
public void ReceiveSpecialInput(Keys key)
{
if (IsIMEActive) { return; }
switch (key)
{
case Keys.Left:
@@ -883,20 +889,7 @@ namespace Barotrauma
public void DrawIMEPreview(SpriteBatch spriteBatch)
{
if (!imePreviewTextHandler.HasText) { return; }
Vector2 imePosition = CaretScreenPos;
int inflate = GUI.IntScale(3);
RectangleF rect = new RectangleF(imePosition, imePreviewTextHandler.TextSize);
rect.Inflate(inflate, inflate);
RectangleF borderRect = rect;
borderRect.Inflate(1, 1);
GUI.DrawFilledRectangle(spriteBatch, borderRect, Color.White, depth: 0.02f);
GUI.DrawFilledRectangle(spriteBatch, rect, Color.Black, depth: 0.01f);
Font.DrawString(spriteBatch, imePreviewTextHandler.PreviewText, imePosition, GUIStyle.Orange, 0.0f, Vector2.Zero, 1f, SpriteEffects.None, 0, alignment: textBlock.TextAlignment, forceUpperCase: textBlock.ForceUpperCase);
imePreviewTextHandler.DrawIMEPreview(spriteBatch, CaretScreenPos, textBlock);
}
private void CalculateSelection()
@@ -1,86 +0,0 @@
using ImeSharp;
using Microsoft.Xna.Framework;
using System;
namespace Barotrauma;
/// <summary>
/// A class for handling Input Method Editor (used for inputting e.g. Chinese and Japanese text)
/// </summary>
public partial class GUITextBox : GUIComponent
{
private static bool initialized;
public static GUIFrame IMEWindow { get; set; }
public static GUITextBlock IMETextBlock { get; set; }
public static void UpdateIME()
{
if (!initialized) { InitializeIME(); }
if (GUI.KeyboardDispatcher.Subscriber is GUITextBox { Selected: true })
{
IMEWindow?.AddToGUIUpdateList(order: 10);
}
}
private static void InitializeIME()
{
InputMethod.Initialize(GameMain.Instance.Window.Hwnd, false);
InputMethod.TextCompositionCallback = OnTextComposition;
InputMethod.CommitTextCompositionCallback = OnCommitTextComposition;
InputMethod.Enabled = true;
IMEWindow = new GUIFrame(new RectTransform(new Point(GUI.IntScale(300), GUI.IntScale(300)), GUI.Canvas), "InnerFrame") { CanBeFocused = false, Visible = false };
IMETextBlock = new GUITextBlock(new RectTransform(Vector2.One, IMEWindow.RectTransform), "") { CanBeFocused = false };
initialized = true;
}
private static void OnTextComposition(IMEString compositionText, int cursorPosition, IMEString[] candidateList, int candidatePageStart, int candidatePageSize, int candidateSelection)
{
if (GUI.KeyboardDispatcher.Subscriber is not GUITextBox { Selected: true } textBox) { return; }
IMEWindow.Visible = true;
string text = compositionText.ToString().Insert(cursorPosition, "|");
if (candidateList != null)
{
text += "\n";
for (int i = 0; i < candidatePageSize; i++)
{
string candidateStr = $"\t{candidatePageStart + i + 1} {candidateList[i]}";
if (candidateSelection == i)
{
candidateStr = $" ‖color:{XMLExtensions.ToStringHex(Color.White)}‖{candidateStr}‖end‖";
}
candidateStr += "\n";
text += candidateStr;
}
}
IMETextBlock.Text = RichString.Rich(text);
IMEWindow.RectTransform.NonScaledSize = new Point(
Math.Max(IMEWindow.Rect.Width, (int)IMETextBlock.TextSize.X + GUI.IntScale(32)),
(int)IMETextBlock.TextSize.Y);
Point windowPos = new Point(textBox.Rect.X, textBox.Rect.Bottom);
if (windowPos.Y + IMEWindow.Rect.Height > GameMain.GraphicsHeight)
{
windowPos.Y = textBox.Rect.Y - IMEWindow.Rect.Height;
}
IMEWindow.RectTransform.ScreenSpaceOffset = windowPos;
}
private static void OnCommitTextComposition(string text)
{
if (IMEWindow.Visible)
{
foreach (char c in text)
{
if (!char.IsControl(c))
{
GUI.KeyboardDispatcher.Subscriber?.ReceiveTextInput(c);
}
}
}
IMEWindow.Visible = false;
}
}
@@ -1,18 +1,25 @@
#nullable enable
using System.Collections.Immutable;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
namespace Barotrauma
{
public sealed class IMEPreviewTextHandler
{
public string PreviewText { get; private set; } = string.Empty;
public Vector2 TextSize { get; private set; }
public bool HasText => !string.IsNullOrEmpty(PreviewText);
public bool HasText => !string.IsNullOrEmpty(previewText);
// This has to be settable because for some reason we update the font of GUITextBox in some places
public GUIFont Font { get; set; }
private string previewText = string.Empty;
private Vector2 textSize;
private bool isSectioned;
private ImmutableArray<RichTextData>? richTextData;
public IMEPreviewTextHandler(GUIFont font)
{
Font = font;
@@ -20,35 +27,64 @@ namespace Barotrauma
public void Reset()
{
TextSize = Vector2.Zero;
PreviewText = string.Empty;
textSize = Vector2.Zero;
previewText = string.Empty;
richTextData = null;
isSectioned = false;
}
public void UpdateText(string text, int start)
public void UpdateText(string text, int start, int length)
{
if (string.IsNullOrEmpty(text) && start is 0)
isSectioned = start >= 0 && length > 0;
richTextData = null;
if (string.IsNullOrEmpty(text))
{
Reset();
return;
}
int totalLength = start + text.Length;
string newText = PreviewText;
if (newText.Length > totalLength)
{
newText = newText[..totalLength];
}
previewText = text;
if (totalLength > newText.Length)
{
// this is required for some reason on Windows
// my guess is that the order which TextEditing events come thru is not guaranteed
newText = newText.PadRight(totalLength);
}
textSize = Font.MeasureString(text);
newText = newText.Remove(start, text.Length).Insert(start, text);
PreviewText = newText;
TextSize = Font.MeasureString(PreviewText);
if (!isSectioned) { return; }
string coloredText = ToolBox.ColorSectionOfString(text, start, length, GUIStyle.Orange);
RichString richString = RichString.Rich(coloredText);
previewText = richString.SanitizedValue;
richTextData = richString.RichTextData;
}
public void DrawIMEPreview(SpriteBatch spriteBatch, Vector2 position, GUITextBlock textBlock)
{
if (!HasText) { return; }
int inflate = GUI.IntScale(3);
RectangleF rect = new RectangleF(position, textSize);
rect.Inflate(inflate, inflate);
RectangleF borderRect = rect;
borderRect.Inflate(1, 1);
GUI.DrawFilledRectangle(spriteBatch, borderRect, Color.White, depth: 0.02f);
GUI.DrawFilledRectangle(spriteBatch, rect, Color.Black, depth: 0.01f);
Font.DrawStringWithColors(spriteBatch,
text: previewText,
position: position,
color: isSectioned ? GUIStyle.TextColorNormal : GUIStyle.Orange,
rotation: 0.0f,
origin: Vector2.Zero,
scale: 1f,
spriteEffects: SpriteEffects.None,
layerDepth: 0,
richTextData: richTextData,
alignment: textBlock.TextAlignment,
forceUpperCase: textBlock.ForceUpperCase);
}
}
}
@@ -377,6 +377,7 @@ namespace Barotrauma
Hyper.ComponentModel.HyperTypeDescriptionProvider.Add(typeof(Hull));
performanceCounterTimer = Stopwatch.StartNew();
ResetIMEWorkaround();
}
/// <summary>
@@ -1239,5 +1240,20 @@ namespace Barotrauma
};
msgBox.Buttons[1].OnClicked = msgBox.Close;
}
/*
* On some systems, IME input is enabled by default, and being able to set the game to a state
* where it doesn't accept IME input on game launch seems very inconsistent.
* This function quickly cycles through IME input states and is called from couple different places
* to ensure that IME input is disabled properly when it's not needed.
*/
public static void ResetIMEWorkaround()
{
Rectangle rect = new Rectangle(0, 0, GraphicsWidth, GraphicsHeight);
TextInput.SetTextInputRect(rect);
TextInput.StartTextInput();
TextInput.SetTextInputRect(rect);
TextInput.StopTextInput();
}
}
}
@@ -999,6 +999,7 @@ namespace Barotrauma
foreach (MapEntityCategory category in Enum.GetValues(typeof(MapEntityCategory)))
{
if (category == MapEntityCategory.None) { continue; }
entityCategoryButtons.Add(new GUIButton(new RectTransform(new Vector2(1.0f, 1.0f), entityMenuTop.RectTransform, scaleBasis: ScaleBasis.BothHeight),
"", style: "CategoryButton." + category.ToString())
{
@@ -1085,6 +1086,7 @@ namespace Barotrauma
foreach (MapEntityCategory category in Enum.GetValues(typeof(MapEntityCategory)))
{
if (category == MapEntityCategory.None) { continue; }
LocalizedString categoryName = TextManager.Get("MapEntityCategory." + category);
maxTextWidth = (int)Math.Max(maxTextWidth, GUIStyle.SubHeadingFont.MeasureString(categoryName.Replace(" ", "\n")).X + GUI.IntScale(50));
foreach (MapEntityPrefab ep in MapEntityPrefab.List)
@@ -863,22 +863,21 @@ namespace Barotrauma
PlayDamageSound(damageType, damage, bodyPosition, 800.0f);
}
private static readonly List<DamageSound> tempList = new List<DamageSound>();
public static void PlayDamageSound(string damageType, float damage, Vector2 position, float range = 2000.0f, IEnumerable<Identifier> tags = null)
{
damage = MathHelper.Clamp(damage + Rand.Range(-10.0f, 10.0f), 0.0f, 100.0f);
tempList.Clear();
foreach (var s in damageSounds)
{
if ((s.DamageRange == Vector2.Zero ||
(damage >= s.DamageRange.X && damage <= s.DamageRange.Y)) &&
s.DamageType == damageType &&
(s.RequiredTag.IsEmpty || (tags == null ? s.RequiredTag.IsEmpty : tags.Contains(s.RequiredTag))))
{
tempList.Add(s);
}
}
var damageSound = tempList.GetRandomUnsynced();
//if the damage is too low for any sound, don't play anything
if (damageSounds.All(d => damage < d.DamageRange.X)) { return; }
//allow the damage to differ by 10 from the configured damage range,
//so the same amount of damage doesn't always play the same sound
float randomizedDamage = MathHelper.Clamp(damage + Rand.Range(-10.0f, 10.0f), 0.0f, 100.0f);
var suitableSounds = damageSounds.Where(s =>
s.DamageType == damageType &&
(s.DamageRange == Vector2.Zero || (randomizedDamage >= s.DamageRange.X && randomizedDamage <= s.DamageRange.Y)) &&
(s.RequiredTag.IsEmpty || (tags == null ? s.RequiredTag.IsEmpty : tags.Contains(s.RequiredTag))));
var damageSound = suitableSounds.GetRandomUnsynced();
damageSound?.Sound?.Play(1.0f, range, position, muffle: !damageSound.IgnoreMuffling && ShouldMuffleSound(Character.Controlled, position, range, null));
}
@@ -512,5 +512,34 @@ namespace Barotrauma
return new Vector2(paddingX, paddingY);
}
public static string ColorSectionOfString(string text, int start, int length, Color color)
{
int end = start + length;
if (start < 0 || length < 0 || end > text.Length)
{
throw new ArgumentOutOfRangeException($"Invalid start ({start}) or length ({length}) for text \"{text}\".");
}
string stichedString = string.Empty;
if (start > 0)
{
stichedString += text[..start];
}
// this is the highlighted part
stichedString += ColorString(text[start..end], color);
if (end < text.Length)
{
stichedString += text[end..];
}
return stichedString;
static string ColorString(string text, Color color) => $"‖color:{color.ToStringHex()}‖{text}‖end‖";
}
}
}