v0.12.0.2
This commit is contained in:
@@ -287,6 +287,7 @@ namespace Barotrauma
|
||||
{
|
||||
lock (mutex)
|
||||
{
|
||||
usedIndicatorAngles.Clear();
|
||||
|
||||
if (ScreenChanged)
|
||||
{
|
||||
@@ -1117,15 +1118,26 @@ namespace Barotrauma
|
||||
/// Set the cursor to an hourglass.
|
||||
/// Will automatically revert after 10 seconds or when <see cref="ClearCursorWait"/> is called.
|
||||
/// </summary>
|
||||
public static void SetCursorWaiting()
|
||||
public static void SetCursorWaiting(int waitSeconds = 10, Func<bool> endCondition = null)
|
||||
{
|
||||
CoroutineManager.StartCoroutine(WaitCursorCoroutine(), "WaitCursorTimeout");
|
||||
|
||||
static IEnumerable<object> WaitCursorCoroutine()
|
||||
IEnumerable<object> WaitCursorCoroutine()
|
||||
{
|
||||
MouseCursor = CursorState.Waiting;
|
||||
var timeOut = DateTime.Now + new TimeSpan(0, 0, 10);
|
||||
while (DateTime.Now < timeOut) { yield return CoroutineStatus.Running; }
|
||||
var timeOut = DateTime.Now + new TimeSpan(0, 0, waitSeconds);
|
||||
while (DateTime.Now < timeOut)
|
||||
{
|
||||
if (endCondition != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (endCondition.Invoke()) { break; }
|
||||
}
|
||||
catch { break; }
|
||||
}
|
||||
yield return CoroutineStatus.Running;
|
||||
}
|
||||
if (MouseCursor == CursorState.Waiting) { MouseCursor = CursorState.Default; }
|
||||
yield return CoroutineStatus.Success;
|
||||
}
|
||||
@@ -1219,7 +1231,7 @@ namespace Barotrauma
|
||||
{
|
||||
foreach (GUIMessage msg in messages)
|
||||
{
|
||||
if (msg.WorldSpace) continue;
|
||||
if (msg.WorldSpace) { continue; }
|
||||
msg.Timer -= deltaTime;
|
||||
|
||||
if (msg.Size.X > HUDLayoutSettings.MessageAreaTop.Width)
|
||||
@@ -1244,7 +1256,7 @@ namespace Barotrauma
|
||||
|
||||
foreach (GUIMessage msg in messages)
|
||||
{
|
||||
if (!msg.WorldSpace) continue;
|
||||
if (!msg.WorldSpace) { continue; }
|
||||
msg.Timer -= deltaTime;
|
||||
msg.Pos += msg.Velocity * deltaTime;
|
||||
}
|
||||
@@ -1256,18 +1268,21 @@ namespace Barotrauma
|
||||
|
||||
#region Element drawing
|
||||
|
||||
private static List<float> usedIndicatorAngles = new List<float>();
|
||||
|
||||
/// <param name="createOffset">Should the indicator move based on the camera position?</param>
|
||||
public static void DrawIndicator(SpriteBatch spriteBatch, Vector2 worldPosition, Camera cam, float hideDist, Sprite sprite, Color color, bool createOffset = true, float scaleMultiplier = 1.0f)
|
||||
/// <param name="overrideAlpha">Override the distance-based alpha value with the specified alpha value</param>
|
||||
public static void DrawIndicator(SpriteBatch spriteBatch, Vector2 worldPosition, Camera cam, float hideDist, Sprite sprite, Color color,
|
||||
bool createOffset = true, float scaleMultiplier = 1.0f, float? overrideAlpha = null)
|
||||
{
|
||||
Vector2 diff = worldPosition - cam.WorldViewCenter;
|
||||
float dist = diff.Length();
|
||||
|
||||
float symbolScale = Math.Min(64.0f / sprite.size.X, 1.0f) * scaleMultiplier;
|
||||
|
||||
if (dist > hideDist)
|
||||
if (overrideAlpha.HasValue || dist > hideDist)
|
||||
{
|
||||
float alpha = Math.Min((dist - hideDist) / 100.0f, 1.0f);
|
||||
float alpha = overrideAlpha ?? Math.Min((dist - hideDist) / 100.0f, 1.0f);
|
||||
Vector2 targetScreenPos = cam.WorldToScreen(worldPosition);
|
||||
|
||||
if (!createOffset)
|
||||
@@ -1279,6 +1294,28 @@ namespace Barotrauma
|
||||
float screenDist = Vector2.Distance(cam.WorldToScreen(cam.WorldViewCenter), targetScreenPos);
|
||||
float angle = MathUtils.VectorToAngle(diff);
|
||||
|
||||
float minAngleDiff = 0.05f;
|
||||
bool overlapFound = true;
|
||||
int iterations = 0;
|
||||
while (overlapFound && iterations < 10)
|
||||
{
|
||||
overlapFound = false;
|
||||
foreach (float usedIndicatorAngle in usedIndicatorAngles)
|
||||
{
|
||||
float shortestAngle = MathUtils.GetShortestAngle(angle, usedIndicatorAngle);
|
||||
if (MathUtils.NearlyEqual(shortestAngle, 0.0f)) { shortestAngle = 0.01f; }
|
||||
if (Math.Abs(shortestAngle) < minAngleDiff)
|
||||
{
|
||||
angle -= Math.Sign(shortestAngle) * (minAngleDiff - Math.Abs(shortestAngle));
|
||||
overlapFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
iterations++;
|
||||
}
|
||||
|
||||
usedIndicatorAngles.Add(angle);
|
||||
|
||||
Vector2 unclampedDiff = new Vector2(
|
||||
(float)Math.Cos(angle) * screenDist,
|
||||
(float)-Math.Sin(angle) * screenDist);
|
||||
@@ -1489,12 +1526,12 @@ namespace Barotrauma
|
||||
|
||||
foreach (GUIMessage msg in messages)
|
||||
{
|
||||
if (msg.WorldSpace) continue;
|
||||
if (msg.WorldSpace) { continue; }
|
||||
|
||||
Vector2 drawPos = new Vector2(HUDLayoutSettings.MessageAreaTop.Right, HUDLayoutSettings.MessageAreaTop.Center.Y);
|
||||
|
||||
msg.Font.DrawString(spriteBatch, msg.Text, drawPos + msg.Pos + Vector2.One, Color.Black, 0, msg.Origin, 1.0f, SpriteEffects.None, 0);
|
||||
msg.Font.DrawString(spriteBatch, msg.Text, drawPos + msg.Pos, msg.Color, 0, msg.Origin, 1.0f, SpriteEffects.None, 0);
|
||||
msg.Font.DrawString(spriteBatch, msg.Text, drawPos + msg.DrawPos + Vector2.One, Color.Black, 0, msg.Origin, 1.0f, SpriteEffects.None, 0);
|
||||
msg.Font.DrawString(spriteBatch, msg.Text, drawPos + msg.DrawPos, msg.Color, 0, msg.Origin, 1.0f, SpriteEffects.None, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1507,14 +1544,14 @@ namespace Barotrauma
|
||||
|
||||
foreach (GUIMessage msg in messages)
|
||||
{
|
||||
if (!msg.WorldSpace) continue;
|
||||
if (!msg.WorldSpace) { continue; }
|
||||
|
||||
if (cam != null)
|
||||
{
|
||||
float alpha = 1.0f;
|
||||
if (msg.Timer < 1.0f) alpha -= 1.0f - msg.Timer;
|
||||
if (msg.Timer < 1.0f) { alpha -= 1.0f - msg.Timer; }
|
||||
|
||||
Vector2 drawPos = cam.WorldToScreen(msg.Pos);
|
||||
Vector2 drawPos = cam.WorldToScreen(msg.DrawPos);
|
||||
msg.Font.DrawString(spriteBatch, msg.Text, drawPos + Vector2.One, Color.Black * alpha, 0, msg.Origin, 1.0f, SpriteEffects.None, 0);
|
||||
msg.Font.DrawString(spriteBatch, msg.Text, drawPos, msg.Color * alpha, 0, msg.Origin, 1.0f, SpriteEffects.None, 0);
|
||||
}
|
||||
@@ -1608,7 +1645,8 @@ namespace Barotrauma
|
||||
|
||||
public static Texture2D CreateCapsule(int radius, int height)
|
||||
{
|
||||
int textureWidth = radius * 2, textureHeight = height + radius * 2;
|
||||
int textureWidth = Math.Max(radius * 2, 1);
|
||||
int textureHeight = Math.Max(height + radius * 2, 1);
|
||||
|
||||
Color[] data = new Color[textureWidth * textureHeight];
|
||||
|
||||
@@ -2079,7 +2117,7 @@ namespace Barotrauma
|
||||
|
||||
if (pauseMenuOpen)
|
||||
{
|
||||
Inventory.draggingItem = null;
|
||||
Inventory.DraggingItems.Clear();
|
||||
Inventory.DraggingInventory = null;
|
||||
|
||||
PauseMenu = new GUIFrame(new RectTransform(Vector2.One, Canvas, Anchor.Center), style: null);
|
||||
@@ -2288,9 +2326,10 @@ namespace Barotrauma
|
||||
if (playSound) SoundPlayer.PlayUISound(GUISoundType.UIMessage);
|
||||
}
|
||||
|
||||
public static void AddMessage(string message, Color color, Vector2 worldPos, Vector2 velocity, float lifeTime = 3.0f, bool playSound = true, GUISoundType soundType = GUISoundType.UIMessage)
|
||||
public static void AddMessage(string message, Color color, Vector2 pos, Vector2 velocity, float lifeTime = 3.0f, bool playSound = true, GUISoundType soundType = GUISoundType.UIMessage, int subId = -1)
|
||||
{
|
||||
messages.Add(new GUIMessage(message, color, worldPos, velocity, lifeTime, Alignment.Center, LargeFont));
|
||||
Submarine sub = Submarine.Loaded.FirstOrDefault(s => s.ID == subId);
|
||||
messages.Add(new GUIMessage(message, color, pos, velocity, lifeTime, Alignment.Center, LargeFont, sub: sub));
|
||||
if (playSound) SoundPlayer.PlayUISound(soundType);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,210 @@
|
||||
#nullable enable
|
||||
using System;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using Microsoft.Xna.Framework;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
public class GUIColorPicker : GUIComponent
|
||||
{
|
||||
public delegate bool OnColorSelectedHandler(GUIColorPicker component, Color color);
|
||||
public OnColorSelectedHandler? OnColorSelected;
|
||||
|
||||
public float SelectedHue;
|
||||
public float SelectedSaturation;
|
||||
public float SelectedValue;
|
||||
|
||||
public Color CurrentColor = Color.Black;
|
||||
|
||||
private Rectangle MainArea,
|
||||
HueArea;
|
||||
|
||||
private Texture2D? mainTexture,
|
||||
hueTexture;
|
||||
|
||||
private Color[]? colorData;
|
||||
|
||||
private Rectangle selectedRect;
|
||||
|
||||
private bool mouseHeld;
|
||||
private bool isInitialized;
|
||||
|
||||
private readonly Color transparentWhite = Color.White * 0.8f,
|
||||
transparentBlack = Color.Black * 0.8f;
|
||||
|
||||
public GUIColorPicker(RectTransform rectT, string? style = null) : base(style, rectT) { }
|
||||
|
||||
~GUIColorPicker()
|
||||
{
|
||||
DisposeTextures();
|
||||
}
|
||||
|
||||
private void Init()
|
||||
{
|
||||
int tWidth = Rect.Width;
|
||||
int sliceWidth = Rect.Width / 8;
|
||||
|
||||
int mainWidth = tWidth - sliceWidth;
|
||||
int hueWidth = sliceWidth;
|
||||
|
||||
MainArea = new Rectangle(0, 0, mainWidth, Rect.Height);
|
||||
HueArea = new Rectangle(mainWidth, 0, hueWidth, Rect.Height);
|
||||
|
||||
colorData = new Color[MainArea.Width * MainArea.Height];
|
||||
|
||||
if (mainTexture == null)
|
||||
{
|
||||
int width = MainArea.Width,
|
||||
height = MainArea.Height;
|
||||
|
||||
GenerateGradient(ref colorData!, width, height, DrawHVArea);
|
||||
mainTexture = CreateGradientTexture(colorData!, MainArea.Width, MainArea.Height);
|
||||
}
|
||||
|
||||
if (hueTexture == null)
|
||||
{
|
||||
int width = HueArea.Width,
|
||||
height = HueArea.Height;
|
||||
|
||||
Color[] hueData = new Color[width * height];
|
||||
|
||||
GenerateGradient(ref hueData, width, height, DrawHueArea);
|
||||
hueTexture = CreateGradientTexture(hueData, width, height);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Draw(SpriteBatch spriteBatch)
|
||||
{
|
||||
if (mainTexture == null || hueTexture == null || !isInitialized) { return; }
|
||||
|
||||
Rectangle mainArea = MainArea,
|
||||
hueArea = HueArea;
|
||||
|
||||
hueArea.Location += Rect.Location;
|
||||
mainArea.Location += Rect.Location;
|
||||
|
||||
Vector2 mainLocation = mainArea.Location.ToVector2(),
|
||||
hueLocation = hueArea.Location.ToVector2();
|
||||
|
||||
spriteBatch.Draw(mainTexture, mainLocation, Color.White);
|
||||
spriteBatch.Draw(hueTexture, hueLocation, Color.White);
|
||||
|
||||
float hueY = hueLocation.Y + ((SelectedHue / 360f) * hueArea.Height);
|
||||
spriteBatch.DrawLine(hueArea.Left, hueY, hueArea.Right, hueY, transparentWhite, thickness: 3);
|
||||
spriteBatch.DrawLine(hueArea.Left, hueY, hueArea.Right, hueY, transparentBlack, thickness: 1);
|
||||
|
||||
float saturationX = mainLocation.X + SelectedSaturation * MainArea.Width;
|
||||
float valueY = mainLocation.Y + (1.0f - SelectedValue) * MainArea.Height;
|
||||
|
||||
spriteBatch.DrawLine(saturationX, mainArea.Top,saturationX, mainArea.Bottom, transparentWhite, thickness: 3);
|
||||
spriteBatch.DrawLine(mainArea.Left,valueY, mainArea.Right, valueY, transparentWhite, thickness: 3);
|
||||
|
||||
spriteBatch.DrawLine(saturationX, mainArea.Top,saturationX, mainArea.Bottom, transparentBlack, thickness: 1);
|
||||
spriteBatch.DrawLine(mainArea.Left,valueY, mainArea.Right, valueY, transparentBlack, thickness: 1);
|
||||
}
|
||||
|
||||
protected override void Update(float deltaTime)
|
||||
{
|
||||
base.Update(deltaTime);
|
||||
|
||||
if (!isInitialized)
|
||||
{
|
||||
Init();
|
||||
isInitialized = true;
|
||||
}
|
||||
|
||||
if (!PlayerInput.PrimaryMouseButtonHeld())
|
||||
{
|
||||
mouseHeld = false;
|
||||
}
|
||||
|
||||
if (GUI.MouseOn != this) { return; }
|
||||
|
||||
Rectangle mainArea = MainArea,
|
||||
hueArea = HueArea;
|
||||
|
||||
hueArea.Location += Rect.Location;
|
||||
mainArea.Location += Rect.Location;
|
||||
|
||||
if (PlayerInput.PrimaryMouseButtonDown())
|
||||
{
|
||||
mouseHeld = true;
|
||||
if (hueArea.Contains(PlayerInput.MousePosition))
|
||||
{
|
||||
selectedRect = HueArea;
|
||||
}
|
||||
else if (mainArea.Contains(PlayerInput.MousePosition))
|
||||
{
|
||||
selectedRect = MainArea;
|
||||
}
|
||||
else
|
||||
{
|
||||
mouseHeld = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!PlayerInput.PrimaryMouseButtonHeld())
|
||||
{
|
||||
mouseHeld = false;
|
||||
}
|
||||
|
||||
if (mouseHeld && (PlayerInput.MouseSpeed != Vector2.Zero || PlayerInput.PrimaryMouseButtonDown()))
|
||||
{
|
||||
if (selectedRect == HueArea)
|
||||
{
|
||||
Vector2 pos = PlayerInput.MousePosition - hueArea.Location.ToVector2();
|
||||
SelectedHue = Math.Clamp(pos.Y / hueArea.Height * 360f, 0, 360);
|
||||
RefreshHue();
|
||||
|
||||
}
|
||||
else if (selectedRect == MainArea)
|
||||
{
|
||||
var (x, y) = PlayerInput.MousePosition - mainArea.Location.ToVector2();
|
||||
SelectedSaturation = Math.Clamp(x / mainArea.Width, 0, 1);
|
||||
SelectedValue = Math.Clamp(1f - (y / mainArea.Height), 0, 1);
|
||||
}
|
||||
|
||||
CurrentColor = ToolBox.HSVToRGB(SelectedHue, SelectedSaturation, SelectedValue);
|
||||
|
||||
OnColorSelected?.Invoke(this, CurrentColor);
|
||||
}
|
||||
}
|
||||
|
||||
public void DisposeTextures()
|
||||
{
|
||||
mainTexture?.Dispose();
|
||||
hueTexture?.Dispose();
|
||||
}
|
||||
|
||||
public void RefreshHue()
|
||||
{
|
||||
if (colorData == null || mainTexture == null) { return; }
|
||||
GenerateGradient(ref colorData, mainTexture.Width, mainTexture.Height, DrawHVArea);
|
||||
mainTexture.SetData(colorData);
|
||||
}
|
||||
|
||||
private Texture2D CreateGradientTexture(Color[] data, int width, int height)
|
||||
{
|
||||
Texture2D texture = new Texture2D(GameMain.GraphicsDeviceManager.GraphicsDevice, width, height);
|
||||
texture.SetData(data);
|
||||
return texture;
|
||||
}
|
||||
|
||||
private void GenerateGradient(ref Color[] data, int width, int height, Func<float, float, Color> algorithm)
|
||||
{
|
||||
for (int y = 0; y < height; y++)
|
||||
{
|
||||
for (int x = 0; x < width; x++)
|
||||
{
|
||||
float relativeX = x / (float) width,
|
||||
relativeY = y / (float) height;
|
||||
|
||||
data[y * width + x] = algorithm(relativeX, relativeY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Color DrawHVArea(float x, float y) => ToolBox.HSVToRGB(SelectedHue, x, 1.0f - y);
|
||||
private Color DrawHueArea(float x, float y) => ToolBox.HSVToRGB(y * 360f, 1f, 1f);
|
||||
}
|
||||
}
|
||||
@@ -510,10 +510,10 @@ namespace Barotrauma
|
||||
for (int i = 0; i < Content.CountChildren; i++)
|
||||
{
|
||||
var child = Content.RectTransform.GetChild(i)?.GUIComponent;
|
||||
if (child == null) continue;
|
||||
if (child == null || !child.Visible) { continue; }
|
||||
|
||||
// selecting
|
||||
if (Enabled && CanBeFocused && child.CanBeFocused && (GUI.IsMouseOn(child)) && child.Rect.Contains(PlayerInput.MousePosition))
|
||||
if (Enabled && CanBeFocused && child.CanBeFocused && child.Rect.Contains(PlayerInput.MousePosition) && GUI.IsMouseOn(child))
|
||||
{
|
||||
child.State = ComponentState.Hover;
|
||||
|
||||
|
||||
@@ -55,6 +55,20 @@ namespace Barotrauma
|
||||
private set;
|
||||
}
|
||||
|
||||
public Submarine Submarine
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public Vector2 DrawPos
|
||||
{
|
||||
get
|
||||
{
|
||||
return Submarine == null ? Pos : Pos + Submarine.DrawPosition;
|
||||
}
|
||||
}
|
||||
|
||||
public GUIMessage(string text, Color color, float lifeTime, ScalableFont font = null)
|
||||
{
|
||||
coloredText = new ColoredText(text, color, false, false);
|
||||
@@ -67,11 +81,11 @@ namespace Barotrauma
|
||||
Font = font;
|
||||
}
|
||||
|
||||
public GUIMessage(string text, Color color, Vector2 worldPosition, Vector2 velocity, float lifeTime, Alignment textAlignment = Alignment.Center, ScalableFont font = null)
|
||||
public GUIMessage(string text, Color color, Vector2 position, Vector2 velocity, float lifeTime, Alignment textAlignment = Alignment.Center, ScalableFont font = null, Submarine sub = null)
|
||||
{
|
||||
coloredText = new ColoredText(text, color, false, false);
|
||||
WorldSpace = true;
|
||||
pos = worldPosition;
|
||||
pos = position;
|
||||
Timer = lifeTime;
|
||||
Velocity = velocity;
|
||||
this.lifeTime = lifeTime;
|
||||
@@ -92,6 +106,8 @@ namespace Barotrauma
|
||||
|
||||
if (textAlignment.HasFlag(Alignment.Bottom))
|
||||
Origin.Y += size.Y * 0.5f;
|
||||
|
||||
Submarine = sub;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,6 +67,8 @@ namespace Barotrauma
|
||||
|
||||
private readonly Type type;
|
||||
|
||||
public Type MessageBoxType => type;
|
||||
|
||||
public static GUIComponent VisibleBox => MessageBoxes.LastOrDefault();
|
||||
|
||||
public GUIMessageBox(string headerText, string text, Vector2? relativeSize = null, Point? minSize = null)
|
||||
@@ -210,6 +212,29 @@ namespace Barotrauma
|
||||
}
|
||||
};
|
||||
|
||||
InputType? closeInput = null;
|
||||
if (GameMain.Config.KeyBind(InputType.Use).MouseButton == MouseButton.None)
|
||||
{
|
||||
closeInput = InputType.Use;
|
||||
}
|
||||
else if (GameMain.Config.KeyBind(InputType.Select).MouseButton == MouseButton.None)
|
||||
{
|
||||
closeInput = InputType.Select;
|
||||
}
|
||||
if (closeInput.HasValue)
|
||||
{
|
||||
Buttons[0].ToolTip = TextManager.ParseInputTypes($"{TextManager.Get("Close")} ([InputType.{closeInput.Value}])");
|
||||
Buttons[0].OnAddedToGUIUpdateList += (GUIComponent component) =>
|
||||
{
|
||||
if (!closing && openState >= 1.0f && PlayerInput.KeyHit(closeInput.Value))
|
||||
{
|
||||
GUIButton btn = component as GUIButton;
|
||||
btn?.OnClicked(btn, btn.UserData);
|
||||
btn?.Flash(GUI.Style.Green);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Header = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), Content.RectTransform), headerText, wrap: true);
|
||||
GUI.Style.Apply(Header, "", this);
|
||||
Header.RectTransform.MinSize = new Point(0, Header.Rect.Height);
|
||||
@@ -291,7 +316,8 @@ namespace Barotrauma
|
||||
{
|
||||
if (Draggable)
|
||||
{
|
||||
if ((GUI.MouseOn == InnerFrame || InnerFrame.IsParentOf(GUI.MouseOn)) && !(GUI.MouseOn is GUIButton))
|
||||
GUIComponent parent = GUI.MouseOn?.Parent?.Parent;
|
||||
if ((GUI.MouseOn == InnerFrame || InnerFrame.IsParentOf(GUI.MouseOn)) && !(GUI.MouseOn is GUIButton || GUI.MouseOn is GUIColorPicker || GUI.MouseOn is GUITextBox || parent is GUITextBox))
|
||||
{
|
||||
GUI.MouseCursor = CursorState.Move;
|
||||
if (PlayerInput.PrimaryMouseButtonDown())
|
||||
|
||||
@@ -70,6 +70,7 @@ namespace Barotrauma
|
||||
public Color ColorInventoryHalf { get; private set; } = Color.Orange;
|
||||
public Color ColorInventoryFull { get; private set; } = Color.LightGreen;
|
||||
public Color ColorInventoryBackground { get; private set; } = Color.Gray;
|
||||
public Color ColorInventoryEmptyOverlay { get; private set; } = Color.Red;
|
||||
|
||||
public Color TextColor { get; private set; } = Color.White * 0.8f;
|
||||
public Color TextColorBright { get; private set; } = Color.White * 0.9f;
|
||||
@@ -150,6 +151,9 @@ namespace Barotrauma
|
||||
case "colorinventorybackground":
|
||||
ColorInventoryBackground = subElement.GetAttributeColor("color", ColorInventoryBackground);
|
||||
break;
|
||||
case "colorinventoryemptyoverlay":
|
||||
ColorInventoryEmptyOverlay = subElement.GetAttributeColor("color", ColorInventoryEmptyOverlay);
|
||||
break;
|
||||
case "textcolordark":
|
||||
TextColorDark = subElement.GetAttributeColor("color", TextColorDark);
|
||||
break;
|
||||
@@ -344,7 +348,7 @@ namespace Barotrauma
|
||||
if (GameMain.Config.Language.Equals(subElement.GetAttributeString("language", ""), StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
uint overrideFontSize = GetFontSize(subElement, 0);
|
||||
if (overrideFontSize > 0) { return overrideFontSize; }
|
||||
if (overrideFontSize > 0) { return (uint)Math.Round(overrideFontSize * GameSettings.TextScale); }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -354,10 +358,10 @@ namespace Barotrauma
|
||||
Point maxResolution = subElement.GetAttributePoint("maxresolution", new Point(int.MaxValue, int.MaxValue));
|
||||
if (GameMain.GraphicsWidth <= maxResolution.X && GameMain.GraphicsHeight <= maxResolution.Y)
|
||||
{
|
||||
return (uint)subElement.GetAttributeInt("size", 14);
|
||||
return (uint)Math.Round(subElement.GetAttributeInt("size", 14) * GameSettings.TextScale);
|
||||
}
|
||||
}
|
||||
return defaultSize;
|
||||
return (uint)Math.Round(defaultSize * GameSettings.TextScale);
|
||||
}
|
||||
|
||||
private string GetFontFilePath(XElement element)
|
||||
|
||||
@@ -240,20 +240,20 @@ namespace Barotrauma
|
||||
|
||||
public class StrikethroughSettings
|
||||
{
|
||||
private Color color = GUI.Style.Red;
|
||||
public Color Color { get; set; } = GUI.Style.Red;
|
||||
private int thickness;
|
||||
private int expand;
|
||||
|
||||
public StrikethroughSettings(Color? color = null, int thickness = 1, int expand = 0)
|
||||
{
|
||||
if (color != null) this.color = color.Value;
|
||||
if (color != null) { Color = color.Value; }
|
||||
this.thickness = thickness;
|
||||
this.expand = expand;
|
||||
}
|
||||
|
||||
public void Draw(SpriteBatch spriteBatch, float textSizeHalf, float xPos, float yPos)
|
||||
{
|
||||
ShapeExtensions.DrawLine(spriteBatch, new Vector2(xPos - textSizeHalf - expand, yPos), new Vector2(xPos + textSizeHalf + expand, yPos), color, thickness);
|
||||
ShapeExtensions.DrawLine(spriteBatch, new Vector2(xPos - textSizeHalf - expand, yPos), new Vector2(xPos + textSizeHalf + expand, yPos), Color, thickness);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -251,7 +251,7 @@ namespace Barotrauma
|
||||
public bool Readonly { get; set; }
|
||||
|
||||
public GUITextBox(RectTransform rectT, string text = "", Color? textColor = null, ScalableFont font = null,
|
||||
Alignment textAlignment = Alignment.Left, bool wrap = false, string style = "", Color? color = null, bool createClearButton = false)
|
||||
Alignment textAlignment = Alignment.Left, bool wrap = false, string style = "", Color? color = null, bool createClearButton = false, bool createPenIcon = true)
|
||||
: base(style, rectT)
|
||||
{
|
||||
HoverCursor = CursorState.IBeam;
|
||||
@@ -283,7 +283,7 @@ namespace Barotrauma
|
||||
clearButtonWidth = (int)(clearButton.Rect.Width * 1.2f);
|
||||
}
|
||||
|
||||
if (this.style != null && this.style.ChildStyles.ContainsKey("textboxicon"))
|
||||
if (this.style != null && this.style.ChildStyles.ContainsKey("textboxicon") && createPenIcon)
|
||||
{
|
||||
icon = new GUIImage(new RectTransform(new Vector2(0.6f, 0.6f), frame.RectTransform, Anchor.CenterRight, scaleBasis: ScaleBasis.BothHeight) { AbsoluteOffset = new Point(5 + clearButtonWidth, 0) }, null, scaleToFit: true);
|
||||
icon.ApplyStyle(this.style.ChildStyles["textboxicon"]);
|
||||
@@ -457,6 +457,11 @@ namespace Barotrauma
|
||||
isSelecting = PlayerInput.KeyDown(Keys.LeftShift) || PlayerInput.KeyDown(Keys.RightShift);
|
||||
}
|
||||
|
||||
if (mouseHeldInside && !PlayerInput.PrimaryMouseButtonHeld())
|
||||
{
|
||||
mouseHeldInside = false;
|
||||
}
|
||||
|
||||
if (CaretEnabled)
|
||||
{
|
||||
if (textBlock.OverflowClipActive)
|
||||
|
||||
@@ -24,9 +24,17 @@ namespace Barotrauma
|
||||
private int buyTotal, sellTotal;
|
||||
|
||||
private GUITextBlock merchantBalanceBlock;
|
||||
private GUILayoutGroup valueChangeGroup;
|
||||
private GUITextBlock currentSellValueBlock, newSellValueBlock;
|
||||
private GUIImage sellValueChangeArrow;
|
||||
private GUIDropDown sortingDropDown;
|
||||
private GUITextBox searchBox;
|
||||
private GUIListBox storeDealsList, storeBuyList, storeSellList;
|
||||
private GUIListBox storeBuyList, storeSellList;
|
||||
/// <summary>
|
||||
/// Can be null when there are no deals at the current location
|
||||
/// </summary>
|
||||
private GUILayoutGroup storeDailySpecialsGroup, storeRequestedGoodGroup;
|
||||
private Color storeSpecialColor;
|
||||
|
||||
private GUIListBox shoppingCrateBuyList, shoppingCrateSellList;
|
||||
private GUITextBlock shoppingCrateTotal;
|
||||
@@ -49,7 +57,6 @@ namespace Barotrauma
|
||||
|
||||
private enum StoreTab
|
||||
{
|
||||
Deals,
|
||||
Buy,
|
||||
Sell
|
||||
}
|
||||
@@ -78,19 +85,19 @@ namespace Barotrauma
|
||||
CurrentLocation.Reputation.OnReputationValueChanged += () => { needsRefresh = true; };
|
||||
}
|
||||
campaignUI.Campaign.CargoManager.OnItemsInBuyCrateChanged += () => { needsBuyingRefresh = true; };
|
||||
campaignUI.Campaign.CargoManager.OnPurchasedItemsChanged += () => { needsBuyingRefresh = true; };
|
||||
campaignUI.Campaign.CargoManager.OnPurchasedItemsChanged += () => { needsRefresh = true; };
|
||||
campaignUI.Campaign.CargoManager.OnItemsInSellCrateChanged += () => { needsSellingRefresh = true; };
|
||||
campaignUI.Campaign.CargoManager.OnSoldItemsChanged += () =>
|
||||
{
|
||||
needsItemsToSellRefresh = true;
|
||||
needsSellingRefresh = true;
|
||||
needsRefresh = true;
|
||||
};
|
||||
}
|
||||
|
||||
public void Refresh()
|
||||
public void Refresh(bool updateOwned = true)
|
||||
{
|
||||
hadPermissions = HasPermissions;
|
||||
UpdateOwnedItems();
|
||||
if (updateOwned) { UpdateOwnedItems(); }
|
||||
RefreshBuying(updateOwned: false);
|
||||
RefreshSelling(updateOwned: false);
|
||||
needsRefresh = false;
|
||||
@@ -100,10 +107,8 @@ namespace Barotrauma
|
||||
{
|
||||
if (updateOwned) { UpdateOwnedItems(); }
|
||||
RefreshShoppingCrateBuyList();
|
||||
//RefreshStoreDealsList();
|
||||
RefreshStoreBuyList();
|
||||
var hasPermissions = HasPermissions;
|
||||
//storeDealsList.Enabled = hasPermissions;
|
||||
storeBuyList.Enabled = hasPermissions;
|
||||
shoppingCrateBuyList.Enabled = hasPermissions;
|
||||
needsBuyingRefresh = false;
|
||||
@@ -166,7 +171,12 @@ namespace Barotrauma
|
||||
};
|
||||
|
||||
// Merchant balance ------------------------------------------------
|
||||
var merchantBalanceContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.75f / 14.0f), storeContent.RectTransform))
|
||||
var balanceAndValueGroup = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.75f / 14.0f), storeContent.RectTransform), isHorizontal: true)
|
||||
{
|
||||
RelativeSpacing = 0.005f
|
||||
};
|
||||
|
||||
var merchantBalanceContainer = new GUILayoutGroup(new RectTransform(new Vector2(0.5f, 1.0f), balanceAndValueGroup.RectTransform))
|
||||
{
|
||||
RelativeSpacing = 0.005f
|
||||
};
|
||||
@@ -177,29 +187,111 @@ namespace Barotrauma
|
||||
ForceUpperCase = true
|
||||
};
|
||||
merchantBalanceBlock = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.5f), merchantBalanceContainer.RectTransform),
|
||||
"", font: GUI.SubHeadingFont, textAlignment: Alignment.TopLeft)
|
||||
"", font: GUI.SubHeadingFont)
|
||||
{
|
||||
AutoScaleVertical = true,
|
||||
TextScale = 1.1f,
|
||||
TextGetter = () =>
|
||||
{
|
||||
var balance = CurrentLocation != null ? CurrentLocation.StoreCurrentBalance : 0;
|
||||
if (balance < (int)(0.25f * Location.StoreInitialBalance))
|
||||
if (CurrentLocation != null)
|
||||
{
|
||||
merchantBalanceBlock.TextColor = Color.Red;
|
||||
}
|
||||
else if (balance < (int)(0.5f * Location.StoreInitialBalance))
|
||||
{
|
||||
merchantBalanceBlock.TextColor = Color.Orange;
|
||||
merchantBalanceBlock.TextColor = CurrentLocation.BalanceColor;
|
||||
return GetCurrencyFormatted(CurrentLocation.StoreCurrentBalance);
|
||||
}
|
||||
else
|
||||
{
|
||||
merchantBalanceBlock.TextColor = Color.White;
|
||||
merchantBalanceBlock.TextColor = Color.Red;
|
||||
return GetCurrencyFormatted(0);
|
||||
}
|
||||
return GetCurrencyFormatted(balance);
|
||||
}
|
||||
};
|
||||
|
||||
// Item sell value ------------------------------------------------
|
||||
var sellValueContainer = new GUILayoutGroup(new RectTransform(new Vector2(0.5f, 1.0f), balanceAndValueGroup.RectTransform))
|
||||
{
|
||||
CanBeFocused = false,
|
||||
RelativeSpacing = 0.005f
|
||||
};
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.5f), sellValueContainer.RectTransform),
|
||||
TextManager.Get("campaignstore.sellvalue"), font: GUI.Font, textAlignment: Alignment.BottomLeft)
|
||||
{
|
||||
AutoScaleVertical = true,
|
||||
CanBeFocused = false,
|
||||
ForceUpperCase = true
|
||||
};
|
||||
|
||||
valueChangeGroup = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.5f), sellValueContainer.RectTransform), isHorizontal: true, childAnchor: Anchor.CenterLeft)
|
||||
{
|
||||
CanBeFocused = true,
|
||||
RelativeSpacing = 0.02f
|
||||
};
|
||||
float blockWidth = GUI.IsFourByThree() ? 0.32f : 0.28f;
|
||||
Point blockMaxSize = new Point((int)(GameSettings.TextScale * 60), valueChangeGroup.Rect.Height);
|
||||
currentSellValueBlock = new GUITextBlock(new RectTransform(new Vector2(blockWidth, 1.0f), valueChangeGroup.RectTransform) { MaxSize = blockMaxSize },
|
||||
"", font: GUI.SubHeadingFont)
|
||||
{
|
||||
AutoScaleVertical = true,
|
||||
CanBeFocused = false,
|
||||
TextScale = 1.1f,
|
||||
TextGetter = () =>
|
||||
{
|
||||
if (CurrentLocation != null)
|
||||
{
|
||||
int balanceAfterTransaction = IsBuying ?
|
||||
CurrentLocation.StoreCurrentBalance + buyTotal :
|
||||
CurrentLocation.StoreCurrentBalance - sellTotal;
|
||||
if (balanceAfterTransaction != CurrentLocation.StoreCurrentBalance)
|
||||
{
|
||||
var newStatus = Location.GetStoreBalanceStatus(balanceAfterTransaction);
|
||||
if (CurrentLocation.ActiveStoreBalanceStatus.SellPriceModifier != newStatus.SellPriceModifier)
|
||||
{
|
||||
string tooltipTag = newStatus.SellPriceModifier > CurrentLocation.ActiveStoreBalanceStatus.SellPriceModifier ?
|
||||
"campaingstore.valueincreasetooltip" : "campaingstore.valuedecreasetooltip";
|
||||
valueChangeGroup.ToolTip = TextManager.Get(tooltipTag);
|
||||
currentSellValueBlock.TextColor = newStatus.Color;
|
||||
sellValueChangeArrow.Color = newStatus.Color;
|
||||
sellValueChangeArrow.Visible = true;
|
||||
newSellValueBlock.TextColor = newStatus.Color;
|
||||
newSellValueBlock.Text = $"{(newStatus.SellPriceModifier * 100).FormatZeroDecimal()} %";
|
||||
return $"{(CurrentLocation.ActiveStoreBalanceStatus.SellPriceModifier * 100).FormatZeroDecimal()} %";
|
||||
}
|
||||
}
|
||||
valueChangeGroup.ToolTip = null;
|
||||
currentSellValueBlock.TextColor = CurrentLocation.BalanceColor;
|
||||
sellValueChangeArrow.Visible = false;
|
||||
newSellValueBlock.Text = null;
|
||||
return $"{(CurrentLocation.ActiveStoreBalanceStatus.SellPriceModifier * 100).FormatZeroDecimal()} %";
|
||||
}
|
||||
else
|
||||
{
|
||||
valueChangeGroup.ToolTip = null;
|
||||
sellValueChangeArrow.Visible = false;
|
||||
newSellValueBlock.Text = null;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
};
|
||||
Vector4 newPadding = currentSellValueBlock.Padding;
|
||||
newPadding.Z = 0;
|
||||
currentSellValueBlock.Padding = newPadding;
|
||||
float relativeHeight = 0.45f;
|
||||
float relativeWidth = (relativeHeight * valueChangeGroup.Rect.Height) / valueChangeGroup.Rect.Width;
|
||||
sellValueChangeArrow = new GUIImage(new RectTransform(new Vector2(relativeWidth, relativeHeight), valueChangeGroup.RectTransform), "StoreArrow", scaleToFit: true)
|
||||
{
|
||||
CanBeFocused = false,
|
||||
Visible = false
|
||||
};
|
||||
newSellValueBlock = new GUITextBlock(new RectTransform(new Vector2(blockWidth, 1.0f), valueChangeGroup.RectTransform) { MaxSize = blockMaxSize },
|
||||
"", font: GUI.SubHeadingFont)
|
||||
{
|
||||
AutoScaleVertical = true,
|
||||
CanBeFocused = false,
|
||||
TextScale = 1.1f
|
||||
};
|
||||
newPadding = newSellValueBlock.Padding;
|
||||
newPadding.X = 0;
|
||||
newSellValueBlock.Padding = newPadding;
|
||||
|
||||
// Store mode buttons ------------------------------------------------
|
||||
var modeButtonFrame = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.6f / 14.0f), storeContent.RectTransform), style: null);
|
||||
var modeButtonContainer = new GUILayoutGroup(new RectTransform(Vector2.One, modeButtonFrame.RectTransform), isHorizontal: true);
|
||||
@@ -209,8 +301,6 @@ namespace Barotrauma
|
||||
tabSortingMethods.Clear();
|
||||
foreach (StoreTab tab in tabs)
|
||||
{
|
||||
// TODO: Remove the row below once the deal page is implemented
|
||||
if (tab == StoreTab.Deals) { continue; }
|
||||
var tabButton = new GUIButton(new RectTransform(new Vector2(1.0f / (tabs.Length + 1), 1.0f), modeButtonContainer.RectTransform),
|
||||
text: TextManager.Get("campaignstoretab." + tab), style: "GUITabButton")
|
||||
{
|
||||
@@ -309,24 +399,22 @@ namespace Barotrauma
|
||||
searchBox.OnTextChanged += (textBox, text) => { FilterStoreItems(null, text); return true; };
|
||||
|
||||
var storeItemListContainer = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.92f), sortFilterListContainer.RectTransform), style: null);
|
||||
storeDealsList = new GUIListBox(new RectTransform(Vector2.One, storeItemListContainer.RectTransform))
|
||||
{
|
||||
AutoHideScrollBar = false,
|
||||
Visible = false
|
||||
};
|
||||
tabLists.Clear();
|
||||
tabLists.Add(StoreTab.Deals, storeDealsList);
|
||||
|
||||
storeBuyList = new GUIListBox(new RectTransform(Vector2.One, storeItemListContainer.RectTransform))
|
||||
{
|
||||
AutoHideScrollBar = false,
|
||||
Visible = false
|
||||
};
|
||||
storeDailySpecialsGroup = CreateDealsGroup(storeBuyList);
|
||||
tabLists.Add(StoreTab.Buy, storeBuyList);
|
||||
|
||||
storeSellList = new GUIListBox(new RectTransform(Vector2.One, storeItemListContainer.RectTransform))
|
||||
{
|
||||
AutoHideScrollBar = false,
|
||||
Visible = false
|
||||
};
|
||||
storeRequestedGoodGroup = CreateDealsGroup(storeSellList);
|
||||
tabLists.Add(StoreTab.Sell, storeSellList);
|
||||
|
||||
// Shopping Crate ------------------------------------------------------------------------------------------------------------------------------------------
|
||||
@@ -428,6 +516,26 @@ namespace Barotrauma
|
||||
resolutionWhenCreated = new Point(GameMain.GraphicsWidth, GameMain.GraphicsHeight);
|
||||
}
|
||||
|
||||
private GUILayoutGroup CreateDealsGroup(GUIListBox parentList)
|
||||
{
|
||||
var elementHeight = (int)(GUI.yScale * 80);
|
||||
var frame = new GUIFrame(new RectTransform(new Point(parentList.Content.Rect.Width, 4 * elementHeight + 3), parent: parentList.Content.RectTransform), style: null);
|
||||
frame.UserData = "deals";
|
||||
var dealsGroup = new GUILayoutGroup(new RectTransform(Vector2.One, frame.RectTransform, anchor: Anchor.Center), childAnchor: Anchor.TopCenter);
|
||||
var dealsHeader = new GUILayoutGroup(new RectTransform(new Point((int)(0.95f * parentList.Content.Rect.Width), elementHeight), parent: dealsGroup.RectTransform), isHorizontal: true, childAnchor: Anchor.CenterLeft);
|
||||
dealsHeader.UserData = "header";
|
||||
var iconWidth = (0.9f * dealsHeader.Rect.Height) / dealsHeader.Rect.Width;
|
||||
var dealsIcon = new GUIImage(new RectTransform(new Vector2(iconWidth, 0.9f), dealsHeader.RectTransform), "StoreDealIcon", scaleToFit: true);
|
||||
var text = TextManager.Get(parentList == storeBuyList ? "campaignstore.dailyspecials" : "campaignstore.requestedgoods");
|
||||
var dealsText = new GUITextBlock(new RectTransform(new Vector2(1.0f - iconWidth, 0.9f), dealsHeader.RectTransform), text, font: GUI.LargeFont);
|
||||
storeSpecialColor = dealsIcon.Color;
|
||||
dealsText.TextColor = storeSpecialColor;
|
||||
var divider = new GUIImage(new RectTransform(new Point(dealsGroup.Rect.Width, 3), dealsGroup.RectTransform), "HorizontalLine");
|
||||
divider.UserData = "divider";
|
||||
frame.CanBeFocused = dealsGroup.CanBeFocused = dealsHeader.CanBeFocused = dealsIcon.CanBeFocused = dealsText.CanBeFocused = divider.CanBeFocused = false;
|
||||
return dealsGroup;
|
||||
}
|
||||
|
||||
private void UpdateLocation(Location prevLocation, Location newLocation)
|
||||
{
|
||||
if (prevLocation == newLocation) { return; }
|
||||
@@ -464,17 +572,8 @@ namespace Barotrauma
|
||||
SetConfirmButtonBehavior();
|
||||
SetConfirmButtonStatus();
|
||||
FilterStoreItems();
|
||||
if (tab == StoreTab.Deals)
|
||||
if (tab == StoreTab.Buy)
|
||||
{
|
||||
storeBuyList.Visible = false;
|
||||
storeSellList.Visible = false;
|
||||
storeDealsList.Visible = true;
|
||||
shoppingCrateSellList.Visible = false;
|
||||
shoppingCrateBuyList.Visible = true;
|
||||
}
|
||||
else if (tab == StoreTab.Buy)
|
||||
{
|
||||
storeDealsList.Visible = false;
|
||||
storeSellList.Visible = false;
|
||||
storeBuyList.Visible = true;
|
||||
shoppingCrateSellList.Visible = false;
|
||||
@@ -482,7 +581,6 @@ namespace Barotrauma
|
||||
}
|
||||
else if (tab == StoreTab.Sell)
|
||||
{
|
||||
storeDealsList.Visible = false;
|
||||
storeBuyList.Visible = false;
|
||||
storeSellList.Visible = true;
|
||||
shoppingCrateBuyList.Visible = false;
|
||||
@@ -525,37 +623,71 @@ namespace Barotrauma
|
||||
|
||||
bool hasPermissions = HasPermissions;
|
||||
HashSet<GUIComponent> existingItemFrames = new HashSet<GUIComponent>();
|
||||
|
||||
if ((storeDailySpecialsGroup != null) != CurrentLocation.DailySpecials.Any())
|
||||
{
|
||||
if (storeDailySpecialsGroup == null)
|
||||
{
|
||||
storeDailySpecialsGroup = CreateDealsGroup(storeBuyList);
|
||||
storeDailySpecialsGroup.Parent.SetAsFirstChild();
|
||||
}
|
||||
else
|
||||
{
|
||||
storeBuyList.RemoveChild(storeDailySpecialsGroup.Parent);
|
||||
storeDailySpecialsGroup = null;
|
||||
}
|
||||
storeBuyList.RecalculateChildren();
|
||||
}
|
||||
|
||||
foreach (PurchasedItem item in CurrentLocation.StoreStock)
|
||||
{
|
||||
if (item.ItemPrefab.CanBeBoughtAtLocation(CurrentLocation, out PriceInfo priceInfo))
|
||||
CreateOrUpdateItemFrame(item.ItemPrefab, item.Quantity);
|
||||
}
|
||||
|
||||
foreach (ItemPrefab itemPrefab in CurrentLocation.DailySpecials)
|
||||
{
|
||||
if (CurrentLocation.StoreStock.Any(pi => pi.ItemPrefab == itemPrefab)) { continue; }
|
||||
CreateOrUpdateItemFrame(itemPrefab, 0);
|
||||
}
|
||||
|
||||
void CreateOrUpdateItemFrame(ItemPrefab itemPrefab, int quantity)
|
||||
{
|
||||
if (itemPrefab.CanBeBoughtAtLocation(CurrentLocation, out PriceInfo priceInfo))
|
||||
{
|
||||
var itemFrame = storeBuyList.Content.Children.FirstOrDefault(c => c.UserData is PurchasedItem pi && pi.ItemPrefab == item.ItemPrefab);
|
||||
var quantity = item.Quantity;
|
||||
if (CargoManager.PurchasedItems.Find(i => i.ItemPrefab == item.ItemPrefab) is PurchasedItem purchasedItem)
|
||||
var isDailySpecial = CurrentLocation.DailySpecials.Contains(itemPrefab);
|
||||
var itemFrame = isDailySpecial ?
|
||||
storeDailySpecialsGroup.FindChild(c => c.UserData is PurchasedItem pi && pi.ItemPrefab == itemPrefab) :
|
||||
storeBuyList.Content.FindChild(c => c.UserData is PurchasedItem pi && pi.ItemPrefab == itemPrefab);
|
||||
if (CargoManager.PurchasedItems.Find(i => i.ItemPrefab == itemPrefab) is PurchasedItem purchasedItem)
|
||||
{
|
||||
quantity = Math.Max(quantity - purchasedItem.Quantity, 0);
|
||||
}
|
||||
if (CargoManager.ItemsInBuyCrate.Find(i => i.ItemPrefab == item.ItemPrefab) is PurchasedItem itemInBuyCrate)
|
||||
if (CargoManager.ItemsInBuyCrate.Find(i => i.ItemPrefab == itemPrefab) is PurchasedItem itemInBuyCrate)
|
||||
{
|
||||
quantity = Math.Max(quantity - itemInBuyCrate.Quantity, 0);
|
||||
}
|
||||
if (itemFrame == null)
|
||||
{
|
||||
itemFrame = CreateItemFrame(new PurchasedItem(item.ItemPrefab, quantity), priceInfo, storeBuyList, forceDisable: !hasPermissions);
|
||||
var parentComponent = isDailySpecial ? storeDailySpecialsGroup : storeBuyList as GUIComponent;
|
||||
itemFrame = CreateItemFrame(new PurchasedItem(itemPrefab, quantity), priceInfo, parentComponent, forceDisable: !hasPermissions);
|
||||
}
|
||||
else
|
||||
{
|
||||
(itemFrame.UserData as PurchasedItem).Quantity = quantity;
|
||||
SetQuantityLabelText(StoreTab.Buy, itemFrame);
|
||||
SetOwnedLabelText(itemFrame);
|
||||
SetItemFrameStatus(itemFrame, hasPermissions && quantity > 0);
|
||||
}
|
||||
SetItemFrameStatus(itemFrame, hasPermissions && quantity > 0);
|
||||
existingItemFrames.Add(itemFrame);
|
||||
}
|
||||
}
|
||||
|
||||
var removedItemFrames = storeBuyList.Content.Children.Except(existingItemFrames).ToList();
|
||||
removedItemFrames.ForEach(f => storeBuyList.Content.RemoveChild(f));
|
||||
var removedItemFrames = storeBuyList.Content.Children.Where(c => c.UserData is PurchasedItem).Except(existingItemFrames).ToList();
|
||||
if (storeDailySpecialsGroup != null)
|
||||
{
|
||||
removedItemFrames.AddRange(storeDailySpecialsGroup.Children.Where(c => c.UserData is PurchasedItem).Except(existingItemFrames).ToList());
|
||||
}
|
||||
removedItemFrames.ForEach(f => f.RectTransform.Parent = null);
|
||||
if (IsBuying) { FilterStoreItems(); }
|
||||
SortItems(StoreTab.Buy);
|
||||
|
||||
@@ -567,36 +699,72 @@ namespace Barotrauma
|
||||
{
|
||||
float prevSellListScroll = storeSellList.BarScroll;
|
||||
float prevShoppingCrateScroll = shoppingCrateSellList.BarScroll;
|
||||
|
||||
bool hasPermissions = HasPermissions;
|
||||
HashSet<GUIComponent> existingItemFrames = new HashSet<GUIComponent>();
|
||||
foreach (PurchasedItem item in itemsToSell)
|
||||
|
||||
if ((storeRequestedGoodGroup != null) != CurrentLocation.RequestedGoods.Any())
|
||||
{
|
||||
PriceInfo priceInfo = item.ItemPrefab.GetPriceInfo(CurrentLocation);
|
||||
if (priceInfo == null) { continue; }
|
||||
var itemFrame = storeSellList.Content.FindChild(c => c.UserData is PurchasedItem i && i.ItemPrefab == item.ItemPrefab);
|
||||
var quantity = item.Quantity;
|
||||
if (CargoManager.ItemsInSellCrate.Find(i => i.ItemPrefab == item.ItemPrefab) is PurchasedItem itemInSellCrate)
|
||||
if (storeRequestedGoodGroup == null)
|
||||
{
|
||||
quantity = Math.Max(quantity - itemInSellCrate.Quantity, 0);
|
||||
}
|
||||
if (itemFrame == null)
|
||||
{
|
||||
itemFrame = CreateItemFrame(new PurchasedItem(item.ItemPrefab, quantity), priceInfo, storeSellList, forceDisable: !hasPermissions);
|
||||
storeRequestedGoodGroup = CreateDealsGroup(storeSellList);
|
||||
storeRequestedGoodGroup.Parent.SetAsFirstChild();
|
||||
}
|
||||
else
|
||||
{
|
||||
(itemFrame.UserData as PurchasedItem).Quantity = quantity;
|
||||
storeSellList.RemoveChild(storeRequestedGoodGroup.Parent);
|
||||
storeRequestedGoodGroup = null;
|
||||
}
|
||||
storeSellList.RecalculateChildren();
|
||||
}
|
||||
|
||||
foreach (PurchasedItem item in itemsToSell)
|
||||
{
|
||||
CreateOrUpdateItemFrame(item.ItemPrefab, item.Quantity);
|
||||
}
|
||||
|
||||
foreach (var requestedGood in CurrentLocation.RequestedGoods)
|
||||
{
|
||||
if (itemsToSell.Any(pi => pi.ItemPrefab == requestedGood)) { continue; }
|
||||
CreateOrUpdateItemFrame(requestedGood, 0);
|
||||
}
|
||||
|
||||
void CreateOrUpdateItemFrame(ItemPrefab itemPrefab, int itemQuantity)
|
||||
{
|
||||
PriceInfo priceInfo = itemPrefab.GetPriceInfo(CurrentLocation);
|
||||
if (priceInfo == null) { return; }
|
||||
var isRequestedGood = CurrentLocation.RequestedGoods.Contains(itemPrefab);
|
||||
var itemFrame = isRequestedGood ?
|
||||
storeRequestedGoodGroup.FindChild(c => c.UserData is PurchasedItem pi && pi.ItemPrefab == itemPrefab) :
|
||||
storeSellList.Content.FindChild(c => c.UserData is PurchasedItem pi && pi.ItemPrefab == itemPrefab);
|
||||
if (CargoManager.ItemsInSellCrate.Find(i => i.ItemPrefab == itemPrefab) is PurchasedItem itemInSellCrate)
|
||||
{
|
||||
itemQuantity = Math.Max(itemQuantity - itemInSellCrate.Quantity, 0);
|
||||
}
|
||||
if (itemFrame == null)
|
||||
{
|
||||
var parentComponent = isRequestedGood ? storeRequestedGoodGroup : storeSellList as GUIComponent;
|
||||
itemFrame = CreateItemFrame(new PurchasedItem(itemPrefab, itemQuantity), priceInfo, parentComponent, forceDisable: !hasPermissions);
|
||||
}
|
||||
else
|
||||
{
|
||||
(itemFrame.UserData as PurchasedItem).Quantity = itemQuantity;
|
||||
SetQuantityLabelText(StoreTab.Sell, itemFrame);
|
||||
SetOwnedLabelText(itemFrame);
|
||||
SetItemFrameStatus(itemFrame, hasPermissions);
|
||||
}
|
||||
if (quantity < 1) { itemFrame.Visible = false; }
|
||||
SetItemFrameStatus(itemFrame, hasPermissions && itemQuantity > 0);
|
||||
if (itemQuantity < 1 && !isRequestedGood)
|
||||
{
|
||||
itemFrame.Visible = false;
|
||||
}
|
||||
existingItemFrames.Add(itemFrame);
|
||||
}
|
||||
|
||||
var removedItemFrames = storeSellList.Content.Children.Except(existingItemFrames).ToList();
|
||||
removedItemFrames.ForEach(f => storeSellList.Content.RemoveChild(f));
|
||||
var removedItemFrames = storeSellList.Content.Children.Where(c => c.UserData is PurchasedItem).Except(existingItemFrames).ToList();
|
||||
if (storeRequestedGoodGroup != null)
|
||||
{
|
||||
removedItemFrames.AddRange(storeRequestedGoodGroup.Children.Where(c => c.UserData is PurchasedItem).Except(existingItemFrames).ToList());
|
||||
}
|
||||
removedItemFrames.ForEach(f => f.RectTransform.Parent = null);
|
||||
if (IsSelling) { FilterStoreItems(); }
|
||||
SortItems(StoreTab.Sell);
|
||||
|
||||
@@ -673,13 +841,10 @@ namespace Barotrauma
|
||||
}
|
||||
suppressBuySell = false;
|
||||
|
||||
if (priceInfo != null)
|
||||
{
|
||||
var price = listBox == shoppingCrateBuyList ?
|
||||
CurrentLocation.GetAdjustedItemBuyPrice(priceInfo) :
|
||||
CurrentLocation.GetAdjustedItemSellPrice(priceInfo);
|
||||
totalPrice += item.Quantity * price;
|
||||
}
|
||||
var price = listBox == shoppingCrateBuyList ?
|
||||
CurrentLocation.GetAdjustedItemBuyPrice(item.ItemPrefab, priceInfo: priceInfo) :
|
||||
CurrentLocation.GetAdjustedItemSellPrice(item.ItemPrefab, priceInfo: priceInfo);
|
||||
totalPrice += item.Quantity * price;
|
||||
}
|
||||
|
||||
var removedItemFrames = listBox.Content.Children.Except(existingItemFrames).ToList();
|
||||
@@ -711,32 +876,138 @@ namespace Barotrauma
|
||||
|
||||
if (sortingMethod == SortingMethod.AlphabeticalAsc || sortingMethod == SortingMethod.AlphabeticalDesc)
|
||||
{
|
||||
list.Content.RectTransform.SortChildren(
|
||||
(x, y) => (x.GUIComponent.UserData as PurchasedItem).ItemPrefab.Name.CompareTo((y.GUIComponent.UserData as PurchasedItem).ItemPrefab.Name));
|
||||
if (sortingMethod == SortingMethod.AlphabeticalDesc) { list.Content.RectTransform.ReverseChildren(); }
|
||||
list.Content.RectTransform.SortChildren(CompareByName);
|
||||
if (GetSpecialsGroup() is GUILayoutGroup specialsGroup)
|
||||
{
|
||||
specialsGroup.RectTransform.SortChildren(CompareByName);
|
||||
specialsGroup.Recalculate();
|
||||
}
|
||||
|
||||
int CompareByName(RectTransform x, RectTransform y)
|
||||
{
|
||||
if (x.GUIComponent.UserData is PurchasedItem itemX && y.GUIComponent.UserData is PurchasedItem itemY)
|
||||
{
|
||||
var sortResult = itemX.ItemPrefab.Name.CompareTo(itemY.ItemPrefab.Name);
|
||||
if (sortingMethod == SortingMethod.AlphabeticalDesc) { sortResult *= -1; }
|
||||
return sortResult;
|
||||
}
|
||||
else
|
||||
{
|
||||
return CompareByElement(x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (sortingMethod == SortingMethod.PriceAsc || sortingMethod == SortingMethod.PriceDesc)
|
||||
{
|
||||
SortItems(list, SortingMethod.AlphabeticalAsc);
|
||||
if (list == storeSellList || list == shoppingCrateSellList)
|
||||
{
|
||||
list.Content.RectTransform.SortChildren(
|
||||
(x, y) => CurrentLocation.GetAdjustedItemSellPrice((x.GUIComponent.UserData as PurchasedItem).ItemPrefab).CompareTo(
|
||||
CurrentLocation.GetAdjustedItemSellPrice((y.GUIComponent.UserData as PurchasedItem).ItemPrefab)));
|
||||
list.Content.RectTransform.SortChildren(CompareBySellPrice);
|
||||
if (GetSpecialsGroup() is GUILayoutGroup specialsGroup)
|
||||
{
|
||||
specialsGroup.RectTransform.SortChildren(CompareBySellPrice);
|
||||
specialsGroup.Recalculate();
|
||||
}
|
||||
|
||||
int CompareBySellPrice(RectTransform x, RectTransform y)
|
||||
{
|
||||
if (x.GUIComponent.UserData is PurchasedItem itemX && y.GUIComponent.UserData is PurchasedItem itemY)
|
||||
{
|
||||
var sortResult = CurrentLocation.GetAdjustedItemSellPrice(itemX.ItemPrefab).CompareTo(
|
||||
CurrentLocation.GetAdjustedItemSellPrice(itemY.ItemPrefab));
|
||||
if (sortingMethod == SortingMethod.PriceDesc) { sortResult *= -1; }
|
||||
return sortResult;
|
||||
}
|
||||
else
|
||||
{
|
||||
return CompareByElement(x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
list.Content.RectTransform.SortChildren(
|
||||
(x, y) => CurrentLocation.GetAdjustedItemBuyPrice((x.GUIComponent.UserData as PurchasedItem).ItemPrefab).CompareTo(
|
||||
CurrentLocation.GetAdjustedItemBuyPrice((y.GUIComponent.UserData as PurchasedItem).ItemPrefab)));
|
||||
list.Content.RectTransform.SortChildren(CompareByBuyPrice);
|
||||
if (GetSpecialsGroup() is GUILayoutGroup specialsGroup)
|
||||
{
|
||||
specialsGroup.RectTransform.SortChildren(CompareByBuyPrice);
|
||||
specialsGroup.Recalculate();
|
||||
}
|
||||
|
||||
int CompareByBuyPrice(RectTransform x, RectTransform y)
|
||||
{
|
||||
if (x.GUIComponent.UserData is PurchasedItem itemX && y.GUIComponent.UserData is PurchasedItem itemY)
|
||||
{
|
||||
var sortResult = CurrentLocation.GetAdjustedItemBuyPrice(itemX.ItemPrefab).CompareTo(
|
||||
CurrentLocation.GetAdjustedItemBuyPrice(itemY.ItemPrefab));
|
||||
if (sortingMethod == SortingMethod.PriceDesc) { sortResult *= -1; }
|
||||
return sortResult;
|
||||
}
|
||||
else
|
||||
{
|
||||
return CompareByElement(x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (sortingMethod == SortingMethod.PriceDesc) { list.Content.RectTransform.ReverseChildren(); }
|
||||
}
|
||||
else if (sortingMethod == SortingMethod.CategoryAsc)
|
||||
{
|
||||
SortItems(list, SortingMethod.AlphabeticalAsc);
|
||||
list.Content.RectTransform.SortChildren((x, y) =>
|
||||
(x.GUIComponent.UserData as PurchasedItem).ItemPrefab.Category.CompareTo((y.GUIComponent.UserData as PurchasedItem).ItemPrefab.Category));
|
||||
list.Content.RectTransform.SortChildren(CompareByCategory);
|
||||
if (GetSpecialsGroup() is GUILayoutGroup specialsGroup)
|
||||
{
|
||||
specialsGroup.RectTransform.SortChildren(CompareByCategory);
|
||||
specialsGroup.Recalculate();
|
||||
}
|
||||
|
||||
static int CompareByCategory(RectTransform x, RectTransform y)
|
||||
{
|
||||
if (x.GUIComponent.UserData is PurchasedItem itemX && y.GUIComponent.UserData is PurchasedItem itemY)
|
||||
{
|
||||
return itemX.ItemPrefab.Category.CompareTo(itemY.ItemPrefab.Category);
|
||||
}
|
||||
else
|
||||
{
|
||||
return CompareByElement(x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GUILayoutGroup GetSpecialsGroup()
|
||||
{
|
||||
if (list == storeBuyList)
|
||||
{
|
||||
return storeDailySpecialsGroup;
|
||||
}
|
||||
else if (list == storeSellList)
|
||||
{
|
||||
return storeRequestedGoodGroup;
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
static int CompareByElement(RectTransform x, RectTransform y)
|
||||
{
|
||||
if (ShouldBeOnTop(x) || ShouldBeOnBottom(y))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
else if (ShouldBeOnBottom(x) || ShouldBeOnTop(y))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool ShouldBeOnTop(RectTransform rt) =>
|
||||
rt.GUIComponent.UserData is string id && (id == "deals" || id == "header");
|
||||
|
||||
static bool ShouldBeOnBottom(RectTransform rt) =>
|
||||
rt.GUIComponent.UserData is string id && id == "divider";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -750,7 +1021,7 @@ namespace Barotrauma
|
||||
|
||||
private void SortActiveTabItems(SortingMethod sortingMethod) => SortItems(activeTab, sortingMethod);
|
||||
|
||||
private GUIComponent CreateItemFrame(PurchasedItem pi, PriceInfo priceInfo, GUIListBox listBox, bool forceDisable = false)
|
||||
private GUIComponent CreateItemFrame(PurchasedItem pi, PriceInfo priceInfo, GUIComponent parentComponent, bool forceDisable = false)
|
||||
{
|
||||
var tooltip = pi.ItemPrefab.Name;
|
||||
if (!string.IsNullOrWhiteSpace(pi.ItemPrefab.Description))
|
||||
@@ -758,7 +1029,21 @@ namespace Barotrauma
|
||||
tooltip += "\n" + pi.ItemPrefab.Description;
|
||||
}
|
||||
|
||||
GUIFrame frame = new GUIFrame(new RectTransform(new Point(listBox.Content.Rect.Width, (int)(GUI.yScale * 80)), parent: listBox.Content.RectTransform), style: "ListBoxElement")
|
||||
GUIListBox parentListBox = parentComponent as GUIListBox;
|
||||
int width = 0;
|
||||
RectTransform parent = null;
|
||||
if (parentListBox != null)
|
||||
{
|
||||
width = parentListBox.Content.Rect.Width;
|
||||
parent = parentListBox.Content.RectTransform;
|
||||
}
|
||||
else
|
||||
{
|
||||
width = parentComponent.Rect.Width;
|
||||
parent = parentComponent.RectTransform;
|
||||
}
|
||||
|
||||
GUIFrame frame = new GUIFrame(new RectTransform(new Point(width, (int)(GUI.yScale * 80)), parent: parent), style: "ListBoxElement")
|
||||
{
|
||||
ToolTip = tooltip,
|
||||
UserData = pi
|
||||
@@ -788,33 +1073,58 @@ namespace Barotrauma
|
||||
img.RectTransform.MaxSize = img.Rect.Size;
|
||||
}
|
||||
|
||||
GUILayoutGroup nameAndQuantityGroup = new GUILayoutGroup(new RectTransform(new Vector2(nameAndIconRelativeWidth - iconRelativeWidth, 1.0f), mainGroup.RectTransform))
|
||||
GUIFrame nameAndQuantityFrame = new GUIFrame(new RectTransform(new Vector2(nameAndIconRelativeWidth - iconRelativeWidth, 1.0f), mainGroup.RectTransform), style: null)
|
||||
{
|
||||
CanBeFocused = false
|
||||
};
|
||||
GUILayoutGroup nameAndQuantityGroup = new GUILayoutGroup(new RectTransform(Vector2.One, nameAndQuantityFrame.RectTransform))
|
||||
{
|
||||
CanBeFocused = false,
|
||||
Stretch = true
|
||||
};
|
||||
var isSellingRelatedList = parentComponent == storeSellList || parentComponent == storeRequestedGoodGroup || parentComponent == shoppingCrateSellList;
|
||||
var locationHasDealOnItem = isSellingRelatedList ?
|
||||
CurrentLocation.RequestedGoods.Contains(pi.ItemPrefab) : CurrentLocation.DailySpecials.Contains(pi.ItemPrefab);
|
||||
GUITextBlock nameBlock = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.4f), nameAndQuantityGroup.RectTransform),
|
||||
pi.ItemPrefab.Name, font: GUI.SubHeadingFont, textAlignment: Alignment.BottomLeft)
|
||||
{
|
||||
CanBeFocused = false,
|
||||
Shadow = locationHasDealOnItem,
|
||||
TextColor = Color.White * (forceDisable ? 0.5f : 1.0f),
|
||||
TextScale = 0.85f,
|
||||
UserData = "name"
|
||||
};
|
||||
if (locationHasDealOnItem)
|
||||
{
|
||||
var relativeWidth = (0.9f * nameAndQuantityFrame.Rect.Height) / nameAndQuantityFrame.Rect.Width;
|
||||
var dealIcon = new GUIImage(
|
||||
new RectTransform(new Vector2(relativeWidth, 0.9f), nameAndQuantityFrame.RectTransform, anchor: Anchor.CenterLeft)
|
||||
{
|
||||
AbsoluteOffset = new Point((int)nameBlock.Padding.X, 0)
|
||||
},
|
||||
"StoreDealIcon", scaleToFit: true)
|
||||
{
|
||||
CanBeFocused = false
|
||||
};
|
||||
dealIcon.SetAsFirstChild();
|
||||
}
|
||||
var isParentOnLeftSideOfInterface = parentComponent == storeBuyList || parentComponent == storeDailySpecialsGroup ||
|
||||
parentComponent == storeSellList || parentComponent == storeRequestedGoodGroup;
|
||||
GUILayoutGroup shoppingCrateAmountGroup = null;
|
||||
GUINumberInput amountInput = null;
|
||||
if (listBox == storeBuyList || listBox == storeSellList)
|
||||
if (isParentOnLeftSideOfInterface)
|
||||
{
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.3f), nameAndQuantityGroup.RectTransform),
|
||||
CreateQuantityLabelText(listBox == storeSellList ? StoreTab.Sell : StoreTab.Buy, pi.Quantity), font: GUI.Font, textAlignment: Alignment.BottomLeft)
|
||||
CreateQuantityLabelText(isSellingRelatedList ? StoreTab.Sell : StoreTab.Buy, pi.Quantity), font: GUI.Font, textAlignment: Alignment.BottomLeft)
|
||||
{
|
||||
CanBeFocused = false,
|
||||
Shadow = locationHasDealOnItem,
|
||||
TextColor = Color.White * (forceDisable ? 0.5f : 1.0f),
|
||||
TextScale = 0.85f,
|
||||
UserData = "quantitylabel"
|
||||
};
|
||||
}
|
||||
else if (listBox == shoppingCrateBuyList || listBox == shoppingCrateSellList)
|
||||
else if (!isParentOnLeftSideOfInterface)
|
||||
{
|
||||
var relativePadding = nameBlock.Padding.X / nameBlock.Rect.Width;
|
||||
shoppingCrateAmountGroup = new GUILayoutGroup(new RectTransform(new Vector2(1.0f - relativePadding, 0.6f), nameAndQuantityGroup.RectTransform) { RelativeOffset = new Vector2(relativePadding, 0) },
|
||||
@@ -825,7 +1135,7 @@ namespace Barotrauma
|
||||
amountInput = new GUINumberInput(new RectTransform(new Vector2(0.4f, 1.0f), shoppingCrateAmountGroup.RectTransform), GUINumberInput.NumberType.Int)
|
||||
{
|
||||
MinValueInt = 0,
|
||||
MaxValueInt = GetMaxAvailable(pi.ItemPrefab, listBox == shoppingCrateBuyList ? StoreTab.Buy : StoreTab.Sell),
|
||||
MaxValueInt = GetMaxAvailable(pi.ItemPrefab, isSellingRelatedList ? StoreTab.Sell : StoreTab.Buy),
|
||||
UserData = pi,
|
||||
IntValue = pi.Quantity
|
||||
};
|
||||
@@ -856,6 +1166,7 @@ namespace Barotrauma
|
||||
textAlignment: shoppingCrateAmountGroup == null ? Alignment.TopLeft : Alignment.CenterLeft)
|
||||
{
|
||||
CanBeFocused = false,
|
||||
Shadow = locationHasDealOnItem,
|
||||
TextColor = Color.White * (forceDisable ? 0.5f : 1.0f),
|
||||
TextScale = 0.85f,
|
||||
UserData = "owned"
|
||||
@@ -864,22 +1175,53 @@ namespace Barotrauma
|
||||
|
||||
var buttonRelativeWidth = (0.9f * mainGroup.Rect.Height) / mainGroup.Rect.Width;
|
||||
|
||||
var priceBlock = new GUITextBlock(new RectTransform(new Vector2(priceAndButtonRelativeWidth - buttonRelativeWidth, 1.0f), mainGroup.RectTransform), "", font: GUI.SubHeadingFont, textAlignment: Alignment.Right)
|
||||
var priceFrame = new GUIFrame(new RectTransform(new Vector2(priceAndButtonRelativeWidth - buttonRelativeWidth, 1.0f), mainGroup.RectTransform), style: null)
|
||||
{
|
||||
CanBeFocused = false
|
||||
};
|
||||
var priceBlock = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.5f), priceFrame.RectTransform, anchor: Anchor.Center),
|
||||
"0 MK", font: GUI.SubHeadingFont, textAlignment: Alignment.Right)
|
||||
{
|
||||
CanBeFocused = false,
|
||||
TextColor = Color.White * (forceDisable ? 0.5f : 1.0f),
|
||||
TextColor = locationHasDealOnItem ? storeSpecialColor : Color.White,
|
||||
UserData = "price"
|
||||
};
|
||||
if (listBox == storeSellList || listBox == shoppingCrateSellList)
|
||||
priceBlock.Color *= (forceDisable ? 0.5f : 1.0f);
|
||||
priceBlock.CalculateHeightFromText();
|
||||
if (isSellingRelatedList)
|
||||
{
|
||||
priceBlock.TextGetter = () => GetCurrencyFormatted(CurrentLocation?.GetAdjustedItemSellPrice(priceInfo) ?? 0);
|
||||
priceBlock.TextGetter = () => GetCurrencyFormatted(CurrentLocation?.GetAdjustedItemSellPrice(pi.ItemPrefab, priceInfo: priceInfo) ?? 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
priceBlock.TextGetter = () => GetCurrencyFormatted(CurrentLocation?.GetAdjustedItemBuyPrice(priceInfo) ?? 0);
|
||||
priceBlock.TextGetter = () => GetCurrencyFormatted(CurrentLocation?.GetAdjustedItemBuyPrice(pi.ItemPrefab, priceInfo: priceInfo) ?? 0);
|
||||
}
|
||||
if (locationHasDealOnItem)
|
||||
{
|
||||
var undiscounterPriceBlock = new GUITextBlock(
|
||||
new RectTransform(new Vector2(1.0f, 0.25f), priceFrame.RectTransform, anchor: Anchor.Center)
|
||||
{
|
||||
AbsoluteOffset = new Point(0, priceBlock.RectTransform.ScaledSize.Y)
|
||||
}, "", font: GUI.SmallFont, textAlignment: Alignment.Center)
|
||||
{
|
||||
CanBeFocused = false,
|
||||
Strikethrough = new GUITextBlock.StrikethroughSettings(color: priceBlock.TextColor, expand: 1),
|
||||
TextColor = priceBlock.TextColor,
|
||||
UserData = "undiscountedprice"
|
||||
};
|
||||
if (isSellingRelatedList)
|
||||
{
|
||||
undiscounterPriceBlock.TextGetter = () => GetCurrencyFormatted(
|
||||
CurrentLocation?.GetAdjustedItemSellPrice(pi.ItemPrefab, priceInfo: priceInfo, considerRequestedGoods: false) ?? 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
undiscounterPriceBlock.TextGetter = () => GetCurrencyFormatted(
|
||||
CurrentLocation?.GetAdjustedItemBuyPrice(pi.ItemPrefab, priceInfo: priceInfo, considerDailySpecials: false) ?? 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (listBox == storeDealsList || listBox == storeBuyList || listBox == storeSellList)
|
||||
if (isParentOnLeftSideOfInterface)
|
||||
{
|
||||
new GUIButton(new RectTransform(new Vector2(buttonRelativeWidth, 0.9f), mainGroup.RectTransform), style: "StoreAddToCrateButton")
|
||||
{
|
||||
@@ -902,7 +1244,14 @@ namespace Barotrauma
|
||||
};
|
||||
}
|
||||
|
||||
listBox.RecalculateChildren();
|
||||
if (parentListBox != null)
|
||||
{
|
||||
parentListBox.RecalculateChildren();
|
||||
}
|
||||
else if (parentComponent is GUILayoutGroup parentLayoutGroup)
|
||||
{
|
||||
parentLayoutGroup.Recalculate();
|
||||
}
|
||||
mainGroup.Recalculate();
|
||||
mainGroup.RectTransform.RecalculateChildren(true, true);
|
||||
amountInput?.LayoutGroup.Recalculate();
|
||||
@@ -923,15 +1272,20 @@ namespace Barotrauma
|
||||
.ForEach(i => AddToOwnedItems(i.Prefab));
|
||||
|
||||
// Add items in character inventories
|
||||
foreach (Character c in GameMain.GameSession.CrewManager.GetCharacters())
|
||||
foreach (var item in Item.ItemList)
|
||||
{
|
||||
Item.ItemList.Where(i => i != null && i.GetRootInventoryOwner() == c)
|
||||
.ForEach(i => AddToOwnedItems(i.Prefab));
|
||||
if (item == null || item.Removed) { continue; }
|
||||
var rootInventoryOwner = item.GetRootInventoryOwner();
|
||||
var ownedByCrewMember = GameMain.GameSession.CrewManager.GetCharacters().Any(c => c == rootInventoryOwner);
|
||||
if (!ownedByCrewMember) { continue; }
|
||||
AddToOwnedItems(item.Prefab);
|
||||
}
|
||||
|
||||
// Add items already purchased
|
||||
CargoManager?.PurchasedItems?.ForEach(pi => AddToOwnedItems(pi.ItemPrefab, amount: pi.Quantity));
|
||||
|
||||
ownedItemsUpdateTimer = 0.0f;
|
||||
|
||||
void AddToOwnedItems(ItemPrefab itemPrefab, int amount = 1)
|
||||
{
|
||||
if (OwnedItems.ContainsKey(itemPrefab))
|
||||
@@ -977,14 +1331,22 @@ namespace Barotrauma
|
||||
numberInput.Enabled = enabled;
|
||||
}
|
||||
|
||||
if (itemFrame.FindChild("owned", recursive: true) is GUITextBlock owned)
|
||||
if (itemFrame.FindChild("owned", recursive: true) is GUITextBlock ownedBlock)
|
||||
{
|
||||
owned.TextColor = color;
|
||||
ownedBlock.TextColor = color;
|
||||
}
|
||||
|
||||
if (itemFrame.FindChild("price", recursive: true) is GUITextBlock price)
|
||||
var isDiscounted = false;
|
||||
if (itemFrame.FindChild("undiscountedprice", recursive: true) is GUITextBlock undiscountedPriceBlock)
|
||||
{
|
||||
price.TextColor = color;
|
||||
undiscountedPriceBlock.TextColor = color;
|
||||
undiscountedPriceBlock.Strikethrough.Color = color;
|
||||
isDiscounted = true;
|
||||
}
|
||||
|
||||
if (itemFrame.FindChild("price", recursive: true) is GUITextBlock priceBlock)
|
||||
{
|
||||
priceBlock.TextColor = isDiscounted ? storeSpecialColor * (enabled ? 1.0f : 0.5f) : color;
|
||||
}
|
||||
|
||||
if (itemFrame.FindChild("addbutton", recursive: true) is GUIButton addButton)
|
||||
@@ -1101,7 +1463,7 @@ namespace Barotrauma
|
||||
itemsToRemove.Add(item);
|
||||
continue;
|
||||
}
|
||||
totalPrice += item.Quantity * CurrentLocation.GetAdjustedItemBuyPrice(priceInfo);
|
||||
totalPrice += item.Quantity * CurrentLocation.GetAdjustedItemBuyPrice(item.ItemPrefab, priceInfo: priceInfo);
|
||||
}
|
||||
itemsToRemove.ForEach(i => itemsToPurchase.Remove(i));
|
||||
|
||||
@@ -1135,7 +1497,7 @@ namespace Barotrauma
|
||||
}
|
||||
if (item.ItemPrefab.GetPriceInfo(CurrentLocation) is PriceInfo priceInfo)
|
||||
{
|
||||
totalValue += item.Quantity * CurrentLocation.GetAdjustedItemSellPrice(priceInfo);
|
||||
totalValue += item.Quantity * CurrentLocation.GetAdjustedItemSellPrice(item.ItemPrefab, priceInfo: priceInfo);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1197,16 +1559,38 @@ namespace Barotrauma
|
||||
private void SetClearAllButtonStatus() => clearAllButton.Enabled =
|
||||
HasPermissions && ActiveShoppingCrateList.Content.RectTransform.Children.Any();
|
||||
|
||||
public void Update()
|
||||
private float ownedItemsUpdateTimer = 0.0f;
|
||||
private readonly float ownedItemsUpdateInterval = 1.5f;
|
||||
|
||||
public void Update(float deltaTime)
|
||||
{
|
||||
if (GameMain.GraphicsWidth != resolutionWhenCreated.X || GameMain.GraphicsHeight != resolutionWhenCreated.Y)
|
||||
{
|
||||
CreateUI();
|
||||
needsRefresh = false;
|
||||
}
|
||||
if (needsRefresh || hadPermissions != HasPermissions) { Refresh(); }
|
||||
if (needsBuyingRefresh) { RefreshBuying(); }
|
||||
else
|
||||
{
|
||||
// Update the owned items at short intervals and check if the interface should be refreshed
|
||||
ownedItemsUpdateTimer += deltaTime;
|
||||
if (ownedItemsUpdateTimer >= ownedItemsUpdateInterval)
|
||||
{
|
||||
var prevOwnedItems = new Dictionary<ItemPrefab, int>(OwnedItems);
|
||||
UpdateOwnedItems();
|
||||
var refresh = (prevOwnedItems.Count != OwnedItems.Count) ||
|
||||
(prevOwnedItems.Select(kvp => kvp.Value).Sum() != OwnedItems.Select(kvp => kvp.Value).Sum()) ||
|
||||
(OwnedItems.Any(kvp => kvp.Value > 0 && !prevOwnedItems.ContainsKey(kvp.Key)) ||
|
||||
prevOwnedItems.Any(kvp => !OwnedItems.TryGetValue(kvp.Key, out var itemCount) || kvp.Value != itemCount));
|
||||
if (refresh)
|
||||
{
|
||||
needsItemsToSellRefresh = true;
|
||||
needsRefresh = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (needsItemsToSellRefresh) { RefreshItemsToSell(); }
|
||||
if (needsRefresh || hadPermissions != HasPermissions) { Refresh(updateOwned: ownedItemsUpdateTimer > 0.0f); }
|
||||
if (needsBuyingRefresh) { RefreshBuying(); }
|
||||
if (needsSellingRefresh) { RefreshSelling(); }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -610,8 +610,8 @@ namespace Barotrauma
|
||||
{
|
||||
if (GameMain.Client == null)
|
||||
{
|
||||
GameMain.GameSession.SwitchSubmarine(selectedSubmarine, deliveryFee);
|
||||
GameMain.GameSession.Campaign.UpgradeManager.RefundResetAndReload(selectedSubmarine);
|
||||
SubmarineInfo newSub = GameMain.GameSession.SwitchSubmarine(selectedSubmarine, deliveryFee);
|
||||
GameMain.GameSession.Campaign.UpgradeManager.RefundResetAndReload(newSub);
|
||||
RefreshSubmarineDisplay(true);
|
||||
}
|
||||
else
|
||||
@@ -645,8 +645,8 @@ namespace Barotrauma
|
||||
if (GameMain.Client == null)
|
||||
{
|
||||
GameMain.GameSession.PurchaseSubmarine(selectedSubmarine);
|
||||
GameMain.GameSession.SwitchSubmarine(selectedSubmarine, 0);
|
||||
GameMain.GameSession.Campaign.UpgradeManager.RefundResetAndReload(selectedSubmarine);
|
||||
SubmarineInfo newSub = GameMain.GameSession.SwitchSubmarine(selectedSubmarine, 0);
|
||||
GameMain.GameSession.Campaign.UpgradeManager.RefundResetAndReload(newSub);
|
||||
RefreshSubmarineDisplay(true);
|
||||
}
|
||||
else
|
||||
|
||||
@@ -29,7 +29,7 @@ namespace Barotrauma
|
||||
private float sizeMultiplier = 1f;
|
||||
|
||||
private IEnumerable<Character> crew;
|
||||
private List<Character.TeamType> teamIDs;
|
||||
private List<CharacterTeamType> teamIDs;
|
||||
private const string inLobbyString = "\u2022 \u2022 \u2022";
|
||||
|
||||
public static Color OwnCharacterBGColor = Color.Gold * 0.7f;
|
||||
@@ -281,11 +281,11 @@ namespace Barotrauma
|
||||
// Show own team first when there's more than one team
|
||||
if (teamIDs.Count > 1 && GameMain.Client?.Character != null)
|
||||
{
|
||||
Character.TeamType ownTeam = GameMain.Client.Character.TeamID;
|
||||
CharacterTeamType ownTeam = GameMain.Client.Character.TeamID;
|
||||
teamIDs = teamIDs.OrderBy(i => i != ownTeam).ThenBy(i => i).ToList();
|
||||
}
|
||||
|
||||
if (!teamIDs.Any()) teamIDs.Add(Character.TeamType.None);
|
||||
if (!teamIDs.Any()) { teamIDs.Add(CharacterTeamType.None); }
|
||||
|
||||
var content = new GUILayoutGroup(new RectTransform(Vector2.One, crewFrame.RectTransform));
|
||||
|
||||
@@ -465,15 +465,14 @@ namespace Barotrauma
|
||||
{
|
||||
foreach (Character character in crew.Where(c => c.TeamID == teamIDs[i]))
|
||||
{
|
||||
if (!(character is AICharacter) && connectedClients.Find(c => c.Character == null && c.Name == character.Name) != null) continue;
|
||||
CreateMultiPlayerCharacterElement(character, GameMain.Client.ConnectedClients.Find(c => c.Character == character), i);
|
||||
if (!(character is AICharacter) && connectedClients.Any(c => c.Character == null && c.Name == character.Name)) { continue; }
|
||||
CreateMultiPlayerCharacterElement(character, GameMain.Client.PreviouslyConnectedClients.FirstOrDefault(c => c.Character == character), i);
|
||||
}
|
||||
}
|
||||
|
||||
for (int j = 0; j < connectedClients.Count; j++)
|
||||
{
|
||||
Client client = connectedClients[j];
|
||||
|
||||
if (!client.InGame || client.Character == null || client.Character.IsDead)
|
||||
{
|
||||
CreateMultiPlayerClientElement(client);
|
||||
@@ -565,7 +564,7 @@ namespace Barotrauma
|
||||
|
||||
private int GetTeamIndex(Client client)
|
||||
{
|
||||
if (teamIDs.Count <= 1) return 0;
|
||||
if (teamIDs.Count <= 1) { return 0; }
|
||||
|
||||
if (client.Character != null)
|
||||
{
|
||||
@@ -707,7 +706,7 @@ namespace Barotrauma
|
||||
{
|
||||
GUIComponent paddedFrame;
|
||||
|
||||
if (client.Character == null)
|
||||
if (client.Character?.Info == null)
|
||||
{
|
||||
paddedFrame = new GUILayoutGroup(new RectTransform(new Vector2(0.874f, 0.58f), frame.RectTransform, Anchor.TopCenter) { RelativeOffset = new Vector2(0.0f, 0.05f) })
|
||||
{
|
||||
|
||||
@@ -625,13 +625,19 @@ namespace Barotrauma
|
||||
selectedUpgradeCategoryLayout?.ClearChildren();
|
||||
GUIFrame frame = new GUIFrame(rectT(1, 0.4f, selectedUpgradeCategoryLayout));
|
||||
GUIListBox prefabList = new GUIListBox(rectT(0.93f, 0.9f, frame, Anchor.Center)) { UserData = "prefablist" };
|
||||
|
||||
List<Item> entitiesOnSub = null;
|
||||
if (!category.IsWallUpgrade)
|
||||
{
|
||||
entitiesOnSub = submarine.GetItems(true).Where(i => submarine.IsEntityFoundOnThisSub(i, true)).ToList();
|
||||
}
|
||||
foreach (UpgradePrefab prefab in prefabs)
|
||||
{
|
||||
CreateUpgradeEntry(prefab, category, prefabList.Content);
|
||||
CreateUpgradeEntry(prefab, category, prefabList.Content, entitiesOnSub);
|
||||
}
|
||||
}
|
||||
|
||||
private void CreateUpgradeEntry(UpgradePrefab prefab, UpgradeCategory category, GUIComponent parent)
|
||||
private void CreateUpgradeEntry(UpgradePrefab prefab, UpgradeCategory category, GUIComponent parent, List<Item> itemsOnSubmarine)
|
||||
{
|
||||
/* UPGRADE PREFAB ENTRY
|
||||
* |------------------------------------------------------------------|
|
||||
@@ -680,12 +686,14 @@ namespace Barotrauma
|
||||
progressLayout.Recalculate();
|
||||
buyButtonLayout.Recalculate();
|
||||
|
||||
if (!HasPermission)
|
||||
if (!HasPermission || itemsOnSubmarine != null && !itemsOnSubmarine.Any(it => category.CanBeApplied(it, prefab)))
|
||||
{
|
||||
prefabFrame.Enabled = false;
|
||||
description.Enabled = false;
|
||||
name.Enabled = false;
|
||||
icon.Color = Color.Gray;
|
||||
buyButton.Enabled = false;
|
||||
buyButtonLayout.UserData = null; // prevent UpdateUpgradeEntry() from enabling the button
|
||||
}
|
||||
|
||||
buyButton.OnClicked += (button, o) =>
|
||||
@@ -731,7 +739,7 @@ namespace Barotrauma
|
||||
// include pending upgrades into the tooltip
|
||||
foreach (var (prefab, category, level) in Campaign.UpgradeManager.PendingUpgrades)
|
||||
{
|
||||
if (entity is Item item && category.CanBeApplied(item) || entity is Structure && category.IsWallUpgrade)
|
||||
if (entity is Item item && category.CanBeApplied(item, prefab) || entity is Structure && category.IsWallUpgrade)
|
||||
{
|
||||
bool found = false;
|
||||
foreach (GUITextBlock textBlock in upgradeList.Content.Children.Where(c => c is GUITextBlock).Cast<GUITextBlock>())
|
||||
@@ -786,7 +794,7 @@ namespace Barotrauma
|
||||
|
||||
foreach (UpgradeCategory category in UpgradeCategory.Categories)
|
||||
{
|
||||
if (entitiesOnSub.Any(item => category.CanBeApplied(item) && !item.disallowedUpgrades.Contains(category.Identifier)))
|
||||
if (entitiesOnSub.Any(item => category.CanBeApplied(item, null)))
|
||||
{
|
||||
applicableCategories.Add(category);
|
||||
}
|
||||
@@ -826,7 +834,7 @@ namespace Barotrauma
|
||||
HoveredItem = item;
|
||||
if (PlayerInput.PrimaryMouseButtonClicked() && selectedUpgradTab == UpgradeTab.Upgrade && currentStoreLayout != null)
|
||||
{
|
||||
ScrollToCategory(data => data.Category.CanBeApplied(item));
|
||||
ScrollToCategory(data => data.Category.CanBeApplied(item, null));
|
||||
}
|
||||
found = true;
|
||||
break;
|
||||
@@ -895,7 +903,7 @@ namespace Barotrauma
|
||||
submarineInfoFrame.RectTransform.ScreenSpaceOffset = new Point(0, (int)(16 * GUI.Scale));
|
||||
|
||||
description.Padding = new Vector4(description.Padding.X, 24 * GUI.Scale, description.Padding.Z, description.Padding.W);
|
||||
List<Entity> pointsOfInterest = (from category in UpgradeCategory.Categories from item in submarine.GetItems(UpgradeManager.UpgradeAlsoConnectedSubs) where category.CanBeApplied(item) && !item.NonInteractable select item).Cast<Entity>().ToList();
|
||||
List<Entity> pointsOfInterest = (from category in UpgradeCategory.Categories from item in submarine.GetItems(UpgradeManager.UpgradeAlsoConnectedSubs) where category.CanBeApplied(item, null) && item.IsPlayerTeamInteractable select item).Cast<Entity>().ToList();
|
||||
|
||||
List<ushort> ids = GameMain.GameSession.SubmarineInfo?.LeftBehindDockingPortIDs ?? new List<ushort>();
|
||||
pointsOfInterest.AddRange(submarine.GetItems(UpgradeManager.UpgradeAlsoConnectedSubs).Where(item => ids.Contains(item.ID)));
|
||||
@@ -1112,7 +1120,7 @@ namespace Barotrauma
|
||||
List<GUIFrame> frames = new List<GUIFrame>();
|
||||
foreach (var (item, guiFrame) in itemPreviews)
|
||||
{
|
||||
if (category.CanBeApplied(item))
|
||||
if (category.CanBeApplied(item, null))
|
||||
{
|
||||
frames.Add(guiFrame);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user