v1.6.17.0 (Unto the Breach update)
This commit is contained in:
@@ -58,7 +58,7 @@ internal class DeathPrompt
|
||||
const float FadeInDuration = 1.0f;
|
||||
|
||||
bool permadeath = GameMain.NetworkMember is { ServerSettings.RespawnMode: RespawnMode.Permadeath };
|
||||
bool ironman = GameMain.NetworkMember is { ServerSettings: { RespawnMode: RespawnMode.Permadeath, IronmanMode: true } };
|
||||
bool ironman = GameMain.NetworkMember is { ServerSettings.IronmanModeActive: true };
|
||||
|
||||
var background = new GUICustomComponent(new RectTransform(Vector2.One, GUI.Canvas, Anchor.Center), onDraw: DrawBackground)
|
||||
{
|
||||
|
||||
@@ -4,7 +4,6 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using Barotrauma.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Barotrauma.Extensions;
|
||||
|
||||
namespace Barotrauma
|
||||
@@ -84,16 +83,31 @@ namespace Barotrauma
|
||||
{
|
||||
currentDirectory += "/";
|
||||
}
|
||||
fileSystemWatcher?.Dispose();
|
||||
fileSystemWatcher = new System.IO.FileSystemWatcher(currentDirectory)
|
||||
try
|
||||
{
|
||||
Filter = "*",
|
||||
NotifyFilter = System.IO.NotifyFilters.LastWrite | System.IO.NotifyFilters.FileName | System.IO.NotifyFilters.DirectoryName
|
||||
};
|
||||
fileSystemWatcher.Created += OnFileSystemChanges;
|
||||
fileSystemWatcher.Deleted += OnFileSystemChanges;
|
||||
fileSystemWatcher.Renamed += OnFileSystemChanges;
|
||||
fileSystemWatcher.EnableRaisingEvents = true;
|
||||
fileSystemWatcher?.Dispose();
|
||||
fileSystemWatcher = new System.IO.FileSystemWatcher(currentDirectory)
|
||||
{
|
||||
Filter = "*",
|
||||
NotifyFilter = System.IO.NotifyFilters.LastWrite | System.IO.NotifyFilters.FileName | System.IO.NotifyFilters.DirectoryName
|
||||
};
|
||||
fileSystemWatcher.Created += OnFileSystemChanges;
|
||||
fileSystemWatcher.Deleted += OnFileSystemChanges;
|
||||
fileSystemWatcher.Renamed += OnFileSystemChanges;
|
||||
fileSystemWatcher.EnableRaisingEvents = true;
|
||||
}
|
||||
catch (System.IO.FileNotFoundException exception)
|
||||
{
|
||||
DebugConsole.ThrowError("Failed to set the current directory, possibly due to insufficient access permissions.", exception);
|
||||
}
|
||||
catch (ArgumentException exception)
|
||||
{
|
||||
DebugConsole.ThrowError("Failed to set the current directory, possibly because it was deleted.", exception);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
DebugConsole.ThrowError("Failed to set the current directory for an unknown reason.", exception);
|
||||
}
|
||||
RefreshFileList();
|
||||
}
|
||||
}
|
||||
@@ -218,6 +232,14 @@ namespace Barotrauma
|
||||
{
|
||||
if (Directory.Exists(txt))
|
||||
{
|
||||
var attributes = System.IO.File.GetAttributes(txt);
|
||||
if (attributes.HasAnyFlag(System.IO.FileAttributes.System) || attributes.HasAnyFlag(System.IO.FileAttributes.Hidden))
|
||||
{
|
||||
// System and hidden folders should be filtered out when populating the options, but the user can still write or copy-paste the path in the text field,
|
||||
// which will throw a file not found exception when the file system watcher starts. Therefore, this extra check.
|
||||
tb.Text = CurrentDirectory;
|
||||
return false;
|
||||
}
|
||||
CurrentDirectory = txt;
|
||||
return true;
|
||||
}
|
||||
@@ -354,20 +376,19 @@ namespace Barotrauma
|
||||
var directories = Directory.EnumerateDirectories(currentDirectory, "*" + filterBox!.Text + "*");
|
||||
foreach (var directory in directories)
|
||||
{
|
||||
string txt = directory;
|
||||
if (txt.StartsWith(currentDirectory)) { txt = txt.Substring(currentDirectory.Length); }
|
||||
if (!txt.EndsWith("/")) { txt += "/"; }
|
||||
//get directory info
|
||||
DirectoryInfo dirInfo = new DirectoryInfo(directory);
|
||||
try
|
||||
{
|
||||
//this will throw an exception if the directory can't be opened
|
||||
Directory.GetDirectories(directory);
|
||||
//this will intentionally throw an exception if the directory can't be opened
|
||||
System.IO.Directory.GetDirectories(directory);
|
||||
}
|
||||
catch (UnauthorizedAccessException)
|
||||
{
|
||||
// Skip the folders that can't be accessed.
|
||||
continue;
|
||||
}
|
||||
string txt = directory;
|
||||
if (txt.StartsWith(currentDirectory)) { txt = txt.Substring(currentDirectory.Length); }
|
||||
if (!txt.EndsWith("/")) { txt += "/"; }
|
||||
var itemFrame = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), fileList.Content.RectTransform), txt)
|
||||
{
|
||||
UserData = ItemIsDirectory.Yes
|
||||
|
||||
@@ -469,7 +469,7 @@ namespace Barotrauma
|
||||
"Loaded sounds: " + GameMain.SoundManager.LoadedSoundCount + " (" + GameMain.SoundManager.UniqueLoadedSoundCount + " unique)", Color.White, Color.Black * 0.5f, 0, GUIStyle.SmallFont);
|
||||
soundTextY += yStep;
|
||||
|
||||
for (int i = 0; i < SoundManager.SOURCE_COUNT; i++)
|
||||
for (int i = 0; i < SoundManager.SourceCount; i++)
|
||||
{
|
||||
Color clr = Color.White;
|
||||
string soundStr = i + ": ";
|
||||
@@ -1546,7 +1546,7 @@ namespace Barotrauma
|
||||
private static readonly VertexPositionColorTexture[] donutVerts = new VertexPositionColorTexture[DonutSegments * 4];
|
||||
|
||||
public static void DrawDonutSection(
|
||||
SpriteBatch sb, Vector2 center, Range<float> radii, float sectionRad, Color clr, float depth = 0.0f)
|
||||
SpriteBatch sb, Vector2 center, Range<float> radii, float sectionRad, Color clr, float depth = 0.0f, float rotationRad = 0.0f)
|
||||
{
|
||||
float getRadius(int vertexIndex)
|
||||
=> (vertexIndex % 4) switch
|
||||
@@ -1589,7 +1589,7 @@ namespace Barotrauma
|
||||
for (int vertexIndex = 0; vertexIndex < maxDirectionIndex * 4; vertexIndex++)
|
||||
{
|
||||
donutVerts[vertexIndex].Color = clr;
|
||||
donutVerts[vertexIndex].Position = new Vector3(center + getDirection(vertexIndex) * getRadius(vertexIndex), 0.0f);
|
||||
donutVerts[vertexIndex].Position = new Vector3(center + Vector2.Transform(getDirection(vertexIndex) * getRadius(vertexIndex), Matrix.CreateRotationZ(rotationRad)), 0.0f);
|
||||
}
|
||||
sb.Draw(solidWhiteTexture, donutVerts, depth, count: maxDirectionIndex);
|
||||
}
|
||||
@@ -1856,9 +1856,16 @@ namespace Barotrauma
|
||||
Vector2 pos = new Vector2(GameMain.GraphicsWidth, GameMain.GraphicsHeight) - new Vector2(HUDLayoutSettings.Padding) - 2 * Scale * sheet.FrameSize.ToVector2();
|
||||
sheet.Draw(spriteBatch, (int)Math.Floor(savingIndicatorSpriteIndex), pos, savingIndicatorColor, origin: Vector2.Zero, rotate: 0.0f, scale: new Vector2(Scale));
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Element creation
|
||||
public static void DrawCapsule(SpriteBatch sb, Vector2 origin, float length, float radius, float rotation, Color clr, float depth = 0, float thickness = 1)
|
||||
{
|
||||
DrawDonutSection(sb, origin + Vector2.Transform(-new Vector2(length / 2, 0), Matrix.CreateRotationZ(rotation)), new Range<float>(radius - thickness / 2, radius + thickness / 2), MathHelper.Pi, clr, depth, rotation - MathHelper.Pi);
|
||||
DrawRectangle(sb, origin, new Vector2(length, radius * 2), new Vector2(length / 2, radius), rotation, clr, depth, thickness);
|
||||
DrawDonutSection(sb, origin + Vector2.Transform(new Vector2(length / 2, 0), Matrix.CreateRotationZ(rotation)), new Range<float>(radius - thickness / 2, radius + thickness / 2), MathHelper.Pi, clr, depth, rotation);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Element creation
|
||||
|
||||
public static Texture2D CreateCircle(int radius, bool filled = false)
|
||||
{
|
||||
|
||||
@@ -159,6 +159,34 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
private GUIComponent holdOverlay;
|
||||
|
||||
private bool requireHold;
|
||||
public bool RequireHold
|
||||
{
|
||||
get => requireHold;
|
||||
set
|
||||
{
|
||||
requireHold = value;
|
||||
if (value)
|
||||
{
|
||||
holdOverlay ??= new GUIFrame(new RectTransform(new Vector2(0.5f, 1f), Frame.RectTransform, Anchor.CenterLeft), style: null)
|
||||
{
|
||||
Color = GUIStyle.Yellow * 0.33f,
|
||||
CanBeFocused = false,
|
||||
IgnoreLayoutGroups = true,
|
||||
Visible = true
|
||||
};
|
||||
}
|
||||
else if (holdOverlay != null)
|
||||
{
|
||||
holdOverlay.Visible = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
public float HoldDurationSeconds { get; set; } = 5f;
|
||||
private float holdTimer;
|
||||
|
||||
public bool Pulse { get; set; }
|
||||
private float pulseTimer;
|
||||
private float pulseExpand;
|
||||
@@ -220,7 +248,7 @@ namespace Barotrauma
|
||||
Rectangle expandRect = Rect;
|
||||
float expand = (pulseExpand * 20.0f) * GUI.Scale;
|
||||
expandRect.Inflate(expand, expand);
|
||||
|
||||
|
||||
GUIStyle.EndRoundButtonPulse.Draw(spriteBatch, expandRect, ToolBox.GradientLerp(pulseExpand, Color.White, Color.White, Color.Transparent));
|
||||
}
|
||||
}
|
||||
@@ -240,6 +268,11 @@ namespace Barotrauma
|
||||
}
|
||||
if (PlayerInput.PrimaryMouseButtonHeld())
|
||||
{
|
||||
if (RequireHold)
|
||||
{
|
||||
holdTimer += deltaTime;
|
||||
}
|
||||
|
||||
if (OnPressed != null)
|
||||
{
|
||||
if (OnPressed())
|
||||
@@ -254,25 +287,34 @@ namespace Barotrauma
|
||||
}
|
||||
else if (PlayerInput.PrimaryMouseButtonClicked())
|
||||
{
|
||||
if (PlaySoundOnSelect)
|
||||
if (!RequireHold || holdTimer > HoldDurationSeconds)
|
||||
{
|
||||
SoundPlayer.PlayUISound(ClickSound);
|
||||
}
|
||||
if (OnClicked != null)
|
||||
{
|
||||
if (OnClicked(this, UserData))
|
||||
if (PlaySoundOnSelect)
|
||||
{
|
||||
State = ComponentState.Selected;
|
||||
SoundPlayer.PlayUISound(ClickSound);
|
||||
}
|
||||
|
||||
if (OnClicked != null)
|
||||
{
|
||||
if (OnClicked(this, UserData))
|
||||
{
|
||||
State = ComponentState.Selected;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Selected = !Selected;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Selected = !Selected;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
holdTimer = 0.0f;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
holdTimer = 0.0f;
|
||||
if (!ExternalHighlight)
|
||||
{
|
||||
State = Selected ? ComponentState.Selected : ComponentState.None;
|
||||
@@ -283,6 +325,20 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
if (RequireHold)
|
||||
{
|
||||
float width = MathHelper.Clamp(holdTimer / HoldDurationSeconds, 0f, 1f);
|
||||
if (!MathUtils.NearlyEqual(width, holdOverlay.RectTransform.RelativeSize.X))
|
||||
{
|
||||
holdOverlay.RectTransform.RelativeSize = new Vector2(width, 1f);
|
||||
}
|
||||
|
||||
holdOverlay.Color =
|
||||
holdTimer >= HoldDurationSeconds
|
||||
? Color.Green * 0.33f
|
||||
: Color.Red * 0.33f;
|
||||
}
|
||||
|
||||
foreach (GUIComponent child in Children)
|
||||
{
|
||||
child.State = State;
|
||||
|
||||
@@ -9,8 +9,21 @@ namespace Barotrauma
|
||||
{
|
||||
public class GUIDropDown : GUIComponent, IKeyboardSubscriber
|
||||
{
|
||||
/// <param name="selected">The component that was selected from the dropdown.</param>
|
||||
/// <param name="obj"><see cref="GUIComponent.UserData"/> of the component selected from the dropdown.</param>
|
||||
public delegate bool OnSelectedHandler(GUIComponent selected, object obj = null);
|
||||
/// <summary>
|
||||
/// Triggers when some item is cliecked from the dropdown.
|
||||
/// Note that <see cref="SelectedData"/> is not set yet when this callback triggers, and returning false from the callback disallows selecting it.
|
||||
/// If you want to access the new value, use the obj argument.
|
||||
/// </summary>
|
||||
public OnSelectedHandler OnSelected;
|
||||
|
||||
/// <summary>
|
||||
/// Triggers after an item has been selected from the dropdown, all validation has been done and the new value has been set.
|
||||
/// </summary>
|
||||
public OnSelectedHandler AfterSelected;
|
||||
|
||||
public OnSelectedHandler OnDropped;
|
||||
|
||||
private readonly GUIButton button;
|
||||
@@ -166,7 +179,7 @@ namespace Barotrauma
|
||||
|
||||
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)
|
||||
public GUIDropDown(RectTransform rectT, LocalizedString text = null, int elementCount = 4, string style = "", bool selectMultiple = false, bool dropAbove = false, Alignment textAlignment = Alignment.CenterLeft, float listBoxScale = 1) : base(style, rectT)
|
||||
{
|
||||
text ??= LocalizedString.EmptyString;
|
||||
|
||||
@@ -185,13 +198,21 @@ namespace Barotrauma
|
||||
|
||||
Anchor listAnchor = dropAbove ? Anchor.TopCenter : Anchor.BottomCenter;
|
||||
Pivot listPivot = dropAbove ? Pivot.BottomCenter : Pivot.TopCenter;
|
||||
listBox = new GUIListBox(new RectTransform(new Point(Rect.Width, Rect.Height * MathHelper.Clamp(elementCount, 2, 10)), rectT, listAnchor, listPivot)
|
||||
listBox = new GUIListBox(new RectTransform(new Point((int)(Rect.Width * listBoxScale), Rect.Height * MathHelper.Clamp(elementCount, 2, 10)), rectT, listAnchor, listPivot)
|
||||
{ IsFixedSize = false }, style: null)
|
||||
{
|
||||
Enabled = !selectMultiple,
|
||||
PlaySoundOnSelect = true,
|
||||
};
|
||||
if (!selectMultiple) { listBox.OnSelected = SelectItem; }
|
||||
if (!selectMultiple)
|
||||
{
|
||||
listBox.AfterSelected = (component, obj) =>
|
||||
{
|
||||
SelectItem(component, obj);
|
||||
AfterSelected?.Invoke(component, obj);
|
||||
return true;
|
||||
};
|
||||
}
|
||||
GUIStyle.Apply(listBox, "GUIListBox", this);
|
||||
GUIStyle.Apply(listBox.ContentBackground, "GUIListBox", this);
|
||||
|
||||
@@ -199,6 +220,8 @@ namespace Barotrauma
|
||||
{
|
||||
icon = new GUIImage(new RectTransform(new Vector2(0.6f, 0.6f), button.RectTransform, Anchor.CenterRight, scaleBasis: ScaleBasis.BothHeight) { AbsoluteOffset = new Point(5, 0) }, null, scaleToFit: true);
|
||||
icon.ApplyStyle(button.Style.ChildStyles["dropdownicon".ToIdentifier()]);
|
||||
//move the text away from the icon
|
||||
button.TextBlock.Padding += new Vector4(0, 0, icon.Rect.Width, 0);
|
||||
}
|
||||
|
||||
currentHighestParent = FindHighestParent();
|
||||
@@ -249,12 +272,12 @@ namespace Barotrauma
|
||||
toolTip ??= "";
|
||||
if (selectMultiple)
|
||||
{
|
||||
var frame = new GUIFrame(new RectTransform(new Point(button.Rect.Width, button.Rect.Height), listBox.Content.RectTransform) { IsFixedSize = false }, style: "ListBoxElement", color: color)
|
||||
var frame = new GUIFrame(new RectTransform(new Point(listBox.Content.Rect.Width, button.Rect.Height), listBox.Content.RectTransform) { IsFixedSize = false }, style: "ListBoxElement", color: color)
|
||||
{
|
||||
UserData = userData,
|
||||
ToolTip = toolTip
|
||||
};
|
||||
new GUITickBox(new RectTransform(new Vector2(1.0f, 0.8f), frame.RectTransform, anchor: Anchor.CenterLeft) { MaxSize = new Point(int.MaxValue, (int)(button.Rect.Height * 0.8f)) }, text)
|
||||
var tickBox = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.8f), frame.RectTransform, anchor: Anchor.CenterLeft) { MaxSize = new Point(int.MaxValue, (int)(button.Rect.Height * 0.8f)) }, text)
|
||||
{
|
||||
UserData = userData,
|
||||
ToolTip = toolTip,
|
||||
@@ -266,6 +289,11 @@ namespace Barotrauma
|
||||
return false;
|
||||
}
|
||||
|
||||
if (OnSelected != null && !OnSelected.Invoke(tb.Parent, tb.Parent.UserData))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
List<LocalizedString> texts = new List<LocalizedString>();
|
||||
selectedDataMultiple.Clear();
|
||||
selectedIndexMultiple.Clear();
|
||||
@@ -282,8 +310,7 @@ namespace Barotrauma
|
||||
i++;
|
||||
}
|
||||
button.Text = LocalizedString.Join(", ", texts);
|
||||
// TODO: The callback is called at least twice, remove this?
|
||||
OnSelected?.Invoke(tb.Parent, tb.Parent.UserData);
|
||||
AfterSelected?.Invoke(tb.Parent, SelectedData);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
@@ -291,7 +318,7 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
return new GUITextBlock(new RectTransform(new Point(button.Rect.Width, button.Rect.Height), listBox.Content.RectTransform) { IsFixedSize = false }, text, style: "ListBoxElement", color: color, textColor: textColor)
|
||||
return new GUITextBlock(new RectTransform(new Point(listBox.Content.Rect.Width, button.Rect.Height), listBox.Content.RectTransform) { IsFixedSize = false }, text, style: "ListBoxElement", color: color, textColor: textColor)
|
||||
{
|
||||
UserData = userData,
|
||||
ToolTip = toolTip
|
||||
@@ -328,9 +355,8 @@ namespace Barotrauma
|
||||
}
|
||||
button.Text = textBlock?.Text ?? "";
|
||||
}
|
||||
OnSelected?.Invoke(component, obj);
|
||||
Dropped = false;
|
||||
// TODO: OnSelected can be called multiple times and when it shouldn't be called -> turn into an event so that nobody else can call it.
|
||||
OnSelected?.Invoke(component, component.UserData);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -344,6 +370,7 @@ namespace Barotrauma
|
||||
{
|
||||
listBox.Select(userData);
|
||||
}
|
||||
AfterSelected?.Invoke(SelectedComponent, SelectedData);
|
||||
}
|
||||
|
||||
public void Select(int index)
|
||||
@@ -360,6 +387,7 @@ namespace Barotrauma
|
||||
{
|
||||
listBox.Select(index);
|
||||
}
|
||||
AfterSelected?.Invoke(this, SelectedData);
|
||||
}
|
||||
|
||||
private bool wasOpened;
|
||||
|
||||
@@ -14,8 +14,17 @@ namespace Barotrauma
|
||||
protected List<GUIComponent> selected;
|
||||
|
||||
public delegate bool OnSelectedHandler(GUIComponent component, object obj);
|
||||
/// <summary>
|
||||
/// Triggers when some element is clicked on the listbox.
|
||||
/// Note that <see cref="SelectedData"/> is not set yet when this callback triggers, and returning false from the callback disallows selecting it.
|
||||
/// </summary>
|
||||
public OnSelectedHandler OnSelected;
|
||||
|
||||
/// <summary>
|
||||
/// Triggers after some element has been selected from the listbox.
|
||||
/// </summary>
|
||||
public OnSelectedHandler AfterSelected;
|
||||
|
||||
public delegate object CheckSelectedHandler();
|
||||
public CheckSelectedHandler CheckSelected;
|
||||
|
||||
@@ -1151,6 +1160,8 @@ namespace Barotrauma
|
||||
{
|
||||
SoundPlayer.PlayUISound(GUISoundType.Select);
|
||||
}
|
||||
|
||||
AfterSelected?.Invoke(child, SelectedData);
|
||||
}
|
||||
|
||||
public void Select(IEnumerable<GUIComponent> children)
|
||||
@@ -1160,8 +1171,9 @@ namespace Barotrauma
|
||||
selected.Clear();
|
||||
selected.AddRange(children.Where(c => Content.Children.Contains(c)));
|
||||
foreach (var child in selected) { OnSelected?.Invoke(child, child.UserData); }
|
||||
AfterSelected?.Invoke(children.FirstOrDefault(), SelectedData);
|
||||
}
|
||||
|
||||
|
||||
public void Deselect()
|
||||
{
|
||||
Selected = false;
|
||||
@@ -1172,6 +1184,15 @@ namespace Barotrauma
|
||||
selected.Clear();
|
||||
}
|
||||
|
||||
public void DeselectElement(GUIComponent child)
|
||||
{
|
||||
if (child == null) { return; }
|
||||
if (selected.Contains(child))
|
||||
{
|
||||
selected.Remove(child);
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateScrollBarSize()
|
||||
{
|
||||
scrollBarNeedsRecalculation = false;
|
||||
@@ -1268,7 +1289,7 @@ namespace Barotrauma
|
||||
ContentBackground.DrawManually(spriteBatch, alsoChildren: false);
|
||||
|
||||
Rectangle prevScissorRect = spriteBatch.GraphicsDevice.ScissorRectangle;
|
||||
if (HideChildrenOutsideFrame)
|
||||
if (HideChildrenOutsideFrame && Content.CountChildren > 0)
|
||||
{
|
||||
spriteBatch.End();
|
||||
spriteBatch.GraphicsDevice.ScissorRectangle = Rectangle.Intersect(prevScissorRect, Content.Rect);
|
||||
@@ -1306,7 +1327,7 @@ namespace Barotrauma
|
||||
GUI.DrawRectangle(spriteBatch, drawRect, Color.White * 0.5f, thickness: 2f);
|
||||
}
|
||||
|
||||
if (HideChildrenOutsideFrame)
|
||||
if (HideChildrenOutsideFrame && Content.CountChildren > 0)
|
||||
{
|
||||
spriteBatch.End();
|
||||
spriteBatch.GraphicsDevice.ScissorRectangle = prevScissorRect;
|
||||
|
||||
@@ -51,6 +51,16 @@ namespace Barotrauma
|
||||
public readonly static GUISprite InteractionLabelBackground = new GUISprite("InteractionLabelBackground");
|
||||
public readonly static GUISprite BrokenIcon = new GUISprite("BrokenIcon");
|
||||
public readonly static GUISprite YouAreHereCircle = new GUISprite("YouAreHereCircle");
|
||||
|
||||
public readonly static GUISprite SubLocationIcon = new GUISprite("SubLocationIcon");
|
||||
public readonly static GUISprite ShuttleIcon = new GUISprite("ShuttleIcon");
|
||||
public readonly static GUISprite WreckIcon = new GUISprite("WreckIcon");
|
||||
public readonly static GUISprite CaveIcon = new GUISprite("CaveIcon");
|
||||
public readonly static GUISprite OutpostIcon = new GUISprite("OutpostIcon");
|
||||
public readonly static GUISprite RuinIcon = new GUISprite("RuinIcon");
|
||||
public readonly static GUISprite EnemyIcon = new GUISprite("EnemyIcon");
|
||||
public readonly static GUISprite CorpseIcon = new GUISprite("CorpseIcon");
|
||||
public readonly static GUISprite BeaconIcon = new GUISprite("BeaconIcon");
|
||||
|
||||
public readonly static GUISprite Radiation = new GUISprite("Radiation");
|
||||
public readonly static GUISpriteSheet RadiationAnimSpriteSheet = new GUISpriteSheet("RadiationAnimSpriteSheet");
|
||||
@@ -71,7 +81,7 @@ namespace Barotrauma
|
||||
public readonly static GUISprite EndRoundButtonPulse = new GUISprite("EndRoundButtonPulse");
|
||||
|
||||
public readonly static GUISpriteSheet FocusIndicator = new GUISpriteSheet("FocusIndicator");
|
||||
|
||||
|
||||
public readonly static GUISprite IconOverflowIndicator = new GUISprite("IconOverflowIndicator");
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -742,8 +742,8 @@ namespace Barotrauma
|
||||
|
||||
private (LocalizedString header, LocalizedString body) GetItemTransferWarningText()
|
||||
{
|
||||
var header = TextManager.Get("itemtransferheader").Fallback("lowfuelheader", useDefaultLanguageIfFound: false);
|
||||
var body = TextManager.Get("itemtransferwarning").Fallback("lowfuelwarning", useDefaultLanguageIfFound: false);
|
||||
var header = TextManager.Get("itemtransferheader").Fallback(TextManager.Get("lowfuelheader"), useDefaultLanguageIfFound: false);
|
||||
var body = TextManager.Get("itemtransferwarning").Fallback(TextManager.Get("lowfuelwarning"), useDefaultLanguageIfFound: false);
|
||||
return (header, body);
|
||||
}
|
||||
|
||||
|
||||
@@ -416,7 +416,10 @@ namespace Barotrauma
|
||||
=> TextManager.GetWithVariable("percentageformat", "[value]", $"{(int)MathF.Round(value)}");
|
||||
}
|
||||
|
||||
var submarineButton = createTabButton(InfoFrameTab.Submarine, "submarine");
|
||||
if (Submarine.MainSub != null)
|
||||
{
|
||||
createTabButton(InfoFrameTab.Submarine, "submarine");
|
||||
}
|
||||
|
||||
var talentsButton = createTabButton(InfoFrameTab.Talents, "tabmenu.character");
|
||||
talentsButton.OnAddedToGUIUpdateList += (component) =>
|
||||
@@ -463,12 +466,14 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
private const float jobColumnWidthPercentage = 0.138f,
|
||||
characterColumnWidthPercentage = 0.45f,
|
||||
pingColumnWidthPercentage = 0.206f,
|
||||
walletColumnWidthPercentage = 0.206f;
|
||||
private const float JobColumnWidthPercentage = 0.138f,
|
||||
CharacterColumnWidthPercentage = 0.45f,
|
||||
KillColumnWidthPercentage = 0.1f,
|
||||
DeathColumnWidthPercentage = 0.1f,
|
||||
PingColumnWidthPercentage = 0.15f,
|
||||
WalletColumnWidthPercentage = 0.206f;
|
||||
|
||||
private int jobColumnWidth, characterColumnWidth, pingColumnWidth, walletColumnWidth;
|
||||
private int jobColumnWidth, characterColumnWidth, pingColumnWidth, walletColumnWidth, deathColumnWidth, killColumnWidth;
|
||||
|
||||
private void CreateCrewListFrame(GUIFrame crewFrame)
|
||||
{
|
||||
@@ -496,11 +501,21 @@ namespace Barotrauma
|
||||
{
|
||||
if (teamIDs.Count > 1)
|
||||
{
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, nameHeight), content.RectTransform), CombatMission.GetTeamName(teamIDs[i]), textColor: i == 0 ? GUIStyle.Green : GUIStyle.Orange) { ForceUpperCase = ForceUpperCase.Yes };
|
||||
var nameText = new GUITextBlock(new RectTransform(new Vector2(1.0f, nameHeight), content.RectTransform), CombatMission.GetTeamName(teamIDs[i]), textColor: CombatMission.GetTeamColor(teamIDs[i]))
|
||||
{
|
||||
ForceUpperCase = ForceUpperCase.Yes
|
||||
};
|
||||
var teamIcon = new GUIImage(new RectTransform(Vector2.One, nameText.RectTransform, Anchor.CenterLeft, scaleBasis: ScaleBasis.BothHeight),
|
||||
style: teamIDs[i] == CharacterTeamType.Team2 ? "SeparatistIcon" : "CoalitionIcon")
|
||||
{
|
||||
Color = nameText.TextColor
|
||||
};
|
||||
nameText.Padding = new Vector4(teamIcon.Rect.Width + nameText.Padding.X, nameText.Padding.Y, nameText.Padding.Z, nameText.Padding.W);
|
||||
}
|
||||
|
||||
headerFrames[i] = new GUILayoutGroup(new RectTransform(Vector2.Zero, content.RectTransform, Anchor.TopLeft, Pivot.BottomLeft) { AbsoluteOffset = new Point(2, -1) }, isHorizontal: true)
|
||||
{
|
||||
Stretch = true,
|
||||
AbsoluteSpacing = 2,
|
||||
UserData = i
|
||||
};
|
||||
@@ -587,8 +602,8 @@ namespace Barotrauma
|
||||
|
||||
sizeMultiplier = (headerFrame.Rect.Width - headerFrame.AbsoluteSpacing * (headerFrame.CountChildren - 1)) / (float)headerFrame.Rect.Width;
|
||||
|
||||
jobButton.RectTransform.RelativeSize = new Vector2(jobColumnWidthPercentage * sizeMultiplier, 1f);
|
||||
characterButton.RectTransform.RelativeSize = new Vector2((1f - jobColumnWidthPercentage * sizeMultiplier) * sizeMultiplier, 1f);
|
||||
jobButton.RectTransform.RelativeSize = new Vector2(JobColumnWidthPercentage * sizeMultiplier, 1f);
|
||||
characterButton.RectTransform.RelativeSize = new Vector2((1f - JobColumnWidthPercentage * sizeMultiplier) * sizeMultiplier, 1f);
|
||||
|
||||
jobButton.TextBlock.Font = characterButton.TextBlock.Font = GUIStyle.HotkeyFont;
|
||||
jobButton.CanBeFocused = characterButton.CanBeFocused = false;
|
||||
@@ -626,7 +641,8 @@ namespace Barotrauma
|
||||
|
||||
var paddedFrame = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.9f), frame.RectTransform, Anchor.Center), isHorizontal: true)
|
||||
{
|
||||
AbsoluteSpacing = 2
|
||||
AbsoluteSpacing = 2,
|
||||
Stretch = true
|
||||
};
|
||||
|
||||
new GUICustomComponent(new RectTransform(new Point(jobColumnWidth, paddedFrame.Rect.Height), paddedFrame.RectTransform, Anchor.Center), onDraw: (sb, component) => character.Info.DrawJobIcon(sb, component.Rect))
|
||||
@@ -639,21 +655,29 @@ namespace Barotrauma
|
||||
GUITextBlock characterNameBlock = new GUITextBlock(new RectTransform(new Point(characterColumnWidth, paddedFrame.Rect.Height), paddedFrame.RectTransform),
|
||||
ToolBox.LimitString(character.Info.Name, GUIStyle.Font, characterColumnWidth), textAlignment: Alignment.Center, textColor: character.Info.Job.Prefab.UIColor);
|
||||
|
||||
paddedFrame.Recalculate();
|
||||
|
||||
linkedGUIList.Add(new LinkedGUI(character, frame, textBlock: null));
|
||||
}
|
||||
|
||||
private void CreateMultiPlayerListContentHolder(GUILayoutGroup headerFrame)
|
||||
{
|
||||
bool isCampaign = GameMain.GameSession?.Campaign is MultiPlayerCampaign;
|
||||
GUIButton jobButton = new GUIButton(new RectTransform(new Vector2(0f, 1f), headerFrame.RectTransform), TextManager.Get("tabmenu.job"), style: "GUIButtonSmallFreeScale");
|
||||
GUIButton characterButton = new GUIButton(new RectTransform(new Vector2(0f, 1f), headerFrame.RectTransform), TextManager.Get("name"), style: "GUIButtonSmallFreeScale");
|
||||
GUIButton pingButton = new GUIButton(new RectTransform(new Vector2(0f, 1f), headerFrame.RectTransform), TextManager.Get("serverlistping"), style: "GUIButtonSmallFreeScale");
|
||||
GUIButton jobButton = new GUIButton(new RectTransform(new Vector2(JobColumnWidthPercentage, 1f), headerFrame.RectTransform), TextManager.Get("tabmenu.job"), style: "GUIButtonSmallFreeScale");
|
||||
GUIButton characterButton = new GUIButton(new RectTransform(new Vector2(CharacterColumnWidthPercentage, 1f), headerFrame.RectTransform), TextManager.Get("name"), style: "GUIButtonSmallFreeScale");
|
||||
|
||||
if (GameMain.GameSession?.GameMode is PvPMode)
|
||||
{
|
||||
var killButton = new GUIButton(new RectTransform(new Vector2(KillColumnWidthPercentage, 1f), headerFrame.RectTransform), TextManager.Get("killcount"), style: "GUIButtonSmallFreeScale");
|
||||
killColumnWidth = killButton.Rect.Width;
|
||||
var deathButton = new GUIButton(new RectTransform(new Vector2(DeathColumnWidthPercentage, 1f), headerFrame.RectTransform), TextManager.Get("deathcount"), style: "GUIButtonSmallFreeScale");
|
||||
deathColumnWidth = deathButton.Rect.Width;
|
||||
}
|
||||
|
||||
GUIButton pingButton = new GUIButton(new RectTransform(new Vector2(PingColumnWidthPercentage, 1f), headerFrame.RectTransform), TextManager.Get("serverlistping"), style: "GUIButtonSmallFreeScale");
|
||||
if (isCampaign)
|
||||
{
|
||||
GUIButton walletButton = new GUIButton(new RectTransform(new Vector2(0f, 1f), headerFrame.RectTransform)
|
||||
{
|
||||
RelativeSize = new Vector2(walletColumnWidthPercentage * sizeMultiplier, 1f)
|
||||
}, TextManager.Get("crewwallet.wallet"), style: "GUIButtonSmallFreeScale")
|
||||
GUIButton walletButton = new GUIButton(new RectTransform(new Vector2(WalletColumnWidthPercentage, 1f), headerFrame.RectTransform), TextManager.Get("crewwallet.wallet"), style: "GUIButtonSmallFreeScale")
|
||||
{
|
||||
TextBlock = { Font = GUIStyle.HotkeyFont },
|
||||
CanBeFocused = false,
|
||||
@@ -662,15 +686,12 @@ namespace Barotrauma
|
||||
walletColumnWidth = walletButton.Rect.Width;
|
||||
}
|
||||
|
||||
sizeMultiplier = (headerFrame.Rect.Width - headerFrame.AbsoluteSpacing * (headerFrame.CountChildren - 1)) / (float)headerFrame.Rect.Width;
|
||||
|
||||
jobButton.RectTransform.RelativeSize = new Vector2(jobColumnWidthPercentage * sizeMultiplier, 1f);
|
||||
characterButton.RectTransform.RelativeSize = new Vector2((characterColumnWidthPercentage + (isCampaign ? 0 : walletColumnWidthPercentage)) * sizeMultiplier, 1f);
|
||||
pingButton.RectTransform.RelativeSize = new Vector2(pingColumnWidthPercentage * sizeMultiplier, 1f);
|
||||
|
||||
jobButton.TextBlock.Font = characterButton.TextBlock.Font = pingButton.TextBlock.Font = GUIStyle.HotkeyFont;
|
||||
jobButton.CanBeFocused = characterButton.CanBeFocused = pingButton.CanBeFocused = false;
|
||||
jobButton.TextBlock.ForceUpperCase = characterButton.TextBlock.ForceUpperCase = pingButton.ForceUpperCase = ForceUpperCase.Yes;
|
||||
foreach (var btn in headerFrame.GetAllChildren<GUIButton>())
|
||||
{
|
||||
btn.TextBlock.Font = GUIStyle.HotkeyFont;
|
||||
btn.CanBeFocused = false;
|
||||
btn.ForceUpperCase = ForceUpperCase.Yes;
|
||||
}
|
||||
|
||||
jobColumnWidth = jobButton.Rect.Width;
|
||||
characterColumnWidth = characterButton.Rect.Width;
|
||||
@@ -692,7 +713,7 @@ namespace Barotrauma
|
||||
{
|
||||
foreach (Character character in crew.Where(c => c.TeamID == teamIDs[i]))
|
||||
{
|
||||
if (!(character is AICharacter) && connectedClients.Any(c => c.Character == null && c.Name == character.Name)) { continue; }
|
||||
if (character is not AICharacter && connectedClients.Any(c => c.Character == null && c.Name == character.Name)) { continue; }
|
||||
CreateMultiPlayerCharacterElement(character, GameMain.Client.PreviouslyConnectedClients.FirstOrDefault(c => c.Character == character), i);
|
||||
}
|
||||
}
|
||||
@@ -723,7 +744,8 @@ namespace Barotrauma
|
||||
|
||||
var paddedFrame = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.9f), frame.RectTransform, Anchor.Center), isHorizontal: true)
|
||||
{
|
||||
AbsoluteSpacing = 2
|
||||
AbsoluteSpacing = 2,
|
||||
Stretch = true
|
||||
};
|
||||
|
||||
new GUICustomComponent(new RectTransform(new Point(jobColumnWidth, paddedFrame.Rect.Height), paddedFrame.RectTransform, Anchor.Center), onDraw: (sb, component) => character.Info.DrawJobIcon(sb, component.Rect))
|
||||
@@ -736,6 +758,19 @@ namespace Barotrauma
|
||||
if (client != null)
|
||||
{
|
||||
CreateNameWithPermissionIcon(client, paddedFrame, out GUIImage permissionIcon);
|
||||
|
||||
if (GameMain.GameSession?.GameMode is PvPMode)
|
||||
{
|
||||
new GUITextBlock(new RectTransform(new Point(killColumnWidth, paddedFrame.Rect.Height), paddedFrame.RectTransform), string.Empty, textAlignment: Alignment.Center)
|
||||
{
|
||||
TextGetter = () => GameMain.GameSession.Missions.Sum(m => (m as CombatMission)?.GetClientKillCount(client) ?? 0).ToString()
|
||||
};
|
||||
new GUITextBlock(new RectTransform(new Point(deathColumnWidth, paddedFrame.Rect.Height), paddedFrame.RectTransform), string.Empty, textAlignment: Alignment.Center)
|
||||
{
|
||||
TextGetter = () => GameMain.GameSession.Missions.Sum(m => (m as CombatMission)?.GetClientDeathCount(client) ?? 0).ToString()
|
||||
};
|
||||
}
|
||||
|
||||
linkedGUIList.Add(new LinkedGUI(client, frame,
|
||||
new GUITextBlock(new RectTransform(new Point(pingColumnWidth, paddedFrame.Rect.Height), paddedFrame.RectTransform), client.Ping.ToString(), textAlignment: Alignment.Center),
|
||||
permissionIcon));
|
||||
@@ -745,6 +780,18 @@ namespace Barotrauma
|
||||
GUITextBlock characterNameBlock = new GUITextBlock(new RectTransform(new Point(characterColumnWidth, paddedFrame.Rect.Height), paddedFrame.RectTransform),
|
||||
ToolBox.LimitString(character.Info.Name, GUIStyle.Font, characterColumnWidth), textAlignment: Alignment.Center, textColor: character.Info.Job.Prefab.UIColor);
|
||||
|
||||
if (GameMain.GameSession?.GameMode is PvPMode)
|
||||
{
|
||||
new GUITextBlock(new RectTransform(new Point(killColumnWidth, paddedFrame.Rect.Height), paddedFrame.RectTransform), string.Empty, textAlignment: Alignment.Center)
|
||||
{
|
||||
TextGetter = () => GameMain.GameSession.Missions.Sum(m => (m as CombatMission)?.GetBotKillCount(character.Info) ?? 0).ToString()
|
||||
};
|
||||
new GUITextBlock(new RectTransform(new Point(deathColumnWidth, paddedFrame.Rect.Height), paddedFrame.RectTransform), string.Empty, textAlignment: Alignment.Center)
|
||||
{
|
||||
TextGetter = () => GameMain.GameSession.Missions.Sum(m => (m as CombatMission)?.GetBotDeathCount(character.Info) ?? 0).ToString()
|
||||
};
|
||||
}
|
||||
|
||||
if (character is AICharacter)
|
||||
{
|
||||
linkedGUIList.Add(new LinkedGUI(character, frame,
|
||||
@@ -764,6 +811,8 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
CreateWalletCrewFrame(character, paddedFrame);
|
||||
|
||||
paddedFrame.Recalculate();
|
||||
}
|
||||
|
||||
private void CreateMultiPlayerClientElement(Client client)
|
||||
@@ -785,7 +834,8 @@ namespace Barotrauma
|
||||
|
||||
var paddedFrame = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.9f), frame.RectTransform, Anchor.Center), isHorizontal: true)
|
||||
{
|
||||
AbsoluteSpacing = 2
|
||||
AbsoluteSpacing = 2,
|
||||
Stretch = true
|
||||
};
|
||||
|
||||
new GUICustomComponent(new RectTransform(new Point(jobColumnWidth, paddedFrame.Rect.Height), paddedFrame.RectTransform, Anchor.Center),
|
||||
@@ -797,6 +847,19 @@ namespace Barotrauma
|
||||
};
|
||||
|
||||
CreateNameWithPermissionIcon(client, paddedFrame, out GUIImage permissionIcon);
|
||||
|
||||
if (GameMain.GameSession?.GameMode is PvPMode)
|
||||
{
|
||||
new GUITextBlock(new RectTransform(new Point(killColumnWidth, paddedFrame.Rect.Height), paddedFrame.RectTransform), string.Empty, textAlignment: Alignment.Center)
|
||||
{
|
||||
TextGetter = () => GameMain.GameSession.Missions.Sum(m => (m as CombatMission)?.GetClientKillCount(client) ?? 0).ToString()
|
||||
};
|
||||
new GUITextBlock(new RectTransform(new Point(deathColumnWidth, paddedFrame.Rect.Height), paddedFrame.RectTransform), string.Empty, textAlignment: Alignment.Center)
|
||||
{
|
||||
TextGetter = () => GameMain.GameSession.Missions.Sum(m => (m as CombatMission)?.GetClientDeathCount(client) ?? 0).ToString()
|
||||
};
|
||||
}
|
||||
|
||||
linkedGUIList.Add(new LinkedGUI(client, frame,
|
||||
new GUITextBlock(new RectTransform(new Point(pingColumnWidth, paddedFrame.Rect.Height), paddedFrame.RectTransform), client.Ping.ToString(), textAlignment: Alignment.Center),
|
||||
permissionIcon));
|
||||
@@ -805,6 +868,8 @@ namespace Barotrauma
|
||||
{
|
||||
CreateWalletCrewFrame(character, paddedFrame);
|
||||
}
|
||||
|
||||
paddedFrame.Recalculate();
|
||||
}
|
||||
|
||||
private int GetTeamIndex(Client client)
|
||||
@@ -842,7 +907,7 @@ namespace Barotrauma
|
||||
|
||||
private void CreateWalletCrewFrame(Character character, GUILayoutGroup paddedFrame)
|
||||
{
|
||||
if (!(GameMain.GameSession?.Campaign is MultiPlayerCampaign)) { return; }
|
||||
if (GameMain.GameSession?.Campaign is not MultiPlayerCampaign) { return; }
|
||||
|
||||
GUILayoutGroup walletLayout = new GUILayoutGroup(new RectTransform(new Point(walletColumnWidth, paddedFrame.Rect.Height), paddedFrame.RectTransform, Anchor.Center), childAnchor: Anchor.Center)
|
||||
{
|
||||
@@ -947,7 +1012,6 @@ namespace Barotrauma
|
||||
float iconWidth = iconSize.X / (float)characterColumnWidth;
|
||||
int xOffset = (int)(jobColumnWidth + characterNameBlock.TextPos.X - GUIStyle.Font.MeasureString(characterNameBlock.Text).X / 2f - paddedFrame.AbsoluteSpacing - iconWidth * paddedFrame.Rect.Width);
|
||||
permissionIcon = new GUIImage(new RectTransform(new Vector2(iconWidth, 1f), paddedFrame.RectTransform) { AbsoluteOffset = new Point(xOffset + 2, 0) }, permissionIconSprite) { IgnoreLayoutGroups = true };
|
||||
|
||||
|
||||
if (client.Character != null && client.Character.IsDead)
|
||||
{
|
||||
@@ -977,10 +1041,7 @@ namespace Barotrauma
|
||||
}
|
||||
else if (client.Character != null && client.Character.IsDead)
|
||||
{
|
||||
if (client.Character.Info != null)
|
||||
{
|
||||
client.Character.Info.DrawJobIcon(spriteBatch, area);
|
||||
}
|
||||
client.Character.Info?.DrawJobIcon(spriteBatch, area);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1663,6 +1724,8 @@ namespace Barotrauma
|
||||
|
||||
private static void CreateSubmarineInfo(GUIFrame infoFrame, Submarine sub)
|
||||
{
|
||||
if (sub == null) { return; }
|
||||
|
||||
GUIFrame subInfoFrame = new GUIFrame(new RectTransform(Vector2.One, infoFrame.RectTransform, Anchor.TopCenter), style: "GUIFrameListBox");
|
||||
GUIFrame paddedFrame = new GUIFrame(new RectTransform(Vector2.One * 0.97f, subInfoFrame.RectTransform, Anchor.Center), style: null);
|
||||
|
||||
@@ -1765,7 +1828,7 @@ namespace Barotrauma
|
||||
{
|
||||
parent.Content.ClearChildren();
|
||||
List<GUITextBlock> skillNames = new List<GUITextBlock>();
|
||||
foreach (Skill skill in info.Job.GetSkills())
|
||||
foreach (Skill skill in info.Job.GetSkills().OrderByDescending(static s => s.Level))
|
||||
{
|
||||
GUILayoutGroup skillContainer = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.0f), parent.Content.RectTransform), isHorizontal: true) { CanBeFocused = true };
|
||||
var skillName = new GUITextBlock(new RectTransform(new Vector2(0.7f, 0.0f), skillContainer.RectTransform), TextManager.Get($"skillname.{skill.Identifier}").Fallback(skill.Identifier.Value));
|
||||
|
||||
@@ -7,6 +7,7 @@ using System.Linq;
|
||||
using Barotrauma.Extensions;
|
||||
using Barotrauma.Networking;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using Microsoft.Xna.Framework.Input;
|
||||
using static Barotrauma.TalentTree;
|
||||
using static Barotrauma.TalentTree.TalentStages;
|
||||
@@ -83,6 +84,10 @@ namespace Barotrauma
|
||||
private GUIButton? talentApplyButton,
|
||||
talentResetButton;
|
||||
|
||||
private delegate void StartAnimation(RectangleF start, RectangleF end, float duration);
|
||||
private StartAnimation? startAnimation;
|
||||
private GUIComponent? talentMainArea;
|
||||
|
||||
public void CreateGUI(GUIFrame parent, Character? targetCharacter)
|
||||
{
|
||||
parent.ClearChildren();
|
||||
@@ -136,7 +141,7 @@ namespace Barotrauma
|
||||
GUILayoutGroup playerFrame = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.9f), containerFrame.RectTransform, Anchor.TopCenter));
|
||||
GameMain.NetLobbyScreen.CreatePlayerFrame(playerFrame, alwaysAllowEditing: true, createPendingText: false);
|
||||
|
||||
if (!GameMain.NetLobbyScreen.PermadeathMode)
|
||||
if (!GameMain.NetLobbyScreen.PermadeathMode && GameMain.GameSession?.GameMode is not PvPMode)
|
||||
{
|
||||
GUIButton newCharacterBox = new GUIButton(new RectTransform(new Vector2(0.5f, 0.2f), skillLayout.RectTransform, Anchor.BottomRight),
|
||||
text: GameMain.NetLobbyScreen.CampaignCharacterDiscarded ? TextManager.Get("settings") : TextManager.Get("createnew"), style: "GUIButtonSmall")
|
||||
@@ -341,7 +346,15 @@ namespace Barotrauma
|
||||
|
||||
private void CreateTalentMenu(GUIComponent parent, CharacterInfo info, TalentTree tree)
|
||||
{
|
||||
GUIListBox mainList = new GUIListBox(new RectTransform(new Vector2(1f, 0.9f), parent.RectTransform, anchor: Anchor.TopCenter));
|
||||
talentMainArea = new GUIFrame(new RectTransform(new Vector2(1f, 0.9f), parent.RectTransform, Anchor.TopCenter), style: null );
|
||||
|
||||
GUIListBox mainList = new GUIListBox(new RectTransform(Vector2.One, talentMainArea.RectTransform));
|
||||
startAnimation = CreatePopupAnimationHandler(talentMainArea);
|
||||
|
||||
if (info is { TalentRefundPoints: > 0, ShowTalentResetPopupOnOpen: true })
|
||||
{
|
||||
CreateTalentResetPopup(talentMainArea);
|
||||
}
|
||||
|
||||
selectedTalents = info.GetUnlockedTalentsInTree().ToHashSet();
|
||||
|
||||
@@ -425,6 +438,124 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
private void CreateTalentResetPopup(GUIComponent parent)
|
||||
{
|
||||
bool hasResetTalentsBefore = character?.Info.TalentResetCount > 0;
|
||||
var bgBlocker = new GUIFrame(new RectTransform(Vector2.One, parent.RectTransform, anchor: Anchor.Center), style: "GUIBackgroundBlocker")
|
||||
{
|
||||
IgnoreLayoutGroups = true
|
||||
};
|
||||
|
||||
var popup = new GUIFrame(new RectTransform(new Vector2(0.6f, 0.8f), bgBlocker.RectTransform, Anchor.Center));
|
||||
|
||||
var popupLayout = new GUILayoutGroup(new RectTransform(ToolBox.PaddingSizeParentRelative(popup.RectTransform, 0.95f), popup.RectTransform, Anchor.Center), isHorizontal: false);
|
||||
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.15f), popupLayout.RectTransform), TextManager.Get("talentresetheader"), font: GUIStyle.SubHeadingFont, textAlignment: Alignment.Center);
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, hasResetTalentsBefore ? 0.25f : 0.5f), popupLayout.RectTransform), TextManager.Get("talentresetprompt"), wrap: true);
|
||||
|
||||
if (hasResetTalentsBefore)
|
||||
{
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.25f), popupLayout.RectTransform), TextManager.Get("talentresetpromptwarning"), wrap: true)
|
||||
{
|
||||
TextColor = GUIStyle.Red
|
||||
};
|
||||
}
|
||||
|
||||
var buttonLayout = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.35f), popupLayout.RectTransform), childAnchor: Anchor.CenterLeft, isHorizontal: true);
|
||||
|
||||
var confirmButton = new GUIButton(new RectTransform(new Vector2(0.5f, 1.0f), buttonLayout.RectTransform), TextManager.Get("holdtoconfirm"))
|
||||
{
|
||||
RequireHold = true,
|
||||
HoldDurationSeconds = 1.5f,
|
||||
OnClicked = (button, o) =>
|
||||
{
|
||||
if (character is null || characterInfo is null) { return false; }
|
||||
|
||||
characterInfo.RefundTalents();
|
||||
selectedTalents.Clear();
|
||||
UpdateTalentInfo();
|
||||
bgBlocker.Visible = false;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
var denyButton = new GUIButton(new RectTransform(new Vector2(0.5f, 1.0f), buttonLayout.RectTransform), TextManager.Get("decidelater"))
|
||||
{
|
||||
RequireHold = false,
|
||||
OnClicked = (button, userData) =>
|
||||
{
|
||||
if (talentResetButton is not { } resetButton) { return false; }
|
||||
startAnimation?.Invoke(popup.Rect, resetButton.Rect, 0.25f);
|
||||
resetButton.Flash(GUIStyle.Green);
|
||||
bgBlocker.Visible = false;
|
||||
if (characterInfo != null)
|
||||
{
|
||||
characterInfo.ShowTalentResetPopupOnOpen = false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static StartAnimation CreatePopupAnimationHandler(GUIComponent parent)
|
||||
{
|
||||
bool drawAnimation = false;
|
||||
|
||||
float animDur = 1f,
|
||||
animTimer = 0f;
|
||||
|
||||
RectangleF drawRect = RectangleF.Empty,
|
||||
animStartRect = RectangleF.Empty,
|
||||
animEndRect = RectangleF.Empty;
|
||||
|
||||
void StartAnimation(RectangleF start, RectangleF end, float duration)
|
||||
{
|
||||
animStartRect = start;
|
||||
animEndRect = end;
|
||||
animTimer = 0;
|
||||
animDur = duration;
|
||||
drawRect = start;
|
||||
drawAnimation = true;
|
||||
}
|
||||
|
||||
void OnDraw(SpriteBatch batch, GUICustomComponent component)
|
||||
{
|
||||
if (!drawAnimation) { return; }
|
||||
|
||||
GUIComponentStyle style = GUIStyle.GetComponentStyle("GUIFrame");
|
||||
|
||||
style.Sprites[GUIComponent.ComponentState.None][0].Draw(batch, drawRect, Color.White);
|
||||
}
|
||||
|
||||
void OnUpdate(float f, GUICustomComponent component)
|
||||
{
|
||||
if (!drawAnimation) { return; }
|
||||
|
||||
animTimer += f;
|
||||
if (animTimer > animDur)
|
||||
{
|
||||
drawRect = animEndRect;
|
||||
drawAnimation = false;
|
||||
return;
|
||||
}
|
||||
|
||||
float lerp = animTimer / animDur;
|
||||
|
||||
drawRect = new RectangleF(
|
||||
MathHelper.Lerp(animStartRect.X, animEndRect.X, lerp),
|
||||
MathHelper.Lerp(animStartRect.Y, animEndRect.Y, lerp),
|
||||
MathHelper.Lerp(animStartRect.Width, animEndRect.Width, lerp),
|
||||
MathHelper.Lerp(animStartRect.Height, animEndRect.Height, lerp));
|
||||
}
|
||||
|
||||
new GUICustomComponent(new RectTransform(Vector2.One, parent.RectTransform), onDraw: OnDraw, onUpdate: OnUpdate)
|
||||
{
|
||||
IgnoreLayoutGroups = true,
|
||||
CanBeFocused = false
|
||||
};
|
||||
|
||||
return StartAnimation;
|
||||
}
|
||||
|
||||
private void CreateTalentOption(GUIComponent parent, TalentSubTree subTree, int index, TalentOption talentOption, CharacterInfo info, int specializationCount)
|
||||
{
|
||||
int elementPadding = GUI.IntScale(8);
|
||||
@@ -679,6 +810,15 @@ namespace Barotrauma
|
||||
private bool ResetTalentSelection(GUIButton guiButton, object userData)
|
||||
{
|
||||
if (characterInfo is null) { return false; }
|
||||
|
||||
int newTalentCount = selectedTalents.Count - characterInfo.GetUnlockedTalentsInTree().Count();
|
||||
// if we don't have talents selected, and we have points to refund, show the refund popup
|
||||
if (characterInfo.TalentRefundPoints > 0 && newTalentCount == 0)
|
||||
{
|
||||
CreateTalentResetPopup(talentMainArea!);
|
||||
return true;
|
||||
}
|
||||
|
||||
selectedTalents = characterInfo.GetUnlockedTalentsInTree().ToHashSet();
|
||||
UpdateTalentInfo();
|
||||
return true;
|
||||
@@ -844,12 +984,31 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly LocalizedString refundText = TextManager.Get("refund"),
|
||||
resetText = TextManager.Get("reset");
|
||||
|
||||
public void Update()
|
||||
{
|
||||
if (characterInfo is null || talentResetButton is null || talentApplyButton is null) { return; }
|
||||
|
||||
int talentCount = selectedTalents.Count - characterInfo.GetUnlockedTalentsInTree().Count();
|
||||
talentResetButton.Enabled = talentApplyButton.Enabled = talentCount > 0;
|
||||
talentApplyButton.Enabled = talentCount > 0;
|
||||
talentResetButton.Enabled = talentCount > 0 || characterInfo.TalentRefundPoints > 0;
|
||||
|
||||
if (talentCount == 0 && characterInfo.TalentRefundPoints > 0)
|
||||
{
|
||||
if (talentResetButton.FlashTimer <= 0.0f)
|
||||
{
|
||||
talentResetButton.Flash(GUIStyle.Orange);
|
||||
}
|
||||
|
||||
talentResetButton.Text = refundText;
|
||||
}
|
||||
else
|
||||
{
|
||||
talentResetButton.Text = resetText;
|
||||
}
|
||||
|
||||
if (talentApplyButton.Enabled && talentApplyButton.FlashTimer <= 0.0f)
|
||||
{
|
||||
talentApplyButton.Flash(GUIStyle.Orange);
|
||||
@@ -893,6 +1052,22 @@ namespace Barotrauma
|
||||
return info.GetIdentifierUsingOriginalName() == ownCharacterInfo.GetIdentifierUsingOriginalName();
|
||||
}
|
||||
|
||||
private static bool IsOnSameTeam(CharacterInfo? info)
|
||||
{
|
||||
if (info is null) { return false; }
|
||||
|
||||
CharacterTeamType? ownCharacterTeam = Character.Controlled?.TeamID ?? GameMain.Client?.MyClient?.TeamID;
|
||||
if (ownCharacterTeam is null) { return false; }
|
||||
|
||||
return info.TeamID == ownCharacterTeam;
|
||||
}
|
||||
|
||||
private static bool IsSpectatingInMultiplayer()
|
||||
{
|
||||
if (GameMain.Client?.MyClient is not { } myClient) { return false; }
|
||||
return myClient.Spectating;
|
||||
}
|
||||
|
||||
public static bool CanManageTalents(CharacterInfo targetInfo)
|
||||
{
|
||||
// in singleplayer we can do whatever we want
|
||||
@@ -901,10 +1076,16 @@ namespace Barotrauma
|
||||
// always allow managing talents for own character
|
||||
if (IsOwnCharacter(targetInfo)) { return true; }
|
||||
|
||||
// disallow managing talents while spectating
|
||||
if (IsSpectatingInMultiplayer()) { return false; }
|
||||
|
||||
// don't allow controlling non-bot characters
|
||||
if (targetInfo.Character is not { IsBot: true }) { return false; }
|
||||
|
||||
// lastly check if we have the permission to do this
|
||||
// only allow managing talents for bots on the same team
|
||||
if (!IsOnSameTeam(targetInfo)) { return false; }
|
||||
|
||||
// lastly, check if we have the permission to do this
|
||||
return GameMain.Client is { } client && client.HasPermission(ClientPermissions.ManageBotTalents);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user