diff --git a/Knossos.NET/Assets/fs2_res/fs1_coop_banner.png b/Knossos.NET/Assets/fs2_res/fs1_coop_banner.png new file mode 100644 index 00000000..63830bfd Binary files /dev/null and b/Knossos.NET/Assets/fs2_res/fs1_coop_banner.png differ diff --git a/Knossos.NET/Assets/fs2_res/fs2_coop_banner.jpg b/Knossos.NET/Assets/fs2_res/fs2_coop_banner.jpg new file mode 100644 index 00000000..9267be15 Binary files /dev/null and b/Knossos.NET/Assets/fs2_res/fs2_coop_banner.jpg differ diff --git a/Knossos.NET/Assets/fs2_res/fs2_demo_banner.png b/Knossos.NET/Assets/fs2_res/fs2_demo_banner.png new file mode 100644 index 00000000..698d3b76 Binary files /dev/null and b/Knossos.NET/Assets/fs2_res/fs2_demo_banner.png differ diff --git a/Knossos.NET/Assets/fs2_res/fsport_banner.png b/Knossos.NET/Assets/fs2_res/fsport_banner.png new file mode 100644 index 00000000..46b1920d Binary files /dev/null and b/Knossos.NET/Assets/fs2_res/fsport_banner.png differ diff --git a/Knossos.NET/Assets/fs2_res/fsport_mvps_banner.png b/Knossos.NET/Assets/fs2_res/fsport_mvps_banner.png new file mode 100644 index 00000000..04368ae5 Binary files /dev/null and b/Knossos.NET/Assets/fs2_res/fsport_mvps_banner.png differ diff --git a/Knossos.NET/Assets/fs2_res/mvps_banner.png b/Knossos.NET/Assets/fs2_res/mvps_banner.png new file mode 100644 index 00000000..41fda8a5 Binary files /dev/null and b/Knossos.NET/Assets/fs2_res/mvps_banner.png differ diff --git a/Knossos.NET/Assets/fs2_res/str_banner.png b/Knossos.NET/Assets/fs2_res/str_banner.png new file mode 100644 index 00000000..65c22435 Binary files /dev/null and b/Knossos.NET/Assets/fs2_res/str_banner.png differ diff --git a/Knossos.NET/Assets/fs2_res/str_coop_banner.jpg b/Knossos.NET/Assets/fs2_res/str_coop_banner.jpg new file mode 100644 index 00000000..3db1e0e8 Binary files /dev/null and b/Knossos.NET/Assets/fs2_res/str_coop_banner.jpg differ diff --git a/Knossos.NET/Assets/general/menu_fs.png b/Knossos.NET/Assets/general/menu_fs.png new file mode 100644 index 00000000..9a6ac790 Binary files /dev/null and b/Knossos.NET/Assets/general/menu_fs.png differ diff --git a/Knossos.NET/Classes/Knossos.cs b/Knossos.NET/Classes/Knossos.cs index 7ecec2ee..f2b9c17b 100644 --- a/Knossos.NET/Classes/Knossos.cs +++ b/Knossos.NET/Classes/Knossos.cs @@ -776,6 +776,9 @@ public static void ResetBasePath() Dispatcher.UIThread.InvokeAsync(async () => { MainWindowViewModel.Instance?.ClearViews(); + FreespaceViewModel.Instance?.SetLoading(true); + FreespaceViewModel.Instance?.SetFS2RootFound(false); + FreespaceViewModel.Instance?.SetInstalling(null, false); installedMods.Clear(); engineBuilds.Clear(); retailFs2RootFound = false; @@ -840,7 +843,8 @@ await Task.Run(async () => { ModListView.Instance?.GenerateFilterButtons(); MainWindowViewModel.Instance?.NebulaModsView?.UpdateFS2InstallButton(); MainWindowViewModel.Instance?.InstalledModsView?.UpdateFS2InstallButton(); - + FreespaceViewModel.Instance?.SetLoading(false); + FreespaceViewModel.Instance?.SetFS2RootFound(retailFs2RootFound); }); initIsComplete = true; diff --git a/Knossos.NET/ViewModels/FreespaceViewModel.cs b/Knossos.NET/ViewModels/FreespaceViewModel.cs new file mode 100644 index 00000000..543babdb --- /dev/null +++ b/Knossos.NET/ViewModels/FreespaceViewModel.cs @@ -0,0 +1,92 @@ +using CommunityToolkit.Mvvm.ComponentModel; +using Knossos.NET.Views; +using ObservableCollections; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Knossos.NET.ViewModels +{ + public partial class FreespaceViewModel : ViewModelBase + { + [ObservableProperty] + public ObservableList cardList = new ObservableList(); + + public static FreespaceViewModel? Instance { get; private set; } + + public FreespaceViewModel() + { + CardList = new ObservableList() { + new FreespaceModCardViewModel("fs2_org_demo", "The original Freespace 2 Demo with no modifications", "avares://Knossos.NET/Assets/fs2_res/fs2_demo_banner.png", false), + new FreespaceModCardViewModel("FS2", "Freespace 2 Retail without any graphics upgrades", "avares://Knossos.NET/Assets/fs2_res/kn_banner.png", true), + new FreespaceModCardViewModel("MVPS", "Freespace 2 with the newerest graphics upgrades", "avares://Knossos.NET/Assets/fs2_res/mvps_banner.png", true), + new FreespaceModCardViewModel("fsport", "FSPort is a conversion of Freespace 1 story to Freespace 2. No graphics upgrades.", "avares://Knossos.NET/Assets/fs2_res/fsport_banner.png", true), + new FreespaceModCardViewModel("fsport-mediavps", "FSPort (Freespace 1 Story) with all the graphic upgrades", "avares://Knossos.NET/Assets/fs2_res/fsport_mvps_banner.png", true), + new FreespaceModCardViewModel("str", "A retell of the Freespace 1 expansion 'Silent Threat', includes all the graphic upgrades", "avares://Knossos.NET/Assets/fs2_res/str_banner.png", true), + new FreespaceModCardViewModel("fs2coopup", "This mod includes multiplayer coop missions to play the entire Freespace 2 story with friends.", "avares://Knossos.NET/Assets/fs2_res/fs2_coop_banner.jpg", true), + new FreespaceModCardViewModel("fs1coopup", "This mod includes multiplayer coop missions to play the entire Freespace 1 story with friends.", "avares://Knossos.NET/Assets/fs2_res/fs1_coop_banner.png", true), + new FreespaceModCardViewModel("strcoopup", "This mod includes multiplayer coop missions to play the entire Silent Threat Reborn story with friends.", "avares://Knossos.NET/Assets/fs2_res/str_coop_banner.jpg", true) + }; + + Instance = this; + } + + /// + /// Sets the loading status to all mods listed in the freespace tab + /// + /// + public void SetLoading(bool status) + { + foreach (var item in CardList) + { + item.SetLoadingOverlay(status); + } + } + + /// + /// Set the status of the freespace 2 root found to all mods listed in the freespace tab + /// + /// + public void SetFS2RootFound(bool status) + { + foreach (var item in CardList) + { + item.SetRetailOverlay(!status); + } + } + + /// + /// Set the status of the installing overlay to a mod in the freespace tab + /// Allows to pass null as modID to change the status of all mods + /// + /// + /// + public void SetInstalling(string? modID,bool status) + { + foreach (var item in CardList) + { + if(modID == null || modID == item.ModID) + item.SetInstallingOverlay(status); + } + } + + /// + /// Set the status of the installed overlay to a mod in the freespace tab + /// + /// + /// + public void SetInstalled(string modID, bool status) + { + foreach (var item in CardList) + { + if (modID == item.ModID) + { + item.SetInstalled(status); + break; + } + } + } + } +} diff --git a/Knossos.NET/ViewModels/ModListViewModel.cs b/Knossos.NET/ViewModels/ModListViewModel.cs index 7bb349b9..ddc1b2ce 100644 --- a/Knossos.NET/ViewModels/ModListViewModel.cs +++ b/Knossos.NET/ViewModels/ModListViewModel.cs @@ -378,5 +378,15 @@ internal async void InstallFS2Command() Fs2Present = Knossos.retailFs2RootFound; } } + + /// + /// Find if a modcard is added to this view by mod id, and return a reference to it + /// + /// + /// ModcardViewModel or null + public ModCardViewModel? GetModCardByID (string modId) + { + return Mods.FirstOrDefault (m => m.ID == modId); + } } } diff --git a/Knossos.NET/ViewModels/NebulaModListViewModel.cs b/Knossos.NET/ViewModels/NebulaModListViewModel.cs index 3ee3a4d6..0f3a70a5 100644 --- a/Knossos.NET/ViewModels/NebulaModListViewModel.cs +++ b/Knossos.NET/ViewModels/NebulaModListViewModel.cs @@ -402,6 +402,16 @@ internal async void InstallFS2Command() await dialog.ShowDialog(MainWindow.instance); Fs2Present = Knossos.retailFs2RootFound; } - } + } + + /// + /// Find if a modcard is added to this view by mod id, and return a reference to it + /// + /// + /// NebulaModcardViewModel or null + public NebulaModCardViewModel? GetModCardByID(string modId) + { + return Mods.FirstOrDefault(m => m.ID == modId); + } } } diff --git a/Knossos.NET/ViewModels/Templates/FreespaceModCardViewModel.cs b/Knossos.NET/ViewModels/Templates/FreespaceModCardViewModel.cs new file mode 100644 index 00000000..1f500b6b --- /dev/null +++ b/Knossos.NET/ViewModels/Templates/FreespaceModCardViewModel.cs @@ -0,0 +1,168 @@ +using Avalonia.Media; +using Avalonia.Media.Imaging; +using Avalonia.Platform; +using CommunityToolkit.Mvvm.ComponentModel; +using Knossos.NET.Views; +using Microsoft.VisualBasic; +using System; + +namespace Knossos.NET.ViewModels +{ + public partial class FreespaceModCardViewModel : ViewModelBase + { + [ObservableProperty] + internal Bitmap? bannerImage; + [ObservableProperty] + internal bool installingOverlay = false; + [ObservableProperty] + internal bool loadingOverlay = false; + [ObservableProperty] + internal bool retailOverlay = false; + [ObservableProperty] + internal bool installed = false; + [ObservableProperty] + internal string tooltip = "Test"; + + public readonly string ModID; + public readonly bool NeedsRetail = false; + + public FreespaceModCardViewModel() + { + ModID = ""; + BannerImage = new Bitmap(AssetLoader.Open(new Uri("avares://Knossos.NET/Assets/fs2_res/fs2_demo_banner.png"))); + } + + public FreespaceModCardViewModel(string modID, string modTooltip, string assetBannerPath, bool needsFs2Retail) + { + ModID = modID; + Tooltip = modTooltip; + BannerImage = new Bitmap(AssetLoader.Open(new Uri(assetBannerPath))); + NeedsRetail = needsFs2Retail; + LoadingOverlay = true; + if(NeedsRetail) + RetailOverlay = true; + } + + public void SetInstallingOverlay(bool status) + { + InstallingOverlay = status; + } + + public void SetInstalled(bool status) + { + Installed = status; + } + + public void SetLoadingOverlay(bool status) + { + LoadingOverlay = status; + } + + public void SetRetailOverlay(bool status) + { + if(NeedsRetail) + RetailOverlay = status; + } + + internal void CommandPlay() + { + var card = FindModCard(); + if (card != null) + { + card.ButtonCommand("play"); + } + else + { + MessageBox.Show(MainWindow.instance,"Unable to find modcard id: " + ModID + ", on the installed mod list. This should not happen, try restarting KnossosNET.", "An error has ocurred", MessageBox.MessageBoxButtons.OK); + } + } + + internal void CommandSettings() + { + var card = FindModCard(); + if (card != null) + { + card.ButtonCommand("settings"); + } + else + { + MessageBox.Show(MainWindow.instance, "Unable to find modcard id: " + ModID + ", on the installed mod list. This should not happen, try restarting KnossosNET.", "An error has ocurred", MessageBox.MessageBoxButtons.OK); + } + } + + internal void CommandModify() + { + var card = FindModCard(); + if (card != null) + { + card.ButtonCommand("modify"); + } + else + { + MessageBox.Show(MainWindow.instance, "Unable to find modcard id: " + ModID + ", on the installed mod list. This should not happen, try restarting KnossosNET.", "An error has ocurred", MessageBox.MessageBoxButtons.OK); + } + } + + internal void CommandDetails() + { + var card = FindModCard(); + if (card != null) + { + card.ButtonCommand("details"); + } + else + { + MessageBox.Show(MainWindow.instance, "Unable to find modcard id: " + ModID + ", on the installed mod list. This should not happen, try restarting KnossosNET.", "An error has ocurred", MessageBox.MessageBoxButtons.OK); + } + } + + internal void CommandInstall() + { + var card = FindNebulaModCard(); + if (card != null) + { + card.ButtonCommand("install"); + } + else + { + MessageBox.Show(MainWindow.instance, "Unable to find modcard id: " + ModID + ", on the nebula mod list. This should not happen, try restarting KnossosNET.", "An error has ocurred", MessageBox.MessageBoxButtons.OK); + } + } + + internal void CommandRetail() + { + if (MainWindowViewModel.Instance != null && MainWindowViewModel.Instance.InstalledModsView != null) + { + MainWindowViewModel.Instance.InstalledModsView.InstallFS2Command(); + } + } + + internal void CommandGetGOG() + { + KnUtils.OpenBrowserURL("https://www.gog.com/en/game/freespace_2"); + } + + internal void CommandGetSteam() + { + KnUtils.OpenBrowserURL("https://store.steampowered.com/app/273620/Freespace_2/"); + } + + private ModCardViewModel? FindModCard() + { + if (MainWindowViewModel.Instance != null && MainWindowViewModel.Instance.InstalledModsView != null) + { + return MainWindowViewModel.Instance.InstalledModsView.GetModCardByID(ModID); + } + return null; + } + + private NebulaModCardViewModel? FindNebulaModCard() + { + if (MainWindowViewModel.Instance != null && MainWindowViewModel.Instance.NebulaModsView != null) + { + return MainWindowViewModel.Instance.NebulaModsView.GetModCardByID(ModID); + } + return null; + } + } +} diff --git a/Knossos.NET/ViewModels/Templates/ModCardViewModel.cs b/Knossos.NET/ViewModels/Templates/ModCardViewModel.cs index 80739056..c0a9c1fe 100644 --- a/Knossos.NET/ViewModels/Templates/ModCardViewModel.cs +++ b/Knossos.NET/ViewModels/Templates/ModCardViewModel.cs @@ -121,6 +121,7 @@ public ModCardViewModel(Mod modJson) BorderColor = KnUtils.GetResourceColor("ModCardBorderDevMode"); } LoadImage(); + FreespaceViewModel.Instance?.SetInstalled(ID, true); } /// @@ -348,6 +349,7 @@ internal async void ButtonCommandDelete() MainWindowViewModel.Instance?.AddNebulaMod(modVersions[modVersions.Count - 1]); } Knossos.RemoveMod(modVersions[activeVersionIndex].id); + FreespaceViewModel.Instance?.SetInstalled(ID, false); MainWindowViewModel.Instance?.RunModStatusChecks(); if (Knossos.globalSettings.hiddenModIds.Contains(modVersions[activeVersionIndex].id)) { diff --git a/Knossos.NET/ViewModels/Templates/NebulaModCardViewModel.cs b/Knossos.NET/ViewModels/Templates/NebulaModCardViewModel.cs index d6be5585..92ab1828 100644 --- a/Knossos.NET/ViewModels/Templates/NebulaModCardViewModel.cs +++ b/Knossos.NET/ViewModels/Templates/NebulaModCardViewModel.cs @@ -123,12 +123,14 @@ public void InstallingMod(CancellationTokenSource cancelToken) { IsInstalling = true; cancellationTokenSource = cancelToken; + FreespaceViewModel.Instance?.SetInstalling(ID!, true); } public void CancelInstall() { IsInstalling = false; cancellationTokenSource = null; + FreespaceViewModel.Instance?.SetInstalling(ID!, false); } public void CancelInstallCommand() @@ -141,6 +143,7 @@ public void CancelInstallCommand() catch { } cancellationTokenSource = null; TaskViewModel.Instance?.CancelAllInstallTaskWithID(ID!, ModVersion); + FreespaceViewModel.Instance?.SetInstalling(ID!,false); } internal async void ButtonCommandDetails() diff --git a/Knossos.NET/ViewModels/Templates/Tasks/InstallMod.cs b/Knossos.NET/ViewModels/Templates/Tasks/InstallMod.cs index ad56d04c..03011a18 100644 --- a/Knossos.NET/ViewModels/Templates/Tasks/InstallMod.cs +++ b/Knossos.NET/ViewModels/Templates/Tasks/InstallMod.cs @@ -603,6 +603,7 @@ await Dispatcher.UIThread.InvokeAsync(() => if (installed == null) { MainWindowViewModel.Instance?.NebulaModsView?.RemoveMod(mod.id); + FreespaceViewModel.Instance?.SetInstalling(mod.id, false); Knossos.AddMod(mod); await Dispatcher.UIThread.InvokeAsync(() => MainWindowViewModel.Instance?.AddInstalledMod(mod), DispatcherPriority.Background); //We cant determine if the version we are installing is the newer one at this point, but this will determine if it is newer than anything was was installed previously, what is good enoght diff --git a/Knossos.NET/ViewModels/Windows/MainWindowViewModel.cs b/Knossos.NET/ViewModels/Windows/MainWindowViewModel.cs index 03ea8193..60c73d36 100644 --- a/Knossos.NET/ViewModels/Windows/MainWindowViewModel.cs +++ b/Knossos.NET/ViewModels/Windows/MainWindowViewModel.cs @@ -50,6 +50,8 @@ public partial class MainWindowViewModel : ViewModelBase [ObservableProperty] internal int minWindowHeight = 500; [ObservableProperty] + internal FreespaceViewModel? freespaceView; + [ObservableProperty] internal ModListViewModel? installedModsView; [ObservableProperty] internal NebulaModListViewModel? nebulaModsView; @@ -106,6 +108,7 @@ public MainWindowViewModel() if (!CustomLauncher.IsCustomMode) { placeholderTileImage = new Bitmap(AssetLoader.Open(new Uri("avares://Knossos.NET/Assets/general/NebulaDefault.png"))); + FreespaceView = new FreespaceViewModel(); InstalledModsView = new ModListViewModel(); NebulaModsView = new NebulaModListViewModel(); FsoBuildsView = new FsoBuildsViewModel(); @@ -245,6 +248,7 @@ private void FillMenuItemsNormalMode(int defaultSelectedIndex) MenuItems = new ObservableCollection{ new MainViewMenuItem(TaskView, null, "Tasks", "Overview of current running tasks"), new MainViewMenuItem(InstalledModsView!, "avares://Knossos.NET/Assets/general/menu_play.png", "Play", "View and run installed Freepsace Open games and modifications"), + new MainViewMenuItem(FreespaceView!, "avares://Knossos.NET/Assets/general/menu_fs.png", "Freespace", "Quick and simple access to Freespace 2 content and improved graphics mods. Also list story relevant and Freespace multiplayer mods."), new MainViewMenuItem(NebulaModsView!, "avares://Knossos.NET/Assets/general/menu_explore.png", "Explore", "Search and install Freespace Open games and modifications"), new MainViewMenuItem(FsoBuildsView!, "avares://Knossos.NET/Assets/general/menu_engine.png", "Engine", "Download new Freespace Open engine builds"), new MainViewMenuItem(DeveloperModView!, "avares://Knossos.NET/Assets/general/menu_develop.png", "Develop", "Develop new games and modifications for the Freespace Open Engine"), diff --git a/Knossos.NET/ViewModels/Windows/ModDetailsViewModel.cs b/Knossos.NET/ViewModels/Windows/ModDetailsViewModel.cs index c9856552..e31b68f2 100644 --- a/Knossos.NET/ViewModels/Windows/ModDetailsViewModel.cs +++ b/Knossos.NET/ViewModels/Windows/ModDetailsViewModel.cs @@ -566,7 +566,7 @@ internal async void ButtonCommandDelete() Knossos.globalSettings.hiddenModIds.Remove(modVersions[0].id); Knossos.globalSettings.Save(); } - + FreespaceViewModel.Instance?.SetInstalled(modVersions[0].id, false); MainWindowViewModel.Instance?.RunModStatusChecks(); if (dialog != null) { diff --git a/Knossos.NET/Views/FreespaceView.axaml b/Knossos.NET/Views/FreespaceView.axaml new file mode 100644 index 00000000..75f99887 --- /dev/null +++ b/Knossos.NET/Views/FreespaceView.axaml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/Knossos.NET/Views/FreespaceView.axaml.cs b/Knossos.NET/Views/FreespaceView.axaml.cs new file mode 100644 index 00000000..c81ed195 --- /dev/null +++ b/Knossos.NET/Views/FreespaceView.axaml.cs @@ -0,0 +1,13 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Markup.Xaml; + +namespace Knossos.NET.Views; + +public partial class FreespaceView : UserControl +{ + public FreespaceView() + { + InitializeComponent(); + } +} \ No newline at end of file diff --git a/Knossos.NET/Views/Templates/FreespaceModCardView.axaml b/Knossos.NET/Views/Templates/FreespaceModCardView.axaml new file mode 100644 index 00000000..5406b5c1 --- /dev/null +++ b/Knossos.NET/Views/Templates/FreespaceModCardView.axaml @@ -0,0 +1,70 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Knossos.NET/Views/Templates/FreespaceModCardView.axaml.cs b/Knossos.NET/Views/Templates/FreespaceModCardView.axaml.cs new file mode 100644 index 00000000..91c5b8b5 --- /dev/null +++ b/Knossos.NET/Views/Templates/FreespaceModCardView.axaml.cs @@ -0,0 +1,13 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Markup.Xaml; + +namespace Knossos.NET.Views; + +public partial class FreespaceModCardView : UserControl +{ + public FreespaceModCardView() + { + InitializeComponent(); + } +} \ No newline at end of file diff --git a/Knossos.NET/Views/Windows/QuickSetupView.axaml b/Knossos.NET/Views/Windows/QuickSetupView.axaml index b89a5c83..a6c2e29d 100644 --- a/Knossos.NET/Views/Windows/QuickSetupView.axaml +++ b/Knossos.NET/Views/Windows/QuickSetupView.axaml @@ -82,6 +82,7 @@ Installing mods (Optional) + The "Freespace" tab is where the most relevant mods to Freespace, including Freespace 2 retail, Freespace 1 and their graphics upgrades are listed for easy access. If you are just starting to KnossosNET we recommend you start there. The "Play" tab is where all your installed mods are displayed, while the "Explore" tab shows only uninstalled mods. If you have installed Freespace 2 Retail, the FS2 retail mod card will already be added to your "Play" tab, but if you click "Play" right now you will be playing Freespace 2 in only its original 1999 glory. At this point you are probably looking for the visual improvements, so go to the "Explore" tab and lets download and install some mods! The following mods are some of the main projects related to improving visuals and Freespace story: • Freespace Upgrade MediaVPs - Visual improvements for Freespace 2. It is also used by most, if not all, other FS related mods. This mod has optional visual improvements components (like MV_AdvancedX) and it is recommended to select them all during install.