This commit is contained in:
Evil Factory
2022-04-28 12:36:24 -03:00
91 changed files with 1140 additions and 491 deletions
@@ -5,6 +5,7 @@ using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using PlayerBalanceElement = Barotrauma.CampaignUI.PlayerBalanceElement;
namespace Barotrauma
{
@@ -21,6 +22,8 @@ namespace Barotrauma
private GUIButton validateHiresButton;
private GUIButton clearAllButton;
private PlayerBalanceElement? playerBalanceElement;
private List<CharacterInfo> PendingHires => campaign.Map?.CurrentLocation?.HireManager?.PendingHires;
private bool HasPermission => campaignUI.Campaign.AllowedToManageCampaign(ClientPermissions.ManageHires);
@@ -157,23 +160,7 @@ namespace Barotrauma
RelativeSpacing = 0.02f
};
var playerBalanceContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.75f / 14.0f), pendingAndCrewMainGroup.RectTransform), childAnchor: Anchor.TopRight)
{
RelativeSpacing = 0.005f
};
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.5f), playerBalanceContainer.RectTransform),
TextManager.Get("campaignstore.balance"), font: GUIStyle.Font, textAlignment: Alignment.BottomRight)
{
AutoScaleVertical = true,
ForceUpperCase = ForceUpperCase.Yes
};
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.5f), playerBalanceContainer.RectTransform),
"", font: GUIStyle.SubHeadingFont, textAlignment: Alignment.TopRight)
{
AutoScaleVertical = true,
TextScale = 1.1f,
TextGetter = () => TextManager.FormatCurrency(campaign.Wallet.Balance)
};
playerBalanceElement = CampaignUI.AddBalanceElement(pendingAndCrewMainGroup, new Vector2(1.0f, 0.75f / 14.0f));
var pendingAndCrewGroup = new GUILayoutGroup(new RectTransform(new Vector2(0.9f, 0.95f), anchor: Anchor.Center,
parent: new GUIFrame(new RectTransform(new Vector2(1.0f, 13.25f / 14.0f), pendingAndCrewMainGroup.RectTransform)
@@ -344,7 +331,7 @@ namespace Barotrauma
Color? jobColor = null;
if (characterInfo.Job != null)
{
skill = characterInfo.Job?.PrimarySkill ?? characterInfo.Job.Skills.OrderByDescending(s => s.Level).FirstOrDefault();
skill = characterInfo.Job?.PrimarySkill ?? characterInfo.Job.GetSkills().OrderByDescending(s => s.Level).FirstOrDefault();
jobColor = characterInfo.Job.Prefab.UIColor;
}
@@ -547,8 +534,8 @@ namespace Barotrauma
GUILayoutGroup skillGroup = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.475f), mainGroup.RectTransform), isHorizontal: true);
GUILayoutGroup skillNameGroup = new GUILayoutGroup(new RectTransform(new Vector2(0.8f, 1.0f), skillGroup.RectTransform));
GUILayoutGroup skillLevelGroup = new GUILayoutGroup(new RectTransform(new Vector2(0.2f, 1.0f), skillGroup.RectTransform));
List<Skill> characterSkills = characterInfo.Job.Skills;
blockHeight = 1.0f / characterSkills.Count;
var characterSkills = characterInfo.Job.GetSkills();
blockHeight = 1.0f / characterSkills.Count();
foreach (Skill skill in characterSkills)
{
new GUITextBlock(new RectTransform(new Vector2(1.0f, blockHeight), skillNameGroup.RectTransform), TextManager.Get("SkillName." + skill.Identifier));
@@ -630,7 +617,7 @@ namespace Barotrauma
total += ((InfoSkill)c.UserData).CharacterInfo.Salary;
});
totalBlock.Text = TextManager.FormatCurrency(total);
bool enoughMoney = campaign == null || campaign.Wallet.CanAfford(total);
bool enoughMoney = campaign == null || campaign.CanAfford(total);
totalBlock.TextColor = enoughMoney ? Color.White : Color.Red;
validateHiresButton.Enabled = enoughMoney && HasPermission && pendingList.Content.RectTransform.Children.Any();
}
@@ -652,7 +639,7 @@ namespace Barotrauma
int total = nonDuplicateHires.Aggregate(0, (total, info) => total + info.Salary);
if (!campaign.Wallet.CanAfford(total)) { return false; }
if (!campaign.CanAfford(total)) { return false; }
bool atLeastOneHired = false;
foreach (CharacterInfo ci in nonDuplicateHires)
@@ -792,6 +779,10 @@ namespace Barotrauma
CreateUI();
UpdateLocationView(campaign.Map.CurrentLocation, false);
}
else
{
playerBalanceElement = CampaignUI.UpdateBalanceElement(playerBalanceElement);
}
(GUIComponent highlightedFrame, CharacterInfo highlightedInfo) = FindHighlightedCharacter(GUI.MouseOn);
if (highlightedFrame != null && highlightedInfo != null)
@@ -567,9 +567,9 @@ namespace Barotrauma
GameMain.GameSession?.EventManager?.DrawPinnedEvent(spriteBatch);
if (HUDLayoutSettings.DebugDraw) HUDLayoutSettings.Draw(spriteBatch);
if (HUDLayoutSettings.DebugDraw) { HUDLayoutSettings.Draw(spriteBatch); }
if (GameMain.Client != null) GameMain.Client.Draw(spriteBatch);
GameMain.Client?.Draw(spriteBatch);
if (Character.Controlled?.Inventory != null)
{
@@ -616,28 +616,46 @@ namespace Barotrauma
}
DrawSavingIndicator(spriteBatch);
if (GameMain.WindowActive && !HideCursor)
{
spriteBatch.End();
spriteBatch.Begin(SpriteSortMode.Deferred, samplerState: SamplerStateClamp, rasterizerState: GameMain.ScissorTestEnable);
if (GameMain.GameSession?.CrewManager is { DraggedOrderPrefab: { SymbolSprite: { } orderSprite, Color: var color }, DragOrder: true })
{
float spriteSize = Math.Max(orderSprite.size.X, orderSprite.size.Y);
orderSprite.Draw(spriteBatch, PlayerInput.LatestMousePosition, color, orderSprite.size / 2f, scale: 32f / spriteSize * Scale);
}
var sprite = MouseCursorSprites[MouseCursor] ?? MouseCursorSprites[CursorState.Default];
sprite.Draw(spriteBatch, PlayerInput.LatestMousePosition, Color.White, sprite.Origin, 0f, Scale / 1.5f);
spriteBatch.End();
spriteBatch.Begin(SpriteSortMode.Deferred, samplerState: SamplerState, rasterizerState: GameMain.ScissorTestEnable);
}
DrawCursor(spriteBatch);
HideCursor = false;
}
}
public static void DrawMessageBoxesOnly(SpriteBatch spriteBatch)
{
bool anyDrawn = false;
foreach (var component in updateList)
{
component.DrawAuto(spriteBatch);
anyDrawn = true;
}
if (anyDrawn)
{
DrawCursor(spriteBatch);
}
}
private static void DrawCursor(SpriteBatch spriteBatch)
{
if (GameMain.WindowActive && !HideCursor && MouseCursorSprites.Prefabs.Any())
{
spriteBatch.End();
spriteBatch.Begin(SpriteSortMode.Deferred, samplerState: SamplerStateClamp, rasterizerState: GameMain.ScissorTestEnable);
if (GameMain.GameSession?.CrewManager is { DraggedOrderPrefab: { SymbolSprite: { } orderSprite, Color: var color }, DragOrder: true })
{
float spriteSize = Math.Max(orderSprite.size.X, orderSprite.size.Y);
orderSprite.Draw(spriteBatch, PlayerInput.LatestMousePosition, color, orderSprite.size / 2f, scale: 32f / spriteSize * Scale);
}
var sprite = MouseCursorSprites[MouseCursor] ?? MouseCursorSprites[CursorState.Default];
sprite.Draw(spriteBatch, PlayerInput.LatestMousePosition, Color.White, sprite.Origin, 0f, Scale / 1.5f);
spriteBatch.End();
spriteBatch.Begin(SpriteSortMode.Deferred, samplerState: SamplerState, rasterizerState: GameMain.ScissorTestEnable);
}
}
public static void DrawBackgroundSprite(SpriteBatch spriteBatch, Sprite backgroundSprite, float aberrationStrength = 1.0f)
{
double aberrationT = (Timing.TotalTime * 0.5f);
@@ -1204,6 +1222,17 @@ namespace Barotrauma
}
}
public static void UpdateGUIMessageBoxesOnly(float deltaTime)
{
GUIMessageBox.AddActiveToGUIUpdateList();
RefreshUpdateList();
UpdateMouseOn();
foreach (var c in updateList)
{
c.UpdateAuto(deltaTime);
}
}
private static void UpdateMessages(float deltaTime)
{
lock (mutex)
@@ -36,6 +36,8 @@ namespace Barotrauma
public string Tag { get; private set; }
public bool Closed { get; private set; }
public bool DisplayInLoadingScreens;
public GUIImage Icon
{
get;
@@ -451,6 +453,10 @@ namespace Barotrauma
continue;
}
if (messageBox.type != type) { continue; }
if (!messageBox.DisplayInLoadingScreens && GameMain.Instance.LoadingScreenOpen)
{
continue;
}
// These are handled separately in GUI.HandlePersistingElements()
if (MessageBoxes[i].UserData as string == "verificationprompt") { continue; }
@@ -395,14 +395,13 @@ namespace Barotrauma
origin = TextSize * 0.5f;
origin.X = 0;
if (textAlignment.HasFlag(Alignment.Left) && !overflowClipActive)
if (textAlignment.HasFlag(Alignment.Left))
{
textPos.X = padding.X;
}
if (textAlignment.HasFlag(Alignment.Right) || overflowClipActive)
if (textAlignment.HasFlag(Alignment.Right))
{
textPos.X = rect.Width - padding.Z;
//origin.X = TextSize.X;
}
if (textAlignment.HasFlag(Alignment.Top))
{
@@ -453,24 +453,7 @@ namespace Barotrauma
if (CaretEnabled)
{
if (textBlock.OverflowClipActive)
{
float left = textBlock.Rect.X + textBlock.Padding.X;
if (CaretScreenPos.X < left)
{
float diff = left - CaretScreenPos.X;
textBlock.TextPos = new Vector2(textBlock.TextPos.X + diff, textBlock.TextPos.Y);
CalculateCaretPos();
}
float right = textBlock.Rect.Right - textBlock.Padding.Z;
if (CaretScreenPos.X > right)
{
float diff = CaretScreenPos.X - right;
textBlock.TextPos = new Vector2(textBlock.TextPos.X - diff, textBlock.TextPos.Y);
CalculateCaretPos();
}
}
HandleCaretBoundsOverflow();
caretTimer += deltaTime;
caretVisible = ((caretTimer * 1000.0f) % 1000) < 500;
if (caretVisible && caretPosDirty)
@@ -496,6 +479,29 @@ namespace Barotrauma
textBlock.State = State;
}
private void HandleCaretBoundsOverflow()
{
if (textBlock.OverflowClipActive)
{
CalculateCaretPos();
float left = textBlock.Rect.X + textBlock.Padding.X;
if (CaretScreenPos.X < left)
{
float diff = left - CaretScreenPos.X;
textBlock.TextPos = new Vector2(textBlock.TextPos.X + diff, textBlock.TextPos.Y);
CalculateCaretPos();
}
float right = textBlock.Rect.Right - textBlock.Padding.Z;
if (CaretScreenPos.X > right)
{
float diff = CaretScreenPos.X - right;
textBlock.TextPos = new Vector2(textBlock.TextPos.X - diff, textBlock.TextPos.Y);
CalculateCaretPos();
}
}
}
private void DrawCaretAndSelection(SpriteBatch spriteBatch, GUICustomComponent customComponent)
{
if (!Visible) { return; }
@@ -564,15 +570,33 @@ namespace Barotrauma
{
RemoveSelectedText();
}
Vector2 textPos = textBlock.TextPos;
bool wasOverflowClipActive = textBlock.OverflowClipActive;
using var _ = new TextPosPreservation(this);
if (SetText(Text.Insert(CaretIndex, input)))
{
CaretIndex = Math.Min(Text.Length, CaretIndex + input.Length);
OnTextChanged?.Invoke(this, Text);
}
}
private readonly ref struct TextPosPreservation
{
private readonly GUITextBox textBox;
private GUITextBlock textBlock => textBox.TextBlock;
private readonly bool wasOverflowClipActive;
private readonly Vector2 textPos;
public TextPosPreservation(GUITextBox tb)
{
textBox = tb;
wasOverflowClipActive = tb.TextBlock.OverflowClipActive;
textPos = tb.TextBlock.TextPos;
}
public void Dispose()
{
if (textBlock.OverflowClipActive && wasOverflowClipActive && !MathUtils.NearlyEqual(textBlock.TextPos, textPos))
{
textBlock.TextPos = textPos + Vector2.UnitX * Font.MeasureString(input).X * TextBlock.TextScale;
textBlock.TextPos = textPos;
}
}
}
@@ -587,6 +611,8 @@ namespace Barotrauma
switch (command)
{
case '\b' when !Readonly: //backspace
{
using var _ = new TextPosPreservation(this);
if (PlayerInput.KeyDown(Keys.LeftControl) || PlayerInput.KeyDown(Keys.RightControl))
{
SetText(string.Empty, false);
@@ -605,6 +631,7 @@ namespace Barotrauma
}
OnTextChanged?.Invoke(this, Text);
break;
}
case (char)0x3: // ctrl-c
CopySelectedText();
break;
@@ -1,13 +1,11 @@
using Microsoft.Xna.Framework;
using Barotrauma.Extensions;
using Barotrauma.Media;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using System;
using System.Collections.Generic;
using System.Xml.Linq;
using Barotrauma.Media;
using System.Linq;
using Barotrauma.Extensions;
using System.Collections.Immutable;
namespace Barotrauma
{
@@ -16,7 +14,7 @@ namespace Barotrauma
private readonly Texture2D defaultBackgroundTexture, overlay;
private readonly SpriteSheet decorativeGraph, decorativeMap;
private Texture2D currentBackgroundTexture;
private Sprite noiseSprite;
private readonly Sprite noiseSprite;
private string randText = "";
@@ -250,8 +248,8 @@ namespace Barotrauma
}
}
}
}
GUI.DrawMessageBoxesOnly(spriteBatch);
spriteBatch.End();
spriteBatch.Begin(blendState: BlendState.Additive);
@@ -7,6 +7,7 @@ using System.Diagnostics.CodeAnalysis;
using System.Linq;
using Barotrauma.Extensions;
using Microsoft.Xna.Framework;
using PlayerBalanceElement = Barotrauma.CampaignUI.PlayerBalanceElement;
namespace Barotrauma
{
@@ -180,6 +181,8 @@ namespace Barotrauma
private const float refreshTimerMax = 3f;
private float refreshTimer = 0;
private PlayerBalanceElement? playerBalanceElement;
public MedicalClinicUI(MedicalClinic clinic, GUIComponent parent)
{
medicalClinic = clinic;
@@ -271,7 +274,7 @@ namespace Barotrauma
healList.PriceBlock.Text = TextManager.FormatCurrency(totalCost);
healList.PriceBlock.TextColor = GUIStyle.Red;
healList.HealButton.Enabled = false;
if (medicalClinic.GetWallet().CanAfford(totalCost))
if (medicalClinic.GetBalance() >= totalCost)
{
healList.PriceBlock.TextColor = GUIStyle.TextColorNormal;
if (medicalClinic.PendingHeals.Any())
@@ -428,6 +431,7 @@ namespace Barotrauma
{
container.ClearChildren();
pendingHealList = null;
playerBalanceElement = null;
int panelMaxWidth = (int)(GUI.xScale * (GUI.HorizontalAspectRatio < 1.4f ? 650 : 560));
GUIFrame paddedParent = new GUIFrame(new RectTransform(new Vector2(0.95f), container.RectTransform, Anchor.Center), style: null);
@@ -458,19 +462,7 @@ namespace Barotrauma
RelativeSpacing = 0.01f
};
GUILayoutGroup balanceLayout = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.1f), crewContent.RectTransform));
GUITextBlock balanceLabel = new GUITextBlock(new RectTransform(new Vector2(1f, 0.5f), balanceLayout.RectTransform), TextManager.Get("campaignstore.balance"), textAlignment: Alignment.BottomRight, font: GUIStyle.Font)
{
AutoScaleVertical = true,
ForceUpperCase = ForceUpperCase.Yes
};
GUITextBlock moneyLabel = new GUITextBlock(new RectTransform(new Vector2(1f, 0.5f), balanceLayout.RectTransform), string.Empty, textAlignment: Alignment.TopRight, font: GUIStyle.SubHeadingFont)
{
TextGetter = () => TextManager.FormatCurrency(medicalClinic.GetWallet().Balance),
AutoScaleVertical = true,
TextScale = 1.1f
};
playerBalanceElement = CampaignUI.AddBalanceElement(crewContent, new Vector2(1f, 0.1f));
GUIFrame crewBackground = new GUIFrame(new RectTransform(Vector2.One, crewContent.RectTransform));
@@ -577,7 +569,7 @@ namespace Barotrauma
GUILayoutGroup buttonLayout = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.5f), footerLayout.RectTransform), isHorizontal: true, childAnchor: Anchor.CenterRight);
GUIButton healButton = new GUIButton(new RectTransform(new Vector2(0.33f, 1f), buttonLayout.RectTransform), TextManager.Get("medicalclinic.heal"))
{
Enabled = medicalClinic.PendingHeals.Any() && medicalClinic.GetWallet().CanAfford(medicalClinic.GetTotalCost()),
Enabled = medicalClinic.PendingHeals.Any() && medicalClinic.GetBalance() >= medicalClinic.GetTotalCost(),
OnClicked = (button, _) =>
{
button.Enabled = false;
@@ -1050,6 +1042,10 @@ namespace Barotrauma
{
CreateUI();
}
else
{
playerBalanceElement = CampaignUI.UpdateBalanceElement(playerBalanceElement);
}
refreshTimer += deltaTime;
@@ -6,6 +6,7 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using PlayerBalanceElement = Barotrauma.CampaignUI.PlayerBalanceElement;
namespace Barotrauma
{
@@ -66,12 +67,15 @@ namespace Barotrauma
private Point resolutionWhenCreated;
private PlayerBalanceElement? playerBalanceElement;
private Dictionary<ItemPrefab, ItemQuantity> OwnedItems { get; } = new Dictionary<ItemPrefab, ItemQuantity>();
private Location.StoreInfo ActiveStore { get; set; }
private CargoManager CargoManager => campaignUI.Campaign.CargoManager;
private Location CurrentLocation => campaignUI.Campaign.Map?.CurrentLocation;
private Wallet PlayerWallet => campaignUI.Campaign.Wallet;
private int Balance => campaignUI.Campaign.GetBalance();
private bool IsBuying => activeTab switch
{
StoreTab.Buy => true,
@@ -207,7 +211,7 @@ namespace Barotrauma
{
if (CurrentLocation?.Stores != null)
{
if (CurrentLocation.GetStore(identifier) is { } store)
if (!identifier.IsEmpty && CurrentLocation.GetStore(identifier) is { } store)
{
ActiveStore = store;
if (storeNameBlock != null)
@@ -223,14 +227,45 @@ namespace Barotrauma
else
{
ActiveStore = null;
string msg = $"Error selecting store with identifier \"{identifier}\" at {CurrentLocation}: store with the identifier doesn't exist at the location.";
string errorId, msg;
if (identifier.IsEmpty)
{
errorId = "Store.SelectStore:IdentifierEmpty";
msg = $"Error selecting store at {CurrentLocation}: identifier is empty.";
}
else
{
errorId = "Store.SelectStore:StoreDoesntExist";
msg = $"Error selecting store with identifier \"{identifier}\" at {CurrentLocation}: store with the identifier doesn't exist at the location.";
}
DebugConsole.ShowError(msg);
GameAnalyticsManager.AddErrorEventOnce("Store.SelectStore:StoreDoesntExist", GameAnalyticsManager.ErrorSeverity.Error, msg);
GameAnalyticsManager.AddErrorEventOnce(errorId, GameAnalyticsManager.ErrorSeverity.Error, msg);
}
}
else
{
ActiveStore = null;
string errorId = "", msg = "";
if (campaignUI.Campaign.Map == null)
{
errorId = "Store.SelectStore:MapNull";
msg = $"Error selecting store with identifier \"{identifier}\": Map is null.";
}
else if (CurrentLocation == null)
{
errorId = "Store.SelectStore:CurrentLocationNull";
msg = $"Error selecting store with identifier \"{identifier}\": CurrentLocation is null.";
}
else if (CurrentLocation.Stores == null)
{
errorId = "Store.SelectStore:StoresNull";
msg = $"Error selecting store with identifier \"{identifier}\": CurrentLocation.Stores is null.";
}
if (!msg.IsNullOrEmpty())
{
DebugConsole.ShowError(msg);
GameAnalyticsManager.AddErrorEventOnce(errorId, GameAnalyticsManager.ErrorSeverity.Error, msg);
}
}
RefreshItemsToSell();
Refresh();
@@ -615,23 +650,7 @@ namespace Barotrauma
};
// Player balance ------------------------------------------------
var playerBalanceContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.75f / 14.0f), shoppingCrateContent.RectTransform), childAnchor: Anchor.TopRight)
{
RelativeSpacing = 0.005f
};
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.5f), playerBalanceContainer.RectTransform),
TextManager.Get("campaignstore.balance"), font: GUIStyle.Font, textAlignment: Alignment.BottomRight)
{
AutoScaleVertical = true,
ForceUpperCase = ForceUpperCase.Yes
};
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.5f), playerBalanceContainer.RectTransform),
"", textColor: Color.White, font: GUIStyle.SubHeadingFont, textAlignment: Alignment.TopRight)
{
AutoScaleVertical = true,
TextScale = 1.1f,
TextGetter = GetPlayerBalanceText
};
playerBalanceElement = CampaignUI.AddBalanceElement(shoppingCrateContent, new Vector2(1.0f, 0.75f / 14.0f));
// Divider ------------------------------------------------
var dividerFrame = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.6f / 14.0f), shoppingCrateContent.RectTransform), style: null);
@@ -663,7 +682,7 @@ namespace Barotrauma
{
CanBeFocused = false,
TextScale = 1.1f,
TextGetter = () => IsBuying ? GetPlayerBalanceText() : GetMerchantBalanceText()
TextGetter = () => IsBuying ? CampaignUI.GetTotalBalance() : GetMerchantBalanceText()
};
var totalContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.05f), shoppingCrateInventoryContainer.RectTransform), isHorizontal: true)
@@ -712,8 +731,6 @@ namespace Barotrauma
private LocalizedString GetMerchantBalanceText() => TextManager.FormatCurrency(ActiveStore?.Balance ?? 0);
private LocalizedString GetPlayerBalanceText() => TextManager.FormatCurrency(PlayerWallet.Balance);
private GUILayoutGroup CreateDealsGroup(GUIListBox parentList, int elementCount)
{
// Add 1 for the header
@@ -2037,7 +2054,7 @@ namespace Barotrauma
totalPrice += item.Quantity * ActiveStore.GetAdjustedItemBuyPrice(item.ItemPrefab, priceInfo: priceInfo);
}
itemsToRemove.ForEach(i => itemsToPurchase.Remove(i));
if (itemsToPurchase.None() || !PlayerWallet.CanAfford(totalPrice)) { return false; }
if (itemsToPurchase.None() || Balance < totalPrice) { return false; }
CargoManager.PurchaseItems(ActiveStore.Identifier, itemsToPurchase, true);
GameMain.Client?.SendCampaignState();
var dialog = new GUIMessageBox(
@@ -2091,7 +2108,7 @@ namespace Barotrauma
if (IsBuying)
{
shoppingCrateTotal.Text = TextManager.FormatCurrency(buyTotal);
shoppingCrateTotal.TextColor = !PlayerWallet.CanAfford(buyTotal) ? Color.Red : Color.White;
shoppingCrateTotal.TextColor = Balance < buyTotal ? Color.Red : Color.White;
}
else
{
@@ -2137,7 +2154,7 @@ namespace Barotrauma
ActiveShoppingCrateList.Content.RectTransform.Children.Any() &&
activeTab switch
{
StoreTab.Buy => PlayerWallet.CanAfford(buyTotal),
StoreTab.Buy => Balance >= buyTotal,
StoreTab.Sell => CurrentLocation != null && sellTotal <= ActiveStore.Balance,
StoreTab.SellSub => CurrentLocation != null && sellFromSubTotal <= ActiveStore.Balance,
_ => false
@@ -2151,6 +2168,7 @@ namespace Barotrauma
ActiveShoppingCrateList.Content.RectTransform.Children.Any();
}
private int prevBalance;
private float ownedItemsUpdateTimer = 0.0f, sellableItemsFromSubUpdateTimer = 0.0f;
private const float timerUpdateInterval = 1.5f;
private readonly Stopwatch updateStopwatch = new Stopwatch();
@@ -2166,6 +2184,8 @@ namespace Barotrauma
}
else
{
playerBalanceElement = CampaignUI.UpdateBalanceElement(playerBalanceElement);
// Update the owned items at short intervals and check if the interface should be refreshed
ownedItemsUpdateTimer += deltaTime;
if (ownedItemsUpdateTimer >= timerUpdateInterval)
@@ -2202,6 +2222,16 @@ namespace Barotrauma
}
}
}
// Refresh the interface if balance changes and the buy tab is open
if (activeTab == StoreTab.Buy)
{
int currBalance = Balance;
if (prevBalance != currBalance)
{
needsBuyingRefresh = true;
prevBalance = currBalance;
}
}
if (needsItemsToSellRefresh)
{
RefreshItemsToSell();
@@ -4,6 +4,8 @@ using Microsoft.Xna.Framework;
using System.Linq;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using System.Globalization;
using PlayerBalanceElement = Barotrauma.CampaignUI.PlayerBalanceElement;
namespace Barotrauma
{
@@ -31,7 +33,7 @@ namespace Barotrauma
private readonly List<SubmarineInfo> subsToShow;
private readonly SubmarineDisplayContent[] submarineDisplays = new SubmarineDisplayContent[submarinesPerPage];
private SubmarineInfo selectedSubmarine = null;
private LocalizedString purchaseAndSwitchText, purchaseOnlyText, deliveryText, currentSubText, deliveryFeeText, priceText, switchText, missingPreviewText, currencyName;
private LocalizedString purchaseAndSwitchText, purchaseOnlyText, deliveryText, currentSubText, switchText, missingPreviewText, currencyName;
private readonly RectTransform parent;
private readonly Action closeAction;
private Sprite pageIndicator;
@@ -44,6 +46,8 @@ namespace Barotrauma
private static readonly Color indicatorColor = new Color(112, 149, 129);
private Point createdForResolution;
private PlayerBalanceElement? playerBalanceElement;
private struct SubmarineDisplayContent
{
public GUIFrame background;
@@ -85,12 +89,10 @@ namespace Barotrauma
{
initialized = true;
currentSubText = TextManager.Get("currentsub");
deliveryFeeText = TextManager.Get("deliveryfee");
deliveryText = TextManager.Get("requestdeliverybutton");
switchText = TextManager.Get("switchtosubmarinebutton");
purchaseAndSwitchText = TextManager.Get("purchaseandswitch");
purchaseOnlyText = TextManager.Get("purchase");
priceText = TextManager.Get("price");
if (transferService)
{
deliveryFee = CalculateDeliveryFee();
@@ -126,10 +128,7 @@ namespace Barotrauma
content = new GUILayoutGroup(new RectTransform(new Point(background.Rect.Width - HUDLayoutSettings.Padding * 4, background.Rect.Height - HUDLayoutSettings.Padding * 4), background.RectTransform, Anchor.Center)) { AbsoluteSpacing = (int)(HUDLayoutSettings.Padding * 1.5f) };
GUITextBlock header = new GUITextBlock(new RectTransform(new Vector2(1f, 0.0f), content.RectTransform), transferService ? TextManager.Get("switchsubmarineheader") : TextManager.GetWithVariable("outpostshipyard", "[location]", GameMain.GameSession.Map.CurrentLocation.Name), font: GUIStyle.LargeFont);
header.CalculateHeightFromText(0, true);
GUITextBlock credits = new GUITextBlock(new RectTransform(Vector2.One, header.RectTransform), "", font: GUIStyle.SubHeadingFont, textAlignment: Alignment.CenterRight)
{
TextGetter = CampaignUI.GetMoney
};
playerBalanceElement = CampaignUI.AddBalanceElement(header, new Vector2(1.0f, 1.5f));
new GUIFrame(new RectTransform(new Vector2(1.0f, 0.01f), content.RectTransform), style: "HorizontalLine");
@@ -257,6 +256,10 @@ namespace Barotrauma
{
RefreshSubmarineDisplay(true);
}
else
{
playerBalanceElement = CampaignUI.UpdateBalanceElement(playerBalanceElement);
}
// Input
if (PlayerInput.KeyHit(Keys.Left))
@@ -271,9 +274,22 @@ namespace Barotrauma
public void RefreshSubmarineDisplay(bool updateSubs)
{
if (!initialized) Initialize();
if (GameMain.GraphicsWidth != createdForResolution.X || GameMain.GraphicsHeight != createdForResolution.Y) CreateGUI();
if (updateSubs) UpdateSubmarines();
if (!initialized)
{
Initialize();
}
if (GameMain.GraphicsWidth != createdForResolution.X || GameMain.GraphicsHeight != createdForResolution.Y)
{
CreateGUI();
}
else
{
playerBalanceElement = CampaignUI.UpdateBalanceElement(playerBalanceElement);
}
if (updateSubs)
{
UpdateSubmarines();
}
if (pageIndicators != null)
{
@@ -327,12 +343,12 @@ namespace Barotrauma
};
submarineDisplays[i].submarineName.Text = subToDisplay.DisplayName;
submarineDisplays[i].submarineClass.Text = $"{TextManager.GetWithVariable("submarineclass.classsuffixformat", "[type]", TextManager.Get($"submarineclass.{subToDisplay.SubmarineClass}"))}";
submarineDisplays[i].submarineClass.Text = TextManager.GetWithVariable("submarineclass.classsuffixformat", "[type]", TextManager.Get($"submarineclass.{subToDisplay.SubmarineClass}"));
if (!GameMain.GameSession.IsSubmarineOwned(subToDisplay))
{
LocalizedString amountString = TextManager.FormatCurrency(subToDisplay.Price);
submarineDisplays[i].submarineFee.Text = priceText.Replace("[amount]", amountString).Replace("[currencyname]", string.Empty).TrimEnd();
submarineDisplays[i].submarineFee.Text = TextManager.GetWithVariable("price", "[amount]", amountString);
}
else
{
@@ -341,7 +357,7 @@ namespace Barotrauma
if (deliveryFee > 0)
{
LocalizedString amountString = TextManager.FormatCurrency(deliveryFee);
submarineDisplays[i].submarineFee.Text = deliveryFeeText.Replace("[amount]", amountString).Replace("[currencyname]", string.Empty).TrimEnd();
submarineDisplays[i].submarineFee.Text = TextManager.GetWithVariable("deliveryfee", "[amount]", amountString);
}
else
{
@@ -577,7 +593,7 @@ namespace Barotrauma
private void ShowTransferPrompt()
{
if (!GameMain.GameSession.Campaign.Wallet.CanAfford(deliveryFee) && deliveryFee > 0)
if (!GameMain.GameSession.Campaign.CanAfford(deliveryFee) && deliveryFee > 0)
{
new GUIMessageBox(TextManager.Get("deliveryrequestheader"), TextManager.GetWithVariables("notenoughmoneyfordeliverytext",
("[currencyname]", currencyName),
@@ -625,7 +641,7 @@ namespace Barotrauma
private void ShowBuyPrompt(bool purchaseOnly)
{
if (!GameMain.GameSession.Campaign.Wallet.CanAfford(selectedSubmarine.Price))
if (!GameMain.GameSession.Campaign.CanAfford(selectedSubmarine.Price))
{
new GUIMessageBox(TextManager.Get("purchasesubmarineheader"), TextManager.GetWithVariables("notenoughmoneyforpurchasetext",
("[currencyname]", currencyName),
@@ -698,6 +698,12 @@ namespace Barotrauma
Color = Color.Transparent
};
frame.OnSecondaryClicked += (component, data) =>
{
NetLobbyScreen.CreateModerationContextMenu(client);
return true;
};
var paddedFrame = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.9f), frame.RectTransform, Anchor.Center), isHorizontal: true)
{
AbsoluteSpacing = 2
@@ -1057,7 +1063,7 @@ namespace Barotrauma
return;
}
bool hasMoneyPermissions = campaign.AllowedToManageCampaign(ClientPermissions.ManageMoney);
bool hasMoneyPermissions = CampaignMode.AllowedToManageWallets();
salarySlider.Enabled = hasMoneyPermissions;
Wallet otherWallet;
@@ -1402,6 +1408,12 @@ namespace Barotrauma
private void CreateMissionInfo(GUIFrame infoFrame)
{
if (Level.Loaded?.LevelData == null)
{
DebugConsole.ThrowError("Failed to display mission info in the tab menu (no level loaded).\n" + Environment.StackTrace);
return;
}
infoFrame.ClearChildren();
GUIFrame missionFrame = new GUIFrame(new RectTransform(Vector2.One, infoFrame.RectTransform, Anchor.TopCenter), style: "GUIFrameListBox");
int padding = (int)(0.0245f * missionFrame.Rect.Height);
@@ -2016,7 +2028,7 @@ namespace Barotrauma
{
parent.Content.ClearChildren();
List<GUITextBlock> skillNames = new List<GUITextBlock>();
foreach (Skill skill in character.Info.Job.Skills)
foreach (Skill skill in character.Info.Job.GetSkills())
{
GUILayoutGroup skillContainer = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.2f), parent.Content.RectTransform), isHorizontal: true) { CanBeFocused = false };
@@ -11,6 +11,7 @@ using FarseerPhysics;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using PlayerBalanceElement = Barotrauma.CampaignUI.PlayerBalanceElement;
// ReSharper disable UnusedVariable
@@ -41,7 +42,7 @@ namespace Barotrauma
private readonly CampaignUI campaignUI;
private CampaignMode? Campaign => campaignUI.Campaign;
private Wallet PlayerWallet => Campaign?.Wallet ?? Wallet.Invalid;
private int PlayerBalance => Campaign?.GetBalance() ?? 0;
private UpgradeTab selectedUpgradeTab = UpgradeTab.Upgrade;
private GUIMessageBox? currectConfirmation;
@@ -75,6 +76,8 @@ namespace Barotrauma
private bool needsRefresh = true;
private PlayerBalanceElement? playerBalanceElement;
/// <summary>
/// While set to true any call to <see cref="RefreshUpgradeList"/> will cause the buy button to be disabled and to not update the prices.
/// This is to prevent us from buying another upgrade before the server has given us the new prices and causing potential syncing issues.
@@ -293,9 +296,14 @@ namespace Barotrauma
* |---------------------------------------------------------------------------------------------------|
*/
GUILayoutGroup rightLayout = new GUILayoutGroup(rectT(0.5f, 1, topHeaderLayout), childAnchor: Anchor.TopRight);
GUILayoutGroup priceLayout = new GUILayoutGroup(rectT(1, 0.8f, rightLayout), childAnchor: Anchor.Center) { RelativeSpacing = 0.08f };
new GUITextBlock(rectT(1f, 0f, priceLayout), TextManager.Get("CampaignStore.Balance"), font: GUIStyle.SubHeadingFont, textAlignment: Alignment.Right);
new GUITextBlock(rectT(1f, 0f, priceLayout), TextManager.FormatCurrency(PlayerWallet.Balance), font: GUIStyle.SubHeadingFont, textAlignment: Alignment.Right) { TextGetter = () => TextManager.FormatCurrency(PlayerWallet.Balance) };
playerBalanceElement = CampaignUI.AddBalanceElement(rightLayout, new Vector2(1.0f, 0.8f));
if (playerBalanceElement is { } balanceElement)
{
balanceElement.TotalBalanceContainer.OnAddedToGUIUpdateList += (_) =>
{
playerBalanceElement = CampaignUI.UpdateBalanceElement(playerBalanceElement);
};
}
new GUIFrame(rectT(0.5f, 0.1f, rightLayout, Anchor.BottomRight), style: "HorizontalLine") { IgnoreLayoutGroups = true };
repairButton.OnClicked = upgradeButton.OnClicked = (button, o) =>
@@ -435,14 +443,14 @@ namespace Barotrauma
return false;
}
if (PlayerWallet.CanAfford(hullRepairCost))
if (PlayerBalance >= hullRepairCost)
{
LocalizedString body = TextManager.GetWithVariable("WallRepairs.PurchasePromptBody", "[amount]", hullRepairCost.ToString());
currectConfirmation = EventEditorScreen.AskForConfirmation(TextManager.Get("Upgrades.PurchasePromptTitle"), body, () =>
{
if (PlayerWallet.Balance >= hullRepairCost)
if (PlayerBalance >= hullRepairCost)
{
PlayerWallet.TryDeduct(hullRepairCost);
Campaign.TryPurchase(null, hullRepairCost);
GameAnalyticsManager.AddMoneySpentEvent(hullRepairCost, GameAnalyticsManager.MoneySink.Service, "hullrepairs");
Campaign.PurchasedHullRepairs = true;
button.Enabled = false;
@@ -470,14 +478,14 @@ namespace Barotrauma
CreateRepairEntry(currentStoreLayout.Content, TextManager.Get("repairallitems"), "RepairItemsButton", itemRepairCost, (button, o) =>
{
if (PlayerWallet.Balance >= itemRepairCost && !Campaign.PurchasedItemRepairs)
if (PlayerBalance >= itemRepairCost && !Campaign.PurchasedItemRepairs)
{
LocalizedString body = TextManager.GetWithVariable("ItemRepairs.PurchasePromptBody", "[amount]", itemRepairCost.ToString());
currectConfirmation = EventEditorScreen.AskForConfirmation(TextManager.Get("Upgrades.PurchasePromptTitle"), body, () =>
{
if (PlayerWallet.Balance >= itemRepairCost && !Campaign.PurchasedItemRepairs)
if (PlayerBalance >= itemRepairCost && !Campaign.PurchasedItemRepairs)
{
PlayerWallet.TryDeduct(itemRepairCost);
Campaign.TryPurchase(null, itemRepairCost);
GameAnalyticsManager.AddMoneySpentEvent(hullRepairCost, GameAnalyticsManager.MoneySink.Service, "devicerepairs");
Campaign.PurchasedItemRepairs = true;
button.Enabled = false;
@@ -516,14 +524,14 @@ namespace Barotrauma
return false;
}
if (PlayerWallet.CanAfford(shuttleRetrieveCost) && !Campaign.PurchasedLostShuttles)
if (PlayerBalance >= shuttleRetrieveCost && !Campaign.PurchasedLostShuttles)
{
LocalizedString body = TextManager.GetWithVariable("ReplaceLostShuttles.PurchasePromptBody", "[amount]", shuttleRetrieveCost.ToString());
currectConfirmation = EventEditorScreen.AskForConfirmation(TextManager.Get("Upgrades.PurchasePromptTitle"), body, () =>
{
if (PlayerWallet.Balance >= shuttleRetrieveCost && !Campaign.PurchasedLostShuttles)
if (PlayerBalance >= shuttleRetrieveCost && !Campaign.PurchasedLostShuttles)
{
PlayerWallet.TryDeduct(shuttleRetrieveCost);
Campaign.TryPurchase(null, shuttleRetrieveCost);
GameAnalyticsManager.AddMoneySpentEvent(hullRepairCost, GameAnalyticsManager.MoneySink.Service, "retrieveshuttle");
Campaign.PurchasedLostShuttles = true;
button.Enabled = false;
@@ -581,13 +589,13 @@ namespace Barotrauma
new GUITextBlock(rectT(1, 0, textLayout), title, font: GUIStyle.SubHeadingFont) { CanBeFocused = false, AutoScaleHorizontal = true };
new GUITextBlock(rectT(1, 0, textLayout), TextManager.FormatCurrency(price));
GUILayoutGroup buyButtonLayout = new GUILayoutGroup(rectT(0.2f, 1, contentLayout), childAnchor: Anchor.Center) { UserData = "buybutton" };
new GUIButton(rectT(0.7f, 0.5f, buyButtonLayout), string.Empty, style: "RepairBuyButton") { ClickSound = GUISoundType.HireRepairClick, Enabled = PlayerWallet.Balance >= price && !isDisabled, OnClicked = onPressed };
new GUIButton(rectT(0.7f, 0.5f, buyButtonLayout), string.Empty, style: "RepairBuyButton") { ClickSound = GUISoundType.HireRepairClick, Enabled = PlayerBalance >= price && !isDisabled, OnClicked = onPressed };
contentLayout.Recalculate();
buyButtonLayout.Recalculate();
if (disableElement)
{
frameChild.Enabled = PlayerWallet.Balance >= price && !isDisabled;
frameChild.Enabled = PlayerBalance >= price && !isDisabled;
}
if (!HasPermission)
@@ -972,7 +980,7 @@ namespace Barotrauma
buttonStyle: isPurchased ? "WeaponInstallButton" : "StoreAddToCrateButton"));
if (!(frames.Last().FindChild(c => c is GUIButton, recursive: true) is GUIButton buyButton)) { continue; }
if (PlayerWallet.CanAfford(price))
if (PlayerBalance >= price)
{
buyButton.Enabled = true;
buyButton.OnClicked += (button, o) =>
@@ -1602,7 +1610,7 @@ namespace Barotrauma
if (button != null)
{
button.Enabled = currentLevel < prefab.MaxLevel;
if (WaitForServerUpdate || !campaign.Wallet.CanAfford(price))
if (WaitForServerUpdate || campaign.GetBalance() < price)
{
button.Enabled = false;
}