diff --git a/Content.Client/FurryServers/FurryServersWindow.xaml b/Content.Client/FurryServers/FurryServersWindow.xaml
new file mode 100644
index 00000000000..1fb63a9281d
--- /dev/null
+++ b/Content.Client/FurryServers/FurryServersWindow.xaml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/Content.Client/FurryServers/FurryServersWindow.xaml.cs b/Content.Client/FurryServers/FurryServersWindow.xaml.cs
new file mode 100644
index 00000000000..29db69f967f
--- /dev/null
+++ b/Content.Client/FurryServers/FurryServersWindow.xaml.cs
@@ -0,0 +1,59 @@
+using System.Linq;
+using Content.Client.Administration.Managers;
+using Content.Client.Stylesheets;
+using Content.Client.UserInterface.Controls;
+using Content.Client.UserInterface.Systems.EscapeMenu;
+using Content.Shared.Administration;
+using JetBrains.Annotations;
+using Robust.Client.AutoGenerated;
+using Robust.Client.UserInterface;
+using Robust.Client.UserInterface.XAML;
+using Robust.Shared.Console;
+using Robust.Client.ResourceManagement;
+using Robust.Shared.Utility;
+
+namespace Content.Client.FurryServers
+{
+ [GenerateTypedNameReferences]
+ public sealed partial class FurryServersWindow : FancyWindow
+ {
+ [Dependency] private readonly IResourceCache _resourceManager = default!;
+ [Dependency] private readonly IUriOpener _uri = default!;
+
+ public FurryServersWindow()
+ {
+ RobustXamlLoader.Load(this);
+ IoCManager.InjectDependencies(this);
+ Stylesheet = IoCManager.Resolve().SheetSpace;
+
+ BlepstationHeader.AddStyleClass(StyleBase.StyleClassLabelHeading);
+ BlepstationHeader.FontColorOverride = Color.FromHex("#7687f2");
+
+ var description = FormattedMessage.FromMarkup(_resourceManager.ContentFileReadAllText($"/FurryServers/Blepstation.txt"));
+ BlepstationDescription.SetMessage(description);
+
+ BlepstationWebsite.OnPressed += _ =>
+ {
+ _uri.OpenUri("https://blepstation.com");
+ };
+ }
+
+ protected override void Opened()
+ {
+ base.Opened();
+ }
+ }
+
+ [UsedImplicitly, AnyCommand]
+ public sealed class FurryServersCommand : IConsoleCommand
+ {
+ public string Command => "furry";
+ public string Description => "Shows list of furry space station 14 servers";
+ public string Help => "Usage: furry";
+
+ public void Execute(IConsoleShell shell, string argStr, string[] args)
+ {
+ IoCManager.Resolve().GetUIController().OpenWindow();
+ }
+ }
+}
diff --git a/Content.Client/Info/LinkBanner.cs b/Content.Client/Info/LinkBanner.cs
index a30aa413761..6f83fe9b5f9 100644
--- a/Content.Client/Info/LinkBanner.cs
+++ b/Content.Client/Info/LinkBanner.cs
@@ -43,6 +43,10 @@ public LinkBanner()
};
buttons.AddChild(guidebookButton);
+ var furryServersButton = new Button() { Text = "More Furry Servers" };
+ furryServersButton.OnPressed += args => UserInterfaceManager.GetUIController().ToggleWindow();
+ buttons.AddChild(furryServersButton);
+
var changelogButton = new ChangelogButton();
changelogButton.OnPressed += args => UserInterfaceManager.GetUIController().ToggleWindow();
buttons.AddChild(changelogButton);
diff --git a/Content.Client/MainMenu/MainMenu.cs b/Content.Client/MainMenu/MainMenu.cs
index 43c5bfe5674..9c73af11583 100644
--- a/Content.Client/MainMenu/MainMenu.cs
+++ b/Content.Client/MainMenu/MainMenu.cs
@@ -10,6 +10,7 @@
using Robust.Shared.Network;
using Robust.Shared.Utility;
using UsernameHelpers = Robust.Shared.AuthLib.UsernameHelpers;
+using Content.Client.UserInterface.Systems.WhitelistWindow;
namespace Content.Client.MainMenu
{
@@ -176,7 +177,18 @@ private void ParseAddress(string address, out string ip, out ushort port)
private void _onConnectFailed(object? _, NetConnectFailArgs args)
{
- _userInterfaceManager.Popup(Loc.GetString("main-menu-failed-to-connect",("reason", args.Reason)));
+ // This assumes whitelist related disconnect will contain the text 'whitelist' which is probably a fair
+ // assumption. More ideally, disconnect reasons would send across an enum or something, but that looks to
+ // be in engine code, perhaps.
+ if (args.Reason.ToUpper().Contains("WHITELIST"))
+ {
+ // Whitelist specialized popup that shows application link for the whitelist
+ _userInterfaceManager.GetUIController().OpenWindow(args.Reason);
+ } else {
+ // Generic popup
+ _userInterfaceManager.Popup(Loc.GetString("main-menu-failed-to-connect",("reason", args.Reason)));
+ }
+
_netManager.ConnectFailed -= _onConnectFailed;
_setConnectingState(false);
}
diff --git a/Content.Client/Options/UI/EscapeMenu.xaml b/Content.Client/Options/UI/EscapeMenu.xaml
index 71da231f29b..f93b1a2ecd6 100644
--- a/Content.Client/Options/UI/EscapeMenu.xaml
+++ b/Content.Client/Options/UI/EscapeMenu.xaml
@@ -12,6 +12,7 @@
+
diff --git a/Content.Client/Stylesheets/StyleNano.cs b/Content.Client/Stylesheets/StyleNano.cs
index 13ba259dbcd..ab5ff4b2896 100644
--- a/Content.Client/Stylesheets/StyleNano.cs
+++ b/Content.Client/Stylesheets/StyleNano.cs
@@ -1335,6 +1335,11 @@ public StyleNano(IResourceCache resCache) : base(resCache)
.Prop(Label.StylePropertyFont, notoSans10),
// ---
+ // Furry Servers - Very Large Label for section headers
+ Element