Build 1.1.4.0

This commit is contained in:
Markus Isberg
2023-03-31 18:40:44 +03:00
parent efba17e0ff
commit 9470edead3
483 changed files with 17487 additions and 8548 deletions
@@ -7,17 +7,13 @@ namespace Barotrauma
{
class CampaignEndScreen : Screen
{
private Video video;
private readonly CreditsPlayer creditsPlayer;
private readonly Camera cam;
public Action OnFinished;
private LocalizedString textOverlay;
private float textOverlayTimer;
private Vector2 textOverlaySize;
protected SlideshowPlayer slideshowPlayer;
public CampaignEndScreen()
{
@@ -27,43 +23,45 @@ namespace Barotrauma
ScrollBarEnabled = false,
AllowMouseWheelScroll = false
};
new GUIButton(new RectTransform(new Vector2(0.1f), creditsPlayer.RectTransform, Anchor.BottomRight, maxSize: new Point(300, 50)) { AbsoluteOffset = new Point(GUI.IntScale(20)) },
TextManager.Get("close"))
creditsPlayer.CloseButton.OnClicked = (btn, userdata) =>
{
OnClicked = (btn, userdata) =>
{
creditsPlayer.Scroll = 1.0f;
return true;
}
creditsPlayer.Scroll = 1.0f;
return true;
};
cam = new Camera();
}
public override void Select()
{
base.Select();
textOverlay = ToolBox.WrapText(TextManager.Get("campaignend1"), GameMain.GraphicsWidth / 3, GUIStyle.Font);
textOverlaySize = GUIStyle.Font.MeasureString(textOverlay);
textOverlayTimer = 0.0f;
video = Video.Load(GameMain.GraphicsDeviceManager.GraphicsDevice, GameMain.SoundManager, "Content/SplashScreens/Ending.webm");
video.Play();
if (SlideshowPrefab.Prefabs.TryGet("campaignending".ToIdentifier(), out var slideshow))
{
slideshowPlayer = new SlideshowPlayer(GUICanvas.Instance, slideshow);
}
creditsPlayer.Restart();
creditsPlayer.Visible = false;
SteamAchievementManager.UnlockAchievement("campaigncompleted".ToIdentifier(), unlockClients: true);
UnlockAchievement("campaigncompleted");
UnlockAchievement(
GameMain.GameSession is { Campaign.Settings.RadiationEnabled: true } ?
"campaigncompleted_radiationenabled" :
"campaigncompleted_radiationdisabled");
static void UnlockAchievement(string id)
{
SteamAchievementManager.UnlockAchievement(id.ToIdentifier(), unlockClients: true);
}
}
public override void Deselect()
{
video?.Dispose();
video = null;
GUI.HideCursor = false;
SoundPlayer.OverrideMusicType = Identifier.Empty;
}
public override void Update(double deltaTime)
{
slideshowPlayer?.UpdateManually((float)deltaTime);
if (creditsPlayer.Finished)
{
OnFinished?.Invoke();
@@ -73,46 +71,18 @@ namespace Barotrauma
public override void Draw(double deltaTime, GraphicsDevice graphics, SpriteBatch spriteBatch)
{
spriteBatch.Begin();
spriteBatch.Begin(SpriteSortMode.Deferred, null, GUI.SamplerState, null, GameMain.ScissorTestEnable);
graphics.Clear(Color.Black);
if (video.IsPlaying)
SoundPlayer.OverrideMusicType = "ending".ToIdentifier();
if (slideshowPlayer != null && !slideshowPlayer.Finished)
{
GUI.HideCursor = !GUI.PauseMenuOpen;
spriteBatch.Draw(video.GetTexture(), new Rectangle(0, 0, GameMain.GraphicsWidth, GameMain.GraphicsHeight), Color.White);
slideshowPlayer.DrawManually(spriteBatch);
}
else
{
SoundPlayer.OverrideMusicType = "ending".ToIdentifier();
float duration = 20.0f;
float creditsDelay = 3.0f;
if (textOverlayTimer < duration + creditsDelay)
{
float textAlpha;
float fadeInTime = 5.0f, fadeOutTime = 3.0f;
textOverlayTimer += (float)deltaTime;
if (textOverlayTimer < fadeInTime)
{
textAlpha = textOverlayTimer / fadeInTime;
}
else if (textOverlayTimer > duration - fadeOutTime)
{
textAlpha = Math.Min((duration - textOverlayTimer) / fadeOutTime, 1.0f);
}
else
{
textAlpha = 1.0f;
}
GUIStyle.Font.DrawString(spriteBatch, textOverlay, new Vector2(GameMain.GraphicsWidth, GameMain.GraphicsHeight) / 2 - textOverlaySize / 2, Color.White * textAlpha);
}
else
{
GUI.HideCursor = false;
creditsPlayer.Visible = true;
}
GUI.HideCursor = false;
creditsPlayer.Visible = true;
}
spriteBatch.End();
spriteBatch.Begin(SpriteSortMode.Deferred, null, GUI.SamplerState, null, GameMain.ScissorTestEnable);
GUI.Draw(cam, spriteBatch);
spriteBatch.End();
}
@@ -38,7 +38,6 @@ namespace Barotrauma
protected set;
}
public CampaignSettings CurrentSettings = new CampaignSettings(element: null);
public GUIButton CampaignCustomizeButton { get; set; }
public GUIMessageBox CampaignCustomizeSettings { get; set; }
@@ -124,6 +123,7 @@ namespace Barotrauma
public struct CampaignSettingElements
{
public SettingValue<string> SelectedPreset;
public SettingValue<bool> TutorialEnabled;
public SettingValue<bool> RadiationEnabled;
public SettingValue<int> MaxMissionCount;
@@ -135,6 +135,7 @@ namespace Barotrauma
{
return new CampaignSettings(element: null)
{
PresetName = SelectedPreset.GetValue(),
TutorialEnabled = TutorialEnabled.GetValue(),
RadiationEnabled = RadiationEnabled.GetValue(),
MaxMissionCount = MaxMissionCount.GetValue(),
@@ -185,9 +186,13 @@ namespace Barotrauma
{
const float verticalSize = 0.14f;
bool loadingPreset = false;
GUILayoutGroup presetDropdownLayout = new GUILayoutGroup(new RectTransform(new Vector2(1f, verticalSize), parent.RectTransform), isHorizontal: true, childAnchor: Anchor.CenterLeft);
new GUITextBlock(new RectTransform(new Vector2(0.5f, 1f), presetDropdownLayout.RectTransform), TextManager.Get("campaignsettingpreset"));
GUIDropDown presetDropdown = new GUIDropDown(new RectTransform(new Vector2(0.5f, 1f), presetDropdownLayout.RectTransform), elementCount: CampaignModePresets.List.Length);
GUIDropDown presetDropdown = new GUIDropDown(new RectTransform(new Vector2(0.5f, 1f), presetDropdownLayout.RectTransform), elementCount: CampaignModePresets.List.Length + 1);
presetDropdown.AddItem(TextManager.Get("karmapreset.custom"), null);
presetDropdown.Select(0);
presetDropdownLayout.RectTransform.MinSize = new Point(0, presetDropdown.Rect.Height);
@@ -195,21 +200,30 @@ namespace Barotrauma
{
string name = settings.PresetName;
presetDropdown.AddItem(TextManager.Get($"preset.{name}").Fallback(name), settings);
if (settings.PresetName.Equals(prevSettings.PresetName, StringComparison.OrdinalIgnoreCase))
{
presetDropdown.SelectItem(settings);
}
}
var presetValue = new SettingValue<string>(
get: () => presetDropdown.SelectedData is CampaignSettings settings ? settings.PresetName : string.Empty,
set: static _ => { }); // we do not need a way to set this value
GUIListBox settingsList = new GUIListBox(new RectTransform(new Vector2(1f, 1f - verticalSize), parent.RectTransform))
{
Spacing = GUI.IntScale(5)
};
SettingValue<bool> tutorialEnabled = isSinglePlayer ?
CreateTickbox(settingsList.Content, TextManager.Get("CampaignOption.EnableTutorial"), TextManager.Get("campaignoption.enabletutorial.tooltip"), prevSettings.TutorialEnabled, verticalSize) :
new SettingValue<bool>(() => false, b => { });
SettingValue<bool> radiationEnabled = CreateTickbox(settingsList.Content, TextManager.Get("CampaignOption.EnableRadiation"), TextManager.Get("campaignoption.enableradiation.tooltip"), prevSettings.RadiationEnabled, verticalSize);
CreateTickbox(settingsList.Content, TextManager.Get("CampaignOption.EnableTutorial"), TextManager.Get("campaignoption.enabletutorial.tooltip"), prevSettings.TutorialEnabled, verticalSize, OnValuesChanged) :
new SettingValue<bool>(static () => false, static _ => { });
SettingValue<bool> radiationEnabled = CreateTickbox(settingsList.Content, TextManager.Get("CampaignOption.EnableRadiation"), TextManager.Get("campaignoption.enableradiation.tooltip"), prevSettings.RadiationEnabled, verticalSize, OnValuesChanged);
ImmutableArray<SettingCarouselElement<Identifier>> startingSetOptions = StartItemSet.Sets.OrderBy(s => s.Order).Select(set => new SettingCarouselElement<Identifier>(set.Identifier, $"startitemset.{set.Identifier}")).ToImmutableArray();
SettingCarouselElement<Identifier> prevStartingSet = startingSetOptions.FirstOrNull(element => element.Value == prevSettings.StartItemSet) ?? startingSetOptions[1];
SettingValue<Identifier> startingSetInput = CreateSelectionCarousel(settingsList.Content, TextManager.Get("startitemset"), TextManager.Get("startitemsettooltip"), prevStartingSet, verticalSize, startingSetOptions);
SettingValue<Identifier> startingSetInput = CreateSelectionCarousel(settingsList.Content, TextManager.Get("startitemset"), TextManager.Get("startitemsettooltip"), prevStartingSet, verticalSize, startingSetOptions, OnValuesChanged);
ImmutableArray<SettingCarouselElement<StartingBalanceAmount>> fundOptions = ImmutableArray.Create(
new SettingCarouselElement<StartingBalanceAmount>(StartingBalanceAmount.Low, "startingfunds.low"),
@@ -218,7 +232,7 @@ namespace Barotrauma
);
SettingCarouselElement<StartingBalanceAmount> prevStartingFund = fundOptions.FirstOrNull(element => element.Value == prevSettings.StartingBalanceAmount) ?? fundOptions[1];
SettingValue<StartingBalanceAmount> startingFundsInput = CreateSelectionCarousel(settingsList.Content, TextManager.Get("startingfundsdescription"), TextManager.Get("startingfundstooltip"), prevStartingFund, verticalSize, fundOptions);
SettingValue<StartingBalanceAmount> startingFundsInput = CreateSelectionCarousel(settingsList.Content, TextManager.Get("startingfundsdescription"), TextManager.Get("startingfundstooltip"), prevStartingFund, verticalSize, fundOptions, OnValuesChanged);
ImmutableArray<SettingCarouselElement<GameDifficulty>> difficultyOptions = ImmutableArray.Create(
new SettingCarouselElement<GameDifficulty>(GameDifficulty.Easy, "difficulty.easy"),
@@ -228,30 +242,38 @@ namespace Barotrauma
);
SettingCarouselElement<GameDifficulty> prevDifficulty = difficultyOptions.FirstOrNull(element => element.Value == prevSettings.Difficulty) ?? difficultyOptions[1];
SettingValue<GameDifficulty> difficultyInput = CreateSelectionCarousel(settingsList.Content, TextManager.Get("leveldifficulty"), TextManager.Get("leveldifficultyexplanation"), prevDifficulty, verticalSize, difficultyOptions);
SettingValue<GameDifficulty> difficultyInput = CreateSelectionCarousel(settingsList.Content, TextManager.Get("leveldifficulty"), TextManager.Get("leveldifficultyexplanation"), prevDifficulty, verticalSize, difficultyOptions, OnValuesChanged);
SettingValue<int> maxMissionCountInput = CreateGUINumberInputCarousel(settingsList.Content, TextManager.Get("maxmissioncount"), TextManager.Get("maxmissioncounttooltip"),
prevSettings.MaxMissionCount,
valueStep: 1, minValue: CampaignSettings.MinMissionCountLimit, maxValue: CampaignSettings.MaxMissionCountLimit,
verticalSize);
verticalSize,
OnValuesChanged);
presetDropdown.OnSelected = (selected, o) =>
presetDropdown.OnSelected = (_, o) =>
{
if (o is CampaignSettings settings)
{
tutorialEnabled.SetValue(isSinglePlayer && settings.TutorialEnabled);
radiationEnabled.SetValue(settings.RadiationEnabled);
maxMissionCountInput.SetValue(settings.MaxMissionCount);
startingFundsInput.SetValue(settings.StartingBalanceAmount);
difficultyInput.SetValue(settings.Difficulty);
startingSetInput.SetValue(settings.StartItemSet);
return true;
}
return false;
if (o is not CampaignSettings settings) { return false; }
loadingPreset = true;
tutorialEnabled.SetValue(isSinglePlayer && settings.TutorialEnabled);
radiationEnabled.SetValue(settings.RadiationEnabled);
maxMissionCountInput.SetValue(settings.MaxMissionCount);
startingFundsInput.SetValue(settings.StartingBalanceAmount);
difficultyInput.SetValue(settings.Difficulty);
startingSetInput.SetValue(settings.StartItemSet);
loadingPreset = false;
return true;
};
void OnValuesChanged()
{
if (loadingPreset) { return; }
presetDropdown.Select(0);
}
return new CampaignSettingElements
{
SelectedPreset = presetValue,
TutorialEnabled = tutorialEnabled,
RadiationEnabled = radiationEnabled,
MaxMissionCount = maxMissionCountInput,
@@ -261,7 +283,7 @@ namespace Barotrauma
};
// Create a number input with plus and minus buttons because for some reason the default GUINumberInput buttons don't work when in a GUIMessageBox
static SettingValue<int> CreateGUINumberInputCarousel(GUIComponent parent, LocalizedString description, LocalizedString tooltip, int defaultValue, int valueStep, int minValue, int maxValue, float verticalSize)
static SettingValue<int> CreateGUINumberInputCarousel(GUIComponent parent, LocalizedString description, LocalizedString tooltip, int defaultValue, int valueStep, int minValue, int maxValue, float verticalSize, Action onChanged)
{
GUILayoutGroup inputContainer = CreateSettingBase(parent, description, tooltip, horizontalSize: 0.55f, verticalSize: verticalSize);
@@ -286,9 +308,11 @@ namespace Barotrauma
minusButton.OnClicked = plusButton.OnClicked = ChangeValue;
numberInput.OnValueChanged += _ => onChanged();
bool ChangeValue(GUIButton btn, object userData)
{
if (!(userData is int change)) { return false; }
if (userData is not int change) { return false; }
numberInput.IntValue += change;
return true;
@@ -298,7 +322,7 @@ namespace Barotrauma
}
static SettingValue<T> CreateSelectionCarousel<T>(GUIComponent parent, LocalizedString description, LocalizedString tooltip, SettingCarouselElement<T> defaultValue, float verticalSize,
ImmutableArray<SettingCarouselElement<T>> options)
ImmutableArray<SettingCarouselElement<T>> options, Action onChanged)
{
GUILayoutGroup inputContainer = CreateSettingBase(parent, description, tooltip, horizontalSize: 0.55f, verticalSize: verticalSize);
@@ -349,6 +373,8 @@ namespace Barotrauma
return true;
}
numberInput.OnValueChanged += _ => onChanged();
void SetValue(int value)
{
numberInput.IntValue = value;
@@ -358,7 +384,7 @@ namespace Barotrauma
return new SettingValue<T>(() => options[numberInput.IntValue].Value, t => SetValue(options.IndexOf(e => Equals(e.Value, t))));
}
static SettingValue<bool> CreateTickbox(GUIComponent parent, LocalizedString description, LocalizedString tooltip, bool defaultValue, float verticalSize)
static SettingValue<bool> CreateTickbox(GUIComponent parent, LocalizedString description, LocalizedString tooltip, bool defaultValue, float verticalSize, Action onChanged)
{
GUILayoutGroup inputContainer = CreateSettingBase(parent, description, tooltip, 0.7f, verticalSize);
GUILayoutGroup tickboxContainer = new GUILayoutGroup(new RectTransform(new Vector2(0.3f, 1.0f), inputContainer.RectTransform), childAnchor: Anchor.Center);
@@ -370,6 +396,13 @@ namespace Barotrauma
tickBox.Box.IgnoreLayoutGroups = true;
tickBox.Box.RectTransform.SetPosition(Anchor.CenterRight);
inputContainer.RectTransform.Parent.MinSize = new Point(0, tickBox.RectTransform.MinSize.Y);
tickBox.OnSelected += _ =>
{
onChanged();
return true;
};
return new SettingValue<bool>(() => tickBox.Selected, b => tickBox.Selected = b);
}
@@ -194,7 +194,7 @@ namespace Barotrauma
{
TextGetter = () =>
{
int initialMoney = CurrentSettings.InitialMoney;
int initialMoney = CampaignSettings.CurrentSettings.InitialMoney;
if (subList.SelectedData is SubmarineInfo subInfo)
{
initialMoney -= subInfo.Price;
@@ -208,15 +208,15 @@ namespace Barotrauma
{
OnClicked = (tb, userdata) =>
{
CreateCustomizeWindow(CurrentSettings, settings =>
CreateCustomizeWindow(CampaignSettings.CurrentSettings, settings =>
{
CampaignSettings prevSettings = CurrentSettings;
CurrentSettings = settings;
CampaignSettings prevSettings = CampaignSettings.CurrentSettings;
CampaignSettings.CurrentSettings = settings;
if (prevSettings.InitialMoney != settings.InitialMoney)
{
object selectedData = subList.SelectedData;
UpdateSubList(SubmarineInfo.SavedSubmarines);
if (selectedData is SubmarineInfo selectedSub && selectedSub.Price <= CurrentSettings.InitialMoney)
if (selectedData is SubmarineInfo selectedSub && selectedSub.Price <= CampaignSettings.CurrentSettings.InitialMoney)
{
subList.Select(selectedData);
}
@@ -375,6 +375,7 @@ namespace Barotrauma
{
onClosed?.Invoke(elements.CreateSettings());
GameSettings.SaveCurrentConfig();
return CampaignCustomizeSettings.Close(button, o);
};
}
@@ -399,7 +400,7 @@ namespace Barotrauma
SubmarineInfo selectedSub = null;
if (!(subList.SelectedData is SubmarineInfo)) { return false; }
if (subList.SelectedData is not SubmarineInfo) { return false; }
selectedSub = subList.SelectedData as SubmarineInfo;
if (selectedSub.SubmarineClass == SubmarineClass.Undefined)
@@ -419,7 +420,7 @@ namespace Barotrauma
string savePath = SaveUtil.CreateSavePath(SaveUtil.SaveType.Singleplayer, saveNameBox.Text);
bool hasRequiredContentPackages = selectedSub.RequiredContentPackagesInstalled;
CampaignSettings settings = CurrentSettings;
CampaignSettings settings = CampaignSettings.CurrentSettings;
if (selectedSub.HasTag(SubmarineTag.Shuttle) || !hasRequiredContentPackages)
{
@@ -476,7 +477,7 @@ namespace Barotrauma
{
foreach (GUIComponent child in subList.Content.Children)
{
if (!(child.UserData is SubmarineInfo sub)) { return; }
if (child.UserData is not SubmarineInfo sub) { return; }
child.Visible = string.IsNullOrEmpty(filter) || sub.DisplayName.Contains(filter.ToLower(), StringComparison.OrdinalIgnoreCase);
}
}
@@ -487,9 +488,9 @@ namespace Barotrauma
(subPreviewContainer.Parent as GUILayoutGroup)?.Recalculate();
subPreviewContainer.ClearChildren();
if (!(obj is SubmarineInfo sub)) { return true; }
if (obj is not SubmarineInfo sub) { return true; }
#if !DEBUG
if (sub.Price > CurrentSettings.InitialMoney && !GameMain.DebugDraw)
if (sub.Price > CampaignSettings.CurrentSettings.InitialMoney && !GameMain.DebugDraw)
{
SetPage(0);
nextButton.Enabled = false;
@@ -551,7 +552,7 @@ namespace Barotrauma
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.5f), infoContainer.RectTransform),
TextManager.GetWithVariable("currencyformat", "[credits]", string.Format(CultureInfo.InvariantCulture, "{0:N0}", sub.Price)), textAlignment: Alignment.BottomRight, font: GUIStyle.SmallFont)
{
TextColor = sub.Price > CurrentSettings.InitialMoney ? GUIStyle.Red : textBlock.TextColor * 0.8f,
TextColor = sub.Price > CampaignSettings.CurrentSettings.InitialMoney ? GUIStyle.Red : textBlock.TextColor * 0.8f,
ToolTip = textBlock.ToolTip
};
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.5f), infoContainer.RectTransform),
@@ -563,7 +564,7 @@ namespace Barotrauma
#if !DEBUG
if (!GameMain.DebugDraw)
{
if (sub.Price > CurrentSettings.InitialMoney || !sub.IsCampaignCompatible)
if (sub.Price > CampaignSettings.CurrentSettings.InitialMoney || !sub.IsCampaignCompatible)
{
textBlock.CanBeFocused = false;
textBlock.TextColor *= 0.5f;
@@ -573,7 +574,7 @@ namespace Barotrauma
}
if (SubmarineInfo.SavedSubmarines.Any())
{
var validSubs = subsToShow.Where(s => s.IsCampaignCompatible && s.Price <= CurrentSettings.InitialMoney).ToList();
var validSubs = subsToShow.Where(s => s.IsCampaignCompatible && s.Price <= CampaignSettings.CurrentSettings.InitialMoney).ToList();
if (validSubs.Count > 0)
{
subList.Select(validSubs[Rand.Int(validSubs.Count)]);
@@ -81,11 +81,21 @@ namespace Barotrauma
tabs[(int)CampaignMode.InteractionType.Map] = CreateDefaultTabContainer(container, new Vector2(0.9f));
var mapFrame = new GUIFrame(new RectTransform(Vector2.One, GetTabContainer(CampaignMode.InteractionType.Map).RectTransform, Anchor.TopLeft), color: Color.Black * 0.9f);
new GUICustomComponent(new RectTransform(Vector2.One, mapFrame.RectTransform), DrawMap, UpdateMap);
var mapContainer = new GUICustomComponent(new RectTransform(Vector2.One, mapFrame.RectTransform), DrawMap, UpdateMap);
var notificationFrame = new GUIFrame(new RectTransform(new Point(mapContainer.Rect.Width, GUI.IntScale(40)), mapContainer.RectTransform, Anchor.BottomCenter), style: "ChatBox");
new GUIFrame(new RectTransform(Vector2.One, mapFrame.RectTransform), style: "InnerGlow", color: Color.Black * 0.9f)
{
CanBeFocused = false
};
var notificationContainer = new GUICustomComponent(new RectTransform(new Vector2(0.98f, 1.0f), notificationFrame.RectTransform, Anchor.Center), DrawMapNotifications, null)
{
HideElementsOutsideFrame = true
};
var notificationHeader = new GUIImage(new RectTransform(new Vector2(0.1f, 1.0f), notificationFrame.RectTransform, Anchor.CenterLeft), style: "GUISlopedHeaderRight");
var text = new GUITextBlock(new RectTransform(Vector2.One, notificationHeader.RectTransform, Anchor.Center), TextManager.Get("breakingnews"), font: GUIStyle.LargeFont);
notificationHeader.RectTransform.MinSize = new Point((int)(text.TextSize.X * 1.3f), 0);
// crew tab -------------------------------------------------------------------------
@@ -152,18 +162,23 @@ namespace Barotrauma
CreateUI(tabs[(int)CampaignMode.InteractionType.Map].Parent);
}
GameMain.GameSession?.Map?.Draw(spriteBatch, mapContainer);
Campaign?.Map?.Draw(Campaign, spriteBatch, mapContainer);
}
private void DrawMapNotifications(SpriteBatch spriteBatch, GUICustomComponent notificationContainer)
{
Campaign?.Map?.DrawNotifications(spriteBatch, notificationContainer);
}
private void UpdateMap(float deltaTime, GUICustomComponent mapContainer)
{
var map = GameMain.GameSession?.Map;
var map = Campaign?.Map;
if (map == null) { return; }
if (selectedLocation != null && selectedLocation == GameMain.GameSession.Campaign.GetCurrentDisplayLocation())
if (selectedLocation != null && selectedLocation == Campaign.GetCurrentDisplayLocation())
{
map.SelectLocation(-1);
}
map.Update(deltaTime, mapContainer);
map.Update(Campaign, deltaTime, mapContainer);
foreach (GUITickBox tickBox in missionTickBoxes)
{
bool disable = hasMaxMissions && !tickBox.Selected;
@@ -260,14 +275,20 @@ namespace Barotrauma
if (connection?.LevelData != null)
{
if (location.Faction?.Prefab != null)
{
var factionLabel = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), textContent.RectTransform),
TextManager.Get("Faction"), font: GUIStyle.SubHeadingFont, textAlignment: Alignment.CenterLeft);
new GUITextBlock(new RectTransform(new Vector2(1.0f, 1.0f), factionLabel.RectTransform), location.Faction.Prefab.Name, textAlignment: Alignment.CenterRight, textColor: location.Faction.Prefab.IconColor);
}
var biomeLabel = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), textContent.RectTransform),
TextManager.Get("Biome", "location"), font: GUIStyle.SubHeadingFont, textAlignment: Alignment.CenterLeft);
new GUITextBlock(new RectTransform(new Vector2(1.0f, 1.0f), biomeLabel.RectTransform), connection.Biome.DisplayName, textAlignment: Alignment.CenterRight);
var difficultyLabel = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), textContent.RectTransform),
TextManager.Get("LevelDifficulty"), font: GUIStyle.SubHeadingFont, textAlignment: Alignment.CenterLeft);
new GUITextBlock(new RectTransform(new Vector2(1.0f, 1.0f), difficultyLabel.RectTransform), ((int)connection.LevelData.Difficulty) + " %", textAlignment: Alignment.CenterRight);
new GUITextBlock(new RectTransform(new Vector2(1.0f, 1.0f), difficultyLabel.RectTransform), TextManager.GetWithVariable("percentageformat", "[value]", ((int)connection.LevelData.Difficulty).ToString()), textAlignment: Alignment.CenterRight);
if (connection.LevelData.HasBeaconStation)
{
var beaconStationContent = new GUILayoutGroup(new RectTransform(biomeLabel.RectTransform.NonScaledSize, textContent.RectTransform), isHorizontal: true, childAnchor: Anchor.CenterLeft);
@@ -328,12 +349,31 @@ namespace Barotrauma
if (connection != null && connection.Locations.Contains(currentDisplayLocation))
{
List<Mission> availableMissions = currentDisplayLocation.GetMissionsInConnection(connection).ToList();
if (!availableMissions.Contains(null)) { availableMissions.Insert(0, null); }
if (!availableMissions.Any()) { availableMissions.Insert(0, null); }
availableMissions.AddRange(location.AvailableMissions.Where(m => m.Locations[0] == m.Locations[1]));
missionList.Content.ClearChildren();
bool isPrevMissionInNextLocation = false;
foreach (Mission mission in availableMissions)
{
bool isMissionInNextLocation = mission != null && location.AvailableMissions.Contains(mission);
if (isMissionInNextLocation && !isPrevMissionInNextLocation)
{
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), missionList.Content.RectTransform), TextManager.Get("outpostmissions"),
textAlignment: Alignment.Center, font: GUIStyle.SubHeadingFont, wrap: true)
{
CanBeFocused = false
};
new GUIFrame(new RectTransform(new Vector2(1.0f, 0.01f), missionList.Content.RectTransform), style: "HorizontalLine")
{
CanBeFocused = false
};
}
isPrevMissionInNextLocation = isMissionInNextLocation;
var missionPanel = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.1f), missionList.Content.RectTransform), style: null)
{
UserData = mission
@@ -347,45 +387,54 @@ namespace Barotrauma
var missionName = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), missionTextContent.RectTransform), mission?.Name ?? TextManager.Get("NoMission"), font: GUIStyle.SubHeadingFont, wrap: true);
missionName.RectTransform.MinSize = new Point(0, GUI.IntScale(15));
if (mission != null)
{
var tickBox = new GUITickBox(new RectTransform(Vector2.One * 0.9f, missionName.RectTransform, anchor: Anchor.CenterLeft, scaleBasis: ScaleBasis.Smallest) { AbsoluteOffset = new Point((int)missionName.Padding.X, 0) }, label: string.Empty)
if (mission == null)
{
missionTextContent.RectTransform.MinSize = missionName.RectTransform.MinSize = new Point(0, GUI.IntScale(35));
missionTextContent.ChildAnchor = Anchor.CenterLeft;
}
else
{
GUITickBox tickBox = null;
if (!isMissionInNextLocation)
{
UserData = mission,
Selected = Campaign.Map.CurrentLocation?.SelectedMissions.Contains(mission) ?? false
};
tickBox.RectTransform.MinSize = new Point(tickBox.Rect.Height, 0);
tickBox.RectTransform.IsFixedSize = true;
tickBox.Enabled = CampaignMode.AllowedToManageCampaign(ClientPermissions.ManageMap);
tickBox.OnSelected += (GUITickBox tb) =>
{
if (!CampaignMode.AllowedToManageCampaign(Networking.ClientPermissions.ManageMap)) { return false; }
if (tb.Selected)
tickBox = new GUITickBox(new RectTransform(Vector2.One * 0.9f, missionName.RectTransform, anchor: Anchor.CenterLeft, scaleBasis: ScaleBasis.Smallest) { AbsoluteOffset = new Point((int)missionName.Padding.X, 0) }, label: string.Empty)
{
Campaign.Map.CurrentLocation.SelectMission(mission);
}
else
UserData = mission,
Selected = Campaign.Map.CurrentLocation?.SelectedMissions.Contains(mission) ?? false
};
tickBox.RectTransform.MinSize = new Point(tickBox.Rect.Height, 0);
tickBox.RectTransform.IsFixedSize = true;
tickBox.Enabled = CampaignMode.AllowedToManageCampaign(ClientPermissions.ManageMap);
tickBox.OnSelected += (GUITickBox tb) =>
{
Campaign.Map.CurrentLocation.DeselectMission(mission);
}
if (!CampaignMode.AllowedToManageCampaign(Networking.ClientPermissions.ManageMap)) { return false; }
foreach (GUITextBlock rewardText in missionRewardTexts)
{
Mission otherMission = rewardText.UserData as Mission;
rewardText.Text = otherMission.GetMissionRewardText(Submarine.MainSub);
}
if (tb.Selected)
{
Campaign.Map.CurrentLocation.SelectMission(mission);
}
else
{
Campaign.Map.CurrentLocation.DeselectMission(mission);
}
UpdateMaxMissions(connection.OtherLocation(currentDisplayLocation));
foreach (GUITextBlock rewardText in missionRewardTexts)
{
Mission otherMission = rewardText.UserData as Mission;
rewardText.Text = otherMission.GetMissionRewardText(Submarine.MainSub);
}
if ((Campaign is MultiPlayerCampaign multiPlayerCampaign) && !multiPlayerCampaign.SuppressStateSending &&
CampaignMode.AllowedToManageCampaign(Networking.ClientPermissions.ManageMap))
{
GameMain.Client?.SendCampaignState();
}
return true;
};
missionTickBoxes.Add(tickBox);
UpdateMaxMissions(connection.OtherLocation(currentDisplayLocation));
if ((Campaign is MultiPlayerCampaign multiPlayerCampaign) && !multiPlayerCampaign.SuppressStateSending &&
CampaignMode.AllowedToManageCampaign(Networking.ClientPermissions.ManageMap))
{
GameMain.Client?.SendCampaignState();
}
return true;
};
missionTickBoxes.Add(tickBox);
}
GUILayoutGroup difficultyIndicatorGroup = null;
if (mission.Difficulty.HasValue)
@@ -410,7 +459,7 @@ namespace Barotrauma
float extraPadding = 0;// 0.8f * tickBox.Rect.Width;
float extraZPadding = difficultyIndicatorGroup != null ? mission.Difficulty.Value * (difficultyIndicatorGroup.Children.First().Rect.Width + difficultyIndicatorGroup.AbsoluteSpacing) : 0;
missionName.Padding = new Vector4(missionName.Padding.X + tickBox.Rect.Width * 1.2f + extraPadding,
missionName.Padding = new Vector4(missionName.Padding.X + (tickBox?.Rect.Width ?? 0) * 1.2f + extraPadding,
missionName.Padding.Y,
missionName.Padding.Z + extraZPadding + extraPadding,
missionName.Padding.W);
@@ -425,9 +474,11 @@ namespace Barotrauma
};
missionRewardTexts.Add(rewardText);
LocalizedString reputationText = mission.GetReputationRewardText(mission.Locations[0]);
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), missionTextContent.RectTransform), RichString.Rich(reputationText), wrap: true);
LocalizedString reputationText = mission.GetReputationRewardText();
if (!reputationText.IsNullOrEmpty())
{
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), missionTextContent.RectTransform), RichString.Rich(reputationText), wrap: true);
}
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), missionTextContent.RectTransform), RichString.Rich(mission.Description), wrap: true);
}
missionPanel.RectTransform.MinSize = new Point(0, (int)(missionTextContent.Children.Sum(c => c.Rect.Height + missionTextContent.AbsoluteSpacing) / missionTextContent.RectTransform.RelativeSize.Y) + GUI.IntScale(0));
@@ -487,7 +538,7 @@ namespace Barotrauma
OnClicked = (GUIButton btn, object obj) =>
{
if (missionList.Content.FindChild(c => c is GUITickBox tickBox && tickBox.Selected, recursive: true) == null &&
missionList.Content.Children.Any(c => c.UserData is Mission))
missionList.Content.Children.Any(c => c.UserData is Mission mission && mission.Locations.Contains(Campaign?.Map?.CurrentLocation)))
{
var noMissionVerification = new GUIMessageBox(string.Empty, TextManager.Get("nomissionprompt"), new LocalizedString[] { TextManager.Get("yes"), TextManager.Get("no") });
noMissionVerification.Buttons[0].OnClicked = (btn, userdata) =>
@@ -520,7 +571,7 @@ namespace Barotrauma
//locationInfoPanel?.UpdateAuto(1.0f);
}
public void SelectTab(CampaignMode.InteractionType tab, Identifier storeIdentifier = default)
public void SelectTab(CampaignMode.InteractionType tab, Character npc = null)
{
if (Campaign.ShowCampaignUI || (Campaign.ForceMapUI && tab == CampaignMode.InteractionType.Map))
{
@@ -541,7 +592,7 @@ namespace Barotrauma
switch (selectedTab)
{
case CampaignMode.InteractionType.Store:
Store.SelectStore(storeIdentifier);
Store.SelectStore(npc);
break;
case CampaignMode.InteractionType.Crew:
CrewManagement.UpdateCrew();
@@ -87,26 +87,26 @@ namespace Barotrauma.CharacterEditor
private float spriteSheetZoom = 1;
private float spriteSheetMinZoom = 0.25f;
private float spriteSheetMaxZoom = 1;
private int spriteSheetOffsetY = 20;
private int spriteSheetOffsetX = 30;
private const int spriteSheetOffsetY = 20;
private const int spriteSheetOffsetX = 30;
private bool hideBodySheet;
private Color backgroundColor = new Color(0.2f, 0.2f, 0.2f, 1.0f);
private Vector2 cameraOffset;
private List<LimbJoint> selectedJoints = new List<LimbJoint>();
private List<Limb> selectedLimbs = new List<Limb>();
private HashSet<Character> editedCharacters = new HashSet<Character>();
private readonly List<LimbJoint> selectedJoints = new List<LimbJoint>();
private readonly List<Limb> selectedLimbs = new List<Limb>();
private readonly HashSet<Character> editedCharacters = new HashSet<Character>();
private bool isEndlessRunner;
private Rectangle spriteSheetRect;
private Rectangle CalculateSpritesheetRectangle() =>
private Rectangle CalculateSpritesheetRectangle() =>
Textures == null || Textures.None() ? Rectangle.Empty :
new Rectangle(
spriteSheetOffsetX,
spriteSheetOffsetY,
(int)(Textures.OrderByDescending(t => t.Width).First().Width * spriteSheetZoom),
spriteSheetOffsetX,
spriteSheetOffsetY,
(int)(Textures.OrderByDescending(t => t.Width).First().Width * spriteSheetZoom),
(int)(Textures.Sum(t => t.Height) * spriteSheetZoom));
private const string screenTextTag = "CharacterEditor.";
@@ -143,7 +143,7 @@ namespace Barotrauma.CharacterEditor
var humanSpeciesName = CharacterPrefab.HumanSpeciesName;
if (humanSpeciesName.IsEmpty)
{
SpawnCharacter(AllSpecies.First());
SpawnCharacter(VisibleSpecies.First());
}
else
{
@@ -192,7 +192,7 @@ namespace Barotrauma.CharacterEditor
jointEndLimb = null;
anchor1Pos = null;
jointStartLimb = null;
allSpecies = null;
visibleSpecies = null;
onlyShowSourceRectForSelectedLimbs = false;
unrestrictSpritesheet = false;
editedCharacters.Clear();
@@ -214,15 +214,12 @@ namespace Barotrauma.CharacterEditor
private void Reset(IEnumerable<Character> characters = null)
{
if (characters == null)
{
characters = editedCharacters;
}
characters ??= editedCharacters;
characters.ForEach(c => ResetParams(c));
ResetVariables();
}
private void ResetParams(Character character)
private static void ResetParams(Character character)
{
character.Params.Reset(true);
foreach (var animation in character.AnimController.AllAnimParams)
@@ -719,7 +716,7 @@ namespace Barotrauma.CharacterEditor
cameraOffset = Vector2.Clamp(cameraOffset, min, max);
}
Cam.Position = targetPos + cameraOffset;
MapEntity.mapEntityList.ForEach(e => e.IsHighlighted = false);
MapEntity.ClearHighlightedEntities();
// Update widgets
jointSelectionWidgets.Values.ForEach(w => w.Update((float)deltaTime));
limbEditWidgets.Values.ForEach(w => w.Update((float)deltaTime));
@@ -994,7 +991,7 @@ namespace Barotrauma.CharacterEditor
var collider = character.AnimController.Collider;
var colliderDrawPos = SimToScreen(collider.SimPosition);
Vector2 forward = Vector2.Transform(Vector2.UnitY, Matrix.CreateRotationZ(collider.Rotation));
var endPos = SimToScreen(collider.SimPosition + forward * collider.radius);
var endPos = SimToScreen(collider.SimPosition + forward * collider.Radius);
GUI.DrawLine(spriteBatch, colliderDrawPos, endPos, GUIStyle.Green);
GUI.DrawLine(spriteBatch, colliderDrawPos, SimToScreen(collider.SimPosition + forward * 0.25f), Color.Blue);
Vector2 left = forward.Left();
@@ -1363,7 +1360,7 @@ namespace Barotrauma.CharacterEditor
private class WallGroup
{
public readonly List<Structure> walls;
public WallGroup(List<Structure> walls)
{
this.walls = walls;
@@ -1374,7 +1371,7 @@ namespace Barotrauma.CharacterEditor
var clones = new List<Structure>();
walls.ForEachMod(w => clones.Add(w.Clone() as Structure));
return new WallGroup(clones);
}
}
}
private void CloneWalls()
@@ -1391,7 +1388,7 @@ namespace Barotrauma.CharacterEditor
else if (i == 2)
{
clones[i].walls[j].Move(new Vector2(-originalWall.walls[j].Rect.Width, 0));
}
}
}
}
}
@@ -1404,8 +1401,8 @@ namespace Barotrauma.CharacterEditor
private WallGroup SelectLastClone(bool right)
{
var lastWall = right
? clones.SelectMany(c => c.walls).OrderBy(w => w.Rect.Right).Last()
var lastWall = right
? clones.SelectMany(c => c.walls).OrderBy(w => w.Rect.Right).Last()
: clones.SelectMany(c => c.walls).OrderBy(w => w.Rect.Left).First();
return clones.Where(c => c.walls.Contains(lastWall)).FirstOrDefault();
}
@@ -1440,33 +1437,35 @@ namespace Barotrauma.CharacterEditor
private Identifier currentCharacterIdentifier;
private Identifier selectedJob = Identifier.Empty;
private List<Identifier> allSpecies;
private List<Identifier> AllSpecies
private List<Identifier> visibleSpecies;
private List<Identifier> VisibleSpecies
{
get
{
if (allSpecies == null)
{
#if DEBUG
allSpecies = CharacterPrefab.Prefabs.Keys.OrderBy(p => p).ToList();
#else
allSpecies = CharacterPrefab.Prefabs.Keys.Where(p => !p.Contains("variant")).OrderBy(p => p).ToList();
#endif
allSpecies.ForEach(f => DebugConsole.NewMessage(f.Value, Color.White));
}
return allSpecies;
visibleSpecies ??= CharacterPrefab.Prefabs.Where(ShowCreature).OrderBy(p => p.Identifier).Select(p => p.Identifier).ToList();
return visibleSpecies;
}
}
private List<CharacterFile> vanillaCharacters;
private List<CharacterFile> VanillaCharacters
private bool ShowCreature(CharacterPrefab prefab)
{
Identifier speciesName = prefab.Identifier;
if (speciesName == CharacterPrefab.HumanSpeciesName) { return true; }
if (!VanillaCharacters.Contains(prefab.ContentFile))
{
// Always show all custom characters.
return true;
}
if (CreatureMetrics.UnlockAll) { return true; }
return CreatureMetrics.Unlocked.Contains(speciesName);
}
private IEnumerable<CharacterFile> vanillaCharacters;
private IEnumerable<CharacterFile> VanillaCharacters
{
get
{
if (vanillaCharacters == null)
{
vanillaCharacters = GameMain.VanillaContent.GetFiles<CharacterFile>().ToList();
}
vanillaCharacters ??= GameMain.VanillaContent.GetFiles<CharacterFile>();
return vanillaCharacters;
}
}
@@ -1475,7 +1474,7 @@ namespace Barotrauma.CharacterEditor
{
GetCurrentCharacterIndex();
IncreaseIndex();
currentCharacterIdentifier = AllSpecies[characterIndex];
currentCharacterIdentifier = VisibleSpecies[characterIndex];
return currentCharacterIdentifier;
}
@@ -1483,19 +1482,19 @@ namespace Barotrauma.CharacterEditor
{
GetCurrentCharacterIndex();
ReduceIndex();
currentCharacterIdentifier = AllSpecies[characterIndex];
currentCharacterIdentifier = VisibleSpecies[characterIndex];
return currentCharacterIdentifier;
}
private void GetCurrentCharacterIndex()
{
characterIndex = AllSpecies.IndexOf(character.SpeciesName);
characterIndex = VisibleSpecies.IndexOf(character.SpeciesName);
}
private void IncreaseIndex()
{
characterIndex++;
if (characterIndex > AllSpecies.Count - 1)
if (characterIndex > VisibleSpecies.Count - 1)
{
characterIndex = 0;
}
@@ -1506,7 +1505,7 @@ namespace Barotrauma.CharacterEditor
characterIndex--;
if (characterIndex < 0)
{
characterIndex = AllSpecies.Count - 1;
characterIndex = VisibleSpecies.Count - 1;
}
}
@@ -1687,7 +1686,7 @@ namespace Barotrauma.CharacterEditor
XElement overrideElement = null;
if (duplicate != null)
{
allSpecies = null;
visibleSpecies = null;
if (!File.Exists(configFilePath))
{
// If the file exists, we just want to overwrite it.
@@ -1823,9 +1822,9 @@ namespace Barotrauma.CharacterEditor
AnimationParams.Create(fullPath, name, animType, type);
}
}
if (!AllSpecies.Contains(name))
if (!VisibleSpecies.Contains(name))
{
AllSpecies.Add(name);
VisibleSpecies.Add(name);
}
SpawnCharacter(name, ragdollParams);
limbPairEditing = false;
@@ -2678,23 +2677,33 @@ namespace Barotrauma.CharacterEditor
{
Stretch = true
};
// Character selection
var characterLabel = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), content.RectTransform), GetCharacterEditorTranslation("CharacterPanel"), font: GUIStyle.LargeFont);
var characterDropDown = new GUIDropDown(new RectTransform(new Vector2(1, 0.2f), content.RectTransform)
{
RelativeOffset = new Vector2(0, 0.2f)
}, elementCount: 8, style: null);
characterDropDown.ListBox.Color = new Color(characterDropDown.ListBox.Color.R, characterDropDown.ListBox.Color.G, characterDropDown.ListBox.Color.B, byte.MaxValue);
foreach (var file in AllSpecies)
foreach (CharacterPrefab prefab in CharacterPrefab.Prefabs.OrderByDescending(p => p.Identifier))
{
characterDropDown.AddItem(file.Value.CapitaliseFirstInvariant(), file);
Identifier speciesName = prefab.Identifier;
if (ShowCreature(prefab))
{
characterDropDown.AddItem(speciesName.Value.CapitaliseFirstInvariant(), speciesName).SetAsFirstChild();
}
else if (!CreatureMetrics.Encountered.Contains(speciesName))
{
// Using a matching placeholder string here ("hidden").
var element = characterDropDown.AddItem(TextManager.Get("hiddensubmarines"), Identifier.Empty, textColor: Color.Gray * 0.75f);
element.SetAsLastChild();
element.Enabled = false;
}
}
characterDropDown.SelectItem(currentCharacterIdentifier);
characterDropDown.OnSelected = (component, data) =>
{
Identifier characterIdentifier = (Identifier)data;
if (characterIdentifier.IsEmpty) { return true; }
try
{
SpawnCharacter(characterIdentifier);
@@ -2795,7 +2804,7 @@ namespace Barotrauma.CharacterEditor
saveAllButton.OnClicked += (button, userData) =>
{
#if !DEBUG
if (VanillaCharacters != null && VanillaCharacters.Contains(CharacterPrefab.Prefabs[currentCharacterIdentifier].ContentFile))
if (VanillaCharacters.Contains(CharacterPrefab.Prefabs[currentCharacterIdentifier].ContentFile))
{
GUI.AddMessage(GetCharacterEditorTranslation("CannotEditVanillaCharacters"), GUIStyle.Red, font: GUIStyle.LargeFont);
return false;
@@ -2835,7 +2844,7 @@ namespace Barotrauma.CharacterEditor
box.Buttons[1].OnClicked += (b, d) =>
{
#if !DEBUG
if (VanillaCharacters != null && VanillaCharacters.Contains(CharacterPrefab.Prefabs[currentCharacterIdentifier].ContentFile))
if (VanillaCharacters.Contains(CharacterPrefab.Prefabs[currentCharacterIdentifier].ContentFile))
{
GUI.AddMessage(GetCharacterEditorTranslation("CannotEditVanillaCharacters"), GUIStyle.Red, font: GUIStyle.LargeFont);
box.Close();
@@ -2973,7 +2982,7 @@ namespace Barotrauma.CharacterEditor
box.Buttons[1].OnClicked += (b, d) =>
{
#if !DEBUG
if (VanillaCharacters != null && VanillaCharacters.Contains(CharacterPrefab.Prefabs[currentCharacterIdentifier].ContentFile))
if (VanillaCharacters.Contains(CharacterPrefab.Prefabs[currentCharacterIdentifier].ContentFile))
{
GUI.AddMessage(GetCharacterEditorTranslation("CannotEditVanillaCharacters"), GUIStyle.Red, font: GUIStyle.LargeFont);
box.Close();
@@ -3212,7 +3221,7 @@ namespace Barotrauma.CharacterEditor
Wizard.Instance.CopyExisting(CharacterParams, RagdollParams, AnimParams);
}
#region ToggleButtons
#region ToggleButtons
private enum Direction
{
Left,
@@ -4235,7 +4244,7 @@ namespace Barotrauma.CharacterEditor
int points = 1000;
float GetAmplitude() => ConvertUnits.ToDisplayUnits(fishSwimParams.WaveAmplitude) * Cam.Zoom / amplitudeMultiplier;
float GetWaveLength() => ConvertUnits.ToDisplayUnits(fishSwimParams.WaveLength) * Cam.Zoom / lengthMultiplier;
Vector2 GetRefPoint() => SimToScreen(collider.SimPosition) - GetScreenSpaceForward() * ConvertUnits.ToDisplayUnits(collider.radius) * 3 * Cam.Zoom;
Vector2 GetRefPoint() => SimToScreen(collider.SimPosition) - GetScreenSpaceForward() * ConvertUnits.ToDisplayUnits(collider.Radius) * 3 * Cam.Zoom;
Vector2 GetDrawPos() => GetRefPoint() - GetScreenSpaceForward() * GetWaveLength();
Vector2 GetDir() => GetRefPoint() - GetDrawPos();
Vector2 GetStartPoint() => GetDrawPos() + GetDir() / 2;
@@ -5008,9 +5017,9 @@ namespace Barotrauma.CharacterEditor
// We want the collider to be slightly smaller than the source rect, because the source rect is usually a bit bigger than the graphic.
float multiplier = 0.9f;
l.body.SetSize(new Vector2(size.X, size.Y) * l.Scale * RagdollParams.TextureScale * multiplier);
TryUpdateLimbParam(l, "radius", ConvertUnits.ToDisplayUnits(l.body.radius / l.Params.Scale / RagdollParams.LimbScale / RagdollParams.TextureScale));
TryUpdateLimbParam(l, "width", ConvertUnits.ToDisplayUnits(l.body.width / l.Params.Scale / RagdollParams.LimbScale / RagdollParams.TextureScale));
TryUpdateLimbParam(l, "height", ConvertUnits.ToDisplayUnits(l.body.height / l.Params.Scale / RagdollParams.LimbScale / RagdollParams.TextureScale));
TryUpdateLimbParam(l, "radius", ConvertUnits.ToDisplayUnits(l.body.Radius / l.Params.Scale / RagdollParams.LimbScale / RagdollParams.TextureScale));
TryUpdateLimbParam(l, "width", ConvertUnits.ToDisplayUnits(l.body.Width / l.Params.Scale / RagdollParams.LimbScale / RagdollParams.TextureScale));
TryUpdateLimbParam(l, "height", ConvertUnits.ToDisplayUnits(l.body.Height / l.Params.Scale / RagdollParams.LimbScale / RagdollParams.TextureScale));
}
private void RecalculateOrigin(Limb l, Vector2? newOrigin = null)
@@ -1,6 +1,4 @@
using Microsoft.Xna.Framework;
using System;
using System.Xml.Linq;
namespace Barotrauma
{
@@ -8,7 +6,7 @@ namespace Barotrauma
{
private GUIListBox listBox;
private ContentXElement configElement;
private readonly ContentXElement configElement;
private float scrollSpeed;
@@ -37,6 +35,8 @@ namespace Barotrauma
set { listBox.BarScroll = value; }
}
public readonly GUIButton CloseButton;
public CreditsPlayer(RectTransform rectT, string configFile) : base(null, rectT)
{
@@ -51,6 +51,10 @@ namespace Barotrauma
configElement = doc.Root.FromPackage(ContentPackageManager.VanillaCorePackage);
Load();
CloseButton = new GUIButton(new RectTransform(new Vector2(0.1f), RectTransform, Anchor.BottomRight, maxSize: new Point(GUI.IntScale(300), GUI.IntScale(50)))
{ AbsoluteOffset = new Point(GUI.IntScale(20), GUI.IntScale(20) + (Rect.Bottom - GameMain.GraphicsHeight)) },
TextManager.Get("close"));
}
private void Load()
@@ -1,4 +1,5 @@
using Barotrauma.Extensions;
using Barotrauma.Lights;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System;
@@ -14,9 +15,9 @@ namespace Barotrauma
private RenderTarget2D renderTargetWater;
private RenderTarget2D renderTargetFinal;
private Effect damageEffect;
private Texture2D damageStencil;
private Texture2D distortTexture;
public readonly Effect DamageEffect;
private readonly Texture2D damageStencil;
private readonly Texture2D distortTexture;
private float fadeToBlackState;
@@ -38,7 +39,7 @@ namespace Barotrauma
};
//var blurEffect = LoadEffect("Effects/blurshader");
damageEffect = EffectLoader.Load("Effects/damageshader");
DamageEffect = EffectLoader.Load("Effects/damageshader");
PostProcessEffect = EffectLoader.Load("Effects/postprocess");
GradientEffect = EffectLoader.Load("Effects/gradientshader");
GrainEffect = EffectLoader.Load("Effects/grainshader");
@@ -46,9 +47,9 @@ namespace Barotrauma
BlueprintEffect = EffectLoader.Load("Effects/blueprintshader");
damageStencil = TextureLoader.FromFile("Content/Map/walldamage.png");
damageEffect.Parameters["xStencil"].SetValue(damageStencil);
damageEffect.Parameters["aMultiplier"].SetValue(50.0f);
damageEffect.Parameters["cMultiplier"].SetValue(200.0f);
DamageEffect.Parameters["xStencil"].SetValue(damageStencil);
DamageEffect.Parameters["aMultiplier"].SetValue(50.0f);
DamageEffect.Parameters["cMultiplier"].SetValue(200.0f);
distortTexture = TextureLoader.FromFile("Content/Effects/distortnormals.png");
PostProcessEffect.Parameters["xDistortTexture"].SetValue(distortTexture);
@@ -105,13 +106,13 @@ namespace Barotrauma
c.DoVisibilityCheck(cam);
if (c.IsVisible != wasVisible)
{
c.AnimController.Limbs.ForEach(l =>
foreach (var limb in c.AnimController.Limbs)
{
if (l.LightSource != null)
if (limb.LightSource is LightSource light)
{
l.LightSource.Enabled = c.IsVisible;
light.Enabled = c.IsVisible;
}
});
}
}
}
@@ -187,6 +188,10 @@ namespace Barotrauma
GameMain.PerformanceCounter.AddElapsedTicks("Draw:Map:LOS", sw.ElapsedTicks);
sw.Restart();
static bool IsFromOutpostDrawnBehindSubs(Entity e)
=> e.Submarine is { Info.OutpostGenerationParams.DrawBehindSubs: true };
//------------------------------------------------------------------------
graphics.SetRenderTarget(renderTarget);
graphics.Clear(Color.Transparent);
@@ -194,7 +199,7 @@ namespace Barotrauma
//(= the background texture that's revealed when a wall is destroyed) into the background render target
//These will be visible through the LOS effect.
spriteBatch.Begin(SpriteSortMode.BackToFront, BlendState.NonPremultiplied, null, DepthStencilState.None, null, null, cam.Transform);
Submarine.DrawBack(spriteBatch, false, e => e is Structure s && (e.SpriteDepth >= 0.9f || s.Prefab.BackgroundSprite != null));
Submarine.DrawBack(spriteBatch, false, e => e is Structure s && (e.SpriteDepth >= 0.9f || s.Prefab.BackgroundSprite != null) && !IsFromOutpostDrawnBehindSubs(e));
Submarine.DrawPaintedColors(spriteBatch, false);
spriteBatch.End();
@@ -221,7 +226,11 @@ namespace Barotrauma
Level.Loaded.DrawBack(graphics, spriteBatch, cam);
}
//draw alpha blended particles that are in water and behind subs
spriteBatch.Begin(SpriteSortMode.BackToFront, BlendState.NonPremultiplied, null, DepthStencilState.None, null, null, cam.Transform);
Submarine.DrawBack(spriteBatch, false, e => e is Structure s && (e.SpriteDepth >= 0.9f || s.Prefab.BackgroundSprite != null) && IsFromOutpostDrawnBehindSubs(e));
spriteBatch.End();
//draw alpha blended particles that are in water and behind subs
#if LINUX || OSX
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, null, DepthStencilState.None, null, null, cam.Transform);
#else
@@ -336,12 +345,13 @@ namespace Barotrauma
GameMain.PerformanceCounter.AddElapsedTicks("Draw:Map:FrontParticles", sw.ElapsedTicks);
sw.Restart();
DamageEffect.CurrentTechnique = DamageEffect.Techniques["StencilShader"];
spriteBatch.Begin(SpriteSortMode.Immediate,
BlendState.NonPremultiplied, SamplerState.LinearWrap,
null, null,
damageEffect,
DamageEffect,
cam.Transform);
Submarine.DrawDamageable(spriteBatch, damageEffect, false);
Submarine.DrawDamageable(spriteBatch, DamageEffect, false);
spriteBatch.End();
sw.Stop();
@@ -368,7 +378,7 @@ namespace Barotrauma
{
graphics.DepthStencilState = DepthStencilState.None;
graphics.SamplerStates[0] = SamplerState.LinearWrap;
graphics.BlendState = Lights.CustomBlendStates.Multiplicative;
graphics.BlendState = CustomBlendStates.Multiplicative;
Quad.UseBasicEffect(GameMain.LightManager.LightMap);
Quad.Render();
}
@@ -399,12 +409,13 @@ namespace Barotrauma
{
GameMain.LightManager.LosEffect.CurrentTechnique = GameMain.LightManager.LosEffect.Techniques["LosShader"];
GameMain.LightManager.LosEffect.Parameters["blurDistance"].SetValue(0.005f);
GameMain.LightManager.LosEffect.Parameters["xTexture"].SetValue(renderTargetBackground);
GameMain.LightManager.LosEffect.Parameters["xLosTexture"].SetValue(GameMain.LightManager.LosTexture);
GameMain.LightManager.LosEffect.Parameters["xLosAlpha"].SetValue(GameMain.LightManager.LosAlpha);
Color losColor;
if (GameMain.LightManager.LosMode == LosMode.Transparent)
if (GameMain.LightManager.LosMode is LosMode.Transparent or LosMode.BlockOutsideView)
{
//convert the los color to HLS and make sure the luminance of the color is always the same
//as the luminance of the ambient light color
@@ -447,6 +458,11 @@ namespace Barotrauma
Vector3 chromaticAberrationStrength = GameSettings.CurrentConfig.Graphics.ChromaticAberration ?
new Vector3(-0.02f, -0.01f, 0.0f) : Vector3.Zero;
if (Level.Loaded?.Renderer != null)
{
chromaticAberrationStrength += new Vector3(-0.03f, -0.015f, 0.0f) * Level.Loaded.Renderer.ChromaticAberrationStrength;
}
if (Character.Controlled != null)
{
BlurStrength = Character.Controlled.BlurStrength * 0.005f;
@@ -504,6 +520,11 @@ namespace Barotrauma
spriteBatch.End();
}
if (GameMain.LightManager.DebugLos)
{
GameMain.LightManager.DebugDrawLos(spriteBatch, cam);
}
sw.Stop();
GameMain.PerformanceCounter.AddElapsedTicks("Draw:Map:PostProcess", sw.ElapsedTicks);
sw.Restart();
@@ -219,7 +219,7 @@ namespace Barotrauma
currentLevelData = LevelData.CreateRandom(seedBox.Text, generationParams: selectedParams);
currentLevelData.ForceOutpostGenerationParams = outpostParamsList.SelectedData as OutpostGenerationParams;
currentLevelData.AllowInvalidOutpost = allowInvalidOutpost.Selected;
var dummyLocations = GameSession.CreateDummyLocations(seed: currentLevelData.Seed);
var dummyLocations = GameSession.CreateDummyLocations(currentLevelData);
Level.Generate(currentLevelData, mirror: mirrorLevel.Selected, startLocation: dummyLocations[0], endLocation: dummyLocations[1]);
Submarine.MainSub?.SetPosition(Level.Loaded.StartPosition);
GameMain.LightManager.AddLight(pointerLightSource);
@@ -343,7 +343,7 @@ namespace Barotrauma
editorContainer.ClearChildren();
paramsList.Content.ClearChildren();
foreach (LevelGenerationParams genParams in LevelGenerationParams.LevelParams)
foreach (LevelGenerationParams genParams in LevelGenerationParams.LevelParams.OrderBy(p => p.Name))
{
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), paramsList.Content.RectTransform) { MinSize = new Point(0, 20) },
genParams.Identifier.Value)
@@ -359,7 +359,7 @@ namespace Barotrauma
editorContainer.ClearChildren();
caveParamsList.Content.ClearChildren();
foreach (CaveGenerationParams genParams in CaveGenerationParams.CaveParams)
foreach (CaveGenerationParams genParams in CaveGenerationParams.CaveParams.OrderBy(p => p.Name))
{
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), caveParamsList.Content.RectTransform) { MinSize = new Point(0, 20) },
genParams.Name)
@@ -375,7 +375,7 @@ namespace Barotrauma
editorContainer.ClearChildren();
ruinParamsList.Content.ClearChildren();
foreach (RuinGenerationParams genParams in RuinGenerationParams.RuinParams)
foreach (RuinGenerationParams genParams in RuinGenerationParams.RuinParams.OrderBy(p => p.Identifier))
{
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), ruinParamsList.Content.RectTransform) { MinSize = new Point(0, 20) },
genParams.Name)
@@ -391,7 +391,7 @@ namespace Barotrauma
editorContainer.ClearChildren();
outpostParamsList.Content.ClearChildren();
foreach (OutpostGenerationParams genParams in OutpostGenerationParams.OutpostParams)
foreach (OutpostGenerationParams genParams in OutpostGenerationParams.OutpostParams.OrderBy(p => p.Name))
{
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), outpostParamsList.Content.RectTransform) { MinSize = new Point(0, 20) },
genParams.Name)
@@ -46,7 +46,7 @@ namespace Barotrauma
private GUITextBox serverNameBox, passwordBox, maxPlayersBox;
private GUITickBox isPublicBox, wrongPasswordBanBox, karmaBox;
private GUIDropDown serverExecutableDropdown;
private GUIDropDown languageDropdown, serverExecutableDropdown;
private readonly GUIButton joinServerButton, hostServerButton;
private readonly GUIFrame modsButtonContainer;
@@ -82,6 +82,7 @@ namespace Barotrauma
{
GameMain.Instance.ResolutionChanged += () =>
{
SetMenuTabPositioning();
CreateHostServerFields();
CreateCampaignSetupUI();
SettingsMenu.Create(menuTabs[Tab.Settings].RectTransform);
@@ -426,31 +427,33 @@ namespace Barotrauma
var relativeSize = new Vector2(0.6f, 0.65f);
var minSize = new Point(600, 400);
var maxSize = new Point(2000, 1500);
var anchor = Anchor.CenterRight;
var pivot = Pivot.CenterRight;
Vector2 relativeSpacing = new Vector2(0.05f, 0.0f);
menuTabs = new Dictionary<Tab, GUIFrame>();
var anchor = Anchor.Center;
var pivot = Pivot.Center;
Vector2 relativeOffset = new Vector2(0.05f, 0.0f);
menuTabs[Tab.Settings] = new GUIFrame(new RectTransform(new Vector2(relativeSize.X, 0.8f), GUI.Canvas, anchor, pivot, minSize, maxSize) { RelativeOffset = relativeSpacing },
style: null);
menuTabs[Tab.Settings].CanBeFocused = false;
menuTabs[Tab.NewGame] = new GUIFrame(new RectTransform(relativeSize * new Vector2(1.0f, 1.15f), GUI.Canvas, anchor, pivot, minSize, maxSize) { RelativeOffset = relativeSpacing });
menuTabs[Tab.LoadGame] = new GUIFrame(new RectTransform(relativeSize, GUI.Canvas, anchor, pivot, minSize, maxSize) { RelativeOffset = relativeSpacing });
menuTabs = new Dictionary<Tab, GUIFrame>
{
[Tab.Settings] = new GUIFrame(new RectTransform(new Vector2(relativeSize.X, 0.8f), GUI.Canvas, anchor, pivot, minSize, maxSize) { RelativeOffset = relativeOffset },
style: null)
{
CanBeFocused = false
},
[Tab.NewGame] = new GUIFrame(new RectTransform(relativeSize * new Vector2(1.0f, 1.15f), GUI.Canvas, anchor, pivot, minSize, maxSize) { RelativeOffset = relativeOffset }),
[Tab.LoadGame] = new GUIFrame(new RectTransform(relativeSize, GUI.Canvas, anchor, pivot, minSize, maxSize) { RelativeOffset = relativeOffset })
};
CreateCampaignSetupUI();
var hostServerScale = new Vector2(0.7f, 1.2f);
menuTabs[Tab.HostServer] = new GUIFrame(new RectTransform(
Vector2.Multiply(relativeSize, hostServerScale), GUI.Canvas, anchor, pivot, minSize.Multiply(hostServerScale), maxSize.Multiply(hostServerScale))
{ RelativeOffset = relativeSpacing });
{ RelativeOffset = relativeOffset });
CreateHostServerFields();
//----------------------------------------------------------------------
menuTabs[Tab.Tutorials] = new GUIFrame(new RectTransform(relativeSize, GUI.Canvas, anchor, pivot, minSize, maxSize) { RelativeOffset = relativeSpacing });
menuTabs[Tab.Tutorials] = new GUIFrame(new RectTransform(relativeSize, GUI.Canvas, anchor, pivot, minSize, maxSize) { RelativeOffset = relativeOffset });
CreateTutorialTab();
this.game = game;
@@ -466,6 +469,25 @@ namespace Barotrauma
var creditsContainer = new GUIFrame(new RectTransform(new Vector2(0.75f, 1.5f), menuTabs[Tab.Credits].RectTransform, Anchor.CenterRight), style: "OuterGlow", color: Color.Black * 0.8f);
creditsPlayer = new CreditsPlayer(new RectTransform(Vector2.One, creditsContainer.RectTransform), "Content/Texts/Credits.xml");
creditsPlayer.CloseButton.OnClicked = (btn, userdata) =>
{
SelectTab(Tab.Empty);
return true;
};
SetMenuTabPositioning();
}
private void SetMenuTabPositioning()
{
foreach (GUIFrame menuTab in menuTabs.Values)
{
var anchor = GUI.IsUltrawide ? Anchor.Center : Anchor.CenterRight;
var pivot = GUI.IsUltrawide ? Pivot.Center : Pivot.CenterRight;
Vector2 relativeOffset = GUI.IsUltrawide ? Vector2.Zero : new Vector2(0.05f, 0.0f);
menuTab.RectTransform.SetPosition(anchor, pivot);
menuTab.RectTransform.RelativeOffset = relativeOffset;
}
}
private void CreateTutorialTab()
@@ -893,12 +915,14 @@ namespace Barotrauma
#endif
}
string arguments = "-name \"" + ToolBox.EscapeCharacters(name) + "\"" +
" -public " + isPublicBox.Selected.ToString() +
" -playstyle " + ((PlayStyle)playstyleBanner.UserData).ToString() +
" -banafterwrongpassword " + wrongPasswordBanBox.Selected.ToString() +
" -karmaenabled " + (!karmaBox.Selected).ToString() +
" -maxplayers " + maxPlayersBox.Text;
string arguments =
"-name \"" + ToolBox.EscapeCharacters(name) + "\"" +
" -public " + isPublicBox.Selected.ToString() +
" -playstyle " + ((PlayStyle)playstyleBanner.UserData).ToString() +
" -banafterwrongpassword " + wrongPasswordBanBox.Selected.ToString() +
" -karmaenabled " + (!karmaBox.Selected).ToString() +
" -maxplayers " + maxPlayersBox.Text +
$" -language \"{(LanguageIdentifier)languageDropdown.SelectedData}\"";
if (!string.IsNullOrWhiteSpace(passwordBox.Text))
{
@@ -1039,22 +1063,29 @@ namespace Barotrauma
#if UNSTABLE
backgroundSprite = new Sprite("Content/UnstableBackground.png", sourceRectangle: null);
#endif
backgroundSprite ??= (LocationType.Prefabs.Where(l => l.UseInMainMenu).GetRandomUnsynced())?.GetPortrait(0);
}
if (backgroundSprite != null)
{
GUI.DrawBackgroundSprite(spriteBatch, backgroundSprite,
aberrationStrength: 0.0f);
if (GUIStyle.GetComponentStyle("MainMenuBackground") is { } mainMenuStyle &&
mainMenuStyle.Sprites.TryGetValue(GUIComponent.ComponentState.None, out var sprites))
{
backgroundSprite = sprites.GetRandomUnsynced()?.Sprite;
}
backgroundSprite ??= LocationType.Prefabs.GetRandomUnsynced()?.GetPortrait(0);
}
var vignette = GUIStyle.GetComponentStyle("mainmenuvignette")?.GetDefaultSprite();
float vignetteScale = Math.Min(GameMain.GraphicsWidth / vignette.size.X, GameMain.GraphicsHeight / vignette.size.Y);
Rectangle drawArea = new Rectangle(
(int)(vignette.size.X * vignetteScale / 2), 0,
(int)(GameMain.GraphicsWidth - vignette.size.X * vignetteScale / 2), GameMain.GraphicsHeight);
if (backgroundSprite?.Texture != null)
{
GUI.DrawBackgroundSprite(spriteBatch, backgroundSprite, Color.White, drawArea);
}
if (vignette != null)
{
spriteBatch.Begin(blendState: BlendState.NonPremultiplied);
vignette.Draw(spriteBatch, Vector2.Zero, Color.White, Vector2.Zero, 0.0f,
new Vector2(GameMain.GraphicsWidth / vignette.size.X, GameMain.GraphicsHeight / vignette.size.Y));
spriteBatch.End();
vignette.Draw(spriteBatch, Vector2.Zero, Color.White, Vector2.Zero, 0.0f, vignetteScale);
}
}
@@ -1067,10 +1098,10 @@ namespace Barotrauma
public override void Draw(double deltaTime, GraphicsDevice graphics, SpriteBatch spriteBatch)
{
DrawBackground(graphics, spriteBatch);
spriteBatch.Begin(SpriteSortMode.Deferred, null, GUI.SamplerState, null, GameMain.ScissorTestEnable);
DrawBackground(graphics, spriteBatch);
GUI.Draw(Cam, spriteBatch);
if (selectedTab != Tab.Credits)
@@ -1100,7 +1131,7 @@ namespace Barotrauma
if (i == 0)
{
GUI.DrawLine(spriteBatch, textPos, textPos - Vector2.UnitX * textSize.X, mouseOn ? Color.White : Color.White * 0.7f);
if (mouseOn && PlayerInput.PrimaryMouseButtonClicked())
if (mouseOn && PlayerInput.PrimaryMouseButtonClicked() && GUI.MouseOn == null)
{
GameMain.ShowOpenUrlInWebBrowserPrompt("http://privacypolicy.daedalic.com");
}
@@ -1205,45 +1236,28 @@ namespace Barotrauma
{
menuTabs[Tab.HostServer].ClearChildren();
string name = "";
string password = "";
int maxPlayers = 8;
bool isPublic = true;
bool banAfterWrongPassword = false;
bool karmaEnabled = true;
string selectedKarmaPreset = "";
PlayStyle selectedPlayStyle = PlayStyle.Casual;
if (File.Exists(ServerSettings.SettingsFile))
var serverSettings = XMLExtensions.TryLoadXml(ServerSettings.SettingsFile, out _)?.Root ?? new XElement("serversettings");
var name = serverSettings.GetAttributeString("name", "");
var password = serverSettings.GetAttributeString("password", "");
var isPublic = serverSettings.GetAttributeBool("IsPublic", true);
var banAfterWrongPassword = serverSettings.GetAttributeBool("banafterwrongpassword", false);
int maxPlayersElement = serverSettings.GetAttributeInt("maxplayers", 8);
if (maxPlayersElement > NetConfig.MaxPlayers)
{
XDocument settingsDoc = XMLExtensions.TryLoadXml(ServerSettings.SettingsFile);
if (settingsDoc != null)
{
name = settingsDoc.Root.GetAttributeString("name", name);
password = settingsDoc.Root.GetAttributeString("password", password);
isPublic = settingsDoc.Root.GetAttributeBool("public", isPublic);
banAfterWrongPassword = settingsDoc.Root.GetAttributeBool("banafterwrongpassword", banAfterWrongPassword);
int maxPlayersElement = settingsDoc.Root.GetAttributeInt("maxplayers", maxPlayers);
if (maxPlayersElement > NetConfig.MaxPlayers)
{
DebugConsole.IsOpen = true;
DebugConsole.NewMessage($"Setting the maximum amount of players to {maxPlayersElement} failed due to exceeding the limit of {NetConfig.MaxPlayers} players per server. Using the maximum of {NetConfig.MaxPlayers} instead.", Color.Red);
maxPlayersElement = NetConfig.MaxPlayers;
}
maxPlayers = maxPlayersElement;
karmaEnabled = settingsDoc.Root.GetAttributeBool("karmaenabled", true);
selectedKarmaPreset = settingsDoc.Root.GetAttributeString("karmapreset", "default");
string playStyleStr = settingsDoc.Root.GetAttributeString("playstyle", "Casual");
Enum.TryParse(playStyleStr, out selectedPlayStyle);
}
DebugConsole.AddWarning($"Setting the maximum amount of players to {maxPlayersElement} failed due to exceeding the limit of {NetConfig.MaxPlayers} players per server. Using the maximum of {NetConfig.MaxPlayers} instead.");
}
int maxPlayers = Math.Clamp(maxPlayersElement, min: 1, max: NetConfig.MaxPlayers);
var karmaEnabled = serverSettings.GetAttributeBool("karmaenabled", true);
var selectedPlayStyle = serverSettings.GetAttributeEnum("playstyle", PlayStyle.Casual);
Vector2 textLabelSize = new Vector2(1.0f, 0.05f);
Alignment textAlignment = Alignment.CenterLeft;
Vector2 textFieldSize = new Vector2(0.5f, 1.0f);
Vector2 tickBoxSize = new Vector2(0.4f, 0.04f);
var content = new GUILayoutGroup(new RectTransform(new Vector2(0.7f, 0.9f), menuTabs[Tab.HostServer].RectTransform, Anchor.Center), childAnchor: Anchor.TopCenter)
var content = new GUILayoutGroup(new RectTransform(new Vector2(0.7f, 0.95f), menuTabs[Tab.HostServer].RectTransform, Anchor.Center), childAnchor: Anchor.TopCenter)
{
RelativeSpacing = 0.01f,
Stretch = true
@@ -1321,7 +1335,7 @@ namespace Barotrauma
//other settings -----------------------------------------------------
//spacing
new GUIFrame(new RectTransform(new Vector2(1.0f, 0.05f), content.RectTransform), style: null);
new GUIFrame(new RectTransform(new Vector2(1.0f, 0.025f), content.RectTransform), style: null);
var label = new GUITextBlock(new RectTransform(textLabelSize, parent.RectTransform), TextManager.Get("ServerName"), textAlignment: textAlignment);
serverNameBox = new GUITextBox(new RectTransform(textFieldSize, label.RectTransform, Anchor.CenterRight), text: name, textAlignment: textAlignment)
@@ -1373,6 +1387,21 @@ namespace Barotrauma
};
label.RectTransform.IsFixedSize = true;
var languageLabel = new GUITextBlock(new RectTransform(textLabelSize, parent.RectTransform),
TextManager.Get("Language"), textAlignment: textAlignment);
languageDropdown = new GUIDropDown(new RectTransform(textFieldSize, languageLabel.RectTransform, Anchor.CenterRight));
foreach (var language in ServerLanguageOptions.Options)
{
languageDropdown.AddItem(language.Label, language.Identifier);
}
var defaultLanguage = ServerLanguageOptions.PickLanguage(GameSettings.CurrentConfig.Language);
var settingsLanguage = serverSettings.GetAttributeIdentifier("language", defaultLanguage.Value).ToLanguageIdentifier();
if (!ServerLanguageOptions.Options.Any(o => o.Identifier == settingsLanguage))
{
settingsLanguage = defaultLanguage;
}
languageDropdown.Select(ServerLanguageOptions.Options.FindIndex(o => o.Identifier == settingsLanguage));
var serverExecutableLabel = new GUITextBlock(new RectTransform(textLabelSize, parent.RectTransform),
TextManager.Get("ServerExecutable"), textAlignment: textAlignment);
const string vanillaServerOption = "Vanilla";
@@ -398,12 +398,9 @@ namespace Barotrauma
public override void Draw(double deltaTime, GraphicsDevice graphics, SpriteBatch spriteBatch)
{
GameMain.MainMenuScreen.DrawBackground(graphics, spriteBatch); //wtf
spriteBatch.Begin(SpriteSortMode.Deferred, null, GUI.SamplerState, null, GameMain.ScissorTestEnable);
GameMain.MainMenuScreen.DrawBackground(graphics, spriteBatch);
GUI.Draw(Cam, spriteBatch);
spriteBatch.End();
}
}
@@ -301,7 +301,7 @@ namespace Barotrauma
levelSeed = value;
int intSeed = ToolBox.StringToInt(levelSeed);
backgroundSprite = LocationType.Random(new MTRandom(intSeed))?.GetPortrait(intSeed);
backgroundSprite = LocationType.Random(new MTRandom(intSeed), predicate: lt => lt.UsePortraitInRandomLoadingScreens)?.GetPortrait(intSeed);
SeedBox.Text = levelSeed;
}
}
@@ -1934,7 +1934,7 @@ namespace Barotrauma
var selectedSub = component.UserData as SubmarineInfo;
if (SelectedMode == GameModePreset.MultiPlayerCampaign && CampaignSetupUI != null)
{
if (selectedSub.Price > CampaignSetupUI.CurrentSettings.InitialMoney)
if (selectedSub.Price > CampaignSettings.CurrentSettings.InitialMoney)
{
new GUIMessageBox(TextManager.Get("warning"), TextManager.Get("campaignsubtooexpensive"));
}
@@ -2244,9 +2244,9 @@ namespace Barotrauma
List<ContextMenuOption> rankOptions = new List<ContextMenuOption>();
foreach (PermissionPreset rank in PermissionPreset.List)
{
rankOptions.Add(new ContextMenuOption(rank.Name, isEnabled: true, onSelected: () =>
rankOptions.Add(new ContextMenuOption(rank.DisplayName, isEnabled: true, onSelected: () =>
{
LocalizedString label = TextManager.GetWithVariables(rank.Permissions == ClientPermissions.None ? "clearrankprompt" : "giverankprompt", ("[user]", client.Name), ("[rank]", rank.Name));
LocalizedString label = TextManager.GetWithVariables(rank.Permissions == ClientPermissions.None ? "clearrankprompt" : "giverankprompt", ("[user]", client.Name), ("[rank]", rank.DisplayName));
GUIMessageBox msgBox = new GUIMessageBox(string.Empty, label, new[] { TextManager.Get("Yes"), TextManager.Get("Cancel") });
msgBox.Buttons[0].OnClicked = delegate
@@ -2350,7 +2350,7 @@ namespace Barotrauma
};
foreach (PermissionPreset permissionPreset in PermissionPreset.List)
{
rankDropDown.AddItem(permissionPreset.Name, permissionPreset, permissionPreset.Description);
rankDropDown.AddItem(permissionPreset.DisplayName, permissionPreset, permissionPreset.Description);
}
rankDropDown.AddItem(TextManager.Get("CustomRank"), null);
@@ -2758,12 +2758,10 @@ namespace Barotrauma
public override void Draw(double deltaTime, GraphicsDevice graphics, SpriteBatch spriteBatch)
{
if (backgroundSprite?.Texture == null) { return; }
graphics.Clear(Color.Black);
GUI.DrawBackgroundSprite(spriteBatch, backgroundSprite);
spriteBatch.Begin(SpriteSortMode.Deferred, samplerState: GUI.SamplerState, rasterizerState: GameMain.ScissorTestEnable);
GUI.DrawBackgroundSprite(spriteBatch, backgroundSprite, Color.White);
GUI.Draw(Cam, spriteBatch);
spriteBatch.End();
}
@@ -3315,7 +3313,7 @@ namespace Barotrauma
foreach (var subElement in SubList.Content.Children)
{
var sub = subElement.UserData as SubmarineInfo;
bool tooExpensive = sub.Price > CampaignSetupUI.CurrentSettings.InitialMoney;
bool tooExpensive = sub.Price > CampaignSettings.CurrentSettings.InitialMoney;
if (tooExpensive || !sub.IsCampaignCompatible)
{
foreach (var textBlock in subElement.GetAllChildren<GUITextBlock>())
@@ -166,7 +166,7 @@ namespace Barotrauma
{
prefabList.ClearChildren();
var particlePrefabs = GameMain.ParticleManager.GetPrefabList();
var particlePrefabs = ParticleManager.GetPrefabList();
foreach (ParticlePrefab particlePrefab in particlePrefabs)
{
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), prefabList.Content.RectTransform) { MinSize = new Point(0, 20) },
@@ -204,7 +204,7 @@ namespace Barotrauma
XDocument doc = XMLExtensions.TryLoadXml(configFile.Path);
if (doc == null) { continue; }
var prefabList = GameMain.ParticleManager.GetPrefabList();
var prefabList = ParticleManager.GetPrefabList();
foreach (ParticlePrefab prefab in prefabList)
{
foreach (XElement element in doc.Root.Elements())
@@ -273,7 +273,7 @@ namespace Barotrauma
XDocument doc = XMLExtensions.TryLoadXml(configFile.Path);
if (doc == null) { continue; }
var prefabList = GameMain.ParticleManager.GetPrefabList();
var prefabList = ParticleManager.GetPrefabList();
foreach (ParticlePrefab otherPrefab in prefabList)
{
foreach (var subElement in doc.Root.Elements())
@@ -7,8 +7,6 @@ using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Xml.Linq;
namespace Barotrauma
@@ -241,6 +239,7 @@ namespace Barotrauma
private GUITickBox filterPassword;
private GUITickBox filterFull;
private GUITickBox filterEmpty;
private GUIDropDown languageDropdown;
private Dictionary<Identifier, GUIDropDown> ternaryFilters;
private Dictionary<Identifier, GUITickBox> filterTickBoxes;
private Dictionary<Identifier, GUITickBox> playStyleTickBoxes;
@@ -255,6 +254,7 @@ namespace Barotrauma
private TernaryOption filterModdedValue = TernaryOption.Any;
private ColumnLabel sortedBy;
private bool sortedAscending = true;
private const float sidebarWidth = 0.2f;
public ServerListScreen()
@@ -425,10 +425,13 @@ namespace Barotrauma
ternaryFilters = new Dictionary<Identifier, GUIDropDown>();
filterTickBoxes = new Dictionary<Identifier, GUITickBox>();
RectTransform createFilterRectT()
=> new RectTransform(new Vector2(1.0f, elementHeight), filters.Content.RectTransform);
GUITickBox addTickBox(Identifier key, LocalizedString text = null, bool defaultState = false, bool addTooltip = false)
{
text ??= TextManager.Get(key);
var tickBox = new GUITickBox(new RectTransform(new Vector2(1.0f, elementHeight), filters.Content.RectTransform), text)
var tickBox = new GUITickBox(createFilterRectT(), text)
{
UserData = text,
Selected = defaultState,
@@ -450,6 +453,109 @@ namespace Barotrauma
filterEmpty = addTickBox("FilterEmptyServers".ToIdentifier());
filterOffensive = addTickBox("FilterOffensiveServers".ToIdentifier());
// Language filter
if (ServerLanguageOptions.Options.Any())
{
var languageKey = "Language".ToIdentifier();
var allLanguagesKey = "AllLanguages".ToIdentifier();
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), filters.Content.RectTransform), TextManager.Get(languageKey), font: GUIStyle.SubHeadingFont)
{
CanBeFocused = false
};
languageDropdown = new GUIDropDown(createFilterRectT(), selectMultiple: true);
languageDropdown.AddItem(TextManager.Get(allLanguagesKey), allLanguagesKey);
var allTickbox = languageDropdown.ListBox.Content.FindChild(allLanguagesKey)?.GetChild<GUITickBox>();
// Spacer between "All" and the individual languages
new GUIFrame(new RectTransform(new Vector2(1.0f, 0.0f), languageDropdown.ListBox.Content.RectTransform)
{
MinSize = new Point(0, GUI.IntScaleCeiling(2))
}, style: null)
{
Color = Color.DarkGray,
CanBeFocused = false
};
var selectedLanguages
= ServerListFilters.Instance.GetAttributeLanguageIdentifierArray(
languageKey,
Array.Empty<LanguageIdentifier>());
foreach (var (label, identifier, _) in ServerLanguageOptions.Options)
{
languageDropdown.AddItem(label, identifier);
}
if (!selectedLanguages.Any())
{
selectedLanguages = ServerLanguageOptions.Options.Select(o => o.Identifier).ToArray();
}
foreach (var lang in selectedLanguages)
{
languageDropdown.SelectItem(lang);
}
if (ServerLanguageOptions.Options.All(o => selectedLanguages.Any(l => o.Identifier == l)))
{
languageDropdown.SelectItem(allLanguagesKey);
languageDropdown.Text = TextManager.Get(allLanguagesKey);
}
var langTickboxes = languageDropdown.ListBox.Content.Children
.Where(c => c.UserData is LanguageIdentifier)
.Select(c => c.GetChild<GUITickBox>())
.ToArray();
bool inSelectedCall = false;
languageDropdown.OnSelected = (_, userData) =>
{
if (inSelectedCall) { return true; }
try
{
inSelectedCall = true;
if (Equals(allLanguagesKey, userData))
{
foreach (var tb in langTickboxes)
{
tb.Selected = allTickbox.Selected;
}
}
bool noneSelected = langTickboxes.All(tb => !tb.Selected);
bool allSelected = langTickboxes.All(tb => tb.Selected);
if (allSelected != allTickbox.Selected)
{
allTickbox.Selected = allSelected;
}
if (allSelected)
{
languageDropdown.Text = TextManager.Get(allLanguagesKey);
}
else if (noneSelected)
{
languageDropdown.Text = TextManager.Get("None");
}
var languages = languageDropdown.SelectedDataMultiple.OfType<LanguageIdentifier>();
ServerListFilters.Instance.SetAttribute(languageKey, string.Join(", ", languages));
GameSettings.SaveCurrentConfig();
return true;
}
finally
{
inSelectedCall = false;
FilterServers();
}
};
}
// Filter Tags
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), filters.Content.RectTransform), TextManager.Get("servertags"), font: GUIStyle.SubHeadingFont)
{
@@ -713,7 +819,7 @@ namespace Barotrauma
private void SortList(ColumnLabel sortBy, bool toggle)
{
if (!(labelHolder.GetChildByUserData(sortBy) is GUIButton button)) { return; }
if (labelHolder.GetChildByUserData(sortBy) is not GUIButton button) { return; }
sortedBy = sortBy;
@@ -730,51 +836,74 @@ namespace Barotrauma
}
}
bool ascending = arrowUp.Visible;
sortedAscending = arrowUp.Visible;
if (toggle)
{
ascending = !ascending;
sortedAscending = !sortedAscending;
}
arrowUp.Visible = ascending;
arrowDown.Visible = !ascending;
arrowUp.Visible = sortedAscending;
arrowDown.Visible = !sortedAscending;
serverList.Content.RectTransform.SortChildren((c1, c2) =>
{
if (!(c1.GUIComponent.UserData is ServerInfo s1)) { return 0; }
if (!(c2.GUIComponent.UserData is ServerInfo s2)) { return 0; }
switch (sortBy)
{
case ColumnLabel.ServerListCompatible:
bool s1Compatible = NetworkMember.IsCompatible(GameMain.Version, s1.GameVersion);
bool s2Compatible = NetworkMember.IsCompatible(GameMain.Version, s2.GameVersion);
if (s1Compatible == s2Compatible) { return 0; }
return (s1Compatible ? 1 : -1) * (ascending ? 1 : -1);
case ColumnLabel.ServerListHasPassword:
if (s1.HasPassword == s2.HasPassword) { return 0; }
return (s1.HasPassword ? 1 : -1) * (ascending ? 1 : -1);
case ColumnLabel.ServerListName:
// I think we actually want culture-specific sorting here?
return string.Compare(s1.ServerName, s2.ServerName, StringComparison.CurrentCulture) * (ascending ? 1 : -1);
case ColumnLabel.ServerListRoundStarted:
if (s1.GameStarted == s2.GameStarted) { return 0; }
return (s1.GameStarted ? 1 : -1) * (ascending ? 1 : -1);
case ColumnLabel.ServerListPlayers:
return s2.PlayerCount.CompareTo(s1.PlayerCount) * (ascending ? 1 : -1);
case ColumnLabel.ServerListPing:
return (s1.Ping.TryUnwrap(out var s1Ping), s2.Ping.TryUnwrap(out var s2Ping)) switch
{
(false, false) => 0,
(true, true) => s2Ping.CompareTo(s1Ping) * (ascending ? 1 : -1),
(false, true) => 1,
(true, false) => -1
};
default:
return 0;
}
if (c1.GUIComponent.UserData is not ServerInfo s1) { return 0; }
if (c2.GUIComponent.UserData is not ServerInfo s2) { return 0; }
int comparison = sortedAscending ? 1 : -1;
return CompareServer(sortBy, s1, s2) * comparison;
});
}
private void InsertServer(ServerInfo serverInfo, GUIComponent component)
{
var children = serverList.Content.RectTransform.Children.Reverse().ToList();
int comparison = sortedAscending ? 1 : -1;
foreach (var child in children)
{
if (child.GUIComponent.UserData is not ServerInfo serverInfo2 || serverInfo.Equals(serverInfo2)) { continue; }
if (CompareServer(sortedBy, serverInfo, serverInfo2) * comparison >= 0)
{
var index = serverList.Content.RectTransform.GetChildIndex(child);
component.RectTransform.RepositionChildInHierarchy(index + 1);
return;
}
}
component.RectTransform.SetAsFirstChild();
}
private static int CompareServer(ColumnLabel sortBy, ServerInfo s1, ServerInfo s2)
{
switch (sortBy)
{
case ColumnLabel.ServerListCompatible:
bool s1Compatible = NetworkMember.IsCompatible(GameMain.Version, s1.GameVersion);
bool s2Compatible = NetworkMember.IsCompatible(GameMain.Version, s2.GameVersion);
if (s1Compatible == s2Compatible) { return 0; }
return s1Compatible ? -1 : 1;
case ColumnLabel.ServerListHasPassword:
if (s1.HasPassword == s2.HasPassword) { return 0; }
return s1.HasPassword ? 1 : -1;
case ColumnLabel.ServerListName:
// I think we actually want culture-specific sorting here?
return string.Compare(s1.ServerName, s2.ServerName, StringComparison.CurrentCulture);
case ColumnLabel.ServerListRoundStarted:
if (s1.GameStarted == s2.GameStarted) { return 0; }
return s1.GameStarted ? 1 : -1;
case ColumnLabel.ServerListPlayers:
return s2.PlayerCount.CompareTo(s1.PlayerCount);
case ColumnLabel.ServerListPing:
return (s1.Ping.TryUnwrap(out var s1Ping), s2.Ping.TryUnwrap(out var s2Ping)) switch
{
(false, false) => 0,
(true, true) => s2Ping.CompareTo(s1Ping),
(false, true) => 1,
(true, false) => -1
};
default:
return 0;
}
}
public override void Select()
{
@@ -821,6 +950,7 @@ namespace Barotrauma
UpdateFriendsList();
panelAnimator?.Update();
scanServersButton.Enabled = (DateTime.Now - lastRefreshTime) >= AllowedRefreshInterval;
if (PlayerInput.PrimaryMouseButtonClicked())
@@ -840,7 +970,7 @@ namespace Barotrauma
RemoveMsgFromServerList(MsgUserData.NoMatchingServers);
foreach (GUIComponent child in serverList.Content.Children)
{
if (!(child.UserData is ServerInfo serverInfo)) { continue; }
if (child.UserData is not ServerInfo serverInfo) { continue; }
child.Visible = ShouldShowServer(serverInfo);
}
@@ -851,6 +981,20 @@ namespace Barotrauma
serverList.UpdateScrollBarSize();
}
private bool AllLanguagesVisible
{
get
{
if (languageDropdown is null) { return true; }
// CountChildren-1 because there's a separator element in there that can't be selected
int tickBoxCount = languageDropdown.ListBox.Content.CountChildren - 1;
int selectedCount = languageDropdown.SelectedIndexMultiple.Count();
return selectedCount >= tickBoxCount;
}
}
private bool ShouldShowServer(ServerInfo serverInfo)
{
#if !DEBUG
@@ -918,6 +1062,14 @@ namespace Barotrauma
}
}
if (!AllLanguagesVisible)
{
if (!languageDropdown.SelectedDataMultiple.OfType<LanguageIdentifier>().Contains(serverInfo.Language))
{
return false;
}
}
foreach (GUITickBox tickBox in gameModeTickBoxes.Values)
{
var gameMode = (Identifier)tickBox.UserData;
@@ -1031,8 +1183,8 @@ namespace Barotrauma
if (!(userdata is FriendInfo { IsInServer: true } info)) { return false; }
if (info.IsInServer
&& info.ConnectCommand is Some<ConnectCommand> { Value: { EndpointOrLobby: var endpointOrLobby } }
&& endpointOrLobby.TryGet(out ConnectCommand.NameAndEndpoint nameAndEndpoint))
&& info.ConnectCommand.TryUnwrap(out var command)
&& command.EndpointOrLobby.TryGet(out ConnectCommand.NameAndEndpoint nameAndEndpoint))
{
const int framePadding = 5;
@@ -1270,7 +1422,7 @@ namespace Barotrauma
serverPreview.Content.ClearChildren();
panelAnimator.RightEnabled = false;
joinButton.Enabled = false;
selectedServer = null;
selectedServer = Option.None;
if (selectedTab == TabEnum.All)
{
@@ -1370,8 +1522,7 @@ namespace Barotrauma
UpdateServerInfoUI(serverInfo);
if (!skipPing) { PingUtils.GetServerPing(serverInfo, UpdateServerInfoUI); }
SortList(sortedBy, toggle: false);
FilterServers();
InsertServer(serverInfo, serverFrame);
}
private void UpdateServerInfoUI(ServerInfo serverInfo)
@@ -1629,7 +1780,7 @@ namespace Barotrauma
#endif
}
private Color GetPingTextColor(int ping)
private static Color GetPingTextColor(int ping)
{
if (ping < 0) { return Color.DarkRed; }
return ToolBox.GradientLerp(ping / 200.0f, GUIStyle.Green, GUIStyle.Orange, GUIStyle.Red);
@@ -1640,12 +1791,10 @@ namespace Barotrauma
graphics.Clear(Color.CornflowerBlue);
GameMain.TitleScreen.DrawLoadingText = false;
GameMain.MainMenuScreen.DrawBackground(graphics, spriteBatch);
spriteBatch.Begin(SpriteSortMode.Deferred, null, GUI.SamplerState, null, GameMain.ScissorTestEnable);
GameMain.MainMenuScreen.DrawBackground(graphics, spriteBatch);
GUI.Draw(Cam, spriteBatch);
spriteBatch.End();
}
@@ -1666,6 +1815,7 @@ namespace Barotrauma
{
ServerListFilters.Instance.SetAttribute(ternaryFilter.Key, ternaryFilter.Value.SelectedData.ToString());
}
GameSettings.SaveCurrentConfig();
}
public void LoadServerFilters()
@@ -0,0 +1,173 @@
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System;
using System.Linq;
namespace Barotrauma
{
class SlideshowPlayer : GUIComponent
{
private readonly SlideshowPrefab slideshowPrefab;
private readonly LocalizedString pressAnyKeyText;
private int state;
private Color overlayColor, textColor;
private float timer;
private LocalizedString currentText;
public bool LastTextShown => state >= slideshowPrefab.Slides.Length;
public bool Finished => state > slideshowPrefab.Slides.Length;
public SlideshowPlayer(RectTransform rectT, SlideshowPrefab prefab) : base(null, rectT)
{
slideshowPrefab = prefab;
overlayColor = Color.Black;
textColor = Color.Transparent;
pressAnyKeyText = TextManager.Get("pressanykey");
RefreshText();
}
public void Restart()
{
state = 0;
}
public void Finish()
{
state = slideshowPrefab.Slides.Length + 1;
}
protected override void Update(float deltaTime)
{
var slide = slideshowPrefab.Slides[Math.Min(state, slideshowPrefab.Slides.Length - 1)];
if (!Visible || (Finished && timer > slide.FadeOutDuration)) { return; }
timer += deltaTime;
if (state == 0)
{
overlayColor = Color.Lerp(Color.Black, Color.White, Math.Min((timer - slide.FadeInDelay) / slide.FadeInDuration, 1.0f));
}
else
{
overlayColor = Color.Lerp(Color.Transparent, Color.White, Math.Min((timer - slide.FadeInDelay) / slide.FadeInDuration, 1.0f));
}
if (timer > slide.TextFadeInDelay)
{
textColor = Color.Lerp(Color.Transparent, Color.White, Math.Min((timer - slide.TextFadeInDelay) / slide.TextFadeInDuration, 1.0f));
if (AnyKeyHit())
{
if (timer > slide.TextFadeInDelay + slide.FadeInDuration)
{
overlayColor = textColor = Color.Transparent;
timer = 0.0f;
state++;
RefreshText();
}
else
{
timer = slide.TextFadeInDelay + slide.TextFadeInDuration;
}
}
}
else
{
textColor = Color.Transparent;
if (AnyKeyHit())
{
timer = slide.TextFadeInDelay + slide.TextFadeInDuration;
}
}
if (state >= slideshowPrefab.Slides.Length)
{
overlayColor = Color.Lerp(Color.White, Color.Transparent, Math.Min(timer / slide.FadeOutDuration, 1.0f));
textColor = Color.Lerp(Color.White, Color.Transparent, Math.Min(timer / slide.FadeOutDuration, 1.0f));
if (timer >= slide.FadeOutDuration)
{
state++;
RefreshText();
}
}
static bool AnyKeyHit()
{
return
PlayerInput.GetKeyboardState.GetPressedKeys().Any(k => PlayerInput.KeyHit(k)) ||
PlayerInput.PrimaryMouseButtonClicked();
}
}
private void RefreshText()
{
var slide = slideshowPrefab.Slides[Math.Min(state, slideshowPrefab.Slides.Length - 1)];
currentText = slide.Text
.Replace("[submarine]", Submarine.MainSub?.Info.Name ?? GameMain.GameSession?.SubmarineInfo?.Name ?? "Unknown")
.Replace("[location]", Level.Loaded?.StartOutpost?.Info.Name ?? "Unknown");
}
protected override void Draw(SpriteBatch spriteBatch)
{
if (slideshowPrefab.Slides.IsEmpty) { return; }
var slide = slideshowPrefab.Slides[Math.Min(state, slideshowPrefab.Slides.Length - 1)];
if ((Finished && timer > slide.FadeOutDuration)) { return; }
var overlaySprite = slide.Portrait;
if (overlaySprite != null)
{
Sprite prevPortrait = null;
if (state > 0 && state < slideshowPrefab.Slides.Length)
{
prevPortrait = slideshowPrefab.Slides[state - 1].Portrait;
DrawOverlay(prevPortrait, Color.White);
}
if (prevPortrait?.Texture != overlaySprite.Texture)
{
DrawOverlay(overlaySprite, overlayColor);
}
}
else
{
GUI.DrawRectangle(spriteBatch, new Rectangle(0, 0, GameMain.GraphicsWidth, GameMain.GraphicsHeight), overlayColor, isFilled: true);
}
if (!currentText.IsNullOrEmpty() && textColor.A > 0)
{
var backgroundSprite = GUIStyle.GetComponentStyle("CommandBackground").GetDefaultSprite();
Vector2 centerPos = new Vector2(GameMain.GraphicsWidth, GameMain.GraphicsHeight) / 2;
LocalizedString wrappedText = ToolBox.WrapText(currentText, GameMain.GraphicsWidth / 3, GUIStyle.Font);
Vector2 textSize = GUIStyle.Font.MeasureString(wrappedText);
Vector2 textPos = centerPos - textSize / 2;
backgroundSprite.Draw(spriteBatch,
centerPos,
Color.White * (textColor.A / 255.0f),
origin: backgroundSprite.size / 2,
rotate: 0.0f,
scale: new Vector2(GameMain.GraphicsWidth / 2 / backgroundSprite.size.X, textSize.Y / backgroundSprite.size.Y * 2.0f));
GUI.DrawString(spriteBatch, textPos + Vector2.One, wrappedText, Color.Black * (textColor.A / 255.0f));
GUI.DrawString(spriteBatch, textPos, wrappedText, textColor);
if (timer > slide.TextFadeInDelay * 2)
{
float alpha = Math.Min(timer - slide.TextFadeInDelay * 2, 1.0f);
Vector2 bottomTextPos = centerPos + new Vector2(0.0f, textSize.Y / 2 + 40 * GUI.Scale) - GUIStyle.Font.MeasureString(pressAnyKeyText) / 2;
GUI.DrawString(spriteBatch, bottomTextPos + Vector2.One, pressAnyKeyText, Color.Black * (textColor.A / 255.0f) * alpha);
GUI.DrawString(spriteBatch, bottomTextPos, pressAnyKeyText, textColor * alpha);
}
}
void DrawOverlay(Sprite sprite, Color color)
{
if (sprite.Texture == null) { return; }
GUI.DrawBackgroundSprite(spriteBatch, sprite, color);
}
}
}
}
@@ -1158,7 +1158,7 @@ namespace Barotrauma
foreach (MapEntityPrefab ep in entityLists[categoryKey])
{
#if !DEBUG
if (ep.HideInMenus) { continue; }
if (ep.HideInMenus && !GameMain.DebugDraw) { continue; }
#endif
CreateEntityElement(ep, entitiesPerRow, entityListInner.Content);
}
@@ -1177,7 +1177,7 @@ namespace Barotrauma
foreach (MapEntityPrefab ep in MapEntityPrefab.List)
{
#if !DEBUG
if (ep.HideInMenus) { continue; }
if (ep.HideInMenus && !GameMain.DebugDraw) { continue; }
#endif
CreateEntityElement(ep, entitiesPerRow, allEntityList.Content);
}
@@ -1306,7 +1306,6 @@ namespace Barotrauma
try
{
assemblyPrefab.Delete();
UpdateEntityList();
OpenEntityMenu(MapEntityCategory.ItemAssembly);
}
catch (Exception e)
@@ -2416,6 +2415,17 @@ namespace Barotrauma
return true;
}
};
new GUITickBox(new RectTransform(new Vector2(1.0f, 0.25f), beaconSettingsContainer.RectTransform), TextManager.Get("beaconstationplacement"))
{
Selected = MainSub.Info.BeaconStationInfo is { Placement: Level.PlacementType.Top },
OnSelected = (tb) =>
{
MainSub.Info.BeaconStationInfo.Placement = tb.Selected ?
Level.PlacementType.Top :
Level.PlacementType.Bottom;
return true;
}
};
beaconSettingsContainer.RectTransform.MinSize = new Point(0, beaconSettingsContainer.RectTransform.Children.Sum(c => c.Children.Any() ? c.Children.Max(c2 => c2.MinSize.Y) : 0));
//------------------------------------------------------------------
@@ -3079,9 +3089,17 @@ namespace Barotrauma
string newPackagePath = ContentPackageManager.LocalPackages.SaveRegularMod(modProject);
existingContentPackage = ContentPackageManager.LocalPackages.GetRegularModByPath(newPackagePath);
}
XDocument doc = new XDocument(ItemAssemblyPrefab.Save(MapEntity.SelectedList.ToList(), nameBox.Text, descriptionBox.Text, hideInMenus));
doc.SaveSafe(filePath);
try
{
doc.SaveSafe(filePath);
}
catch (Exception e)
{
DebugConsole.ThrowError($"Failed to save the item assembly to \"{filePath}\".", e);
return;
}
var result = ContentPackageManager.ReloadContentPackage(existingContentPackage);
if (!result.TryUnwrapSuccess(out var resultPackage))
@@ -3635,6 +3653,8 @@ namespace Barotrauma
private void OpenEntityMenu(MapEntityCategory? entityCategory)
{
UpdateEntityList();
foreach (GUIButton categoryButton in entityCategoryButtons)
{
categoryButton.Selected = entityCategory.HasValue ?
@@ -3762,14 +3782,14 @@ namespace Barotrauma
{
if (GUIContextMenu.CurrentContextMenu != null) { return; }
List<MapEntity> targets = MapEntity.mapEntityList.Any(me => me.IsHighlighted && !MapEntity.SelectedList.Contains(me)) ?
MapEntity.mapEntityList.Where(me => me.IsHighlighted).ToList() :
List<MapEntity> targets = MapEntity.HighlightedEntities.Any(me => !MapEntity.SelectedList.Contains(me)) ?
MapEntity.HighlightedEntities.ToList() :
new List<MapEntity>(MapEntity.SelectedList);
Item target = null;
var single = targets.Count == 1 ? targets.Single() : null;
if (single is Item item && item.Components.Any(ic => !(ic is ConnectionPanel) && !(ic is Repairable) && ic.GuiFrame != null))
if (single is Item item && item.Components.Any(ic => !(ic is ConnectionPanel) && ic is not Repairable && ic.GuiFrame != null))
{
// Do not offer the ability to open the inventory if the inventory should never be drawn
var container = item.GetComponent<ItemContainer>();
@@ -4014,7 +4034,7 @@ namespace Barotrauma
pickerMutex = new object(),
hexMutex = new object();
Vector2 relativeSize = new Vector2(GUI.IsFourByThree() ? 0.4f : 0.3f, 0.3f);
Vector2 relativeSize = new Vector2(0.4f * GUI.AspectRatioAdjustment, 0.3f);
GUIMessageBox msgBox = new GUIMessageBox(string.Empty, string.Empty, Array.Empty<LocalizedString>(), relativeSize, type: GUIMessageBox.Type.Vote)
{
@@ -4053,24 +4073,31 @@ namespace Barotrauma
GUILayoutGroup sliderLayout = new GUILayoutGroup(new RectTransform(new Vector2(1.0f - colorPicker.RectTransform.RelativeSize.X, 1f), colorLayout.RectTransform), childAnchor: Anchor.TopRight);
float currentHue = colorPicker.SelectedHue / 360f;
GUILayoutGroup hueSliderLayout = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.25f), sliderLayout.RectTransform), isHorizontal: true, childAnchor: Anchor.CenterLeft);
GUILayoutGroup hueSliderLayout = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.25f), sliderLayout.RectTransform), isHorizontal: true, childAnchor: Anchor.CenterLeft) { Stretch = true };
new GUITextBlock(new RectTransform(new Vector2(0.1f, 0.2f), hueSliderLayout.RectTransform), text: "H:", font: GUIStyle.SubHeadingFont) { Padding = Vector4.Zero, ToolTip = "Hue" };
GUIScrollBar hueScrollBar = new GUIScrollBar(new RectTransform(new Vector2(0.7f, 1f), hueSliderLayout.RectTransform), style: "GUISlider", barSize: 0.05f) { BarScroll = currentHue };
GUINumberInput hueTextBox = new GUINumberInput(new RectTransform(new Vector2(0.2f, 1f), hueSliderLayout.RectTransform), inputType: NumberType.Float) { FloatValue = currentHue, MaxValueFloat = 1f, MinValueFloat = 0f, DecimalsToDisplay = 2 };
GUINumberInput hueTextBox = new GUINumberInput(new RectTransform(new Vector2(0.2f, 1f), hueSliderLayout.RectTransform) { MinSize = new Point(GUI.IntScale(100), 0) },
inputType: NumberType.Float) { FloatValue = currentHue, MaxValueFloat = 1f, MinValueFloat = 0f, DecimalsToDisplay = 2 };
GUILayoutGroup satSliderLayout = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.2f), sliderLayout.RectTransform), isHorizontal: true, childAnchor: Anchor.CenterLeft);
GUILayoutGroup satSliderLayout = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.2f), sliderLayout.RectTransform), isHorizontal: true, childAnchor: Anchor.CenterLeft) { Stretch = true };
new GUITextBlock(new RectTransform(new Vector2(0.1f, 0.2f), satSliderLayout.RectTransform), text: "S:", font: GUIStyle.SubHeadingFont) { Padding = Vector4.Zero, ToolTip = "Saturation"};
GUIScrollBar satScrollBar = new GUIScrollBar(new RectTransform(new Vector2(0.7f, 1f), satSliderLayout.RectTransform), style: "GUISlider", barSize: 0.05f) { BarScroll = colorPicker.SelectedSaturation };
GUINumberInput satTextBox = new GUINumberInput(new RectTransform(new Vector2(0.2f, 1f), satSliderLayout.RectTransform), inputType: NumberType.Float) { FloatValue = colorPicker.SelectedSaturation, MaxValueFloat = 1f, MinValueFloat = 0f, DecimalsToDisplay = 2 };
GUINumberInput satTextBox = new GUINumberInput(new RectTransform(new Vector2(0.2f, 1f), satSliderLayout.RectTransform) { MinSize = new Point(GUI.IntScale(100), 0) },
inputType: NumberType.Float) { FloatValue = colorPicker.SelectedSaturation, MaxValueFloat = 1f, MinValueFloat = 0f, DecimalsToDisplay = 2 };
GUILayoutGroup valueSliderLayout = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.2f), sliderLayout.RectTransform), isHorizontal: true, childAnchor: Anchor.CenterLeft);
GUILayoutGroup valueSliderLayout = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.2f), sliderLayout.RectTransform), isHorizontal: true, childAnchor: Anchor.CenterLeft) { Stretch = true };
new GUITextBlock(new RectTransform(new Vector2(0.1f, 0.2f), valueSliderLayout.RectTransform), text: "V:", font: GUIStyle.SubHeadingFont) { Padding = Vector4.Zero, ToolTip = "Value"};
GUIScrollBar valueScrollBar = new GUIScrollBar(new RectTransform(new Vector2(0.7f, 1f), valueSliderLayout.RectTransform), style: "GUISlider", barSize: 0.05f) { BarScroll = colorPicker.SelectedValue };
GUINumberInput valueTextBox = new GUINumberInput(new RectTransform(new Vector2(0.2f, 1f), valueSliderLayout.RectTransform), inputType: NumberType.Float) { FloatValue = colorPicker.SelectedValue, MaxValueFloat = 1f, MinValueFloat = 0f, DecimalsToDisplay = 2 };
GUINumberInput valueTextBox = new GUINumberInput(new RectTransform(new Vector2(0.2f, 1f), valueSliderLayout.RectTransform) { MinSize = new Point(GUI.IntScale(100), 0) },
inputType: NumberType.Float) { FloatValue = colorPicker.SelectedValue, MaxValueFloat = 1f, MinValueFloat = 0f, DecimalsToDisplay = 2 };
GUILayoutGroup colorInfoLayout = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.3f), sliderLayout.RectTransform), childAnchor: Anchor.CenterLeft, isHorizontal: true) { RelativeSpacing = 0.15f };
GUILayoutGroup colorInfoLayout = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.3f), sliderLayout.RectTransform), childAnchor: Anchor.CenterLeft, isHorizontal: true)
{
Stretch = true,
RelativeSpacing = 0.1f
};
new GUICustomComponent(new RectTransform(new Vector2(0.4f, 0.8f), colorInfoLayout.RectTransform), (batch, component) =>
new GUICustomComponent(new RectTransform(Vector2.One, colorInfoLayout.RectTransform, scaleBasis: ScaleBasis.BothHeight), (batch, component) =>
{
Rectangle rect = component.Rect;
Point areaSize = new Point(rect.Width, rect.Height / 2);
@@ -5236,15 +5263,15 @@ namespace Barotrauma
}
}
if (PlayerInput.KeyHit(Keys.E) && mode == Mode.Default)
if (PlayerInput.KeyHit(InputType.Use) && mode == Mode.Default)
{
if (dummyCharacter != null)
{
if (dummyCharacter.SelectedItem == null)
{
foreach (var entity in MapEntity.mapEntityList)
foreach (var entity in MapEntity.HighlightedEntities)
{
if (entity is Item item && entity.IsHighlighted && item.Components.Any(ic => !(ic is ConnectionPanel) && !(ic is Repairable) && ic.GuiFrame != null))
if (entity is Item item && item.Components.Any(ic => ic is not ConnectionPanel && ic is not Repairable && ic.GuiFrame != null))
{
var container = item.GetComponents<ItemContainer>().ToList();
if (!container.Any() || container.Any(ic => ic?.DrawInventory ?? false))
@@ -5327,6 +5354,16 @@ namespace Barotrauma
else
{
var selectables = MapEntity.mapEntityList.Where(entity => entity.SelectableInEditor).ToList();
foreach (var item in Item.ItemList)
{
//attached wires are not normally selectable (by clicking),
//but let's select them manually when selecting all
var wire = item.GetComponent<Wire>();
if (wire != null && wire.Connections.None(c => c == null) && !selectables.Contains(item))
{
selectables.Add(item);
}
}
lock (selectables)
{
selectables.ForEach(MapEntity.AddSelection);
@@ -49,7 +49,7 @@ namespace Barotrauma
}
dummyCharacter = Character.Create(CharacterPrefab.HumanSpeciesName, Vector2.Zero, "", id: Entity.DummyID, hasAi: false);
dummyCharacter.Info.Job = new Job(JobPrefab.Prefabs.FirstOrDefault(static jp => jp.Identifier == "assistant"));
dummyCharacter.Info.Job = new Job(JobPrefab.Prefabs.FirstOrDefault(static jp => jp.Identifier == "captain"));
dummyCharacter.Info.Name = "Galldren";
dummyCharacter.Inventory.CreateSlots();
dummyCharacter.Info.GiveExperience(999999);