Unstable v0.1300.0.0 (February 19th 2021)

This commit is contained in:
Joonas Rikkonen
2021-02-25 13:44:23 +02:00
parent b772654326
commit 24cbef485a
441 changed files with 21343 additions and 8562 deletions
@@ -11,15 +11,15 @@ namespace Barotrauma
{
class CampaignSetupUI
{
private GUIComponent newGameContainer, loadGameContainer;
private readonly GUIComponent newGameContainer, loadGameContainer;
private GUIListBox subList;
private GUIListBox saveList;
private List<GUITickBox> subTickBoxes;
private GUITextBox saveNameBox, seedBox;
private readonly GUITextBox saveNameBox, seedBox;
private GUILayoutGroup subPreviewContainer;
private readonly GUILayoutGroup subPreviewContainer;
private GUIButton loadGameButton, deleteMpSaveButton;
@@ -35,6 +35,12 @@ namespace Barotrauma
private set;
}
public GUITextBlock InitialMoneyText
{
get;
private set;
}
private readonly bool isMultiplayer;
public CampaignSetupUI(bool isMultiplayer, GUIComponent newGameContainer, GUIComponent loadGameContainer, IEnumerable<SubmarineInfo> submarines, IEnumerable<string> saveFiles = null)
@@ -122,10 +128,10 @@ namespace Barotrauma
};
var buttonContainer = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.12f),
(isMultiplayer ? leftColumn : rightColumn).RectTransform) { MaxSize = new Point(int.MaxValue, 60) }, childAnchor: Anchor.TopRight);
(isMultiplayer ? leftColumn : rightColumn).RectTransform) { MaxSize = new Point(int.MaxValue, 60) }, childAnchor: Anchor.BottomRight, isHorizontal: true);
if (!isMultiplayer) { buttonContainer.IgnoreLayoutGroups = true; }
StartButton = new GUIButton(new RectTransform(new Vector2(0.45f, 1f), buttonContainer.RectTransform, Anchor.BottomRight) { MaxSize = new Point(350, 60) }, TextManager.Get("StartCampaignButton"))
StartButton = new GUIButton(new RectTransform(new Vector2(0.4f, 1f), buttonContainer.RectTransform, Anchor.BottomRight) { MaxSize = new Point(350, 60) }, TextManager.Get("StartCampaignButton"))
{
OnClicked = (GUIButton btn, object userData) =>
{
@@ -224,6 +230,27 @@ namespace Barotrauma
}
};
InitialMoneyText = new GUITextBlock(new RectTransform(new Vector2(0.6f, 1f), buttonContainer.RectTransform), "",
font: isMultiplayer ? GUI.Style.SmallFont : GUI.Style.Font, textColor: GUI.Style.Green)
{
TextGetter = () =>
{
int initialMoney = CampaignMode.InitialMoney;
if (isMultiplayer)
{
if (GameMain.NetLobbyScreen.SelectedSub != null)
{
initialMoney -= GameMain.NetLobbyScreen.SelectedSub.Price;
}
}
else if (subList.SelectedData is SubmarineInfo subInfo)
{
initialMoney -= subInfo.Price;
}
initialMoney = Math.Max(initialMoney, isMultiplayer ? MultiPlayerCampaign.MinimumInitialMoney : 0);
return TextManager.GetWithVariable("campaignstartingmoney", "[money]", string.Format(CultureInfo.InvariantCulture, "{0:N0}", initialMoney));
}
};
if (!isMultiplayer)
{
@@ -366,7 +393,7 @@ namespace Barotrauma
if (!(obj is SubmarineInfo sub)) { return true; }
#if !DEBUG
if (!isMultiplayer && sub.Price > CampaignMode.MaxInitialSubmarinePrice && !GameMain.DebugDraw)
if (!isMultiplayer && sub.Price > CampaignMode.InitialMoney && !GameMain.DebugDraw)
{
StartButton.Enabled = false;
return false;
@@ -419,13 +446,14 @@ namespace Barotrauma
}
else
{
subsToShow = submarines.Where(s => s.IsCampaignCompatibleIgnoreClass).ToList();
string downloadFolder = Path.GetFullPath(SaveUtil.SubmarineDownloadFolder);
subsToShow = submarines.Where(s => s.IsCampaignCompatibleIgnoreClass && Path.GetDirectoryName(Path.GetFullPath(s.FilePath)) != downloadFolder).ToList();
}
subsToShow.Sort((s1, s2) =>
{
int p1 = s1.Price > CampaignMode.MaxInitialSubmarinePrice ? 10 : 0;
int p2 = s2.Price > CampaignMode.MaxInitialSubmarinePrice ? 10 : 0;
int p1 = s1.Price > CampaignMode.InitialMoney ? 10 : 0;
int p2 = s2.Price > CampaignMode.InitialMoney ? 10 : 0;
return p1.CompareTo(p2) * 100 + s1.Name.CompareTo(s2.Name);
});
@@ -450,13 +478,13 @@ namespace Barotrauma
var priceText = new GUITextBlock(new RectTransform(new Vector2(0.5f, 1.0f), textBlock.RectTransform, Anchor.CenterRight),
TextManager.GetWithVariable("currencyformat", "[credits]", string.Format(CultureInfo.InvariantCulture, "{0:N0}", sub.Price)), textAlignment: Alignment.CenterRight, font: GUI.SmallFont)
{
TextColor = sub.Price > CampaignMode.MaxInitialSubmarinePrice ? GUI.Style.Red : textBlock.TextColor * 0.8f,
TextColor = sub.Price > CampaignMode.InitialMoney ? GUI.Style.Red : textBlock.TextColor * 0.8f,
ToolTip = textBlock.ToolTip
};
#if !DEBUG
if (!GameMain.DebugDraw)
{
if (sub.Price > CampaignMode.MaxInitialSubmarinePrice || !sub.IsCampaignCompatible)
if (sub.Price > CampaignMode.InitialMoney || !sub.IsCampaignCompatible)
{
textBlock.CanBeFocused = false;
textBlock.TextColor *= 0.5f;
@@ -466,7 +494,7 @@ namespace Barotrauma
}
if (SubmarineInfo.SavedSubmarines.Any())
{
var validSubs = subsToShow.Where(s => s.IsCampaignCompatible && s.Price <= CampaignMode.MaxInitialSubmarinePrice).ToList();
var validSubs = subsToShow.Where(s => s.IsCampaignCompatible && s.Price <= CampaignMode.InitialMoney).ToList();
if (validSubs.Count > 0)
{
subList.Select(validSubs[Rand.Int(validSubs.Count)]);
@@ -326,7 +326,7 @@ namespace Barotrauma
break;
case CampaignMode.InteractionType.Store:
Store?.Update();
Store?.Update(deltaTime);
break;
}
}
@@ -394,6 +394,42 @@ namespace Barotrauma
var difficultyLabel = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), textContent.RectTransform),
TextManager.Get("LevelDifficulty"), font: GUI.SubHeadingFont, textAlignment: Alignment.CenterLeft);
new GUITextBlock(new RectTransform(new Vector2(1.0f, 1.0f), difficultyLabel.RectTransform), ((int)connection.LevelData.Difficulty) + " %", textAlignment: Alignment.CenterRight);
if (connection.LevelData.HasBeaconStation)
{
var beaconStationContent = new GUILayoutGroup(new RectTransform(biomeLabel.RectTransform.NonScaledSize, textContent.RectTransform), isHorizontal: true, childAnchor: Anchor.CenterLeft);
string style = connection.LevelData.IsBeaconActive ? "BeaconStationActive" : "BeaconStationInactive";
var icon = new GUIImage(new RectTransform(new Point((int)(beaconStationContent.Rect.Height * 1.2f)), beaconStationContent.RectTransform),
style, scaleToFit: true)
{
Color = MapGenerationParams.Instance.IndicatorColor,
HoverColor = Color.Lerp(MapGenerationParams.Instance.IndicatorColor, Color.White, 0.5f),
ToolTip = TextManager.Get(connection.LevelData.IsBeaconActive ? "BeaconStationActiveTooltip" : "BeaconStationInactiveTooltip")
};
new GUITextBlock(new RectTransform(Vector2.One, beaconStationContent.RectTransform),
TextManager.Get("submarinetype.beaconstation"), font: GUI.SubHeadingFont, textAlignment: Alignment.CenterLeft)
{
Padding = Vector4.Zero,
ToolTip = icon.ToolTip
};
}
if (connection.LevelData.HasHuntingGrounds)
{
var huntingGroundsContent = new GUILayoutGroup(new RectTransform(biomeLabel.RectTransform.NonScaledSize, textContent.RectTransform), isHorizontal: true, childAnchor: Anchor.CenterLeft);
var icon = new GUIImage(new RectTransform(new Point((int)(huntingGroundsContent.Rect.Height * 1.5f)), huntingGroundsContent.RectTransform),
"HuntingGrounds", scaleToFit: true)
{
Color = MapGenerationParams.Instance.IndicatorColor,
HoverColor = Color.Lerp(MapGenerationParams.Instance.IndicatorColor, Color.White, 0.5f),
ToolTip = TextManager.Get("HuntingGroundsTooltip")
};
new GUITextBlock(new RectTransform(Vector2.One, huntingGroundsContent.RectTransform),
TextManager.Get("missionname.huntinggrounds"), font: GUI.SubHeadingFont, textAlignment: Alignment.CenterLeft)
{
Padding = Vector4.Zero,
ToolTip = icon.ToolTip
};
}
}
missionList = new GUIListBox(new RectTransform(new Vector2(1.0f, 0.4f), content.RectTransform))
@@ -439,8 +475,9 @@ namespace Barotrauma
};
missionName.Padding = new Vector4(missionName.Padding.X + icon.Rect.Width * 1.5f, missionName.Padding.Y, missionName.Padding.Z, missionName.Padding.W);
}
string rewardText = TextManager.GetWithVariable("currencyformat", "[credits]", string.Format(CultureInfo.InvariantCulture, "{0:N0}", mission.Reward));
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), missionTextContent.RectTransform),
TextManager.GetWithVariable("missionreward", "[reward]", string.Format(CultureInfo.InvariantCulture, "{0:N0}", mission.Reward)), wrap: true);
TextManager.GetWithVariable("missionreward", "[reward]", rewardText), wrap: true);
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), missionTextContent.RectTransform), mission.Description, wrap: true);
}
missionPanel.RectTransform.MinSize = new Point(0, (int)(missionTextContent.Children.Sum(c => c.Rect.Height) / missionTextContent.RectTransform.RelativeSize.Y) + GUI.IntScale(20));
@@ -491,7 +528,25 @@ namespace Barotrauma
StartButton = new GUIButton(new RectTransform(new Vector2(0.5f, 0.1f), content.RectTransform),
TextManager.Get("StartCampaignButton"), style: "GUIButtonLarge")
{
OnClicked = (GUIButton btn, object obj) => { StartRound?.Invoke(); return true; },
OnClicked = (GUIButton btn, object obj) =>
{
if (missionList.Content.Children.Any(c => c.UserData is Mission) && !(missionList.SelectedData is Mission))
{
var noMissionVerification = new GUIMessageBox(string.Empty, TextManager.Get("nomissionprompt"), new string[] { TextManager.Get("yes"), TextManager.Get("no") });
noMissionVerification.Buttons[0].OnClicked = (btn, userdata) =>
{
StartRound?.Invoke();
noMissionVerification.Close();
return true;
};
noMissionVerification.Buttons[1].OnClicked = noMissionVerification.Close;
}
else
{
StartRound?.Invoke();
}
return true;
},
Enabled = true,
Visible = Campaign.AllowedToEndRound()
};
@@ -766,7 +766,7 @@ namespace Barotrauma.CharacterEditor
if (editLimbs && !spriteSheetRect.Contains(PlayerInput.MousePosition) &&
MathUtils.RectangleContainsPoint(GetLimbPhysicRect(limb), PlayerInput.MousePosition)) { return CursorState.Hand; }
// spritesheet
if (GetLimbSpritesheetRect(limb).Contains(PlayerInput.MousePosition)) { return CursorState.Hand; }
if (showSpritesheet && GetLimbSpritesheetRect(limb).Contains(PlayerInput.MousePosition)) { return CursorState.Hand; }
}
return CursorState.Default;
}
@@ -820,6 +820,7 @@ namespace Barotrauma.CharacterEditor
}
}
}
spriteBatch.End();
// Lights
@@ -860,10 +861,7 @@ namespace Barotrauma.CharacterEditor
}
if (isDrawingLimb)
{
if (spriteSheetRect.Contains(PlayerInput.MousePosition))
{
GUI.DrawRectangle(spriteBatch, newLimbRect, Color.Yellow);
}
GUI.DrawRectangle(spriteBatch, newLimbRect, Color.Yellow);
}
if (jointCreationMode != JointCreationMode.None)
{
@@ -1131,32 +1129,25 @@ namespace Barotrauma.CharacterEditor
{
SetToggle(limbsToggle, true);
}
if (spriteSheetRect.Contains(PlayerInput.MousePosition))
if (PlayerInput.PrimaryMouseButtonHeld())
{
if (PlayerInput.PrimaryMouseButtonHeld())
if (newLimbRect == Rectangle.Empty)
{
if (newLimbRect == Rectangle.Empty)
{
newLimbRect = new Rectangle((int)PlayerInput.MousePosition.X, (int)PlayerInput.MousePosition.Y, 0, 0);
}
else
{
newLimbRect.Size = new Point((int)PlayerInput.MousePosition.X - newLimbRect.X, (int)PlayerInput.MousePosition.Y - newLimbRect.Y);
}
newLimbRect.Size = new Point(Math.Max(newLimbRect.Width, 2), Math.Max(newLimbRect.Height, 2));
newLimbRect = new Rectangle((int)PlayerInput.MousePosition.X, (int)PlayerInput.MousePosition.Y, 0, 0);
}
if (PlayerInput.PrimaryMouseButtonClicked())
else
{
// Take the offset and the zoom into account
newLimbRect.Location = new Point(newLimbRect.X - spriteSheetOffsetX, newLimbRect.Y - spriteSheetOffsetY);
newLimbRect = newLimbRect.Divide(spriteSheetZoom);
CreateNewLimb(newLimbRect);
isDrawingLimb = false;
newLimbRect = Rectangle.Empty;
newLimbRect.Size = new Point((int)PlayerInput.MousePosition.X - newLimbRect.X, (int)PlayerInput.MousePosition.Y - newLimbRect.Y);
}
newLimbRect.Size = new Point(Math.Max(newLimbRect.Width, 2), Math.Max(newLimbRect.Height, 2));
}
else
if (PlayerInput.PrimaryMouseButtonClicked())
{
// Take the offset and the zoom into account
newLimbRect.Location = new Point(newLimbRect.X - spriteSheetOffsetX, newLimbRect.Y - spriteSheetOffsetY);
newLimbRect = newLimbRect.Divide(spriteSheetZoom);
CreateNewLimb(newLimbRect);
isDrawingLimb = false;
newLimbRect = Rectangle.Empty;
}
}
@@ -1449,7 +1440,11 @@ namespace Barotrauma.CharacterEditor
{
if (allFiles == null)
{
#if DEBUG
allFiles = CharacterPrefab.ConfigFilePaths.OrderBy(p => p).ToList();
#else
allFiles = CharacterPrefab.ConfigFilePaths.Where(p => !p.Contains("variant", StringComparison.OrdinalIgnoreCase)).OrderBy(p => p).ToList();
#endif
allFiles.ForEach(f => DebugConsole.NewMessage(f, Color.White));
}
return allFiles;
@@ -1780,7 +1775,7 @@ namespace Barotrauma.CharacterEditor
// Animations
AnimationParams.ClearCache();
string animFolder = AnimationParams.GetFolder(name, contentPackage);
string animFolder = AnimationParams.GetFolder(name);
if (animations != null)
{
if (!Directory.Exists(animFolder))
@@ -1791,7 +1786,7 @@ namespace Barotrauma.CharacterEditor
{
XElement element = animation.MainElement;
element.SetAttributeValue("type", name);
string fullPath = AnimationParams.GetDefaultFile(name, animation.AnimationType, contentPackage);
string fullPath = AnimationParams.GetDefaultFile(name, animation.AnimationType);
element.Name = AnimationParams.GetDefaultFileName(name, animation.AnimationType);
#if DEBUG
element.Save(fullPath);
@@ -1816,7 +1811,7 @@ namespace Barotrauma.CharacterEditor
default: continue;
}
Type type = AnimationParams.GetParamTypeFromAnimType(animType, isHumanoid);
string fullPath = AnimationParams.GetDefaultFile(name, animType, contentPackage);
string fullPath = AnimationParams.GetDefaultFile(name, animType);
AnimationParams.Create(fullPath, name, animType, type);
}
}
@@ -1836,9 +1831,8 @@ namespace Barotrauma.CharacterEditor
private void ShowWearables()
{
if (character.Inventory == null) { return; }
foreach (var item in character.Inventory.Items)
foreach (var item in character.Inventory.AllItems)
{
if (item == null) { continue; }
// Temp condition, todo: remove
if (item.AllowedSlots.Contains(InvSlotType.Head) || item.AllowedSlots.Contains(InvSlotType.Headset)) { continue; }
item.Equip(character);
@@ -1847,7 +1841,7 @@ namespace Barotrauma.CharacterEditor
private void HideWearables()
{
character.Inventory?.Items.ForEachMod(i => i?.Unequip(character));
character.Inventory?.AllItemsMod.ForEach(i => i.Unequip(character));
}
#endregion
@@ -2787,8 +2781,10 @@ namespace Barotrauma.CharacterEditor
}
return true;
};
// Spacing
new GUIFrame(new RectTransform(buttonSize / 2, layoutGroup.RectTransform), style: null) { CanBeFocused = false };
Vector2 messageBoxRelSize = new Vector2(0.5f, 0.7f);
var saveRagdollButton = new GUIButton(new RectTransform(buttonSize, layoutGroup.RectTransform), GetCharacterEditorTranslation("SaveRagdoll"));
saveRagdollButton.OnClicked += (button, userData) =>
@@ -3573,15 +3569,33 @@ namespace Barotrauma.CharacterEditor
return rect;
}
// TODO: refactor this so that it can be used in all cases
private void UpdateSourceRect(Limb limb, Rectangle newRect)
private void UpdateSourceRect(Limb limb, Rectangle newRect, bool resize)
{
limb.ActiveSprite.SourceRect = newRect;
Sprite activeSprite = limb.ActiveSprite;
activeSprite.SourceRect = newRect;
if (limb.DamagedSprite != null)
{
limb.DamagedSprite.SourceRect = limb.ActiveSprite.SourceRect;
limb.DamagedSprite.SourceRect = activeSprite.SourceRect;
}
Vector2 colliderSize = new Vector2(ConvertUnits.ToSimUnits(newRect.Width), ConvertUnits.ToSimUnits(newRect.Height));
if (resize)
{
if (recalculateCollider)
{
RecalculateCollider(limb, colliderSize);
}
}
var spritePos = new Vector2(spriteSheetOffsetX, GetOffsetY(activeSprite));
var originWidget = GetLimbEditWidget($"{limb.Params.ID}_origin", limb);
if (!resize && originWidget != null)
{
Vector2 newOrigin = (originWidget.DrawPos - spritePos - activeSprite.SourceRect.Location.ToVector2() * spriteSheetZoom) / spriteSheetZoom;
RecalculateOrigin(limb, newOrigin);
}
else
{
RecalculateOrigin(limb);
}
RecalculateOrigin(limb);
TryUpdateLimbParam(limb, "sourcerect", newRect);
if (limbPairEditing)
{
@@ -3592,30 +3606,25 @@ namespace Barotrauma.CharacterEditor
{
otherLimb.DamagedSprite.SourceRect = newRect;
}
if (resize)
{
if (recalculateCollider)
{
RecalculateCollider(otherLimb, colliderSize);
}
}
if (!resize && originWidget != null)
{
Vector2 newOrigin = (originWidget.DrawPos - spritePos - activeSprite.SourceRect.Location.ToVector2() * spriteSheetZoom) / spriteSheetZoom;
RecalculateOrigin(otherLimb, newOrigin);
}
else
{
RecalculateOrigin(otherLimb);
}
TryUpdateLimbParam(otherLimb, "sourcerect", newRect);
RecalculateOrigin(otherLimb);
});
};
void RecalculateOrigin(Limb l)
{
// Keeps the relative origin unchanged. The absolute origin will be recalculated.
l.ActiveSprite.RelativeOrigin = l.ActiveSprite.RelativeOrigin;
// TODO:
//if (lockSpriteOrigin)
//{
// // Keeps the absolute origin unchanged. The relative origin will be recalculated.
// var spritePos = new Vector2(spriteSheetOffsetX, GetOffsetY(l));
// l.ActiveSprite.Origin = (originWidget.DrawPos - spritePos - l.ActiveSprite.SourceRect.Location.ToVector2() * spriteSheetZoom) / spriteSheetZoom;
// TryUpdateLimbParam(l, "origin", l.ActiveSprite.RelativeOrigin);
//}
//else
//{
// // Keeps the relative origin unchanged. The absolute origin will be recalculated.
// l.ActiveSprite.RelativeOrigin = l.ActiveSprite.RelativeOrigin;
//}
}
}
private void CalculateSpritesheetZoom()
@@ -4765,7 +4774,7 @@ namespace Barotrauma.CharacterEditor
w.refresh();
w.MouseHeld += dTime =>
{
var spritePos = new Vector2(spriteSheetOffsetX, GetOffsetY(limb));
var spritePos = new Vector2(spriteSheetOffsetX, GetOffsetY(limb.ActiveSprite));
w.DrawPos = PlayerInput.MousePosition.Clamp(spritePos + GetTopLeft() * spriteSheetZoom, spritePos + GetBottomRight() * spriteSheetZoom);
sprite.Origin = (w.DrawPos - spritePos - sprite.SourceRect.Location.ToVector2() * spriteSheetZoom) / spriteSheetZoom;
if (limb.DamagedSprite != null)
@@ -4796,14 +4805,14 @@ namespace Barotrauma.CharacterEditor
};
w.PreDraw += (sb, dTime) =>
{
var spritePos = new Vector2(spriteSheetOffsetX, GetOffsetY(limb));
var spritePos = new Vector2(spriteSheetOffsetX, GetOffsetY(limb.ActiveSprite));
w.DrawPos = (spritePos + (sprite.Origin + sprite.SourceRect.Location.ToVector2()) * spriteSheetZoom)
.Clamp(spritePos + GetTopLeft() * spriteSheetZoom, spritePos + GetBottomRight() * spriteSheetZoom);
w.refresh();
};
});
originWidget.Draw(spriteBatch, deltaTime);
if (!lockSpritePosition)
if (!lockSpritePosition && (limb.type != LimbType.Head || !character.IsHuman))
{
var positionWidget = GetLimbEditWidget($"{limb.Params.ID}_position", limb, widgetSize, Widget.Shape.Rectangle, initMethod: w =>
{
@@ -4812,17 +4821,20 @@ namespace Barotrauma.CharacterEditor
w.MouseHeld += dTime =>
{
w.DrawPos = PlayerInput.MousePosition;
var newRect = limb.ActiveSprite.SourceRect;
Sprite activeSprite = limb.ActiveSprite;
var newRect = activeSprite.SourceRect;
newRect.Location = new Point(
(int)((PlayerInput.MousePosition.X + halfSize - spriteSheetOffsetX) / spriteSheetZoom),
(int)((PlayerInput.MousePosition.Y + halfSize - GetOffsetY(limb)) / spriteSheetZoom));
limb.ActiveSprite.SourceRect = newRect;
(int)((PlayerInput.MousePosition.Y + halfSize - GetOffsetY(activeSprite)) / spriteSheetZoom));
activeSprite.SourceRect = newRect;
if (limb.DamagedSprite != null)
{
limb.DamagedSprite.SourceRect = limb.ActiveSprite.SourceRect;
limb.DamagedSprite.SourceRect = activeSprite.SourceRect;
}
RecalculateOrigin(limb);
TryUpdateLimbParam(limb, "sourcerect", newRect);
var spritePos = new Vector2(spriteSheetOffsetX, GetOffsetY(activeSprite));
Vector2 newOrigin = (originWidget.DrawPos - spritePos - activeSprite.SourceRect.Location.ToVector2() * spriteSheetZoom) / spriteSheetZoom;
RecalculateOrigin(limb, newOrigin);
if (limbPairEditing)
{
UpdateOtherLimbs(limb, otherLimb =>
@@ -4833,24 +4845,9 @@ namespace Barotrauma.CharacterEditor
otherLimb.DamagedSprite.SourceRect = newRect;
}
TryUpdateLimbParam(otherLimb, "sourcerect", newRect);
RecalculateOrigin(otherLimb);
RecalculateOrigin(otherLimb, newOrigin);
});
};
void RecalculateOrigin(Limb l)
{
if (lockSpriteOrigin)
{
// Keeps the absolute origin unchanged. The relative origin will be recalculated.
var spritePos = new Vector2(spriteSheetOffsetX, GetOffsetY(l));
l.ActiveSprite.Origin = (originWidget.DrawPos - spritePos - l.ActiveSprite.SourceRect.Location.ToVector2() * spriteSheetZoom) / spriteSheetZoom;
TryUpdateLimbParam(l, "origin", l.ActiveSprite.RelativeOrigin);
}
else
{
// Keeps the relative origin unchanged. The absolute origin will be recalculated.
l.ActiveSprite.RelativeOrigin = l.ActiveSprite.RelativeOrigin;
}
}
};
w.PreDraw += (sb, dTime) => w.refresh();
});
@@ -4860,7 +4857,7 @@ namespace Barotrauma.CharacterEditor
}
positionWidget.Draw(spriteBatch, deltaTime);
}
if (!lockSpriteSize)
if (!lockSpriteSize && (limb.type != LimbType.Head || !character.IsHuman))
{
var sizeWidget = GetLimbEditWidget($"{limb.Params.ID}_size", limb, widgetSize, Widget.Shape.Rectangle, initMethod: w =>
{
@@ -4869,22 +4866,24 @@ namespace Barotrauma.CharacterEditor
w.MouseHeld += dTime =>
{
w.DrawPos = PlayerInput.MousePosition;
var newRect = limb.ActiveSprite.SourceRect;
float offset_y = limb.ActiveSprite.SourceRect.Y * spriteSheetZoom + GetOffsetY(limb);
float offset_x = limb.ActiveSprite.SourceRect.X * spriteSheetZoom + spriteSheetOffsetX;
Sprite activeSprite = limb.ActiveSprite;
Rectangle newRect = activeSprite.SourceRect;
float offset_y = activeSprite.SourceRect.Y * spriteSheetZoom + GetOffsetY(activeSprite);
float offset_x = activeSprite.SourceRect.X * spriteSheetZoom + spriteSheetOffsetX;
int width = (int)((PlayerInput.MousePosition.X - halfSize - offset_x) / spriteSheetZoom);
int height = (int)((PlayerInput.MousePosition.Y - halfSize - offset_y) / spriteSheetZoom);
newRect.Size = new Point(width, height);
limb.ActiveSprite.SourceRect = newRect;
limb.ActiveSprite.size = new Vector2(width, height);
activeSprite.SourceRect = newRect;
activeSprite.size = new Vector2(width, height);
Vector2 colliderSize = new Vector2(ConvertUnits.ToSimUnits(width), ConvertUnits.ToSimUnits(height));
if (recalculateCollider)
{
RecalculateCollider(limb);
RecalculateCollider(limb, colliderSize);
}
RecalculateOrigin(limb);
if (limb.DamagedSprite != null)
{
limb.DamagedSprite.SourceRect = limb.ActiveSprite.SourceRect;
limb.DamagedSprite.SourceRect = activeSprite.SourceRect;
}
TryUpdateLimbParam(limb, "sourcerect", newRect);
if (limbPairEditing)
@@ -4895,7 +4894,7 @@ namespace Barotrauma.CharacterEditor
RecalculateOrigin(otherLimb);
if (recalculateCollider)
{
RecalculateCollider(otherLimb);
RecalculateCollider(otherLimb, colliderSize);
}
if (otherLimb.DamagedSprite != null)
{
@@ -4904,29 +4903,6 @@ namespace Barotrauma.CharacterEditor
TryUpdateLimbParam(otherLimb, "sourcerect", newRect);
});
};
void RecalculateCollider(Limb l)
{
// 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(ConvertUnits.ToSimUnits(width), ConvertUnits.ToSimUnits(height)) * 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));
}
void RecalculateOrigin(Limb l)
{
if (lockSpriteOrigin)
{
// Keeps the absolute origin unchanged. The relative origin will be recalculated.
l.ActiveSprite.Origin = l.ActiveSprite.Origin;
TryUpdateLimbParam(l, "origin", l.ActiveSprite.RelativeOrigin);
}
else
{
// Keeps the relative origin unchanged. The absolute origin will be recalculated.
l.ActiveSprite.RelativeOrigin = l.ActiveSprite.RelativeOrigin;
}
}
};
w.PreDraw += (sb, dTime) => w.refresh();
});
@@ -4955,22 +4931,48 @@ namespace Barotrauma.CharacterEditor
}
offsetY += (int)(texture.Height * spriteSheetZoom);
}
}
int GetTextureHeight(Limb limb)
private int GetTextureHeight(Sprite sprite)
{
int textureIndex = Textures.IndexOf(sprite.Texture);
int height = 0;
foreach (var t in Textures)
{
int textureIndex = Textures.IndexOf(limb.ActiveSprite.Texture);
int height = 0;
foreach (var t in Textures)
if (Textures.IndexOf(t) < textureIndex)
{
if (Textures.IndexOf(t) < textureIndex)
{
height += t.Height;
}
height += t.Height;
}
return (int)(height * spriteSheetZoom);
}
return (int)(height * spriteSheetZoom);
}
int GetOffsetY(Limb limb) => spriteSheetOffsetY + GetTextureHeight(limb);
private int GetOffsetY(Sprite sprite) => spriteSheetOffsetY + GetTextureHeight(sprite);
private void RecalculateCollider(Limb l, Vector2 size)
{
// 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));
}
private void RecalculateOrigin(Limb l, Vector2? newOrigin = null)
{
Sprite activeSprite = l.ActiveSprite;
if (lockSpriteOrigin)
{
// Keeps the absolute origin unchanged. The relative origin will be recalculated.
activeSprite.Origin = newOrigin ?? activeSprite.Origin;
TryUpdateLimbParam(l, "origin", activeSprite.RelativeOrigin);
}
else
{
// Keeps the relative origin unchanged. The absolute origin will be recalculated.
activeSprite.RelativeOrigin = activeSprite.RelativeOrigin;
}
}
private void DrawSpritesheetJointEditor(SpriteBatch spriteBatch, float deltaTime, Limb limb, Vector2 limbScreenPos, float spriteRotation = 0)
@@ -5175,61 +5177,81 @@ namespace Barotrauma.CharacterEditor
case Keys.Left:
foreach (var limb in selectedLimbs)
{
// Can't edit human heads
if (limb.type == LimbType.Head && character.IsHuman) { continue; }
var newRect = limb.ActiveSprite.SourceRect;
if (PlayerInput.KeyDown(Keys.LeftControl))
bool resize = PlayerInput.KeyDown(Keys.LeftControl);
if (resize)
{
if (lockSpriteSize) { return; }
newRect.Width--;
}
else
{
if (lockSpritePosition) { return; }
newRect.X--;
}
UpdateSourceRect(limb, newRect);
UpdateSourceRect(limb, newRect, resize);
}
break;
case Keys.Right:
foreach (var limb in selectedLimbs)
{
// Can't edit human heads
if (limb.type == LimbType.Head && character.IsHuman) { continue; }
var newRect = limb.ActiveSprite.SourceRect;
if (PlayerInput.KeyDown(Keys.LeftControl))
bool resize = PlayerInput.KeyDown(Keys.LeftControl);
if (resize)
{
if (lockSpriteSize) { return; }
newRect.Width++;
}
else
{
if (lockSpritePosition) { return; }
newRect.X++;
}
UpdateSourceRect(limb, newRect);
UpdateSourceRect(limb, newRect, resize);
}
break;
case Keys.Down:
foreach (var limb in selectedLimbs)
{
// Can't edit human heads
if (limb.type == LimbType.Head && character.IsHuman) { continue; }
var newRect = limb.ActiveSprite.SourceRect;
if (PlayerInput.KeyDown(Keys.LeftControl))
bool resize = PlayerInput.KeyDown(Keys.LeftControl);
if (resize)
{
if (lockSpriteSize) { return; }
newRect.Height++;
}
else
{
if (lockSpritePosition) { return; }
newRect.Y++;
}
UpdateSourceRect(limb, newRect);
UpdateSourceRect(limb, newRect, resize);
}
break;
case Keys.Up:
foreach (var limb in selectedLimbs)
{
// Can't edit human heads
if (limb.type == LimbType.Head && character.IsHuman) { continue; }
var newRect = limb.ActiveSprite.SourceRect;
if (PlayerInput.KeyDown(Keys.LeftControl))
bool resize = PlayerInput.KeyDown(Keys.LeftControl);
if (resize)
{
if (lockSpriteSize) { return; }
newRect.Height--;
}
else
{
if (lockSpritePosition) { return; }
newRect.Y--;
}
UpdateSourceRect(limb, newRect);
UpdateSourceRect(limb, newRect, resize);
}
break;
}
@@ -0,0 +1,571 @@
#nullable enable
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
namespace Barotrauma
{
class EditorImageManager
{
private struct EditorImageContainer
{
public float Rotation;
public float Scale;
public Vector2 Position;
public string Path;
public float Opacity;
public EditorImage.DrawTargetType DrawTarget;
public EditorImage CreateImage()
{
return new EditorImage(Path, Position)
{
Position = Position,
Scale = Scale,
Opacity = Opacity,
Rotation = Rotation,
DrawTarget = DrawTarget
};
}
public static EditorImageContainer? Load(XElement element)
{
string path = element.GetAttributeString("path", "");
if (string.IsNullOrWhiteSpace(path)) { return null; }
Vector2 pos = element.GetAttributeVector2("pos", Vector2.Zero);
float scale = element.GetAttributeFloat("scale", 1f);
float rotation = element.GetAttributeFloat("rotation", 0f);
float opacity = element.GetAttributeFloat("opacity", 1f);
string drawTargetString = element.GetAttributeString("drawtarget", "");
if (!Enum.TryParse<EditorImage.DrawTargetType>(drawTargetString, out var drawTarget))
{
drawTarget = EditorImage.DrawTargetType.World;
}
return new EditorImageContainer
{
Path = path,
Rotation = rotation,
Opacity = opacity,
Position = pos,
Scale = scale,
DrawTarget = drawTarget
};
}
public static EditorImageContainer ImageToContainer(EditorImage img)
{
return new EditorImageContainer
{
Path = img.ImagePath,
Rotation = img.Rotation,
Position = img.Position,
Opacity = img.Opacity,
Scale = img.Scale,
DrawTarget = img.DrawTarget
};
}
public static XElement SerializeImage(EditorImageContainer image)
{
return new XElement("image",
new XAttribute("pos", XMLExtensions.Vector2ToString(image.Position)),
new XAttribute("rotation", image.Rotation),
new XAttribute("opacity", image.Opacity),
new XAttribute("path", image.Path),
new XAttribute("scale", image.Scale),
new XAttribute("drawtarget", image.DrawTarget.ToString()));
}
}
private readonly List<EditorImageContainer> PendingImages = new List<EditorImageContainer>();
public readonly List<EditorImage> Images = new List<EditorImage>();
private readonly List<EditorImage> screenImages = new List<EditorImage>(),
worldImages = new List<EditorImage>();
public bool EditorMode;
private string editModeText = "";
private Vector2 textSize = Vector2.Zero;
public void Save(XElement element)
{
XElement saveElement = new XElement("editorimages");
foreach (EditorImage image in Images)
{
EditorImageContainer container = EditorImageContainer.ImageToContainer(image);
saveElement.Add(EditorImageContainer.SerializeImage(container));
}
foreach (EditorImageContainer container in PendingImages)
{
saveElement.Add(EditorImageContainer.SerializeImage(container));
}
element.Add(saveElement);
}
public void Load(XElement element)
{
Clear(alsoPending: true);
foreach (XElement subElement in element.Elements())
{
EditorImageContainer? tempImage = EditorImageContainer.Load(subElement);
if (tempImage != null)
{
PendingImages.Add(tempImage.Value);
}
}
}
public void OnEditorSelected()
{
editModeText = TextManager.Get("SubEditor.ImageEditingMode");
textSize = GUI.LargeFont.MeasureString(editModeText);
TryLoadPendingImages();
}
private void TryLoadPendingImages()
{
if (PendingImages.Count == 0) { return; }
Clear(alsoPending: false);
foreach (EditorImageContainer pendingImage in PendingImages)
{
EditorImage img = pendingImage.CreateImage();
if (img.Image == null) { continue; }
Images.Add(img);
img.UpdateRectangle();
}
UpdateImageCategories();
PendingImages.Clear();
}
public void Clear(bool alsoPending = false)
{
foreach (EditorImage img in Images)
{
img.Image?.Dispose();
}
Images.Clear();
screenImages.Clear();
worldImages.Clear();
if (alsoPending)
{
PendingImages.Clear();
}
}
public void Update(float deltaTime)
{
if (!EditorMode) { return; }
foreach (EditorImage image in Images)
{
image.Update(deltaTime);
}
if (PlayerInput.PrimaryMouseButtonDown())
{
EditorImage? hover = Images.FirstOrDefault(img => img.IsMouseOn());
if (hover != null)
{
foreach (EditorImage image in Images)
{
image.Selected = false;
}
hover.Selected = true;
}
}
if (PlayerInput.KeyHit(Keys.Delete) || (PlayerInput.IsCtrlDown() && PlayerInput.KeyHit(Keys.D)))
{
Images.RemoveAll(img => img.Selected);
UpdateImageCategories();
}
if (PlayerInput.KeyHit(Keys.Space))
{
foreach (EditorImage image in Images)
{
if (image.Selected)
{
if (image.DrawTarget == EditorImage.DrawTargetType.World)
{
Vector2 pos = image.Position;
pos.Y = -pos.Y;
pos = Screen.Selected.Cam.WorldToScreen(pos);
if (PlayerInput.IsShiftDown())
{
pos = new Vector2(GameMain.GraphicsWidth / 2f, GameMain.GraphicsHeight / 2f);
}
image.Position = pos;
image.DrawTarget = EditorImage.DrawTargetType.Camera;
image.Scale *= Screen.Selected.Cam.Zoom;
image.UpdateRectangle();
}
else
{
Vector2 pos = Screen.Selected.Cam.ScreenToWorld(image.Position);
pos.Y = -pos.Y;
image.Position = pos;
image.DrawTarget = EditorImage.DrawTargetType.World;
image.Scale /= Screen.Selected.Cam.Zoom;
image.UpdateRectangle();
}
}
}
UpdateImageCategories();
}
MapEntity.DisableSelect = true;
}
private void UpdateImageCategories()
{
screenImages.Clear();
worldImages.Clear();
foreach (EditorImage image in Images)
{
switch (image.DrawTarget)
{
case EditorImage.DrawTargetType.World:
worldImages.Add(image);
break;
default:
screenImages.Add(image);
break;
}
}
}
public void CreateImageWizard()
{
string home = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
if (!Directory.Exists(home)) { return; }
FileSelection.OnFileSelected = file =>
{
Vector2 pos = Screen.Selected.Cam.ScreenToWorld(PlayerInput.MousePosition);
pos.Y = -pos.Y;
Images.Add(new EditorImage(file, pos) { DrawTarget = EditorImage.DrawTargetType.World });
UpdateImageCategories();
GameMain.Config.SaveNewPlayerConfig();
};
FileSelection.ClearFileTypeFilters();
FileSelection.AddFileTypeFilter("PNG", "*.png");
FileSelection.AddFileTypeFilter("JPEG", "*.jpg, *.jpeg");
FileSelection.AddFileTypeFilter("All files", "*.*");
FileSelection.SelectFileTypeFilter("*.png");
FileSelection.CurrentDirectory = home;
FileSelection.Open = true;
}
public void DrawEditing(SpriteBatch spriteBatch, Camera cam)
{
if (!EditorMode) { return; }
DrawImages(spriteBatch, cam);
spriteBatch.Begin(SpriteSortMode.Deferred, samplerState: GUI.SamplerState);
Vector2 textPos = new Vector2(GameMain.GraphicsWidth / 2f - (textSize.X / 2f), GameMain.GraphicsHeight / 10f - (textSize.Y / 2f));
GUI.DrawString(spriteBatch, textPos, editModeText, GUI.Style.Yellow, Color.Black * 0.4f, 8, GUI.LargeFont);
spriteBatch.End();
}
public void Draw(SpriteBatch spriteBatch, Camera cam)
{
if (EditorMode) { return; }
DrawImages(spriteBatch, cam);
}
private void DrawImages(SpriteBatch spriteBatch, Camera cam)
{
if (screenImages.Count > 0)
{
spriteBatch.Begin(SpriteSortMode.Deferred, samplerState: GUI.SamplerState);
foreach (EditorImage image in screenImages)
{
image.Draw(spriteBatch);
if (EditorMode) { image.DrawEditing(spriteBatch, cam); }
}
spriteBatch.End();
}
if (worldImages.Count > 0)
{
spriteBatch.Begin(SpriteSortMode.Deferred, samplerState: GUI.SamplerState, transformMatrix: cam.Transform);
foreach (EditorImage image in worldImages)
{
image.Draw(spriteBatch);
if (EditorMode) { image.DrawEditing(spriteBatch, cam); }
}
spriteBatch.End();
}
}
}
class EditorImage
{
public enum DrawTargetType
{
Camera,
World
}
public Texture2D? Image;
public string ImagePath;
public Vector2 Position;
public float Rotation;
public float Opacity = 1f;
public float Scale = 1f;
public DrawTargetType DrawTarget;
public bool Selected;
public Rectangle Bounds;
private float prevAngle;
private bool disableMove;
private bool isDragging;
private readonly Dictionary<string, Widget> widgets = new Dictionary<string, Widget>();
public EditorImage(string path, Vector2 pos)
{
Image = Sprite.LoadTexture(path, out Sprite _, compress: false);
ImagePath = path;
Position = pos;
UpdateRectangle();
}
public bool IsMouseOn() => Bounds.Contains(GetMousePos());
public Vector2 GetMousePos()
{
switch (DrawTarget)
{
case DrawTargetType.Camera:
return PlayerInput.MousePosition;
case DrawTargetType.World:
Vector2 pos = Screen.Selected.Cam.ScreenToWorld(PlayerInput.MousePosition);
pos.Y = -pos.Y;
return pos;
default:
return PlayerInput.MousePosition;
}
}
public void Update(float deltaTime)
{
if (!Selected) { return; }
if (widgets.Values.Any(w => w.IsSelected)) { return; }
if (PlayerInput.PrimaryMouseButtonDown() && !disableMove && IsMouseOn())
{
isDragging = true;
}
if (isDragging)
{
Camera cam = Screen.Selected.Cam;
if (PlayerInput.MouseSpeed != Vector2.Zero)
{
Vector2 mouseSpeed = PlayerInput.MouseSpeed;
if (DrawTarget == DrawTargetType.World)
{
mouseSpeed /= cam.Zoom;
}
Position += mouseSpeed;
UpdateRectangle();
}
}
if (PlayerInput.KeyDown(Keys.OemPlus) || PlayerInput.KeyDown(Keys.Up))
{
Opacity += 0.01f;
}
if (PlayerInput.KeyDown(Keys.OemMinus) || PlayerInput.KeyDown(Keys.Down))
{
Opacity -= 0.01f;
}
if (PlayerInput.KeyHit(Keys.D0))
{
Opacity = 1f;
}
Opacity = Math.Clamp(Opacity, 0, 1f);
if (!PlayerInput.PrimaryMouseButtonHeld())
{
isDragging = false;
}
}
private void DrawWidgets(SpriteBatch spriteBatch)
{
float widgetSize = Image == null ? 100f : Math.Max(Image.Width, Image.Height) / 2f;
int width = 3;
int size = 32;
if (DrawTarget == DrawTargetType.World)
{
width = Math.Max(width, (int) (width / Screen.Selected.Cam.Zoom));
}
Widget currentWidget = GetWidget("transform", size, width, widget =>
{
widget.MouseDown += () =>
{
widget.color = GUI.Style.Green;
prevAngle = Rotation;
disableMove = true;
};
widget.Deselected += () =>
{
widget.color = Color.Yellow;
disableMove = false;
};
widget.MouseHeld += (deltaTime) =>
{
Rotation = GetRotationAngle(Position) + (float) Math.PI / 2f;
float distance = Vector2.Distance(Position, GetMousePos());
Scale = Math.Abs(distance) / widgetSize;
if (PlayerInput.IsShiftDown())
{
const float rotationStep = (float) (Math.PI / 4f);
Rotation = (float) Math.Round(Rotation / rotationStep) * rotationStep;
}
if (PlayerInput.IsCtrlDown())
{
const float scaleStep = 0.1f;
Scale = (float) Math.Round(Scale / scaleStep) * scaleStep;
}
UpdateRectangle();
};
widget.PreUpdate += (deltaTime) =>
{
if (DrawTarget != DrawTargetType.World) { return; }
widget.DrawPos = new Vector2(widget.DrawPos.X, -widget.DrawPos.Y);
widget.DrawPos = Screen.Selected.Cam.WorldToScreen(widget.DrawPos);
};
widget.PostUpdate += (deltaTime) =>
{
if (DrawTarget != DrawTargetType.World) { return; }
widget.DrawPos = Screen.Selected.Cam.ScreenToWorld(widget.DrawPos);
widget.DrawPos = new Vector2(widget.DrawPos.X, -widget.DrawPos.Y);
};
widget.PreDraw += (sprtBtch, deltaTime) =>
{
widget.tooltip = $"Scale: {Math.Round(Scale, 2)}\n" +
$"Rotation: {(int) MathHelper.ToDegrees(Rotation)}";
float rotation = Rotation - (float) Math.PI / 2f;
widget.DrawPos = Position + new Vector2((float) Math.Cos(rotation), (float) Math.Sin(rotation)) * (Scale * widgetSize);
widget.Update(deltaTime);
};
});
currentWidget.Draw(spriteBatch, (float) Timing.Step);
GUI.DrawLine(spriteBatch, Position, currentWidget.DrawPos, GUI.Style.Green, width: width);
}
private float GetRotationAngle(Vector2 drawPosition)
{
Vector2 rotationVector = GetMousePos() - drawPosition;
rotationVector.Normalize();
double angle = Math.Atan2(MathHelper.ToRadians(rotationVector.Y), MathHelper.ToRadians(rotationVector.X));
if (angle < 0)
{
angle = Math.Abs(angle - prevAngle) < Math.Abs((angle + Math.PI * 2) - prevAngle) ? angle : angle + Math.PI * 2;
}
else if (angle > 0)
{
angle = Math.Abs(angle - prevAngle) < Math.Abs((angle - Math.PI * 2) - prevAngle) ? angle : angle - Math.PI * 2;
}
angle = MathHelper.Clamp((float) angle, -((float) Math.PI * 2), (float) Math.PI * 2);
prevAngle = (float) angle;
return (float) angle;
}
private Widget GetWidget(string id, int size, float thickness = 1f, Action<Widget>? initMethod = null)
{
if (!widgets.TryGetValue(id, out Widget? widget))
{
widget = new Widget(id, size, Widget.Shape.Rectangle)
{
color = Color.Yellow,
RequireMouseOn = false
};
widgets.Add(id, widget);
initMethod?.Invoke(widget);
}
widget.size = size;
widget.thickness = thickness;
return widget;
}
public void UpdateRectangle()
{
if (Image == null)
{
Bounds = new Rectangle((int) Position.X, (int) Position.Y, 512, 512);
return;
}
Vector2 size = new Vector2(Image.Width * Scale, Image.Height * Scale);
Bounds = new Rectangle((Position - size / 2f).ToPoint(), size.ToPoint());
}
public void Draw(SpriteBatch spriteBatch)
{
if (Image == null) { return; }
spriteBatch.Draw(Image, Position, null, Color.White * Opacity, Rotation, new Vector2(Image.Width / 2f, Image.Height / 2f), scale: Scale, SpriteEffects.None, 0f);
}
public void DrawEditing(SpriteBatch spriteBatch, Camera cam)
{
Rectangle bounds = Bounds;
int width = 4;
if (DrawTarget == DrawTargetType.World)
{
width = (int) (width / cam.Zoom);
}
GUI.DrawRectangle(spriteBatch, bounds, Selected ? GUI.Style.Red : GUI.Style.Green, thickness: width);
if (Selected)
{
DrawWidgets(spriteBatch);
}
}
}
}
@@ -17,8 +17,6 @@ namespace Barotrauma
{
private GUIFrame GuiFrame = null!;
private GUIListBox? contextMenu;
public override Camera Cam { get; }
public static string? DrawnTooltip { get; set; }
@@ -399,7 +397,7 @@ namespace Barotrauma
else
{
newNode = new CustomNode(subElement.Name.ToString()) { Position = new Vector2(ident, 0), ID = CreateID() };
foreach (XAttribute attribute in subElement.Attributes())
foreach (XAttribute attribute in subElement.Attributes().Where(attribute => !attribute.ToString().StartsWith("_")))
{
newNode.Connections.Add(new NodeConnection(newNode, NodeConnectionType.Value, attribute.Name.ToString(), typeof(string)));
}
@@ -525,6 +523,7 @@ namespace Barotrauma
public override void Select()
{
GUI.PreventPauseMenuToggle = false;
projectName = TextManager.Get("EventEditor.Unnamed");
base.Select();
}
@@ -537,7 +536,6 @@ namespace Barotrauma
public override void AddToGUIUpdateList()
{
GuiFrame.AddToGUIUpdateList();
contextMenu?.AddToGUIUpdateList();
}
private XElement? ExportXML()
@@ -596,7 +594,7 @@ namespace Barotrauma
foreach (var (node, text, end) in options)
{
XElement optionElement = new XElement("Option");
optionElement.Add(new XAttribute("text", text));
optionElement.Add(new XAttribute("text", text ?? ""));
if (end) { optionElement.Add(new XAttribute("endconversation", true)); }
if (node is EventNode eventNode)
@@ -673,82 +671,37 @@ namespace Barotrauma
private void CreateContextMenu(EditorNode node, NodeConnection? connection = null)
{
contextMenu = new GUIListBox(new RectTransform(new Vector2(0.1f, 0.1f), GUI.Canvas) { ScreenSpaceOffset = PlayerInput.MousePosition.ToPoint() }, style: "GUIToolTip") { Padding = new Vector4(5) };
if (GUIContextMenu.CurrentContextMenu != null) { return; }
new GUITextBlock(new RectTransform(Point.Zero, contextMenu.Content.RectTransform),
TextManager.Get("EventEditor.Edit"), font: GUI.SmallFont) { UserData = "edit", Enabled = node is ValueNode || connection?.Type == NodeConnectionType.Value || connection?.Type == NodeConnectionType.Option };
new GUITextBlock(new RectTransform(Point.Zero, contextMenu.Content.RectTransform),
TextManager.Get("EventEditor.MarkEnding"), font: GUI.SmallFont) { UserData = "markend", Enabled = connection != null && connection.Type == NodeConnectionType.Option };
new GUITextBlock(new RectTransform(Point.Zero, contextMenu.Content.RectTransform),
TextManager.Get("EventEditor.RemoveConnection"), font: GUI.SmallFont) { UserData = "remcon", Enabled = connection != null };
new GUITextBlock(new RectTransform(Point.Zero, contextMenu.Content.RectTransform),
TextManager.Get("EventEditor.AddOption"), font: GUI.SmallFont) { UserData = "addoption", Enabled = node.CanAddConnections };
new GUITextBlock(new RectTransform(Point.Zero, contextMenu.Content.RectTransform),
TextManager.Get("EventEditor.RemoveOption"), font: GUI.SmallFont) { UserData = "removeoption", Enabled = connection != null && node.RemovableTypes.Contains(connection.Type) };
new GUITextBlock(new RectTransform(Point.Zero, contextMenu.Content.RectTransform),
TextManager.Get("EventEditor.Delete"), font: GUI.SmallFont) { UserData = "delete", Enabled = true };
foreach (var guiComponent in contextMenu.Content.Children)
{
if (guiComponent is GUITextBlock child)
GUIContextMenu.CreateContextMenu(
new ContextMenuOption("EventEditor.Edit", isEnabled: node is ValueNode || connection?.Type == NodeConnectionType.Value || connection?.Type == NodeConnectionType.Option, onSelected: delegate
{
if (!child.Enabled)
{
child.TextColor *= 0.5f;
}
}
}
foreach (GUIComponent c in contextMenu.Content.Children)
{
if (c is GUITextBlock block)
CreateEditMenu(node as ValueNode, connection);
}),
new ContextMenuOption("EventEditor.MarkEnding", isEnabled: connection != null && connection.Type == NodeConnectionType.Option, onSelected: delegate
{
block.RectTransform.NonScaledSize = new Point((int) (block.TextSize.X + block.Padding.X * 2), (int) (18 * GUI.Scale));
}
}
if (connection == null) { return; }
int biggestSize = contextMenu.Content.Children.Max(c => c.Rect.Width + (int) contextMenu.Padding.X * 2);
contextMenu.Content.Children.ForEach(c => c.RectTransform.MinSize = new Point(biggestSize, c.Rect.Height));
contextMenu.RectTransform.NonScaledSize = new Point(biggestSize, (int) (contextMenu.Content.Children.Sum(c => c.Rect.Height) + (contextMenu.Padding.X * 2)));
contextMenu.OnSelected = (component, obj) =>
{
if (!component.Enabled) { return false; }
switch (obj as string)
connection.EndConversation = !connection.EndConversation;
}),
new ContextMenuOption("EventEditor.RemoveConnection", isEnabled: connection != null, onSelected: delegate
{
case "edit":
CreateEditMenu(node as ValueNode, connection);
break;
case "markend" when connection != null:
connection.EndConversation = !connection.EndConversation;
break;
case "remcon" when connection != null:
connection.ClearConnections();
connection.OverrideValue = null;
connection.OptionText = connection.OptionText;
break;
case "addoption":
node.AddOption();
break;
case "removeoption":
connection?.Parent.RemoveOption(connection);
break;
case "delete":
nodeList.Remove(node);
node.ClearConnections();
if (connection == null) { return; }
break;
}
contextMenu = null;
return true;
};
connection.ClearConnections();
connection.OverrideValue = null;
connection.OptionText = connection.OptionText;
}),
new ContextMenuOption("EventEditor.AddOption", isEnabled: node.CanAddConnections, onSelected: node.AddOption),
new ContextMenuOption("EventEditor.RemoveOption", isEnabled: connection != null && node.RemovableTypes.Contains(connection.Type), onSelected: delegate
{
connection?.Parent.RemoveOption(connection);
}),
new ContextMenuOption("EventEditor.Delete", isEnabled: true, onSelected: delegate
{
nodeList.Remove(node);
node.ClearConnections();
}));
}
private bool CreateTestSetupMenu()
@@ -1141,16 +1094,6 @@ namespace Barotrauma
DraggingPosition = Vector2.Zero;
}
if (contextMenu != null)
{
Rectangle expandedRect = contextMenu.Rect;
expandedRect.Inflate(20, 20);
if (!expandedRect.Contains(PlayerInput.MousePosition))
{
contextMenu = null;
}
}
if (PlayerInput.MidButtonHeld())
{
Vector2 moveSpeed = PlayerInput.MouseSpeed * (float) deltaTime * 60.0f / Cam.Zoom;
@@ -77,9 +77,8 @@ namespace Barotrauma
}
if (Character.Controlled?.Inventory != null)
{
foreach (Item item in Character.Controlled.Inventory.Items)
foreach (Item item in Character.Controlled.Inventory.AllItems)
{
if (item == null) { continue; }
if (Character.Controlled.HasEquippedItem(item))
{
item.AddToGUIUpdateList();
@@ -249,6 +248,8 @@ namespace Barotrauma
}
spriteBatch.End();
Level.Loaded?.DrawFront(spriteBatch, cam);
//draw the rendertarget and particles that are only supposed to be drawn in water into renderTargetWater
graphics.SetRenderTarget(renderTargetWater);
@@ -317,10 +318,8 @@ namespace Barotrauma
{
c.DrawFront(spriteBatch, cam);
}
if (Level.Loaded != null)
{
Level.Loaded.DrawFront(spriteBatch, cam);
}
Level.Loaded?.DrawDebugOverlay(spriteBatch, cam);
if (GameMain.DebugDraw)
{
MapEntity.mapEntityList.ForEach(me => me.AiTarget?.Draw(spriteBatch));
@@ -374,7 +373,10 @@ namespace Barotrauma
{
BlurStrength = Character.Controlled.BlurStrength * 0.005f;
DistortStrength = Character.Controlled.DistortStrength;
chromaticAberrationStrength -= Vector3.One * Character.Controlled.RadialDistortStrength;
if (GameMain.Config.EnableRadialDistortion)
{
chromaticAberrationStrength -= Vector3.One * Character.Controlled.RadialDistortStrength;
}
chromaticAberrationStrength += new Vector3(-0.03f, -0.015f, 0.0f) * Character.Controlled.ChromaticAberrationStrength;
}
else
@@ -438,8 +440,8 @@ namespace Barotrauma
if (!PlayerInput.PrimaryMouseButtonHeld())
{
Inventory.draggingSlot = null;
Inventory.draggingItem = null;
Inventory.DraggingSlot = null;
Inventory.DraggingItems.Clear();
}
}
}
@@ -489,7 +489,7 @@ namespace Barotrauma
{
MinValueFloat = 0,
MaxValueFloat = 100,
FloatValue = caveGenerationParams.GetCommonness(selectedParams),
FloatValue = caveGenerationParams.GetCommonness(selectedParams, abyss: false),
OnValueChanged = (numberInput) =>
{
caveGenerationParams.OverrideCommonness[selectedParams.Identifier] = numberInput.FloatValue;
@@ -514,7 +514,7 @@ namespace Barotrauma
}
foreach (var caveParam in CaveGenerationParams.CaveParams)
{
if (selectedParams != null && caveParam.GetCommonness(selectedParams) <= 0.0f) { continue; }
if (selectedParams != null && caveParam.GetCommonness(selectedParams, abyss: false) <= 0.0f) { continue; }
availableIdentifiers.Add(caveParam.Identifier);
}
availableIdentifiers.Reverse();
@@ -714,8 +714,9 @@ namespace Barotrauma
if (Level.Loaded != null)
{
Level.Loaded.DrawBack(graphics, spriteBatch, cam);
spriteBatch.Begin(SpriteSortMode.BackToFront, BlendState.NonPremultiplied, SamplerState.LinearWrap, DepthStencilState.DepthRead, transformMatrix: cam.Transform);
Level.Loaded.DrawFront(spriteBatch, cam);
spriteBatch.Begin(SpriteSortMode.BackToFront, BlendState.NonPremultiplied, SamplerState.LinearWrap, DepthStencilState.DepthRead, transformMatrix: cam.Transform);
Level.Loaded.DrawDebugOverlay(spriteBatch, cam);
Submarine.Draw(spriteBatch, false);
Submarine.DrawFront(spriteBatch);
Submarine.DrawDamageable(spriteBatch, null);
@@ -810,6 +811,19 @@ namespace Barotrauma
GUI.DrawLine(spriteBatch, new Vector2(0, crushDepthScreen), new Vector2(GameMain.GraphicsWidth, crushDepthScreen), GUI.Style.Red * 0.25f, width: 5);
GUI.DrawString(spriteBatch, new Vector2(GameMain.GraphicsWidth / 2, crushDepthScreen), "Crush depth", GUI.Style.Red, backgroundColor: Color.Black);
}
float abyssStartScreen = cam.WorldToScreen(new Vector2(0.0f, Level.Loaded.AbyssArea.Bottom)).Y;
if (abyssStartScreen > 0.0f && abyssStartScreen < GameMain.GraphicsHeight)
{
GUI.DrawLine(spriteBatch, new Vector2(0, abyssStartScreen), new Vector2(GameMain.GraphicsWidth, abyssStartScreen), GUI.Style.Blue * 0.25f, width: 5);
GUI.DrawString(spriteBatch, new Vector2(GameMain.GraphicsWidth / 2, abyssStartScreen), "Abyss start", GUI.Style.Blue, backgroundColor: Color.Black);
}
float abyssEndScreen = cam.WorldToScreen(new Vector2(0.0f, Level.Loaded.AbyssArea.Y)).Y;
if (abyssEndScreen > 0.0f && abyssEndScreen < GameMain.GraphicsHeight)
{
GUI.DrawLine(spriteBatch, new Vector2(0, abyssEndScreen), new Vector2(GameMain.GraphicsWidth, abyssEndScreen), GUI.Style.Blue * 0.25f, width: 5);
GUI.DrawString(spriteBatch, new Vector2(GameMain.GraphicsWidth / 2, abyssEndScreen), "Abyss end", GUI.Style.Blue, backgroundColor: Color.Black);
}
}
GUI.Draw(Cam, spriteBatch);
spriteBatch.End();
@@ -817,6 +831,13 @@ namespace Barotrauma
public override void Update(double deltaTime)
{
if (lightingEnabled.Selected)
{
foreach (Item item in Item.ItemList)
{
item?.GetComponent<Items.Components.LightComponent>()?.Update((float)deltaTime, cam);
}
}
GameMain.LightManager?.Update((float)deltaTime);
pointerLightSource.Position = cam.ScreenToWorld(PlayerInput.MousePosition);
@@ -886,16 +907,16 @@ namespace Barotrauma
{
foreach (XElement subElement in element.Elements())
{
string id = element.GetAttributeString("identifier", null) ?? element.Name.ToString();
string id = subElement.GetAttributeString("identifier", null) ?? subElement.Name.ToString();
if (!id.Equals(genParams.Name, StringComparison.OrdinalIgnoreCase)) { continue; }
SerializableProperty.SerializeProperties(genParams, element, true);
genParams.Save(subElement);
}
}
else
{
string id = element.GetAttributeString("identifier", null) ?? element.Name.ToString();
if (!id.Equals(genParams.Name, StringComparison.OrdinalIgnoreCase)) { continue; }
SerializableProperty.SerializeProperties(genParams, element, true);
genParams.Save(element);
}
break;
}
@@ -679,7 +679,7 @@ namespace Barotrauma
}
#endregion
public void QuickStart(bool fixedSeed = false)
public void QuickStart(bool fixedSeed = false, string sub = null)
{
if (fixedSeed)
{
@@ -688,7 +688,7 @@ namespace Barotrauma
}
SubmarineInfo selectedSub = null;
string subName = GameMain.Config.QuickStartSubmarineName;
string subName = sub ?? GameMain.Config.QuickStartSubmarineName;
if (!string.IsNullOrEmpty(subName))
{
DebugConsole.NewMessage($"Loading the predefined quick start sub \"{subName}\"", Color.White);
@@ -709,7 +709,7 @@ namespace Barotrauma
var gamesession = new GameSession(
selectedSub,
GameModePreset.DevSandbox,
missionPrefab: null);
missionPrefabs: null);
//(gamesession.GameMode as SinglePlayerCampaign).GenerateMap(ToolBox.RandomSeed(8));
gamesession.StartRound(fixedSeed ? "abcd" : ToolBox.RandomSeed(8), difficulty: 40);
GameMain.GameScreen.Select();
@@ -834,6 +834,39 @@ namespace Barotrauma
return true;
}
private void TryStartServer()
{
if (SubmarineInfo.SavedSubmarines.Any(s => s.CalculatingHash))
{
var waitBox = new GUIMessageBox(TextManager.Get("pleasewait"), TextManager.Get("waitforsubmarinehashcalculations"), new string[] { TextManager.Get("cancel") });
var waitCoroutine = CoroutineManager.StartCoroutine(WaitForSubmarineHashCalculations(waitBox), "WaitForSubmarineHashCalculations");
waitBox.Buttons[0].OnClicked += (btn, userdata) =>
{
CoroutineManager.StopCoroutines(waitCoroutine);
return true;
};
}
else
{
StartServer();
}
}
private IEnumerable<object> WaitForSubmarineHashCalculations(GUIMessageBox messageBox)
{
string originalText = messageBox.Text.Text;
int doneCount = 0;
do
{
doneCount = SubmarineInfo.SavedSubmarines.Count(s => !s.CalculatingHash);
messageBox.Text.Text = originalText + $" ({doneCount}/{SubmarineInfo.SavedSubmarines.Count()})";
yield return CoroutineStatus.Running;
} while (doneCount < SubmarineInfo.SavedSubmarines.Count());
messageBox.Close();
StartServer();
yield return CoroutineStatus.Success;
}
private void StartServer()
{
string name = serverNameBox.Text;
@@ -1095,12 +1128,13 @@ namespace Barotrauma
StartNewGame = StartGame
};
var startButtonContainer = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.05f), innerNewGame.RectTransform, Anchor.Center), style: null);
var startButtonContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.05f), innerNewGame.RectTransform, Anchor.Center), isHorizontal: true, childAnchor: Anchor.BottomRight);
campaignSetupUI.StartButton.RectTransform.Parent = startButtonContainer.RectTransform;
campaignSetupUI.StartButton.RectTransform.MinSize = new Point(
(int)(campaignSetupUI.StartButton.TextBlock.TextSize.X * 1.5f),
campaignSetupUI.StartButton.RectTransform.MinSize.Y);
startButtonContainer.RectTransform.MinSize = new Point(0, campaignSetupUI.StartButton.RectTransform.MinSize.Y);
campaignSetupUI.InitialMoneyText.RectTransform.Parent = startButtonContainer.RectTransform;
}
private void CreateHostServerFields()
@@ -1340,7 +1374,7 @@ namespace Barotrauma
new string[] { TextManager.Get("yes"), TextManager.Get("no") });
msgBox.Buttons[0].OnClicked += (_, __) =>
{
StartServer();
TryStartServer();
msgBox.Close();
return true;
};
@@ -1348,7 +1382,7 @@ namespace Barotrauma
}
else
{
StartServer();
TryStartServer();
}
return true;
@@ -193,6 +193,12 @@ namespace Barotrauma
private set;
}
public GUIListBox TeamPreferenceListBox
{
get;
private set;
}
public GUIButton StartButton
{
get;
@@ -927,6 +933,7 @@ namespace Barotrauma
TextManager.Get("MissionType." + missionType.ToString()))
{
UserData = (int)missionType,
ToolTip = TextManager.Get("MissionTypeDescription." + missionType.ToString(), returnNull: true),
OnSelected = (tickbox) =>
{
int missionTypeOr = tickbox.Selected ? (int)tickbox.UserData : (int)MissionType.None;
@@ -1229,24 +1236,23 @@ namespace Barotrauma
{
tickBox.Enabled = GameMain.Client.HasPermission(ClientPermissions.ManageSettings);
}
traitorProbabilityButtons[0].Enabled = GameMain.Client.HasPermission(ClientPermissions.ManageSettings);
traitorProbabilityButtons[1].Enabled = GameMain.Client.HasPermission(ClientPermissions.ManageSettings);
botCountButtons[0].Enabled = GameMain.Client.HasPermission(ClientPermissions.ManageSettings);
botCountButtons[1].Enabled = GameMain.Client.HasPermission(ClientPermissions.ManageSettings);
botSpawnModeButtons[0].Enabled = GameMain.Client.HasPermission(ClientPermissions.ManageSettings);
botSpawnModeButtons[1].Enabled = GameMain.Client.HasPermission(ClientPermissions.ManageSettings);
levelDifficultyScrollBar.Enabled = GameMain.Client.HasPermission(ClientPermissions.ManageSettings);
SeedBox.Enabled = !CampaignFrame.Visible && !CampaignSetupFrame.Visible && GameMain.Client.HasPermission(ClientPermissions.ManageSettings);
levelDifficultyScrollBar.Enabled = !CampaignFrame.Visible && !CampaignSetupFrame.Visible && GameMain.Client.HasPermission(ClientPermissions.ManageSettings);
traitorProbabilityButtons[0].Enabled = traitorProbabilityButtons[1].Enabled = traitorProbabilityText.Enabled =
!CampaignFrame.Visible && !CampaignSetupFrame.Visible && GameMain.Client.HasPermission(ClientPermissions.ManageSettings);
botCountButtons[0].Enabled = botCountButtons[1].Enabled = GameMain.Client.HasPermission(ClientPermissions.ManageSettings);
botSpawnModeButtons[0].Enabled = botSpawnModeButtons[1].Enabled = GameMain.Client.HasPermission(ClientPermissions.ManageSettings);
autoRestartBox.Enabled = GameMain.Client.HasPermission(ClientPermissions.ManageSettings);
SeedBox.Enabled = GameMain.Client.HasPermission(ClientPermissions.ManageSettings);
SettingsButton.Visible = GameMain.Client.HasPermission(ClientPermissions.ManageSettings);
SettingsButton.OnClicked = GameMain.Client.ServerSettings.ToggleSettingsFrame;
StartButton.Visible = GameMain.Client.HasPermission(ClientPermissions.ManageRound) && !GameMain.Client.GameStarted && !CampaignSetupFrame.Visible && !CampaignFrame.Visible;
ServerName.Readonly = !GameMain.Client.HasPermission(ClientPermissions.ManageSettings);
ServerMessage.Readonly = !GameMain.Client.HasPermission(ClientPermissions.ManageSettings);
shuttleTickBox.Enabled = GameMain.Client.HasPermission(ClientPermissions.ManageSettings);
SubList.Enabled = !CampaignFrame.Visible && (GameMain.Client.ServerSettings.Voting.AllowSubVoting || GameMain.Client.HasPermission(ClientPermissions.SelectSub));
shuttleList.Enabled = shuttleTickBox.Enabled = !CampaignFrame.Visible && GameMain.Client.HasPermission(ClientPermissions.SelectSub);
shuttleTickBox.Enabled = !CampaignFrame.Visible && !CampaignSetupFrame.Visible && GameMain.Client.HasPermission(ClientPermissions.ManageSettings);
SubList.Enabled = !CampaignFrame.Visible && (GameMain.Client.ServerSettings.Voting.AllowSubVoting || GameMain.Client.HasPermission(ClientPermissions.SelectSub));
shuttleList.Enabled = shuttleList.ButtonEnabled = shuttleTickBox.Enabled = !CampaignFrame.Visible && !CampaignSetupFrame.Visible && GameMain.Client.HasPermission(ClientPermissions.SelectSub);
ModeList.Enabled = GameMain.Client.ServerSettings.Voting.AllowModeVoting || GameMain.Client.HasPermission(ClientPermissions.SelectMode);
LogButtons.Visible = GameMain.Client.HasPermission(ClientPermissions.ServerLog);
GameMain.Client.ShowLogButton.Visible = GameMain.Client.HasPermission(ClientPermissions.ServerLog);
@@ -1292,7 +1298,7 @@ namespace Barotrauma
public void CreatePlayerFrame(GUIComponent parent)
{
UpdatePlayerFrame(
playerInfoContainer.Children?.First().UserData as CharacterInfo,
Character.Controlled?.Info ?? playerInfoContainer.Children?.First().UserData as CharacterInfo,
allowEditing: campaignCharacterInfo == null,
parent: parent);
}
@@ -1372,9 +1378,9 @@ namespace Barotrauma
};
};
new GUICustomComponent(new RectTransform(new Vector2(0.6f, 0.18f), infoContainer.RectTransform, Anchor.TopCenter),
new GUICustomComponent(new RectTransform(new Vector2(0.6f, 0.16f), infoContainer.RectTransform, Anchor.TopCenter),
onDraw: (sb, component) => characterInfo.DrawIcon(sb, component.Rect.Center.ToVector2(), targetAreaSize: component.Rect.Size.ToVector2()));
if (allowEditing)
{
GUILayoutGroup characterInfoTabs = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.04f), infoContainer.RectTransform), isHorizontal: true)
@@ -1487,6 +1493,78 @@ namespace Barotrauma
}
};
}
TeamPreferenceListBox = null;
if (SelectedMode == GameModePreset.PvP)
{
TeamPreferenceListBox = new GUIListBox(new RectTransform(new Vector2(1.0f, 0.04f), infoContainer.RectTransform, anchor: Anchor.TopLeft, pivot: Pivot.TopLeft), isHorizontal: true, style: null)
{
Enabled = true,
KeepSpaceForScrollBar = false,
ScrollBarEnabled = false,
ScrollBarVisible = false
};
TeamPreferenceListBox.UpdateDimensions();
Color team1Color = new Color(0, 110, 150, 255);
var team1Option = new GUITextBlock(new RectTransform(new Vector2(0.3f, 1.0f), TeamPreferenceListBox.Content.RectTransform), TextManager.Get("teampreference.team1"), textAlignment: Alignment.Center, style: null)
{
UserData = CharacterTeamType.Team1,
CanBeFocused = true,
Padding = Vector4.One * 10.0f * GUI.Scale,
Color = Color.Lerp(team1Color, Color.Black, 0.7f) * 0.7f,
HoverColor = team1Color * 0.95f,
SelectedColor = team1Color * 0.8f,
OutlineColor = team1Color,
TextColor = Color.White,
HoverTextColor = Color.White,
SelectedTextColor = Color.White
};
Color noPreferenceColor = new Color(100, 100, 100, 255);
var noPreferenceOption = new GUITextBlock(new RectTransform(new Vector2(0.4f, 1.0f), TeamPreferenceListBox.Content.RectTransform), TextManager.Get("teampreference.nopreference"), textAlignment: Alignment.Center, style: null)
{
UserData = CharacterTeamType.None,
CanBeFocused = true,
Padding = Vector4.One * 10.0f * GUI.Scale,
Color = Color.Lerp(noPreferenceColor, Color.Black, 0.7f) * 0.7f,
HoverColor = noPreferenceColor * 0.95f,
SelectedColor = noPreferenceColor * 0.8f,
OutlineColor = noPreferenceColor,
TextColor = Color.White,
HoverTextColor = Color.White,
SelectedTextColor = Color.White
};
Color team2Color = new Color(150, 110, 0, 255);
var team2Option = new GUITextBlock(new RectTransform(new Vector2(0.3f, 1.0f), TeamPreferenceListBox.Content.RectTransform), TextManager.Get("teampreference.team2"), textAlignment: Alignment.Center, style: null)
{
UserData = CharacterTeamType.Team2,
CanBeFocused = true,
Padding = Vector4.One * 10.0f * GUI.Scale,
Color = Color.Lerp(team2Color, Color.Black, 0.7f) * 0.7f,
HoverColor = team2Color * 0.95f,
SelectedColor = team2Color * 0.8f,
OutlineColor = team2Color,
TextColor = Color.White,
HoverTextColor = Color.White,
SelectedTextColor = Color.White
};
TeamPreferenceListBox.Select(GameMain.Config.TeamPreference);
TeamPreferenceListBox.OnSelected += (component, obj) =>
{
if ((CharacterTeamType)obj == GameMain.Config.TeamPreference) { return true; }
GameMain.Config.TeamPreference = (CharacterTeamType)obj;
GameMain.Client.ForceNameAndJobUpdate();
GameMain.Config.SaveNewPlayerConfig();
return true;
};
}
}
private void CreateChangesPendingText()
@@ -1748,6 +1826,15 @@ namespace Barotrauma
}
GameMain.Client.RequestSelectMode(component.Parent.GetChildIndex(component));
HighlightMode(SelectedModeIndex);
if (presetName.Equals("multiplayercampaign", StringComparison.OrdinalIgnoreCase))
{
GUI.SetCursorWaiting(endCondition: () =>
{
return CampaignFrame.Visible || CampaignSetupFrame.Visible;
});
}
return !presetName.Equals("multiplayercampaign", StringComparison.OrdinalIgnoreCase);
}
return false;
@@ -1818,7 +1905,19 @@ namespace Barotrauma
playerFrame.Text = client.Name;
Color color = Color.White;
if (JobPrefab.Prefabs.ContainsKey(client.PreferredJob))
if (SelectedMode == GameModePreset.PvP)
{
switch (client.PreferredTeam)
{
case CharacterTeamType.Team1:
color = new Color(0, 110, 150, 255);
break;
case CharacterTeamType.Team2:
color = new Color(150, 110, 0, 255);
break;
}
}
else if (JobPrefab.Prefabs.ContainsKey(client.PreferredJob))
{
color = JobPrefab.Prefabs[client.PreferredJob].UIColor;
}
@@ -2103,42 +2202,44 @@ namespace Barotrauma
rangebanButton.OnClicked += ClosePlayerFrame;
}
if (GameMain.Client != null && GameMain.Client.ServerSettings.Voting.AllowVoteKick &&
selectedClient != null && selectedClient.AllowKicking)
if (GameMain.Client != null && GameMain.Client.ConnectedClients.Contains(selectedClient))
{
var kickVoteButton = new GUIButton(new RectTransform(new Vector2(0.34f, 1.0f), buttonAreaLower.RectTransform),
TextManager.Get("VoteToKick"))
if (GameMain.Client.ServerSettings.Voting.AllowVoteKick &&
selectedClient != null && selectedClient.AllowKicking)
{
Enabled = !selectedClient.HasKickVoteFromID(GameMain.Client.ID),
OnClicked = (btn, userdata) => { GameMain.Client.VoteForKick(selectedClient); btn.Enabled = false; return true; },
UserData = selectedClient
};
}
var kickVoteButton = new GUIButton(new RectTransform(new Vector2(0.34f, 1.0f), buttonAreaLower.RectTransform),
TextManager.Get("VoteToKick"))
{
Enabled = !selectedClient.HasKickVoteFromID(GameMain.Client.ID),
OnClicked = (btn, userdata) => { GameMain.Client.VoteForKick(selectedClient); btn.Enabled = false; return true; },
UserData = selectedClient
};
}
if (GameMain.Client.HasPermission(ClientPermissions.Kick) &&
selectedClient != null && selectedClient.AllowKicking)
{
var kickButton = new GUIButton(new RectTransform(new Vector2(0.34f, 1.0f), buttonAreaLower.RectTransform),
TextManager.Get("Kick"))
if (GameMain.Client.HasPermission(ClientPermissions.Kick) &&
selectedClient != null && selectedClient.AllowKicking)
{
UserData = selectedClient
var kickButton = new GUIButton(new RectTransform(new Vector2(0.34f, 1.0f), buttonAreaLower.RectTransform),
TextManager.Get("Kick"))
{
UserData = selectedClient
};
kickButton.OnClicked = (bt, userdata) => { KickPlayer(selectedClient); return true; };
kickButton.OnClicked += ClosePlayerFrame;
}
new GUITickBox(new RectTransform(new Vector2(0.175f, 1.0f), headerContainer.RectTransform, Anchor.TopRight),
TextManager.Get("Mute"))
{
Selected = selectedClient.MutedLocally,
OnSelected = (tickBox) => { selectedClient.MutedLocally = tickBox.Selected; return true; }
};
kickButton.OnClicked = (bt, userdata) => { KickPlayer(selectedClient); return true; };
kickButton.OnClicked += ClosePlayerFrame;
}
if (buttonAreaTop.CountChildren > 0)
{
GUITextBlock.AutoScaleAndNormalize(buttonAreaTop.Children.Select(c => ((GUIButton)c).TextBlock).Concat(buttonAreaLower.Children.Select(c => ((GUIButton)c).TextBlock)));
}
new GUITickBox(new RectTransform(new Vector2(0.175f, 1.0f), headerContainer.RectTransform, Anchor.TopRight),
TextManager.Get("Mute"))
{
Selected = selectedClient.MutedLocally,
OnSelected = (tickBox) => { selectedClient.MutedLocally = tickBox.Selected; return true; }
};
}
if (selectedClient.SteamID != 0 && Steam.SteamManager.IsInitialized)
@@ -2982,16 +3083,25 @@ namespace Barotrauma
{
ToggleCampaignMode(false);
}
var prevMode = modeList.Content.GetChild(selectedModeIndex).UserData as GameModePreset;
if ((HighlightedModeIndex == selectedModeIndex || HighlightedModeIndex < 0) && modeList.SelectedIndex != modeIndex) { modeList.Select(modeIndex, true); }
selectedModeIndex = modeIndex;
if ((prevMode == GameModePreset.PvP) != (SelectedMode == GameModePreset.PvP))
{
UpdatePlayerFrame(null);
GameMain.Client.ConnectedClients.ForEach(c => SetPlayerNameAndJobPreference(c));
}
if (SelectedMode != GameModePreset.MultiPlayerCampaign && GameMain.GameSession?.GameMode is CampaignMode && Selected == this)
{
GameMain.GameSession = null;
}
RefreshGameModeContent();
RefreshEnabledElements();
}
public void HighlightMode(int modeIndex)
@@ -3000,6 +3110,7 @@ namespace Barotrauma
HighlightedModeIndex = modeIndex;
RefreshGameModeContent();
RefreshEnabledElements();
}
private void RefreshMissionTypes()
@@ -3046,7 +3157,13 @@ namespace Barotrauma
else
{
CampaignFrame.Visible = false;
CampaignSetupFrame.Visible = GameMain.Client.HasPermission(ClientPermissions.ManageCampaign);
CampaignSetupFrame.Visible = true;
if (!GameMain.Client.HasPermission(ClientPermissions.ManageCampaign))
{
CampaignSetupFrame.ClearChildren();
new GUITextBlock(new RectTransform(new Vector2(0.8f, 0.5f), CampaignSetupFrame.RectTransform, Anchor.Center),
TextManager.Get("campaignstarting"), font: GUI.SubHeadingFont, textAlignment: Alignment.Center, wrap: true);
}
}
}
else
@@ -151,8 +151,9 @@ namespace Barotrauma
private GUITickBox filterTraitor;
private GUITickBox filterModded;
private GUITickBox filterVoip;
private List<GUITickBox> playStyleTickBoxes;
private List<GUITickBox> gameModeTickBoxes;
private Dictionary<string, GUITickBox> filterTickBoxes;
private Dictionary<string, GUITickBox> playStyleTickBoxes;
private Dictionary<string, GUITickBox> gameModeTickBoxes;
private GUITickBox filterOffensive;
private string sortedBy;
@@ -322,7 +323,7 @@ namespace Barotrauma
};
filterToggle.Children.ForEach(c => c.SpriteEffects = SpriteEffects.FlipHorizontally);
List<GUITextBlock> filterTextList = new List<GUITextBlock>();
filterTickBoxes = new Dictionary<string, GUITickBox>();
filterSameVersion = new GUITickBox(new RectTransform(new Vector2(1.0f, elementHeight), filters.Content.RectTransform), TextManager.Get("FilterSameVersion"))
{
@@ -330,42 +331,42 @@ namespace Barotrauma
Selected = true,
OnSelected = (tickBox) => { FilterServers(); return true; }
};
filterTextList.Add(filterSameVersion.TextBlock);
filterTickBoxes.Add("FilterSameVersion", filterSameVersion);
filterPassword = new GUITickBox(new RectTransform(new Vector2(1.0f, elementHeight), filters.Content.RectTransform), TextManager.Get("FilterPassword"))
{
UserData = TextManager.Get("FilterPassword"),
OnSelected = (tickBox) => { FilterServers(); return true; }
};
filterTextList.Add(filterPassword.TextBlock);
filterTickBoxes.Add("FilterPassword", filterPassword);
filterIncompatible = new GUITickBox(new RectTransform(new Vector2(1.0f, elementHeight), filters.Content.RectTransform), TextManager.Get("FilterIncompatibleServers"))
{
UserData = TextManager.Get("FilterIncompatibleServers"),
OnSelected = (tickBox) => { FilterServers(); return true; }
};
filterTextList.Add(filterIncompatible.TextBlock);
filterTickBoxes.Add("FilterIncompatibleServers", filterIncompatible);
filterFull = new GUITickBox(new RectTransform(new Vector2(1.0f, elementHeight), filters.Content.RectTransform), TextManager.Get("FilterFullServers"))
{
UserData = TextManager.Get("FilterFullServers"),
OnSelected = (tickBox) => { FilterServers(); return true; }
};
filterTextList.Add(filterFull.TextBlock);
filterTickBoxes.Add("FilterFullServers", filterFull);
filterEmpty = new GUITickBox(new RectTransform(new Vector2(1.0f, elementHeight), filters.Content.RectTransform), TextManager.Get("FilterEmptyServers"))
{
UserData = TextManager.Get("FilterEmptyServers"),
OnSelected = (tickBox) => { FilterServers(); return true; }
};
filterTextList.Add(filterEmpty.TextBlock);
filterTickBoxes.Add("FilterEmptyServers", filterEmpty);
filterWhitelisted = new GUITickBox(new RectTransform(new Vector2(1.0f, elementHeight), filters.Content.RectTransform), TextManager.Get("FilterWhitelistedServers"))
{
UserData = TextManager.Get("FilterWhitelistedServers"),
OnSelected = (tickBox) => { FilterServers(); return true; }
};
filterTextList.Add(filterWhitelisted.TextBlock);
filterTickBoxes.Add("FilterWhitelistedServers", filterWhitelisted);
filterOffensive = new GUITickBox(new RectTransform(new Vector2(1.0f, elementHeight), filters.Content.RectTransform), TextManager.Get("FilterOffensiveServers"))
{
@@ -373,7 +374,7 @@ namespace Barotrauma
ToolTip = TextManager.Get("FilterOffensiveServersToolTip"),
OnSelected = (tickBox) => { FilterServers(); return true; }
};
filterTextList.Add(filterOffensive.TextBlock);
filterTickBoxes.Add("FilterOffensiveServers", filterOffensive);
// Filter Tags
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), filters.Content.RectTransform), TextManager.Get("servertags"), font: GUI.SubHeadingFont)
@@ -386,35 +387,35 @@ namespace Barotrauma
UserData = TextManager.Get("servertag.karma.true"),
OnSelected = (tickBox) => { FilterServers(); return true; }
};
filterTextList.Add(filterKarma.TextBlock);
filterTickBoxes.Add("servertag.karma", filterKarma);
filterTraitor = new GUITickBox(new RectTransform(new Vector2(1.0f, elementHeight), filters.Content.RectTransform), TextManager.Get("servertag.traitors.true"))
{
UserData = TextManager.Get("servertag.traitors.true"),
OnSelected = (tickBox) => { FilterServers(); return true; }
};
filterTextList.Add(filterTraitor.TextBlock);
filterTickBoxes.Add("servertag.traitors", filterTraitor);
filterFriendlyFire = new GUITickBox(new RectTransform(new Vector2(1.0f, elementHeight), filters.Content.RectTransform), TextManager.Get("servertag.friendlyfire.false"))
{
UserData = TextManager.Get("servertag.friendlyfire.false"),
OnSelected = (tickBox) => { FilterServers(); return true; }
};
filterTextList.Add(filterFriendlyFire.TextBlock);
filterTickBoxes.Add("servertag.friendlyfire", filterFriendlyFire);
filterVoip = new GUITickBox(new RectTransform(new Vector2(1.0f, elementHeight), filters.Content.RectTransform), TextManager.Get("servertag.voip.false"))
{
UserData = TextManager.Get("servertag.voip.false"),
OnSelected = (tickBox) => { FilterServers(); return true; }
};
filterTextList.Add(filterVoip.TextBlock);
filterTickBoxes.Add("servertag.voip", filterVoip);
filterModded = new GUITickBox(new RectTransform(new Vector2(1.0f, elementHeight), filters.Content.RectTransform), TextManager.Get("servertag.modded.true"))
{
UserData = TextManager.Get("servertag.modded.true"),
OnSelected = (tickBox) => { FilterServers(); return true; }
};
filterTextList.Add(filterModded.TextBlock);
filterTickBoxes.Add("servertag.modded", filterModded);
// Play Style Selection
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), filters.Content.RectTransform), TextManager.Get("ServerSettingsPlayStyle"), font: GUI.SubHeadingFont)
@@ -422,7 +423,7 @@ namespace Barotrauma
CanBeFocused = false
};
playStyleTickBoxes = new List<GUITickBox>();
playStyleTickBoxes = new Dictionary<string, GUITickBox>();
foreach (PlayStyle playStyle in Enum.GetValues(typeof(PlayStyle)))
{
var selectionTick = new GUITickBox(new RectTransform(new Vector2(1.0f, elementHeight), filters.Content.RectTransform), TextManager.Get("servertag." + playStyle))
@@ -432,14 +433,14 @@ namespace Barotrauma
OnSelected = (tickBox) => { FilterServers(); return true; },
UserData = playStyle
};
playStyleTickBoxes.Add(selectionTick);
filterTextList.Add(selectionTick.TextBlock);
playStyleTickBoxes.Add("servertag." + playStyle, selectionTick);
filterTickBoxes.Add("servertag." + playStyle, selectionTick);
}
// Game mode Selection
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), filters.Content.RectTransform), TextManager.Get("gamemode"), font: GUI.SubHeadingFont) { CanBeFocused = false };
gameModeTickBoxes = new List<GUITickBox>();
gameModeTickBoxes = new Dictionary<string, GUITickBox>();
foreach (GameModePreset mode in GameModePreset.List)
{
if (mode.IsSinglePlayer) continue;
@@ -451,21 +452,21 @@ namespace Barotrauma
OnSelected = (tickBox) => { FilterServers(); return true; },
UserData = mode.Identifier
};
gameModeTickBoxes.Add(selectionTick);
filterTextList.Add(selectionTick.TextBlock);
gameModeTickBoxes.Add(mode.Identifier, selectionTick);
filterTickBoxes.Add(mode.Identifier, selectionTick);
}
filters.Content.RectTransform.SizeChanged += () =>
{
filters.Content.RectTransform.RecalculateChildren(true, true);
filterTextList.ForEach(t => t.Text = t.Parent.Parent.UserData as string);
gameModeTickBoxes.ForEach(tb => tb.Text = tb.ToolTip);
playStyleTickBoxes.ForEach(tb => tb.Text = tb.ToolTip);
GUITextBlock.AutoScaleAndNormalize(filterTextList, defaultScale: 1.0f);
if (filterTextList[0].TextScale < 0.8f)
filterTickBoxes.ForEach(t => t.Value.Text = t.Value.UserData as string);
gameModeTickBoxes.ForEach(tb => tb.Value.Text = tb.Value.ToolTip);
playStyleTickBoxes.ForEach(tb => tb.Value.Text = tb.Value.ToolTip);
GUITextBlock.AutoScaleAndNormalize(filterTickBoxes.Values.Select(tb => tb.TextBlock), defaultScale: 1.0f);
if (filterTickBoxes.Values.First().TextBlock.TextScale < 0.8f)
{
filterTextList.ForEach(t => t.TextScale = 1.0f);
filterTextList.ForEach(t => t.Text = ToolBox.LimitString(t.Text, t.Font, (int)(filters.Content.Rect.Width * 0.8f)));
filterTickBoxes.ForEach(t => t.Value.TextBlock.TextScale = 1.0f);
filterTickBoxes.ForEach(t => t.Value.TextBlock.Text = ToolBox.LimitString(t.Value.TextBlock.Text, t.Value.TextBlock.Font, (int)(filters.Content.Rect.Width * 0.8f)));
}
};
@@ -696,6 +697,7 @@ namespace Barotrauma
private void ReadServerMemFromFile(string file, ref List<ServerInfo> servers)
{
if (servers == null) { servers = new List<ServerInfo>(); }
servers.Clear();
if (!File.Exists(file)) { return; }
@@ -716,11 +718,21 @@ namespace Barotrauma
return;
}
bool saveCleanup = false;
foreach (XElement element in doc.Root.Elements())
{
if (element.Name != "ServerInfo") { continue; }
servers.Add(ServerInfo.FromXElement(element));
var info = ServerInfo.FromXElement(element);
if (!servers.Any(s => s.Equals(info)))
{
servers.Add(info);
}
else
{
saveCleanup = true;
}
}
if (saveCleanup) { WriteServerMemToFile(file, servers); }
}
private void WriteServerMemToFile(string file, List<ServerInfo> servers)
@@ -948,6 +960,19 @@ namespace Barotrauma
{
base.Select();
SelectedTab = ServerListTab.All;
LoadServerFilters(GameMain.Config.ServerFilterElement);
if (GameSettings.ShowOffensiveServerPrompt)
{
var filterOffensivePrompt = new GUIMessageBox(string.Empty, TextManager.Get("filteroffensiveserversprompt"), new string[] { TextManager.Get("yes"), TextManager.Get("no") });
filterOffensivePrompt.Buttons[0].OnClicked = (btn, userData) =>
{
filterOffensive.Selected = true;
filterOffensivePrompt.Close();
return true;
};
filterOffensivePrompt.Buttons[1].OnClicked = filterOffensivePrompt.Close;
GameSettings.ShowOffensiveServerPrompt = false;
}
Steamworks.SteamMatchmaking.ResetActions();
@@ -964,6 +989,8 @@ namespace Barotrauma
{
base.Deselect();
GameMain.Config.SaveNewPlayerConfig();
pendingWorkshopDownloads?.Clear();
workshopDownloadsFrame = null;
}
@@ -1072,10 +1099,9 @@ namespace Barotrauma
(selectedTab == ServerListTab.Favorites && serverInfo.Favorite));
}
foreach (GUITickBox tickBox in playStyleTickBoxes)
foreach (GUITickBox tickBox in playStyleTickBoxes.Values)
{
var playStyle = (PlayStyle)tickBox.UserData;
if (!tickBox.Selected && (serverInfo.PlayStyle == playStyle || !serverInfo.PlayStyle.HasValue))
{
child.Visible = false;
@@ -1083,7 +1109,7 @@ namespace Barotrauma
}
}
foreach (GUITickBox tickBox in gameModeTickBoxes)
foreach (GUITickBox tickBox in gameModeTickBoxes.Values)
{
var gameMode = (string)tickBox.UserData;
if (!tickBox.Selected && serverInfo.GameMode != null && serverInfo.GameMode.Equals(gameMode, StringComparison.OrdinalIgnoreCase))
@@ -1259,20 +1285,50 @@ namespace Barotrauma
if (info.InServer)
{
int framePadding = 5;
friendPopup = new GUIFrame(new RectTransform(Vector2.One, GUI.Canvas));
var serverNameText = new GUITextBlock(new RectTransform(new Vector2(0.7f, 1.0f), friendPopup.RectTransform), info.ConnectName ?? "[Unnamed]");
var joinButton = new GUIButton(new RectTransform(new Vector2(0.3f, 1.0f), friendPopup.RectTransform, Anchor.TopRight), TextManager.Get("ServerListJoin"))
var serverNameText = new GUITextBlock(new RectTransform(new Vector2(0.7f, 1.0f), friendPopup.RectTransform, Anchor.CenterLeft), info.ConnectName ?? "[Unnamed]");
serverNameText.RectTransform.AbsoluteOffset = new Point(framePadding, 0);
var joinButton = new GUIButton(new RectTransform(new Vector2(0.3f, 1.0f), friendPopup.RectTransform, Anchor.CenterRight), TextManager.Get("ServerListJoin"))
{
UserData = info
};
joinButton.OnClicked = JoinFriend;
joinButton.RectTransform.AbsoluteOffset = new Point(framePadding, 0);
Vector2 frameDims = joinButton.Font.MeasureString(info.ConnectName ?? "[Unnamed]");
frameDims.X /= 0.6f;
frameDims.Y *= 1.5f;
friendPopup.RectTransform.NonScaledSize = frameDims.ToPoint();
Point joinButtonTextSize = joinButton.Font.MeasureString(joinButton.Text).ToPoint();
int joinButtonHeight = joinButton.RectTransform.NonScaledSize.Y;
int totalAdditionalTextPadding = (joinButtonHeight - joinButtonTextSize.Y);
// Make the final button sized so that the space between the text and the edges in the X direction is the same as the Y direction.
Point finalButtonSize = new Point(joinButtonTextSize.X + totalAdditionalTextPadding, joinButtonHeight);
// Add padding to the server name to match the padding on the button text.
serverNameText.Padding = new Vector4(totalAdditionalTextPadding / 2);
// Get the dimensions of the text we want to show, plus the extra padding we added.
Point serverNameSize = serverNameText.Font.MeasureString(serverNameText.Text).ToPoint() + new Point(totalAdditionalTextPadding, totalAdditionalTextPadding);
// Now determine how large the parent frame has to be to exactly fit our two controls.
Point frameDims = new Point(serverNameSize.X + finalButtonSize.X + framePadding*2, Math.Max(serverNameSize.Y, finalButtonSize.Y) + framePadding * 2);
var popupPos = PlayerInput.MousePosition.ToPoint();
if(popupPos.X+frameDims.X > GUI.Canvas.NonScaledSize.X)
{
// Prevent the Join button from going off the end of the screen if the server name is long or we click a user towards the edge.
popupPos.X = GUI.Canvas.NonScaledSize.X - frameDims.X;
}
// Apply the size and position changes.
friendPopup.RectTransform.NonScaledSize = frameDims;
friendPopup.RectTransform.RelativeOffset = Vector2.Zero;
friendPopup.RectTransform.AbsoluteOffset = PlayerInput.MousePosition.ToPoint();
friendPopup.RectTransform.AbsoluteOffset = popupPos;
joinButton.RectTransform.NonScaledSize = finalButtonSize;
friendPopup.RectTransform.RecalculateChildren(true);
friendPopup.RectTransform.SetPosition(Anchor.TopLeft);
}
@@ -2266,13 +2322,29 @@ namespace Barotrauma
public override void AddToGUIUpdateList()
{
menu.AddToGUIUpdateList();
friendPopup?.AddToGUIUpdateList();
friendsDropdown?.AddToGUIUpdateList();
workshopDownloadsFrame?.AddToGUIUpdateList();
}
public void SaveServerFilters(XElement element)
{
element.RemoveAttributes();
foreach (KeyValuePair<string, GUITickBox> filterBox in filterTickBoxes)
{
element.Add(new XAttribute(filterBox.Key, filterBox.Value.Selected.ToString()));
}
}
public void LoadServerFilters(XElement element)
{
if (element == null) { return; }
foreach (KeyValuePair<string, GUITickBox> filterBox in filterTickBoxes)
{
filterBox.Value.Selected = element.GetAttributeBool(filterBox.Key, filterBox.Value.Selected);
}
}
}
}
@@ -351,28 +351,48 @@ namespace Barotrauma
void LoadSprites(XElement element)
{
element.Elements("sprite").ForEach(s => CreateSprite(s));
element.Elements("Sprite").ForEach(s => CreateSprite(s));
element.Elements("backgroundsprite").ForEach(s => CreateSprite(s));
element.Elements("BackgroundSprite").ForEach(s => CreateSprite(s));
element.Elements("brokensprite").ForEach(s => CreateSprite(s));
element.Elements("BrokenSprite").ForEach(s => CreateSprite(s));
element.Elements("containedsprite").ForEach(s => CreateSprite(s));
element.Elements("ContainedSprite").ForEach(s => CreateSprite(s));
element.Elements("inventoryicon").ForEach(s => CreateSprite(s));
element.Elements("InventoryIcon").ForEach(s => CreateSprite(s));
element.Elements("icon").ForEach(s => CreateSprite(s));
element.Elements("Icon").ForEach(s => CreateSprite(s));
//decorativesprites don't necessarily have textures (can be used to hide/disable other sprites)
element.Elements("decorativesprite").ForEach(s => { if (s.Attribute("texture") != null) CreateSprite(s); });
element.Elements("DecorativeSprite").ForEach(s => { if (s.Attribute("texture") != null) CreateSprite(s); });
string[] spriteElementNames = new string[]
{
"Sprite",
"DeformableSprite",
"BackgroundSprite",
"BrokenSprite",
"ContainedSprite",
"InventoryIcon",
"Icon",
"VineSprite",
"LeafSprite",
"FlowerSprite",
"DecorativeSprite"
};
foreach (string spriteElementName in spriteElementNames)
{
element.Elements(spriteElementName).ForEach(s => CreateSprite(s));
element.Elements(spriteElementName.ToLowerInvariant()).ForEach(s => CreateSprite(s));
}
element.Elements().ForEach(e => LoadSprites(e));
}
void CreateSprite(XElement element)
{
string spriteFolder = "";
string textureElement = element.GetAttributeString("texture", "");
string textureElement = "";
if (element.Attribute("texture") != null)
{
textureElement = element.GetAttributeString("texture", "");
}
else
{
if (element.Name.ToString().ToLower() == "vinesprite")
{
textureElement = element.Parent.GetAttributeString("vineatlas", "");
}
}
if (string.IsNullOrEmpty(textureElement)) { return; }
// TODO: parse and create?
if (textureElement.Contains("[GENDER]") || textureElement.Contains("[HEADID]") || textureElement.Contains("[RACE]") || textureElement.Contains("[VARIANT]")) { return; }
if (!textureElement.Contains("/"))
@@ -386,7 +406,7 @@ namespace Barotrauma
//{
// loadedSprites.Add(new Sprite(element, spriteFolder));
//}
loadedSprites.Add(new Sprite(element, spriteFolder));
loadedSprites.Add(new Sprite(element, spriteFolder, textureElement));
}
}
File diff suppressed because it is too large Load Diff