(965c31410a) Unstable v0.10.4.0
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
@@ -144,6 +145,15 @@ namespace Barotrauma
|
||||
GetSize(element);
|
||||
}
|
||||
|
||||
public Sprite GetDefaultSprite()
|
||||
{
|
||||
return GetSprite(GUIComponent.ComponentState.None);
|
||||
}
|
||||
public Sprite GetSprite(GUIComponent.ComponentState state)
|
||||
{
|
||||
return Sprites.ContainsKey(state) ? Sprites[state]?.First()?.Sprite : null;
|
||||
}
|
||||
|
||||
public void GetSize(XElement element)
|
||||
{
|
||||
Point size = new Point(0, 0);
|
||||
|
||||
@@ -0,0 +1,729 @@
|
||||
using Barotrauma.Extensions;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using Barotrauma.Networking;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
class CrewManagement
|
||||
{
|
||||
private CampaignMode campaign => campaignUI.Campaign;
|
||||
private readonly CampaignUI campaignUI;
|
||||
private readonly GUIComponent parentComponent;
|
||||
|
||||
private GUIListBox hireableList, pendingList, crewList;
|
||||
private GUIFrame characterPreviewFrame;
|
||||
private GUIDropDown sortingDropDown;
|
||||
private GUITextBlock totalBlock;
|
||||
private GUIButton validateHiresButton;
|
||||
private GUIButton clearAllButton;
|
||||
|
||||
private List<CharacterInfo> PendingHires => campaign.Map?.CurrentLocation?.HireManager?.PendingHires;
|
||||
private bool HasPermission => campaignUI.Campaign.AllowedToManageCampaign();
|
||||
|
||||
private Point resolutionWhenCreated;
|
||||
|
||||
private enum SortingMethod
|
||||
{
|
||||
AlphabeticalAsc,
|
||||
JobAsc,
|
||||
PriceAsc,
|
||||
PriceDesc,
|
||||
SkillAsc,
|
||||
SkillDesc
|
||||
}
|
||||
|
||||
public CrewManagement(CampaignUI campaignUI, GUIComponent parentComponent)
|
||||
{
|
||||
this.campaignUI = campaignUI;
|
||||
this.parentComponent = parentComponent;
|
||||
|
||||
CreateUI();
|
||||
UpdateLocationView(campaignUI.Campaign.Map.CurrentLocation, true);
|
||||
|
||||
campaignUI.Campaign.Map.OnLocationChanged += (prevLocation, newLocation) => UpdateLocationView(newLocation, true, prevLocation);
|
||||
}
|
||||
|
||||
public void RefreshPermissions()
|
||||
{
|
||||
RefreshCrewFrames(hireableList);
|
||||
RefreshCrewFrames(crewList);
|
||||
RefreshCrewFrames(pendingList);
|
||||
if (clearAllButton != null) { clearAllButton.Enabled = HasPermission; }
|
||||
}
|
||||
|
||||
private void RefreshCrewFrames(GUIListBox listBox)
|
||||
{
|
||||
if (listBox == null) { return; }
|
||||
listBox.CanBeFocused = HasPermission;
|
||||
foreach (GUIComponent child in listBox.Content.Children)
|
||||
{
|
||||
if (child.FindChild(c => c is GUIButton && c.UserData is CharacterInfo, true) is GUIButton buyButton)
|
||||
{
|
||||
buyButton.Enabled = HasPermission;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void CreateUI()
|
||||
{
|
||||
if (parentComponent.FindChild(c => c.UserData as string == "glow") is GUIComponent glowChild)
|
||||
{
|
||||
parentComponent.RemoveChild(glowChild);
|
||||
}
|
||||
if (parentComponent.FindChild(c => c.UserData as string == "container") is GUIComponent containerChild)
|
||||
{
|
||||
parentComponent.RemoveChild(containerChild);
|
||||
}
|
||||
|
||||
new GUIFrame(new RectTransform(new Vector2(1.25f, 1.25f), parentComponent.RectTransform, Anchor.Center),
|
||||
style: "OuterGlow", color: Color.Black * 0.7f)
|
||||
{
|
||||
UserData = "glow"
|
||||
};
|
||||
new GUIFrame(new RectTransform(new Vector2(0.95f), parentComponent.RectTransform, anchor: Anchor.Center),
|
||||
style: null)
|
||||
{
|
||||
CanBeFocused = false,
|
||||
UserData = "container"
|
||||
};
|
||||
|
||||
var availableMainGroup = new GUILayoutGroup(new RectTransform(new Vector2(0.4f, 1.0f), campaignUI.GetTabContainer(CampaignMode.InteractionType.Crew).RectTransform)
|
||||
{
|
||||
MaxSize = new Point(560, campaignUI.GetTabContainer(CampaignMode.InteractionType.Crew).Rect.Height)
|
||||
})
|
||||
{
|
||||
Stretch = true,
|
||||
RelativeSpacing = 0.02f
|
||||
};
|
||||
|
||||
// Header ------------------------------------------------
|
||||
var headerGroup = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.75f / 14.0f), availableMainGroup.RectTransform), isHorizontal: true)
|
||||
{
|
||||
RelativeSpacing = 0.005f
|
||||
};
|
||||
var imageWidth = (float)headerGroup.Rect.Height / headerGroup.Rect.Width;
|
||||
new GUIImage(new RectTransform(new Vector2(imageWidth, 1.0f), headerGroup.RectTransform), "CrewManagementHeaderIcon");
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f - imageWidth, 1.0f), headerGroup.RectTransform), TextManager.Get("campaigncrew.header"), font: GUI.LargeFont)
|
||||
{
|
||||
CanBeFocused = false,
|
||||
ForceUpperCase = true
|
||||
};
|
||||
|
||||
var hireablesGroup = new GUILayoutGroup(new RectTransform(new Vector2(0.9f, 0.95f), anchor: Anchor.Center,
|
||||
parent: new GUIFrame(new RectTransform(new Vector2(1.0f, 13.25f / 14.0f), availableMainGroup.RectTransform)).RectTransform))
|
||||
{
|
||||
RelativeSpacing = 0.015f,
|
||||
Stretch = true
|
||||
};
|
||||
|
||||
var sortGroup = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.04f), hireablesGroup.RectTransform), isHorizontal: true)
|
||||
{
|
||||
RelativeSpacing = 0.015f
|
||||
};
|
||||
new GUITextBlock(new RectTransform(new Vector2(0.15f, 1.0f), sortGroup.RectTransform), text: TextManager.Get("campaignstore.sortby"));
|
||||
sortingDropDown = new GUIDropDown(new RectTransform(new Vector2(0.4f, 1.0f), sortGroup.RectTransform), elementCount: 5)
|
||||
{
|
||||
OnSelected = (child, userData) =>
|
||||
{
|
||||
SortCharacters(hireableList, (SortingMethod)userData);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
var tag = "sortingmethod.";
|
||||
sortingDropDown.AddItem(TextManager.Get(tag + SortingMethod.JobAsc), userData: SortingMethod.JobAsc);
|
||||
sortingDropDown.AddItem(TextManager.Get(tag + SortingMethod.SkillAsc), userData: SortingMethod.SkillAsc);
|
||||
sortingDropDown.AddItem(TextManager.Get(tag + SortingMethod.SkillDesc), userData: SortingMethod.SkillDesc);
|
||||
sortingDropDown.AddItem(TextManager.Get(tag + SortingMethod.PriceAsc), userData: SortingMethod.PriceAsc);
|
||||
sortingDropDown.AddItem(TextManager.Get(tag + SortingMethod.PriceDesc), userData: SortingMethod.PriceDesc);
|
||||
|
||||
hireableList = new GUIListBox(new RectTransform(new Vector2(1.0f, 0.96f),
|
||||
hireablesGroup.RectTransform,
|
||||
anchor: Anchor.Center))
|
||||
{
|
||||
Spacing = 1
|
||||
};
|
||||
|
||||
var pendingAndCrewMainGroup = new GUILayoutGroup(new RectTransform(new Vector2(0.4f, 1.0f), campaignUI.GetTabContainer(CampaignMode.InteractionType.Crew).RectTransform, anchor: Anchor.TopRight)
|
||||
{
|
||||
MaxSize = new Point(560, campaignUI.GetTabContainer(CampaignMode.InteractionType.Crew).Rect.Height)
|
||||
})
|
||||
{
|
||||
Stretch = true,
|
||||
RelativeSpacing = 0.02f
|
||||
};
|
||||
|
||||
var playerBalanceContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.75f / 14.0f), pendingAndCrewMainGroup.RectTransform), childAnchor: Anchor.TopRight)
|
||||
{
|
||||
RelativeSpacing = 0.005f
|
||||
};
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.5f), playerBalanceContainer.RectTransform),
|
||||
TextManager.Get("campaignstore.balance"), font: GUI.Font, textAlignment: Alignment.BottomRight)
|
||||
{
|
||||
AutoScaleVertical = true,
|
||||
ForceUpperCase = true
|
||||
};
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.5f), playerBalanceContainer.RectTransform),
|
||||
"", font: GUI.SubHeadingFont, textAlignment: Alignment.TopRight)
|
||||
{
|
||||
AutoScaleVertical = true,
|
||||
TextScale = 1.1f,
|
||||
TextGetter = () => FormatCurrency(campaign.Money)
|
||||
};
|
||||
|
||||
var pendingAndCrewGroup = new GUILayoutGroup(new RectTransform(new Vector2(0.9f, 0.95f), anchor: Anchor.Center,
|
||||
parent: new GUIFrame(new RectTransform(new Vector2(1.0f, 13.25f / 14.0f), pendingAndCrewMainGroup.RectTransform)
|
||||
{
|
||||
MaxSize = new Point(560, campaignUI.GetTabContainer(CampaignMode.InteractionType.Crew).Rect.Height)
|
||||
}).RectTransform));
|
||||
|
||||
float height = 0.05f;
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, height), pendingAndCrewGroup.RectTransform), TextManager.Get("campaigncrew.pending"), font: GUI.SubHeadingFont);
|
||||
pendingList = new GUIListBox(new RectTransform(new Vector2(1.0f, 8 * height), pendingAndCrewGroup.RectTransform))
|
||||
{
|
||||
Spacing = 1
|
||||
};
|
||||
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, height), pendingAndCrewGroup.RectTransform), TextManager.Get("campaignmenucrew"), font: GUI.SubHeadingFont);
|
||||
crewList = new GUIListBox(new RectTransform(new Vector2(1.0f, (8)* height), pendingAndCrewGroup.RectTransform))
|
||||
{
|
||||
Spacing = 1
|
||||
};
|
||||
|
||||
var group = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, height), pendingAndCrewGroup.RectTransform), isHorizontal: true);
|
||||
new GUITextBlock(new RectTransform(new Vector2(0.5f, 1.0f), group.RectTransform), TextManager.Get("campaignstore.total"));
|
||||
totalBlock = new GUITextBlock(new RectTransform(new Vector2(0.5f, 1.0f), group.RectTransform), "", font: GUI.SubHeadingFont, textAlignment: Alignment.Right)
|
||||
{
|
||||
TextScale = 1.1f
|
||||
};
|
||||
group = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, height), pendingAndCrewGroup.RectTransform), isHorizontal: true, childAnchor: Anchor.TopRight)
|
||||
{
|
||||
RelativeSpacing = 0.01f
|
||||
};
|
||||
validateHiresButton = new GUIButton(new RectTransform(new Vector2(1.0f / 3.0f, 1.0f), group.RectTransform), text: TextManager.Get("campaigncrew.validate"))
|
||||
{
|
||||
ForceUpperCase = true,
|
||||
OnClicked = (b, o) => ValidatePendingHires(true)
|
||||
};
|
||||
clearAllButton = new GUIButton(new RectTransform(new Vector2(1.0f / 3.0f, 1.0f), group.RectTransform), text: TextManager.Get("campaignstore.clearall"))
|
||||
{
|
||||
ForceUpperCase = true,
|
||||
Enabled = HasPermission,
|
||||
OnClicked = (b, o) => RemoveAllPendingHires()
|
||||
};
|
||||
|
||||
resolutionWhenCreated = new Point(GameMain.GraphicsWidth, GameMain.GraphicsHeight);
|
||||
}
|
||||
|
||||
private void UpdateLocationView(Location location, bool removePending, Location prevLocation = null)
|
||||
{
|
||||
if (prevLocation != null && prevLocation == location && GameMain.NetworkMember != null) { return; }
|
||||
|
||||
if (characterPreviewFrame != null)
|
||||
{
|
||||
characterPreviewFrame.Parent?.RemoveChild(characterPreviewFrame);
|
||||
characterPreviewFrame = null;
|
||||
}
|
||||
UpdateHireables(location);
|
||||
if (pendingList != null)
|
||||
{
|
||||
if (removePending)
|
||||
{
|
||||
PendingHires?.Clear();
|
||||
pendingList.Content.ClearChildren();
|
||||
}
|
||||
else
|
||||
{
|
||||
PendingHires?.ForEach(ci => AddPendingHire(ci));
|
||||
}
|
||||
SetTotalHireCost();
|
||||
}
|
||||
UpdateCrew();
|
||||
}
|
||||
|
||||
private void UpdateHireables(Location location)
|
||||
{
|
||||
if (hireableList != null)
|
||||
{
|
||||
hireableList.Content.Children.ToList().ForEach(c => hireableList.RemoveChild(c));
|
||||
var hireableCharacters = location.GetHireableCharacters();
|
||||
if (hireableCharacters.None())
|
||||
{
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.2f), hireableList.Content.RectTransform), TextManager.Get("HireUnavailable"), textAlignment: Alignment.Center)
|
||||
{
|
||||
CanBeFocused = false
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (CharacterInfo c in hireableCharacters)
|
||||
{
|
||||
if (c == null) { continue; }
|
||||
CreateCharacterFrame(c, hireableList);
|
||||
}
|
||||
}
|
||||
sortingDropDown.SelectItem(SortingMethod.JobAsc);
|
||||
hireableList.UpdateScrollBarSize();
|
||||
}
|
||||
}
|
||||
|
||||
public void SetHireables(Location location, List<CharacterInfo> availableHires)
|
||||
{
|
||||
HireManager hireManager = location.HireManager;
|
||||
if (hireManager == null) { return; }
|
||||
int hireVal = hireManager.AvailableCharacters.Aggregate(0, (curr, hire) => curr + hire.GetIdentifier());
|
||||
int newVal = availableHires.Aggregate(0, (curr, hire) => curr + hire.GetIdentifier());
|
||||
if (hireVal != newVal)
|
||||
{
|
||||
location.HireManager.AvailableCharacters = availableHires;
|
||||
UpdateHireables(location);
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateCrew()
|
||||
{
|
||||
crewList.Content.Children.ToList().ForEach(c => crewList.Content.RemoveChild(c));
|
||||
foreach (CharacterInfo c in GameMain.GameSession.CrewManager.GetCharacterInfos())
|
||||
{
|
||||
if (c == null || !((c.Character?.IsBot ?? true) || campaign is SinglePlayerCampaign)) { continue; }
|
||||
CreateCharacterFrame(c, crewList);
|
||||
}
|
||||
SortCharacters(crewList, SortingMethod.JobAsc);
|
||||
crewList.UpdateScrollBarSize();
|
||||
}
|
||||
|
||||
private void SortCharacters(GUIListBox list, SortingMethod sortingMethod)
|
||||
{
|
||||
if (sortingMethod == SortingMethod.AlphabeticalAsc)
|
||||
{
|
||||
list.Content.RectTransform.SortChildren((x, y) =>
|
||||
(x.GUIComponent.UserData as Tuple<CharacterInfo, float>).Item1.Name.CompareTo((y.GUIComponent.UserData as Tuple<CharacterInfo, float>).Item1.Name));
|
||||
}
|
||||
else if (sortingMethod == SortingMethod.JobAsc)
|
||||
{
|
||||
SortCharacters(list, SortingMethod.AlphabeticalAsc);
|
||||
list.Content.RectTransform.SortChildren((x, y) =>
|
||||
String.Compare((x.GUIComponent.UserData as Tuple<CharacterInfo, float>)?.Item1.Job.Name, (y.GUIComponent.UserData as Tuple<CharacterInfo, float>).Item1.Job.Name, StringComparison.Ordinal));
|
||||
}
|
||||
else if (sortingMethod == SortingMethod.PriceAsc || sortingMethod == SortingMethod.PriceDesc)
|
||||
{
|
||||
SortCharacters(list, SortingMethod.AlphabeticalAsc);
|
||||
list.Content.RectTransform.SortChildren((x, y) =>
|
||||
(x.GUIComponent.UserData as Tuple<CharacterInfo, float>).Item1.Salary.CompareTo((y.GUIComponent.UserData as Tuple<CharacterInfo, float>).Item1.Salary));
|
||||
if (sortingMethod == SortingMethod.PriceDesc) { list.Content.RectTransform.ReverseChildren(); }
|
||||
}
|
||||
else if (sortingMethod == SortingMethod.SkillAsc || sortingMethod == SortingMethod.SkillDesc)
|
||||
{
|
||||
SortCharacters(list, SortingMethod.AlphabeticalAsc);
|
||||
list.Content.RectTransform.SortChildren((x, y) =>
|
||||
(x.GUIComponent.UserData as Tuple<CharacterInfo, float>).Item2.CompareTo((y.GUIComponent.UserData as Tuple<CharacterInfo, float>).Item2));
|
||||
if (sortingMethod == SortingMethod.SkillDesc) { list.Content.RectTransform.ReverseChildren(); }
|
||||
}
|
||||
}
|
||||
|
||||
private void CreateCharacterFrame(CharacterInfo characterInfo, GUIListBox listBox)
|
||||
{
|
||||
Skill skill = null;
|
||||
Color? jobColor = null;
|
||||
if (characterInfo.Job != null)
|
||||
{
|
||||
skill = characterInfo.Job?.PrimarySkill ?? characterInfo.Job.Skills.OrderByDescending(s => s.Level).FirstOrDefault();
|
||||
jobColor = characterInfo.Job.Prefab.UIColor;
|
||||
}
|
||||
|
||||
GUIFrame frame = new GUIFrame(new RectTransform(new Point(listBox.Content.Rect.Width, 55), parent: listBox.Content.RectTransform), "ListBoxElement")
|
||||
{
|
||||
UserData = new Tuple<CharacterInfo, float>(characterInfo, skill != null ? skill.Level : 0.0f)
|
||||
};
|
||||
GUILayoutGroup mainGroup = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.95f), frame.RectTransform, anchor: Anchor.Center), isHorizontal: true, childAnchor: Anchor.CenterLeft)
|
||||
{
|
||||
Stretch = true
|
||||
};
|
||||
|
||||
float portraitWidth = (0.8f * mainGroup.Rect.Height) / mainGroup.Rect.Width;
|
||||
new GUICustomComponent(new RectTransform(new Vector2(portraitWidth, 0.8f), mainGroup.RectTransform),
|
||||
onDraw: (sb, component) => characterInfo.DrawIcon(sb, component.Rect.Center.ToVector2(), targetAreaSize: component.Rect.Size.ToVector2()))
|
||||
{
|
||||
CanBeFocused = false
|
||||
};
|
||||
|
||||
GUILayoutGroup nameAndJobGroup = new GUILayoutGroup(new RectTransform(new Vector2(0.4f - portraitWidth, 0.8f), mainGroup.RectTransform));
|
||||
GUITextBlock nameBlock = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.5f), nameAndJobGroup.RectTransform),
|
||||
characterInfo.Name, textColor: jobColor, textAlignment: Alignment.BottomLeft)
|
||||
{
|
||||
CanBeFocused = false
|
||||
};
|
||||
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: GUI.SmallFont, textAlignment: Alignment.TopLeft)
|
||||
{
|
||||
CanBeFocused = false
|
||||
};
|
||||
jobBlock.Text = ToolBox.LimitString(jobBlock.Text, jobBlock.Font, jobBlock.Rect.Width);
|
||||
|
||||
float width = 0.6f / 3;
|
||||
if (characterInfo.Job != null)
|
||||
{
|
||||
GUILayoutGroup skillGroup = new GUILayoutGroup(new RectTransform(new Vector2(width, 0.6f), mainGroup.RectTransform), isHorizontal: true);
|
||||
float iconWidth = (float)skillGroup.Rect.Height / skillGroup.Rect.Width;
|
||||
GUIImage skillIcon = new GUIImage(new RectTransform(new Vector2(iconWidth, 1.0f), skillGroup.RectTransform), skill.Icon)
|
||||
{
|
||||
CanBeFocused = false
|
||||
};
|
||||
if (jobColor.HasValue) { skillIcon.Color = jobColor.Value; }
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f - iconWidth, 1.0f), skillGroup.RectTransform), ((int)skill.Level).ToString(), textAlignment: Alignment.CenterLeft)
|
||||
{
|
||||
CanBeFocused = false
|
||||
};
|
||||
}
|
||||
|
||||
if (listBox != crewList)
|
||||
{
|
||||
new GUITextBlock(new RectTransform(new Vector2(width, 1.0f), mainGroup.RectTransform), FormatCurrency(characterInfo.Salary), textAlignment: Alignment.Center)
|
||||
{
|
||||
CanBeFocused = false
|
||||
};
|
||||
}
|
||||
|
||||
if (listBox == hireableList)
|
||||
{
|
||||
new GUIButton(new RectTransform(new Vector2(width, 0.9f), mainGroup.RectTransform), style: "CrewManagementAddButton")
|
||||
{
|
||||
UserData = characterInfo,
|
||||
Enabled = HasPermission,
|
||||
OnClicked = (b, o) => AddPendingHire(o as CharacterInfo)
|
||||
};
|
||||
}
|
||||
else if (listBox == pendingList)
|
||||
{
|
||||
new GUIButton(new RectTransform(new Vector2(width, 0.9f), mainGroup.RectTransform), style: "CrewManagementRemoveButton")
|
||||
{
|
||||
UserData = characterInfo,
|
||||
Enabled = HasPermission,
|
||||
OnClicked = (b, o) => RemovePendingHire(o as CharacterInfo)
|
||||
};
|
||||
}
|
||||
else if (listBox == crewList && campaign != null)
|
||||
{
|
||||
var currentCrew = GameMain.GameSession.CrewManager.GetCharacterInfos();
|
||||
new GUIButton(new RectTransform(new Vector2(width, 0.9f), mainGroup.RectTransform), style: "CrewManagementFireButton")
|
||||
{
|
||||
UserData = characterInfo,
|
||||
//can't fire if there's only one character in the crew
|
||||
Enabled = currentCrew.Contains(characterInfo) && currentCrew.Count() > 1 && HasPermission,
|
||||
OnClicked = (btn, obj) =>
|
||||
{
|
||||
var confirmDialog = new GUIMessageBox(
|
||||
TextManager.Get("FireWarningHeader"),
|
||||
TextManager.GetWithVariable("FireWarningText", "[charactername]", ((CharacterInfo)obj).Name),
|
||||
new string[] { TextManager.Get("Yes"), TextManager.Get("No") });
|
||||
confirmDialog.Buttons[0].UserData = (CharacterInfo)obj;
|
||||
confirmDialog.Buttons[0].OnClicked = FireCharacter;
|
||||
confirmDialog.Buttons[0].OnClicked += confirmDialog.Close;
|
||||
confirmDialog.Buttons[1].OnClicked = confirmDialog.Close;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private void CreateCharacterPreviewFrame(GUIListBox listBox, GUIFrame characterFrame, CharacterInfo characterInfo)
|
||||
{
|
||||
Pivot pivot = listBox == hireableList ? Pivot.TopLeft : Pivot.TopRight;
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
AbsoluteOffset = absoluteOffset
|
||||
}, style: "InnerFrame")
|
||||
{
|
||||
UserData = characterInfo
|
||||
};
|
||||
GUILayoutGroup mainGroup = new GUILayoutGroup(new RectTransform(new Vector2(0.95f), characterPreviewFrame.RectTransform, anchor: Anchor.Center))
|
||||
{
|
||||
RelativeSpacing = 0.01f
|
||||
};
|
||||
|
||||
// Character info
|
||||
GUILayoutGroup infoGroup = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.475f), mainGroup.RectTransform), isHorizontal: true);
|
||||
GUILayoutGroup infoLabelGroup = new GUILayoutGroup(new RectTransform(new Vector2(0.4f, 1.0f), infoGroup.RectTransform)) { Stretch = true };
|
||||
GUILayoutGroup infoValueGroup = new GUILayoutGroup(new RectTransform(new Vector2(0.6f, 1.0f), infoGroup.RectTransform)) { Stretch = true };
|
||||
float blockHeight = 1.0f / 4;
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, blockHeight), infoLabelGroup.RectTransform), TextManager.Get("name"));
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, blockHeight), infoValueGroup.RectTransform), characterInfo.Name);
|
||||
if (characterInfo.HasGenders)
|
||||
{
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, blockHeight), infoLabelGroup.RectTransform), TextManager.Get("gender"));
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, blockHeight), infoValueGroup.RectTransform), TextManager.Get(characterInfo.Gender.ToString()));
|
||||
}
|
||||
if (characterInfo.Job is Job job)
|
||||
{
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, blockHeight), infoLabelGroup.RectTransform), TextManager.Get("tabmenu.job"));
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, blockHeight), infoValueGroup.RectTransform), job.Name);
|
||||
}
|
||||
if (characterInfo.PersonalityTrait is NPCPersonalityTrait trait)
|
||||
{
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, blockHeight), infoLabelGroup.RectTransform), TextManager.Get("PersonalityTrait"));
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, blockHeight), infoValueGroup.RectTransform), TextManager.Get("personalitytrait." + trait.Name.Replace(" ", "")));
|
||||
}
|
||||
infoLabelGroup.Recalculate();
|
||||
infoValueGroup.Recalculate();
|
||||
|
||||
new GUIImage(new RectTransform(new Vector2(1.0f, 0.05f), mainGroup.RectTransform), "HorizontalLine");
|
||||
|
||||
// Skills
|
||||
GUILayoutGroup skillGroup = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.475f), mainGroup.RectTransform), isHorizontal: true);
|
||||
GUILayoutGroup skillNameGroup = new GUILayoutGroup(new RectTransform(new Vector2(0.8f, 1.0f), skillGroup.RectTransform));
|
||||
GUILayoutGroup skillLevelGroup = new GUILayoutGroup(new RectTransform(new Vector2(0.2f, 1.0f), skillGroup.RectTransform));
|
||||
List<Skill> characterSkills = characterInfo.Job.Skills;
|
||||
blockHeight = 1.0f / characterSkills.Count;
|
||||
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), skillLevelGroup.RectTransform), ((int)skill.Level).ToString(), textAlignment: Alignment.Right);
|
||||
}
|
||||
}
|
||||
|
||||
private bool SelectCharacter(GUIListBox listBox, GUIFrame characterFrame, CharacterInfo characterInfo)
|
||||
{
|
||||
if (characterPreviewFrame != null && characterPreviewFrame.UserData != characterInfo)
|
||||
{
|
||||
characterPreviewFrame.Parent?.RemoveChild(characterPreviewFrame);
|
||||
characterPreviewFrame = null;
|
||||
}
|
||||
|
||||
if (listBox == null || characterFrame == null || characterInfo == null) { return false; }
|
||||
|
||||
if (characterPreviewFrame == null)
|
||||
{
|
||||
CreateCharacterPreviewFrame(listBox, characterFrame, characterInfo);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool AddPendingHire(CharacterInfo characterInfo, bool createNetworkMessage = true)
|
||||
{
|
||||
hireableList.Content.RemoveChild(hireableList.Content.FindChild(c => (c.UserData as Tuple<CharacterInfo, float>).Item1 == characterInfo));
|
||||
hireableList.UpdateScrollBarSize();
|
||||
if (!PendingHires.Contains(characterInfo)) { PendingHires.Add(characterInfo); }
|
||||
CreateCharacterFrame(characterInfo, pendingList);
|
||||
SortCharacters(pendingList, SortingMethod.JobAsc);
|
||||
pendingList.UpdateScrollBarSize();
|
||||
SetTotalHireCost();
|
||||
if (createNetworkMessage) { SendCrewState(true); }
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool RemovePendingHire(CharacterInfo characterInfo, bool setTotalHireCost = true, bool createNetworkMessage = true)
|
||||
{
|
||||
if (PendingHires.Contains(characterInfo)) { PendingHires.Remove(characterInfo); }
|
||||
pendingList.Content.RemoveChild(pendingList.Content.FindChild(c => (c.UserData as Tuple<CharacterInfo, float>).Item1 == characterInfo));
|
||||
pendingList.UpdateScrollBarSize();
|
||||
CreateCharacterFrame(characterInfo, hireableList);
|
||||
SortCharacters(hireableList, (SortingMethod)sortingDropDown.SelectedItemData);
|
||||
hireableList.UpdateScrollBarSize();
|
||||
if (setTotalHireCost) { SetTotalHireCost(); }
|
||||
if (createNetworkMessage) { SendCrewState(true); }
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool RemoveAllPendingHires(bool createNetworkMessage = true)
|
||||
{
|
||||
pendingList.Content.Children.ToList().ForEach(c => RemovePendingHire((c.UserData as Tuple<CharacterInfo, float>).Item1, setTotalHireCost: false, createNetworkMessage));
|
||||
SetTotalHireCost();
|
||||
return true;
|
||||
}
|
||||
|
||||
private void SetTotalHireCost()
|
||||
{
|
||||
if (pendingList == null || totalBlock == null || validateHiresButton == null) { return; }
|
||||
int total = 0;
|
||||
pendingList.Content.Children.ForEach(c => total += (c.UserData as Tuple<CharacterInfo, float>).Item1.Salary);
|
||||
totalBlock.Text = FormatCurrency(total);
|
||||
bool enoughMoney = campaign != null ? total <= campaign.Money : true;
|
||||
totalBlock.TextColor = enoughMoney ? Color.White : Color.Red;
|
||||
validateHiresButton.Enabled = enoughMoney && pendingList.Content.RectTransform.Children.Any();
|
||||
}
|
||||
|
||||
public bool ValidatePendingHires(bool createNetworkEvent = false)
|
||||
{
|
||||
List<CharacterInfo> hires = new List<CharacterInfo>();
|
||||
int total = 0;
|
||||
foreach (GUIComponent c in pendingList.Content.Children.ToList())
|
||||
{
|
||||
if (c.UserData is Tuple<CharacterInfo, float> info)
|
||||
{
|
||||
hires.Add(info.Item1);
|
||||
total += info.Item1.Salary;
|
||||
}
|
||||
}
|
||||
|
||||
if (hires.None() || total > campaign.Money) { return false; }
|
||||
|
||||
bool atLeastOneHired = false;
|
||||
foreach (CharacterInfo ci in hires)
|
||||
{
|
||||
if (campaign.TryHireCharacter(campaign.Map.CurrentLocation, ci))
|
||||
{
|
||||
atLeastOneHired = true;
|
||||
PendingHires.Remove(ci);
|
||||
pendingList.Content.RemoveChild(pendingList.Content.FindChild(c => (c.UserData as Tuple<CharacterInfo, float>).Item1 == ci));
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (atLeastOneHired)
|
||||
{
|
||||
UpdateLocationView(campaign.Map.CurrentLocation, true);
|
||||
SelectCharacter(null, null, null);
|
||||
var dialog = new GUIMessageBox(
|
||||
TextManager.Get("newcrewmembers"),
|
||||
TextManager.GetWithVariable("crewhiredmessage", "[location]", campaignUI?.Campaign?.Map?.CurrentLocation?.Name),
|
||||
new string[] { TextManager.Get("Ok") });
|
||||
dialog.Buttons[0].OnClicked += dialog.Close;
|
||||
}
|
||||
|
||||
if (createNetworkEvent)
|
||||
{
|
||||
SendCrewState(true, validateHires: true);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool FireCharacter(GUIButton button, object selection)
|
||||
{
|
||||
if (!(selection is CharacterInfo characterInfo)) { return false; }
|
||||
|
||||
campaign.CrewManager.FireCharacter(characterInfo);
|
||||
SelectCharacter(null, null, null);
|
||||
UpdateCrew();
|
||||
|
||||
SendCrewState(false, firedCharacter: characterInfo);
|
||||
return false;
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
if (GameMain.GraphicsWidth != resolutionWhenCreated.X || GameMain.GraphicsHeight != resolutionWhenCreated.Y)
|
||||
{
|
||||
CreateUI();
|
||||
UpdateLocationView(campaign.Map.CurrentLocation, false);
|
||||
}
|
||||
|
||||
if ((GUI.MouseOn?.UserData as Tuple<CharacterInfo, float>)?.Item1 is CharacterInfo characterInfo)
|
||||
{
|
||||
if (characterPreviewFrame == null || characterInfo != characterPreviewFrame.UserData)
|
||||
{
|
||||
GUIComponent component = GUI.MouseOn;
|
||||
GUIListBox listBox = null;
|
||||
do
|
||||
{
|
||||
if (component.Parent is GUIListBox)
|
||||
{
|
||||
listBox = component.Parent as GUIListBox;
|
||||
break;
|
||||
}
|
||||
else if (component.Parent != null)
|
||||
{
|
||||
component = component.Parent;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
} while (listBox == null);
|
||||
|
||||
if (listBox != null)
|
||||
{
|
||||
SelectCharacter(listBox, GUI.MouseOn as GUIFrame, characterInfo);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: Reposition the current preview panel if necessary
|
||||
// Could happen if we scroll a list while hovering?
|
||||
}
|
||||
}
|
||||
else if (characterPreviewFrame != null)
|
||||
{
|
||||
characterPreviewFrame.Parent?.RemoveChild(characterPreviewFrame);
|
||||
characterPreviewFrame = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void SetPendingHires(List<int> characterInfos, Location location)
|
||||
{
|
||||
List<CharacterInfo> oldHires = PendingHires.ToList();
|
||||
foreach (CharacterInfo pendingHire in oldHires)
|
||||
{
|
||||
RemovePendingHire(pendingHire, createNetworkMessage: false);
|
||||
}
|
||||
PendingHires.Clear();
|
||||
foreach (int identifier in characterInfos)
|
||||
{
|
||||
CharacterInfo match = location.HireManager.AvailableCharacters.Find(info => info.GetIdentifier() == identifier);
|
||||
if (match != null)
|
||||
{
|
||||
PendingHires.Add(match);
|
||||
AddPendingHire(match, createNetworkMessage: false);
|
||||
}
|
||||
else
|
||||
{
|
||||
DebugConsole.ThrowError("Received a hire that doesn't exist.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Notify the server of crew changes
|
||||
/// </summary>
|
||||
/// <param name="updatePending">When set to true will tell the server to update the pending hires</param>
|
||||
/// <param name="firedCharacter">When not null tell the server to fire this character</param>
|
||||
/// <param name="validateHires">When set to true will tell the server to validate pending hires</param>
|
||||
public void SendCrewState(bool updatePending, CharacterInfo firedCharacter = null, bool validateHires = false)
|
||||
{
|
||||
if (campaign is MultiPlayerCampaign)
|
||||
{
|
||||
IWriteMessage msg = new WriteOnlyMessage();
|
||||
msg.Write((byte)ClientPacketHeader.CREW);
|
||||
|
||||
msg.Write(updatePending);
|
||||
if (updatePending)
|
||||
{
|
||||
msg.Write((ushort)PendingHires.Count);
|
||||
foreach (CharacterInfo pendingHire in PendingHires)
|
||||
{
|
||||
msg.Write(pendingHire.GetIdentifier());
|
||||
}
|
||||
}
|
||||
|
||||
msg.Write(validateHires);
|
||||
|
||||
msg.Write(firedCharacter != null);
|
||||
if (firedCharacter != null)
|
||||
{
|
||||
msg.Write(firedCharacter.GetIdentifier());
|
||||
}
|
||||
|
||||
GameMain.Client.ClientPeer?.Send(msg, DeliveryMethod.Reliable);
|
||||
}
|
||||
}
|
||||
|
||||
private string FormatCurrency(int currency) => TextManager.GetWithVariable("currencyformat", "[credits]", string.Format(CultureInfo.InvariantCulture, "{0:N0}", currency));
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,5 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
|
||||
namespace Barotrauma
|
||||
@@ -145,6 +146,11 @@ namespace Barotrauma
|
||||
textBlock.ToolTip = value;
|
||||
}
|
||||
}
|
||||
|
||||
public bool Pulse { get; set; }
|
||||
private float pulseTimer;
|
||||
private float pulseExpand;
|
||||
private bool flashed;
|
||||
|
||||
public GUIButton(RectTransform rectT, string text = "", Alignment textAlignment = Alignment.Center, string style = "", Color? color = null) : base(style, rectT)
|
||||
{
|
||||
@@ -196,7 +202,14 @@ namespace Barotrauma
|
||||
|
||||
protected override void Draw(SpriteBatch spriteBatch)
|
||||
{
|
||||
//do nothing
|
||||
if (Pulse && pulseTimer > 1.0f)
|
||||
{
|
||||
Rectangle expandRect = Rect;
|
||||
float expand = (pulseExpand * 20.0f) * GUI.Scale;
|
||||
expandRect.Inflate(expand, expand);
|
||||
|
||||
GUI.Style.ButtonPulse.Draw(spriteBatch, expandRect, ToolBox.GradientLerp(pulseExpand, Color.White, Color.White, Color.Transparent));
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Update(float deltaTime)
|
||||
@@ -244,13 +257,41 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
State = Selected ? ComponentState.Selected : ComponentState.None;
|
||||
if (!ExternalHighlight)
|
||||
{
|
||||
State = Selected ? ComponentState.Selected : ComponentState.None;
|
||||
}
|
||||
else
|
||||
{
|
||||
State = ComponentState.Hover;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (GUIComponent child in Children)
|
||||
{
|
||||
child.State = State;
|
||||
}
|
||||
|
||||
if (Pulse)
|
||||
{
|
||||
pulseTimer += deltaTime;
|
||||
if (pulseTimer > 1.0f)
|
||||
{
|
||||
if (!flashed)
|
||||
{
|
||||
flashed = true;
|
||||
Frame.Flash(Color.White * 0.2f, 0.8f, true);
|
||||
}
|
||||
|
||||
pulseExpand += deltaTime;
|
||||
if (pulseExpand > 1.0f)
|
||||
{
|
||||
pulseTimer = 0.0f;
|
||||
pulseExpand = 0.0f;
|
||||
flashed = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace Barotrauma
|
||||
_instance = new GUICanvas();
|
||||
if (GameMain.Instance != null)
|
||||
{
|
||||
GameMain.Instance.OnResolutionChanged += RecalculateSize;
|
||||
GameMain.Instance.ResolutionChanged += RecalculateSize;
|
||||
}
|
||||
_instance.ItemComponentHolder = new GUIFrame(new RectTransform(Vector2.One, _instance, Anchor.Center)).RectTransform;
|
||||
}
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
public class GUIColorSettings
|
||||
{
|
||||
// Inventory
|
||||
public static Color EquipmentSlotIconColor = new Color(99, 70, 64);
|
||||
|
||||
// Health HUD
|
||||
public static Color BuffColorLow = Color.LightGreen;
|
||||
public static Color BuffColorMedium = Color.Green;
|
||||
public static Color BuffColorHigh = Color.DarkGreen;
|
||||
|
||||
public static Color DebuffColorLow = Color.DarkSalmon;
|
||||
public static Color DebuffColorMedium = Color.Red;
|
||||
public static Color DebuffColorHigh = Color.DarkRed;
|
||||
|
||||
public static Color HealthBarColorLow = Color.Red;
|
||||
public static Color HealthBarColorMedium = Color.Orange;
|
||||
public static Color HealthBarColorHigh = new Color(78, 114, 88);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -11,12 +11,16 @@ using System.Net;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
public enum SlideDirection { Up, Down, Left, Right }
|
||||
|
||||
public abstract class GUIComponent
|
||||
{
|
||||
#region Hierarchy
|
||||
public GUIComponent Parent => RectTransform.Parent?.GUIComponent;
|
||||
|
||||
public CursorState HoverCursor = CursorState.Default;
|
||||
|
||||
public bool AlwaysOverrideCursor = false;
|
||||
|
||||
public delegate bool SecondaryButtonDownHandler(GUIComponent component, object userData);
|
||||
public SecondaryButtonDownHandler OnSecondaryClicked;
|
||||
@@ -75,7 +79,7 @@ namespace Barotrauma
|
||||
|
||||
public virtual void RemoveChild(GUIComponent child)
|
||||
{
|
||||
if (child == null) return;
|
||||
if (child == null) { return; }
|
||||
child.RectTransform.Parent = null;
|
||||
}
|
||||
|
||||
@@ -139,6 +143,11 @@ namespace Barotrauma
|
||||
public bool AutoUpdate { get; set; } = true;
|
||||
public bool AutoDraw { get; set; } = true;
|
||||
public int UpdateOrder { get; set; }
|
||||
|
||||
public bool Bounce { get; set; }
|
||||
private float bounceTimer;
|
||||
private float bounceJump;
|
||||
private bool bounceDown;
|
||||
|
||||
public Action<GUIComponent> OnAddedToGUIUpdateList;
|
||||
|
||||
@@ -158,6 +167,8 @@ namespace Barotrauma
|
||||
protected Color disabledColor;
|
||||
protected Color pressedColor;
|
||||
|
||||
public bool GlowOnSelect { get; set; }
|
||||
|
||||
private CoroutineHandle pulsateCoroutine;
|
||||
|
||||
protected Color flashColor;
|
||||
@@ -326,6 +337,11 @@ namespace Barotrauma
|
||||
{
|
||||
get { return RectTransform.CountChildren; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Currently only used for the fade effect in GUIListBox, should be set to the same value as Color but only assigned once
|
||||
/// </summary>
|
||||
public Color DefaultColor { get; set; }
|
||||
|
||||
public virtual Color Color
|
||||
{
|
||||
@@ -462,6 +478,36 @@ namespace Barotrauma
|
||||
OnSecondaryClicked?.Invoke(this, userData);
|
||||
}
|
||||
}
|
||||
|
||||
if (Bounce)
|
||||
{
|
||||
if (bounceTimer > 3.0f || bounceDown)
|
||||
{
|
||||
RectTransform.ScreenSpaceOffset = new Point(RectTransform.ScreenSpaceOffset.X, (int) -(bounceJump * 10f));
|
||||
if (!bounceDown)
|
||||
{
|
||||
bounceJump += deltaTime * 4;
|
||||
if (bounceJump > 0.5f)
|
||||
{
|
||||
bounceDown = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
bounceJump -= deltaTime * 4;
|
||||
if (bounceJump <= 0.0f)
|
||||
{
|
||||
bounceJump = 0.0f;
|
||||
bounceTimer = 0.0f;
|
||||
bounceDown = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
bounceTimer += deltaTime;
|
||||
}
|
||||
}
|
||||
|
||||
if (flashTimer > 0.0f)
|
||||
{
|
||||
@@ -526,12 +572,14 @@ namespace Barotrauma
|
||||
protected virtual Color GetColor(ComponentState state)
|
||||
{
|
||||
if (!Enabled) { return DisabledColor; }
|
||||
if (ExternalHighlight) { return HoverColor; }
|
||||
|
||||
return state switch
|
||||
{
|
||||
ComponentState.Hover => HoverColor,
|
||||
ComponentState.HoverSelected => HoverColor,
|
||||
ComponentState.Pressed => PressedColor,
|
||||
ComponentState.Selected => SelectedColor,
|
||||
ComponentState.Selected when !GlowOnSelect => SelectedColor,
|
||||
_ => Color,
|
||||
};
|
||||
}
|
||||
@@ -619,6 +667,11 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
if (GlowOnSelect && State == ComponentState.Selected)
|
||||
{
|
||||
GUI.UIGlow.Draw(spriteBatch, Rect, SelectedColor);
|
||||
}
|
||||
|
||||
if (flashTimer > 0.0f)
|
||||
{
|
||||
//the number of flashes depends on the duration, 1 flash per 1 full second
|
||||
@@ -690,6 +743,7 @@ namespace Barotrauma
|
||||
protected virtual void SetAlpha(float a)
|
||||
{
|
||||
color = new Color(color.R / 255.0f, color.G / 255.0f, color.B / 255.0f, a);
|
||||
hoverColor = new Color(hoverColor.R / 255.0f, hoverColor.G / 255.0f, hoverColor.B / 255.0f, a);;
|
||||
}
|
||||
|
||||
public virtual void Flash(Color? color = null, float flashDuration = 1.5f, bool useRectangleFlash = false, bool useCircularFlash = false, Vector2? flashRectInflate = null)
|
||||
@@ -707,10 +761,77 @@ namespace Barotrauma
|
||||
CoroutineManager.StartCoroutine(LerpAlpha(0.0f, duration, removeAfter));
|
||||
}
|
||||
|
||||
private IEnumerable<object> LerpAlpha(float to, float duration, bool removeAfter)
|
||||
public void FadeIn(float wait, float duration)
|
||||
{
|
||||
SetAlpha(0.0f);
|
||||
CoroutineManager.StartCoroutine(LerpAlpha(1.0f, duration, false, wait));
|
||||
}
|
||||
|
||||
public void SlideIn(float wait, float duration, int amount, SlideDirection direction)
|
||||
{
|
||||
RectTransform.ScreenSpaceOffset = direction switch
|
||||
{
|
||||
SlideDirection.Up => new Point(0, amount),
|
||||
SlideDirection.Down => new Point(0, -amount),
|
||||
SlideDirection.Left => new Point(amount, 0),
|
||||
SlideDirection.Right => new Point(-amount, 0),
|
||||
_ => RectTransform.ScreenSpaceOffset
|
||||
};
|
||||
CoroutineManager.StartCoroutine(SlideToPosition(duration, wait, Vector2.Zero));
|
||||
}
|
||||
|
||||
public void SlideOut(float duration, int amount, SlideDirection direction)
|
||||
{
|
||||
RectTransform.ScreenSpaceOffset = Point.Zero;
|
||||
|
||||
Vector2 targetPos = direction switch
|
||||
{
|
||||
SlideDirection.Up => new Vector2(0, amount),
|
||||
SlideDirection.Down => new Vector2(0, -amount),
|
||||
SlideDirection.Left => new Vector2(amount, 0),
|
||||
SlideDirection.Right => new Vector2(-amount, 0),
|
||||
_ => Vector2.Zero
|
||||
};
|
||||
|
||||
CoroutineManager.StartCoroutine(SlideToPosition(duration, 0.0f, targetPos));
|
||||
}
|
||||
|
||||
private IEnumerable<object> SlideToPosition(float duration, float wait, Vector2 target)
|
||||
{
|
||||
float t = 0.0f;
|
||||
float startA = color.A;
|
||||
var (startX, startY) = RectTransform.ScreenSpaceOffset.ToVector2();
|
||||
var (endX, endY) = target;
|
||||
while (t < wait)
|
||||
{
|
||||
t += CoroutineManager.DeltaTime;
|
||||
yield return CoroutineStatus.Running;
|
||||
}
|
||||
t = 0.0f;
|
||||
|
||||
while (t < duration)
|
||||
{
|
||||
t += CoroutineManager.DeltaTime;
|
||||
RectTransform.ScreenSpaceOffset = new Point((int)MathHelper.Lerp(startX, endX, t / duration), (int)MathHelper.Lerp(startY, endY, t / duration));
|
||||
yield return CoroutineStatus.Running;
|
||||
}
|
||||
|
||||
RectTransform.ScreenSpaceOffset = new Point(0, 0);
|
||||
|
||||
yield return CoroutineStatus.Success;
|
||||
}
|
||||
|
||||
private IEnumerable<object> LerpAlpha(float to, float duration, bool removeAfter, float wait = 0.0f)
|
||||
{
|
||||
State = ComponentState.None;
|
||||
float t = 0.0f;
|
||||
float startA = color.A / 255.0f;
|
||||
|
||||
while (t < wait)
|
||||
{
|
||||
t += CoroutineManager.DeltaTime;
|
||||
yield return CoroutineStatus.Running;
|
||||
}
|
||||
t = 0.0f;
|
||||
|
||||
while (t < duration)
|
||||
{
|
||||
|
||||
@@ -6,6 +6,8 @@ namespace Barotrauma
|
||||
{
|
||||
public class GUIFrame : GUIComponent
|
||||
{
|
||||
public int OutlineThickness { get; set; }
|
||||
|
||||
public GUIFrame(RectTransform rectT, string style = "", Color? color = null) : base(style, rectT)
|
||||
{
|
||||
Enabled = true;
|
||||
@@ -26,7 +28,7 @@ namespace Barotrauma
|
||||
|
||||
if (OutlineColor != Color.Transparent)
|
||||
{
|
||||
GUI.DrawRectangle(spriteBatch, Rect, OutlineColor * (OutlineColor.A/255.0f), false);
|
||||
GUI.DrawRectangle(spriteBatch, Rect, OutlineColor * (OutlineColor.A/255.0f), false, thickness: OutlineThickness);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,17 +42,32 @@ namespace Barotrauma
|
||||
{
|
||||
return crop;
|
||||
}
|
||||
set
|
||||
}
|
||||
|
||||
public void SetCrop(bool state, bool center = true)
|
||||
{
|
||||
crop = state;
|
||||
if (crop && sprite != null)
|
||||
{
|
||||
crop = value;
|
||||
if (crop)
|
||||
{
|
||||
sourceRect.Width = Math.Min(sprite.SourceRect.Width, Rect.Width);
|
||||
sourceRect.Height = Math.Min(sprite.SourceRect.Height, Rect.Height);
|
||||
sourceRect.Width = Math.Min(sprite.SourceRect.Width, (int)(Rect.Width / Scale));
|
||||
sourceRect.Height = Math.Min(sprite.SourceRect.Height, (int)(Rect.Height / Scale));
|
||||
|
||||
if (center)
|
||||
{
|
||||
sourceRect.X = (sprite.SourceRect.Width - sourceRect.Width) / 2;
|
||||
sourceRect.Y = (sprite.SourceRect.Height - sourceRect.Height) / 2;
|
||||
}
|
||||
|
||||
origin = sourceRect.Size.ToVector2() / 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
origin = sprite == null ? Vector2.Zero : sprite.size / 2;
|
||||
}
|
||||
}
|
||||
|
||||
private Vector2 origin;
|
||||
|
||||
public float Scale
|
||||
{
|
||||
get;
|
||||
@@ -72,7 +87,8 @@ namespace Barotrauma
|
||||
{
|
||||
if (sprite == value) return;
|
||||
sprite = value;
|
||||
sourceRect = sprite.SourceRect;
|
||||
sourceRect = value == null ? Rectangle.Empty : value.SourceRect;
|
||||
origin = value == null ? Vector2.Zero : value.size / 2;
|
||||
if (scaleToFit) RecalculateScale();
|
||||
}
|
||||
}
|
||||
@@ -134,7 +150,8 @@ namespace Barotrauma
|
||||
{
|
||||
loadingTextures = true;
|
||||
loading = true;
|
||||
TaskPool.Add(LoadTextureAsync(), (Task) =>
|
||||
TaskPool.Add("LoadTextureAsync",
|
||||
LoadTextureAsync(), (Task) =>
|
||||
{
|
||||
loading = false;
|
||||
lazyLoaded = true;
|
||||
@@ -178,7 +195,7 @@ namespace Barotrauma
|
||||
}
|
||||
else if (sprite?.Texture != null)
|
||||
{
|
||||
spriteBatch.Draw(sprite.Texture, Rect.Center.ToVector2(), sourceRect, currentColor * (currentColor.A / 255.0f), Rotation, sprite.size / 2,
|
||||
spriteBatch.Draw(sprite.Texture, Rect.Center.ToVector2(), sourceRect, currentColor * (currentColor.A / 255.0f), Rotation, origin,
|
||||
Scale, SpriteEffects, 0.0f);
|
||||
}
|
||||
|
||||
|
||||
@@ -134,7 +134,7 @@ namespace Barotrauma
|
||||
(RectTransform.Children.Count(c => !c.GUIComponent.IgnoreLayoutGroups) - 1) *
|
||||
(absoluteSpacing + relativeSpacing * thisSize);
|
||||
|
||||
stretchFactor = totalSize <= 0.0f || minSize >= thisSize ?
|
||||
stretchFactor = totalSize <= 0.0f || minSize >= thisSize || totalSize == minSize ?
|
||||
1.0f :
|
||||
(thisSize - minSize) / (totalSize - minSize);
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ namespace Barotrauma
|
||||
public GUIScrollBar ScrollBar { get; private set; }
|
||||
|
||||
private Dictionary<GUIComponent, bool> childVisible = new Dictionary<GUIComponent, bool>();
|
||||
|
||||
|
||||
private int totalSize;
|
||||
private bool childrenNeedsRecalculation;
|
||||
private bool scrollBarNeedsRecalculation;
|
||||
@@ -59,6 +59,37 @@ namespace Barotrauma
|
||||
|
||||
private bool useGridLayout;
|
||||
|
||||
private float targetScroll;
|
||||
|
||||
private GUIComponent pendingScroll;
|
||||
|
||||
public bool AllowMouseWheelScroll { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Scrolls the list smoothly
|
||||
/// </summary>
|
||||
public bool SmoothScroll { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether to only allow scrolling from one element to the next when smooth scrolling is enabled
|
||||
/// </summary>
|
||||
public bool ClampScrollToElements { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// When set to true elements at the bottom of the list are gradually faded
|
||||
/// </summary>
|
||||
public bool FadeElements { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Adds enough extra padding to the bottom so the end of the scroll will only contain the last element
|
||||
/// </summary>
|
||||
public bool PadBottom { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// When set to true always selects the topmost item on the list
|
||||
/// </summary>
|
||||
public bool SelectTop { get; set; }
|
||||
|
||||
public bool UseGridLayout
|
||||
{
|
||||
get { return useGridLayout; }
|
||||
@@ -189,10 +220,13 @@ namespace Barotrauma
|
||||
private Point draggedReferenceOffset;
|
||||
|
||||
public GUIComponent DraggedElement => draggedElement;
|
||||
|
||||
private bool scheduledScroll = false;
|
||||
|
||||
/// <param name="isScrollBarOnDefaultSide">For horizontal listbox, default side is on the bottom. For vertical, it's on the right.</param>
|
||||
public GUIListBox(RectTransform rectT, bool isHorizontal = false, Color? color = null, string style = "", bool isScrollBarOnDefaultSide = true, bool useMouseDownToSelect = false) : base(style, rectT)
|
||||
{
|
||||
HoverCursor = CursorState.Hand;
|
||||
CanBeFocused = true;
|
||||
selected = new List<GUIComponent>();
|
||||
this.useMouseDownToSelect = useMouseDownToSelect;
|
||||
@@ -363,6 +397,49 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Scrolls the list to the specific element, currently only works when smooth scrolling and PadBottom are enabled.
|
||||
/// </summary>
|
||||
/// <param name="component"></param>
|
||||
public void ScrollToElement(GUIComponent component)
|
||||
{
|
||||
GUI.PlayUISound(GUISoundType.Click);
|
||||
List<GUIComponent> children = Content.Children.ToList();
|
||||
int index = children.IndexOf(component);
|
||||
if (index < 0) { return; }
|
||||
|
||||
targetScroll = MathHelper.Clamp(MathHelper.Lerp(0, 1, MathUtils.InverseLerp(0, (children.Count - 0.9f), index)), ScrollBar.MinValue, ScrollBar.MaxValue);
|
||||
}
|
||||
|
||||
public void ScrollToEnd(float duration)
|
||||
{
|
||||
CoroutineManager.StartCoroutine(ScrollCoroutine());
|
||||
|
||||
IEnumerable<object> ScrollCoroutine()
|
||||
{
|
||||
if (BarSize >= 1.0f)
|
||||
{
|
||||
yield return CoroutineStatus.Success;
|
||||
}
|
||||
float t = 0.0f;
|
||||
float startScroll = BarScroll * BarSize;
|
||||
float distanceToTravel = ScrollBar.MaxValue - startScroll;
|
||||
float progress = startScroll;
|
||||
float speed = distanceToTravel / duration;
|
||||
|
||||
while (t < duration && !MathUtils.NearlyEqual(ScrollBar.MaxValue, progress))
|
||||
{
|
||||
t += CoroutineManager.DeltaTime;
|
||||
progress += speed * CoroutineManager.DeltaTime;
|
||||
BarScroll = progress;
|
||||
yield return CoroutineStatus.Running;
|
||||
}
|
||||
|
||||
yield return CoroutineStatus.Success;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void UpdateChildrenRect()
|
||||
{
|
||||
@@ -404,6 +481,32 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
if (SelectTop)
|
||||
{
|
||||
foreach (GUIComponent child in Content.Children)
|
||||
{
|
||||
child.CanBeFocused = !selected.Contains(child);
|
||||
if (!child.CanBeFocused)
|
||||
{
|
||||
child.State = ComponentState.None;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (SelectTop && Content.Children.Any() && pendingScroll == null)
|
||||
{
|
||||
GUIComponent component = Content.Children.FirstOrDefault(c => (c.Rect.Y - Content.Rect.Y) / (float)c.Rect.Height > -0.1f);
|
||||
|
||||
if (component != null && !selected.Contains(component))
|
||||
{
|
||||
int index = Content.Children.ToList().IndexOf(component);
|
||||
if (index >= 0)
|
||||
{
|
||||
Select(index, false, false, takeKeyBoardFocus: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < Content.CountChildren; i++)
|
||||
{
|
||||
var child = Content.RectTransform.GetChild(i)?.GUIComponent;
|
||||
@@ -418,7 +521,16 @@ namespace Barotrauma
|
||||
|
||||
if (mouseDown)
|
||||
{
|
||||
Select(i, autoScroll: false);
|
||||
if (SelectTop)
|
||||
{
|
||||
pendingScroll = child;
|
||||
ScrollToElement(child);
|
||||
Select(i, autoScroll: false, takeKeyBoardFocus: true);
|
||||
}
|
||||
else
|
||||
{
|
||||
Select(i, autoScroll: false, takeKeyBoardFocus: true);
|
||||
}
|
||||
}
|
||||
|
||||
if (CanDragElements && PlayerInput.LeftButtonDown() && GUI.MouseOn == child)
|
||||
@@ -538,10 +650,93 @@ namespace Barotrauma
|
||||
{
|
||||
UpdateScrollBarSize();
|
||||
}
|
||||
if ((GUI.IsMouseOn(this) || GUI.IsMouseOn(ScrollBar)) && PlayerInput.ScrollWheelSpeed != 0)
|
||||
|
||||
|
||||
if (FadeElements)
|
||||
{
|
||||
ScrollBar.BarScroll -= (PlayerInput.ScrollWheelSpeed / 500.0f) * BarSize;
|
||||
foreach (var (component, _) in childVisible)
|
||||
{
|
||||
float lerp = 0;
|
||||
float y = component.Rect.Y;
|
||||
float contentY = Content.Rect.Y;
|
||||
float height = component.Rect.Height;
|
||||
if (y < Content.Rect.Y)
|
||||
{
|
||||
float distance = (contentY - y) / height;
|
||||
lerp = distance;
|
||||
}
|
||||
|
||||
float centerY = Content.Rect.Y + Content.Rect.Height / 2.0f;
|
||||
if (y > centerY)
|
||||
{
|
||||
float distance = (y - centerY) / (centerY - height);
|
||||
lerp = distance;
|
||||
}
|
||||
|
||||
component.Color = component.HoverColor = ToolBox.GradientLerp(lerp, component.DefaultColor, Color.Transparent);
|
||||
component.DisabledColor = ToolBox.GradientLerp(lerp, component.Style.DisabledColor, Color.Transparent);
|
||||
component.HoverColor = ToolBox.GradientLerp(lerp, component.Style.HoverColor, Color.Transparent);
|
||||
|
||||
foreach (var child in component.GetAllChildren())
|
||||
{
|
||||
Color gradient = ToolBox.GradientLerp(lerp, child.DefaultColor, Color.Transparent);
|
||||
child.Color = child.HoverColor = gradient;
|
||||
if (child is GUITextBlock block)
|
||||
{
|
||||
block.TextColor = block.HoverTextColor = gradient;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (SmoothScroll)
|
||||
{
|
||||
if (targetScroll > -1)
|
||||
{
|
||||
float distance = Math.Abs(targetScroll - BarScroll);
|
||||
float speed = Math.Max(distance * BarSize, 0.1f);
|
||||
BarScroll = (1.0f - speed) * BarScroll + speed * targetScroll;
|
||||
if (MathUtils.NearlyEqual(BarScroll, targetScroll) || GUIScrollBar.DraggingBar != null)
|
||||
{
|
||||
targetScroll = -1;
|
||||
pendingScroll = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((GUI.IsMouseOn(this) || GUI.IsMouseOn(ScrollBar)) && AllowMouseWheelScroll && PlayerInput.ScrollWheelSpeed != 0)
|
||||
{
|
||||
float speed = PlayerInput.ScrollWheelSpeed / 500.0f * BarSize;
|
||||
if (SmoothScroll)
|
||||
{
|
||||
if (ClampScrollToElements)
|
||||
{
|
||||
bool scrollDown = Math.Clamp(PlayerInput.ScrollWheelSpeed, 0, 1) > 0;
|
||||
|
||||
if (scrollDown)
|
||||
{
|
||||
SelectPrevious(takeKeyBoardFocus: true);
|
||||
}
|
||||
else
|
||||
{
|
||||
SelectNext(takeKeyBoardFocus: true);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pendingScroll = null;
|
||||
if (targetScroll < 0) { targetScroll = BarScroll; }
|
||||
targetScroll -= speed;
|
||||
targetScroll = Math.Clamp(targetScroll, ScrollBar.MinValue, ScrollBar.MaxValue);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ScrollBar.BarScroll -= (PlayerInput.ScrollWheelSpeed / 500.0f) * BarSize;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ScrollBar.Enabled = ScrollBarEnabled && BarSize < 1.0f;
|
||||
if (AutoHideScrollBar)
|
||||
{
|
||||
@@ -553,35 +748,47 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public void SelectNext(bool force = false, bool autoScroll = true)
|
||||
public void SelectNext(bool force = false, bool autoScroll = true, bool takeKeyBoardFocus = false)
|
||||
{
|
||||
int index = SelectedIndex + 1;
|
||||
while (index < Content.CountChildren)
|
||||
{
|
||||
if (Content.GetChild(index).Visible)
|
||||
GUIComponent child = Content.GetChild(index);
|
||||
if (child.Visible)
|
||||
{
|
||||
Select(index, force, autoScroll);
|
||||
Select(index, force, !SmoothScroll && autoScroll, takeKeyBoardFocus: takeKeyBoardFocus);
|
||||
if (SmoothScroll)
|
||||
{
|
||||
pendingScroll = child;
|
||||
ScrollToElement(child);
|
||||
}
|
||||
break;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
public void SelectPrevious(bool force = false, bool autoScroll = true)
|
||||
public void SelectPrevious(bool force = false, bool autoScroll = true, bool takeKeyBoardFocus = false)
|
||||
{
|
||||
int index = SelectedIndex - 1;
|
||||
while (index >= 0)
|
||||
{
|
||||
if (Content.GetChild(index).Visible)
|
||||
GUIComponent child = Content.GetChild(index);
|
||||
if (child.Visible)
|
||||
{
|
||||
Select(index, force, autoScroll);
|
||||
Select(index, force, !SmoothScroll && autoScroll, takeKeyBoardFocus: takeKeyBoardFocus);
|
||||
if (SmoothScroll)
|
||||
{
|
||||
pendingScroll = child;
|
||||
ScrollToElement(child);
|
||||
}
|
||||
break;
|
||||
}
|
||||
index--;
|
||||
}
|
||||
}
|
||||
|
||||
public void Select(int childIndex, bool force = false, bool autoScroll = true)
|
||||
public void Select(int childIndex, bool force = false, bool autoScroll = true, bool takeKeyBoardFocus = false)
|
||||
{
|
||||
if (childIndex >= Content.CountChildren || childIndex < 0) { return; }
|
||||
|
||||
@@ -646,7 +853,7 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
// If one of the children is the subscriber, we don't want to register, because it will unregister the child.
|
||||
if (RectTransform.GetAllChildren().None(rt => rt.GUIComponent == GUI.KeyboardDispatcher.Subscriber))
|
||||
if (takeKeyBoardFocus && RectTransform.GetAllChildren().None(rt => rt.GUIComponent == GUI.KeyboardDispatcher.Subscriber))
|
||||
{
|
||||
Selected = true;
|
||||
GUI.KeyboardDispatcher.Subscriber = this;
|
||||
@@ -712,6 +919,14 @@ namespace Barotrauma
|
||||
totalSize += (ScrollBar.IsHorizontal) ? child.Rect.Width : child.Rect.Height;
|
||||
}
|
||||
totalSize += Content.CountChildren * Spacing;
|
||||
if (PadBottom)
|
||||
{
|
||||
GUIComponent last = Content.Children.LastOrDefault();
|
||||
if (last != null)
|
||||
{
|
||||
totalSize += Rect.Height - last.Rect.Height;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
float minScrollBarSize = 20.0f;
|
||||
|
||||
@@ -57,7 +57,7 @@ namespace Barotrauma
|
||||
|
||||
public GUIMessage(string text, Color color, float lifeTime, ScalableFont font = null)
|
||||
{
|
||||
coloredText = new ColoredText(text, color, false);
|
||||
coloredText = new ColoredText(text, color, false, false);
|
||||
this.lifeTime = lifeTime;
|
||||
Timer = lifeTime;
|
||||
|
||||
@@ -69,7 +69,7 @@ namespace Barotrauma
|
||||
|
||||
public GUIMessage(string text, Color color, Vector2 worldPosition, Vector2 velocity, float lifeTime, Alignment textAlignment = Alignment.Center, ScalableFont font = null)
|
||||
{
|
||||
coloredText = new ColoredText(text, color, false);
|
||||
coloredText = new ColoredText(text, color, false, false);
|
||||
WorldSpace = true;
|
||||
pos = worldPosition;
|
||||
Timer = lifeTime;
|
||||
|
||||
@@ -30,6 +30,7 @@ namespace Barotrauma
|
||||
public GUITextBlock Header { get; private set; }
|
||||
public GUITextBlock Text { get; private set; }
|
||||
public string Tag { get; private set; }
|
||||
public bool Closed { get; private set; }
|
||||
|
||||
public GUIImage Icon
|
||||
{
|
||||
@@ -47,9 +48,16 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
private bool alwaysVisible;
|
||||
public GUIImage BackgroundIcon { get; private set; }
|
||||
private GUIImage newBackgroundIcon;
|
||||
|
||||
public bool AutoClose;
|
||||
|
||||
private readonly bool alwaysVisible;
|
||||
|
||||
private float openState;
|
||||
private float iconState;
|
||||
private bool iconSwitching;
|
||||
private bool closing;
|
||||
|
||||
private Type type;
|
||||
@@ -62,7 +70,7 @@ namespace Barotrauma
|
||||
this.Buttons[0].OnClicked = Close;
|
||||
}
|
||||
|
||||
public GUIMessageBox(string headerText, string text, string[] buttons, Vector2? relativeSize = null, Point? minSize = null, Alignment textAlignment = Alignment.TopLeft, Type type = Type.Default, string tag = "", Sprite icon = null)
|
||||
public GUIMessageBox(string headerText, string text, string[] buttons, Vector2? relativeSize = null, Point? minSize = null, Alignment textAlignment = Alignment.TopLeft, Type type = Type.Default, string tag = "", Sprite icon = null, string iconStyle = "", Sprite backgroundIcon = null)
|
||||
: base(new RectTransform(GUI.Canvas.RelativeSize, GUI.Canvas, Anchor.Center), style: GUI.Style.GetComponentStyle("GUIMessageBox." + type) != null ? "GUIMessageBox." + type : "GUIMessageBox")
|
||||
{
|
||||
int width = (int)(DefaultWidth * (type == Type.Default ? 1.0f : 1.5f)), height = 0;
|
||||
@@ -80,6 +88,15 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
if (backgroundIcon != null)
|
||||
{
|
||||
BackgroundIcon = new GUIImage(new RectTransform(backgroundIcon.size.ToPoint(), RectTransform), backgroundIcon)
|
||||
{
|
||||
IgnoreLayoutGroups = true,
|
||||
Color = Color.Transparent
|
||||
};
|
||||
}
|
||||
|
||||
InnerFrame = new GUIFrame(new RectTransform(new Point(width, height), RectTransform, type == Type.InGame ? Anchor.TopCenter : Anchor.Center) { IsFixedSize = false }, style: null);
|
||||
GUI.Style.Apply(InnerFrame, "", this);
|
||||
this.type = type;
|
||||
@@ -145,6 +162,7 @@ namespace Barotrauma
|
||||
InnerFrame.RectTransform.AbsoluteOffset = new Point(0, GameMain.GraphicsHeight);
|
||||
alwaysVisible = true;
|
||||
CanBeFocused = false;
|
||||
AutoClose = true;
|
||||
GUI.Style.Apply(InnerFrame, "", this);
|
||||
|
||||
var horizontalLayoutGroup = new GUILayoutGroup(new RectTransform(new Vector2(0.98f, 0.95f), InnerFrame.RectTransform, Anchor.Center),
|
||||
@@ -157,6 +175,10 @@ namespace Barotrauma
|
||||
{
|
||||
Icon = new GUIImage(new RectTransform(new Vector2(0.2f, 0.95f), horizontalLayoutGroup.RectTransform), icon, scaleToFit: true);
|
||||
}
|
||||
else if (iconStyle != string.Empty)
|
||||
{
|
||||
Icon = new GUIImage(new RectTransform(new Vector2(0.2f, 0.95f), horizontalLayoutGroup.RectTransform), iconStyle, scaleToFit: true);
|
||||
}
|
||||
|
||||
Content = new GUILayoutGroup(new RectTransform(new Vector2(icon != null ? 0.65f : 0.85f, 1.0f), horizontalLayoutGroup.RectTransform));
|
||||
|
||||
@@ -182,6 +204,10 @@ namespace Barotrauma
|
||||
Text.RectTransform.NonScaledSize = Text.RectTransform.MinSize = Text.RectTransform.MaxSize =
|
||||
new Point(Text.Rect.Width, Text.Rect.Height);
|
||||
Text.RectTransform.IsFixedSize = true;
|
||||
if (string.IsNullOrWhiteSpace(headerText))
|
||||
{
|
||||
Content.ChildAnchor = Anchor.Center;
|
||||
}
|
||||
}
|
||||
|
||||
if (height == 0)
|
||||
@@ -226,6 +252,23 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public void SetBackgroundIcon(Sprite icon)
|
||||
{
|
||||
if (icon == null) { return; }
|
||||
GUIImage newIcon = new GUIImage(new RectTransform(icon.size.ToPoint(), RectTransform), icon)
|
||||
{
|
||||
IgnoreLayoutGroups = true,
|
||||
Color = Color.Transparent
|
||||
};
|
||||
|
||||
if (newBackgroundIcon != null)
|
||||
{
|
||||
RemoveChild(newBackgroundIcon);
|
||||
newBackgroundIcon = null;
|
||||
}
|
||||
newBackgroundIcon = newIcon;
|
||||
}
|
||||
|
||||
protected override void Update(float deltaTime)
|
||||
{
|
||||
if (type == Type.InGame)
|
||||
@@ -246,10 +289,19 @@ namespace Barotrauma
|
||||
|
||||
if (!closing)
|
||||
{
|
||||
InnerFrame.RectTransform.AbsoluteOffset = Vector2.SmoothStep(initialPos, defaultPos, openState).ToPoint();
|
||||
Point step = Vector2.SmoothStep(initialPos, defaultPos, openState).ToPoint();
|
||||
InnerFrame.RectTransform.AbsoluteOffset = step;
|
||||
if (BackgroundIcon != null)
|
||||
{
|
||||
BackgroundIcon.RectTransform.AbsoluteOffset = new Point(InnerFrame.Rect.Location.X - (int) (BackgroundIcon.Rect.Size.X / 1.25f), (int)defaultPos.Y - BackgroundIcon.Rect.Size.Y / 2);
|
||||
if (!MathUtils.NearlyEqual(openState, 1.0f))
|
||||
{
|
||||
BackgroundIcon.Color = ToolBox.GradientLerp(openState, Color.Transparent, Color.White);
|
||||
}
|
||||
}
|
||||
openState = Math.Min(openState + deltaTime * 2.0f, 1.0f);
|
||||
|
||||
if (GUI.MouseOn != InnerFrame && !InnerFrame.IsParentOf(GUI.MouseOn))
|
||||
if (GUI.MouseOn != InnerFrame && !InnerFrame.IsParentOf(GUI.MouseOn) && AutoClose)
|
||||
{
|
||||
inGameCloseTimer += deltaTime;
|
||||
}
|
||||
@@ -262,13 +314,55 @@ namespace Barotrauma
|
||||
else
|
||||
{
|
||||
openState += deltaTime * 2.0f;
|
||||
InnerFrame.RectTransform.AbsoluteOffset = Vector2.SmoothStep(defaultPos, endPos, openState - 1.0f).ToPoint();
|
||||
Point step = Vector2.SmoothStep(defaultPos, endPos, openState - 1.0f).ToPoint();
|
||||
InnerFrame.RectTransform.AbsoluteOffset = step;
|
||||
if (BackgroundIcon != null)
|
||||
{
|
||||
BackgroundIcon.Color *= 0.9f;
|
||||
}
|
||||
if (openState >= 2.0f)
|
||||
{
|
||||
if (Parent != null) { Parent.RemoveChild(this); }
|
||||
if (MessageBoxes.Contains(this)) { MessageBoxes.Remove(this); }
|
||||
}
|
||||
}
|
||||
|
||||
if (newBackgroundIcon != null)
|
||||
{
|
||||
if (!iconSwitching)
|
||||
{
|
||||
if (BackgroundIcon != null)
|
||||
{
|
||||
BackgroundIcon.Color *= 0.9f;
|
||||
if (BackgroundIcon.Color.A == 0)
|
||||
{
|
||||
BackgroundIcon = null;
|
||||
iconSwitching = true;
|
||||
RemoveChild(BackgroundIcon);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
iconSwitching = true;
|
||||
}
|
||||
iconState = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
newBackgroundIcon.SetAsFirstChild();
|
||||
newBackgroundIcon.RectTransform.AbsoluteOffset = new Point(InnerFrame.Rect.Location.X - (int) (newBackgroundIcon.Rect.Size.X / 1.25f), (int)defaultPos.Y - newBackgroundIcon.Rect.Size.Y / 2);
|
||||
newBackgroundIcon.Color = ToolBox.GradientLerp(iconState, Color.Transparent, Color.White);
|
||||
if (newBackgroundIcon.Color.A == 255)
|
||||
{
|
||||
BackgroundIcon = newBackgroundIcon;
|
||||
BackgroundIcon.SetAsFirstChild();
|
||||
newBackgroundIcon = null;
|
||||
iconSwitching = false;
|
||||
}
|
||||
|
||||
iconState = Math.Min(iconState + deltaTime * 2.0f, 1.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -284,6 +378,8 @@ namespace Barotrauma
|
||||
if (Parent != null) { Parent.RemoveChild(this); }
|
||||
if (MessageBoxes.Contains(this)) { MessageBoxes.Remove(this); }
|
||||
}
|
||||
|
||||
Closed = true;
|
||||
}
|
||||
|
||||
public bool Close(GUIButton button, object obj)
|
||||
|
||||
@@ -179,7 +179,7 @@ namespace Barotrauma
|
||||
private float pressedDelay = 0.5f;
|
||||
private bool IsPressedTimerRunning { get { return pressedTimer > 0; } }
|
||||
|
||||
public GUINumberInput(RectTransform rectT, NumberType inputType, string style = "", Alignment textAlignment = Alignment.Center, float? relativeButtonAreaWidth = null) : base(style, rectT)
|
||||
public GUINumberInput(RectTransform rectT, NumberType inputType, string style = "", Alignment textAlignment = Alignment.Center, float? relativeButtonAreaWidth = null, bool hidePlusMinusButtons = false) : base(style, rectT)
|
||||
{
|
||||
LayoutGroup = new GUILayoutGroup(new RectTransform(Vector2.One, rectT), isHorizontal: true, childAnchor: Anchor.CenterLeft) { Stretch = true };
|
||||
|
||||
@@ -235,7 +235,7 @@ namespace Barotrauma
|
||||
return true;
|
||||
};
|
||||
|
||||
if (inputType != NumberType.Int)
|
||||
if (inputType != NumberType.Int || hidePlusMinusButtons)
|
||||
{
|
||||
HidePlusMinusButtons();
|
||||
}
|
||||
|
||||
@@ -121,7 +121,7 @@ namespace Barotrauma
|
||||
(int)(Rect.Width - style.Padding.X + style.Padding.Z),
|
||||
(int)(Rect.Height - style.Padding.Y + style.Padding.W));
|
||||
frame.Visible = showFrame;
|
||||
slider.Visible = true;
|
||||
slider.Visible = BarSize > 0.0f;
|
||||
|
||||
if (showFrame)
|
||||
{
|
||||
|
||||
@@ -37,6 +37,8 @@ namespace Barotrauma
|
||||
public UISprite UIGlow { get; private set; }
|
||||
public UISprite UIGlowCircular { get; private set; }
|
||||
|
||||
public UISprite ButtonPulse { get; private set; }
|
||||
|
||||
public SpriteSheet FocusIndicator { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
@@ -206,6 +208,9 @@ namespace Barotrauma
|
||||
case "uiglowcircular":
|
||||
UIGlowCircular = new UISprite(subElement);
|
||||
break;
|
||||
case "endroundbuttonpulse":
|
||||
ButtonPulse = new UISprite(subElement);
|
||||
break;
|
||||
case "focusindicator":
|
||||
FocusIndicator = new SpriteSheet(subElement);
|
||||
break;
|
||||
@@ -255,7 +260,8 @@ namespace Barotrauma
|
||||
DebugConsole.NewMessage("Global font not defined in the current UI style file. The global font is used to render western symbols when using Chinese/Japanese/Korean localization. Using default font instead...", Color.Orange);
|
||||
}
|
||||
|
||||
GameMain.Instance.OnResolutionChanged += () => { RescaleElements(); };
|
||||
// TODO: Needs to unregister if we ever remove GUIStyles.
|
||||
GameMain.Instance.ResolutionChanged += RescaleElements;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -271,6 +271,8 @@ namespace Barotrauma
|
||||
public OnClickDelegate OnClick;
|
||||
}
|
||||
public List<ClickableArea> ClickableAreas { get; private set; } = new List<ClickableArea>();
|
||||
|
||||
public bool Shadow { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// This is the new constructor.
|
||||
@@ -320,10 +322,10 @@ namespace Barotrauma
|
||||
hasColorHighlight = richTextData != null;
|
||||
}
|
||||
|
||||
public void CalculateHeightFromText(int padding = 0)
|
||||
public void CalculateHeightFromText(int padding = 0, bool removeExtraSpacing = false)
|
||||
{
|
||||
if (wrappedText == null) { return; }
|
||||
RectTransform.Resize(new Point(RectTransform.Rect.Width, (int)Font.MeasureString(wrappedText).Y + padding));
|
||||
RectTransform.Resize(new Point(RectTransform.Rect.Width, (int)Font.MeasureString(wrappedText, removeExtraSpacing).Y + padding));
|
||||
}
|
||||
|
||||
public override void ApplyStyle(GUIComponentStyle componentStyle)
|
||||
@@ -443,8 +445,8 @@ namespace Barotrauma
|
||||
|
||||
protected override void SetAlpha(float a)
|
||||
{
|
||||
base.SetAlpha(a);
|
||||
textColor = new Color(textColor.R, textColor.G, textColor.B, a);
|
||||
// base.SetAlpha(a);
|
||||
textColor = new Color(TextColor.R / 255.0f, TextColor.G / 255.0f, TextColor.B / 255.0f, a);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -626,12 +628,17 @@ namespace Barotrauma
|
||||
|
||||
if (!hasColorHighlight)
|
||||
{
|
||||
Font.DrawString(spriteBatch,
|
||||
Censor ? censoredText : (Wrap ? wrappedText : text),
|
||||
pos,
|
||||
currentTextColor * (currentTextColor.A / 255.0f),
|
||||
0.0f, origin, TextScale,
|
||||
SpriteEffects.None, textDepth);
|
||||
string textToShow = Censor ? censoredText : (Wrap ? wrappedText : text);
|
||||
Color colorToShow = currentTextColor * (currentTextColor.A / 255.0f);
|
||||
|
||||
if (Shadow)
|
||||
{
|
||||
Vector2 shadowOffset = new Vector2(GUI.IntScale(2));
|
||||
Font.DrawString(spriteBatch, textToShow, pos + shadowOffset, Color.Black, 0.0f, origin, TextScale, SpriteEffects.None, textDepth);
|
||||
}
|
||||
|
||||
Font.DrawString(spriteBatch, textToShow, pos, colorToShow, 0.0f, origin, TextScale, SpriteEffects.None, textDepth);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -134,6 +134,10 @@ namespace Barotrauma
|
||||
{
|
||||
textBlock.OverflowClip = value != null;
|
||||
maxTextLength = value;
|
||||
if (Text.Length > MaxTextLength)
|
||||
{
|
||||
SetText(textBlock.Text.Substring(0, (int)maxTextLength));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -360,6 +364,7 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
CaretIndex = Math.Min(CaretIndex, textDrawn.Length);
|
||||
textDrawn = Censor ? textBlock.CensoredText : textBlock.Text;
|
||||
Vector2 textSize = Font.MeasureString(textDrawn.Substring(0, CaretIndex));
|
||||
caretPos = new Vector2(textSize.X, 0) + textBlock.TextPos - textBlock.Origin;
|
||||
|
||||
@@ -75,6 +75,11 @@ namespace Barotrauma
|
||||
get; private set;
|
||||
}
|
||||
|
||||
public static Rectangle VotingArea
|
||||
{
|
||||
get; private set;
|
||||
}
|
||||
|
||||
public static int Padding
|
||||
{
|
||||
get; private set;
|
||||
@@ -84,7 +89,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (GameMain.Instance != null)
|
||||
{
|
||||
GameMain.Instance.OnResolutionChanged += CreateAreas;
|
||||
GameMain.Instance.ResolutionChanged += CreateAreas;
|
||||
GameMain.Config.OnHUDScaleChanged += CreateAreas;
|
||||
CreateAreas();
|
||||
CharacterInfo.Init();
|
||||
@@ -144,6 +149,13 @@ namespace Barotrauma
|
||||
int healthWindowY = GameMain.GraphicsHeight / 2 - healthWindowHeight / 2;
|
||||
|
||||
HealthWindowAreaLeft = new Rectangle(healthWindowX, healthWindowY, healthWindowWidth, healthWindowHeight);
|
||||
|
||||
int votingAreaWidth = (int)(400 * GUI.Scale);
|
||||
int votingAreaX = GameMain.GraphicsWidth - Padding - votingAreaWidth;
|
||||
int votingAreaY = Padding + ButtonAreaTop.Height;
|
||||
|
||||
// Height is based on text content
|
||||
VotingArea = new Rectangle(votingAreaX, votingAreaY, votingAreaWidth, 0);
|
||||
}
|
||||
|
||||
public static void Draw(SpriteBatch spriteBatch)
|
||||
|
||||
@@ -165,7 +165,7 @@ namespace Barotrauma
|
||||
float noiseStrength = (float)PerlinNoise.CalculatePerlin(noiseT, noiseT, 0);
|
||||
float noiseScale = (float)PerlinNoise.CalculatePerlin(noiseT * 5.0f, noiseT * 2.0f, 0) * 4.0f;
|
||||
noiseSprite.DrawTiled(spriteBatch, Vector2.Zero, new Vector2(GameMain.GraphicsWidth, GameMain.GraphicsHeight),
|
||||
startOffset: new Point(Rand.Range(0, noiseSprite.SourceRect.Width), Rand.Range(0, noiseSprite.SourceRect.Height)),
|
||||
startOffset: new Vector2(Rand.Range(0.0f, noiseSprite.SourceRect.Width), Rand.Range(0.0f, noiseSprite.SourceRect.Height)),
|
||||
color: Color.White * noiseStrength * 0.1f,
|
||||
textureScale: Vector2.One * noiseScale);
|
||||
|
||||
@@ -185,7 +185,7 @@ namespace Barotrauma
|
||||
if (LoadState == 100.0f)
|
||||
{
|
||||
#if DEBUG
|
||||
if (GameMain.Config.AutomaticQuickStartEnabled && GameMain.FirstLoad)
|
||||
if (GameMain.Config.AutomaticQuickStartEnabled || GameMain.Config.AutomaticCampaignLoadEnabled && GameMain.FirstLoad)
|
||||
{
|
||||
loadText = "QUICKSTARTING ...";
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,683 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System.Linq;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using Microsoft.Xna.Framework.Input;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
class SubmarineSelection
|
||||
{
|
||||
private const int submarinesPerPage = 4;
|
||||
private int currentPage = 1;
|
||||
private int pageCount;
|
||||
private bool transferService, purchaseService, initialized;
|
||||
private int deliveryFee;
|
||||
private string deliveryLocationName;
|
||||
|
||||
public GUIFrame GuiFrame;
|
||||
private GUIFrame pageIndicatorHolder;
|
||||
private GUICustomComponent selectedSubmarineIndicator;
|
||||
private GUILayoutGroup submarineHorizontalGroup, submarineControlsGroup;
|
||||
private GUIButton browseLeftButton, browseRightButton, confirmButton, confirmButtonAlt;
|
||||
private GUIListBox specsFrame;
|
||||
private GUIImage[] pageIndicators;
|
||||
private GUITextBlock descriptionTextBlock;
|
||||
private int selectionIndicatorThickness;
|
||||
private GUIImage listBackground;
|
||||
|
||||
private List<SubmarineInfo> subsToShow;
|
||||
private SubmarineDisplayContent[] submarineDisplays = new SubmarineDisplayContent[submarinesPerPage];
|
||||
private SubmarineInfo selectedSubmarine = null;
|
||||
private string purchaseAndSwitchText, purchaseOnlyText, deliveryText, currentSubText, deliveryFeeText, priceText, switchText, missingPreviewText, currencyShorthandText, currencyLongText;
|
||||
private RectTransform parent;
|
||||
private Action closeAction;
|
||||
private Sprite pageIndicator;
|
||||
|
||||
public static readonly string[] DeliveryTextVariables = new string[] { "[submarinename1]", "[location1]", "[location2]", "[submarinename2]", "[amount]", "[currencyname]" };
|
||||
public static readonly string[] SwitchTextVariables = new string[] { "[submarinename1]", "[submarinename2]" };
|
||||
public static readonly string[] PurchaseAndSwitchTextVariables = new string[] { "[submarinename1]", "[amount]", "[currencyname]", "[submarinename2]" };
|
||||
public static readonly string[] PurchaseTextVariables = new string[] { "[submarinename]", "[amount]", "[currencyname]" };
|
||||
|
||||
private static readonly string[] notEnoughCreditsDeliveryTextVariables = new string[] { "[currencyname]", "[submarinename]", "[location1]", "[location2]" };
|
||||
private static readonly string[] notEnoughCreditsPurchaseTextVariables = new string[] { "[currencyname]", "[submarinename]" };
|
||||
private string[] messageBoxOptions;
|
||||
|
||||
public const int DeliveryFeePerDistanceTravelled = 1000;
|
||||
public static bool ContentRefreshRequired = false;
|
||||
|
||||
private static readonly Color indicatorColor = new Color(112, 149, 129);
|
||||
private Point createdForResolution;
|
||||
|
||||
private struct SubmarineDisplayContent
|
||||
{
|
||||
public GUIFrame background;
|
||||
public GUIImage submarineImage;
|
||||
public SubmarineInfo displayedSubmarine;
|
||||
public GUITextBlock submarineName;
|
||||
public GUITextBlock submarineClass;
|
||||
public GUITextBlock submarineFee;
|
||||
public GUIButton selectSubmarineButton;
|
||||
public GUITextBlock middleTextBlock;
|
||||
}
|
||||
|
||||
public SubmarineSelection(bool transfer, Action closeAction, RectTransform parent)
|
||||
{
|
||||
if (GameMain.GameSession.Campaign == null) return;
|
||||
|
||||
transferService = transfer;
|
||||
purchaseService = !transfer;
|
||||
this.parent = parent;
|
||||
this.closeAction = closeAction;
|
||||
|
||||
subsToShow = new List<SubmarineInfo>();
|
||||
|
||||
if (GameMain.Client == null)
|
||||
{
|
||||
messageBoxOptions = new string[2] { TextManager.Get("Yes"), TextManager.Get("Cancel") };
|
||||
}
|
||||
else
|
||||
{
|
||||
messageBoxOptions = new string[2] { TextManager.Get("Yes") + " " + TextManager.Get("initiatevoting"), TextManager.Get("Cancel") };
|
||||
}
|
||||
|
||||
if (Submarine.MainSub?.Info == null) return;
|
||||
Initialize();
|
||||
}
|
||||
|
||||
private void Initialize()
|
||||
{
|
||||
initialized = true;
|
||||
if (transferService)
|
||||
{
|
||||
deliveryFee = CalculateDeliveryFee();
|
||||
currentSubText = TextManager.Get("currentsub");
|
||||
deliveryFeeText = TextManager.Get("deliveryfee");
|
||||
deliveryText = TextManager.Get("requestdeliverybutton");
|
||||
switchText = TextManager.Get("switchtosubmarinebutton");
|
||||
}
|
||||
else
|
||||
{
|
||||
purchaseAndSwitchText = TextManager.Get("purchaseandswitch");
|
||||
purchaseOnlyText = TextManager.Get("purchase");
|
||||
priceText = TextManager.Get("price");
|
||||
}
|
||||
|
||||
currencyShorthandText = TextManager.Get("currencyformat");
|
||||
currencyLongText = TextManager.Get("credit").ToLower();
|
||||
|
||||
UpdateSubmarines();
|
||||
missingPreviewText = TextManager.Get("SubPreviewImageNotFound");
|
||||
CreateGUI();
|
||||
}
|
||||
|
||||
private int CalculateDeliveryFee()
|
||||
{
|
||||
int distanceToOutpost = GameMain.GameSession.Map.DistanceToClosestLocationWithOutpost(GameMain.GameSession.Map.CurrentLocation, out Location endLocation);
|
||||
deliveryLocationName = endLocation.Name;
|
||||
return DeliveryFeePerDistanceTravelled * distanceToOutpost;
|
||||
}
|
||||
|
||||
private void CreateGUI()
|
||||
{
|
||||
createdForResolution = new Point(GameMain.GraphicsWidth, GameMain.GraphicsHeight);
|
||||
|
||||
GUILayoutGroup content;
|
||||
GuiFrame = new GUIFrame(new RectTransform(new Vector2(0.75f, 0.7f), parent, Anchor.TopCenter, Pivot.TopCenter) { RelativeOffset = new Vector2(0.0f, 0.02f) });
|
||||
selectionIndicatorThickness = HUDLayoutSettings.Padding / 2;
|
||||
|
||||
GUIFrame background = new GUIFrame(new RectTransform(GuiFrame.Rect.Size - GUIStyle.ItemFrameMargin, GuiFrame.RectTransform, Anchor.Center), color: Color.Black * 0.9f)
|
||||
{
|
||||
CanBeFocused = false
|
||||
};
|
||||
|
||||
content = new GUILayoutGroup(new RectTransform(new Point(background.Rect.Width - HUDLayoutSettings.Padding * 4, background.Rect.Height - HUDLayoutSettings.Padding * 4), background.RectTransform, Anchor.Center)) { AbsoluteSpacing = (int)(HUDLayoutSettings.Padding * 1.5f) };
|
||||
GUITextBlock header = new GUITextBlock(new RectTransform(new Vector2(1f, 0.0f), content.RectTransform), transferService ? TextManager.Get("switchsubmarineheader") : TextManager.GetWithVariable("outpostshipyard", "[location]", GameMain.GameSession.Map.CurrentLocation.Name), font: GUI.LargeFont);
|
||||
header.CalculateHeightFromText(0, true);
|
||||
GUITextBlock credits = new GUITextBlock(new RectTransform(Vector2.One, header.RectTransform), "", font: GUI.SubHeadingFont, textAlignment: Alignment.CenterRight)
|
||||
{
|
||||
TextGetter = CampaignUI.GetMoney
|
||||
};
|
||||
|
||||
new GUIFrame(new RectTransform(new Vector2(1.0f, 0.01f), content.RectTransform), style: "HorizontalLine");
|
||||
|
||||
GUILayoutGroup submarineContentGroup = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.4f), content.RectTransform)) { AbsoluteSpacing = HUDLayoutSettings.Padding, Stretch = true };
|
||||
submarineHorizontalGroup = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.9f), submarineContentGroup.RectTransform)) { IsHorizontal = true, AbsoluteSpacing = HUDLayoutSettings.Padding, Stretch = true };
|
||||
|
||||
submarineControlsGroup = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.1f), submarineContentGroup.RectTransform), true, Anchor.TopCenter);
|
||||
|
||||
GUILayoutGroup infoFrame = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.4f), content.RectTransform)) { IsHorizontal = true, Stretch = true, AbsoluteSpacing = HUDLayoutSettings.Padding };
|
||||
new GUIFrame(new RectTransform(Vector2.One, infoFrame.RectTransform), style: null, new Color(8, 13, 19)) { IgnoreLayoutGroups = true };
|
||||
listBackground = new GUIImage(new RectTransform(new Vector2(0.59f, 1f), infoFrame.RectTransform, Anchor.CenterRight), style: null, true)
|
||||
{
|
||||
IgnoreLayoutGroups = true
|
||||
};
|
||||
new GUIListBox(new RectTransform(Vector2.One, infoFrame.RectTransform)) { IgnoreLayoutGroups = true, CanBeFocused = false };
|
||||
specsFrame = new GUIListBox(new RectTransform(new Vector2(0.39f, 1f), infoFrame.RectTransform), style: null) { Spacing = GUI.IntScale(5), Padding = new Vector4(HUDLayoutSettings.Padding / 2f, HUDLayoutSettings.Padding, 0, 0) };
|
||||
new GUIFrame(new RectTransform(new Vector2(0.02f, 0.8f), infoFrame.RectTransform) { RelativeOffset = new Vector2(0.0f, 0.1f) }, style: "VerticalLine");
|
||||
GUIListBox descriptionFrame = new GUIListBox(new RectTransform(new Vector2(0.59f, 1f), infoFrame.RectTransform), style: null) { Padding = new Vector4(HUDLayoutSettings.Padding / 2f, HUDLayoutSettings.Padding * 1.5f, HUDLayoutSettings.Padding * 1.5f, HUDLayoutSettings.Padding / 2f) };
|
||||
descriptionTextBlock = new GUITextBlock(new RectTransform(new Vector2(1, 0), descriptionFrame.Content.RectTransform), string.Empty, font: GUI.Font, wrap: true) { CanBeFocused = false };
|
||||
|
||||
GUILayoutGroup buttonFrame = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.075f), content.RectTransform), childAnchor: Anchor.CenterRight) { IsHorizontal = true, AbsoluteSpacing = HUDLayoutSettings.Padding };
|
||||
|
||||
if (closeAction != null)
|
||||
{
|
||||
GUIButton closeButton = new GUIButton(new RectTransform(new Vector2(0.2f, 1f), buttonFrame.RectTransform), TextManager.Get("Close"), style: "GUIButtonFreeScale")
|
||||
{
|
||||
OnClicked = (button, userData) =>
|
||||
{
|
||||
closeAction();
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
if (purchaseService) confirmButtonAlt = new GUIButton(new RectTransform(new Vector2(0.2f, 1f), buttonFrame.RectTransform), purchaseOnlyText, style: "GUIButtonFreeScale");
|
||||
confirmButton = new GUIButton(new RectTransform(new Vector2(0.2f, 1f), buttonFrame.RectTransform), purchaseService ? purchaseAndSwitchText : deliveryFee > 0 ? deliveryText : switchText, style: "GUIButtonFreeScale");
|
||||
SetConfirmButtonState(false);
|
||||
|
||||
pageIndicatorHolder = new GUIFrame(new RectTransform(new Vector2(1f, 1.5f), submarineControlsGroup.RectTransform), style: null);
|
||||
pageIndicator = GUI.Style.GetComponentStyle("GUIPageIndicator").GetDefaultSprite();
|
||||
UpdatePaging();
|
||||
|
||||
for (int i = 0; i < submarineDisplays.Length; i++)
|
||||
{
|
||||
SubmarineDisplayContent submarineDisplayElement = new SubmarineDisplayContent();
|
||||
submarineDisplayElement.background = new GUIFrame(new RectTransform(new Vector2(1f / submarinesPerPage, 1f), submarineHorizontalGroup.RectTransform), style: null, new Color(8, 13, 19));
|
||||
submarineDisplayElement.submarineImage = new GUIImage(new RectTransform(new Vector2(0.8f, 1f), submarineDisplayElement.background.RectTransform, Anchor.Center), null, true);
|
||||
submarineDisplayElement.middleTextBlock = new GUITextBlock(new RectTransform(new Vector2(0.8f, 1f), submarineDisplayElement.background.RectTransform, Anchor.Center), string.Empty, textAlignment: Alignment.Center);
|
||||
submarineDisplayElement.submarineName = new GUITextBlock(new RectTransform(new Vector2(1f, 0.1f), submarineDisplayElement.background.RectTransform, Anchor.TopCenter, Pivot.TopCenter) { AbsoluteOffset = new Point(0, HUDLayoutSettings.Padding) }, string.Empty, textAlignment: Alignment.Center, font: GUI.SubHeadingFont);
|
||||
submarineDisplayElement.submarineClass = new GUITextBlock(new RectTransform(new Vector2(1f, 0.1f), submarineDisplayElement.background.RectTransform, Anchor.TopCenter, Pivot.TopCenter) { AbsoluteOffset = new Point(0, HUDLayoutSettings.Padding + (int)GUI.Font.MeasureString(submarineDisplayElement.submarineName.Text).Y) }, string.Empty, textAlignment: Alignment.Center);
|
||||
submarineDisplayElement.submarineFee = new GUITextBlock(new RectTransform(new Vector2(1f, 0.1f), submarineDisplayElement.background.RectTransform, Anchor.BottomCenter, Pivot.BottomCenter) { AbsoluteOffset = new Point(0, HUDLayoutSettings.Padding) }, string.Empty, textAlignment: Alignment.Center, font: GUI.SubHeadingFont);
|
||||
submarineDisplayElement.selectSubmarineButton = new GUIButton(new RectTransform(Vector2.One, submarineDisplayElement.background.RectTransform), style: null);
|
||||
submarineDisplays[i] = submarineDisplayElement;
|
||||
}
|
||||
|
||||
selectedSubmarineIndicator = new GUICustomComponent(new RectTransform(Point.Zero, submarineHorizontalGroup.RectTransform), onDraw: (sb, component) => DrawSubmarineIndicator(sb, component.Rect)) { IgnoreLayoutGroups = true, CanBeFocused = false };
|
||||
}
|
||||
|
||||
private void UpdatePaging()
|
||||
{
|
||||
if (pageIndicatorHolder == null) return;
|
||||
pageIndicatorHolder.ClearChildren();
|
||||
if (currentPage > pageCount) currentPage = pageCount;
|
||||
if (pageCount < 2) return;
|
||||
|
||||
browseLeftButton = new GUIButton(new RectTransform(new Vector2(1.15f, 1.15f), pageIndicatorHolder.RectTransform, Anchor.CenterLeft, Pivot.CenterRight) { AbsoluteOffset = new Point(-HUDLayoutSettings.Padding * 3, 0) }, string.Empty, style: "GUIButtonToggleLeft")
|
||||
{
|
||||
IgnoreLayoutGroups = true,
|
||||
OnClicked = (button, userData) =>
|
||||
{
|
||||
ChangePage(-1);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
Point indicatorSize = new Point(GUI.IntScale(pageIndicator.SourceRect.Width * 1.5f), GUI.IntScale(pageIndicator.SourceRect.Height * 1.5f));
|
||||
pageIndicatorHolder.RectTransform.NonScaledSize = new Point(pageCount * indicatorSize.X + HUDLayoutSettings.Padding * (pageCount - 1), pageIndicatorHolder.RectTransform.NonScaledSize.Y);
|
||||
|
||||
int xPos = 0;
|
||||
int yPos = pageIndicatorHolder.Rect.Height / 2 - indicatorSize.Y / 2;
|
||||
|
||||
pageIndicators = new GUIImage[pageCount];
|
||||
for (int i = 0; i < pageCount; i++)
|
||||
{
|
||||
pageIndicators[i] = new GUIImage(new RectTransform(indicatorSize, pageIndicatorHolder.RectTransform) { AbsoluteOffset = new Point(xPos, yPos) }, pageIndicator, null, true);
|
||||
xPos += indicatorSize.X + HUDLayoutSettings.Padding;
|
||||
}
|
||||
|
||||
for (int i = 0; i < pageIndicators.Length; i++)
|
||||
{
|
||||
pageIndicators[i].Color = i == currentPage - 1 ? Color.White : Color.Gray;
|
||||
}
|
||||
|
||||
browseRightButton = new GUIButton(new RectTransform(new Vector2(1.15f, 1.15f), pageIndicatorHolder.RectTransform, Anchor.CenterRight, Pivot.CenterLeft) { AbsoluteOffset = new Point(-HUDLayoutSettings.Padding * 3, 0) }, string.Empty, style: "GUIButtonToggleRight")
|
||||
{
|
||||
IgnoreLayoutGroups = true,
|
||||
OnClicked = (button, userData) =>
|
||||
{
|
||||
ChangePage(1);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
browseLeftButton.Enabled = currentPage > 1;
|
||||
browseRightButton.Enabled = currentPage < pageCount;
|
||||
}
|
||||
|
||||
private void DrawSubmarineIndicator(SpriteBatch spriteBatch, Rectangle area)
|
||||
{
|
||||
if (area == Rectangle.Empty) return;
|
||||
GUI.DrawRectangle(spriteBatch, area, indicatorColor, thickness: selectionIndicatorThickness);
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
if (ContentRefreshRequired)
|
||||
{
|
||||
RefreshSubmarineDisplay(true);
|
||||
}
|
||||
|
||||
// Input
|
||||
if (PlayerInput.KeyHit(Keys.Left))
|
||||
{
|
||||
SelectSubmarine(subsToShow.IndexOf(selectedSubmarine), -1);
|
||||
}
|
||||
else if (PlayerInput.KeyHit(Keys.Right))
|
||||
{
|
||||
SelectSubmarine(subsToShow.IndexOf(selectedSubmarine), 1);
|
||||
}
|
||||
}
|
||||
|
||||
public void RefreshSubmarineDisplay(bool updateSubs)
|
||||
{
|
||||
if (!initialized) Initialize();
|
||||
if (GameMain.GraphicsWidth != createdForResolution.X || GameMain.GraphicsHeight != createdForResolution.Y) CreateGUI();
|
||||
if (updateSubs) UpdateSubmarines();
|
||||
|
||||
if (pageIndicators != null)
|
||||
{
|
||||
for (int i = 0; i < pageIndicators.Length; i++)
|
||||
{
|
||||
pageIndicators[i].Color = i == currentPage - 1 ? Color.White : Color.Gray;
|
||||
}
|
||||
}
|
||||
|
||||
int submarineIndex = (currentPage - 1) * submarinesPerPage;
|
||||
|
||||
for (int i = 0; i < submarineDisplays.Length; i++)
|
||||
{
|
||||
SubmarineInfo subToDisplay = GetSubToDisplay(submarineIndex);
|
||||
if (subToDisplay == null)
|
||||
{
|
||||
submarineDisplays[i].submarineImage.Sprite = null;
|
||||
submarineDisplays[i].submarineName.Text = string.Empty;
|
||||
submarineDisplays[i].submarineFee.Text = string.Empty;
|
||||
submarineDisplays[i].submarineClass.Text = string.Empty;
|
||||
submarineDisplays[i].selectSubmarineButton.Enabled = false;
|
||||
submarineDisplays[i].selectSubmarineButton.OnClicked = null;
|
||||
submarineDisplays[i].displayedSubmarine = null;
|
||||
submarineDisplays[i].middleTextBlock.AutoDraw = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
submarineDisplays[i].displayedSubmarine = subToDisplay;
|
||||
Sprite previewImage = GetPreviewImage(subToDisplay);
|
||||
|
||||
if (previewImage != null)
|
||||
{
|
||||
submarineDisplays[i].submarineImage.Sprite = previewImage;
|
||||
submarineDisplays[i].middleTextBlock.AutoDraw = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
submarineDisplays[i].submarineImage.Sprite = null;
|
||||
submarineDisplays[i].middleTextBlock.Text = missingPreviewText;
|
||||
submarineDisplays[i].middleTextBlock.AutoDraw = true;
|
||||
}
|
||||
|
||||
submarineDisplays[i].selectSubmarineButton.Enabled = true;
|
||||
|
||||
int index = i;
|
||||
submarineDisplays[i].selectSubmarineButton.OnClicked = (button, userData) =>
|
||||
{
|
||||
SelectSubmarine(subToDisplay, submarineDisplays[index].background.Rect);
|
||||
return true;
|
||||
};
|
||||
|
||||
submarineDisplays[i].submarineName.Text = subToDisplay.DisplayName;
|
||||
submarineDisplays[i].submarineClass.Text = $"{TextManager.GetWithVariable("submarineclass.classsuffixformat", "[type]", TextManager.Get($"submarineclass.{subToDisplay.SubmarineClass}"))}";
|
||||
|
||||
if (!GameMain.GameSession.IsSubmarineOwned(subToDisplay))
|
||||
{
|
||||
string amountString = currencyShorthandText.Replace("[credits]", subToDisplay.Price.ToString());
|
||||
submarineDisplays[i].submarineFee.Text = priceText.Replace("[amount]", amountString).Replace("[currencyname]", string.Empty).TrimEnd();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (subToDisplay.Name != CurrentOrPendingSubmarine().Name)
|
||||
{
|
||||
if (deliveryFee > 0)
|
||||
{
|
||||
string amountString = currencyShorthandText.Replace("[credits]", deliveryFee.ToString());
|
||||
submarineDisplays[i].submarineFee.Text = deliveryFeeText.Replace("[amount]", amountString).Replace("[currencyname]", string.Empty).TrimEnd();
|
||||
}
|
||||
else
|
||||
{
|
||||
submarineDisplays[i].submarineFee.Text = string.Empty;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
submarineDisplays[i].submarineFee.Text = currentSubText;
|
||||
}
|
||||
}
|
||||
|
||||
if (transferService && subToDisplay.Name == CurrentOrPendingSubmarine().Name && updateSubs)
|
||||
{
|
||||
if (selectedSubmarine == null)
|
||||
{
|
||||
CoroutineManager.StartCoroutine(SelectOwnSubmarineWithDelay(subToDisplay, submarineDisplays[i]));
|
||||
}
|
||||
else
|
||||
{
|
||||
SelectSubmarine(subToDisplay, submarineDisplays[i].background.Rect);
|
||||
}
|
||||
}
|
||||
else if (!transferService && selectedSubmarine == null || !transferService && GameMain.GameSession.IsSubmarineOwned(selectedSubmarine) || subToDisplay == selectedSubmarine)
|
||||
{
|
||||
SelectSubmarine(subToDisplay, submarineDisplays[i].background.Rect);
|
||||
}
|
||||
}
|
||||
|
||||
submarineIndex++;
|
||||
}
|
||||
|
||||
if (subsToShow.Count == 0)
|
||||
{
|
||||
SelectSubmarine(null, Rectangle.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateSubmarines()
|
||||
{
|
||||
subsToShow.Clear();
|
||||
if (transferService)
|
||||
{
|
||||
subsToShow.AddRange(GameMain.GameSession.OwnedSubmarines);
|
||||
subsToShow.Sort((x, y) => x.SubmarineClass.CompareTo(y.SubmarineClass));
|
||||
string currentSubName = CurrentOrPendingSubmarine().Name;
|
||||
int currentIndex = subsToShow.FindIndex(s => s.Name == currentSubName);
|
||||
if (currentIndex != -1)
|
||||
{
|
||||
currentPage = (int)Math.Ceiling((currentIndex + 1) / (float)submarinesPerPage);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (GameMain.Client == null)
|
||||
{
|
||||
subsToShow.AddRange(SubmarineInfo.SavedSubmarines.Where(s => s.IsCampaignCompatible && !GameMain.GameSession.OwnedSubmarines.Any(os => os.Name == s.Name)));
|
||||
}
|
||||
else
|
||||
{
|
||||
subsToShow.AddRange(GameMain.NetLobbyScreen.CampaignSubmarines.Where(s => !GameMain.GameSession.OwnedSubmarines.Any(os => os.Name == s.Name)));
|
||||
}
|
||||
|
||||
subsToShow.Sort((x, y) => x.SubmarineClass.CompareTo(y.SubmarineClass));
|
||||
}
|
||||
|
||||
if (transferService) 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;
|
||||
}
|
||||
|
||||
private SubmarineInfo GetSubToDisplay(int index)
|
||||
{
|
||||
if (subsToShow.Count <= index || index < 0) return null;
|
||||
return subsToShow[index];
|
||||
}
|
||||
|
||||
private Sprite GetPreviewImage(SubmarineInfo info)
|
||||
{
|
||||
Sprite preview = info.PreviewImage;
|
||||
|
||||
if (preview == null)
|
||||
{
|
||||
SubmarineInfo potentialMatch;
|
||||
|
||||
if (GameMain.Client == null)
|
||||
{
|
||||
potentialMatch = SubmarineInfo.SavedSubmarines.FirstOrDefault(s => s.EqualityCheckVal == info.EqualityCheckVal);
|
||||
}
|
||||
else
|
||||
{
|
||||
potentialMatch = GameMain.NetLobbyScreen.CampaignSubmarines.FirstOrDefault(s => s.EqualityCheckVal == info.EqualityCheckVal);
|
||||
}
|
||||
|
||||
preview = potentialMatch?.PreviewImage;
|
||||
|
||||
// Try from savedsubmarines with name comparison as a backup
|
||||
if (preview == null)
|
||||
{
|
||||
potentialMatch = SubmarineInfo.SavedSubmarines.FirstOrDefault(s => s.Name == info.Name);
|
||||
preview = potentialMatch?.PreviewImage;
|
||||
}
|
||||
}
|
||||
|
||||
return preview;
|
||||
}
|
||||
|
||||
// Initial submarine selection needs a slight wait to allow the layoutgroups to place content properly
|
||||
private IEnumerable<object> SelectOwnSubmarineWithDelay(SubmarineInfo info, SubmarineDisplayContent display)
|
||||
{
|
||||
yield return new WaitForSeconds(0.05f);
|
||||
SelectSubmarine(info, display.background.Rect);
|
||||
}
|
||||
|
||||
// Selection based on key input
|
||||
private void SelectSubmarine(int index, int direction)
|
||||
{
|
||||
SubmarineInfo nextSub = GetSubToDisplay(index + direction);
|
||||
if (nextSub == null) return;
|
||||
|
||||
for (int i = 0; i < submarineDisplays.Length; i++)
|
||||
{
|
||||
if (submarineDisplays[i].displayedSubmarine == nextSub)
|
||||
{
|
||||
SelectSubmarine(nextSub, submarineDisplays[i].background.Rect);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ChangePage(direction);
|
||||
|
||||
for (int i = 0; i < submarineDisplays.Length; i++)
|
||||
{
|
||||
if (submarineDisplays[i].displayedSubmarine == nextSub)
|
||||
{
|
||||
SelectSubmarine(nextSub, submarineDisplays[i].background.Rect);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void SelectSubmarine(SubmarineInfo info, Rectangle backgroundRect)
|
||||
{
|
||||
#if !DEBUG
|
||||
if (selectedSubmarine == info) return;
|
||||
#endif
|
||||
specsFrame.Content.ClearChildren();
|
||||
selectedSubmarine = info;
|
||||
|
||||
if (info != null)
|
||||
{
|
||||
bool owned = GameMain.GameSession.IsSubmarineOwned(info);
|
||||
|
||||
if (owned)
|
||||
{
|
||||
confirmButton.Text = deliveryFee > 0 ? deliveryText : switchText;
|
||||
confirmButton.OnClicked = (button, userData) =>
|
||||
{
|
||||
ShowTransferPrompt();
|
||||
return true;
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
confirmButton.Text = purchaseAndSwitchText;
|
||||
confirmButton.OnClicked = (button, userData) =>
|
||||
{
|
||||
ShowBuyPrompt(false);
|
||||
return true;
|
||||
};
|
||||
|
||||
confirmButtonAlt.Text = purchaseOnlyText;
|
||||
confirmButtonAlt.OnClicked = (button, userData) =>
|
||||
{
|
||||
ShowBuyPrompt(true);
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
SetConfirmButtonState(selectedSubmarine.Name != CurrentOrPendingSubmarine().Name);
|
||||
|
||||
selectedSubmarineIndicator.RectTransform.NonScaledSize = backgroundRect.Size;
|
||||
selectedSubmarineIndicator.RectTransform.AbsoluteOffset = new Point(backgroundRect.Left - submarineHorizontalGroup.Rect.Left, 0);
|
||||
|
||||
Sprite previewImage = GetPreviewImage(info);
|
||||
listBackground.Sprite = previewImage;
|
||||
listBackground.SetCrop(true);
|
||||
|
||||
ScalableFont font = GUI.Font;
|
||||
info.CreateSpecsWindow(specsFrame, font);
|
||||
descriptionTextBlock.Text = info.Description;
|
||||
descriptionTextBlock.CalculateHeightFromText();
|
||||
}
|
||||
else
|
||||
{
|
||||
listBackground.Sprite = null;
|
||||
listBackground.SetCrop(false);
|
||||
descriptionTextBlock.Text = string.Empty;
|
||||
selectedSubmarineIndicator.RectTransform.NonScaledSize = Point.Zero;
|
||||
SetConfirmButtonState(false);
|
||||
}
|
||||
}
|
||||
|
||||
private void SetConfirmButtonState(bool state)
|
||||
{
|
||||
if (confirmButtonAlt != null)
|
||||
{
|
||||
confirmButtonAlt.Enabled = state;
|
||||
}
|
||||
|
||||
if (confirmButton != null)
|
||||
{
|
||||
confirmButton.Enabled = state;
|
||||
}
|
||||
}
|
||||
|
||||
public static SubmarineInfo CurrentOrPendingSubmarine()
|
||||
{
|
||||
if (GameMain.GameSession?.Campaign?.PendingSubmarineSwitch == null)
|
||||
{
|
||||
return Submarine.MainSub.Info;
|
||||
}
|
||||
else
|
||||
{
|
||||
return GameMain.GameSession.Campaign.PendingSubmarineSwitch;
|
||||
}
|
||||
}
|
||||
|
||||
private void ChangePage(int pageChangeDirection)
|
||||
{
|
||||
SelectSubmarine(null, Rectangle.Empty);
|
||||
if (pageChangeDirection < 0 && currentPage > 1) currentPage--;
|
||||
if (pageChangeDirection > 0 && currentPage < pageCount) currentPage++;
|
||||
browseLeftButton.Enabled = currentPage > 1;
|
||||
browseRightButton.Enabled = currentPage < pageCount;
|
||||
|
||||
RefreshSubmarineDisplay(false);
|
||||
}
|
||||
|
||||
private void ShowTransferPrompt()
|
||||
{
|
||||
if (GameMain.GameSession.Campaign.Money < deliveryFee && deliveryFee > 0)
|
||||
{
|
||||
new GUIMessageBox(TextManager.Get("deliveryrequestheader"), TextManager.GetWithVariables("notenoughmoneyfordeliverytext", notEnoughCreditsDeliveryTextVariables,
|
||||
new string[] { currencyLongText, selectedSubmarine.DisplayName, deliveryLocationName, GameMain.GameSession.Map.CurrentLocation.Name }));
|
||||
return;
|
||||
}
|
||||
|
||||
GUIMessageBox msgBox;
|
||||
|
||||
if (deliveryFee > 0)
|
||||
{
|
||||
msgBox = new GUIMessageBox(TextManager.Get("deliveryrequestheader"), TextManager.GetWithVariables("deliveryrequesttext", DeliveryTextVariables,
|
||||
new string[6] { selectedSubmarine.DisplayName, deliveryLocationName, GameMain.GameSession.Map.CurrentLocation.Name, CurrentOrPendingSubmarine().DisplayName, deliveryFee.ToString(), currencyLongText }), messageBoxOptions);
|
||||
}
|
||||
else
|
||||
{
|
||||
msgBox = new GUIMessageBox(TextManager.Get("switchsubmarineheader"), TextManager.GetWithVariables("switchsubmarinetext", SwitchTextVariables,
|
||||
new string[2] { CurrentOrPendingSubmarine().DisplayName, selectedSubmarine.DisplayName }), messageBoxOptions);
|
||||
}
|
||||
|
||||
msgBox.Buttons[0].OnClicked = (applyButton, obj) =>
|
||||
{
|
||||
if (GameMain.Client == null)
|
||||
{
|
||||
GameMain.GameSession.SwitchSubmarine(selectedSubmarine, deliveryFee);
|
||||
GameMain.GameSession.Campaign.UpgradeManager.RefundResetAndReload(selectedSubmarine);
|
||||
RefreshSubmarineDisplay(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
GameMain.Client.InitiateSubmarineChange(selectedSubmarine, Networking.VoteType.SwitchSub);
|
||||
}
|
||||
return true;
|
||||
};
|
||||
msgBox.Buttons[0].OnClicked += msgBox.Close;
|
||||
msgBox.Buttons[1].OnClicked = msgBox.Close;
|
||||
}
|
||||
|
||||
private void ShowBuyPrompt(bool purchaseOnly)
|
||||
{
|
||||
if (GameMain.GameSession.Campaign.Money < selectedSubmarine.Price)
|
||||
{
|
||||
new GUIMessageBox(TextManager.Get("purchasesubmarineheader"), TextManager.GetWithVariables("notenoughmoneyforpurchasetext", notEnoughCreditsPurchaseTextVariables,
|
||||
new string[2] { currencyLongText, selectedSubmarine.DisplayName }));
|
||||
return;
|
||||
}
|
||||
|
||||
GUIMessageBox msgBox;
|
||||
|
||||
if (!purchaseOnly)
|
||||
{
|
||||
msgBox = new GUIMessageBox(TextManager.Get("purchaseandswitchsubmarineheader"), TextManager.GetWithVariables("purchaseandswitchsubmarinetext", PurchaseAndSwitchTextVariables,
|
||||
new string[4] { selectedSubmarine.DisplayName, selectedSubmarine.Price.ToString(), currencyLongText, CurrentOrPendingSubmarine().DisplayName }), messageBoxOptions);
|
||||
|
||||
msgBox.Buttons[0].OnClicked = (applyButton, obj) =>
|
||||
{
|
||||
if (GameMain.Client == null)
|
||||
{
|
||||
GameMain.GameSession.PurchaseSubmarine(selectedSubmarine);
|
||||
GameMain.GameSession.SwitchSubmarine(selectedSubmarine, 0);
|
||||
GameMain.GameSession.Campaign.UpgradeManager.RefundResetAndReload(selectedSubmarine);
|
||||
RefreshSubmarineDisplay(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
GameMain.Client.InitiateSubmarineChange(selectedSubmarine, Networking.VoteType.PurchaseAndSwitchSub);
|
||||
}
|
||||
return true;
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
msgBox = new GUIMessageBox(TextManager.Get("purchasesubmarineheader"), TextManager.GetWithVariables("purchasesubmarinetext", PurchaseTextVariables,
|
||||
new string[3] { selectedSubmarine.DisplayName, selectedSubmarine.Price.ToString(), currencyLongText }), messageBoxOptions);
|
||||
|
||||
msgBox.Buttons[0].OnClicked = (applyButton, obj) =>
|
||||
{
|
||||
if (GameMain.Client == null)
|
||||
{
|
||||
GameMain.GameSession.PurchaseSubmarine(selectedSubmarine);
|
||||
RefreshSubmarineDisplay(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
GameMain.Client.InitiateSubmarineChange(selectedSubmarine, Networking.VoteType.PurchaseSub);
|
||||
}
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
msgBox.Buttons[0].OnClicked += msgBox.Close;
|
||||
msgBox.Buttons[1].OnClicked = msgBox.Close;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System.Linq;
|
||||
using Barotrauma.Networking;
|
||||
using System.Globalization;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
@@ -13,7 +14,7 @@ namespace Barotrauma
|
||||
|
||||
private static bool initialized = false;
|
||||
|
||||
private static UISprite spectateIcon, deadIcon, disconnectedIcon;
|
||||
private static UISprite spectateIcon, disconnectedIcon;
|
||||
private static Sprite ownerIcon, moderatorIcon;
|
||||
|
||||
private enum InfoFrameTab { Crew, Mission, MyCharacter, Traitor };
|
||||
@@ -31,7 +32,7 @@ namespace Barotrauma
|
||||
private List<Character.TeamType> teamIDs;
|
||||
private const string inLobbyString = "\u2022 \u2022 \u2022";
|
||||
|
||||
private static Color ownCharacterBGColor = Color.Gold * 0.7f;
|
||||
public static Color OwnCharacterBGColor = Color.Gold * 0.7f;
|
||||
|
||||
private class LinkedGUI
|
||||
{
|
||||
@@ -115,10 +116,9 @@ namespace Barotrauma
|
||||
public void Initialize()
|
||||
{
|
||||
spectateIcon = GUI.Style.GetComponentStyle("SpectateIcon").Sprites[GUIComponent.ComponentState.None][0];
|
||||
deadIcon = GUI.Style.GetComponentStyle("DeadIcon").Sprites[GUIComponent.ComponentState.None][0];
|
||||
disconnectedIcon = GUI.Style.GetComponentStyle("DisconnectedIcon").Sprites[GUIComponent.ComponentState.None][0];
|
||||
ownerIcon = GUI.Style.GetComponentStyle("OwnerIcon").Sprites[GUIComponent.ComponentState.None][0].Sprite;
|
||||
moderatorIcon = GUI.Style.GetComponentStyle("ModeratorIcon").Sprites[GUIComponent.ComponentState.None][0].Sprite;
|
||||
ownerIcon = GUI.Style.GetComponentStyle("OwnerIcon").GetDefaultSprite();
|
||||
moderatorIcon = GUI.Style.GetComponentStyle("ModeratorIcon").GetDefaultSprite();
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
@@ -279,7 +279,7 @@ namespace Barotrauma
|
||||
teamIDs = crew.Select(c => c.TeamID).Distinct().ToList();
|
||||
|
||||
// Show own team first when there's more than one team
|
||||
if (teamIDs.Count > 1 && GameMain.Client.Character != null)
|
||||
if (teamIDs.Count > 1 && GameMain.Client?.Character != null)
|
||||
{
|
||||
Character.TeamType ownTeam = GameMain.Client.Character.TeamID;
|
||||
teamIDs = teamIDs.OrderBy(i => i != ownTeam).ThenBy(i => i).ToList();
|
||||
@@ -408,7 +408,7 @@ namespace Barotrauma
|
||||
GUIFrame frame = new GUIFrame(new RectTransform(new Point(crewListArray[i].Content.Rect.Width, GUI.IntScale(33f)), crewListArray[i].Content.RectTransform), style: "ListBoxElement")
|
||||
{
|
||||
UserData = character,
|
||||
Color = (Character.Controlled == character) ? ownCharacterBGColor : Color.Transparent
|
||||
Color = (Character.Controlled == character) ? OwnCharacterBGColor : Color.Transparent
|
||||
};
|
||||
|
||||
var paddedFrame = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.9f), frame.RectTransform, Anchor.Center), isHorizontal: true)
|
||||
@@ -486,7 +486,7 @@ namespace Barotrauma
|
||||
GUIFrame frame = new GUIFrame(new RectTransform(new Point(crewListArray[i].Content.Rect.Width, GUI.IntScale(33f)), crewListArray[i].Content.RectTransform), style: "ListBoxElement")
|
||||
{
|
||||
UserData = character,
|
||||
Color = (GameMain.NetworkMember != null && GameMain.Client.Character == character) ? ownCharacterBGColor : Color.Transparent
|
||||
Color = (GameMain.NetworkMember != null && GameMain.Client.Character == character) ? OwnCharacterBGColor : Color.Transparent
|
||||
};
|
||||
|
||||
frame.OnSecondaryClicked += (component, data) =>
|
||||
@@ -631,7 +631,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (GameMain.NetworkMember == null || client == null || !client.HasPermissions) return null;
|
||||
|
||||
if (!client.AllowKicking) // Owner cannot be kicked
|
||||
if (client.IsOwner) // Owner cannot be kicked
|
||||
{
|
||||
return ownerIcon;
|
||||
}
|
||||
@@ -649,7 +649,10 @@ namespace Barotrauma
|
||||
}
|
||||
else if (client.Character != null && client.Character.IsDead)
|
||||
{
|
||||
client.Character.Info.DrawJobIcon(spriteBatch, area);
|
||||
if (client.Character.Info != null)
|
||||
{
|
||||
client.Character.Info.DrawJobIcon(spriteBatch, area);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -780,7 +783,7 @@ namespace Barotrauma
|
||||
|
||||
public static void StorePlayerConnectionChangeMessage(ChatMessage message)
|
||||
{
|
||||
if (!GameMain.GameSession?.GameMode?.IsRunning ?? true) { return; }
|
||||
if (!GameMain.GameSession?.IsRunning ?? true) { return; }
|
||||
|
||||
string msg = ChatMessage.GetTimeStamp() + message.TextWithSender;
|
||||
storedMessages.Add(new Pair<string, PlayerConnectionChangeType>(msg, message.ChangeType));
|
||||
@@ -847,15 +850,15 @@ namespace Barotrauma
|
||||
infoFrame.ClearChildren();
|
||||
GUIFrame missionFrame = new GUIFrame(new RectTransform(Vector2.One, infoFrame.RectTransform, Anchor.TopCenter), style: "GUIFrameListBox");
|
||||
int padding = (int)(0.0245f * missionFrame.Rect.Height);
|
||||
Location endLocation = GameMain.GameSession.EndLocation;
|
||||
Sprite portrait = endLocation.Type.GetPortrait(endLocation.PortraitId);
|
||||
Location location = GameMain.GameSession.EndLocation != null ? GameMain.GameSession.EndLocation : GameMain.GameSession.StartLocation;
|
||||
Sprite portrait = location.Type.GetPortrait(location.PortraitId);
|
||||
bool hasPortrait = portrait != null && portrait.SourceRect.Width > 0 && portrait.SourceRect.Height > 0;
|
||||
int contentWidth = hasPortrait ? (int)(missionFrame.Rect.Width * 0.951f) : missionFrame.Rect.Width - padding * 2;
|
||||
|
||||
Vector2 locationNameSize = GUI.LargeFont.MeasureString(endLocation.Name);
|
||||
Vector2 locationTypeSize = GUI.SubHeadingFont.MeasureString(endLocation.Name);
|
||||
GUITextBlock locationNameText = new GUITextBlock(new RectTransform(new Point(contentWidth, (int)locationNameSize.Y), missionFrame.RectTransform, Anchor.TopCenter) { AbsoluteOffset = new Point(0, padding) }, endLocation.Name, font: GUI.LargeFont);
|
||||
GUITextBlock locationTypeText = new GUITextBlock(new RectTransform(new Point(contentWidth, (int)locationTypeSize.Y), missionFrame.RectTransform, Anchor.TopCenter) { AbsoluteOffset = new Point(0, locationNameText.Rect.Height + padding) }, endLocation.Type.Name, font: GUI.SubHeadingFont);
|
||||
Vector2 locationNameSize = GUI.LargeFont.MeasureString(location.Name);
|
||||
Vector2 locationTypeSize = GUI.SubHeadingFont.MeasureString(location.Name);
|
||||
GUITextBlock locationNameText = new GUITextBlock(new RectTransform(new Point(contentWidth, (int)locationNameSize.Y), missionFrame.RectTransform, Anchor.TopCenter) { AbsoluteOffset = new Point(0, padding) }, location.Name, font: GUI.LargeFont);
|
||||
GUITextBlock locationTypeText = new GUITextBlock(new RectTransform(new Point(contentWidth, (int)locationTypeSize.Y), missionFrame.RectTransform, Anchor.TopCenter) { AbsoluteOffset = new Point(0, locationNameText.Rect.Height + padding) }, location.Type.Name, font: GUI.SubHeadingFont);
|
||||
|
||||
int locationInfoYOffset = locationNameText.Rect.Height + locationTypeText.Rect.Height + padding * 2;
|
||||
|
||||
@@ -881,7 +884,8 @@ namespace Barotrauma
|
||||
|
||||
string missionNameString = ToolBox.WrapText(mission.Name, missionTextGroup.Rect.Width, GUI.LargeFont);
|
||||
string missionDescriptionString = ToolBox.WrapText(mission.Description, missionTextGroup.Rect.Width, GUI.Font);
|
||||
string missionRewardString = ToolBox.WrapText(TextManager.GetWithVariable("MissionReward", "[reward]", mission.Reward.ToString()), missionTextGroup.Rect.Width, GUI.Font);
|
||||
string rewardText = TextManager.GetWithVariable("currencyformat", "[credits]", string.Format(CultureInfo.InvariantCulture, "{0:N0}", mission.Reward));
|
||||
string missionRewardString = ToolBox.WrapText(TextManager.GetWithVariable("MissionReward", "[reward]", rewardText), missionTextGroup.Rect.Width, GUI.Font);
|
||||
|
||||
Vector2 missionNameSize = GUI.LargeFont.MeasureString(missionNameString);
|
||||
Vector2 missionDescriptionSize = GUI.Font.MeasureString(missionDescriptionString);
|
||||
@@ -890,13 +894,15 @@ namespace Barotrauma
|
||||
missionDescriptionHolder.RectTransform.NonScaledSize = new Point(missionDescriptionHolder.RectTransform.NonScaledSize.X, (int)(missionNameSize.Y + missionDescriptionSize.Y + missionRewardSize.Y));
|
||||
missionTextGroup.RectTransform.NonScaledSize = new Point(missionTextGroup.RectTransform.NonScaledSize.X, missionDescriptionHolder.RectTransform.NonScaledSize.Y);
|
||||
|
||||
float iconAspectRatio = mission.Prefab.Icon.SourceRect.Width / mission.Prefab.Icon.SourceRect.Height;
|
||||
int iconWidth = (int)(0.225f * missionDescriptionHolder.RectTransform.NonScaledSize.X);
|
||||
int iconHeight = Math.Max(missionTextGroup.RectTransform.NonScaledSize.Y, (int)(iconWidth * iconAspectRatio));
|
||||
Point iconSize = new Point(iconWidth, iconHeight);
|
||||
|
||||
new GUIImage(new RectTransform(iconSize, missionDescriptionHolder.RectTransform), mission.Prefab.Icon, null, true) { Color = mission.Prefab.IconColor };
|
||||
if (mission.Prefab.Icon != null)
|
||||
{
|
||||
float iconAspectRatio = mission.Prefab.Icon.SourceRect.Width / mission.Prefab.Icon.SourceRect.Height;
|
||||
int iconWidth = (int)(0.225f * missionDescriptionHolder.RectTransform.NonScaledSize.X);
|
||||
int iconHeight = Math.Max(missionTextGroup.RectTransform.NonScaledSize.Y, (int)(iconWidth * iconAspectRatio));
|
||||
Point iconSize = new Point(iconWidth, iconHeight);
|
||||
|
||||
new GUIImage(new RectTransform(iconSize, missionDescriptionHolder.RectTransform), mission.Prefab.Icon, null, true) { Color = mission.Prefab.IconColor };
|
||||
}
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), missionTextGroup.RectTransform), missionNameString, font: GUI.LargeFont);
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), missionTextGroup.RectTransform), missionRewardString);
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), missionTextGroup.RectTransform), missionDescriptionString);
|
||||
|
||||
@@ -36,6 +36,12 @@ namespace Barotrauma
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public bool MaintainBorderAspectRatio
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// How much the borders of a sliced sprite are allowed to scale
|
||||
@@ -52,6 +58,7 @@ namespace Barotrauma
|
||||
{
|
||||
Sprite = new Sprite(element);
|
||||
MaintainAspectRatio = element.GetAttributeBool("maintainaspectratio", false);
|
||||
MaintainBorderAspectRatio = element.GetAttributeBool("maintainborderaspectratio", false);
|
||||
Tile = element.GetAttributeBool("tile", true);
|
||||
CrossFadeIn = element.GetAttributeBool("crossfadein", CrossFadeIn);
|
||||
CrossFadeOut = element.GetAttributeBool("crossfadeout", CrossFadeOut);
|
||||
@@ -120,13 +127,16 @@ namespace Barotrauma
|
||||
{
|
||||
Vector2 pos = new Vector2(rect.X, rect.Y);
|
||||
|
||||
float scale = GetSliceBorderScale(rect.Size);
|
||||
float scale = MaintainBorderAspectRatio ? 1.0f : GetSliceBorderScale(rect.Size);
|
||||
float aspectScale = MaintainBorderAspectRatio ? Math.Min((float)rect.Width / Sprite.SourceRect.Width, (float)rect.Height / Sprite.SourceRect.Height) : 1.0f;
|
||||
|
||||
int centerHeight = rect.Height - (int)((Slices[0].Height + Slices[6].Height) * scale);
|
||||
int centerWidth = rect.Width - (int)((Slices[0].Width + Slices[2].Width) * scale);
|
||||
int centerWidth = rect.Width - (int)((Slices[0].Width + Slices[2].Width) * scale * aspectScale);
|
||||
|
||||
for (int x = 0; x < 3; x++)
|
||||
{
|
||||
int width = (int)(x == 1 ? centerWidth : Slices[x].Width * scale);
|
||||
|
||||
int width = (int)(x == 1 ? centerWidth : Slices[x].Width * scale * aspectScale);
|
||||
if (width <= 0) { continue; }
|
||||
for (int y = 0; y < 3; y++)
|
||||
{
|
||||
@@ -147,7 +157,7 @@ namespace Barotrauma
|
||||
else if (Tile)
|
||||
{
|
||||
Vector2 startPos = new Vector2(rect.X, rect.Y);
|
||||
Sprite.DrawTiled(spriteBatch, startPos, new Vector2(rect.Width, rect.Height), null, color);
|
||||
Sprite.DrawTiled(spriteBatch, startPos, new Vector2(rect.Width, rect.Height), color);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,235 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Barotrauma.Networking;
|
||||
using Microsoft.Xna.Framework;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
class VotingInterface
|
||||
{
|
||||
public bool VoteRunning = false;
|
||||
|
||||
private GUIFrame frame;
|
||||
private GUITextBlock votingTextBlock, votedTextBlock, voteCounter;
|
||||
private GUIProgressBar votingTimer;
|
||||
private GUIButton yesVoteButton, noVoteButton;
|
||||
private Action onVoteEnd;
|
||||
|
||||
private int yesVotes, noVotes, maxVotes;
|
||||
private Func<int> getYesVotes, getNoVotes, getMaxVotes;
|
||||
private bool votePassed;
|
||||
|
||||
private string votingOnText;
|
||||
private List<RichTextData> votingOnTextData;
|
||||
private float votingTime = 100f;
|
||||
private float timer;
|
||||
private VoteType currentVoteType;
|
||||
private Color submarineColor => GUI.Style.Orange;
|
||||
private Point createdForResolution;
|
||||
|
||||
public VotingInterface(Client starter, SubmarineInfo info, VoteType type, float votingTime)
|
||||
{
|
||||
if (starter == null || info == null) return;
|
||||
SetSubmarineVotingText(starter, info, type);
|
||||
this.votingTime = votingTime;
|
||||
getYesVotes = SubmarineYesVotes;
|
||||
getNoVotes = SubmarineNoVotes;
|
||||
getMaxVotes = SubmarineMaxVotes;
|
||||
onVoteEnd = () => SendSubmarineVoteEndMessage(info, type);
|
||||
|
||||
Initialize(starter, type);
|
||||
}
|
||||
|
||||
private void Initialize(Client starter, VoteType type)
|
||||
{
|
||||
currentVoteType = type;
|
||||
CreateVotingGUI();
|
||||
if (starter.ID == GameMain.Client.ID) SetGUIToVotedState(2);
|
||||
VoteRunning = true;
|
||||
}
|
||||
|
||||
private void CreateVotingGUI()
|
||||
{
|
||||
createdForResolution = new Point(GameMain.GraphicsWidth, GameMain.GraphicsHeight);
|
||||
|
||||
if (frame != null) frame.Parent.RemoveChild(frame);
|
||||
frame = new GUIFrame(HUDLayoutSettings.ToRectTransform(HUDLayoutSettings.VotingArea, GameMain.Client.InGameHUD.RectTransform), style: "");
|
||||
|
||||
int padding = HUDLayoutSettings.Padding * 2;
|
||||
int spacing = HUDLayoutSettings.Padding;
|
||||
int yOffset = padding;
|
||||
int paddedWidth = frame.Rect.Width - padding * 2;
|
||||
|
||||
votingTextBlock = new GUITextBlock(new RectTransform(new Point(paddedWidth, 0), frame.RectTransform), votingOnTextData, votingOnText, wrap: true);
|
||||
votingTextBlock.RectTransform.NonScaledSize = votingTextBlock.RectTransform.MinSize = votingTextBlock.RectTransform.MaxSize = new Point(votingTextBlock.Rect.Width, votingTextBlock.Rect.Height);
|
||||
votingTextBlock.RectTransform.IsFixedSize = true;
|
||||
votingTextBlock.RectTransform.AbsoluteOffset = new Point(padding, yOffset);
|
||||
|
||||
yOffset += votingTextBlock.Rect.Height + spacing;
|
||||
|
||||
voteCounter = new GUITextBlock(new RectTransform(new Point(paddedWidth, 0), frame.RectTransform), "(0/0)", GUI.Style.Green, textAlignment: Alignment.Center);
|
||||
voteCounter.RectTransform.NonScaledSize = voteCounter.RectTransform.MinSize = voteCounter.RectTransform.MaxSize = new Point(voteCounter.Rect.Width, voteCounter.Rect.Height);
|
||||
voteCounter.RectTransform.IsFixedSize = true;
|
||||
voteCounter.RectTransform.AbsoluteOffset = new Point(padding, yOffset);
|
||||
|
||||
yOffset += voteCounter.Rect.Height + spacing;
|
||||
|
||||
votingTimer = new GUIProgressBar(new RectTransform(new Point(paddedWidth, Math.Max(spacing, 8)), frame.RectTransform) { AbsoluteOffset = new Point(padding, yOffset) }, HUDLayoutSettings.Padding);
|
||||
votingTimer.RectTransform.IsFixedSize = true;
|
||||
yOffset += votingTimer.Rect.Height + spacing;
|
||||
|
||||
int buttonWidth = (int)(paddedWidth * 0.3f);
|
||||
yesVoteButton = new GUIButton(new RectTransform(new Point(buttonWidth, 0), frame.RectTransform) { AbsoluteOffset = new Point((int)(frame.Rect.Width / 2f - buttonWidth - spacing), yOffset) }, TextManager.Get("yes"))
|
||||
{
|
||||
OnClicked = (applyButton, obj) =>
|
||||
{
|
||||
SetGUIToVotedState(2);
|
||||
GameMain.Client.Vote(currentVoteType, 2);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
noVoteButton = new GUIButton(new RectTransform(new Point(buttonWidth, 0), frame.RectTransform) { AbsoluteOffset = new Point(yesVoteButton.RectTransform.AbsoluteOffset.X + yesVoteButton.Rect.Width + padding, yOffset) }, TextManager.Get("no"))
|
||||
{
|
||||
OnClicked = (applyButton, obj) =>
|
||||
{
|
||||
SetGUIToVotedState(1);
|
||||
GameMain.Client.Vote(currentVoteType, 1);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
votedTextBlock = new GUITextBlock(new RectTransform(new Point(paddedWidth, yesVoteButton.Rect.Height), frame.RectTransform), string.Empty, textAlignment: Alignment.Center);
|
||||
votedTextBlock.RectTransform.IsFixedSize = true;
|
||||
votedTextBlock.RectTransform.AbsoluteOffset = new Point(padding, yOffset);
|
||||
votedTextBlock.Visible = false;
|
||||
|
||||
yOffset += yesVoteButton.Rect.Height;
|
||||
|
||||
frame.RectTransform.NonScaledSize = new Point(frame.Rect.Width, yOffset + padding);
|
||||
}
|
||||
|
||||
private void SetGUIToVotedState(int vote)
|
||||
{
|
||||
yesVoteButton.Visible = noVoteButton.Visible = false;
|
||||
votedTextBlock.Text = TextManager.Get(vote == 2 ? "yesvoted" : "novoted");
|
||||
votedTextBlock.Visible = true;
|
||||
}
|
||||
|
||||
public void Update(float deltaTime)
|
||||
{
|
||||
if (!VoteRunning) return;
|
||||
if (GameMain.GraphicsWidth != createdForResolution.X || GameMain.GraphicsHeight != createdForResolution.Y) CreateVotingGUI();
|
||||
yesVotes = getYesVotes();
|
||||
noVotes = getNoVotes();
|
||||
maxVotes = getMaxVotes();
|
||||
voteCounter.Text = $"({yesVotes + noVotes}/{maxVotes})";
|
||||
timer += deltaTime;
|
||||
votingTimer.BarSize = timer / votingTime;
|
||||
}
|
||||
|
||||
|
||||
public void EndVote(bool passed, int yesVoteFinal, int noVoteFinal)
|
||||
{
|
||||
VoteRunning = false;
|
||||
votePassed = passed;
|
||||
yesVotes = yesVoteFinal;
|
||||
noVotes = noVoteFinal;
|
||||
onVoteEnd?.Invoke();
|
||||
}
|
||||
|
||||
#region Submarine Voting
|
||||
private void SetSubmarineVotingText(Client starter, SubmarineInfo info, VoteType type)
|
||||
{
|
||||
string name = starter.Name;
|
||||
JobPrefab prefab = starter?.Character?.Info?.Job?.Prefab;
|
||||
Color nameColor = prefab != null ? prefab.UIColor : Color.White;
|
||||
string characterRichString = $"‖color:{nameColor.R},{nameColor.G},{nameColor.B}‖{name}‖color:end‖";
|
||||
string submarineRichString = $"‖color:{submarineColor.R},{submarineColor.G},{submarineColor.B}‖{info.DisplayName}‖color:end‖";
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case VoteType.PurchaseAndSwitchSub:
|
||||
votingOnText = TextManager.GetWithVariables("submarinepurchaseandswitchvote", new string[] { "[playername]", "[submarinename]", "[amount]", "[currencyname]" }, new string[] { characterRichString, submarineRichString, info.Price.ToString(), TextManager.Get("credit").ToLower() });
|
||||
break;
|
||||
case VoteType.PurchaseSub:
|
||||
votingOnText = TextManager.GetWithVariables("submarinepurchasevote", new string[] { "[playername]", "[submarinename]", "[amount]", "[currencyname]" }, new string[] { characterRichString, submarineRichString, info.Price.ToString(), TextManager.Get("credit").ToLower() });
|
||||
break;
|
||||
case VoteType.SwitchSub:
|
||||
int deliveryFee = SubmarineSelection.DeliveryFeePerDistanceTravelled * GameMain.GameSession.Map.DistanceToClosestLocationWithOutpost(GameMain.GameSession.Map.CurrentLocation, out Location endLocation);
|
||||
|
||||
if (deliveryFee > 0)
|
||||
{
|
||||
votingOnText = TextManager.GetWithVariables("submarineswitchfeevote", new string[] { "[playername]", "[submarinename]", "[locationname]", "[amount]", "[currencyname]" }, new string[] { characterRichString, submarineRichString, endLocation.Name, deliveryFee.ToString(), TextManager.Get("credit").ToLower() });
|
||||
}
|
||||
else
|
||||
{
|
||||
votingOnText = TextManager.GetWithVariables("submarineswitchnofeevote", new string[] { "[playername]", "[submarinename]" }, new string[] { characterRichString, submarineRichString });
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
votingOnTextData = RichTextData.GetRichTextData(votingOnText, out votingOnText);
|
||||
}
|
||||
|
||||
private int SubmarineYesVotes()
|
||||
{
|
||||
return GameMain.NetworkMember.SubmarineVoteYesCount;
|
||||
}
|
||||
|
||||
private int SubmarineNoVotes()
|
||||
{
|
||||
return GameMain.NetworkMember.SubmarineVoteNoCount;
|
||||
}
|
||||
|
||||
private int SubmarineMaxVotes()
|
||||
{
|
||||
return GameMain.NetworkMember.SubmarineVoteMax;
|
||||
}
|
||||
|
||||
private void SendSubmarineVoteEndMessage(SubmarineInfo info, VoteType type)
|
||||
{
|
||||
GameMain.NetworkMember.AddChatMessage(GetSubmarineVoteResultMessage(info, type, yesVotes.ToString(), noVotes.ToString(), votePassed), ChatMessageType.Server);
|
||||
}
|
||||
|
||||
public static string GetSubmarineVoteResultMessage(SubmarineInfo info, VoteType type, string yesVoteString, string noVoteString, bool votePassed)
|
||||
{
|
||||
string result = string.Empty;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case VoteType.PurchaseAndSwitchSub:
|
||||
result = TextManager.GetWithVariables(votePassed ? "submarinepurchaseandswitchvotepassed" : "submarinepurchaseandswitchvotefailed", new string[] { "[submarinename]", "[amount]", "[currencyname]", "[yesvotecount]", "[novotecount]" }, new string[] { info.DisplayName, info.Price.ToString(), TextManager.Get("credit").ToLower(), yesVoteString, noVoteString });
|
||||
break;
|
||||
case VoteType.PurchaseSub:
|
||||
result = TextManager.GetWithVariables(votePassed ? "submarinepurchasevotepassed" : "submarinepurchasevotefailed", new string[] { "[submarinename]", "[amount]", "[currencyname]", "[yesvotecount]", "[novotecount]" }, new string[] { info.DisplayName, info.Price.ToString(), TextManager.Get("credit").ToLower(), yesVoteString, noVoteString });
|
||||
break;
|
||||
case VoteType.SwitchSub:
|
||||
int deliveryFee = SubmarineSelection.DeliveryFeePerDistanceTravelled * GameMain.GameSession.Map.DistanceToClosestLocationWithOutpost(GameMain.GameSession.Map.CurrentLocation, out Location endLocation);
|
||||
|
||||
if (deliveryFee > 0)
|
||||
{
|
||||
result = TextManager.GetWithVariables(votePassed ? "submarineswitchfeevotepassed" : "submarineswitchfeevotefailed", new string[] { "[submarinename]", "[locationname]", "[amount]", "[currencyname]", "[yesvotecount]", "[novotecount]" }, new string[] { info.DisplayName, endLocation.Name, deliveryFee.ToString(), TextManager.Get("credit").ToLower(), yesVoteString, noVoteString });
|
||||
}
|
||||
else
|
||||
{
|
||||
result = TextManager.GetWithVariables(votePassed ? "submarineswitchnofeevotepassed" : "submarineswitchnofeevotefailed", new string[] { "[submarinename]", "[yesvotecount]", "[novotecount]" }, new string[] { info.DisplayName, yesVoteString, noVoteString });
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
#endregion
|
||||
|
||||
public void Remove()
|
||||
{
|
||||
if (frame != null)
|
||||
{
|
||||
frame.Parent.RemoveChild(frame);
|
||||
frame = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user