Faction Test 100.9.0.0

This commit is contained in:
Markus Isberg
2022-12-05 19:55:31 +02:00
parent f7f1ebd979
commit 55e1d3560a
55 changed files with 347 additions and 3512 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;
@@ -1248,10 +1248,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)
@@ -902,22 +902,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‖";
}
}
}
@@ -6,7 +6,7 @@
<RootNamespace>Barotrauma</RootNamespace>
<Authors>FakeFish, Undertow Games</Authors>
<Product>Barotrauma</Product>
<Version>100.8.0.0</Version>
<Version>100.9.0.0</Version>
<Copyright>Copyright © FakeFish 2018-2022</Copyright>
<Platforms>AnyCPU;x64</Platforms>
<AssemblyName>Barotrauma</AssemblyName>
+1 -1
View File
@@ -6,7 +6,7 @@
<RootNamespace>Barotrauma</RootNamespace>
<Authors>FakeFish, Undertow Games</Authors>
<Product>Barotrauma</Product>
<Version>100.8.0.0</Version>
<Version>100.9.0.0</Version>
<Copyright>Copyright © FakeFish 2018-2022</Copyright>
<Platforms>AnyCPU;x64</Platforms>
<AssemblyName>Barotrauma</AssemblyName>
@@ -6,7 +6,7 @@
<RootNamespace>Barotrauma</RootNamespace>
<Authors>FakeFish, Undertow Games</Authors>
<Product>Barotrauma</Product>
<Version>100.8.0.0</Version>
<Version>100.9.0.0</Version>
<Copyright>Copyright © FakeFish 2018-2022</Copyright>
<Platforms>AnyCPU;x64</Platforms>
<AssemblyName>Barotrauma</AssemblyName>
@@ -117,7 +117,6 @@
<ProjectReference Include="..\..\Libraries\Lidgren.Network\Lidgren.NetStandard.csproj" AdditionalProperties="Configuration=Release" />
<ProjectReference Include="..\..\Libraries\MonoGame.Framework\Src\MonoGame.Framework\MonoGame.Framework.Windows.NetStandard.csproj" AdditionalProperties="Configuration=Release" />
<ProjectReference Include="..\..\Libraries\SharpFont\Source\SharpFont\SharpFont.NetStandard.csproj" AdditionalProperties="Configuration=Release" />
<ProjectReference Include="..\..\Libraries\ImeSharp\ImeSharp.csproj" AdditionalProperties="Configuration=Release" />
</ItemGroup>
<ItemGroup Condition="'$(Configuration)'=='Debug'">
<ProjectReference Include="..\..\Libraries\Concentus\CSharp\Concentus\Concentus.NetStandard.csproj" AdditionalProperties="Configuration=Debug" />
@@ -127,7 +126,6 @@
<ProjectReference Include="..\..\Libraries\Lidgren.Network\Lidgren.NetStandard.csproj" AdditionalProperties="Configuration=Debug" />
<ProjectReference Include="..\..\Libraries\MonoGame.Framework\Src\MonoGame.Framework\MonoGame.Framework.Windows.NetStandard.csproj" AdditionalProperties="Configuration=Debug" />
<ProjectReference Include="..\..\Libraries\SharpFont\Source\SharpFont\SharpFont.NetStandard.csproj" AdditionalProperties="Configuration=Debug" />
<ProjectReference Include="..\..\Libraries\ImeSharp\ImeSharp.csproj" AdditionalProperties="Configuration=Debug" />
</ItemGroup>
<ItemGroup>
Binary file not shown.
Binary file not shown.
@@ -6,7 +6,7 @@
<RootNamespace>Barotrauma</RootNamespace>
<Authors>FakeFish, Undertow Games</Authors>
<Product>Barotrauma Dedicated Server</Product>
<Version>100.8.0.0</Version>
<Version>100.9.0.0</Version>
<Copyright>Copyright © FakeFish 2018-2022</Copyright>
<Platforms>AnyCPU;x64</Platforms>
<AssemblyName>DedicatedServer</AssemblyName>
+1 -1
View File
@@ -6,7 +6,7 @@
<RootNamespace>Barotrauma</RootNamespace>
<Authors>FakeFish, Undertow Games</Authors>
<Product>Barotrauma Dedicated Server</Product>
<Version>100.8.0.0</Version>
<Version>100.9.0.0</Version>
<Copyright>Copyright © FakeFish 2018-2022</Copyright>
<Platforms>AnyCPU;x64</Platforms>
<AssemblyName>DedicatedServer</AssemblyName>
@@ -6,7 +6,7 @@
<RootNamespace>Barotrauma</RootNamespace>
<Authors>FakeFish, Undertow Games</Authors>
<Product>Barotrauma Dedicated Server</Product>
<Version>100.8.0.0</Version>
<Version>100.9.0.0</Version>
<Copyright>Copyright © FakeFish 2018-2022</Copyright>
<Platforms>AnyCPU;x64</Platforms>
<AssemblyName>DedicatedServer</AssemblyName>
@@ -30,8 +30,7 @@ namespace Barotrauma.Abilities
NotSelf = 3,
Alive = 4,
Monster = 5,
InFriendlySubmarine = 6,
Large = 7,
InFriendlySubmarine = 6
};
protected List<TargetType> ParseTargetTypes(string[] targetTypeStrings)
@@ -80,9 +79,6 @@ namespace Barotrauma.Abilities
return !targetCharacter.IsHuman;
case TargetType.InFriendlySubmarine:
return targetCharacter.Submarine != null && targetCharacter.Submarine.TeamID == character.TeamID;
case TargetType.Large:
// mass of mudraptor is ~48
return targetCharacter.AnimController is { Mass: > 50.0f };
default:
return true;
}
@@ -1,21 +1,25 @@
using System;
using Barotrauma.Extensions;
using System;
using System.Collections.Immutable;
using System.Linq;
namespace Barotrauma.Abilities
{
class AbilityConditionItem : AbilityConditionData
{
private readonly string[] identifiers;
private readonly string[] tags;
private readonly ImmutableArray<Identifier> identifiers;
private readonly ImmutableArray<Identifier> tags;
private readonly MapEntityCategory category = MapEntityCategory.None;
public AbilityConditionItem(CharacterTalent characterTalent, ContentXElement conditionElement) : base(characterTalent, conditionElement)
{
identifiers = conditionElement.GetAttributeStringArray("identifiers", Array.Empty<string>(), convertToLowerInvariant: true);
tags = conditionElement.GetAttributeStringArray("tags", Array.Empty<string>(), convertToLowerInvariant: true);
identifiers = conditionElement.GetAttributeIdentifierArray("identifiers", Array.Empty<Identifier>()).ToImmutableArray();
tags = conditionElement.GetAttributeIdentifierArray("tags", Array.Empty<Identifier>()).ToImmutableArray();
category = conditionElement.GetAttributeEnum("category", MapEntityCategory.None);
if (!identifiers.Any() && !tags.Any())
if (identifiers.None() && tags.None() && category == MapEntityCategory.None)
{
DebugConsole.ThrowError($"Error in talent \"{characterTalent}\". No identifiers or tags defined.");
DebugConsole.ThrowError($"Error in talent \"{characterTalent}\". No identifiers, tags or category defined.");
}
}
@@ -33,6 +37,11 @@ namespace Barotrauma.Abilities
if (itemPrefab != null)
{
if (category != MapEntityCategory.None)
{
if (!itemPrefab.Category.HasFlag(category)) { return false; }
}
if (identifiers.Any())
{
if (!identifiers.Any(t => itemPrefab.Identifier == t))
@@ -40,7 +49,6 @@ namespace Barotrauma.Abilities
return false;
}
}
return !tags.Any() || tags.Any(t => itemPrefab.Tags.Any(p => t == p));
}
else
@@ -10,7 +10,7 @@ namespace Barotrauma.Abilities
{
foreach (Character c in GameSession.GetSessionCrewCharacters(CharacterType.Both))
{
if (c.IsUnconscious)
if (!c.IsDead && c.IsUnconscious)
{
return true;
}
@@ -34,7 +34,7 @@ namespace Barotrauma.Abilities
public bool IsViable()
{
if (!AllowClientSimulation && GameMain.NetworkMember != null && GameMain.NetworkMember.IsClient) { return false; }
if (!AllowClientSimulation && GameMain.NetworkMember is { IsClient: true }) { return false; }
if (RequiresAlive && Character.IsDead) { return false; }
return true;
}
@@ -9,6 +9,8 @@ namespace Barotrauma.Abilities
{
internal sealed class CharacterAbilityUnlockApprenticeshipTalentTree : CharacterAbility
{
public override bool AllowClientSimulation => false;
public CharacterAbilityUnlockApprenticeshipTalentTree(CharacterAbilityGroup characterAbilityGroup, ContentXElement abilityElement) : base(characterAbilityGroup, abilityElement) { }
public override void InitializeAbility(bool addingFirstTime)
@@ -426,16 +426,8 @@ namespace Barotrauma.Items.Components
item.body.FarseerBody.OnCollision += OnProjectileCollision;
item.body.FarseerBody.IsBullet = true;
if (item.body.CollisionCategories != Category.None)
{
item.body.CollisionCategories = Physics.CollisionProjectile;
item.body.CollidesWith = Physics.CollisionCharacter | Physics.CollisionWall | Physics.CollisionLevel | Physics.CollisionItemBlocking;
}
if (item.Prefab.DamagedByProjectiles && !IgnoreProjectilesWhileActive)
{
if (item.body.CollisionCategories == Category.None) { item.body.CollisionCategories = Physics.CollisionCharacter; }
item.body.CollidesWith |= Physics.CollisionProjectile;
}
EnableProjectileCollisions();
IsActive = true;
if (stickJoint == null) { return; }
@@ -560,12 +552,12 @@ namespace Barotrauma.Items.Components
}
else if (fixture?.Body == null || fixture.IsSensor)
{
//ignore sensors and items
//ignore sensors
return true;
}
if (fixture.Body.UserData is VineTile) { return true; }
if (fixture.CollidesWith == Category.None) { return true; }
if (fixture.Body.UserData is Item item && (item.GetComponent<Door>() == null && !item.Prefab.DamagedByProjectiles || item.Condition <= 0)) { return true; }
if (fixture.Body.UserData as string == "ruinroom" || fixture.Body.UserData is Hull || fixture.UserData is Hull) { return true; }
//if doing the raycast in a submarine's coordinate space, ignore anything that's not in that sub
@@ -575,13 +567,28 @@ namespace Barotrauma.Items.Components
if (fixture.Body.UserData is Entity entity && entity.Submarine != submarine) { return true; }
}
//ignore everything else than characters, sub walls and level walls
if (!fixture.CollisionCategories.HasFlag(Physics.CollisionCharacter) &&
!fixture.CollisionCategories.HasFlag(Physics.CollisionWall) &&
!fixture.CollisionCategories.HasFlag(Physics.CollisionLevel)) { return true; }
if (fixture.Body.UserData is VoronoiCell && (this.item.Submarine != null || submarine != null)) { return true; }
if (fixture.Body.UserData is Item item)
{
if (item == Item) { return true; }
if (item.Condition <= 0) { return true; }
if (!item.Prefab.DamagedByProjectiles && item.GetComponent<Door>() == null) { return true; }
}
else if (fixture.Body.UserData is Holdable { CanPush: false })
{
// Ignore holdables that can't push -> shouldn't block
return true;
}
else
{
// TODO: This might make us ignore something we don't want to ignore?
// Not item -> ignore everything else than characters, sub walls and level walls
if (!fixture.CollisionCategories.HasFlag(Physics.CollisionCharacter) &&
!fixture.CollisionCategories.HasFlag(Physics.CollisionWall) &&
!fixture.CollisionCategories.HasFlag(Physics.CollisionLevel)) { return true; }
}
fixture.Body.GetTransform(out FarseerPhysics.Common.Transform transform);
if (!fixture.Shape.TestPoint(ref transform, ref rayStart)) { return true; }
@@ -598,21 +605,17 @@ namespace Barotrauma.Items.Components
}
else if (fixture?.Body == null || fixture.IsSensor)
{
//ignore sensors and items
//ignore sensors
return -1;
}
if (fixture.Body.UserData is VineTile) { return -1; }
if (fixture.Body.UserData is Item item && (item.GetComponent<Door>() == null && !item.Prefab.DamagedByProjectiles || item.Condition <= 0)) { return -1; }
if (fixture.Body.UserData as string == "ruinroom" || fixture.Body?.UserData is Hull || fixture.UserData is Hull) { return -1; }
if (fixture.CollidesWith == Category.None) { return -1; }
if (!(fixture.Body.UserData is Holdable holdable && holdable.CanPush))
if (fixture.Body.UserData is Item item)
{
//ignore everything else than characters, sub walls and level walls
if (!fixture.CollisionCategories.HasFlag(Physics.CollisionCharacter) &&
!fixture.CollisionCategories.HasFlag(Physics.CollisionWall) &&
!fixture.CollisionCategories.HasFlag(Physics.CollisionLevel)) { return -1; }
if (item.Condition <= 0) { return -1; }
if (!item.Prefab.DamagedByProjectiles && item.GetComponent<Door>() == null) { return -1; }
}
if (fixture.Body.UserData as string == "ruinroom" || fixture.Body?.UserData is Hull || fixture.UserData is Hull) { return -1; }
//if doing the raycast in a submarine's coordinate space, ignore anything that's not in that sub
if (submarine != null)
@@ -622,6 +625,12 @@ namespace Barotrauma.Items.Components
if (fixture.Body.UserData is Limb limb && limb.character?.Submarine != submarine) { return -1; }
}
// Ignore holdables that can't push -> shouldn't block
if (fixture.Body.UserData is Holdable { CanPush: false })
{
return -1;
}
//ignore level cells if the item and the point of impact are inside a sub
if (fixture.Body.UserData is VoronoiCell)
{
@@ -652,7 +661,7 @@ namespace Barotrauma.Items.Components
hits.Add(new HitscanResult(fixture, point, normal, fraction));
return 1;
}, rayStart, rayEnd, Physics.CollisionCharacter | Physics.CollisionWall | Physics.CollisionLevel | Physics.CollisionItemBlocking);
}, rayStart, rayEnd, Physics.CollisionCharacter | Physics.CollisionWall | Physics.CollisionLevel | Physics.CollisionItemBlocking | Physics.CollisionProjectile);
return hits;
}
@@ -773,6 +782,12 @@ namespace Barotrauma.Items.Components
else if (target.Body.UserData is Item item)
{
if (item.Condition <= 0.0f) { return false; }
if (!item.Prefab.DamagedByProjectiles) { return false; }
}
else if (target.Body.UserData is Holdable { CanPush: false })
{
// Ignore holdables that can't push -> shouldn't block
return false;
}
//ignore character colliders (the projectile only hits limbs)
@@ -1068,6 +1083,20 @@ namespace Barotrauma.Items.Components
return true;
}
private void EnableProjectileCollisions()
{
if (item.body.CollisionCategories != Category.None)
{
item.body.CollisionCategories = Physics.CollisionProjectile;
item.body.CollidesWith = Physics.CollisionCharacter | Physics.CollisionWall | Physics.CollisionLevel | Physics.CollisionItemBlocking;
}
if (item.Prefab.DamagedByProjectiles && !IgnoreProjectilesWhileActive)
{
if (item.body.CollisionCategories == Category.None) { item.body.CollisionCategories = Physics.CollisionCharacter; }
item.body.CollidesWith |= Physics.CollisionProjectile;
}
}
private void DisableProjectileCollisions()
{
item.body.FarseerBody.OnCollision -= OnProjectileCollision;
@@ -10,6 +10,7 @@ namespace Barotrauma
[Flags]
enum MapEntityCategory
{
None = 0,
Structure = 1,
Decorative = 2,
Machine = 4,
@@ -35,6 +35,7 @@
{
GUI.DisableSavingIndicatorDelayed();
}
GameMain.ResetIMEWorkaround();
#endif
}
+32
View File
@@ -1,3 +1,10 @@
---------------------------------------------------------------------------------------------------------
v100.9.0.0
---------------------------------------------------------------------------------------------------------
- Fixes included in v0.20.10.0.
- Fixed genetic materials still being available for sale without the "Blackmarket Genes" talent.
---------------------------------------------------------------------------------------------------------
v100.8.0.0
---------------------------------------------------------------------------------------------------------
@@ -95,6 +102,31 @@ Test version of the faction overhaul:
- There's now always two paths from biome to another, one controlled by the Coalition and one by Separatists.
- Improvements to the campaign map.
---------------------------------------------------------------------------------------------------------
v0.20.10.0
---------------------------------------------------------------------------------------------------------
Input Method Editor (Chinese/Japanese input) fixes:
- Fixed inputs sometimes not working. Happened because listboxes stole keyboard focus, for example when rearranging bot orders or interacting with a chatbox.
- Fixed moving the input position with arrow keys in the candidate box moving the caret in the textbox too.
- Fixed current composition text disappearing when you browse through the options with arrow keys.
- Fixed candidate box not being hidden when there's no input (= when you've just selected the textbox or committed the input).
Fixes/improvements to depth charges:
- Fixed projectile-on-projectile collisions not working properly.
- Reduced the health of the depth charges (100 -> 10) to make them easier to detonate with turrets.
- Made decoys self-destruct instead of just becoming disabled after 45 seconds, turning them into time bombs.
- Fixed depth charges disappearing with a delay (after the explosion particles had gone away, making it easy to see them vanish).
- Fixed regular depth charges being destructible before launching.
Misc fixes:
- Fixed "Graduation Ceremony" talent unlocking 2 talent trees instead of one.
- Fixed Scrap Cannon's firing sound being barely audibly.
- Fixed "Better Than New" allowing you to repair any device past the maximum condition, not just electrical devices.
- Adjustments to Harpoon Coil-rifle sounds.
- Fixed some sprite bleed issues in the new talent icons.
- Fixed Kastrull's reactor having 1000 condition instead of 100.
---------------------------------------------------------------------------------------------------------
v0.20.9.0
---------------------------------------------------------------------------------------------------------