Faction Test 100.4.0.0
This commit is contained in:
@@ -769,7 +769,7 @@ namespace Barotrauma
|
||||
if (Character.Controlled != null && ChatMessage.CanUseRadio(Character.Controlled, out WifiComponent radio))
|
||||
{
|
||||
radio.Channel = channel;
|
||||
GameMain.Client?.CreateEntityEvent(radio.Item, new Item.ChangePropertyEventData(radio.SerializableProperties["channel".ToIdentifier()]));
|
||||
GameMain.Client?.CreateEntityEvent(radio.Item, new Item.ChangePropertyEventData(radio.SerializableProperties["channel".ToIdentifier()], radio));
|
||||
|
||||
if (setText)
|
||||
{
|
||||
|
||||
@@ -3,7 +3,6 @@ using Barotrauma.Networking;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using PlayerBalanceElement = Barotrauma.CampaignUI.PlayerBalanceElement;
|
||||
|
||||
@@ -29,6 +28,8 @@ namespace Barotrauma
|
||||
|
||||
private Point resolutionWhenCreated;
|
||||
|
||||
private bool needsHireableRefresh;
|
||||
|
||||
private enum SortingMethod
|
||||
{
|
||||
AlphabeticalAsc,
|
||||
@@ -50,6 +51,8 @@ namespace Barotrauma
|
||||
campaignUI.Campaign.Map.OnLocationChanged.RegisterOverwriteExisting(
|
||||
"CrewManagement.UpdateLocationView".ToIdentifier(),
|
||||
(locationChangeInfo) => UpdateLocationView(locationChangeInfo.NewLocation, true, locationChangeInfo.PrevLocation));
|
||||
Reputation.OnAnyReputationValueChanged.RegisterOverwriteExisting(
|
||||
"CrewManagement.UpdateLocationView".ToIdentifier(), _ => needsHireableRefresh = true);
|
||||
}
|
||||
|
||||
public void RefreshPermissions()
|
||||
@@ -68,7 +71,13 @@ namespace Barotrauma
|
||||
{
|
||||
if (child.FindChild(c => c is GUIButton && c.UserData is CharacterInfo, true) is GUIButton buyButton)
|
||||
{
|
||||
buyButton.Enabled = HasPermission;
|
||||
CharacterInfo characterInfo = buyButton.UserData as CharacterInfo;
|
||||
bool enoughReputationToHire = EnoughReputationToHire(characterInfo);
|
||||
buyButton.Enabled = HasPermission && enoughReputationToHire;
|
||||
foreach (GUITextBlock text in child.GetAllChildren<GUITextBlock>())
|
||||
{
|
||||
text.TextColor = new Color(text.TextColor, buyButton.Enabled ? 1.0f : 0.6f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -294,18 +303,21 @@ namespace Barotrauma
|
||||
if (sortingMethod == SortingMethod.AlphabeticalAsc)
|
||||
{
|
||||
list.Content.RectTransform.SortChildren((x, y) =>
|
||||
CompareReputationRequirement(x.GUIComponent, y.GUIComponent) ??
|
||||
((InfoSkill)x.GUIComponent.UserData).CharacterInfo.Name.CompareTo(((InfoSkill)y.GUIComponent.UserData).CharacterInfo.Name));
|
||||
}
|
||||
else if (sortingMethod == SortingMethod.JobAsc)
|
||||
{
|
||||
SortCharacters(list, SortingMethod.AlphabeticalAsc);
|
||||
list.Content.RectTransform.SortChildren((x, y) =>
|
||||
String.Compare(((InfoSkill)x.GUIComponent.UserData).CharacterInfo.Job.Name.Value, ((InfoSkill)y.GUIComponent.UserData).CharacterInfo.Job.Name.Value, StringComparison.Ordinal));
|
||||
CompareReputationRequirement(x.GUIComponent, y.GUIComponent) ??
|
||||
string.Compare(((InfoSkill)x.GUIComponent.UserData).CharacterInfo.Job.Name.Value, ((InfoSkill)y.GUIComponent.UserData).CharacterInfo.Job.Name.Value, StringComparison.Ordinal));
|
||||
}
|
||||
else if (sortingMethod == SortingMethod.PriceAsc || sortingMethod == SortingMethod.PriceDesc)
|
||||
{
|
||||
SortCharacters(list, SortingMethod.AlphabeticalAsc);
|
||||
list.Content.RectTransform.SortChildren((x, y) =>
|
||||
CompareReputationRequirement(x.GUIComponent, y.GUIComponent) ??
|
||||
((InfoSkill)x.GUIComponent.UserData).CharacterInfo.Salary.CompareTo(((InfoSkill)y.GUIComponent.UserData).CharacterInfo.Salary));
|
||||
if (sortingMethod == SortingMethod.PriceDesc) { list.Content.RectTransform.ReverseChildren(); }
|
||||
}
|
||||
@@ -313,9 +325,26 @@ namespace Barotrauma
|
||||
{
|
||||
SortCharacters(list, SortingMethod.AlphabeticalAsc);
|
||||
list.Content.RectTransform.SortChildren((x, y) =>
|
||||
CompareReputationRequirement(x.GUIComponent, y.GUIComponent) ??
|
||||
((InfoSkill)x.GUIComponent.UserData).SkillLevel.CompareTo(((InfoSkill)y.GUIComponent.UserData).SkillLevel));
|
||||
if (sortingMethod == SortingMethod.SkillDesc) { list.Content.RectTransform.ReverseChildren(); }
|
||||
}
|
||||
|
||||
int? CompareReputationRequirement(GUIComponent c1, GUIComponent c2)
|
||||
{
|
||||
CharacterInfo info1 = ((InfoSkill)c1.UserData).CharacterInfo;
|
||||
CharacterInfo info2 = ((InfoSkill)c2.UserData).CharacterInfo;
|
||||
float requirement1 = EnoughReputationToHire(info1) ? 0 : info1.MinReputationToHire.reputation;
|
||||
float requirement2 = EnoughReputationToHire(info2) ? 0 : info2.MinReputationToHire.reputation;
|
||||
if (MathUtils.NearlyEqual(requirement1, 0.0f) && MathUtils.NearlyEqual(requirement2, 0.0f))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
return requirement1.CompareTo(requirement2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private readonly struct InfoSkill
|
||||
@@ -367,12 +396,25 @@ namespace Barotrauma
|
||||
nameBlock.Text = ToolBox.LimitString(nameBlock.Text, nameBlock.Font, nameBlock.Rect.Width);
|
||||
|
||||
GUITextBlock jobBlock = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.5f), nameAndJobGroup.RectTransform),
|
||||
characterInfo.Job.Name, textColor: Color.White, font: GUIStyle.SmallFont, textAlignment: Alignment.TopLeft)
|
||||
characterInfo.Title ?? characterInfo.Job.Name, textColor: Color.White, font: GUIStyle.SmallFont, textAlignment: Alignment.TopLeft)
|
||||
{
|
||||
CanBeFocused = false
|
||||
};
|
||||
jobBlock.Text = ToolBox.LimitString(jobBlock.Text, jobBlock.Font, jobBlock.Rect.Width);
|
||||
|
||||
if (!characterInfo.MinReputationToHire.factionId.IsEmpty)
|
||||
{
|
||||
var faction = campaign.Factions.Find(f => f.Prefab.Identifier == characterInfo.MinReputationToHire.factionId);
|
||||
if (faction != null)
|
||||
{
|
||||
jobBlock.TextColor = faction.Prefab.IconColor;
|
||||
}
|
||||
}
|
||||
var fullJobText = jobBlock.Text;
|
||||
jobBlock.Text = ToolBox.LimitString(fullJobText, jobBlock.Font, jobBlock.Rect.Width);
|
||||
if (jobBlock.Text != fullJobText)
|
||||
{
|
||||
jobBlock.ToolTip = fullJobText;
|
||||
jobBlock.CanBeFocused = true;
|
||||
}
|
||||
float width = 0.6f / 3;
|
||||
if (characterInfo.Job != null && skill != null)
|
||||
{
|
||||
@@ -410,7 +452,7 @@ namespace Barotrauma
|
||||
{
|
||||
ClickSound = GUISoundType.Cart,
|
||||
UserData = characterInfo,
|
||||
Enabled = HasPermission,
|
||||
Enabled = CanHire(characterInfo),
|
||||
OnClicked = (b, o) => AddPendingHire(o as CharacterInfo)
|
||||
};
|
||||
hireButton.OnAddedToGUIUpdateList += (GUIComponent btn) =>
|
||||
@@ -426,10 +468,9 @@ namespace Barotrauma
|
||||
else if (!btn.Enabled)
|
||||
{
|
||||
btn.ToolTip = string.Empty;
|
||||
btn.Enabled = HasPermission;
|
||||
btn.Enabled = CanHire(characterInfo);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
else if (listBox == pendingList)
|
||||
{
|
||||
@@ -437,7 +478,7 @@ namespace Barotrauma
|
||||
{
|
||||
ClickSound = GUISoundType.Cart,
|
||||
UserData = characterInfo,
|
||||
Enabled = HasPermission,
|
||||
Enabled = CanHire(characterInfo),
|
||||
OnClicked = (b, o) => RemovePendingHire(o as CharacterInfo)
|
||||
};
|
||||
}
|
||||
@@ -474,12 +515,30 @@ namespace Barotrauma
|
||||
size = new Point(3 * mainGroup.AbsoluteSpacing + icon.Rect.Width + nameAndJobGroup.Rect.Width, mainGroup.Rect.Height);
|
||||
new GUIButton(new RectTransform(size, frame.RectTransform) { RelativeOffset = new Vector2(0.025f) }, style: null)
|
||||
{
|
||||
Enabled = HasPermission,
|
||||
Enabled = CanHire(characterInfo),
|
||||
ToolTip = TextManager.GetWithVariable("campaigncrew.givenicknametooltip", "[mouseprimary]", TextManager.Get($"input.{(PlayerInput.MouseButtonsSwapped() ? "rightmouse" : "leftmouse")}")),
|
||||
UserData = characterInfo,
|
||||
OnClicked = CreateRenamingComponent
|
||||
};
|
||||
}
|
||||
|
||||
bool CanHire(CharacterInfo characterInfo)
|
||||
{
|
||||
if (!HasPermission) { return false; }
|
||||
return EnoughReputationToHire(characterInfo);
|
||||
}
|
||||
}
|
||||
|
||||
private bool EnoughReputationToHire(CharacterInfo characterInfo)
|
||||
{
|
||||
if (characterInfo.MinReputationToHire.factionId != Identifier.Empty)
|
||||
{
|
||||
if (campaign.GetReputation(characterInfo.MinReputationToHire.factionId) < characterInfo.MinReputationToHire.reputation)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void CreateCharacterPreviewFrame(GUIListBox listBox, GUIFrame characterFrame, CharacterInfo characterInfo)
|
||||
@@ -488,13 +547,13 @@ namespace Barotrauma
|
||||
Point absoluteOffset = new Point(
|
||||
pivot == Pivot.TopLeft ? listBox.Parent.Parent.Rect.Right + 5 : listBox.Parent.Parent.Rect.Left - 5,
|
||||
characterFrame.Rect.Top);
|
||||
int frameSize = (int)(GUI.Scale * 300);
|
||||
if (GameMain.GraphicsHeight - (absoluteOffset.Y + frameSize) < 0)
|
||||
Point frameSize = new Point(GUI.IntScale(300), GUI.IntScale(350));
|
||||
if (GameMain.GraphicsHeight - (absoluteOffset.Y + frameSize.Y) < 0)
|
||||
{
|
||||
pivot = listBox == hireableList ? Pivot.BottomLeft : Pivot.BottomRight;
|
||||
absoluteOffset.Y = characterFrame.Rect.Bottom;
|
||||
}
|
||||
characterPreviewFrame = new GUIFrame(new RectTransform(new Point(frameSize), parent: campaignUI.GetTabContainer(CampaignMode.InteractionType.Crew).Parent.RectTransform, pivot: pivot)
|
||||
characterPreviewFrame = new GUIFrame(new RectTransform(frameSize, parent: campaignUI.GetTabContainer(CampaignMode.InteractionType.Crew).Parent.RectTransform, pivot: pivot)
|
||||
{
|
||||
AbsoluteOffset = absoluteOffset
|
||||
}, style: "InnerFrame")
|
||||
@@ -503,7 +562,8 @@ namespace Barotrauma
|
||||
};
|
||||
GUILayoutGroup mainGroup = new GUILayoutGroup(new RectTransform(new Vector2(0.95f), characterPreviewFrame.RectTransform, anchor: Anchor.Center))
|
||||
{
|
||||
RelativeSpacing = 0.01f
|
||||
RelativeSpacing = 0.01f,
|
||||
Stretch = true
|
||||
};
|
||||
|
||||
// Character info
|
||||
@@ -545,9 +605,23 @@ namespace Barotrauma
|
||||
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));
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, blockHeight), skillNameGroup.RectTransform), TextManager.Get("SkillName." + skill.Identifier), font: GUIStyle.SmallFont);
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, blockHeight), skillLevelGroup.RectTransform), ((int)skill.Level).ToString(), textAlignment: Alignment.Right);
|
||||
}
|
||||
|
||||
if (characterInfo.MinReputationToHire.reputation > 0.0f)
|
||||
{
|
||||
var repStr = TextManager.GetWithVariables(
|
||||
"campaignstore.reputationrequired",
|
||||
("[amount]", ((int)characterInfo.MinReputationToHire.reputation).ToString()),
|
||||
("[faction]", TextManager.Get("faction." + characterInfo.MinReputationToHire.factionId).Value));
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), mainGroup.RectTransform),
|
||||
repStr, textColor: !EnoughReputationToHire(characterInfo) ? GUIStyle.Orange : GUIStyle.Green,
|
||||
font: GUIStyle.SmallFont, wrap: true, textAlignment: Alignment.Center);
|
||||
}
|
||||
mainGroup.Recalculate();
|
||||
characterPreviewFrame.RectTransform.MinSize =
|
||||
new Point(0, (int)(mainGroup.Children.Sum(c => c.Rect.Height + mainGroup.Rect.Height * mainGroup.RelativeSpacing) / mainGroup.RectTransform.RelativeSize.Y));
|
||||
}
|
||||
|
||||
private bool SelectCharacter(GUIListBox listBox, GUIFrame characterFrame, CharacterInfo characterInfo)
|
||||
@@ -636,7 +710,7 @@ namespace Barotrauma
|
||||
List<CharacterInfo> nonDuplicateHires = new List<CharacterInfo>();
|
||||
hires.ForEach(hireInfo =>
|
||||
{
|
||||
if(campaign.CrewManager.GetCharacterInfos().None(crewInfo => crewInfo.IsNewHire && crewInfo.GetIdentifierUsingOriginalName() == hireInfo.GetIdentifierUsingOriginalName()))
|
||||
if (campaign.CrewManager.GetCharacterInfos().None(crewInfo => crewInfo.IsNewHire && crewInfo.GetIdentifierUsingOriginalName() == hireInfo.GetIdentifierUsingOriginalName()))
|
||||
{
|
||||
nonDuplicateHires.Add(hireInfo);
|
||||
}
|
||||
@@ -791,6 +865,16 @@ namespace Barotrauma
|
||||
playerBalanceElement = CampaignUI.UpdateBalanceElement(playerBalanceElement);
|
||||
}
|
||||
|
||||
if (needsHireableRefresh)
|
||||
{
|
||||
RefreshCrewFrames(hireableList);
|
||||
if (sortingDropDown?.SelectedItemData != null)
|
||||
{
|
||||
SortCharacters(hireableList, (SortingMethod)sortingDropDown.SelectedItemData);
|
||||
}
|
||||
needsHireableRefresh = false;
|
||||
}
|
||||
|
||||
(GUIComponent highlightedFrame, CharacterInfo highlightedInfo) = FindHighlightedCharacter(GUI.MouseOn);
|
||||
if (highlightedFrame != null && highlightedInfo != null)
|
||||
{
|
||||
|
||||
@@ -357,6 +357,17 @@ namespace Barotrauma
|
||||
string txt = directory;
|
||||
if (txt.StartsWith(currentDirectory)) { txt = txt.Substring(currentDirectory.Length); }
|
||||
if (!txt.EndsWith("/")) { txt += "/"; }
|
||||
//get directory info
|
||||
DirectoryInfo dirInfo = new DirectoryInfo(directory);
|
||||
try
|
||||
{
|
||||
//this will throw an exception if the directory can't be opened
|
||||
Directory.GetDirectories(directory);
|
||||
}
|
||||
catch (UnauthorizedAccessException)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
var itemFrame = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), fileList.Content.RectTransform), txt)
|
||||
{
|
||||
UserData = ItemIsDirectory.Yes
|
||||
|
||||
@@ -3,7 +3,6 @@ using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using Barotrauma.IO;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
using Barotrauma.CharacterEditor;
|
||||
using Barotrauma.Extensions;
|
||||
using Barotrauma.Items.Components;
|
||||
@@ -50,6 +49,14 @@ namespace Barotrauma
|
||||
|
||||
static class GUI
|
||||
{
|
||||
// Controls where a line is drawn for given coords.
|
||||
public enum OutlinePosition
|
||||
{
|
||||
Default = 0, // Thickness is inside of top left and outside of bottom right coord
|
||||
Inside = 1, // Thickness is subtracted from the inside
|
||||
Centered = 2, // Thickness is centered on given coords
|
||||
Outside = 3, // Tickness is added to the outside
|
||||
}
|
||||
public static GUICanvas Canvas => GUICanvas.Instance;
|
||||
public static CursorState MouseCursor = CursorState.Default;
|
||||
|
||||
@@ -133,13 +140,20 @@ namespace Barotrauma
|
||||
public static Texture2D WhiteTexture => solidWhiteTexture;
|
||||
private static GUICursor MouseCursorSprites => GUIStyle.CursorSprite;
|
||||
|
||||
private static bool debugDrawSounds, debugDrawEvents, debugDrawMetadata;
|
||||
private static int debugDrawMetadataOffset;
|
||||
private static readonly string[] ignoredMetadataInfo = { string.Empty, string.Empty, string.Empty, string.Empty };
|
||||
private static bool debugDrawSounds, debugDrawEvents;
|
||||
|
||||
private static DebugDrawMetaData debugDrawMetaData;
|
||||
|
||||
public struct DebugDrawMetaData
|
||||
{
|
||||
public bool Enabled;
|
||||
public bool FactionMetadata, UpgradeLevels, UpgradePrices;
|
||||
public int Offset;
|
||||
}
|
||||
|
||||
public static GraphicsDevice GraphicsDevice => GameMain.Instance.GraphicsDevice;
|
||||
|
||||
private static List<GUIMessage> messages = new List<GUIMessage>();
|
||||
private static readonly List<GUIMessage> messages = new List<GUIMessage>();
|
||||
|
||||
public static GUIFrame PauseMenu { get; private set; }
|
||||
public static GUIFrame SettingsMenuContainer { get; private set; }
|
||||
@@ -188,8 +202,9 @@ namespace Barotrauma
|
||||
SettingsMenuOpen ||
|
||||
DebugConsole.IsOpen ||
|
||||
GameSession.IsTabMenuOpen ||
|
||||
(GameMain.GameSession?.GameMode?.Paused ?? false) ||
|
||||
CharacterHUD.IsCampaignInterfaceOpen;
|
||||
GameMain.GameSession?.GameMode is { Paused: true } ||
|
||||
CharacterHUD.IsCampaignInterfaceOpen ||
|
||||
GameMain.GameSession?.Campaign is { SlideshowPlayer: { Finished: false, Visible: true } };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -248,7 +263,17 @@ namespace Barotrauma
|
||||
ScreenChanged = false;
|
||||
}
|
||||
|
||||
updateList.ForEach(c => c.DrawAuto(spriteBatch));
|
||||
foreach (GUIComponent c in updateList)
|
||||
{
|
||||
c.DrawAuto(spriteBatch);
|
||||
}
|
||||
|
||||
// always draw IME preview on top of everything else
|
||||
foreach (GUIComponent c in updateList)
|
||||
{
|
||||
if (c is not GUITextBox box) { continue; }
|
||||
box.DrawIMEPreview(spriteBatch);
|
||||
}
|
||||
|
||||
if (ScreenOverlayColor.A > 0.0f)
|
||||
{
|
||||
@@ -516,18 +541,17 @@ namespace Barotrauma
|
||||
if (GameMain.GameSession?.GameMode is CampaignMode campaignMode)
|
||||
{
|
||||
// TODO: TEST THIS
|
||||
if (debugDrawMetadata)
|
||||
if (debugDrawMetaData.Enabled)
|
||||
{
|
||||
string text = "Ctrl+M to hide campaign metadata debug info\n\n" +
|
||||
$"Ctrl+1 to {(string.IsNullOrWhiteSpace(ignoredMetadataInfo[0]) ? "hide" : "show")} outpost reputations, \n" +
|
||||
$"Ctrl+2 to {(string.IsNullOrWhiteSpace(ignoredMetadataInfo[1]) ? "hide" : "show")} faction reputations, \n" +
|
||||
$"Ctrl+3 to {(string.IsNullOrWhiteSpace(ignoredMetadataInfo[2]) ? "hide" : "show")} upgrade levels, \n" +
|
||||
$"Ctrl+4 to {(string.IsNullOrWhiteSpace(ignoredMetadataInfo[3]) ? "hide" : "show")} upgrade prices";
|
||||
$"Ctrl+1 to {(debugDrawMetaData.FactionMetadata ? "hide" : "show")} faction reputations, \n" +
|
||||
$"Ctrl+2 to {(debugDrawMetaData.UpgradeLevels ? "hide" : "show")} upgrade levels, \n" +
|
||||
$"Ctrl+3 to {(debugDrawMetaData.UpgradePrices ? "hide" : "show")} upgrade prices";
|
||||
Vector2 textSize = GUIStyle.SmallFont.MeasureString(text);
|
||||
Vector2 pos = new Vector2(GameMain.GraphicsWidth - (textSize.X + 10), 300);
|
||||
DrawString(spriteBatch, pos, text, Color.White, Color.Black * 0.5f, 0, GUIStyle.SmallFont);
|
||||
pos.Y += textSize.Y + 8;
|
||||
campaignMode.CampaignMetadata?.DebugDraw(spriteBatch, pos, debugDrawMetadataOffset, ignoredMetadataInfo);
|
||||
campaignMode.CampaignMetadata?.DebugDraw(spriteBatch, pos, campaignMode, debugDrawMetaData);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -582,6 +606,10 @@ namespace Barotrauma
|
||||
|
||||
GameMain.Client?.Draw(spriteBatch);
|
||||
|
||||
string factionWaterMark = "FACTION/ENDGAME TEST VERSION - please do not publicly share any material you see here!".ToUpper();
|
||||
DrawString(spriteBatch, new Vector2(GameMain.GraphicsWidth / 2, 100 * yScale) - GUIStyle.SubHeadingFont.MeasureString(factionWaterMark) / 2, factionWaterMark,
|
||||
GUIStyle.Red * 0.5f, font: GUIStyle.SubHeadingFont, backgroundColor: Color.Black * 0.5f, backgroundPadding: 10);
|
||||
|
||||
if (Character.Controlled?.Inventory != null)
|
||||
{
|
||||
if (Character.Controlled.Stun < 0.1f && !Character.Controlled.IsDead)
|
||||
@@ -667,21 +695,8 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public static void DrawBackgroundSprite(SpriteBatch spriteBatch, Sprite backgroundSprite, float aberrationStrength = 1.0f)
|
||||
public static void DrawBackgroundSprite(SpriteBatch spriteBatch, Sprite backgroundSprite, Color color)
|
||||
{
|
||||
double aberrationT = (Timing.TotalTime * 0.5f);
|
||||
GameMain.GameScreen.PostProcessEffect.Parameters["blurDistance"].SetValue(0.001f * aberrationStrength);
|
||||
GameMain.GameScreen.PostProcessEffect.Parameters["chromaticAberrationStrength"].SetValue(new Vector3(-0.025f, -0.01f, -0.05f) *
|
||||
(float)(PerlinNoise.CalculatePerlin(aberrationT, aberrationT, 0) + 0.5f) * aberrationStrength);
|
||||
|
||||
Matrix.CreateOrthographicOffCenter(0, GameMain.GraphicsWidth, GameMain.GraphicsHeight, 0, 0, -1, out Matrix projection);
|
||||
|
||||
GameMain.GameScreen.PostProcessEffect.Parameters["MatrixTransform"].SetValue(projection);
|
||||
GameMain.GameScreen.PostProcessEffect.CurrentTechnique = GameMain.GameScreen.PostProcessEffect.Techniques["BlurChromaticAberration"];
|
||||
GameMain.GameScreen.PostProcessEffect.CurrentTechnique.Passes[0].Apply();
|
||||
|
||||
spriteBatch.Begin(SpriteSortMode.Immediate, effect: GameMain.GameScreen.PostProcessEffect);
|
||||
|
||||
float scale = Math.Max(
|
||||
(float)GameMain.GraphicsWidth / backgroundSprite.SourceRect.Width,
|
||||
(float)GameMain.GraphicsHeight / backgroundSprite.SourceRect.Height) * 1.1f;
|
||||
@@ -694,10 +709,8 @@ namespace Barotrauma
|
||||
|
||||
spriteBatch.Draw(backgroundSprite.Texture,
|
||||
new Vector2(GameMain.GraphicsWidth, GameMain.GraphicsHeight) / 2 + pos,
|
||||
null, Color.White, 0.0f, backgroundSprite.size / 2,
|
||||
null, color, 0.0f, backgroundSprite.size / 2,
|
||||
scale, SpriteEffects.None, 0.0f);
|
||||
|
||||
spriteBatch.End();
|
||||
}
|
||||
|
||||
#region Update list
|
||||
@@ -1189,48 +1202,37 @@ namespace Barotrauma
|
||||
}
|
||||
if (PlayerInput.IsCtrlDown() && PlayerInput.KeyHit(Keys.M))
|
||||
{
|
||||
debugDrawMetadata = !debugDrawMetadata;
|
||||
debugDrawMetaData.Enabled = !debugDrawMetaData.Enabled;
|
||||
}
|
||||
|
||||
if (debugDrawMetadata)
|
||||
if (debugDrawMetaData.Enabled)
|
||||
{
|
||||
if (PlayerInput.KeyHit(Keys.Up))
|
||||
{
|
||||
debugDrawMetadataOffset--;
|
||||
debugDrawMetaData.Offset--;
|
||||
}
|
||||
|
||||
if (PlayerInput.KeyHit(Keys.Down))
|
||||
{
|
||||
debugDrawMetadataOffset++;
|
||||
debugDrawMetaData.Offset++;
|
||||
}
|
||||
|
||||
if (PlayerInput.IsCtrlDown())
|
||||
{
|
||||
if (PlayerInput.KeyHit(Keys.D1))
|
||||
{
|
||||
ignoredMetadataInfo[0] = ignoredMetadataInfo[0] == string.Empty ? "reputation.location" : string.Empty;
|
||||
debugDrawMetadataOffset = 0;
|
||||
debugDrawMetaData.FactionMetadata = !debugDrawMetaData.FactionMetadata;
|
||||
debugDrawMetaData.Offset = 0;
|
||||
}
|
||||
|
||||
if (PlayerInput.KeyHit(Keys.D2))
|
||||
{
|
||||
ignoredMetadataInfo[1] = ignoredMetadataInfo[1] == string.Empty ? "reputation.faction" : string.Empty;
|
||||
debugDrawMetadataOffset = 0;
|
||||
debugDrawMetaData.UpgradeLevels = !debugDrawMetaData.UpgradeLevels;
|
||||
debugDrawMetaData.Offset = 0;
|
||||
}
|
||||
|
||||
if (PlayerInput.KeyHit(Keys.D3))
|
||||
{
|
||||
ignoredMetadataInfo[2] = ignoredMetadataInfo[2] == string.Empty ? "upgrade." : string.Empty;
|
||||
debugDrawMetadataOffset = 0;
|
||||
}
|
||||
|
||||
if (PlayerInput.KeyHit(Keys.D4))
|
||||
{
|
||||
ignoredMetadataInfo[3] = ignoredMetadataInfo[3] == string.Empty ? "upgradeprice." : string.Empty;
|
||||
debugDrawMetadataOffset = 0;
|
||||
debugDrawMetaData.UpgradePrices = !debugDrawMetaData.UpgradePrices;
|
||||
debugDrawMetaData.Offset = 0;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
HandlePersistingElements(deltaTime);
|
||||
@@ -1244,6 +1246,10 @@ namespace Barotrauma
|
||||
UpdateMessages(deltaTime);
|
||||
UpdateSavingIndicator(deltaTime);
|
||||
}
|
||||
|
||||
#if WINDOWS
|
||||
GUITextBox.UpdateIME();
|
||||
#endif
|
||||
}
|
||||
|
||||
public static void UpdateGUIMessageBoxesOnly(float deltaTime)
|
||||
@@ -1350,7 +1356,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
#region Element drawing
|
||||
#region Element drawing
|
||||
|
||||
private static readonly List<float> usedIndicatorAngles = new List<float>();
|
||||
|
||||
@@ -1605,6 +1611,54 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public static void DrawRectangle(SpriteBatch sb, Vector2 position, Vector2 size, Vector2 origin, float rotation, Color clr, float depth = 0.0f, float thickness = 1, OutlinePosition outlinePos = OutlinePosition.Centered)
|
||||
{
|
||||
Vector2 topLeft = new Vector2(-origin.X, -origin.Y);
|
||||
Vector2 topRight = new Vector2(-origin.X + size.X, -origin.Y);
|
||||
Vector2 bottomLeft = new Vector2(-origin.X, -origin.Y + size.Y);
|
||||
Vector2 actualSize = size;
|
||||
|
||||
switch(outlinePos)
|
||||
{
|
||||
case OutlinePosition.Default:
|
||||
actualSize += new Vector2(thickness);
|
||||
break;
|
||||
case OutlinePosition.Centered:
|
||||
topLeft -= new Vector2(thickness * 0.5f);
|
||||
topRight -= new Vector2(thickness * 0.5f);
|
||||
bottomLeft -= new Vector2(thickness * 0.5f);
|
||||
actualSize += new Vector2(thickness);
|
||||
break;
|
||||
case OutlinePosition.Inside:
|
||||
topRight -= new Vector2(thickness, 0.0f);
|
||||
bottomLeft -= new Vector2(0.0f, thickness);
|
||||
break;
|
||||
case OutlinePosition.Outside:
|
||||
topLeft -= new Vector2(thickness);
|
||||
topRight -= new Vector2(0.0f, thickness);
|
||||
bottomLeft -= new Vector2(thickness, 0.0f);
|
||||
actualSize += new Vector2(thickness * 2.0f);
|
||||
break;
|
||||
}
|
||||
|
||||
Matrix rotate = Matrix.CreateRotationZ(rotation);
|
||||
topLeft = Vector2.Transform(topLeft, rotate) + position;
|
||||
topRight = Vector2.Transform(topRight, rotate) + position;
|
||||
bottomLeft = Vector2.Transform(bottomLeft, rotate) + position;
|
||||
|
||||
Rectangle srcRect = new Rectangle(0, 0, 1, 1);
|
||||
sb.Draw(solidWhiteTexture, topLeft, srcRect, clr, rotation, Vector2.Zero, new Vector2(thickness, actualSize.Y), SpriteEffects.None, depth);
|
||||
sb.Draw(solidWhiteTexture, topLeft, srcRect, clr, rotation, Vector2.Zero, new Vector2(actualSize.X, thickness), SpriteEffects.None, depth);
|
||||
sb.Draw(solidWhiteTexture, topRight, srcRect, clr, rotation, Vector2.Zero, new Vector2(thickness, actualSize.Y), SpriteEffects.None, depth);
|
||||
sb.Draw(solidWhiteTexture, bottomLeft, srcRect, clr, rotation, Vector2.Zero, new Vector2(actualSize.X, thickness), SpriteEffects.None, depth);
|
||||
}
|
||||
|
||||
public static void DrawFilledRectangle(SpriteBatch sb, Vector2 position, Vector2 size, Vector2 pivot, float rotation, Color clr, float depth = 0.0f)
|
||||
{
|
||||
Rectangle srcRect = new Rectangle(0, 0, 1, 1);
|
||||
sb.Draw(solidWhiteTexture, position, srcRect, clr, rotation, (pivot/size), size, SpriteEffects.None, depth);
|
||||
}
|
||||
|
||||
public static void DrawFilledRectangle(SpriteBatch sb, RectangleF rect, Color clr, float depth = 0.0f)
|
||||
{
|
||||
DrawFilledRectangle(sb, rect.Location, rect.Size, clr, depth);
|
||||
@@ -1788,9 +1842,9 @@ namespace Barotrauma
|
||||
Vector2 pos = new Vector2(GameMain.GraphicsWidth, GameMain.GraphicsHeight) - new Vector2(HUDLayoutSettings.Padding) - 2 * Scale * sheet.FrameSize.ToVector2();
|
||||
sheet.Draw(spriteBatch, (int)Math.Floor(savingIndicatorSpriteIndex), pos, savingIndicatorColor, origin: Vector2.Zero, rotate: 0.0f, scale: new Vector2(Scale));
|
||||
}
|
||||
#endregion
|
||||
#endregion
|
||||
|
||||
#region Element creation
|
||||
#region Element creation
|
||||
|
||||
public static Texture2D CreateCircle(int radius, bool filled = false)
|
||||
{
|
||||
@@ -2162,9 +2216,9 @@ namespace Barotrauma
|
||||
return msgBox;
|
||||
}
|
||||
|
||||
#endregion
|
||||
#endregion
|
||||
|
||||
#region Element positioning
|
||||
#region Element positioning
|
||||
private static List<T> CreateElements<T>(int count, RectTransform parent, Func<RectTransform, T> constructor,
|
||||
Vector2? relativeSize = null, Point? absoluteSize = null,
|
||||
Anchor anchor = Anchor.TopLeft, Pivot? pivot = null, Point? minSize = null, Point? maxSize = null,
|
||||
@@ -2363,9 +2417,9 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
#endregion
|
||||
|
||||
#region Misc
|
||||
#region Misc
|
||||
public static void TogglePauseMenu()
|
||||
{
|
||||
if (Screen.Selected == GameMain.MainMenuScreen) { return; }
|
||||
@@ -2603,6 +2657,6 @@ namespace Barotrauma
|
||||
if (!isSavingIndicatorEnabled) { return; }
|
||||
timeUntilSavingIndicatorDisabled = delay;
|
||||
}
|
||||
#endregion
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ using Barotrauma.IO;
|
||||
using RestSharp;
|
||||
using System.Net;
|
||||
using System.Collections.Immutable;
|
||||
using Barotrauma.Tutorials;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
@@ -736,7 +737,7 @@ namespace Barotrauma
|
||||
|
||||
public static void DrawToolTip(SpriteBatch spriteBatch, RichString toolTip, Vector2 pos)
|
||||
{
|
||||
if (GameMain.GameSession?.GameMode is TutorialMode tutorialMode && tutorialMode.Tutorial.ContentRunning) { return; }
|
||||
if (ObjectiveManager.ContentRunning) { return; }
|
||||
|
||||
int width = (int)(400 * GUI.Scale);
|
||||
int height = (int)(18 * GUI.Scale);
|
||||
@@ -759,7 +760,7 @@ namespace Barotrauma
|
||||
|
||||
public static void DrawToolTip(SpriteBatch spriteBatch, RichString toolTip, Rectangle targetElement)
|
||||
{
|
||||
if (GameMain.GameSession?.GameMode is TutorialMode tutorialMode && tutorialMode.Tutorial.ContentRunning) { return; }
|
||||
if (ObjectiveManager.ContentRunning) { return; }
|
||||
|
||||
int width = (int)(400 * GUI.Scale);
|
||||
int height = (int)(18 * GUI.Scale);
|
||||
|
||||
@@ -112,6 +112,10 @@ namespace Barotrauma
|
||||
public void ReceiveTextInput(string text) { }
|
||||
public void ReceiveCommandInput(char command) { }
|
||||
|
||||
#if !WINDOWS
|
||||
public void ReceiveEditingInput(string text, int start) { }
|
||||
#endif
|
||||
|
||||
public void ReceiveSpecialInput(Keys key)
|
||||
{
|
||||
switch (key)
|
||||
|
||||
@@ -1349,6 +1349,10 @@ namespace Barotrauma
|
||||
public void ReceiveTextInput(string text) { }
|
||||
public void ReceiveCommandInput(char command) { }
|
||||
|
||||
#if !WINDOWS
|
||||
public void ReceiveEditingInput(string text, int start) { }
|
||||
#endif
|
||||
|
||||
public void ReceiveSpecialInput(Keys key)
|
||||
{
|
||||
switch (key)
|
||||
|
||||
@@ -24,7 +24,8 @@ namespace Barotrauma
|
||||
InGame,
|
||||
Vote,
|
||||
Hint,
|
||||
Tutorial
|
||||
Tutorial,
|
||||
Warning // Keep this last so that it's always drawn in front
|
||||
}
|
||||
|
||||
private bool IsAnimated => type == Type.InGame || type == Type.Hint || type == Type.Tutorial;
|
||||
@@ -84,8 +85,8 @@ namespace Barotrauma
|
||||
|
||||
public static GUIComponent VisibleBox => MessageBoxes.LastOrDefault();
|
||||
|
||||
public GUIMessageBox(LocalizedString headerText, LocalizedString text, Vector2? relativeSize = null, Point? minSize = null)
|
||||
: this(headerText, text, new LocalizedString[] { "OK" }, relativeSize, minSize)
|
||||
public GUIMessageBox(LocalizedString headerText, LocalizedString text, Vector2? relativeSize = null, Point? minSize = null, Type type = Type.Default)
|
||||
: this(headerText, text, new LocalizedString[] { "OK" }, relativeSize, minSize, type: type)
|
||||
{
|
||||
this.Buttons[0].OnClicked = Close;
|
||||
}
|
||||
@@ -147,7 +148,7 @@ namespace Barotrauma
|
||||
Tag = tag.ToIdentifier();
|
||||
|
||||
#warning TODO: These should be broken into separate methods at least
|
||||
if (type == Type.Default || type == Type.Vote)
|
||||
if (type == Type.Default || type == Type.Vote || type == Type.Warning)
|
||||
{
|
||||
Content = new GUILayoutGroup(new RectTransform(new Vector2(0.9f, 0.85f), InnerFrame.RectTransform, Anchor.Center)) { AbsoluteSpacing = 5 };
|
||||
|
||||
@@ -266,7 +267,7 @@ namespace Barotrauma
|
||||
Buttons.Clear();
|
||||
}
|
||||
|
||||
Header = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), Content.RectTransform), headerText, wrap: true);
|
||||
Header = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), Content.RectTransform), headerText, wrap: true, textColor: GUIStyle.TextColorBright);
|
||||
GUIStyle.Apply(Header, "", this);
|
||||
Header.RectTransform.MinSize = new Point(0, Header.Rect.Height);
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ using Microsoft.Xna.Framework.Graphics;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
@@ -285,8 +286,8 @@ namespace Barotrauma
|
||||
/// This is the new constructor.
|
||||
/// If the rectT height is set 0, the height is calculated from the text.
|
||||
/// </summary>
|
||||
public GUITextBlock(RectTransform rectT, RichString text, Color? textColor = null, GUIFont font = null,
|
||||
Alignment textAlignment = Alignment.Left, bool wrap = false, string style = "", Color? color = null)
|
||||
public GUITextBlock(RectTransform rectT, RichString text, Color? textColor = null, GUIFont font = null,
|
||||
Alignment textAlignment = Alignment.Left, bool wrap = false, string style = "", Color? color = null)
|
||||
: base(style, rectT)
|
||||
{
|
||||
if (color.HasValue)
|
||||
@@ -551,6 +552,8 @@ namespace Barotrauma
|
||||
|
||||
if (TextGetter != null) { Text = TextGetter(); }
|
||||
|
||||
string textToShow = Censor ? censoredText : (Wrap ? wrappedText.Value : text.SanitizedValue);
|
||||
|
||||
Rectangle prevScissorRect = spriteBatch.GraphicsDevice.ScissorRectangle;
|
||||
if (overflowClipActive)
|
||||
{
|
||||
@@ -561,7 +564,7 @@ namespace Barotrauma
|
||||
spriteBatch.Begin(SpriteSortMode.Deferred, samplerState: GUI.SamplerState, rasterizerState: GameMain.ScissorTestEnable);
|
||||
}
|
||||
|
||||
if (!text.IsNullOrEmpty())
|
||||
if (!string.IsNullOrEmpty(textToShow))
|
||||
{
|
||||
Vector2 pos = rect.Location.ToVector2() + textPos + TextOffset;
|
||||
if (RoundToNearestPixel)
|
||||
@@ -570,7 +573,8 @@ namespace Barotrauma
|
||||
pos.Y = (int)pos.Y;
|
||||
}
|
||||
|
||||
Color currentTextColor = State == ComponentState.Hover || State == ComponentState.HoverSelected ? HoverTextColor : TextColor;
|
||||
Color currentTextColor = State is ComponentState.Hover or ComponentState.HoverSelected ? HoverTextColor : TextColor;
|
||||
|
||||
if (!enabled)
|
||||
{
|
||||
currentTextColor = disabledTextColor;
|
||||
@@ -582,8 +586,14 @@ namespace Barotrauma
|
||||
|
||||
if (!HasColorHighlight)
|
||||
{
|
||||
string textToShow = Censor ? censoredText : (Wrap ? wrappedText.Value : text.SanitizedValue);
|
||||
Color colorToShow = currentTextColor * (currentTextColor.A / 255.0f);
|
||||
if (TextManager.DebugDraw)
|
||||
{
|
||||
if (!text.NestedStr.Loaded || text.NestedStr.Language == LanguageIdentifier.None)
|
||||
{
|
||||
colorToShow = Color.Magenta;
|
||||
}
|
||||
}
|
||||
|
||||
if (Shadow)
|
||||
{
|
||||
@@ -597,10 +607,10 @@ namespace Barotrauma
|
||||
{
|
||||
if (OverrideRichTextDataAlpha)
|
||||
{
|
||||
RichTextData.Value.ForEach(rt => rt.Alpha = currentTextColor.A / 255.0f);
|
||||
RichTextData?.ForEach(rt => rt.Alpha = currentTextColor.A / 255.0f);
|
||||
}
|
||||
Font.DrawStringWithColors(spriteBatch, Censor ? censoredText : (Wrap ? wrappedText : text.SanitizedString).Value, pos,
|
||||
currentTextColor * (currentTextColor.A / 255.0f), 0.0f, origin, TextScale, SpriteEffects.None, textDepth, RichTextData.Value, alignment: textAlignment, forceUpperCase: ForceUpperCase);
|
||||
Font.DrawStringWithColors(spriteBatch, textToShow, pos,
|
||||
currentTextColor * (currentTextColor.A / 255.0f), 0.0f, origin, TextScale, SpriteEffects.None, textDepth, RichTextData, alignment: textAlignment, forceUpperCase: ForceUpperCase);
|
||||
}
|
||||
|
||||
Strikethrough?.Draw(spriteBatch, (int)Math.Ceiling(TextSize.X / 2f), pos.X,
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace Barotrauma
|
||||
|
||||
public delegate void TextBoxEvent(GUITextBox sender, Keys key);
|
||||
|
||||
public class GUITextBox : GUIComponent, IKeyboardSubscriber
|
||||
public partial class GUITextBox : GUIComponent, IKeyboardSubscriber
|
||||
{
|
||||
public event TextBoxEvent OnSelected;
|
||||
public event TextBoxEvent OnDeselected;
|
||||
@@ -67,12 +67,12 @@ namespace Barotrauma
|
||||
private int selectionEndIndex;
|
||||
private bool IsLeftToRight => selectionStartIndex <= selectionEndIndex;
|
||||
|
||||
private GUICustomComponent caretAndSelectionRenderer;
|
||||
private readonly GUICustomComponent caretAndSelectionRenderer;
|
||||
|
||||
private bool mouseHeldInside;
|
||||
|
||||
private readonly Memento<string> memento = new Memento<string>();
|
||||
|
||||
|
||||
// Skip one update cycle, fixes Enter key instantly deselecting the chatbox
|
||||
private bool skipUpdate;
|
||||
|
||||
@@ -189,6 +189,7 @@ namespace Barotrauma
|
||||
base.Font = value;
|
||||
if (textBlock == null) { return; }
|
||||
textBlock.Font = value;
|
||||
imePreviewTextHandler.Font = Font;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -253,6 +254,8 @@ namespace Barotrauma
|
||||
|
||||
public override bool PlaySoundOnSelect { get; set; } = true;
|
||||
|
||||
private readonly IMEPreviewTextHandler imePreviewTextHandler;
|
||||
|
||||
public GUITextBox(RectTransform rectT, string text = "", Color? textColor = null, GUIFont font = null,
|
||||
Alignment textAlignment = Alignment.Left, bool wrap = false, string style = "", Color? color = null, bool createClearButton = false, bool createPenIcon = true)
|
||||
: base(style, rectT)
|
||||
@@ -264,6 +267,7 @@ namespace Barotrauma
|
||||
frame = new GUIFrame(new RectTransform(Vector2.One, rectT, Anchor.Center), style, color);
|
||||
GUIStyle.Apply(frame, style == "" ? "GUITextBox" : style);
|
||||
textBlock = new GUITextBlock(new RectTransform(Vector2.One, frame.RectTransform, Anchor.CenterLeft), text ?? "", textColor, font, textAlignment, wrap);
|
||||
imePreviewTextHandler = new IMEPreviewTextHandler(textBlock.Font);
|
||||
GUIStyle.Apply(textBlock, "", this);
|
||||
if (font != null) { textBlock.Font = font; }
|
||||
CaretEnabled = true;
|
||||
@@ -295,18 +299,17 @@ namespace Barotrauma
|
||||
textBlock.RectTransform.MaxSize = new Point(frame.Rect.Width - icon.Rect.Height - clearButtonWidth - icon.RectTransform.AbsoluteOffset.X * 2, int.MaxValue);
|
||||
}
|
||||
Font = textBlock.Font;
|
||||
|
||||
Enabled = true;
|
||||
|
||||
rectT.SizeChanged += () =>
|
||||
rectT.SizeChanged += () =>
|
||||
{
|
||||
if (icon != null) { textBlock.RectTransform.MaxSize = new Point(frame.Rect.Width - icon.Rect.Height - icon.RectTransform.AbsoluteOffset.X * 2, int.MaxValue); }
|
||||
caretPosDirty = true;
|
||||
caretPosDirty = true;
|
||||
};
|
||||
rectT.ScaleChanged += () =>
|
||||
{
|
||||
if (icon != null) { textBlock.RectTransform.MaxSize = new Point(frame.Rect.Width - icon.Rect.Height - icon.RectTransform.AbsoluteOffset.X * 2, int.MaxValue); }
|
||||
caretPosDirty = true;
|
||||
caretPosDirty = true;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -381,14 +384,16 @@ namespace Barotrauma
|
||||
{
|
||||
GUI.KeyboardDispatcher.Subscriber = null;
|
||||
}
|
||||
|
||||
OnDeselected?.Invoke(this, Keys.None);
|
||||
imePreviewTextHandler.Reset();
|
||||
}
|
||||
|
||||
public override void Flash(Color? color = null, float flashDuration = 1.5f, bool useRectangleFlash = false, bool useCircularFlash = false, Vector2? flashRectOffset = null)
|
||||
{
|
||||
frame.Flash(color, flashDuration, useRectangleFlash, useCircularFlash, flashRectOffset);
|
||||
}
|
||||
|
||||
|
||||
protected override void Update(float deltaTime)
|
||||
{
|
||||
if (!Visible) return;
|
||||
@@ -673,6 +678,18 @@ namespace Barotrauma
|
||||
break;
|
||||
}
|
||||
}
|
||||
#if !WINDOWS
|
||||
public void ReceiveEditingInput(string text, int start)
|
||||
{
|
||||
if (string.IsNullOrEmpty(text))
|
||||
{
|
||||
if (start is 0) { imePreviewTextHandler.Reset(); }
|
||||
return;
|
||||
}
|
||||
|
||||
imePreviewTextHandler.UpdateText(text, start);
|
||||
}
|
||||
#endif
|
||||
|
||||
public void ReceiveSpecialInput(Keys key)
|
||||
{
|
||||
@@ -864,6 +881,24 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public void DrawIMEPreview(SpriteBatch spriteBatch)
|
||||
{
|
||||
if (!imePreviewTextHandler.HasText) { return; }
|
||||
|
||||
Vector2 imePosition = CaretScreenPos;
|
||||
int inflate = GUI.IntScale(3);
|
||||
|
||||
RectangleF rect = new RectangleF(imePosition, imePreviewTextHandler.TextSize);
|
||||
rect.Inflate(inflate, inflate);
|
||||
|
||||
RectangleF borderRect = rect;
|
||||
borderRect.Inflate(1, 1);
|
||||
|
||||
GUI.DrawFilledRectangle(spriteBatch, borderRect, Color.White, depth: 0.02f);
|
||||
GUI.DrawFilledRectangle(spriteBatch, rect, Color.Black, depth: 0.01f);
|
||||
Font.DrawString(spriteBatch, imePreviewTextHandler.PreviewText, imePosition, GUIStyle.Orange, 0.0f, Vector2.Zero, 1f, SpriteEffects.None, 0, alignment: textBlock.TextAlignment, forceUpperCase: textBlock.ForceUpperCase);
|
||||
}
|
||||
|
||||
private void CalculateSelection()
|
||||
{
|
||||
string textDrawn = Censor ? textBlock.CensoredText : WrappedText;
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
using ImeSharp;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
|
||||
namespace Barotrauma;
|
||||
|
||||
/// <summary>
|
||||
/// A class for handling Input Method Editor (used for inputting e.g. Chinese and Japanese text)
|
||||
/// </summary>
|
||||
public partial class GUITextBox : GUIComponent
|
||||
{
|
||||
private static bool initialized;
|
||||
|
||||
public static GUIFrame IMEWindow { get; set; }
|
||||
public static GUITextBlock IMETextBlock { get; set; }
|
||||
|
||||
public static void UpdateIME()
|
||||
{
|
||||
if (!initialized) { InitializeIME(); }
|
||||
if (GUI.KeyboardDispatcher.Subscriber is GUITextBox { Selected: true })
|
||||
{
|
||||
IMEWindow?.AddToGUIUpdateList(order: 10);
|
||||
}
|
||||
}
|
||||
|
||||
private static void InitializeIME()
|
||||
{
|
||||
InputMethod.Initialize(GameMain.Instance.Window.Hwnd, false);
|
||||
InputMethod.TextCompositionCallback = OnTextComposition;
|
||||
InputMethod.CommitTextCompositionCallback = OnCommitTextComposition;
|
||||
InputMethod.Enabled = true;
|
||||
IMEWindow = new GUIFrame(new RectTransform(new Point(GUI.IntScale(300), GUI.IntScale(300)), GUI.Canvas), "InnerFrame") { CanBeFocused = false, Visible = false };
|
||||
IMETextBlock = new GUITextBlock(new RectTransform(Vector2.One, IMEWindow.RectTransform), "") { CanBeFocused = false };
|
||||
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
private static void OnTextComposition(IMEString compositionText, int cursorPosition, IMEString[] candidateList, int candidatePageStart, int candidatePageSize, int candidateSelection)
|
||||
{
|
||||
if (GUI.KeyboardDispatcher.Subscriber is not GUITextBox { Selected: true } textBox) { return; }
|
||||
IMEWindow.Visible = true;
|
||||
string text = compositionText.ToString().Insert(cursorPosition, "|");
|
||||
if (candidateList != null)
|
||||
{
|
||||
text += "\n";
|
||||
for (int i = 0; i < candidatePageSize; i++)
|
||||
{
|
||||
string candidateStr = $"\t{candidatePageStart + i + 1} {candidateList[i]}";
|
||||
if (candidateSelection == i)
|
||||
{
|
||||
candidateStr = $" ‖color:{XMLExtensions.ToStringHex(Color.White)}‖{candidateStr}‖end‖";
|
||||
}
|
||||
candidateStr += "\n";
|
||||
text += candidateStr;
|
||||
}
|
||||
}
|
||||
IMETextBlock.Text = RichString.Rich(text);
|
||||
|
||||
IMEWindow.RectTransform.NonScaledSize = new Point(
|
||||
Math.Max(IMEWindow.Rect.Width, (int)IMETextBlock.TextSize.X + GUI.IntScale(32)),
|
||||
(int)IMETextBlock.TextSize.Y);
|
||||
|
||||
Point windowPos = new Point(textBox.Rect.X, textBox.Rect.Bottom);
|
||||
if (windowPos.Y + IMEWindow.Rect.Height > GameMain.GraphicsHeight)
|
||||
{
|
||||
windowPos.Y = textBox.Rect.Y - IMEWindow.Rect.Height;
|
||||
}
|
||||
IMEWindow.RectTransform.ScreenSpaceOffset = windowPos;
|
||||
}
|
||||
|
||||
private static void OnCommitTextComposition(string text)
|
||||
{
|
||||
if (IMEWindow.Visible)
|
||||
{
|
||||
foreach (char c in text)
|
||||
{
|
||||
if (!char.IsControl(c))
|
||||
{
|
||||
GUI.KeyboardDispatcher.Subscriber?.ReceiveTextInput(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
IMEWindow.Visible = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,7 +65,7 @@ namespace Barotrauma
|
||||
get; private set;
|
||||
}
|
||||
|
||||
public static Rectangle AfflictionAreaLeft
|
||||
public static Rectangle HealthBarAfflictionArea
|
||||
{
|
||||
get; private set;
|
||||
}
|
||||
@@ -143,7 +143,7 @@ namespace Barotrauma
|
||||
}
|
||||
int healthBarHeight = (int)(50f * GUI.Scale);
|
||||
HealthBarArea = new Rectangle(BottomRightInfoArea.Right - healthBarWidth + (int)Math.Floor(1 / GUI.Scale), BottomRightInfoArea.Y - healthBarHeight + GUI.IntScale(10), healthBarWidth, healthBarHeight);
|
||||
AfflictionAreaLeft = new Rectangle(HealthBarArea.X, HealthBarArea.Y - Padding - afflictionAreaHeight, HealthBarArea.Width, afflictionAreaHeight);
|
||||
HealthBarAfflictionArea = new Rectangle(HealthBarArea.X, HealthBarArea.Y - Padding - afflictionAreaHeight, HealthBarArea.Width, afflictionAreaHeight);
|
||||
|
||||
|
||||
int messageAreaWidth = GameMain.GraphicsWidth / 3;
|
||||
@@ -173,7 +173,7 @@ namespace Barotrauma
|
||||
|
||||
int objectiveListAreaX = HealthWindowAreaLeft.Right + Padding;
|
||||
int objectiveListAreaY = ButtonAreaTop.Bottom + Padding;
|
||||
TutorialObjectiveListArea = new Rectangle(objectiveListAreaX, objectiveListAreaY, (GameMain.GraphicsWidth - Padding) - objectiveListAreaX, (AfflictionAreaLeft.Top - Padding) - objectiveListAreaY);
|
||||
TutorialObjectiveListArea = new Rectangle(objectiveListAreaX, objectiveListAreaY, (GameMain.GraphicsWidth - Padding) - objectiveListAreaX, (HealthBarAfflictionArea.Top - Padding) - objectiveListAreaY);
|
||||
|
||||
int votingAreaWidth = (int)(400 * GUI.Scale);
|
||||
int votingAreaX = GameMain.GraphicsWidth - Padding - votingAreaWidth;
|
||||
@@ -193,7 +193,7 @@ namespace Barotrauma
|
||||
DrawRectangle(CrewArea, Color.Blue * 0.5f);
|
||||
DrawRectangle(ChatBoxArea, Color.Cyan * 0.5f);
|
||||
DrawRectangle(HealthBarArea, Color.Red * 0.5f);
|
||||
DrawRectangle(AfflictionAreaLeft, Color.Red * 0.5f);
|
||||
DrawRectangle(HealthBarAfflictionArea, Color.Red * 0.5f);
|
||||
DrawRectangle(InventoryAreaLower, Color.Yellow * 0.5f);
|
||||
DrawRectangle(HealthWindowAreaLeft, Color.Red * 0.5f);
|
||||
DrawRectangle(BottomRightInfoArea, Color.Green * 0.5f);
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
#nullable enable
|
||||
|
||||
using Microsoft.Xna.Framework;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
public sealed class IMEPreviewTextHandler
|
||||
{
|
||||
public string PreviewText { get; private set; } = string.Empty;
|
||||
public Vector2 TextSize { get; private set; }
|
||||
public bool HasText => !string.IsNullOrEmpty(PreviewText);
|
||||
|
||||
// This has to be settable because for some reason we update the font of GUITextBox in some places
|
||||
public GUIFont Font { get; set; }
|
||||
|
||||
public IMEPreviewTextHandler(GUIFont font)
|
||||
{
|
||||
Font = font;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
TextSize = Vector2.Zero;
|
||||
PreviewText = string.Empty;
|
||||
}
|
||||
|
||||
public void UpdateText(string text, int start)
|
||||
{
|
||||
if (string.IsNullOrEmpty(text) && start is 0)
|
||||
{
|
||||
Reset();
|
||||
return;
|
||||
}
|
||||
|
||||
int totalLength = start + text.Length;
|
||||
string newText = PreviewText;
|
||||
if (newText.Length > totalLength)
|
||||
{
|
||||
newText = newText[..totalLength];
|
||||
}
|
||||
|
||||
if (totalLength > newText.Length)
|
||||
{
|
||||
// this is required for some reason on Windows
|
||||
// my guess is that the order which TextEditing events come thru is not guaranteed
|
||||
newText = newText.PadRight(totalLength);
|
||||
}
|
||||
|
||||
newText = newText.Remove(start, text.Length).Insert(start, text);
|
||||
PreviewText = newText;
|
||||
TextSize = Font.MeasureString(PreviewText);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -117,7 +117,7 @@ namespace Barotrauma
|
||||
decorativeMap = new SpriteSheet("Content/Map/MapHUD.png", 6, 5, Vector2.Zero, sourceRect: new Rectangle(0, 0, 2048, 640));
|
||||
decorativeGraph = new SpriteSheet("Content/Map/MapHUD.png", 4, 10, Vector2.Zero, sourceRect: new Rectangle(1025, 1259, 1024, 732));
|
||||
|
||||
overlay = TextureLoader.FromFile("Content/UI/LoadingScreenOverlay.png");
|
||||
overlay = TextureLoader.FromFile("Content/UI/MainMenuVignette.png");
|
||||
noiseSprite = new Sprite("Content/UI/noise.png", Vector2.Zero);
|
||||
DrawLoadingText = true;
|
||||
SetSelectedTip(TextManager.Get("LoadingScreenTip"));
|
||||
@@ -138,13 +138,6 @@ namespace Barotrauma
|
||||
DisableSplashScreen();
|
||||
}
|
||||
}
|
||||
|
||||
var titleStyle = GUIStyle.GetComponentStyle("TitleText");
|
||||
Sprite titleSprite = null;
|
||||
if (!WaitForLanguageSelection && titleStyle != null && titleStyle.Sprites.ContainsKey(GUIComponent.ComponentState.None))
|
||||
{
|
||||
titleSprite = titleStyle.Sprites[GUIComponent.ComponentState.None].First()?.Sprite;
|
||||
}
|
||||
|
||||
drawn = true;
|
||||
|
||||
@@ -165,7 +158,7 @@ namespace Barotrauma
|
||||
null, Color.White, 0.0f, new Vector2(currentBackgroundTexture.Width / 2, currentBackgroundTexture.Height / 2),
|
||||
scale, SpriteEffects.None, 0.0f);
|
||||
|
||||
spriteBatch.Draw(overlay, new Rectangle(0, 0, GameMain.GraphicsWidth, GameMain.GraphicsHeight), null, Color.White, 0.0f, Vector2.Zero, SpriteEffects.None, 0.0f);
|
||||
spriteBatch.Draw(overlay, Vector2.Zero, null, Color.White, 0.0f, Vector2.Zero, Math.Min(GameMain.GraphicsWidth / (float)overlay.Width, GameMain.GraphicsHeight / (float)overlay.Height), SpriteEffects.None, 0.0f);
|
||||
|
||||
float noiseStrength = (float)PerlinNoise.CalculatePerlin(noiseT, noiseT, 0);
|
||||
float noiseScale = (float)PerlinNoise.CalculatePerlin(noiseT * 5.0f, noiseT * 2.0f, 0) * 4.0f;
|
||||
@@ -174,10 +167,7 @@ namespace Barotrauma
|
||||
color: Color.White * noiseStrength * 0.1f,
|
||||
textureScale: Vector2.One * noiseScale);
|
||||
|
||||
titleSprite?.Draw(spriteBatch, new Vector2(GameMain.GraphicsWidth * 0.05f, GameMain.GraphicsHeight * 0.125f),
|
||||
Color.White, origin: new Vector2(0.0f, titleSprite.SourceRect.Height / 2.0f),
|
||||
scale: GameMain.GraphicsHeight / 2000.0f);
|
||||
|
||||
Vector2 textPos = new Vector2((int)(GameMain.GraphicsWidth * 0.05f), (int)(GameMain.GraphicsHeight * 0.75f));
|
||||
if (WaitForLanguageSelection)
|
||||
{
|
||||
DrawLanguageSelectionPrompt(spriteBatch, graphics);
|
||||
@@ -215,16 +205,18 @@ namespace Barotrauma
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if (GUIStyle.LargeFont.HasValue)
|
||||
{
|
||||
GUIStyle.LargeFont.DrawString(spriteBatch, loadText.ToUpper(),
|
||||
new Vector2(GameMain.GraphicsWidth / 2.0f - GUIStyle.LargeFont.MeasureString(loadText.ToUpper()).X / 2.0f, GameMain.GraphicsHeight * 0.75f),
|
||||
textPos,
|
||||
Color.White);
|
||||
textPos.Y += GUIStyle.LargeFont.MeasureString(loadText.ToUpper()).Y * 1.2f;
|
||||
}
|
||||
|
||||
if (GUIStyle.Font.HasValue && selectedTip != null)
|
||||
{
|
||||
string wrappedTip = ToolBox.WrapText(selectedTip.SanitizedValue, GameMain.GraphicsWidth * 0.5f, GUIStyle.Font.Value);
|
||||
string wrappedTip = ToolBox.WrapText(selectedTip.SanitizedValue, GameMain.GraphicsWidth * 0.3f, GUIStyle.Font.Value);
|
||||
string[] lines = wrappedTip.Split('\n');
|
||||
float lineHeight = GUIStyle.Font.MeasureString(selectedTip).Y;
|
||||
|
||||
@@ -234,7 +226,8 @@ namespace Barotrauma
|
||||
for (int i = 0; i < lines.Length; i++)
|
||||
{
|
||||
GUIStyle.Font.DrawStringWithColors(spriteBatch, lines[i],
|
||||
new Vector2((int)(GameMain.GraphicsWidth / 2.0f - GUIStyle.Font.MeasureString(lines[i]).X / 2.0f), (int)(GameMain.GraphicsHeight * 0.8f + i * lineHeight)), Color.White,
|
||||
new Vector2(textPos.X, (int)(textPos.Y + i * lineHeight)),
|
||||
Color.White,
|
||||
0f, Vector2.Zero, 1f, SpriteEffects.None, 0f, selectedTip.RichTextData.Value, rtdOffset);
|
||||
rtdOffset += lines[i].Length;
|
||||
}
|
||||
@@ -244,7 +237,8 @@ namespace Barotrauma
|
||||
for (int i = 0; i < lines.Length; i++)
|
||||
{
|
||||
GUIStyle.Font.DrawString(spriteBatch, lines[i],
|
||||
new Vector2((int)(GameMain.GraphicsWidth / 2.0f - GUIStyle.Font.MeasureString(lines[i]).X / 2.0f), (int)(GameMain.GraphicsHeight * 0.8f + i * lineHeight)), Color.White);
|
||||
new Vector2(textPos.X, (int)(textPos.Y + i * lineHeight)),
|
||||
new Color(228, 217, 167, 255));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -257,13 +251,16 @@ namespace Barotrauma
|
||||
Vector2 decorativeScale = new Vector2(GameMain.GraphicsHeight / 1080.0f);
|
||||
|
||||
float noiseVal = (float)PerlinNoise.CalculatePerlin(Timing.TotalTime * 0.25f, Timing.TotalTime * 0.5f, 0);
|
||||
decorativeGraph.Draw(spriteBatch, (int)(decorativeGraph.FrameCount * noiseVal),
|
||||
new Vector2(GameMain.GraphicsWidth * 0.001f, GameMain.GraphicsHeight * 0.24f),
|
||||
Color.White, Vector2.Zero, 0.0f, decorativeScale, SpriteEffects.FlipVertically);
|
||||
if (!WaitForLanguageSelection)
|
||||
{
|
||||
decorativeGraph.Draw(spriteBatch, (int)(decorativeGraph.FrameCount * noiseVal),
|
||||
new Vector2(GameMain.GraphicsWidth * 0.001f, textPos.Y),
|
||||
Color.White, new Vector2(0, decorativeMap.FrameSize.Y), 0.0f, decorativeScale, SpriteEffects.FlipVertically);
|
||||
}
|
||||
|
||||
decorativeMap.Draw(spriteBatch, (int)(decorativeMap.FrameCount * noiseVal),
|
||||
new Vector2(GameMain.GraphicsWidth * 0.99f, GameMain.GraphicsHeight * 0.66f),
|
||||
Color.White, decorativeMap.FrameSize.ToVector2(), 0.0f, decorativeScale);
|
||||
new Vector2(GameMain.GraphicsWidth * 0.99f, GameMain.GraphicsHeight * 0.01f),
|
||||
Color.White, new Vector2(decorativeMap.FrameSize.X, 0), 0.0f, decorativeScale, SpriteEffects.FlipHorizontally | SpriteEffects.FlipVertically);
|
||||
|
||||
if (noiseVal < 0.2f)
|
||||
{
|
||||
@@ -285,8 +282,9 @@ namespace Barotrauma
|
||||
|
||||
if (GUIStyle.LargeFont.HasValue)
|
||||
{
|
||||
Vector2 textSize = GUIStyle.LargeFont.MeasureString(randText);
|
||||
GUIStyle.LargeFont.DrawString(spriteBatch, randText,
|
||||
new Vector2(GameMain.GraphicsWidth - decorativeMap.FrameSize.X * decorativeScale.X * 0.8f, GameMain.GraphicsHeight * 0.57f),
|
||||
new Vector2(GameMain.GraphicsWidth * 0.95f - textSize.X, GameMain.GraphicsHeight * 0.06f),
|
||||
Color.White * (1.0f - noiseVal));
|
||||
}
|
||||
|
||||
@@ -312,8 +310,8 @@ namespace Barotrauma
|
||||
languageSelectionCursor = new Sprite("Content/UI/cursor.png", Vector2.Zero);
|
||||
}
|
||||
|
||||
Vector2 textPos = new Vector2(GameMain.GraphicsWidth / 2, GameMain.GraphicsHeight * 0.3f);
|
||||
Vector2 textSpacing = new Vector2(0.0f, (GameMain.GraphicsHeight * 0.5f) / AvailableLanguages.Length);
|
||||
Vector2 textPos = new Vector2((int)(GameMain.GraphicsWidth * 0.05f), (int)(GameMain.GraphicsHeight * 0.3f));
|
||||
Vector2 textSpacing = new Vector2(0.0f, GameMain.GraphicsHeight * 0.5f / AvailableLanguages.Length);
|
||||
foreach (LanguageIdentifier language in AvailableLanguages)
|
||||
{
|
||||
string localizedLanguageName = TextManager.GetTranslatedLanguageName(language);
|
||||
@@ -321,10 +319,10 @@ namespace Barotrauma
|
||||
|
||||
Vector2 textSize = font.MeasureString(localizedLanguageName);
|
||||
bool hover =
|
||||
Math.Abs(PlayerInput.MousePosition.X - textPos.X) < textSize.X / 2 &&
|
||||
Math.Abs(PlayerInput.MousePosition.Y - textPos.Y) < textSpacing.Y / 2;
|
||||
PlayerInput.MousePosition.X > textPos.X && PlayerInput.MousePosition.X < textPos.X + textSize.X &&
|
||||
PlayerInput.MousePosition.Y > textPos.Y && PlayerInput.MousePosition.Y < textPos.Y + textSize.Y;
|
||||
|
||||
font.DrawString(spriteBatch, localizedLanguageName, textPos - textSize / 2,
|
||||
font.DrawString(spriteBatch, localizedLanguageName, textPos,
|
||||
hover ? Color.White : Color.White * 0.6f);
|
||||
if (hover && PlayerInput.PrimaryMouseButtonClicked())
|
||||
{
|
||||
@@ -431,7 +429,7 @@ namespace Barotrauma
|
||||
drawn = false;
|
||||
LoadState = null;
|
||||
SetSelectedTip(TextManager.Get("LoadingScreenTip"));
|
||||
currentBackgroundTexture = LocationType.Prefabs.GetRandomUnsynced()?.GetPortrait(Rand.Int(int.MaxValue))?.Texture;
|
||||
currentBackgroundTexture = LocationType.Prefabs.Where(p => p.UsePortraitInRandomLoadingScreens).GetRandomUnsynced()?.GetPortrait(Rand.Int(int.MaxValue))?.Texture;
|
||||
|
||||
while (!drawn)
|
||||
{
|
||||
|
||||
@@ -12,7 +12,7 @@ using PlayerBalanceElement = Barotrauma.CampaignUI.PlayerBalanceElement;
|
||||
namespace Barotrauma
|
||||
{
|
||||
[SuppressMessage("ReSharper", "UnusedVariable")]
|
||||
internal class MedicalClinicUI
|
||||
internal sealed class MedicalClinicUI
|
||||
{
|
||||
private enum ElementState
|
||||
{
|
||||
@@ -127,12 +127,14 @@ namespace Barotrauma
|
||||
{
|
||||
public readonly GUIComponent Panel;
|
||||
public readonly GUIListBox HealList;
|
||||
public readonly GUIComponent TreatAllButton;
|
||||
public readonly List<CrewElement> HealElements;
|
||||
|
||||
public CrewHealList(GUIListBox healList, GUIComponent panel)
|
||||
public CrewHealList(GUIListBox healList, GUIComponent panel, GUIComponent treatAllButton)
|
||||
{
|
||||
Panel = panel;
|
||||
HealList = healList;
|
||||
TreatAllButton = treatAllButton;
|
||||
HealElements = new List<CrewElement>();
|
||||
}
|
||||
}
|
||||
@@ -179,7 +181,7 @@ namespace Barotrauma
|
||||
private PopupAfflictionList? selectedCrewAfflictionList;
|
||||
private bool isWaitingForServer;
|
||||
private const float refreshTimerMax = 3f;
|
||||
private float refreshTimer = 0;
|
||||
private float refreshTimer;
|
||||
|
||||
private PlayerBalanceElement? playerBalanceElement;
|
||||
|
||||
@@ -196,7 +198,7 @@ namespace Barotrauma
|
||||
{
|
||||
new GUIButton(new RectTransform(new Vector2(0.2f, 0.1f), parent.RectTransform, Anchor.TopCenter), "Recreate UI - NOT PRESENT IN RELEASE!")
|
||||
{
|
||||
OnClicked = (_, __) =>
|
||||
OnClicked = (_, _) =>
|
||||
{
|
||||
parent.ClearChildren();
|
||||
CreateUI();
|
||||
@@ -254,7 +256,7 @@ namespace Barotrauma
|
||||
continue;
|
||||
}
|
||||
|
||||
CreatePendingHealElement(healList.HealList.Content, crewMember, healList, Array.Empty<MedicalClinic.NetAffliction>());
|
||||
CreatePendingHealElement(healList.HealList.Content, crewMember, healList, ImmutableArray<MedicalClinic.NetAffliction>.Empty);
|
||||
}
|
||||
|
||||
// check if there are elements that the crew doesn't have
|
||||
@@ -309,7 +311,7 @@ namespace Barotrauma
|
||||
|
||||
private void UpdateCrewPanel()
|
||||
{
|
||||
if (!(crewHealList is { } healList)) { return; }
|
||||
if (crewHealList is not { } healList) { return; }
|
||||
|
||||
ImmutableArray<CharacterInfo> crew = MedicalClinic.GetCrewCharacters();
|
||||
|
||||
@@ -334,12 +336,21 @@ namespace Barotrauma
|
||||
healList.HealList.Content.RemoveChild(element.UIElement);
|
||||
}
|
||||
|
||||
IEnumerable<CrewElement> orderedList = healList.HealElements.OrderBy(element => element.Target.Character?.HealthPercentage ?? 100);
|
||||
IEnumerable<CrewElement> orderedList = healList.HealElements.OrderBy(static element => element.Target.Character?.HealthPercentage ?? 100);
|
||||
|
||||
foreach (CrewElement element in orderedList)
|
||||
{
|
||||
element.UIElement.SetAsLastChild();
|
||||
}
|
||||
|
||||
healList.TreatAllButton.Enabled = false;
|
||||
foreach (CrewElement element in healList.HealElements)
|
||||
{
|
||||
if (element.Afflictions.Count is 0) { continue; }
|
||||
|
||||
healList.TreatAllButton.Enabled = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private static void UpdateAfflictionList(CrewElement healElement)
|
||||
@@ -350,7 +361,7 @@ namespace Barotrauma
|
||||
// sum up all the afflictions and their strengths
|
||||
Dictionary<AfflictionPrefab, float> afflictionAndStrength = new Dictionary<AfflictionPrefab, float>();
|
||||
|
||||
foreach (Affliction affliction in health.GetAllAfflictions().Where(a => MedicalClinic.IsHealable(a)))
|
||||
foreach (Affliction affliction in health.GetAllAfflictions().Where(MedicalClinic.IsHealable))
|
||||
{
|
||||
if (afflictionAndStrength.TryGetValue(affliction.Prefab, out float strength))
|
||||
{
|
||||
@@ -446,8 +457,8 @@ namespace Barotrauma
|
||||
};
|
||||
|
||||
GUILayoutGroup clinicLabelLayout = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.1f), clinicContent.RectTransform), isHorizontal: true, childAnchor: Anchor.CenterLeft);
|
||||
GUIImage clinicIcon = new GUIImage(new RectTransform(Vector2.One, clinicLabelLayout.RectTransform, scaleBasis: ScaleBasis.BothHeight), style: "CrewManagementHeaderIcon", scaleToFit: true);
|
||||
GUITextBlock clinicLabel = new GUITextBlock(new RectTransform(Vector2.One, clinicLabelLayout.RectTransform), TextManager.Get("medicalclinic.medicalclinic"), font: GUIStyle.LargeFont);
|
||||
new GUIImage(new RectTransform(Vector2.One, clinicLabelLayout.RectTransform, scaleBasis: ScaleBasis.BothHeight), style: "CrewManagementHeaderIcon", scaleToFit: true);
|
||||
new GUITextBlock(new RectTransform(Vector2.One, clinicLabelLayout.RectTransform), TextManager.Get("medicalclinic.medicalclinic"), font: GUIStyle.LargeFont);
|
||||
|
||||
GUIFrame clinicBackground = new GUIFrame(new RectTransform(Vector2.One, clinicContent.RectTransform));
|
||||
|
||||
@@ -480,22 +491,24 @@ namespace Barotrauma
|
||||
Stretch = true
|
||||
};
|
||||
|
||||
// GUILayoutGroup sortLayout = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.05f), clinicContainer.RectTransform), isHorizontal: true, childAnchor: Anchor.CenterLeft);
|
||||
|
||||
// new GUITextBlock(new RectTransform(new Vector2(0.2f, 1f), sortLayout.RectTransform), TextManager.Get("campaignstore.sortby"), font: GUI.SubHeadingFont);
|
||||
|
||||
// GUIDropDown sortDropdown = new GUIDropDown(new RectTransform(new Vector2(0.3f, 1f), sortLayout.RectTransform));
|
||||
//
|
||||
// foreach (SortMode mode in Enum.GetValues(typeof(SortMode)).Cast<SortMode>())
|
||||
// {
|
||||
// sortDropdown.AddItem(TextManager.Get($"medicalclinic.sortmode.{mode}"), mode);
|
||||
// }
|
||||
//
|
||||
// sortDropdown.SelectItem(SortMode.Severity);
|
||||
|
||||
GUIListBox crewList = new GUIListBox(new RectTransform(Vector2.One, clinicContainer.RectTransform));
|
||||
|
||||
crewHealList = new CrewHealList(crewList, parent);
|
||||
GUIButton treatAllButton = new GUIButton(new RectTransform(new Vector2(1.0f, 0.05f), clinicContainer.RectTransform), TextManager.Get("medicalclinic.treateveryone"))
|
||||
{
|
||||
OnClicked = (_, _) =>
|
||||
{
|
||||
isWaitingForServer = true;
|
||||
medicalClinic.TreatAllButtonAction(OnReceived);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
crewHealList = new CrewHealList(crewList, parent, treatAllButton);
|
||||
|
||||
void OnReceived(MedicalClinic.CallbackOnlyRequest obj)
|
||||
{
|
||||
isWaitingForServer = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void CreateCrewEntry(GUIComponent parent, CrewHealList healList, CharacterInfo info, GUIComponent panel)
|
||||
@@ -525,9 +538,9 @@ namespace Barotrauma
|
||||
TextColor = GUIStyle.Red
|
||||
};
|
||||
|
||||
MedicalClinic.NetCrewMember member = new MedicalClinic.NetCrewMember { CharacterInfo = info, Afflictions = Array.Empty<MedicalClinic.NetAffliction>() };
|
||||
MedicalClinic.NetCrewMember member = new MedicalClinic.NetCrewMember(info);
|
||||
|
||||
crewBackground.OnClicked = (_, __) =>
|
||||
crewBackground.OnClicked = (_, _) =>
|
||||
{
|
||||
SelectCharacter(member, new Vector2(panel.Rect.Right, crewBackground.Rect.Top));
|
||||
return true;
|
||||
@@ -618,7 +631,7 @@ namespace Barotrauma
|
||||
pendingHealList = list;
|
||||
}
|
||||
|
||||
private void CreatePendingHealElement(GUIComponent parent, MedicalClinic.NetCrewMember crewMember, PendingHealList healList, MedicalClinic.NetAffliction[] afflictions)
|
||||
private void CreatePendingHealElement(GUIComponent parent, MedicalClinic.NetCrewMember crewMember, PendingHealList healList, ImmutableArray<MedicalClinic.NetAffliction> afflictions)
|
||||
{
|
||||
CharacterInfo? healInfo = crewMember.FindCharacterInfo(MedicalClinic.GetCrewCharacters());
|
||||
if (healInfo is null) { return; }
|
||||
@@ -803,7 +816,7 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
allComponents.Add(treatAllButton);
|
||||
treatAllButton.OnClicked = (_, __) =>
|
||||
treatAllButton.OnClicked = (_, _) =>
|
||||
{
|
||||
ImmutableArray<MedicalClinic.NetAffliction> afflictions = request.Afflictions.Where(a => !medicalClinic.IsAfflictionPending(crewMember, a)).ToImmutableArray();
|
||||
if (!afflictions.Any()) { return true; }
|
||||
@@ -845,9 +858,9 @@ namespace Barotrauma
|
||||
|
||||
GUITextBlock prefabBlock = new GUITextBlock(new RectTransform(new Vector2(0.5f, 1f), topTextLayout.RectTransform), prefab.Name, font: GUIStyle.SubHeadingFont);
|
||||
|
||||
Color textColor = Color.Lerp(GUIStyle.Orange, GUIStyle.Red, (int)affliction.AfflictionSeverity / 2f);
|
||||
Color textColor = Color.Lerp(GUIStyle.Orange, GUIStyle.Red, affliction.Strength / affliction.Prefab.MaxStrength);
|
||||
|
||||
LocalizedString vitalityText = TextManager.GetWithVariable("medicalclinic.vitalitydifference", "[amount]", (-affliction.Strength).ToString());
|
||||
LocalizedString vitalityText = affliction.VitalityDecrease == 0 ? string.Empty : TextManager.GetWithVariable("medicalclinic.vitalitydifference", "[amount]", (-affliction.VitalityDecrease).ToString());
|
||||
GUITextBlock vitalityBlock = new GUITextBlock(new RectTransform(new Vector2(0.25f, 1f), topTextLayout.RectTransform), vitalityText, textAlignment: Alignment.Center)
|
||||
{
|
||||
TextColor = textColor,
|
||||
@@ -856,7 +869,7 @@ namespace Barotrauma
|
||||
AutoScaleHorizontal = true
|
||||
};
|
||||
|
||||
LocalizedString severityText = TextManager.Get($"AfflictionStrength{affliction.AfflictionSeverity}");
|
||||
LocalizedString severityText = Affliction.GetStrengthText(affliction.Strength, affliction.Prefab.MaxStrength);
|
||||
GUITextBlock severityBlock = new GUITextBlock(new RectTransform(new Vector2(0.25f, 1f), topTextLayout.RectTransform), severityText, textAlignment: Alignment.Center, font: GUIStyle.SubHeadingFont)
|
||||
{
|
||||
TextColor = textColor,
|
||||
@@ -873,9 +886,13 @@ namespace Barotrauma
|
||||
{
|
||||
RelativeSpacing = 0.05f
|
||||
};
|
||||
GUITextBlock descriptionBlock = new GUITextBlock(new RectTransform(new Vector2(1f, 0.6f), bottomTextLayout.RectTransform), prefab.Description, font: GUIStyle.SmallFont, wrap: true)
|
||||
LocalizedString description = affliction.Prefab.GetDescription(affliction.Strength, AfflictionPrefab.Description.TargetType.OtherCharacter);
|
||||
GUITextBlock descriptionBlock = new GUITextBlock(new RectTransform(new Vector2(1f, 0.6f), bottomTextLayout.RectTransform),
|
||||
description,
|
||||
font: GUIStyle.SmallFont,
|
||||
wrap: true)
|
||||
{
|
||||
ToolTip = prefab.Description
|
||||
ToolTip = description
|
||||
};
|
||||
bool truncated = false;
|
||||
while (descriptionBlock.TextSize.Y > descriptionBlock.Rect.Height && descriptionBlock.WrappedText.Contains('\n'))
|
||||
@@ -919,10 +936,9 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
MedicalClinic.NetCrewMember newMember = new MedicalClinic.NetCrewMember
|
||||
MedicalClinic.NetCrewMember newMember = crewMember with
|
||||
{
|
||||
CharacterInfoID = crewMember.CharacterInfoID,
|
||||
Afflictions = Array.Empty<MedicalClinic.NetAffliction>()
|
||||
Afflictions = ImmutableArray<MedicalClinic.NetAffliction>.Empty
|
||||
};
|
||||
|
||||
existingMember = newMember;
|
||||
@@ -936,7 +952,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
existingMember.Afflictions = existingMember.Afflictions.Concat(afflictions).ToArray();
|
||||
existingMember.Afflictions = existingMember.Afflictions.Concat(afflictions).ToImmutableArray();
|
||||
ToggleElements(ElementState.Disabled, elementsToDisable);
|
||||
medicalClinic.AddPendingButtonAction(existingMember, request =>
|
||||
{
|
||||
|
||||
@@ -724,7 +724,7 @@ namespace Barotrauma
|
||||
ChangeStoreTab(StoreTab.Buy);
|
||||
if (newLocation?.Reputation != null)
|
||||
{
|
||||
CurrentLocation.Reputation.OnReputationValueChanged.RegisterOverwriteExisting("RefreshStore".ToIdentifier(), _ => { SetNeedsRefresh(); });
|
||||
newLocation.Reputation.OnReputationValueChanged.RegisterOverwriteExisting("RefreshStore".ToIdentifier(), _ => { SetNeedsRefresh(); });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -745,7 +745,7 @@ namespace Barotrauma
|
||||
} ?? Enumerable.Empty<PurchasedItem>();
|
||||
foreach (var button in itemCategoryButtons)
|
||||
{
|
||||
if (!(button.UserData is MapEntityCategory category))
|
||||
if (button.UserData is not MapEntityCategory category)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -852,6 +852,28 @@ namespace Barotrauma
|
||||
FilterStoreItems(category, searchBox.Text);
|
||||
}
|
||||
|
||||
private static KeyValuePair<Identifier, float>? GetReputationRequirement(PriceInfo priceInfo)
|
||||
{
|
||||
return GameMain.GameSession?.Campaign is not null
|
||||
? priceInfo.MinReputation.FirstOrNull()
|
||||
: null;
|
||||
}
|
||||
|
||||
private static KeyValuePair<Identifier, float>? GetTooLowReputation(PriceInfo priceInfo)
|
||||
{
|
||||
if (GameMain.GameSession?.Campaign is CampaignMode campaign)
|
||||
{
|
||||
foreach (var minRep in priceInfo.MinReputation)
|
||||
{
|
||||
if (campaign.GetReputation(minRep.Key) < minRep.Value)
|
||||
{
|
||||
return minRep;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
int prevDailySpecialCount, prevRequestedGoodsCount, prevSubRequestedGoodsCount;
|
||||
|
||||
private void RefreshStoreBuyList()
|
||||
@@ -892,8 +914,9 @@ namespace Barotrauma
|
||||
|
||||
void CreateOrUpdateItemFrame(ItemPrefab itemPrefab, int quantity)
|
||||
{
|
||||
if (itemPrefab.CanBeBoughtFrom(ActiveStore, out PriceInfo priceInfo))
|
||||
if (itemPrefab.CanBeBoughtFrom(ActiveStore, out PriceInfo priceInfo) && itemPrefab.CanCharacterBuy())
|
||||
{
|
||||
|
||||
bool isDailySpecial = ActiveStore.DailySpecials.Contains(itemPrefab);
|
||||
var itemFrame = isDailySpecial ?
|
||||
storeDailySpecialsGroup.FindChild(c => c.UserData is PurchasedItem pi && pi.ItemPrefab == itemPrefab) :
|
||||
@@ -918,7 +941,8 @@ namespace Barotrauma
|
||||
SetOwnedText(itemFrame);
|
||||
SetPriceGetters(itemFrame, true);
|
||||
}
|
||||
SetItemFrameStatus(itemFrame, hasPermissions && quantity > 0);
|
||||
|
||||
SetItemFrameStatus(itemFrame, hasPermissions && quantity > 0 && !GetTooLowReputation(priceInfo).HasValue);
|
||||
existingItemFrames.Add(itemFrame);
|
||||
}
|
||||
}
|
||||
@@ -1110,7 +1134,7 @@ namespace Barotrauma
|
||||
|
||||
private void SetPriceGetters(GUIComponent itemFrame, bool buying)
|
||||
{
|
||||
if (itemFrame == null || !(itemFrame.UserData is PurchasedItem pi)) { return; }
|
||||
if (itemFrame == null || itemFrame.UserData is not PurchasedItem pi) { return; }
|
||||
|
||||
if (itemFrame.FindChild("undiscountedprice", recursive: true) is GUITextBlock undiscountedPriceBlock)
|
||||
{
|
||||
@@ -1302,6 +1326,8 @@ namespace Barotrauma
|
||||
{
|
||||
if (x.GUIComponent.UserData is PurchasedItem itemX && y.GUIComponent.UserData is PurchasedItem itemY)
|
||||
{
|
||||
int reputationCompare = CompareByReputationRestriction(itemX, itemY);
|
||||
if (reputationCompare != 0) { return reputationCompare; }
|
||||
int sortResult = itemX.ItemPrefab.Name != itemY.ItemPrefab.Name ?
|
||||
itemX.ItemPrefab.Name.CompareTo(itemY.ItemPrefab.Name) :
|
||||
itemX.ItemPrefab.Identifier.CompareTo(itemY.ItemPrefab.Identifier);
|
||||
@@ -1330,6 +1356,8 @@ namespace Barotrauma
|
||||
{
|
||||
if (x.GUIComponent.UserData is PurchasedItem itemX && y.GUIComponent.UserData is PurchasedItem itemY)
|
||||
{
|
||||
int reputationCompare = CompareByReputationRestriction(itemX, itemY);
|
||||
if (reputationCompare != 0) { return reputationCompare; }
|
||||
int sortResult = ActiveStore.GetAdjustedItemSellPrice(itemX.ItemPrefab).CompareTo(
|
||||
ActiveStore.GetAdjustedItemSellPrice(itemY.ItemPrefab));
|
||||
if (sortingMethod == SortingMethod.PriceDesc) { sortResult *= -1; }
|
||||
@@ -1354,6 +1382,8 @@ namespace Barotrauma
|
||||
{
|
||||
if (x.GUIComponent.UserData is PurchasedItem itemX && y.GUIComponent.UserData is PurchasedItem itemY)
|
||||
{
|
||||
int reputationCompare = CompareByReputationRestriction(itemX, itemY);
|
||||
if (reputationCompare != 0) { return reputationCompare; }
|
||||
int sortResult = ActiveStore.GetAdjustedItemBuyPrice(itemX.ItemPrefab).CompareTo(
|
||||
ActiveStore.GetAdjustedItemBuyPrice(itemY.ItemPrefab));
|
||||
if (sortingMethod == SortingMethod.PriceDesc) { sortResult *= -1; }
|
||||
@@ -1376,10 +1406,12 @@ namespace Barotrauma
|
||||
specialsGroup.Recalculate();
|
||||
}
|
||||
|
||||
static int CompareByCategory(RectTransform x, RectTransform y)
|
||||
int CompareByCategory(RectTransform x, RectTransform y)
|
||||
{
|
||||
if (x.GUIComponent.UserData is PurchasedItem itemX && y.GUIComponent.UserData is PurchasedItem itemY)
|
||||
{
|
||||
int reputationCompare = CompareByReputationRestriction(itemX, itemY);
|
||||
if (reputationCompare != 0) { return reputationCompare; }
|
||||
return itemX.ItemPrefab.Category.CompareTo(itemY.ItemPrefab.Category);
|
||||
}
|
||||
else
|
||||
@@ -1409,6 +1441,19 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
int CompareByReputationRestriction(PurchasedItem item1, PurchasedItem item2)
|
||||
{
|
||||
PriceInfo priceInfo1 = item1.ItemPrefab.GetPriceInfo(ActiveStore);
|
||||
PriceInfo priceInfo2 = item2.ItemPrefab.GetPriceInfo(ActiveStore);
|
||||
if (priceInfo1 != null && priceInfo2 != null)
|
||||
{
|
||||
var requiredReputation1 = GetTooLowReputation(priceInfo1)?.Value ?? 0.0f;
|
||||
var requiredReputation2 = GetTooLowReputation(priceInfo2)?.Value ?? 0.0f;
|
||||
return requiredReputation1.CompareTo(requiredReputation2);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int CompareByElement(RectTransform x, RectTransform y)
|
||||
{
|
||||
if (ShouldBeOnTop(x) || ShouldBeOnBottom(y))
|
||||
@@ -1667,8 +1712,8 @@ namespace Barotrauma
|
||||
{
|
||||
foreach (var subItem in subItems)
|
||||
{
|
||||
if (!subItem.Components.All(c => !(c is Holdable h) || !h.Attachable || !h.Attached)) { continue; }
|
||||
if (!subItem.Components.All(c => !(c is Wire w) || w.Connections.All(c => c == null))) { continue; }
|
||||
if (!subItem.Components.All(c => c is not Holdable h || !h.Attachable || !h.Attached)) { continue; }
|
||||
if (!subItem.Components.All(c => c is not Wire w || w.Connections.All(c => c == null))) { continue; }
|
||||
if (!ItemAndAllContainersInteractable(subItem)) { continue; }
|
||||
AddOwnedItem(subItem);
|
||||
}
|
||||
@@ -1701,7 +1746,7 @@ namespace Barotrauma
|
||||
|
||||
void AddOwnedItem(Item item)
|
||||
{
|
||||
if (!(item?.Prefab.GetPriceInfo(ActiveStore) is PriceInfo priceInfo)) { return; }
|
||||
if (item?.Prefab.GetPriceInfo(ActiveStore) is not PriceInfo priceInfo) { return; }
|
||||
bool isNonEmpty = !priceInfo.DisplayNonEmpty || item.ConditionPercentage > 5.0f;
|
||||
if (OwnedItems.TryGetValue(item.Prefab, out ItemQuantity itemQuantity))
|
||||
{
|
||||
@@ -1729,14 +1774,14 @@ namespace Barotrauma
|
||||
|
||||
private void SetItemFrameStatus(GUIComponent itemFrame, bool enabled)
|
||||
{
|
||||
if (!(itemFrame?.UserData is PurchasedItem pi)) { return; }
|
||||
if (itemFrame?.UserData is not PurchasedItem pi) { return; }
|
||||
bool refreshFrameStatus = !pi.IsStoreComponentEnabled.HasValue || pi.IsStoreComponentEnabled.Value != enabled;
|
||||
if (!refreshFrameStatus) { return; }
|
||||
if (itemFrame.FindChild("icon", recursive: true) is GUIImage icon)
|
||||
{
|
||||
if (pi.ItemPrefab?.InventoryIcon != null)
|
||||
{
|
||||
icon.Color = pi.ItemPrefab.InventoryIconColor * (enabled ? 1.0f: 0.5f);
|
||||
icon.Color = pi.ItemPrefab.InventoryIconColor * (enabled ? 1.0f : 0.5f);
|
||||
}
|
||||
else if (pi.ItemPrefab?.Sprite != null)
|
||||
{
|
||||
@@ -1841,11 +1886,7 @@ namespace Barotrauma
|
||||
LocalizedString toolTip = string.Empty;
|
||||
if (purchasedItem.ItemPrefab != null)
|
||||
{
|
||||
toolTip = purchasedItem.ItemPrefab.Name;
|
||||
if (!purchasedItem.ItemPrefab.Description.IsNullOrEmpty())
|
||||
{
|
||||
toolTip += $"\n{purchasedItem.ItemPrefab.Description}";
|
||||
}
|
||||
toolTip = purchasedItem.ItemPrefab.GetTooltip();
|
||||
if (itemQuantity != null)
|
||||
{
|
||||
if (itemQuantity.AllNonEmpty)
|
||||
@@ -1858,8 +1899,25 @@ namespace Barotrauma
|
||||
toolTip += $"\n{TextManager.GetWithVariable("campaignstore.ownedtotal", "[amount]", itemQuantity.Total.ToString())}";
|
||||
}
|
||||
}
|
||||
|
||||
PriceInfo priceInfo = purchasedItem.ItemPrefab.GetPriceInfo(ActiveStore);
|
||||
var campaign = GameMain.GameSession?.Campaign;
|
||||
if (priceInfo != null && campaign != null)
|
||||
{
|
||||
var requiredReputation = GetReputationRequirement(priceInfo);
|
||||
if (requiredReputation != null)
|
||||
{
|
||||
var repStr = TextManager.GetWithVariables(
|
||||
"campaignstore.reputationrequired",
|
||||
("[amount]", ((int)requiredReputation.Value.Value).ToString()),
|
||||
("[faction]", TextManager.Get("faction." + requiredReputation.Value.Key).Value));
|
||||
Color color = campaign.GetReputation(requiredReputation.Value.Key) < requiredReputation.Value.Value ?
|
||||
GUIStyle.Orange : GUIStyle.Green;
|
||||
toolTip += $"\n‖color:{color.ToStringHex()}‖{repStr}‖color:end‖";
|
||||
}
|
||||
}
|
||||
}
|
||||
itemComponent.ToolTip = toolTip;
|
||||
itemComponent.ToolTip = RichString.Rich(toolTip);
|
||||
}
|
||||
if (ownedLabel != null)
|
||||
{
|
||||
@@ -1995,11 +2053,23 @@ namespace Barotrauma
|
||||
int totalPrice = 0;
|
||||
foreach (var item in itemsToPurchase)
|
||||
{
|
||||
if (item?.ItemPrefab == null || !item.ItemPrefab.CanBeBoughtFrom(ActiveStore, out var priceInfo))
|
||||
if (item is null) { continue; }
|
||||
|
||||
if (item.ItemPrefab == null || !item.ItemPrefab.CanBeBoughtFrom(ActiveStore, out var priceInfo))
|
||||
{
|
||||
itemsToRemove.Add(item);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (item.ItemPrefab.DefaultPrice.RequiresUnlock)
|
||||
{
|
||||
if (!CargoManager.HasUnlockedStoreItem(item.ItemPrefab))
|
||||
{
|
||||
itemsToRemove.Add(item);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
totalPrice += item.Quantity * ActiveStore.GetAdjustedItemBuyPrice(item.ItemPrefab, priceInfo: priceInfo);
|
||||
}
|
||||
itemsToRemove.ForEach(i => itemsToPurchase.Remove(i));
|
||||
@@ -2169,7 +2239,7 @@ namespace Barotrauma
|
||||
{
|
||||
needsRefresh = itemsToSellFromSub.Count != prevSubItems.Count ||
|
||||
itemsToSellFromSub.Sum(i => i.Quantity) != prevSubItems.Sum(i => i.Quantity) ||
|
||||
itemsToSellFromSub.Any(i => !(prevSubItems.FirstOrDefault(prev => prev.ItemPrefab == i.ItemPrefab) is PurchasedItem prev) || i.Quantity != prev.Quantity) ||
|
||||
itemsToSellFromSub.Any(i => prevSubItems.FirstOrDefault(prev => prev.ItemPrefab == i.ItemPrefab) is not PurchasedItem prev || i.Quantity != prev.Quantity) ||
|
||||
prevSubItems.Any(prev => itemsToSellFromSub.None(i => i.ItemPrefab == prev.ItemPrefab));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -406,7 +406,7 @@ namespace Barotrauma
|
||||
|
||||
if (!GameMain.GameSession.IsSubmarineOwned(subToDisplay))
|
||||
{
|
||||
LocalizedString amountString = TextManager.FormatCurrency(subToDisplay.Price);
|
||||
LocalizedString amountString = TextManager.FormatCurrency(subToDisplay.GetPrice());
|
||||
submarineDisplays[i].submarineFee.Text = TextManager.GetWithVariable("price", "[amount]", amountString);
|
||||
}
|
||||
else
|
||||
@@ -472,7 +472,7 @@ namespace Barotrauma
|
||||
if (transferService)
|
||||
{
|
||||
subsToShow.AddRange(GameMain.GameSession.OwnedSubmarines);
|
||||
subsToShow.Sort((x, y) => x.SubmarineClass.CompareTo(y.SubmarineClass));
|
||||
subsToShow.Sort(ComparePrice);
|
||||
string currentSubName = CurrentOrPendingSubmarine().Name;
|
||||
int currentIndex = subsToShow.FindIndex(s => s.Name == currentSubName);
|
||||
if (currentIndex != -1)
|
||||
@@ -484,7 +484,11 @@ namespace Barotrauma
|
||||
{
|
||||
subsToShow.AddRange((GameMain.Client is null ? SubmarineInfo.SavedSubmarines : MultiPlayerCampaign.GetCampaignSubs())
|
||||
.Where(s => s.IsCampaignCompatible && !GameMain.GameSession.OwnedSubmarines.Any(os => os.Name == s.Name)));
|
||||
subsToShow.Sort((x, y) => x.SubmarineClass.CompareTo(y.SubmarineClass));
|
||||
if (GameMain.GameSession.Campaign?.Map?.CurrentLocation is Location currentLocation)
|
||||
{
|
||||
subsToShow.RemoveAll(sub => !currentLocation.IsSubmarineAvailable(sub));
|
||||
}
|
||||
subsToShow.Sort(ComparePrice);
|
||||
}
|
||||
|
||||
if (transferService)
|
||||
@@ -492,10 +496,14 @@ namespace Barotrauma
|
||||
SetConfirmButtonState(selectedSubmarine != null && selectedSubmarine.Name != CurrentOrPendingSubmarine().Name);
|
||||
}
|
||||
|
||||
subsToShow.Sort((x, y) => x.SubmarineClass.CompareTo(y.SubmarineClass));
|
||||
pageCount = Math.Max(1, (int)Math.Ceiling(subsToShow.Count / (float)submarinesPerPage));
|
||||
UpdatePaging();
|
||||
ContentRefreshRequired = false;
|
||||
|
||||
static int ComparePrice(SubmarineInfo x, SubmarineInfo y)
|
||||
{
|
||||
return x.Price.CompareTo(y.Price) * 100 + x.Name.CompareTo(y.Name);
|
||||
}
|
||||
}
|
||||
|
||||
private SubmarineInfo GetSubToDisplay(int index)
|
||||
@@ -673,7 +681,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (GameMain.GameSession?.Campaign?.PendingSubmarineSwitch == null)
|
||||
{
|
||||
return Submarine.MainSub.Info;
|
||||
return Submarine.MainSub?.Info;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -789,7 +797,9 @@ namespace Barotrauma
|
||||
|
||||
private void ShowBuyPrompt(bool purchaseOnly)
|
||||
{
|
||||
if (!GameMain.GameSession.Campaign.CanAfford(selectedSubmarine.Price))
|
||||
int price = selectedSubmarine.GetPrice();
|
||||
|
||||
if (!GameMain.GameSession.Campaign.CanAfford(price))
|
||||
{
|
||||
new GUIMessageBox(TextManager.Get("purchasesubmarineheader"), TextManager.GetWithVariables("notenoughmoneyforpurchasetext",
|
||||
("[currencyname]", currencyName),
|
||||
@@ -802,7 +812,7 @@ namespace Barotrauma
|
||||
{
|
||||
var text = TextManager.GetWithVariables("purchaseandswitchsubmarinetext",
|
||||
("[submarinename1]", selectedSubmarine.DisplayName),
|
||||
("[amount]", selectedSubmarine.Price.ToString()),
|
||||
("[amount]", price.ToString()),
|
||||
("[currencyname]", currencyName),
|
||||
("[submarinename2]", CurrentOrPendingSubmarine().DisplayName));
|
||||
text += GetItemTransferText();
|
||||
@@ -860,7 +870,7 @@ namespace Barotrauma
|
||||
{
|
||||
msgBox = new GUIMessageBox(TextManager.Get("purchasesubmarineheader"), TextManager.GetWithVariables("purchasesubmarinetext",
|
||||
("[submarinename]", selectedSubmarine.DisplayName),
|
||||
("[amount]", selectedSubmarine.Price.ToString()),
|
||||
("[amount]", price.ToString()),
|
||||
("[currencyname]", currencyName)) + '\n' + TextManager.Get("submarineswitchinstruction"), messageBoxOptions);
|
||||
|
||||
msgBox.Buttons[0].OnClicked = (applyButton, obj) =>
|
||||
|
||||
@@ -34,7 +34,7 @@ namespace Barotrauma
|
||||
private List<CharacterTeamType> teamIDs;
|
||||
private const string inLobbyString = "\u2022 \u2022 \u2022";
|
||||
|
||||
private GUIFrame pendingChangesFrame = null;
|
||||
public static GUIFrame PendingChangesFrame = null;
|
||||
|
||||
public static Color OwnCharacterBGColor = Color.Gold * 0.7f;
|
||||
private bool isTransferMenuOpen;
|
||||
@@ -44,6 +44,7 @@ namespace Barotrauma
|
||||
private float transferMenuOpenState;
|
||||
private bool transferMenuStateCompleted;
|
||||
private readonly HashSet<Identifier> registeredEvents = new HashSet<Identifier>();
|
||||
private readonly TalentMenu talentMenu = new TalentMenu();
|
||||
|
||||
private class LinkedGUI
|
||||
{
|
||||
@@ -206,15 +207,8 @@ namespace Barotrauma
|
||||
transferMenuButton.RectTransform.AbsoluteOffset = new Point(0, -pos - transferMenu.Rect.Height);
|
||||
}
|
||||
GameSession.UpdateTalentNotificationIndicator(talentPointNotification);
|
||||
if (Character.Controlled?.Info is { } characterInfo && talentResetButton != null && talentApplyButton != null)
|
||||
{
|
||||
int talentCount = selectedTalents.Count - characterInfo.GetUnlockedTalentsInTree().Count();
|
||||
talentResetButton.Enabled = talentApplyButton.Enabled = talentCount > 0;
|
||||
if (talentApplyButton.Enabled && talentApplyButton.FlashTimer <= 0.0f)
|
||||
{
|
||||
talentApplyButton.Flash(GUIStyle.Orange);
|
||||
}
|
||||
}
|
||||
|
||||
talentMenu?.Update();
|
||||
|
||||
if (SelectedTab != InfoFrameTab.Crew) { return; }
|
||||
if (linkedGUIList == null) { return; }
|
||||
@@ -325,11 +319,11 @@ namespace Barotrauma
|
||||
AbsoluteOffset = new Point(contentFrame.Rect.X, contentFrame.Rect.Bottom + GUI.IntScale(8))
|
||||
}, style: null);
|
||||
|
||||
pendingChangesFrame = new GUIFrame(new RectTransform(Vector2.One, bottomDisclaimerFrame.RectTransform, Anchor.Center), style: null);
|
||||
PendingChangesFrame = new GUIFrame(new RectTransform(Vector2.One, bottomDisclaimerFrame.RectTransform, Anchor.Center), style: null);
|
||||
|
||||
if (GameMain.NetLobbyScreen?.CampaignCharacterDiscarded ?? false)
|
||||
{
|
||||
NetLobbyScreen.CreateChangesPendingFrame(pendingChangesFrame);
|
||||
NetLobbyScreen.CreateChangesPendingFrame(PendingChangesFrame);
|
||||
}
|
||||
|
||||
SetBalanceText(balanceText, campaignMode.Bank.Balance);
|
||||
@@ -403,7 +397,7 @@ namespace Barotrauma
|
||||
CreateSubmarineInfo(infoFrameHolder, Submarine.MainSub);
|
||||
break;
|
||||
case InfoFrameTab.Talents:
|
||||
CreateCharacterInfo(infoFrameHolder);
|
||||
talentMenu.CreateGUI(infoFrameHolder, Character.Controlled ?? GameMain.Client?.Character);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -957,16 +951,26 @@ namespace Barotrauma
|
||||
|
||||
if (character != null)
|
||||
{
|
||||
if (GameMain.Client == null)
|
||||
if (GameMain.Client is null)
|
||||
{
|
||||
GUIComponent preview = character.Info.CreateInfoFrame(background, false, null);
|
||||
}
|
||||
else
|
||||
{
|
||||
GUIComponent preview = character.Info.CreateInfoFrame(background, false, GetPermissionIcon(GameMain.Client.ConnectedClients.Find(c => c.Character == character)));
|
||||
|
||||
GameMain.Client.SelectCrewCharacter(character, preview);
|
||||
if (!character.IsBot && GameMain.GameSession?.Campaign is MultiPlayerCampaign mpCampaign) { CreateWalletFrame(background, character, mpCampaign); }
|
||||
}
|
||||
|
||||
if (background.FindChild(TalentMenu.ManageBotTalentsButtonUserData, recursive: true) is GUIButton { Enabled: true } talentButton)
|
||||
{
|
||||
talentButton.OnClicked = (button, o) =>
|
||||
{
|
||||
talentMenu.CreateGUI(infoFrameHolder, character);
|
||||
return true;
|
||||
};
|
||||
}
|
||||
}
|
||||
else if (client != null)
|
||||
{
|
||||
@@ -1494,27 +1498,9 @@ namespace Barotrauma
|
||||
AbsoluteSpacing = GUI.IntScale(10)
|
||||
};
|
||||
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), locationInfoContainer.RectTransform), location.Name, font: GUIStyle.LargeFont);
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), locationInfoContainer.RectTransform), location.Type.Name, font: GUIStyle.SubHeadingFont);
|
||||
|
||||
var biomeLabel = new GUITextBlock(new RectTransform(new Vector2(0.5f, 0.0f), locationInfoContainer.RectTransform),
|
||||
TextManager.Get("Biome", "location"), font: GUIStyle.SubHeadingFont, textAlignment: Alignment.CenterLeft);
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 1.0f), biomeLabel.RectTransform), Level.Loaded.LevelData.Biome.DisplayName, textAlignment: Alignment.CenterRight);
|
||||
var difficultyLabel = new GUITextBlock(new RectTransform(new Vector2(0.5f, 0.0f), locationInfoContainer.RectTransform),
|
||||
TextManager.Get("LevelDifficulty"), font: GUIStyle.SubHeadingFont, textAlignment: Alignment.CenterLeft);
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 1.0f), difficultyLabel.RectTransform), ((int)Level.Loaded.LevelData.Difficulty) + " %", textAlignment: Alignment.CenterRight);
|
||||
|
||||
new GUIFrame(new RectTransform(new Vector2(1.0f, 0.01f), missionFrameContent.RectTransform) { AbsoluteOffset = new Point(0, locationInfoContainer.Rect.Height + padding) }, style: "HorizontalLine")
|
||||
{
|
||||
CanBeFocused = false
|
||||
};
|
||||
|
||||
int locationInfoYOffset = locationInfoContainer.Rect.Height + padding * 2;
|
||||
|
||||
Sprite portrait = location.Type.GetPortrait(location.PortraitId);
|
||||
bool hasPortrait = portrait != null && portrait.SourceRect.Width > 0 && portrait.SourceRect.Height > 0;
|
||||
int contentWidth = missionFrameContent.Rect.Width;
|
||||
|
||||
if (hasPortrait)
|
||||
{
|
||||
float portraitAspectRatio = portrait.SourceRect.Width / portrait.SourceRect.Height;
|
||||
@@ -1526,6 +1512,30 @@ namespace Barotrauma
|
||||
portraitImage.RectTransform.NonScaledSize = new Point(Math.Min((int)(portraitImage.Rect.Size.Y * portraitAspectRatio), portraitImage.Rect.Width), portraitImage.Rect.Size.Y);
|
||||
}
|
||||
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), locationInfoContainer.RectTransform), location.Name, font: GUIStyle.LargeFont);
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), locationInfoContainer.RectTransform), location.Type.Name, font: GUIStyle.SubHeadingFont);
|
||||
|
||||
if (location.Faction?.Prefab != null)
|
||||
{
|
||||
var factionLabel = new GUITextBlock(new RectTransform(new Vector2(0.5f, 0.0f), locationInfoContainer.RectTransform),
|
||||
TextManager.Get("Faction"), font: GUIStyle.SubHeadingFont, textAlignment: Alignment.CenterLeft);
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 1.0f), factionLabel.RectTransform), location.Faction.Prefab.Name, textAlignment: Alignment.CenterRight);
|
||||
}
|
||||
var biomeLabel = new GUITextBlock(new RectTransform(new Vector2(0.5f, 0.0f), locationInfoContainer.RectTransform),
|
||||
TextManager.Get("Biome", "location"), font: GUIStyle.SubHeadingFont, textAlignment: Alignment.CenterLeft);
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 1.0f), biomeLabel.RectTransform), Level.Loaded.LevelData.Biome.DisplayName, textAlignment: Alignment.CenterRight);
|
||||
var difficultyLabel = new GUITextBlock(new RectTransform(new Vector2(0.5f, 0.0f), locationInfoContainer.RectTransform),
|
||||
TextManager.Get("LevelDifficulty"), font: GUIStyle.SubHeadingFont, textAlignment: Alignment.CenterLeft);
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 1.0f), difficultyLabel.RectTransform), TextManager.GetWithVariable("percentageformat", "[value]", ((int)Level.Loaded.LevelData.Difficulty).ToString()), textAlignment: Alignment.CenterRight);
|
||||
|
||||
new GUIFrame(new RectTransform(new Vector2(1.0f, 0.01f), missionFrameContent.RectTransform) { AbsoluteOffset = new Point(0, locationInfoContainer.Rect.Height + padding) }, style: "HorizontalLine")
|
||||
{
|
||||
CanBeFocused = false
|
||||
};
|
||||
|
||||
int locationInfoYOffset = locationInfoContainer.Rect.Height + padding * 2;
|
||||
|
||||
|
||||
GUIListBox missionList = new GUIListBox(new RectTransform(new Point(contentWidth, missionFrameContent.Rect.Height - locationInfoYOffset), missionFrameContent.RectTransform, Anchor.TopCenter) { AbsoluteOffset = new Point(0, locationInfoYOffset) });
|
||||
missionList.ContentBackground.Color = Color.Transparent;
|
||||
missionList.Spacing = GUI.IntScale(15);
|
||||
@@ -1537,6 +1547,7 @@ namespace Barotrauma
|
||||
|
||||
foreach (Mission mission in GameMain.GameSession.Missions)
|
||||
{
|
||||
if (!mission.Prefab.ShowInMenus) { continue; }
|
||||
GUIFrame missionDescriptionHolder = new GUIFrame(new RectTransform(Vector2.One, missionList.Content.RectTransform), style: null);
|
||||
GUILayoutGroup missionTextGroup = new GUILayoutGroup(new RectTransform(new Vector2(0.744f, 0f), missionDescriptionHolder.RectTransform, Anchor.CenterLeft) { AbsoluteOffset = new Point(iconSize + spacing, 0) }, false, childAnchor: Anchor.TopLeft)
|
||||
{
|
||||
@@ -1774,373 +1785,10 @@ namespace Barotrauma
|
||||
sub.Info.CreateSpecsWindow(specsListBox, GUIStyle.Font, includeTitle: false, includeClass: false, includeDescription: true);
|
||||
}
|
||||
}
|
||||
private Color unselectedColor = new Color(240, 255, 255, 225);
|
||||
private Color unselectableColor = new Color(100, 100, 100, 225);
|
||||
private Color pressedColor = new Color(60, 60, 60, 225);
|
||||
|
||||
private readonly List<(GUIButton button, GUIComponent icon)> talentButtons = new List<(GUIButton button, GUIComponent icon)>();
|
||||
private readonly List<(Identifier talentTree, int index, GUIImage icon, GUIFrame background, GUIFrame backgroundGlow)> talentCornerIcons = new List<(Identifier talentTree, int index, GUIImage icon, GUIFrame background, GUIFrame backgroundGlow)>();
|
||||
private List<Identifier> selectedTalents = new List<Identifier>();
|
||||
|
||||
private GUITextBlock experienceText;
|
||||
private GUIProgressBar experienceBar;
|
||||
private GUITextBlock talentPointText;
|
||||
private GUIListBox skillListBox;
|
||||
|
||||
private GUIButton talentApplyButton,
|
||||
talentResetButton;
|
||||
|
||||
private GUIImage talentPointNotification;
|
||||
|
||||
private readonly ImmutableDictionary<TalentTree.TalentTreeStageState, GUIComponentStyle> talentStageStyles = new Dictionary<TalentTree.TalentTreeStageState, GUIComponentStyle>
|
||||
{
|
||||
{ TalentTree.TalentTreeStageState.Invalid, GUIStyle.GetComponentStyle("TalentTreeLocked") },
|
||||
{ TalentTree.TalentTreeStageState.Locked, GUIStyle.GetComponentStyle("TalentTreeLocked") },
|
||||
{ TalentTree.TalentTreeStageState.Unlocked, GUIStyle.GetComponentStyle("TalentTreePurchased") },
|
||||
{ TalentTree.TalentTreeStageState.Available, GUIStyle.GetComponentStyle("TalentTreeUnlocked") },
|
||||
{ TalentTree.TalentTreeStageState.Highlighted, GUIStyle.GetComponentStyle("TalentTreeAvailable") },
|
||||
}.ToImmutableDictionary();
|
||||
|
||||
private readonly ImmutableDictionary<TalentTree.TalentTreeStageState, Color> talentStageBackgroundColors = new Dictionary<TalentTree.TalentTreeStageState, Color>
|
||||
{
|
||||
{ TalentTree.TalentTreeStageState.Invalid, new Color(48,48,48,255) },
|
||||
{ TalentTree.TalentTreeStageState.Locked, new Color(48,48,48,255) },
|
||||
{ TalentTree.TalentTreeStageState.Unlocked, new Color(24,37,31,255) },
|
||||
{ TalentTree.TalentTreeStageState.Available, new Color(50,47,33,255) },
|
||||
{ TalentTree.TalentTreeStageState.Highlighted, new Color(50,47,33,255) },
|
||||
}.ToImmutableDictionary();
|
||||
|
||||
private void CreateCharacterInfo(GUIFrame infoFrame)
|
||||
{
|
||||
infoFrame.ClearChildren();
|
||||
talentButtons.Clear();
|
||||
talentCornerIcons.Clear();
|
||||
|
||||
GUIFrame background = new GUIFrame(new RectTransform(Vector2.One, infoFrame.RectTransform, Anchor.TopCenter), style: "GUIFrameListBox");
|
||||
int padding = GUI.IntScale(15);
|
||||
GUIFrame frame = new GUIFrame(new RectTransform(new Point(background.Rect.Width - padding, background.Rect.Height - padding), infoFrame.RectTransform, Anchor.Center), style: null);
|
||||
|
||||
GUIFrame content = new GUIFrame(new RectTransform(new Vector2(0.98f), frame.RectTransform, Anchor.Center), style: null);
|
||||
|
||||
GUIFrame characterSettingsFrame = null;
|
||||
GUILayoutGroup characterLayout = null;
|
||||
if (!(GameMain.NetworkMember is null))
|
||||
{
|
||||
characterSettingsFrame = new GUIFrame(new RectTransform(Vector2.One, frame.RectTransform), style: null) { Visible = false };
|
||||
characterLayout = new GUILayoutGroup(new RectTransform(Vector2.One, characterSettingsFrame.RectTransform));
|
||||
GUIFrame containerFrame = new GUIFrame(new RectTransform(new Vector2(1f, 0.9f), characterLayout.RectTransform), style: null);
|
||||
GUIFrame playerFrame = new GUIFrame(new RectTransform(new Vector2(0.9f, 0.7f), containerFrame.RectTransform, Anchor.Center), style: null);
|
||||
GameMain.NetLobbyScreen.CreatePlayerFrame(playerFrame, alwaysAllowEditing: true, createPendingText: false);
|
||||
}
|
||||
|
||||
Character controlledCharacter = Character.Controlled;
|
||||
CharacterInfo info = controlledCharacter?.Info ?? GameMain.Client?.CharacterInfo;
|
||||
if (info == null) { return; }
|
||||
|
||||
Job job = info.Job;
|
||||
|
||||
GUILayoutGroup contentLayout = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 1.0f), content.RectTransform, anchor: Anchor.Center), childAnchor: Anchor.TopCenter)
|
||||
{
|
||||
AbsoluteSpacing = GUI.IntScale(10),
|
||||
Stretch = true
|
||||
};
|
||||
|
||||
GUILayoutGroup topLayout = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.3f), contentLayout.RectTransform, Anchor.Center), isHorizontal: true);
|
||||
|
||||
new GUICustomComponent(new RectTransform(new Vector2(0.25f, 1f), topLayout.RectTransform), onDraw: (batch, component) =>
|
||||
{
|
||||
float posY = component.Rect.Center.Y - component.Rect.Width / 2;
|
||||
info.DrawPortrait(batch, new Vector2(component.Rect.X, posY), Vector2.Zero, component.Rect.Width, false, false);
|
||||
});
|
||||
|
||||
GUILayoutGroup nameLayout = new GUILayoutGroup(new RectTransform(new Vector2(0.3f, 1f), topLayout.RectTransform))
|
||||
{
|
||||
AbsoluteSpacing = GUI.IntScale(5),
|
||||
CanBeFocused = true
|
||||
};
|
||||
|
||||
GUITextBlock nameBlock = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), nameLayout.RectTransform), info.Name, font: GUIStyle.SubHeadingFont);
|
||||
|
||||
if (!info.OmitJobInMenus)
|
||||
{
|
||||
nameBlock.TextColor = job.Prefab.UIColor;
|
||||
GUITextBlock jobBlock = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), nameLayout.RectTransform), job.Name, font: GUIStyle.SmallFont) { TextColor = job.Prefab.UIColor };
|
||||
}
|
||||
|
||||
if (info.PersonalityTrait != null)
|
||||
{
|
||||
LocalizedString traitString = TextManager.AddPunctuation(':', TextManager.Get("PersonalityTrait"), info.PersonalityTrait.DisplayName);
|
||||
Vector2 traitSize = GUIStyle.SmallFont.MeasureString(traitString);
|
||||
GUITextBlock traitBlock = new GUITextBlock(new RectTransform(Vector2.One, nameLayout.RectTransform), traitString, font: GUIStyle.SmallFont);
|
||||
traitBlock.RectTransform.NonScaledSize = traitSize.Pad(traitBlock.Padding).ToPoint();
|
||||
}
|
||||
|
||||
IEnumerable<TalentPrefab> talentsOutsideTree = info.GetUnlockedTalentsOutsideTree().Select(e => TalentPrefab.TalentPrefabs.Find(c => c.Identifier == e));
|
||||
if (talentsOutsideTree.Count() > 0)
|
||||
{
|
||||
//spacing
|
||||
new GUIFrame(new RectTransform(new Vector2(1.0f, 0.05f), nameLayout.RectTransform), style: null);
|
||||
|
||||
GUILayoutGroup extraTalentLayout = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.3f), nameLayout.RectTransform), childAnchor: Anchor.TopCenter);
|
||||
|
||||
talentPointText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), extraTalentLayout.RectTransform, anchor: Anchor.Center), TextManager.Get("talentmenu.extratalents"), font: GUIStyle.SubHeadingFont);
|
||||
talentPointText.RectTransform.MaxSize = new Point(int.MaxValue, (int)talentPointText.TextSize.Y);
|
||||
|
||||
var extraTalentList = new GUIListBox(new RectTransform(new Vector2(0.9f, 0.8f), extraTalentLayout.RectTransform, anchor: Anchor.Center), isHorizontal: true)
|
||||
{
|
||||
AutoHideScrollBar = false,
|
||||
ResizeContentToMakeSpaceForScrollBar = false
|
||||
};
|
||||
extraTalentList.ScrollBar.RectTransform.SetPosition(Anchor.BottomCenter, Pivot.TopCenter);
|
||||
extraTalentList.RectTransform.MinSize = new Point(0, GUI.IntScale(65));
|
||||
extraTalentLayout.Recalculate();
|
||||
extraTalentList.ForceLayoutRecalculation();
|
||||
|
||||
foreach (var extraTalent in talentsOutsideTree)
|
||||
{
|
||||
var img = new GUIImage(new RectTransform(new Point(extraTalentList.Content.Rect.Height), extraTalentList.Content.RectTransform), sprite: extraTalent.Icon, scaleToFit: true)
|
||||
{
|
||||
ToolTip = RichString.Rich($"‖color:{Color.White.ToStringHex()}‖{extraTalent.DisplayName}‖color:end‖" + "\n\n" + extraTalent.Description),
|
||||
Color = GUIStyle.Green
|
||||
};
|
||||
img.RectTransform.SizeChanged += () =>
|
||||
{
|
||||
img.RectTransform.MaxSize = new Point(img.Rect.Height);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
GUILayoutGroup skillLayout = new GUILayoutGroup(new RectTransform(new Vector2(0.45f, 1f), topLayout.RectTransform), childAnchor: Anchor.TopRight)
|
||||
{
|
||||
AbsoluteSpacing = GUI.IntScale(5),
|
||||
Stretch = true
|
||||
};
|
||||
|
||||
GUITextBlock skillBlock = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), skillLayout.RectTransform), TextManager.Get("skills"), font: GUIStyle.SubHeadingFont);
|
||||
|
||||
skillListBox = new GUIListBox(new RectTransform(new Vector2(1f, 1f - skillBlock.RectTransform.RelativeSize.Y), skillLayout.RectTransform), style: null);
|
||||
CreateSkillList(controlledCharacter, info, skillListBox);
|
||||
|
||||
new GUIFrame(new RectTransform(new Vector2(1f, 1f), contentLayout.RectTransform), style: "HorizontalLine");
|
||||
|
||||
GUIListBox talentTreeListBox = new GUIListBox(new RectTransform(new Vector2(1f, 0.6f), contentLayout.RectTransform, Anchor.TopCenter), isHorizontal: true, style: null);
|
||||
|
||||
if (controlledCharacter == null)
|
||||
{
|
||||
talentTreeListBox.Enabled = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!TalentTree.JobTalentTrees.TryGet(info.Job.Prefab.Identifier, out TalentTree talentTree)) { return; }
|
||||
|
||||
selectedTalents = info.GetUnlockedTalentsInTree().ToList();
|
||||
|
||||
List<GUITextBlock> subTreeNames = new List<GUITextBlock>();
|
||||
foreach (var subTree in talentTree.TalentSubTrees)
|
||||
{
|
||||
GUIFrame subTreeFrame = new GUIFrame(new RectTransform(new Vector2(0.333f, 1f), talentTreeListBox.Content.RectTransform, anchor: Anchor.TopLeft), style: null);
|
||||
GUILayoutGroup subTreeLayoutGroup = new GUILayoutGroup(new RectTransform(new Vector2(1f, 1f), subTreeFrame.RectTransform, Anchor.Center), false, childAnchor: Anchor.TopCenter);
|
||||
|
||||
GUIFrame subtreeTitleFrame = new GUIFrame(new RectTransform(new Vector2(1f, 0.111f), subTreeLayoutGroup.RectTransform, anchor: Anchor.TopCenter), style: null);
|
||||
int elementPadding = GUI.IntScale(8);
|
||||
Point headerSize = subtreeTitleFrame.RectTransform.NonScaledSize;
|
||||
GUIFrame subTreeTitleBackground = new GUIFrame(new RectTransform(new Point(headerSize.X - elementPadding, headerSize.Y), subtreeTitleFrame.RectTransform, anchor: Anchor.Center), style: "SubtreeHeader");
|
||||
subTreeNames.Add(new GUITextBlock(new RectTransform(Vector2.One, subTreeTitleBackground.RectTransform, anchor: Anchor.TopCenter), subTree.DisplayName, font: GUIStyle.SubHeadingFont, textAlignment: Alignment.Center));
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
GUIFrame talentOptionFrame = new GUIFrame(new RectTransform(new Vector2(1f, 0.222f), subTreeLayoutGroup.RectTransform, anchor: Anchor.TopCenter), style: null);
|
||||
|
||||
Point talentFrameSize = talentOptionFrame.RectTransform.NonScaledSize;
|
||||
|
||||
GUIFrame talentBackground = new GUIFrame(new RectTransform(new Point(talentFrameSize.X - elementPadding, talentFrameSize.Y - elementPadding), talentOptionFrame.RectTransform, anchor: Anchor.Center), style: "TalentBackground")
|
||||
{
|
||||
Color = talentStageBackgroundColors[TalentTree.TalentTreeStageState.Locked]
|
||||
};
|
||||
GUIFrame talentBackgroundHighlight = new GUIFrame(new RectTransform(Vector2.One, talentBackground.RectTransform, anchor: Anchor.Center), style: "TalentBackgroundGlow") { Visible = false };
|
||||
|
||||
GUIImage cornerIcon = new GUIImage(new RectTransform(new Vector2(0.2f), talentOptionFrame.RectTransform, anchor: Anchor.BottomRight, scaleBasis: ScaleBasis.BothHeight) { MaxSize = new Point(16) }, style: null)
|
||||
{
|
||||
CanBeFocused = false,
|
||||
Color = talentStageBackgroundColors[TalentTree.TalentTreeStageState.Locked]
|
||||
};
|
||||
|
||||
Point iconSize = cornerIcon.RectTransform.NonScaledSize;
|
||||
cornerIcon.RectTransform.AbsoluteOffset = new Point(iconSize.X / 2, iconSize.Y / 2);
|
||||
|
||||
if (subTree.TalentOptionStages.Length <= i) { continue; }
|
||||
|
||||
TalentOption talentOption = subTree.TalentOptionStages[i];
|
||||
GUILayoutGroup talentOptionCenterGroup = new GUILayoutGroup(new RectTransform(new Vector2(0.75f, 0.7f), talentOptionFrame.RectTransform, Anchor.Center), childAnchor: Anchor.CenterLeft);
|
||||
GUILayoutGroup talentOptionLayoutGroup = new GUILayoutGroup(new RectTransform(Vector2.One, talentOptionCenterGroup.RectTransform), isHorizontal: true, childAnchor: Anchor.CenterLeft) { Stretch = true };
|
||||
|
||||
foreach (Identifier talentId in talentOption.TalentIdentifiers.OrderBy(t => t))
|
||||
{
|
||||
if (!TalentPrefab.TalentPrefabs.TryGet(talentId, out TalentPrefab talent)) { continue; }
|
||||
GUIFrame talentFrame = new GUIFrame(new RectTransform(Vector2.One, talentOptionLayoutGroup.RectTransform), style: null)
|
||||
{
|
||||
CanBeFocused = false
|
||||
};
|
||||
|
||||
GUIFrame croppedTalentFrame = new GUIFrame(new RectTransform(Vector2.One, talentFrame.RectTransform, anchor: Anchor.Center, scaleBasis: ScaleBasis.BothHeight), style: null);
|
||||
GUIButton talentButton = new GUIButton(new RectTransform(Vector2.One, croppedTalentFrame.RectTransform, anchor: Anchor.Center), style: null)
|
||||
{
|
||||
ToolTip = RichString.Rich($"‖color:{Color.White.ToStringHex()}‖{talent.DisplayName}‖color:end‖" + "\n\n" + talent.Description),
|
||||
UserData = talent.Identifier,
|
||||
PressedColor = pressedColor,
|
||||
Enabled = controlledCharacter != null,
|
||||
OnClicked = (button, userData) =>
|
||||
{
|
||||
// deselect other buttons in tier by removing their selected talents from pool
|
||||
foreach (GUIButton guiButton in talentOptionLayoutGroup.GetAllChildren<GUIButton>())
|
||||
{
|
||||
if (guiButton.UserData is Identifier otherTalentIdentifier && guiButton != button)
|
||||
{
|
||||
if (!controlledCharacter.HasTalent(otherTalentIdentifier))
|
||||
{
|
||||
selectedTalents.Remove(otherTalentIdentifier);
|
||||
}
|
||||
}
|
||||
}
|
||||
Identifier talentIdentifier = (Identifier)userData;
|
||||
|
||||
if (TalentTree.IsViableTalentForCharacter(controlledCharacter, talentIdentifier, selectedTalents))
|
||||
{
|
||||
if (!selectedTalents.Contains(talentIdentifier))
|
||||
{
|
||||
selectedTalents.Add(talentIdentifier);
|
||||
}
|
||||
}
|
||||
else if (!controlledCharacter.HasTalent(talentIdentifier))
|
||||
{
|
||||
selectedTalents.Remove(talentIdentifier);
|
||||
}
|
||||
|
||||
UpdateTalentInfo();
|
||||
return true;
|
||||
},
|
||||
};
|
||||
|
||||
talentButton.Color = talentButton.HoverColor = talentButton.PressedColor = talentButton.SelectedColor = talentButton.DisabledColor = Color.Transparent;
|
||||
|
||||
GUIComponent iconImage;
|
||||
if (talent.Icon is null)
|
||||
{
|
||||
iconImage = new GUITextBlock(new RectTransform(Vector2.One, talentButton.RectTransform, anchor: Anchor.Center), text: "???", font: GUIStyle.LargeFont, textAlignment: Alignment.Center, style: null)
|
||||
{
|
||||
OutlineColor = GUIStyle.Red,
|
||||
TextColor = GUIStyle.Red,
|
||||
PressedColor = unselectableColor,
|
||||
DisabledColor = unselectableColor,
|
||||
CanBeFocused = false,
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
iconImage = new GUIImage(new RectTransform(Vector2.One, talentButton.RectTransform, anchor: Anchor.Center), sprite: talent.Icon, scaleToFit: true)
|
||||
{
|
||||
PressedColor = unselectableColor,
|
||||
DisabledColor = unselectableColor * 0.5f,
|
||||
CanBeFocused = false,
|
||||
};
|
||||
}
|
||||
iconImage.Enabled = talentButton.Enabled;
|
||||
talentButtons.Add((talentButton, iconImage));
|
||||
}
|
||||
talentCornerIcons.Add((subTree.Identifier, i, cornerIcon, talentBackground, talentBackgroundHighlight));
|
||||
}
|
||||
}
|
||||
GUITextBlock.AutoScaleAndNormalize(subTreeNames);
|
||||
|
||||
GUILayoutGroup bottomLayout = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.07f), contentLayout.RectTransform, Anchor.TopCenter), isHorizontal: true)
|
||||
{
|
||||
RelativeSpacing = 0.01f,
|
||||
Stretch = true
|
||||
};
|
||||
|
||||
GUILayoutGroup experienceLayout = new GUILayoutGroup(new RectTransform(new Vector2(0.59f, 1f), bottomLayout.RectTransform));
|
||||
GUIFrame experienceBarFrame = new GUIFrame(new RectTransform(new Vector2(1f, 0.5f), experienceLayout.RectTransform), style: null);
|
||||
|
||||
experienceBar = new GUIProgressBar(new RectTransform(new Vector2(1f, 1f), experienceBarFrame.RectTransform, Anchor.CenterLeft),
|
||||
barSize: info.GetProgressTowardsNextLevel(), color: GUIStyle.Green)
|
||||
{
|
||||
IsHorizontal = true,
|
||||
};
|
||||
|
||||
experienceText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 1.0f), experienceBarFrame.RectTransform, anchor: Anchor.Center), "", font: GUIStyle.Font, textAlignment: Alignment.CenterRight)
|
||||
{
|
||||
Shadow = true,
|
||||
ToolTip = TextManager.Get("experiencetooltip")
|
||||
};
|
||||
|
||||
talentPointText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.5f), experienceLayout.RectTransform, anchor: Anchor.Center), "", font: GUIStyle.SubHeadingFont, textAlignment: Alignment.CenterRight) { AutoScaleVertical = true };
|
||||
|
||||
talentResetButton = new GUIButton(new RectTransform(new Vector2(0.19f, 1f), bottomLayout.RectTransform), text: TextManager.Get("reset"), style: "GUIButtonFreeScale")
|
||||
{
|
||||
OnClicked = ResetTalentSelection
|
||||
};
|
||||
talentApplyButton = new GUIButton(new RectTransform(new Vector2(0.19f, 1f), bottomLayout.RectTransform), text: TextManager.Get("applysettingsbutton"), style: "GUIButtonFreeScale")
|
||||
{
|
||||
OnClicked = ApplyTalentSelection,
|
||||
};
|
||||
GUITextBlock.AutoScaleAndNormalize(talentResetButton.TextBlock, talentApplyButton.TextBlock);
|
||||
}
|
||||
|
||||
if (!(GameMain.NetworkMember is null))
|
||||
{
|
||||
GUIButton newCharacterBox = new GUIButton(new RectTransform(new Vector2(0.5f, 0.2f), skillLayout.RectTransform, Anchor.BottomRight),
|
||||
text: GameMain.NetLobbyScreen.CampaignCharacterDiscarded ? TextManager.Get("settings") : TextManager.Get("createnew"), style: "GUIButtonSmall")
|
||||
{
|
||||
IgnoreLayoutGroups = false
|
||||
};
|
||||
newCharacterBox.TextBlock.AutoScaleHorizontal = true;
|
||||
|
||||
newCharacterBox.OnClicked = (button, o) =>
|
||||
{
|
||||
if (!GameMain.NetLobbyScreen.CampaignCharacterDiscarded)
|
||||
{
|
||||
GameMain.NetLobbyScreen.TryDiscardCampaignCharacter(() =>
|
||||
{
|
||||
newCharacterBox.Text = TextManager.Get("settings");
|
||||
if (pendingChangesFrame != null)
|
||||
{
|
||||
NetLobbyScreen.CreateChangesPendingFrame(pendingChangesFrame);
|
||||
}
|
||||
OpenMenu();
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
OpenMenu();
|
||||
return true;
|
||||
|
||||
void OpenMenu()
|
||||
{
|
||||
characterSettingsFrame!.Visible = true;
|
||||
content.Visible = false;
|
||||
}
|
||||
};
|
||||
|
||||
if (!(characterLayout is null))
|
||||
{
|
||||
GUILayoutGroup characterCloseButtonLayout = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.1f), characterLayout.RectTransform), childAnchor: Anchor.BottomCenter);
|
||||
new GUIButton(new RectTransform(new Vector2(0.4f, 1f), characterCloseButtonLayout.RectTransform), TextManager.Get("ApplySettingsButton")) //TODO: Is this text appropriate for this circumstance for all languages?
|
||||
{
|
||||
OnClicked = (button, o) =>
|
||||
{
|
||||
GameMain.Client?.SendCharacterInfo(GameMain.Client.PendingName);
|
||||
characterSettingsFrame!.Visible = false;
|
||||
content.Visible = true;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
UpdateTalentInfo();
|
||||
}
|
||||
|
||||
private void CreateSkillList(Character character, CharacterInfo info, GUIListBox parent)
|
||||
public static void CreateSkillList(Character character, CharacterInfo info, GUIListBox parent)
|
||||
{
|
||||
parent.Content.ClearChildren();
|
||||
List<GUITextBlock> skillNames = new List<GUITextBlock>();
|
||||
@@ -2154,10 +1802,10 @@ namespace Barotrauma
|
||||
|
||||
new GUITextBlock(new RectTransform(new Vector2(0.15f, 1.0f), skillContainer.RectTransform), Math.Floor(skill.Level).ToString("F0"), textAlignment: Alignment.TopRight);
|
||||
|
||||
float modifiedSkillLevel = character?.GetSkillLevel(skill.Identifier) ?? skill.Level;
|
||||
float modifiedSkillLevel = MathF.Floor(character?.GetSkillLevel(skill.Identifier) ?? skill.Level);
|
||||
if (!MathUtils.NearlyEqual(MathF.Floor(modifiedSkillLevel), MathF.Floor(skill.Level)))
|
||||
{
|
||||
int skillChange = (int)MathF.Floor(modifiedSkillLevel - skill.Level);
|
||||
int skillChange = (int)MathF.Floor(modifiedSkillLevel - MathF.Floor(skill.Level));
|
||||
string stringColor = skillChange switch
|
||||
{
|
||||
> 0 => XMLExtensions.ToStringHex(GUIStyle.Green),
|
||||
@@ -2168,123 +1816,17 @@ namespace Barotrauma
|
||||
RichString changeText = RichString.Rich($"(‖color:{stringColor}‖{(skillChange > 0 ? "+" : string.Empty) + skillChange}‖color:end‖)");
|
||||
new GUITextBlock(new RectTransform(new Vector2(0.15f, 1.0f), skillContainer.RectTransform), changeText) { Padding = Vector4.Zero };
|
||||
}
|
||||
//skillContainer.Recalculate();
|
||||
skillContainer.Recalculate();
|
||||
}
|
||||
|
||||
parent.RecalculateChildren();
|
||||
GUITextBlock.AutoScaleAndNormalize(skillNames);
|
||||
}
|
||||
|
||||
private void UpdateTalentInfo()
|
||||
{
|
||||
Character controlledCharacter = Character.Controlled;
|
||||
if (controlledCharacter?.Info == null) { return; }
|
||||
|
||||
if (SelectedTab != InfoFrameTab.Talents) { return; }
|
||||
|
||||
bool unlockedAllTalents = controlledCharacter.HasUnlockedAllTalents();
|
||||
|
||||
if (unlockedAllTalents)
|
||||
{
|
||||
experienceText.Text = string.Empty;
|
||||
experienceBar.BarSize = 1f;
|
||||
}
|
||||
else
|
||||
{
|
||||
experienceText.Text = $"{controlledCharacter.Info.ExperiencePoints - controlledCharacter.Info.GetExperienceRequiredForCurrentLevel()} / {controlledCharacter.Info.GetExperienceRequiredToLevelUp() - controlledCharacter.Info.GetExperienceRequiredForCurrentLevel()}";
|
||||
experienceBar.BarSize = controlledCharacter.Info.GetProgressTowardsNextLevel();
|
||||
}
|
||||
|
||||
selectedTalents = TalentTree.CheckTalentSelection(controlledCharacter, selectedTalents);
|
||||
|
||||
string pointsLeft = controlledCharacter.Info.GetAvailableTalentPoints().ToString();
|
||||
|
||||
int talentCount = selectedTalents.Count - controlledCharacter.Info.GetUnlockedTalentsInTree().Count();
|
||||
|
||||
if (unlockedAllTalents)
|
||||
{
|
||||
talentPointText.SetRichText($"‖color:{XMLExtensions.ToStringHex(Color.Gray)}‖{TextManager.Get("talentmenu.alltalentsunlocked")}‖color:end‖");
|
||||
}
|
||||
else if (talentCount > 0)
|
||||
{
|
||||
string pointsUsed = $"‖color:{XMLExtensions.ColorToString(GUIStyle.Red)}‖{-talentCount}‖color:end‖";
|
||||
LocalizedString localizedString = TextManager.GetWithVariables("talentmenu.points.spending", ("[amount]", pointsLeft), ("[used]", pointsUsed));
|
||||
talentPointText.SetRichText(localizedString);
|
||||
}
|
||||
else
|
||||
{
|
||||
talentPointText.SetRichText(TextManager.GetWithVariable("talentmenu.points", "[amount]", pointsLeft));
|
||||
}
|
||||
|
||||
foreach (var (talentTree, index, icon, frame, glow) in talentCornerIcons)
|
||||
{
|
||||
TalentTree.TalentTreeStageState state = TalentTree.GetTalentOptionStageState(controlledCharacter, talentTree, index, selectedTalents);
|
||||
GUIComponentStyle newStyle = talentStageStyles[state];
|
||||
icon.ApplyStyle(newStyle);
|
||||
icon.Color = newStyle.Color;
|
||||
frame.Color = talentStageBackgroundColors[state];
|
||||
glow.Visible = state == TalentTree.TalentTreeStageState.Highlighted;
|
||||
}
|
||||
|
||||
foreach (var talentButton in talentButtons)
|
||||
{
|
||||
Identifier talentIdentifier = (Identifier)talentButton.button.UserData;
|
||||
bool unselectable = !TalentTree.IsViableTalentForCharacter(controlledCharacter, talentIdentifier, selectedTalents) || controlledCharacter.HasTalent(talentIdentifier);
|
||||
Color newTalentColor = unselectable ? unselectableColor : unselectedColor;
|
||||
Color hoverColor = Color.White;
|
||||
|
||||
if (controlledCharacter.HasTalent(talentIdentifier))
|
||||
{
|
||||
newTalentColor = GUIStyle.Green;
|
||||
}
|
||||
else if (selectedTalents.Contains(talentIdentifier))
|
||||
{
|
||||
newTalentColor = GUIStyle.Orange;
|
||||
hoverColor = Color.Lerp(GUIStyle.Orange, Color.White, 0.7f);
|
||||
}
|
||||
|
||||
talentButton.icon.Color = newTalentColor;
|
||||
talentButton.icon.HoverColor = hoverColor;
|
||||
}
|
||||
|
||||
CreateSkillList(controlledCharacter, controlledCharacter.Info, skillListBox);
|
||||
}
|
||||
|
||||
private void ApplyTalents(Character controlledCharacter)
|
||||
{
|
||||
selectedTalents = TalentTree.CheckTalentSelection(controlledCharacter, selectedTalents);
|
||||
foreach (Identifier talent in selectedTalents)
|
||||
{
|
||||
controlledCharacter.GiveTalent(talent);
|
||||
if (GameMain.Client != null)
|
||||
{
|
||||
GameMain.Client.CreateEntityEvent(controlledCharacter, new Character.UpdateTalentsEventData());
|
||||
}
|
||||
}
|
||||
selectedTalents = controlledCharacter.Info.GetUnlockedTalentsInTree().ToList();
|
||||
UpdateTalentInfo();
|
||||
}
|
||||
|
||||
private bool ApplyTalentSelection(GUIButton guiButton, object userData)
|
||||
{
|
||||
Character controlledCharacter = Character.Controlled;
|
||||
ApplyTalents(controlledCharacter);
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool ResetTalentSelection(GUIButton guiButton, object userData)
|
||||
{
|
||||
Character controlledCharacter = Character.Controlled;
|
||||
if (controlledCharacter?.Info == null) { return false; }
|
||||
selectedTalents = controlledCharacter.Info.GetUnlockedTalentsInTree().ToList();
|
||||
UpdateTalentInfo();
|
||||
return true;
|
||||
}
|
||||
|
||||
public void OnExperienceChanged(Character character)
|
||||
{
|
||||
if (character != Character.Controlled) { return; }
|
||||
UpdateTalentInfo();
|
||||
talentMenu.UpdateTalentInfo();
|
||||
}
|
||||
|
||||
public void OnClose()
|
||||
|
||||
@@ -0,0 +1,805 @@
|
||||
#nullable enable
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using Barotrauma.Extensions;
|
||||
using Barotrauma.Networking;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Input;
|
||||
using static Barotrauma.TalentTree;
|
||||
using static Barotrauma.TalentTree.TalentStages;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
internal readonly record struct TalentShowCaseButton(ImmutableHashSet<TalentButton> Buttons,
|
||||
GUIComponent IconComponent);
|
||||
|
||||
internal readonly record struct TalentButton(GUIComponent IconComponent,
|
||||
TalentPrefab Prefab)
|
||||
{
|
||||
public Identifier Identifier => Prefab.Identifier;
|
||||
}
|
||||
|
||||
internal readonly record struct TalentCornerIcon(Identifier TalentTree,
|
||||
int Index,
|
||||
GUIImage IconComponent,
|
||||
GUIFrame BackgroundComponent,
|
||||
GUIFrame GlowComponent);
|
||||
|
||||
internal readonly struct TalentTreeStyle
|
||||
{
|
||||
public readonly GUIComponentStyle ComponentStyle;
|
||||
public readonly Color Color;
|
||||
|
||||
public TalentTreeStyle(string componentStyle, Color color)
|
||||
{
|
||||
ComponentStyle = GUIStyle.GetComponentStyle(componentStyle);
|
||||
Color = color;
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class TalentMenu
|
||||
{
|
||||
public const string ManageBotTalentsButtonUserData = "managebottalentsbutton";
|
||||
|
||||
private Character? character;
|
||||
private CharacterInfo? characterInfo;
|
||||
|
||||
private static readonly Color unselectedColor = new Color(240, 255, 255, 225),
|
||||
unselectableColor = new Color(100, 100, 100, 225),
|
||||
pressedColor = new Color(60, 60, 60, 225),
|
||||
lockedColor = new Color(48, 48, 48, 255),
|
||||
unlockedColor = new Color(24, 37, 31, 255),
|
||||
availableColor = new Color(50, 47, 33, 255);
|
||||
|
||||
private static readonly ImmutableDictionary<TalentStages, TalentTreeStyle> talentStageStyles =
|
||||
new Dictionary<TalentStages, TalentTreeStyle>
|
||||
{
|
||||
[Invalid] = new TalentTreeStyle("TalentTreeLocked", lockedColor),
|
||||
[Locked] = new TalentTreeStyle("TalentTreeLocked", lockedColor),
|
||||
[Unlocked] = new TalentTreeStyle("TalentTreePurchased", unlockedColor),
|
||||
[Available] = new TalentTreeStyle("TalentTreeUnlocked", availableColor),
|
||||
[Highlighted] = new TalentTreeStyle("TalentTreeAvailable", availableColor)
|
||||
}.ToImmutableDictionary();
|
||||
|
||||
private readonly HashSet<TalentButton> talentButtons = new HashSet<TalentButton>();
|
||||
private readonly HashSet<TalentShowCaseButton> talentShowCaseButtons = new HashSet<TalentShowCaseButton>();
|
||||
private readonly HashSet<GUIComponent> showCaseTalentFrames = new HashSet<GUIComponent>();
|
||||
private readonly HashSet<TalentCornerIcon> talentCornerIcons = new HashSet<TalentCornerIcon>();
|
||||
private HashSet<Identifier> selectedTalents = new HashSet<Identifier>();
|
||||
|
||||
private readonly Queue<Identifier> showCaseClosureQueue = new();
|
||||
|
||||
private GUIListBox? skillListBox;
|
||||
private GUITextBlock? talentPointText;
|
||||
private GUIProgressBar? experienceBar;
|
||||
private GUITextBlock? experienceText;
|
||||
private GUILayoutGroup? skillLayout;
|
||||
|
||||
private GUIButton? talentApplyButton,
|
||||
talentResetButton;
|
||||
|
||||
public void CreateGUI(GUIFrame parent, Character? targetCharacter)
|
||||
{
|
||||
parent.ClearChildren();
|
||||
talentButtons.Clear();
|
||||
talentShowCaseButtons.Clear();
|
||||
talentCornerIcons.Clear();
|
||||
showCaseTalentFrames.Clear();
|
||||
|
||||
character = targetCharacter;
|
||||
characterInfo = targetCharacter?.Info;
|
||||
|
||||
GUIFrame background = new GUIFrame(new RectTransform(Vector2.One, parent.RectTransform, Anchor.TopCenter), style: "GUIFrameListBox");
|
||||
int padding = GUI.IntScale(15);
|
||||
GUIFrame frame = new GUIFrame(new RectTransform(new Point(background.Rect.Width - padding, background.Rect.Height - padding), parent.RectTransform, Anchor.Center), style: null);
|
||||
|
||||
GUIFrame content = new GUIFrame(new RectTransform(new Vector2(0.98f), frame.RectTransform, Anchor.Center), style: null);
|
||||
|
||||
GUILayoutGroup contentLayout = new GUILayoutGroup(new RectTransform(Vector2.One, content.RectTransform, anchor: Anchor.Center), childAnchor: Anchor.TopCenter)
|
||||
{
|
||||
AbsoluteSpacing = GUI.IntScale(10),
|
||||
Stretch = true
|
||||
};
|
||||
|
||||
if (characterInfo is null) { return; }
|
||||
|
||||
CreateStatPanel(contentLayout, characterInfo);
|
||||
|
||||
new GUIFrame(new RectTransform(new Vector2(1f, 1f), contentLayout.RectTransform), style: "HorizontalLine");
|
||||
|
||||
if (JobTalentTrees.TryGet(characterInfo.Job.Prefab.Identifier, out TalentTree? talentTree))
|
||||
{
|
||||
CreateTalentMenu(contentLayout, characterInfo, talentTree!);
|
||||
}
|
||||
|
||||
CreateFooter(contentLayout, characterInfo);
|
||||
UpdateTalentInfo();
|
||||
|
||||
if (GameMain.NetworkMember != null && IsOwnCharacter(characterInfo))
|
||||
{
|
||||
CreateMultiplayerCharacterSettings(frame, content);
|
||||
}
|
||||
}
|
||||
|
||||
private void CreateMultiplayerCharacterSettings(GUIComponent parent, GUIComponent content)
|
||||
{
|
||||
if (skillLayout is null) { return; }
|
||||
|
||||
GUIFrame characterSettingsFrame = new GUIFrame(new RectTransform(Vector2.One, parent.RectTransform), style: null) { Visible = false };
|
||||
GUILayoutGroup characterLayout = new GUILayoutGroup(new RectTransform(Vector2.One, characterSettingsFrame.RectTransform));
|
||||
GUIFrame containerFrame = new GUIFrame(new RectTransform(new Vector2(1f, 0.9f), characterLayout.RectTransform), style: null);
|
||||
GUIFrame playerFrame = new GUIFrame(new RectTransform(new Vector2(0.9f, 0.7f), containerFrame.RectTransform, Anchor.Center), style: null);
|
||||
GameMain.NetLobbyScreen.CreatePlayerFrame(playerFrame, alwaysAllowEditing: true, createPendingText: false);
|
||||
|
||||
GUIButton newCharacterBox = new GUIButton(new RectTransform(new Vector2(0.5f, 0.2f), skillLayout.RectTransform, Anchor.BottomRight),
|
||||
text: GameMain.NetLobbyScreen.CampaignCharacterDiscarded ? TextManager.Get("settings") : TextManager.Get("createnew"), style: "GUIButtonSmall")
|
||||
{
|
||||
IgnoreLayoutGroups = false,
|
||||
TextBlock =
|
||||
{
|
||||
AutoScaleHorizontal = true
|
||||
}
|
||||
};
|
||||
|
||||
newCharacterBox.OnClicked = (button, o) =>
|
||||
{
|
||||
if (!GameMain.NetLobbyScreen.CampaignCharacterDiscarded)
|
||||
{
|
||||
GameMain.NetLobbyScreen.TryDiscardCampaignCharacter(() =>
|
||||
{
|
||||
newCharacterBox.Text = TextManager.Get("settings");
|
||||
if (TabMenu.PendingChangesFrame != null)
|
||||
{
|
||||
NetLobbyScreen.CreateChangesPendingFrame(TabMenu.PendingChangesFrame);
|
||||
}
|
||||
|
||||
OpenMenu();
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
OpenMenu();
|
||||
return true;
|
||||
|
||||
void OpenMenu()
|
||||
{
|
||||
characterSettingsFrame!.Visible = true;
|
||||
content.Visible = false;
|
||||
}
|
||||
};
|
||||
|
||||
GUILayoutGroup characterCloseButtonLayout = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.1f), characterLayout.RectTransform), childAnchor: Anchor.BottomCenter);
|
||||
new GUIButton(new RectTransform(new Vector2(0.4f, 1f), characterCloseButtonLayout.RectTransform), TextManager.Get("ApplySettingsButton")) //TODO: Is this text appropriate for this circumstance for all languages?
|
||||
{
|
||||
OnClicked = (button, o) =>
|
||||
{
|
||||
GameMain.Client?.SendCharacterInfo(GameMain.Client.PendingName);
|
||||
characterSettingsFrame.Visible = false;
|
||||
content.Visible = true;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void CreateStatPanel(GUIComponent parent, CharacterInfo info)
|
||||
{
|
||||
Job job = info.Job;
|
||||
|
||||
GUILayoutGroup topLayout = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.3f), parent.RectTransform, Anchor.Center), isHorizontal: true);
|
||||
|
||||
new GUICustomComponent(new RectTransform(new Vector2(0.25f, 1f), topLayout.RectTransform), onDraw: (batch, component) =>
|
||||
{
|
||||
info.DrawPortrait(batch, component.Rect.Location.ToVector2(), Vector2.Zero, component.Rect.Width, false, false);
|
||||
});
|
||||
|
||||
GUILayoutGroup nameLayout = new GUILayoutGroup(new RectTransform(new Vector2(0.3f, 1f), topLayout.RectTransform))
|
||||
{
|
||||
AbsoluteSpacing = GUI.IntScale(5),
|
||||
CanBeFocused = true
|
||||
};
|
||||
|
||||
GUITextBlock nameBlock = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), nameLayout.RectTransform), info.Name, font: GUIStyle.SubHeadingFont);
|
||||
|
||||
if (!info.OmitJobInMenus)
|
||||
{
|
||||
nameBlock.TextColor = job.Prefab.UIColor;
|
||||
GUITextBlock jobBlock = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), nameLayout.RectTransform), job.Name, font: GUIStyle.SmallFont) { TextColor = job.Prefab.UIColor };
|
||||
}
|
||||
|
||||
if (info.PersonalityTrait != null)
|
||||
{
|
||||
LocalizedString traitString = TextManager.AddPunctuation(':', TextManager.Get("PersonalityTrait"), info.PersonalityTrait.DisplayName);
|
||||
Vector2 traitSize = GUIStyle.SmallFont.MeasureString(traitString);
|
||||
GUITextBlock traitBlock = new GUITextBlock(new RectTransform(Vector2.One, nameLayout.RectTransform), traitString, font: GUIStyle.SmallFont);
|
||||
traitBlock.RectTransform.NonScaledSize = traitSize.Pad(traitBlock.Padding).ToPoint();
|
||||
}
|
||||
|
||||
ImmutableHashSet<TalentPrefab?> talentsOutsideTree = info.GetUnlockedTalentsOutsideTree().Select(static e => TalentPrefab.TalentPrefabs.Find(c => c.Identifier == e)).ToImmutableHashSet();
|
||||
if (talentsOutsideTree.Any())
|
||||
{
|
||||
//spacing
|
||||
new GUIFrame(new RectTransform(new Vector2(1.0f, 0.01f), nameLayout.RectTransform), style: null);
|
||||
|
||||
GUILayoutGroup extraTalentLayout = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.55f), nameLayout.RectTransform), childAnchor: Anchor.TopCenter);
|
||||
|
||||
talentPointText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.3f), extraTalentLayout.RectTransform, anchor: Anchor.Center), TextManager.Get("talentmenu.extratalents"), font: GUIStyle.SubHeadingFont)
|
||||
{
|
||||
AutoScaleVertical = true
|
||||
};
|
||||
talentPointText.RectTransform.MaxSize = new Point(int.MaxValue, (int)talentPointText.TextSize.Y);
|
||||
|
||||
var extraTalentList = new GUIListBox(new RectTransform(new Vector2(0.9f, 0.7f), extraTalentLayout.RectTransform, anchor: Anchor.Center), isHorizontal: true)
|
||||
{
|
||||
AutoHideScrollBar = false,
|
||||
ResizeContentToMakeSpaceForScrollBar = false
|
||||
};
|
||||
extraTalentList.ScrollBar.RectTransform.SetPosition(Anchor.BottomCenter, Pivot.TopCenter);
|
||||
extraTalentLayout.Recalculate();
|
||||
extraTalentList.ForceLayoutRecalculation();
|
||||
|
||||
foreach (var extraTalent in talentsOutsideTree)
|
||||
{
|
||||
if (extraTalent is null) { continue; }
|
||||
GUIImage talentImg = new GUIImage(new RectTransform(Vector2.One, extraTalentList.Content.RectTransform, scaleBasis: ScaleBasis.BothHeight), sprite: extraTalent.Icon, scaleToFit: true)
|
||||
{
|
||||
ToolTip = RichString.Rich($"‖color:{Color.White.ToStringHex()}‖{extraTalent.DisplayName}‖color:end‖" + "\n\n" + ToolBox.ExtendColorToPercentageSigns(extraTalent.Description.Value)),
|
||||
Color = GUIStyle.Green
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
skillLayout = new GUILayoutGroup(new RectTransform(new Vector2(0.45f, 1f), topLayout.RectTransform), childAnchor: Anchor.TopRight)
|
||||
{
|
||||
AbsoluteSpacing = GUI.IntScale(5),
|
||||
Stretch = true
|
||||
};
|
||||
|
||||
GUITextBlock skillBlock = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), skillLayout.RectTransform), TextManager.Get("skills"), font: GUIStyle.SubHeadingFont);
|
||||
|
||||
skillListBox = new GUIListBox(new RectTransform(new Vector2(1f, 1f - skillBlock.RectTransform.RelativeSize.Y), skillLayout.RectTransform), style: null);
|
||||
TabMenu.CreateSkillList(info.Character, info, skillListBox);
|
||||
}
|
||||
|
||||
private void CreateTalentMenu(GUIComponent parent, CharacterInfo info, TalentTree tree)
|
||||
{
|
||||
GUIListBox mainList = new GUIListBox(new RectTransform(new Vector2(1f, 0.9f), parent.RectTransform, anchor: Anchor.TopCenter));
|
||||
|
||||
selectedTalents = info.GetUnlockedTalentsInTree().ToHashSet();
|
||||
|
||||
List<GUITextBlock> subTreeNames = new List<GUITextBlock>();
|
||||
foreach (var subTree in tree.TalentSubTrees)
|
||||
{
|
||||
GUIListBox talentList;
|
||||
GUIComponent talentParent;
|
||||
Vector2 treeSize;
|
||||
switch (subTree.Type)
|
||||
{
|
||||
case TalentTreeType.Primary:
|
||||
talentList = mainList;
|
||||
treeSize = new Vector2(1f, 0.5f);
|
||||
break;
|
||||
case TalentTreeType.Specialization:
|
||||
talentList = GetSpecializationList();
|
||||
treeSize = new Vector2(0.333f, 1f);
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException($"Invalid TalentTreeType \"{subTree.Type}\"");
|
||||
}
|
||||
talentParent = talentList.Content;
|
||||
|
||||
GUILayoutGroup subTreeLayoutGroup = new GUILayoutGroup(new RectTransform(treeSize, talentParent.RectTransform), isHorizontal: false, childAnchor: Anchor.TopCenter)
|
||||
{
|
||||
Stretch = true
|
||||
};
|
||||
|
||||
if (subTree.Type != TalentTreeType.Primary)
|
||||
{
|
||||
GUIFrame subtreeTitleFrame = new GUIFrame(new RectTransform(new Vector2(1f, 0.05f), subTreeLayoutGroup.RectTransform, anchor: Anchor.TopCenter)
|
||||
{ MinSize = new Point(0, GUI.IntScale(30)) }, style: null);
|
||||
subtreeTitleFrame.RectTransform.IsFixedSize = true;
|
||||
int elementPadding = GUI.IntScale(8);
|
||||
Point headerSize = subtreeTitleFrame.RectTransform.NonScaledSize;
|
||||
GUIFrame subTreeTitleBackground = new GUIFrame(new RectTransform(new Point(headerSize.X - elementPadding, headerSize.Y), subtreeTitleFrame.RectTransform, anchor: Anchor.Center), style: "SubtreeHeader");
|
||||
subTreeNames.Add(new GUITextBlock(new RectTransform(Vector2.One, subTreeTitleBackground.RectTransform, anchor: Anchor.TopCenter), subTree.DisplayName, font: GUIStyle.SubHeadingFont, textAlignment: Alignment.Center));
|
||||
}
|
||||
|
||||
int optionAmount = subTree.TalentOptionStages.Length;
|
||||
for (int i = 0; i < optionAmount; i++)
|
||||
{
|
||||
TalentOption option = subTree.TalentOptionStages[i];
|
||||
CreateTalentOption(subTreeLayoutGroup, subTree, i, option, info);
|
||||
}
|
||||
subTreeLayoutGroup.RectTransform.Resize(new Point(subTreeLayoutGroup.Rect.Width,
|
||||
subTreeLayoutGroup.Children.Sum(c => c.Rect.Height + subTreeLayoutGroup.AbsoluteSpacing)));
|
||||
subTreeLayoutGroup.RectTransform.MinSize = new Point(subTreeLayoutGroup.Rect.Width, subTreeLayoutGroup.Rect.Height);
|
||||
subTreeLayoutGroup.Recalculate();
|
||||
|
||||
if (subTree.Type == TalentTreeType.Specialization)
|
||||
{
|
||||
talentList.RectTransform.Resize(new Point(talentList.Rect.Width, Math.Max(subTreeLayoutGroup.Rect.Height, talentList.Rect.Height)));
|
||||
talentList.RectTransform.MinSize = new Point(0, talentList.Rect.Height);
|
||||
}
|
||||
}
|
||||
|
||||
var specializationList = GetSpecializationList();
|
||||
GetSpecializationList().RectTransform.Resize(new Point(specializationList.Content.Children.Sum(static c => c.Rect.Width), specializationList.Rect.Height));
|
||||
|
||||
GUITextBlock.AutoScaleAndNormalize(subTreeNames);
|
||||
|
||||
GUIListBox GetSpecializationList()
|
||||
{
|
||||
if (mainList.Content.Children.LastOrDefault() is GUIListBox specList)
|
||||
{
|
||||
return specList;
|
||||
}
|
||||
|
||||
GUIListBox newSpecializationList = new GUIListBox(new RectTransform(new Vector2(1.0f, 0.5f), mainList.Content.RectTransform, Anchor.TopCenter), isHorizontal: true, style: null);
|
||||
return newSpecializationList;
|
||||
}
|
||||
}
|
||||
|
||||
private void CreateTalentOption(GUIComponent parent, TalentSubTree subTree, int index, TalentOption talentOption, CharacterInfo info)
|
||||
{
|
||||
int elementPadding = GUI.IntScale(8);
|
||||
GUIFrame talentOptionFrame = new GUIFrame(new RectTransform(new Vector2(1f, 0.01f), parent.RectTransform, anchor: Anchor.TopCenter)
|
||||
{ MinSize = new Point(0, GUI.IntScale(65)) }, style: null);
|
||||
|
||||
Point talentFrameSize = talentOptionFrame.RectTransform.NonScaledSize;
|
||||
|
||||
GUIFrame talentBackground = new GUIFrame(new RectTransform(new Point(talentFrameSize.X - elementPadding, talentFrameSize.Y - elementPadding), talentOptionFrame.RectTransform, anchor: Anchor.Center),
|
||||
style: "TalentBackground")
|
||||
{
|
||||
Color = talentStageStyles[Locked].Color
|
||||
};
|
||||
GUIFrame talentBackgroundHighlight = new GUIFrame(new RectTransform(Vector2.One, talentBackground.RectTransform, anchor: Anchor.Center), style: "TalentBackgroundGlow") { Visible = false };
|
||||
|
||||
GUIImage cornerIcon = new GUIImage(new RectTransform(new Vector2(0.2f), talentOptionFrame.RectTransform, anchor: Anchor.BottomRight, scaleBasis: ScaleBasis.BothHeight) { MaxSize = new Point(16) }, style: null)
|
||||
{
|
||||
CanBeFocused = false,
|
||||
Color = talentStageStyles[Locked].Color
|
||||
};
|
||||
|
||||
Point iconSize = cornerIcon.RectTransform.NonScaledSize;
|
||||
cornerIcon.RectTransform.AbsoluteOffset = new Point(iconSize.X / 2, iconSize.Y / 2);
|
||||
|
||||
GUILayoutGroup talentOptionCenterGroup = new GUILayoutGroup(new RectTransform(new Vector2(0.6f, 0.9f), talentOptionFrame.RectTransform, Anchor.Center), childAnchor: Anchor.CenterLeft);
|
||||
GUILayoutGroup talentOptionLayoutGroup = new GUILayoutGroup(new RectTransform(Vector2.One, talentOptionCenterGroup.RectTransform), isHorizontal: true, childAnchor: Anchor.CenterLeft) { Stretch = true };
|
||||
|
||||
HashSet<Identifier> talentOptionIdentifiers = talentOption.TalentIdentifiers.OrderBy(static t => t).ToHashSet();
|
||||
HashSet<TalentButton> buttonsToAdd = new();
|
||||
|
||||
Dictionary<GUILayoutGroup, ImmutableHashSet<Identifier>> showCaseTalentParents = new();
|
||||
Dictionary<Identifier, GUIComponent> showCaseTalentButtonsToAdd = new();
|
||||
|
||||
foreach (var (showCaseTalentIdentifier, talents) in talentOption.ShowCaseTalents)
|
||||
{
|
||||
talentOptionIdentifiers.Add(showCaseTalentIdentifier);
|
||||
Point parentSize = talentBackground.RectTransform.NonScaledSize;
|
||||
GUIFrame showCaseFrame = new GUIFrame(new RectTransform(new Point((int)(parentSize.X / 3f * (talents.Count - 1)), parentSize.Y)), style: "GUITooltip")
|
||||
{
|
||||
UserData = showCaseTalentIdentifier,
|
||||
IgnoreLayoutGroups = true,
|
||||
Visible = false
|
||||
};
|
||||
GUILayoutGroup showcaseCenterGroup = new GUILayoutGroup(new RectTransform(new Vector2(0.9f, 0.7f), showCaseFrame.RectTransform, Anchor.Center), childAnchor: Anchor.CenterLeft);
|
||||
GUILayoutGroup showcaseLayout = new GUILayoutGroup(new RectTransform(Vector2.One, showcaseCenterGroup.RectTransform), isHorizontal: true) { Stretch = true };
|
||||
showCaseTalentParents.Add(showcaseLayout, talents);
|
||||
showCaseTalentFrames.Add(showCaseFrame);
|
||||
}
|
||||
|
||||
foreach (Identifier talentId in talentOptionIdentifiers)
|
||||
{
|
||||
if (!TalentPrefab.TalentPrefabs.TryGet(talentId, out TalentPrefab? talent)) { continue; }
|
||||
|
||||
bool isShowCaseTalent = talentOption.ShowCaseTalents.ContainsKey(talentId);
|
||||
GUIComponent talentParent = talentOptionLayoutGroup;
|
||||
|
||||
foreach (var (key, value) in showCaseTalentParents)
|
||||
{
|
||||
if (value.Contains(talentId))
|
||||
{
|
||||
talentParent = key;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
GUIFrame talentFrame = new GUIFrame(new RectTransform(Vector2.One, talentParent.RectTransform), style: null)
|
||||
{
|
||||
CanBeFocused = false
|
||||
};
|
||||
|
||||
GUIFrame croppedTalentFrame = new GUIFrame(new RectTransform(Vector2.One, talentFrame.RectTransform, anchor: Anchor.Center, scaleBasis: ScaleBasis.BothHeight), style: null);
|
||||
GUIButton talentButton = new GUIButton(new RectTransform(Vector2.One, croppedTalentFrame.RectTransform, anchor: Anchor.Center), style: null)
|
||||
{
|
||||
ToolTip = RichString.Rich($"‖color:{Color.White.ToStringHex()}‖{talent.DisplayName}‖color:end‖" + "\n\n" + ToolBox.ExtendColorToPercentageSigns(talent.Description.Value)),
|
||||
UserData = talent.Identifier,
|
||||
PressedColor = pressedColor,
|
||||
Enabled = info.Character != null,
|
||||
OnClicked = (button, userData) =>
|
||||
{
|
||||
if (isShowCaseTalent)
|
||||
{
|
||||
foreach (GUIComponent component in showCaseTalentFrames)
|
||||
{
|
||||
if (component.UserData is Identifier showcaseIdentifier && showcaseIdentifier == talentId)
|
||||
{
|
||||
component.RectTransform.ScreenSpaceOffset = new Point((int)(button.Rect.Location.X - component.Rect.Width / 2f + button.Rect.Width / 2f), button.Rect.Location.Y - component.Rect.Height);
|
||||
component.Visible = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
component.Visible = false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (character is null) { return false; }
|
||||
|
||||
if (talentOption.MaxChosenTalents is 1)
|
||||
{
|
||||
// deselect other buttons in tier by removing their selected talents from pool
|
||||
foreach (Identifier identifier in selectedTalents)
|
||||
{
|
||||
if (character.HasTalent(identifier) || identifier == talentId) { continue; }
|
||||
|
||||
if (talentOptionIdentifiers.Contains(identifier))
|
||||
{
|
||||
selectedTalents.Remove(identifier);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Identifier talentIdentifier = (Identifier)userData;
|
||||
|
||||
if (IsViableTalentForCharacter(info.Character, talentIdentifier, selectedTalents))
|
||||
{
|
||||
if (!selectedTalents.Contains(talentIdentifier))
|
||||
{
|
||||
selectedTalents.Add(talentIdentifier);
|
||||
}
|
||||
else
|
||||
{
|
||||
selectedTalents.Remove(talentIdentifier);
|
||||
}
|
||||
}
|
||||
else if (!character.HasTalent(talentIdentifier))
|
||||
{
|
||||
selectedTalents.Remove(talentIdentifier);
|
||||
}
|
||||
|
||||
UpdateTalentInfo();
|
||||
return true;
|
||||
},
|
||||
};
|
||||
|
||||
talentButton.Color = talentButton.HoverColor = talentButton.PressedColor = talentButton.SelectedColor = talentButton.DisabledColor = Color.Transparent;
|
||||
|
||||
GUIComponent iconImage;
|
||||
if (talent.Icon is null)
|
||||
{
|
||||
iconImage = new GUITextBlock(new RectTransform(Vector2.One, talentButton.RectTransform, anchor: Anchor.Center), text: "???", font: GUIStyle.LargeFont, textAlignment: Alignment.Center, style: null)
|
||||
{
|
||||
OutlineColor = GUIStyle.Red,
|
||||
TextColor = GUIStyle.Red,
|
||||
PressedColor = unselectableColor,
|
||||
DisabledColor = unselectableColor,
|
||||
CanBeFocused = false,
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
iconImage = new GUIImage(new RectTransform(Vector2.One, talentButton.RectTransform, anchor: Anchor.Center), sprite: talent.Icon, scaleToFit: true)
|
||||
{
|
||||
Color = talent.ColorOverride.TryUnwrap(out Color color) ? color : Color.White,
|
||||
PressedColor = unselectableColor,
|
||||
DisabledColor = unselectableColor * 0.5f,
|
||||
CanBeFocused = false,
|
||||
};
|
||||
}
|
||||
|
||||
iconImage.Enabled = talentButton.Enabled;
|
||||
if (isShowCaseTalent)
|
||||
{
|
||||
showCaseTalentButtonsToAdd.Add(talentId, iconImage);
|
||||
continue;
|
||||
}
|
||||
|
||||
buttonsToAdd.Add(new TalentButton(iconImage, talent));
|
||||
}
|
||||
|
||||
foreach (TalentButton button in buttonsToAdd)
|
||||
{
|
||||
talentButtons.Add(button);
|
||||
}
|
||||
|
||||
foreach (var (key, value) in showCaseTalentButtonsToAdd)
|
||||
{
|
||||
HashSet<TalentButton> buttons = new();
|
||||
foreach (Identifier identifier in talentOption.ShowCaseTalents[key])
|
||||
{
|
||||
if (talentButtons.FirstOrNull(talentButton => talentButton.Identifier == identifier) is not { } button) { continue; }
|
||||
|
||||
buttons.Add(button);
|
||||
}
|
||||
|
||||
talentShowCaseButtons.Add(new TalentShowCaseButton(buttons.ToImmutableHashSet(), value));
|
||||
}
|
||||
|
||||
talentCornerIcons.Add(new TalentCornerIcon(subTree.Identifier, index, cornerIcon, talentBackground, talentBackgroundHighlight));
|
||||
}
|
||||
|
||||
private void CreateFooter(GUIComponent parent, CharacterInfo info)
|
||||
{
|
||||
GUILayoutGroup bottomLayout = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.07f), parent.RectTransform, Anchor.TopCenter), isHorizontal: true)
|
||||
{
|
||||
RelativeSpacing = 0.01f,
|
||||
Stretch = true
|
||||
};
|
||||
|
||||
GUILayoutGroup experienceLayout = new GUILayoutGroup(new RectTransform(new Vector2(0.59f, 1f), bottomLayout.RectTransform));
|
||||
GUIFrame experienceBarFrame = new GUIFrame(new RectTransform(new Vector2(1f, 0.5f), experienceLayout.RectTransform), style: null);
|
||||
|
||||
experienceBar = new GUIProgressBar(new RectTransform(new Vector2(1f, 1f), experienceBarFrame.RectTransform, Anchor.CenterLeft),
|
||||
barSize: info.GetProgressTowardsNextLevel(), color: GUIStyle.Green)
|
||||
{
|
||||
IsHorizontal = true,
|
||||
};
|
||||
|
||||
experienceText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 1.0f), experienceBarFrame.RectTransform, anchor: Anchor.Center), "", font: GUIStyle.Font, textAlignment: Alignment.CenterRight)
|
||||
{
|
||||
Shadow = true,
|
||||
ToolTip = TextManager.Get("experiencetooltip")
|
||||
};
|
||||
|
||||
talentPointText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.5f), experienceLayout.RectTransform, anchor: Anchor.Center), "", font: GUIStyle.SubHeadingFont, textAlignment: Alignment.CenterRight)
|
||||
{ AutoScaleVertical = true };
|
||||
|
||||
talentResetButton = new GUIButton(new RectTransform(new Vector2(0.19f, 1f), bottomLayout.RectTransform), text: TextManager.Get("reset"), style: "GUIButtonFreeScale")
|
||||
{
|
||||
OnClicked = ResetTalentSelection
|
||||
};
|
||||
talentApplyButton = new GUIButton(new RectTransform(new Vector2(0.19f, 1f), bottomLayout.RectTransform), text: TextManager.Get("applysettingsbutton"), style: "GUIButtonFreeScale")
|
||||
{
|
||||
OnClicked = ApplyTalentSelection,
|
||||
};
|
||||
GUITextBlock.AutoScaleAndNormalize(talentResetButton.TextBlock, talentApplyButton.TextBlock);
|
||||
}
|
||||
|
||||
private bool ResetTalentSelection(GUIButton guiButton, object userData)
|
||||
{
|
||||
if (characterInfo is null) { return false; }
|
||||
selectedTalents = characterInfo.GetUnlockedTalentsInTree().ToHashSet();
|
||||
UpdateTalentInfo();
|
||||
return true;
|
||||
}
|
||||
|
||||
private void ApplyTalents(Character controlledCharacter)
|
||||
{
|
||||
foreach (Identifier talent in CheckTalentSelection(controlledCharacter, selectedTalents))
|
||||
{
|
||||
controlledCharacter.GiveTalent(talent);
|
||||
if (GameMain.Client != null)
|
||||
{
|
||||
GameMain.Client.CreateEntityEvent(controlledCharacter, new Character.UpdateTalentsEventData());
|
||||
}
|
||||
}
|
||||
|
||||
UpdateTalentInfo();
|
||||
}
|
||||
|
||||
private bool ApplyTalentSelection(GUIButton guiButton, object userData)
|
||||
{
|
||||
if (character is null) { return false; }
|
||||
|
||||
ApplyTalents(character);
|
||||
return true;
|
||||
}
|
||||
|
||||
public void UpdateTalentInfo()
|
||||
{
|
||||
if (character is null || characterInfo is null) { return; }
|
||||
|
||||
bool unlockedAllTalents = character.HasUnlockedAllTalents();
|
||||
|
||||
if (experienceBar is null || experienceText is null) { return; }
|
||||
|
||||
if (unlockedAllTalents)
|
||||
{
|
||||
experienceText.Text = string.Empty;
|
||||
experienceBar.BarSize = 1f;
|
||||
}
|
||||
else
|
||||
{
|
||||
experienceText.Text = $"{characterInfo.ExperiencePoints - characterInfo.GetExperienceRequiredForCurrentLevel()} / {characterInfo.GetExperienceRequiredToLevelUp() - characterInfo.GetExperienceRequiredForCurrentLevel()}";
|
||||
experienceBar.BarSize = characterInfo.GetProgressTowardsNextLevel();
|
||||
}
|
||||
|
||||
selectedTalents = CheckTalentSelection(character, selectedTalents).ToHashSet();
|
||||
|
||||
string pointsLeft = characterInfo.GetAvailableTalentPoints().ToString();
|
||||
|
||||
int talentCount = selectedTalents.Count - characterInfo.GetUnlockedTalentsInTree().Count();
|
||||
|
||||
if (unlockedAllTalents)
|
||||
{
|
||||
talentPointText?.SetRichText($"‖color:{Color.Gray.ToStringHex()}‖{TextManager.Get("talentmenu.alltalentsunlocked")}‖color:end‖");
|
||||
}
|
||||
else if (talentCount > 0)
|
||||
{
|
||||
string pointsUsed = $"‖color:{XMLExtensions.ToStringHex(GUIStyle.Red)}‖{-talentCount}‖color:end‖";
|
||||
LocalizedString localizedString = TextManager.GetWithVariables("talentmenu.points.spending", ("[amount]", pointsLeft), ("[used]", pointsUsed));
|
||||
talentPointText?.SetRichText(localizedString);
|
||||
}
|
||||
else
|
||||
{
|
||||
talentPointText?.SetRichText(TextManager.GetWithVariable("talentmenu.points", "[amount]", pointsLeft));
|
||||
}
|
||||
|
||||
foreach (TalentCornerIcon cornerIcon in talentCornerIcons)
|
||||
{
|
||||
TalentStages state = GetTalentOptionStageState(character, cornerIcon.TalentTree, cornerIcon.Index, selectedTalents);
|
||||
TalentTreeStyle style = talentStageStyles[state];
|
||||
GUIComponentStyle newStyle = style.ComponentStyle;
|
||||
cornerIcon.IconComponent.ApplyStyle(newStyle);
|
||||
cornerIcon.IconComponent.Color = newStyle.Color;
|
||||
cornerIcon.BackgroundComponent.Color = style.Color;
|
||||
cornerIcon.GlowComponent.Visible = state == Highlighted;
|
||||
}
|
||||
|
||||
foreach (TalentButton talentButton in talentButtons)
|
||||
{
|
||||
TalentStages stage = GetTalentState(character, talentButton.Identifier, selectedTalents);
|
||||
ApplyTalentIconColor(stage, talentButton.IconComponent, talentButton.Prefab.ColorOverride);
|
||||
}
|
||||
|
||||
foreach (TalentShowCaseButton showCaseTalentButton in talentShowCaseButtons)
|
||||
{
|
||||
TalentStages collectiveTalentStage = GetCollectiveTalentState(character, showCaseTalentButton.Buttons, selectedTalents);
|
||||
ApplyTalentIconColor(collectiveTalentStage, showCaseTalentButton.IconComponent, Option<Color>.None());
|
||||
}
|
||||
|
||||
if (skillListBox is null) { return; }
|
||||
|
||||
TabMenu.CreateSkillList(character, characterInfo, skillListBox);
|
||||
|
||||
static TalentStages GetTalentState(Character character, Identifier talentIdentifier, IReadOnlyCollection<Identifier> selectedTalents)
|
||||
{
|
||||
bool unselectable = !IsViableTalentForCharacter(character, talentIdentifier, selectedTalents) || character.HasTalent(talentIdentifier);
|
||||
TalentStages stage = unselectable ? Locked : Available;
|
||||
if (unselectable)
|
||||
{
|
||||
stage = Locked;
|
||||
}
|
||||
|
||||
if (character.HasTalent(talentIdentifier))
|
||||
{
|
||||
stage = Unlocked;
|
||||
}
|
||||
else if (selectedTalents.Contains(talentIdentifier))
|
||||
{
|
||||
stage = Highlighted;
|
||||
}
|
||||
|
||||
return stage;
|
||||
}
|
||||
|
||||
static void ApplyTalentIconColor(TalentStages stage, GUIComponent component, Option<Color> colorOverride)
|
||||
{
|
||||
Color color = stage switch
|
||||
{
|
||||
Invalid => unselectableColor,
|
||||
Locked => unselectableColor,
|
||||
Unlocked => GetColorOrOverride(GUIStyle.Green, colorOverride),
|
||||
Highlighted => GetColorOrOverride(GUIStyle.Orange, colorOverride),
|
||||
Available => GetColorOrOverride(unselectedColor, colorOverride),
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(stage), stage, null)
|
||||
};
|
||||
|
||||
component.Color = color;
|
||||
component.HoverColor = Color.Lerp(color, Color.White, 0.7f);
|
||||
|
||||
static Color GetColorOrOverride(Color color, Option<Color> colorOverride) => colorOverride.TryUnwrap(out Color overrideColor) ? overrideColor : color;
|
||||
}
|
||||
|
||||
// this could also be reused for setting colors for talentCornerIcons but that's for another time
|
||||
static TalentStages GetCollectiveTalentState(Character character, IReadOnlyCollection<TalentButton> buttons, IReadOnlyCollection<Identifier> selectedTalents)
|
||||
{
|
||||
HashSet<TalentStages> talentStages = new HashSet<TalentStages>();
|
||||
foreach (TalentButton button in buttons)
|
||||
{
|
||||
talentStages.Add(GetTalentState(character, button.Identifier, selectedTalents));
|
||||
}
|
||||
|
||||
TalentStages collectiveStage = talentStages.All(static stage => stage is Locked)
|
||||
? Locked
|
||||
: Available;
|
||||
|
||||
foreach (TalentStages stage in talentStages)
|
||||
{
|
||||
if (stage is Highlighted)
|
||||
{
|
||||
collectiveStage = Highlighted;
|
||||
break;
|
||||
}
|
||||
|
||||
if (stage is Unlocked)
|
||||
{
|
||||
collectiveStage = Unlocked;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return collectiveStage;
|
||||
}
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
if (characterInfo is null || talentResetButton is null || talentApplyButton is null) { return; }
|
||||
|
||||
int talentCount = selectedTalents.Count - characterInfo.GetUnlockedTalentsInTree().Count();
|
||||
talentResetButton.Enabled = talentApplyButton.Enabled = talentCount > 0;
|
||||
if (talentApplyButton.Enabled && talentApplyButton.FlashTimer <= 0.0f)
|
||||
{
|
||||
talentApplyButton.Flash(GUIStyle.Orange);
|
||||
}
|
||||
|
||||
while (showCaseClosureQueue.TryDequeue(out Identifier identifier))
|
||||
{
|
||||
foreach (GUIComponent component in showCaseTalentFrames)
|
||||
{
|
||||
if (component.UserData is Identifier showcaseIdentifier && showcaseIdentifier == identifier)
|
||||
{
|
||||
component.Visible = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool mouseInteracted = PlayerInput.PrimaryMouseButtonClicked() || PlayerInput.SecondaryMouseButtonClicked() || PlayerInput.ScrollWheelSpeed != 0;
|
||||
bool keyboardInteracted = PlayerInput.KeyHit(Keys.Escape) || GameSettings.CurrentConfig.KeyMap.Bindings[InputType.InfoTab].IsHit();
|
||||
|
||||
foreach (GUIComponent component in showCaseTalentFrames)
|
||||
{
|
||||
if (component.UserData is not Identifier identifier) { continue; }
|
||||
|
||||
component.AddToGUIUpdateList(order: 1);
|
||||
if (!component.Visible) { continue; }
|
||||
|
||||
if (keyboardInteracted || (mouseInteracted && !component.Rect.Contains(PlayerInput.MousePosition)))
|
||||
{
|
||||
showCaseClosureQueue.Enqueue(identifier);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static bool IsOwnCharacter(CharacterInfo? info)
|
||||
{
|
||||
if (info is null) { return false; }
|
||||
|
||||
CharacterInfo? ownCharacterInfo = Character.Controlled?.Info ?? GameMain.Client?.CharacterInfo;
|
||||
if (ownCharacterInfo is null) { return false; }
|
||||
|
||||
return info == ownCharacterInfo;
|
||||
}
|
||||
|
||||
public static bool CanManageTalents(CharacterInfo targetInfo)
|
||||
{
|
||||
// in singleplayer we can do whatever we want
|
||||
if (GameMain.IsSingleplayer) { return true; }
|
||||
|
||||
// always allow managing talents for own character
|
||||
if (IsOwnCharacter(targetInfo)) { return true; }
|
||||
|
||||
// don't allow controlling non-bot characters
|
||||
if (targetInfo.Character is not { IsBot: true }) { return false; }
|
||||
|
||||
// lastly check if we have the permission to do this
|
||||
return GameMain.Client is { } client && client.HasPermission(ClientPermissions.ManageBotTalents);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
@@ -78,6 +79,8 @@ namespace Barotrauma
|
||||
|
||||
private PlayerBalanceElement? playerBalanceElement;
|
||||
|
||||
private static ImmutableHashSet<Character> characterList = ImmutableHashSet<Character>.Empty;
|
||||
|
||||
/// <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.
|
||||
@@ -93,6 +96,7 @@ namespace Barotrauma
|
||||
public UpgradeStore(CampaignUI campaignUI, GUIComponent parent)
|
||||
{
|
||||
WaitForServerUpdate = false;
|
||||
characterList = GameSession.GetSessionCrewCharacters(CharacterType.Both);
|
||||
this.campaignUI = campaignUI;
|
||||
GUIFrame upgradeFrame = new GUIFrame(rectT(1, 1, parent, Anchor.Center), style: "OuterGlow", color: Color.Black * 0.7f)
|
||||
{
|
||||
@@ -121,6 +125,7 @@ namespace Barotrauma
|
||||
|
||||
private void RefreshAll()
|
||||
{
|
||||
characterList = GameSession.GetSessionCrewCharacters(CharacterType.Both);
|
||||
switch (selectedUpgradeTab)
|
||||
{
|
||||
case UpgradeTab.Repairs:
|
||||
@@ -278,10 +283,13 @@ namespace Barotrauma
|
||||
* | upgrades | maintenance | <- 1/3rd empty space |
|
||||
* |---------------------------------------------------------------------------------------------------|
|
||||
*/
|
||||
GUILayoutGroup leftLayout = new GUILayoutGroup(rectT(0.5f, 1, topHeaderLayout)) { RelativeSpacing = 0.05f };
|
||||
GUILayoutGroup leftLayout = new GUILayoutGroup(rectT(0.4f, 1, topHeaderLayout)) { RelativeSpacing = 0.05f };
|
||||
GUILayoutGroup locationLayout = new GUILayoutGroup(rectT(1, 0.5f, leftLayout), isHorizontal: true);
|
||||
GUIImage submarineIcon = new GUIImage(rectT(new Point(locationLayout.Rect.Height, locationLayout.Rect.Height), locationLayout), style: "SubmarineIcon", scaleToFit: true);
|
||||
new GUITextBlock(rectT(1.0f - submarineIcon.RectTransform.RelativeSize.X, 1, locationLayout), TextManager.Get("UpgradeUI.Title"), font: GUIStyle.LargeFont);
|
||||
var header = new GUITextBlock(rectT(1.0f - submarineIcon.RectTransform.RelativeSize.X, 1, locationLayout), TextManager.Get("UpgradeUI.Title"), font: GUIStyle.LargeFont);
|
||||
header.RectTransform.MaxSize = new Point((int)(header.TextSize.X + header.Padding.X + header.Padding.Z), int.MaxValue);
|
||||
new GUITextBlock(rectT(1.0f, 1, locationLayout), TextManager.Get("UpgradeUI.AllSubmarinesInfo"), font: GUIStyle.SmallFont, wrap: true);
|
||||
|
||||
categoryButtonLayout = new GUILayoutGroup(rectT(0.4f, 0.3f, leftLayout), isHorizontal: true) { Stretch = true };
|
||||
GUIButton upgradeButton = new GUIButton(rectT(1, 1f, categoryButtonLayout), TextManager.Get("UICategory.Upgrades"), style: "GUITabButton") { UserData = UpgradeTab.Upgrade, Selected = selectedUpgradeTab == UpgradeTab.Upgrade };
|
||||
GUIButton repairButton = new GUIButton(rectT(1, 1f, categoryButtonLayout), TextManager.Get("UICategory.Maintenance"), style: "GUITabButton") { UserData = UpgradeTab.Repairs, Selected = selectedUpgradeTab == UpgradeTab.Repairs };
|
||||
@@ -433,8 +441,8 @@ namespace Barotrauma
|
||||
|
||||
Location location = Campaign.Map.CurrentLocation;
|
||||
|
||||
int hullRepairCost = Campaign.GetHullRepairCost();
|
||||
int itemRepairCost = Campaign.GetItemRepairCost();
|
||||
int hullRepairCost = CampaignMode.GetHullRepairCost();
|
||||
int itemRepairCost = CampaignMode.GetItemRepairCost();
|
||||
int shuttleRetrieveCost = CampaignMode.ShuttleReplaceCost;
|
||||
if (location != null)
|
||||
{
|
||||
@@ -1080,7 +1088,7 @@ namespace Barotrauma
|
||||
|
||||
public static GUIFrame CreateUpgradeFrame(UpgradePrefab prefab, UpgradeCategory category, CampaignMode campaign, RectTransform rectTransform, bool addBuyButton = true)
|
||||
{
|
||||
int price = prefab.Price.GetBuyPrice(campaign.UpgradeManager.GetUpgradeLevel(prefab, category), campaign.Map?.CurrentLocation);
|
||||
int price = prefab.Price.GetBuyPrice(campaign.UpgradeManager.GetUpgradeLevel(prefab, category), campaign.Map?.CurrentLocation, characterList);
|
||||
return CreateUpgradeEntry(rectTransform, prefab.Sprite, prefab.Name, prefab.Description, price, new CategoryData(category, prefab), addBuyButton, upgradePrefab: prefab, currentLevel: campaign.UpgradeManager.GetUpgradeLevel(prefab, category));
|
||||
}
|
||||
|
||||
@@ -1222,7 +1230,7 @@ namespace Barotrauma
|
||||
{
|
||||
LocalizedString promptBody = TextManager.GetWithVariables("Upgrades.PurchasePromptBody",
|
||||
("[upgradename]", prefab.Name),
|
||||
("[amount]", prefab.Price.GetBuyPrice(Campaign.UpgradeManager.GetUpgradeLevel(prefab, category), Campaign.Map?.CurrentLocation).ToString()));
|
||||
("[amount]", prefab.Price.GetBuyPrice(Campaign.UpgradeManager.GetUpgradeLevel(prefab, category), Campaign.Map?.CurrentLocation, characterList).ToString()));
|
||||
currectConfirmation = EventEditorScreen.AskForConfirmation(TextManager.Get("Upgrades.PurchasePromptTitle"), promptBody, () =>
|
||||
{
|
||||
if (GameMain.NetworkMember != null)
|
||||
@@ -1639,7 +1647,7 @@ namespace Barotrauma
|
||||
|
||||
GUITextBlock priceLabel = textBlocks[0];
|
||||
priceLabel.Visible = true;
|
||||
int price = prefab.Price.GetBuyPrice(campaign.UpgradeManager.GetUpgradeLevel(prefab, category), campaign.Map?.CurrentLocation);
|
||||
int price = prefab.Price.GetBuyPrice(campaign.UpgradeManager.GetUpgradeLevel(prefab, category), campaign.Map?.CurrentLocation, characterList);
|
||||
|
||||
if (priceLabel != null && !WaitForServerUpdate)
|
||||
{
|
||||
|
||||
@@ -163,6 +163,7 @@ namespace Barotrauma
|
||||
|
||||
private void SetSubmarineVotingText(Client starter, SubmarineInfo info, bool transferItems, VoteType type)
|
||||
{
|
||||
int price = info.GetPrice();
|
||||
string name = starter.Name;
|
||||
JobPrefab prefab = starter?.Character?.Info?.Job?.Prefab;
|
||||
Color nameColor = prefab != null ? prefab.UIColor : Color.White;
|
||||
@@ -177,14 +178,14 @@ namespace Barotrauma
|
||||
text = TextManager.GetWithVariables(tag,
|
||||
("[playername]", characterRichString),
|
||||
("[submarinename]", submarineRichString),
|
||||
("[amount]", info.Price.ToString()),
|
||||
("[amount]", price.ToString()),
|
||||
("[currencyname]", TextManager.Get("credit").ToLower()));
|
||||
break;
|
||||
case VoteType.PurchaseSub:
|
||||
text = TextManager.GetWithVariables("submarinepurchasevote",
|
||||
("[playername]", characterRichString),
|
||||
("[submarinename]", submarineRichString),
|
||||
("[amount]", info.Price.ToString()),
|
||||
("[amount]", price.ToString()),
|
||||
("[currencyname]", TextManager.Get("credit").ToLower()));
|
||||
break;
|
||||
case VoteType.SwitchSub:
|
||||
@@ -218,6 +219,7 @@ namespace Barotrauma
|
||||
|
||||
private LocalizedString GetSubmarineVoteResultMessage(SubmarineInfo info, VoteType type, int yesVoteCount, int noVoteCount, bool votePassed)
|
||||
{
|
||||
int price = info.GetPrice();
|
||||
LocalizedString result = string.Empty;
|
||||
|
||||
switch (type)
|
||||
@@ -225,7 +227,7 @@ namespace Barotrauma
|
||||
case VoteType.PurchaseAndSwitchSub:
|
||||
result = TextManager.GetWithVariables(votePassed ? "submarinepurchaseandswitchvotepassed" : "submarinepurchaseandswitchvotefailed",
|
||||
("[submarinename]", info.DisplayName),
|
||||
("[amount]", string.Format(CultureInfo.InvariantCulture, "{0:N0}", info.Price)),
|
||||
("[amount]", string.Format(CultureInfo.InvariantCulture, "{0:N0}", price)),
|
||||
("[currencyname]", TextManager.Get("credit").ToLower()),
|
||||
("[yesvotecount]", yesVoteCount.ToString()),
|
||||
("[novotecount]" , noVoteCount.ToString()));
|
||||
@@ -233,7 +235,7 @@ namespace Barotrauma
|
||||
case VoteType.PurchaseSub:
|
||||
result = TextManager.GetWithVariables(votePassed ? "submarinepurchasevotepassed" : "submarinepurchasevotefailed",
|
||||
("[submarinename]", info.DisplayName),
|
||||
("[amount]", string.Format(CultureInfo.InvariantCulture, "{0:N0}", info.Price)),
|
||||
("[amount]", string.Format(CultureInfo.InvariantCulture, "{0:N0}", price)),
|
||||
("[currencyname]", TextManager.Get("credit").ToLower()),
|
||||
("[yesvotecount]", yesVoteCount.ToString()),
|
||||
("[novotecount]", noVoteCount.ToString()));
|
||||
|
||||
Reference in New Issue
Block a user