diff --git a/Additional files/7z/7z.dll b/Additional files/7z/7z.dll new file mode 100644 index 0000000..b32d7bf Binary files /dev/null and b/Additional files/7z/7z.dll differ diff --git a/Additional files/7z/7z.exe b/Additional files/7z/7z.exe new file mode 100644 index 0000000..37b8514 Binary files /dev/null and b/Additional files/7z/7z.exe differ diff --git a/Additional files/7z/License.txt b/Additional files/7z/License.txt new file mode 100644 index 0000000..b6ff3de --- /dev/null +++ b/Additional files/7z/License.txt @@ -0,0 +1,90 @@ + 7-Zip + ~~~~~ + License for use and distribution + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + 7-Zip Copyright (C) 1999-2019 Igor Pavlov. + + The licenses for files are: + + 1) 7z.dll: + - The "GNU LGPL" as main license for most of the code + - The "GNU LGPL" with "unRAR license restriction" for some code + - The "BSD 3-clause License" for some code + 2) All other files: the "GNU LGPL". + + Redistributions in binary form must reproduce related license information from this file. + + Note: + You can use 7-Zip on any computer, including a computer in a commercial + organization. You don't need to register or pay for 7-Zip. + + + GNU LGPL information + -------------------- + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You can receive a copy of the GNU Lesser General Public License from + http://www.gnu.org/ + + + + + BSD 3-clause License + -------------------- + + The "BSD 3-clause License" is used for the code in 7z.dll that implements LZFSE data decompression. + That code was derived from the code in the "LZFSE compression library" developed by Apple Inc, + that also uses the "BSD 3-clause License": + + ---- + Copyright (c) 2015-2016, Apple Inc. All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer + in the documentation and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder(s) nor the names of any contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ---- + + + + + unRAR license restriction + ------------------------- + + The decompression engine for RAR archives was developed using source + code of unRAR program. + All copyrights to original unRAR code are owned by Alexander Roshal. + + The license for original unRAR code has the following restriction: + + The unRAR sources cannot be used to re-create the RAR compression algorithm, + which is proprietary. Distribution of modified unRAR sources in separate form + or as a part of other software is permitted, provided that it is clearly + stated in the documentation and source comments that the code may + not be used to develop a RAR (WinRAR) compatible archiver. + + + -- + Igor Pavlov diff --git a/Additional files/7z/readme.txt b/Additional files/7z/readme.txt new file mode 100644 index 0000000..b3dc571 --- /dev/null +++ b/Additional files/7z/readme.txt @@ -0,0 +1,51 @@ +7-Zip 19.00 +----------- + +7-Zip is a file archiver for Windows. + +7-Zip Copyright (C) 1999-2019 Igor Pavlov. + +The main features of 7-Zip: + + - High compression ratio in the new 7z format + - Supported formats: + - Packing / unpacking: 7z, XZ, BZIP2, GZIP, TAR, ZIP and WIM. + - Unpacking only: AR, ARJ, CAB, CHM, CPIO, CramFS, DMG, EXT, FAT, GPT, HFS, + IHEX, ISO, LZH, LZMA, MBR, MSI, NSIS, NTFS, QCOW2, RAR, + RPM, SquashFS, UDF, UEFI, VDI, VHD, VMDK, XAR and Z. + - Fast compression and decompression + - Self-extracting capability for 7z format + - Strong AES-256 encryption in 7z and ZIP formats + - Integration with Windows Shell + - Powerful File Manager + - Powerful command line version + - Localizations for 85 languages + + +7-Zip is free software distributed under the GNU LGPL (except for unRar code). +Read License.txt for more information about license. + + + This distribution package contains the following files: + + 7zFM.exe - 7-Zip File Manager + 7-zip.dll - Plugin for Windows Shell + 7-zip32.dll - Plugin for Windows Shell (32-bit plugin for 64-bit system) + 7zg.exe - GUI module + 7z.exe - Command line version + 7z.dll - 7-Zip engine module + 7z.sfx - SFX module (Windows version) + 7zCon.sfx - SFX module (Console version) + + License.txt - License information + readme.txt - This file + History.txt - History of 7-Zip + 7-zip.chm - User's Manual in HTML Help format + descript.ion - Description for files + + Lang\en.ttt - English (base) localization file + Lang\*.txt - Localization files + + +--- +End of document diff --git a/Additional files/Attribution.txt b/Additional files/Attribution.txt new file mode 100644 index 0000000..5c74bd1 --- /dev/null +++ b/Additional files/Attribution.txt @@ -0,0 +1,67 @@ +ICONS + Most icons have been downloaded from iconsdb.com: + + "Soylent red fire 2 icon" by recognizeapp.com is licensed under CC BY 4.0 + https://www.iconsdb.com/soylent-red-icons/fire-2-icon.html + + "Royal blue save icon" by icons8.com is licensed under CC BY-ND 3.0 + https://www.iconsdb.com/royal-blue-icons/save-icon.html + + "Caribbean blue checked checkbox icon" by icons8.com is licensed under CC BY-ND 3.0 + https://www.iconsdb.com/caribbean-blue-icons/checked-checkbox-icon.html + + "Orange folder 3 icon" by icons8.com is licensed under CC BY-ND 3.0 + https://www.iconsdb.com/orange-icons/folder-3-icon.html + + "Soylent red delete icon" by icons8.com is licensed under CC BY-ND 3.0 + https://www.iconsdb.com/soylent-red-icons/delete-icon.html + + "Orange adventures icon" by icons8.com is licensed under CC BY-ND 3.0 + https://www.iconsdb.com/orange-icons/adventures-icon.html + + "Royal blue help icon" by icons8.com is licensed under CC BY-ND 3.0 + https://www.iconsdb.com/royal-blue-icons/help-icon.html + + "Black heart 69 ico" is licensed under CC0 1.0 Universal + https://www.iconsdb.com/black-icons/heart-69-icon.html + + "Royal blue cog icon" by Iconic is licensed under MIT License + https://www.iconsdb.com/royal-blue-icons/cog-icon.html + + "Black exit icon" is licensed under CC0 1.0 Universal + https://www.iconsdb.com/black-icons/exit-icon.html + + "Black text icon" by icons8 is licensed under Creative Commons Attribution-NoDerivs 3.0 + https://www.iconsdb.com/black-icons/text-icon.html + + "Guacamole green download 2 icon" by James Lynch is licensed under CC0 1.0 Universal (CC0 1.0) + https://www.iconsdb.com/guacamole-green-icons/download-2-icon.html + + "Black archive 3 icon" by bulb9 is licensed under CC0 1.0 Universal (CC0 1.0) + https://www.iconsdb.com/black-icons/archive-3-icon.html + + "Orange external link 2 icon" by Iconic licensed under MIT License. + https://www.iconsdb.com/orange-icons/external-link-2-icon.html + + "Black login icon" by icons8.com is licensed under Creative Commons Attribution-NoDerivs 3.0 + https://www.iconsdb.com/black-icons/login-icon.html + + + Thumbs up and down icons made by Those Icons from www.flaticon.com + https://www.flaticon.com/free-icon/like_2087973?term=thumbs%20up&page=1&position=5&related_item_id=2087973 + + Checkbox icon made by Freepik from www.flaticon.com + https://www.flaticon.com/free-icon/checkbox_1287087?term=checkbox&page=1&position=1&related_item_id=1287087 + + + Loading *.gif's: 'Spinner' and 'Gear' released under Loading.io FREE License. + + +SOUNDS + "Chord Alert Notification" (notify.wav) by graham_makes is licensed under CC BY 3.0 + (changed by adding a fade out effect and turning the volume down): + https://freesound.org/people/graham_makes/sounds/457518/ + + "error2.wav" (error.wav) by chrisw92 is licensed under CC BY 3.0 + (changed by adding a reverb and equalizing the volume on left and right channel): + https://freesound.org/people/chrisw92/sounds/110931/ \ No newline at end of file diff --git a/Additional files/DefaultINI/Fallout76.ini b/Additional files/DefaultINI/Fallout76.ini new file mode 100644 index 0000000..02cf9e3 --- /dev/null +++ b/Additional files/DefaultINI/Fallout76.ini @@ -0,0 +1,100 @@ +[General] +sLanguage = en +bAlwaysActive = 1 +bPlayMainMenuMusic = 1 +sIntroSequence = BGSLogo4k.bk2 +sStreamInstallVideoPlayList = +sMainMenuMusic = Data\Music\Special\MUS_Special_Wastelanders_MainTheme.xwm +uMainMenuMusicFadeTimeMS = 1500 +uMainMenuMusicAttnmB = 800 +uModMenuMusicAttnmB = 800 +bStreamingWallEnabled = 0 +bJobifyMagicUpdate = 0 +sBabylonMasters = NW.esm +bSteamEnabled = 1 + +[ScreenSplatter] +bBloodSplatterEnabled = 1 + +[Display] +bDynamicObjectQueryManager = 1 +bMultiThreadedAccumulation = 1 +bMultiThreadedRenderingUNP = 1 +fDecalLOD0 = 8192 +fSAORadius = 108.2 +fSAOBias = 0.6 +fSunUpdateThreshold = 0.5f +iSize W = 1920 +iSize H = 1080 +bFull Screen = 0 +bBorderless = 1 + +[HairLighting] +fHairPrimSpecScale = 0.04 +fHairPrimSpecPow = 388 +fHairPrimSpecShift = 1.0 +fHairSecSpecScale = 0.89 +fHairSecSpecPow = 98 +fHairSecSpecShift = 1.2 + +[Audio] +bEnableAudio = 1 + +[Interface] +iMainMenuStoreState = 1 +fDefaultWorldFOV = 70 +fDefault1stPersonFOV = 80 +fSafeZoneX = 15.0 +fSafeZoneY = 15.0 +fSafeZoneXWide = 64.0 +fSafeZoneXWide16x10 = 64.0 +fSafeZoneYWide16x10 = 36.0 + +[MapMenu] +uLockedObjectMapLOD = 16 +uLockedTerrainLOD = 32 + +[Controls] +fMouseHeadingXScale = .021 +fMouseHeadingYScale = .021 + +[Grass] +iMinGrassSize = 20 +bAllowCreateGrass = 1 + +[ImageSpace] +bDoRadialBlur = 1 + +[Weather] +bPrecipitation = 1 +bFogEnabled = 1 +fWindSpeedHighestHighMultiplier = 1.5 +bRainOcclusion = 1 +bWetnessOcclusion = 1 + +[Archive] +sResourceIndexFileList = SeventySix - Textures01.ba2, SeventySix - Textures02.ba2, SeventySix - Textures03.ba2, SeventySix - Textures04.ba2, SeventySix - Textures05.ba2, SeventySix - Textures06.ba2 +sResourceStartUpArchiveList = SeventySix - Interface.ba2, SeventySix - Localization.ba2, SeventySix - Shaders.ba2, SeventySix - Startup.ba2 +SResourceArchiveList = SeventySix - GeneratedMeshes01.ba2, SeventySix - GeneratedMeshes02.ba2, SeventySix - Materials.ba2, SeventySix - Meshes.ba2, SeventySix - MeshesExtra.ba2, SeventySix - MiscClient.ba2, SeventySix - Sounds01.ba2, SeventySix - Sounds02.ba2, SeventySix - Startup.ba2, SeventySix - Voices.ba2 +SResourceArchiveList2 = SeventySix - Animations.ba2, SeventySix - EnlightenInteriors.ba2, SeventySix - GeneratedTextures01.ba2, SeventySix - GeneratedTextures02.ba2, SeventySix - WorkshopIcons.ba2, SeventySix - EnlightenExteriors01.ba2, SeventySix - EnlightenExteriors02.ba2 +sResourceDataDirsFinal = STRINGS\, TERRAIN\ +SGeometryPackageList = SeventySix - Geometry.csg +SCellResourceIndexFileList = SeventySix.cdx +SResourceArchiveMemoryCacheList = SeventySix - Interface.ba2, SeventySix - Materials.ba2, SeventySix - MiscClient.ba2, SeventySix - Shaders.ba2 +sResourceArchive2List = SeventySix - StaticMeshes.ba2, SeventySix - 00UpdateMain.ba2, SeventySix - 01UpdateMain.ba2, SeventySix - 02UpdateMain.ba2, SeventySix - 03UpdateMain01.ba2, SeventySix - 03UpdateMain02.ba2, SeventySix - 04UpdateMain.ba2, SeventySix - 00UpdateStream.ba2, SeventySix - 01UpdateStream.ba2, SeventySix - 02UpdateStream.ba2, SeventySix - 03UpdateStream.ba2, SeventySix - 04UpdateStream.ba2, SeventySix - 00UpdateTextures.ba2, SeventySix - 01UpdateTextures.ba2, SeventySix - 02UpdateTextures.ba2, SeventySix - 03UpdateTextures.ba2, SeventySix - 04UpdateTextures.ba2, SeventySix - 00UpdateVoices.ba2, SeventySix - 01UpdateVoices.ba2, SeventySix - 02UpdateVoices.ba2, SeventySix - 03UpdateVoices.ba2, SeventySix - 04UpdateVoices.ba2 + +[LOD] +fLODFadeOutMultObjects = 4.5000 +fLODFadeOutMultItems = 2.5000 + +[Enlighten] +bEnableEnlighten = 1 + +[Voice] +sVivoxDomain = @fowp.vivox.com +sVivoxEndpoint = https://fowp.www.vivox.com/api2 + +[Platform] +sCREnv = PROD +sEnvId = prodpc01 + diff --git a/Additional files/DefaultINI/High.ini b/Additional files/DefaultINI/High.ini new file mode 100644 index 0000000..d75573c --- /dev/null +++ b/Additional files/DefaultINI/High.ini @@ -0,0 +1,57 @@ +[Display] +iMaxAnisotropy=16 +fShadowDistance=120000.0 +fDirShadowDistance=120000.0 +iShadowMapResolution=2048.0 +uiShadowFilter=3 +uiOrthoShadowFilter=3 +fBlendSplitDirShadow=48.0000 +iMaxFocusShadows=4 +iMaxDecalsPerFrame=100 +iMaxSkinDecalsPerFrame=25 +bVolumetricLightingEnable=1 +bSAOEnable=1 +uWaterShadowFilter=3 +iVolumetricLightingTextureQuality=2 + +[Decals] +bDecals=1 +bSkinnedDecals=1 +uMaxDecals=250 +uMaxSkinDecals=50 + +[TerrainManager] +fBlockMaximumDistance=180000.0000 +fBlockLevel2Distance=110000.0000 +fBlockLevel1Distance=60000.0000 +fBlockLevel0Distance=30000.0000 + +[ImageSpace] +bDoDepthOfField=1 +bMBEnable=1 + +[LightingShader] +bScreenSpaceReflections=1 + +[LOD] +fLODFadeOutMultActors=9.0000 +fLODFadeOutMultItems=6.0000 +fLODFadeOutMultObjects=9.0000 +fLODFadeOutMultSkyCell=1.0000 + +[Grass] +fGrassStartFadeDistance = 5500 + +[Texture] +iLargeTextureArrayMipSkip=0 +iTextureMipSkipBC1UNormSrgb=1 +iTextureMipSkipBC3UNormSrgb=1 +iTextureMipSkipBC1UNorm=1 +iTextureMipSkipBC5SNorm=1 +iTextureMipSkipBC4UNorm=1 +iTextureMipSkipMinDimension=1024 +iLargeTextureArrayDim=2048 +iTextureQualityLevel=2 + +[Water] +bUseWaterHiRes=1 \ No newline at end of file diff --git a/Additional files/DefaultINI/Low.ini b/Additional files/DefaultINI/Low.ini new file mode 100644 index 0000000..2160b83 --- /dev/null +++ b/Additional files/DefaultINI/Low.ini @@ -0,0 +1,57 @@ +[Display] +iMaxAnisotropy=0 +fShadowDistance=60000.0 +fDirShadowDistance=60000.0 +iShadowMapResolution=1024 +uiShadowFilter=1 +uiOrthoShadowFilter=1 +fBlendSplitDirShadow=0.0000 +iMaxFocusShadows=0 +iMaxDecalsPerFrame=0 +iMaxSkinDecalsPerFrame=0 +bVolumetricLightingEnable=0 +bSAOEnable=1 +uWaterShadowFilter=1 +iVolumetricLightingTextureQuality=0 + +[Decals] +bDecals=0 +bSkinnedDecals=0 +uMaxDecals=0 +uMaxSkinDecals=0 + +[TerrainManager] +fBlockMaximumDistance=100000.0000 +fBlockLevel2Distance=75000.0000 +fBlockLevel1Distance=25000.0000 +fBlockLevel0Distance=15000.0000 + +[ImageSpace] +bDoDepthOfField=0 +bMBEnable=0 + +[LightingShader] +bScreenSpaceReflections=1 + +[LOD] +fLODFadeOutMultActors=5.0000 +fLODFadeOutMultItems=1.5000 +fLODFadeOutMultObjects=5.0000 +fLODFadeOutMultSkyCell=1.0000 + +[Grass] +fGrassStartFadeDistance = 3500 + +[Texture] +iLargeTextureArrayMipSkip=2 +iTextureMipSkipBC1UNormSrgb=2 +iTextureMipSkipBC3UNormSrgb=2 +iTextureMipSkipBC1UNorm=2 +iTextureMipSkipBC5SNorm=2 +iTextureMipSkipBC4UNorm=2 +iTextureMipSkipMinDimension=256 +iLargeTextureArrayDim=1024 +iTextureQualityLevel=0 + +[Water] +bUseWaterHiRes=0 \ No newline at end of file diff --git a/Additional files/DefaultINI/Medium.ini b/Additional files/DefaultINI/Medium.ini new file mode 100644 index 0000000..25aba38 --- /dev/null +++ b/Additional files/DefaultINI/Medium.ini @@ -0,0 +1,57 @@ +[Display] +iMaxAnisotropy=16 +fShadowDistance=90000.0 +fDirShadowDistance=90000.0 +iShadowMapResolution=2048.0 +uiShadowFilter=2 +uiOrthoShadowFilter=2 +fBlendSplitDirShadow=48.0000 +iMaxFocusShadows=1 +iMaxDecalsPerFrame=10 +iMaxSkinDecalsPerFrame=3 +bVolumetricLightingEnable=1 +bSAOEnable=1 +uWaterShadowFilter=2 +iVolumetricLightingTextureQuality=1 + +[Decals] +bDecals=1 +bSkinnedDecals=1 +uMaxDecals=100 +uMaxSkinDecals=35 + +[TerrainManager] +fBlockMaximumDistance=100000.0000 +fBlockLevel2Distance=80000.0000 +fBlockLevel1Distance=32000.0000 +fBlockLevel0Distance=20000.0000 + +[ImageSpace] +bDoDepthOfField=1 +bMBEnable=1 + +[LightingShader] +bScreenSpaceReflections=1 + +[LOD] +fLODFadeOutMultActors=7.0000 +fLODFadeOutMultItems=3.0000 +fLODFadeOutMultObjects=7.0000 +fLODFadeOutMultSkyCell=1.0000 + +[Grass] +fGrassStartFadeDistance = 4500 + +[Texture] +iLargeTextureArrayMipSkip=1 +iTextureMipSkipBC1UNormSrgb=1 +iTextureMipSkipBC3UNormSrgb=1 +iTextureMipSkipBC1UNorm=1 +iTextureMipSkipBC5SNorm=1 +iTextureMipSkipBC4UNorm=1 +iTextureMipSkipMinDimension=256 +iLargeTextureArrayDim=1024 +iTextureQualityLevel=1 + +[Water] +bUseWaterHiRes=0 \ No newline at end of file diff --git a/Additional files/DefaultINI/Ultra.ini b/Additional files/DefaultINI/Ultra.ini new file mode 100644 index 0000000..ac3fc57 --- /dev/null +++ b/Additional files/DefaultINI/Ultra.ini @@ -0,0 +1,57 @@ +[Display] +iMaxAnisotropy=16 +fShadowDistance=150000.0 +fDirShadowDistance=150000.0 +iShadowMapResolution=2048.0 +uiShadowFilter=3 +uiOrthoShadowFilter=3 +fBlendSplitDirShadow=48.0000 +iMaxFocusShadows=4 +iMaxDecalsPerFrame=100 +iMaxSkinDecalsPerFrame=25 +bVolumetricLightingEnable=1 +bSAOEnable=1 +uWaterShadowFilter=3 +iVolumetricLightingTextureQuality=2 + +[Decals] +bDecals=1 +bSkinnedDecals=1 +uMaxDecals=1000 +uMaxSkinDecals=100 + +[TerrainManager] +fBlockMaximumDistance=250000.0000 +fBlockLevel2Distance=110000.0000 +fBlockLevel1Distance=90000.0000 +fBlockLevel0Distance=60000.0000 + +[ImageSpace] +bDoDepthOfField=1 +bMBEnable=1 + +[LightingShader] +bScreenSpaceReflections=1 + +[LOD] +fLODFadeOutMultActors=15.0000 +fLODFadeOutMultItems=10.0000 +fLODFadeOutMultObjects=30.0000 +fLODFadeOutMultSkyCell=1.0000 + +[Grass] +fGrassStartFadeDistance = 7000 + +[Texture] +iLargeTextureArrayMipSkip=0 +iTextureMipSkipBC1UNormSrgb=0 +iTextureMipSkipBC3UNormSrgb=0 +iTextureMipSkipBC1UNorm=0 +iTextureMipSkipBC5SNorm=0 +iTextureMipSkipBC4UNorm=0 +iTextureMipSkipMinDimension=1024 +iLargeTextureArrayDim=2048 +iTextureQualityLevel=3 + +[Water] +bUseWaterHiRes=1 \ No newline at end of file diff --git a/Additional files/error.wav b/Additional files/error.wav new file mode 100644 index 0000000..8582da1 Binary files /dev/null and b/Additional files/error.wav differ diff --git a/Additional files/notify.wav b/Additional files/notify.wav new file mode 100644 index 0000000..85ca43b Binary files /dev/null and b/Additional files/notify.wav differ diff --git a/Fo76ini/7z/7za.dll b/Fo76ini/7z/7za.dll deleted file mode 100644 index bc2b47a..0000000 Binary files a/Fo76ini/7z/7za.dll and /dev/null differ diff --git a/Fo76ini/7z/7za.exe b/Fo76ini/7z/7za.exe deleted file mode 100644 index 9f27b20..0000000 Binary files a/Fo76ini/7z/7za.exe and /dev/null differ diff --git a/Fo76ini/7z/7zxa.dll b/Fo76ini/7z/7zxa.dll deleted file mode 100644 index d51e3f0..0000000 Binary files a/Fo76ini/7z/7zxa.dll and /dev/null differ diff --git a/Fo76ini/7z/License.txt b/Fo76ini/7z/License.txt deleted file mode 100644 index 48dc6c6..0000000 --- a/Fo76ini/7z/License.txt +++ /dev/null @@ -1,31 +0,0 @@ - 7-Zip Extra - ~~~~~~~~~~~ - License for use and distribution - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - Copyright (C) 1999-2019 Igor Pavlov. - - 7-Zip Extra files are under the GNU LGPL license. - - - Notes: - You can use 7-Zip Extra on any computer, including a computer in a commercial - organization. You don't need to register or pay for 7-Zip. - - - GNU LGPL information - -------------------- - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You can receive a copy of the GNU Lesser General Public License from - http://www.gnu.org/ - diff --git a/Fo76ini/App.config b/Fo76ini/App.config index a7bb9fb..f55ca4f 100644 --- a/Fo76ini/App.config +++ b/Fo76ini/App.config @@ -13,6 +13,10 @@ + + + + \ No newline at end of file diff --git a/Fo76ini/Configuration.cs b/Fo76ini/Configuration.cs new file mode 100644 index 0000000..a90dcb7 --- /dev/null +++ b/Fo76ini/Configuration.cs @@ -0,0 +1,85 @@ +using System; +using System.Collections.Generic; +using System.Windows.Forms; + +namespace Fo76ini +{ + public static class Configuration + { + // https://stackoverflow.com/questions/1873658/net-windows-forms-remember-windows-size-and-location + public static void SaveWindowState(string formName, Form form) + { + if (form.WindowState == FormWindowState.Maximized) + { + IniFiles.Config.Set(formName, "iLocationX", form.RestoreBounds.Location.X); + IniFiles.Config.Set(formName, "iLocationY", form.RestoreBounds.Location.Y); + IniFiles.Config.Set(formName, "iWidth", form.RestoreBounds.Size.Width); + IniFiles.Config.Set(formName, "iHeight", form.RestoreBounds.Size.Height); + IniFiles.Config.Set(formName, "bMaximised", true); + } + else + { + IniFiles.Config.Set(formName, "iLocationX", form.Location.X); + IniFiles.Config.Set(formName, "iLocationY", form.Location.Y); + IniFiles.Config.Set(formName, "iWidth", form.Size.Width); + IniFiles.Config.Set(formName, "iHeight", form.Size.Height); + IniFiles.Config.Set(formName, "bMaximised", false); + } + IniFiles.Config.Save(); + } + + public static void LoadWindowState(string formName, Form form) + { + int locX = IniFiles.Config.GetInt(formName, "iLocationX", -1); + int locY = IniFiles.Config.GetInt(formName, "iLocationY", -1); + if (locX >= 0 && locY >= 0) + form.Location = new System.Drawing.Point(locX, locY); + + int width = IniFiles.Config.GetInt(formName, "iWidth", form.Size.Width); + int height = IniFiles.Config.GetInt(formName, "iHeight", form.Size.Height); + if (width >= form.MinimumSize.Width && height >= form.MinimumSize.Height) + form.Size = new System.Drawing.Size(width, height); + + if (IniFiles.Config.GetBool(formName, "bMaximised", false)) + form.WindowState = FormWindowState.Maximized; + } + + public static void SaveListViewState(string formName, ListView listView) + { + List widths = new List(); + foreach (ColumnHeader column in listView.Columns) + { + widths.Add(column.Width); + } + IniFiles.Config.Set(formName, "sColumnWidths", string.Join(",", widths)); + } + + public static void LoadListViewState(string formName, ListView listView) + { + List lWidths = new List(); + string[] sWidths = IniFiles.Config.GetString(formName, "sColumnWidths", "").Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); + foreach (string sWidth in sWidths) + lWidths.Add(Convert.ToInt32(sWidth)); + + int i = 0; + foreach (ColumnHeader column in listView.Columns) + { + if (i < lWidths.Count) + column.Width = lWidths[i++]; + } + } + + // TODO: Remove + public static bool bUseHardlinks + { + get + { + return IniFiles.Config.GetBool("Mods", "bUseHardlinks", true); + } + set + { + IniFiles.Config.Set("Mods", "bUseHardlinks", value); + } + } + } +} diff --git a/Fo76ini/Fo76ini.csproj b/Fo76ini/Fo76ini.csproj index 47db491..280b6bc 100644 --- a/Fo76ini/Fo76ini.csproj +++ b/Fo76ini/Fo76ini.csproj @@ -60,6 +60,9 @@ app.manifest + + + packages\ini-parser.2.5.2\lib\net20\INIFileParser.dll @@ -67,13 +70,15 @@ packages\Newtonsoft.Json.12.0.3\lib\net45\Newtonsoft.Json.dll - - packages\SharpCompress.0.26.0\lib\net46\SharpCompress.dll - packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll + + packages\System.Collections.Specialized.4.3.0\lib\net46\System.Collections.Specialized.dll + True + True + packages\System.Memory.4.5.4\lib\net461\System.Memory.dll @@ -82,12 +87,25 @@ packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll + + packages\System.Reactive.4.3.2\lib\net46\System.Reactive.dll + - packages\System.Runtime.CompilerServices.Unsafe.4.7.0\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll + packages\System.Runtime.CompilerServices.Unsafe.4.7.1\lib\net461\System.Runtime.CompilerServices.Unsafe.dll - packages\System.Text.Encoding.CodePages.4.7.0\lib\net461\System.Text.Encoding.CodePages.dll + packages\System.Text.Encoding.CodePages.4.7.1\lib\net461\System.Text.Encoding.CodePages.dll + + + packages\System.Threading.Channels.4.7.0\lib\netstandard2.0\System.Threading.Channels.dll + + + packages\System.Threading.Tasks.Extensions.4.5.3\lib\netstandard2.0\System.Threading.Tasks.Extensions.dll + + + packages\System.ValueTuple.4.5.0\lib\net47\System.ValueTuple.dll + @@ -97,19 +115,165 @@ - - packages\Tulpep.NotificationWindow.1.1.31\lib\net40\Tulpep.NotificationWindow.dll + + packages\Tulpep.NotificationWindow.1.1.37\lib\net40\Tulpep.NotificationWindow.dll + + packages\Websocket.Client.4.3.21\lib\netstandard2.0\Websocket.Client.dll + + - + + Form + + + FormIniError.cs + + + Form + + + FormSettings.cs + + + Form + + + FormSplash.cs + + + Form + + + TextPrompt.cs + + + Form + + + FormWelcome.cs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Form FormExceptionDialog.cs - + + Component + + Form @@ -142,29 +306,64 @@ FormWhatsNew.cs + + + - - - - + + + + + + + + + + + + + + + + - + - - + + + + + + FormExceptionDialog.cs Form1.cs + + FormIniError.cs + FormMods.cs + Designer + + + FormSettings.cs + + + FormSplash.cs + + + TextPrompt.cs + + + FormWelcome.cs FormWhatsNew.cs @@ -195,7 +394,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + @@ -213,7 +437,6 @@ - @@ -260,5 +483,6 @@ false + \ No newline at end of file diff --git a/Fo76ini/Fo76ini.sln b/Fo76ini/Fo76ini.sln index d3e3f2a..72425c6 100644 --- a/Fo76ini/Fo76ini.sln +++ b/Fo76ini/Fo76ini.sln @@ -5,6 +5,8 @@ VisualStudioVersion = 16.0.29920.165 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Fo76ini", "Fo76ini.csproj", "{F657CC3C-8FDF-4D1A-AE64-2F7E8A883D3C}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Fo76ini_Updater", "..\Fo76ini_Updater\Fo76ini_Updater.csproj", "{9904A9D3-44A9-4952-A5A7-8C82E209C6C8}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -15,11 +17,15 @@ Global {F657CC3C-8FDF-4D1A-AE64-2F7E8A883D3C}.Debug|Any CPU.Build.0 = Debug|Any CPU {F657CC3C-8FDF-4D1A-AE64-2F7E8A883D3C}.Release|Any CPU.ActiveCfg = Release|Any CPU {F657CC3C-8FDF-4D1A-AE64-2F7E8A883D3C}.Release|Any CPU.Build.0 = Release|Any CPU + {9904A9D3-44A9-4952-A5A7-8C82E209C6C8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9904A9D3-44A9-4952-A5A7-8C82E209C6C8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9904A9D3-44A9-4952-A5A7-8C82E209C6C8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9904A9D3-44A9-4952-A5A7-8C82E209C6C8}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {94AE7D92-ECD9-4EFA-997D-1D67A4231AAA} + SolutionGuid = {B2D832BB-F9E7-4CB8-ABE2-0C3251C3B94B} EndGlobalSection EndGlobal diff --git a/Fo76ini/Forms/ExceptionDialog/FormExceptionDialog.Designer.cs b/Fo76ini/Forms/ExceptionDialog/FormExceptionDialog.Designer.cs index 50b6b9e..bb55006 100644 --- a/Fo76ini/Forms/ExceptionDialog/FormExceptionDialog.Designer.cs +++ b/Fo76ini/Forms/ExceptionDialog/FormExceptionDialog.Designer.cs @@ -39,6 +39,7 @@ private void InitializeComponent() // // buttonCloseProgram // + this.buttonCloseProgram.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); this.buttonCloseProgram.Font = new System.Drawing.Font("Microsoft Sans Serif", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.buttonCloseProgram.Location = new System.Drawing.Point(358, 371); this.buttonCloseProgram.Name = "buttonCloseProgram"; @@ -50,6 +51,7 @@ private void InitializeComponent() // // buttonCopyText // + this.buttonCopyText.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); this.buttonCopyText.Font = new System.Drawing.Font("Microsoft Sans Serif", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.buttonCopyText.Location = new System.Drawing.Point(219, 371); this.buttonCopyText.Name = "buttonCopyText"; @@ -72,6 +74,9 @@ private void InitializeComponent() // // textBoxDebugText // + this.textBoxDebugText.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); this.textBoxDebugText.BackColor = System.Drawing.SystemColors.Window; this.textBoxDebugText.Font = new System.Drawing.Font("Consolas", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.textBoxDebugText.Location = new System.Drawing.Point(13, 82); @@ -103,8 +108,6 @@ private void InitializeComponent() this.Controls.Add(this.buttonCopyText); this.Controls.Add(this.buttonCloseProgram); this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); - this.MaximizeBox = false; - this.MaximumSize = new System.Drawing.Size(520, 450); this.MinimumSize = new System.Drawing.Size(520, 450); this.Name = "FormExceptionDialog"; this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; diff --git a/Fo76ini/Forms/ExceptionDialog/FormExceptionDialog.cs b/Fo76ini/Forms/ExceptionDialog/FormExceptionDialog.cs index 35cba2b..5d1796b 100644 --- a/Fo76ini/Forms/ExceptionDialog/FormExceptionDialog.cs +++ b/Fo76ini/Forms/ExceptionDialog/FormExceptionDialog.cs @@ -1,11 +1,5 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Data; -using System.Drawing; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using Fo76ini.Utilities; +using System; using System.Windows.Forms; namespace Fo76ini.Forms.ExceptionDialog @@ -19,7 +13,7 @@ public FormExceptionDialog() this.FormClosing += this.FormExceptionDialog_FormClosing; } - public static FormExceptionDialog OpenDialog (Exception ex) + public static FormExceptionDialog OpenDialog(Exception ex) { FormExceptionDialog form = new FormExceptionDialog(); @@ -27,12 +21,11 @@ public static FormExceptionDialog OpenDialog (Exception ex) { form.textBoxDebugText.Text = $"Operating system: {Utils.GetOSName()} {Utils.GetOSArchitecture()}\r\n" + $"Program version: {Shared.VERSION}\r\n" + - $"Program locale: {Localization.locale}\r\n" + - $"Game edition: {Shared.GameEdition}\r\n" + + $"Program locale: {Localization.Locale}\r\n" + "\r\n" + $"************** Exception Text **************\r\n{ex.GetType()}: {ex.Message}\r\n{ex.StackTrace}\r\n"; } - catch (Exception e) + catch { form.textBoxDebugText.Text = $"************** Exception Text **************\r\n{ex.GetType()}: {ex.Message}\r\n{ex.StackTrace}\r\n"; } diff --git a/Fo76ini/Forms/Form1/ColorPreview.cs b/Fo76ini/Forms/Form1/ColorPreview.cs new file mode 100644 index 0000000..dbe576a --- /dev/null +++ b/Fo76ini/Forms/Form1/ColorPreview.cs @@ -0,0 +1,25 @@ +using System; +using System.Drawing; +using System.Windows.Forms; + +namespace Fo76ini.Forms.Form1 +{ + public class ColorPreview : PictureBox + { + public event EventHandler ColorChanged; + + public override Color BackColor + { + get + { + return base.BackColor; + } + set + { + base.BackColor = value; + if (this.ColorChanged != null) + this.ColorChanged(this, new EventArgs()); + } + } + } +} diff --git a/Fo76ini/Forms/Form1/Form1.Camera.cs b/Fo76ini/Forms/Form1/Form1.Camera.cs index 1898b1f..44d7d2d 100644 --- a/Fo76ini/Forms/Form1/Form1.Camera.cs +++ b/Fo76ini/Forms/Form1/Form1.Camera.cs @@ -1,14 +1,4 @@ -using IniParser.Model; -using System; -using System.Collections.Generic; -using System.Globalization; -using System.IO; -using System.Linq; -using System.Net; -using System.Text; -using System.Text.RegularExpressions; -using System.Threading.Tasks; -using System.Windows.Forms; +using System; namespace Fo76ini { @@ -21,13 +11,14 @@ public enum CameraPositionMode partial class Form1 { +#if false private CameraPositionMode camPosMode = CameraPositionMode.Unarmed; private float camOffsetMultiplier = 50; private float camOffsetToMetersRatio = 30; // I have no idea. We'll see. - private void UpdateCameraPositionUI () + private void UpdateCameraPositionUI() { this.trackBarCameraY.Enabled = camPosMode != CameraPositionMode.Unarmed; @@ -40,24 +31,24 @@ private void UpdateCameraPositionUI () switch (camPosMode) { case CameraPositionMode.Unarmed: - x = IniFiles.Instance.GetFloat("Camera", "fOverShoulderPosX", 0); - z = IniFiles.Instance.GetFloat("Camera", "fOverShoulderPosZ", 0); + x = IniFiles.GetFloat("Camera", "fOverShoulderPosX", 0); + z = IniFiles.GetFloat("Camera", "fOverShoulderPosZ", 0); this.trackBarCameraX.Value = (int)(x / camOffsetMultiplier * rangeX / 2); this.trackBarCameraY.Value = 0; this.trackBarCameraZ.Value = (int)(z / camOffsetMultiplier * rangeZ / 2); break; case CameraPositionMode.Combat: - x = IniFiles.Instance.GetFloat("Camera", "fOverShoulderCombatPosX", 0); - y = IniFiles.Instance.GetFloat("Camera", "fOverShoulderCombatAddY", 0); - z = IniFiles.Instance.GetFloat("Camera", "fOverShoulderCombatPosZ", 0); + x = IniFiles.GetFloat("Camera", "fOverShoulderCombatPosX", 0); + y = IniFiles.GetFloat("Camera", "fOverShoulderCombatAddY", 0); + z = IniFiles.GetFloat("Camera", "fOverShoulderCombatPosZ", 0); this.trackBarCameraX.Value = (int)(x / camOffsetMultiplier * rangeX / 2); this.trackBarCameraY.Value = (int)(y / camOffsetMultiplier * rangeY / 2); this.trackBarCameraZ.Value = (int)(z / camOffsetMultiplier * rangeZ / 2); break; case CameraPositionMode.MeleeCombat: - x = IniFiles.Instance.GetFloat("Camera", "fOverShoulderMeleeCombatPosX", 0); - y = IniFiles.Instance.GetFloat("Camera", "fOverShoulderMeleeCombatAddY", 0); - z = IniFiles.Instance.GetFloat("Camera", "fOverShoulderMeleeCombatPosZ", 0); + x = IniFiles.GetFloat("Camera", "fOverShoulderMeleeCombatPosX", 0); + y = IniFiles.GetFloat("Camera", "fOverShoulderMeleeCombatAddY", 0); + z = IniFiles.GetFloat("Camera", "fOverShoulderMeleeCombatPosZ", 0); this.trackBarCameraX.Value = (int)(x / camOffsetMultiplier * rangeX / 2); this.trackBarCameraY.Value = (int)(y / camOffsetMultiplier * rangeY / 2); this.trackBarCameraZ.Value = (int)(z / camOffsetMultiplier * rangeZ / 2); @@ -75,22 +66,21 @@ private void trackBarCameraX_Scroll(object sender, EventArgs e) float value = normalized * camOffsetMultiplier; - bool alternativeMode = IniFiles.Instance.GetBool(IniFile.Config, "Preferences", "bAlternativeINIMode", false); switch (camPosMode) { case CameraPositionMode.Unarmed: - IniFiles.Instance.Set(!alternativeMode ? IniFile.F76Custom : IniFile.F76, "Camera", "fOverShoulderPosX", value); + IniFiles.F76Custom.Set("Camera", "fOverShoulderPosX", value); break; case CameraPositionMode.Combat: - IniFiles.Instance.Set(!alternativeMode ? IniFile.F76Custom : IniFile.F76, "Camera", "fOverShoulderCombatPosX", value); + IniFiles.F76Custom.Set("Camera", "fOverShoulderCombatPosX", value); break; case CameraPositionMode.MeleeCombat: - IniFiles.Instance.Set(!alternativeMode ? IniFile.F76Custom : IniFile.F76, "Camera", "fOverShoulderMeleeCombatPosX", value); + IniFiles.F76Custom.Set("Camera", "fOverShoulderMeleeCombatPosX", value); break; } this.checkBoxbApplyCameraNodeAnimations.Checked = false; - IniFiles.Instance.Set(!alternativeMode ? IniFile.F76Custom : IniFile.F76, "Camera", "bApplyCameraNodeAnimations", false); + IniFiles.F76Custom.Set("Camera", "bApplyCameraNodeAnimations", false); if (value < 0) Console.WriteLine($"Camera is offset to the left by {-value / camOffsetToMetersRatio} meters."); @@ -108,19 +98,18 @@ private void trackBarCameraY_Scroll(object sender, EventArgs e) float value = normalized * camOffsetMultiplier; - bool alternativeMode = IniFiles.Instance.GetBool(IniFile.Config, "Preferences", "bAlternativeINIMode", false); switch (camPosMode) { case CameraPositionMode.Combat: - IniFiles.Instance.Set(!alternativeMode ? IniFile.F76Custom : IniFile.F76, "Camera", "fOverShoulderCombatAddY", value); + IniFiles.F76Custom.Set("Camera", "fOverShoulderCombatAddY", value); break; case CameraPositionMode.MeleeCombat: - IniFiles.Instance.Set(!alternativeMode ? IniFile.F76Custom : IniFile.F76, "Camera", "fOverShoulderMeleeCombatAddY", value); + IniFiles.F76Custom.Set("Camera", "fOverShoulderMeleeCombatAddY", value); break; } this.checkBoxbApplyCameraNodeAnimations.Checked = false; - IniFiles.Instance.Set(!alternativeMode ? IniFile.F76Custom : IniFile.F76, "Camera", "bApplyCameraNodeAnimations", false); + IniFiles.F76Custom.Set("Camera", "bApplyCameraNodeAnimations", false); if (value < 0) Console.WriteLine($"Camera is zoomed out by {-value / camOffsetToMetersRatio} meters."); @@ -138,22 +127,21 @@ private void trackBarCameraZ_Scroll(object sender, EventArgs e) float value = normalized * camOffsetMultiplier; - bool alternativeMode = IniFiles.Instance.GetBool(IniFile.Config, "Preferences", "bAlternativeINIMode", false); switch (camPosMode) { case CameraPositionMode.Unarmed: - IniFiles.Instance.Set(!alternativeMode ? IniFile.F76Custom : IniFile.F76, "Camera", "fOverShoulderPosZ", value); + IniFiles.F76Custom.Set("Camera", "fOverShoulderPosZ", value); break; case CameraPositionMode.Combat: - IniFiles.Instance.Set(!alternativeMode ? IniFile.F76Custom : IniFile.F76, "Camera", "fOverShoulderCombatPosZ", value); + IniFiles.F76Custom.Set("Camera", "fOverShoulderCombatPosZ", value); break; case CameraPositionMode.MeleeCombat: - IniFiles.Instance.Set(!alternativeMode ? IniFile.F76Custom : IniFile.F76, "Camera", "fOverShoulderMeleeCombatPosZ", value); + IniFiles.F76Custom.Set("Camera", "fOverShoulderMeleeCombatPosZ", value); break; } this.checkBoxbApplyCameraNodeAnimations.Checked = false; - IniFiles.Instance.Set(!alternativeMode ? IniFile.F76Custom : IniFile.F76, "Camera", "bApplyCameraNodeAnimations", false); + IniFiles.F76Custom.Set("Camera", "bApplyCameraNodeAnimations", false); if (value < 0) Console.WriteLine($"Camera is offset downwards by {-value / camOffsetToMetersRatio} meters."); @@ -167,66 +155,41 @@ private void buttonCameraPositionReset_Click(object sender, EventArgs e) { this.checkBoxbApplyCameraNodeAnimations.Checked = true; - IniFiles.Instance.Remove(IniFile.F76Custom, "Camera", "fOverShoulderPosX"); - IniFiles.Instance.Remove(IniFile.F76Custom, "Camera", "fOverShoulderPosZ"); - IniFiles.Instance.Remove(IniFile.F76Custom, "Camera", "fOverShoulderCombatPosX"); - IniFiles.Instance.Remove(IniFile.F76Custom, "Camera", "fOverShoulderCombatAddY"); - IniFiles.Instance.Remove(IniFile.F76Custom, "Camera", "fOverShoulderCombatPosZ"); - IniFiles.Instance.Remove(IniFile.F76Custom, "Camera", "fOverShoulderMeleeCombatPosX"); - IniFiles.Instance.Remove(IniFile.F76Custom, "Camera", "fOverShoulderMeleeCombatAddY"); - IniFiles.Instance.Remove(IniFile.F76Custom, "Camera", "fOverShoulderMeleeCombatPosZ"); - - IniFiles.Instance.Remove(IniFile.F76Custom, "Camera", "bApplyCameraNodeAnimations"); - - bool alternativeMode = IniFiles.Instance.GetBool(IniFile.Config, "Preferences", "bAlternativeINIMode", false); - if (alternativeMode) - { - /* - IniFiles.Instance.Set(IniFile.F76, "Camera", "fOverShoulderPosX", 0.0f); - IniFiles.Instance.Set(IniFile.F76, "Camera", "fOverShoulderPosZ", 0.0f); - IniFiles.Instance.Set(IniFile.F76, "Camera", "fOverShoulderCombatPosX", 0.0f); - IniFiles.Instance.Set(IniFile.F76, "Camera", "fOverShoulderCombatAddY", 0.0f); - IniFiles.Instance.Set(IniFile.F76, "Camera", "fOverShoulderCombatPosZ", 0.0f); - IniFiles.Instance.Set(IniFile.F76, "Camera", "fOverShoulderMeleeCombatPosX", 0.0f); - IniFiles.Instance.Set(IniFile.F76, "Camera", "fOverShoulderMeleeCombatAddY", 0.0f); - IniFiles.Instance.Set(IniFile.F76, "Camera", "fOverShoulderMeleeCombatPosZ", 0.0f); - */ - IniFiles.Instance.Remove(IniFile.F76, "Camera", "fOverShoulderPosX"); - IniFiles.Instance.Remove(IniFile.F76, "Camera", "fOverShoulderPosZ"); - IniFiles.Instance.Remove(IniFile.F76, "Camera", "fOverShoulderCombatPosX"); - IniFiles.Instance.Remove(IniFile.F76, "Camera", "fOverShoulderCombatAddY"); - IniFiles.Instance.Remove(IniFile.F76, "Camera", "fOverShoulderCombatPosZ"); - IniFiles.Instance.Remove(IniFile.F76, "Camera", "fOverShoulderMeleeCombatPosX"); - IniFiles.Instance.Remove(IniFile.F76, "Camera", "fOverShoulderMeleeCombatAddY"); - IniFiles.Instance.Remove(IniFile.F76, "Camera", "fOverShoulderMeleeCombatPosZ"); - } + IniFiles.F76Custom.Remove("Camera", "fOverShoulderPosX"); + IniFiles.F76Custom.Remove("Camera", "fOverShoulderPosZ"); + IniFiles.F76Custom.Remove("Camera", "fOverShoulderCombatPosX"); + IniFiles.F76Custom.Remove("Camera", "fOverShoulderCombatAddY"); + IniFiles.F76Custom.Remove("Camera", "fOverShoulderCombatPosZ"); + IniFiles.F76Custom.Remove("Camera", "fOverShoulderMeleeCombatPosX"); + IniFiles.F76Custom.Remove("Camera", "fOverShoulderMeleeCombatAddY"); + IniFiles.F76Custom.Remove("Camera", "fOverShoulderMeleeCombatPosZ"); + IniFiles.F76Custom.Remove("Camera", "bApplyCameraNodeAnimations"); UpdateCameraPositionUI(); } private void buttonCameraPositionCenter_Click(object sender, EventArgs e) { - bool alternativeMode = IniFiles.Instance.GetBool(IniFile.Config, "Preferences", "bAlternativeINIMode", false); switch (camPosMode) { case CameraPositionMode.Unarmed: - IniFiles.Instance.Set(!alternativeMode ? IniFile.F76Custom : IniFile.F76, "Camera", "fOverShoulderPosX", 0); - IniFiles.Instance.Set(!alternativeMode ? IniFile.F76Custom : IniFile.F76, "Camera", "fOverShoulderPosZ", 0); + IniFiles.F76Custom.Set("Camera", "fOverShoulderPosX", 0); + IniFiles.F76Custom.Set("Camera", "fOverShoulderPosZ", 0); break; case CameraPositionMode.Combat: - IniFiles.Instance.Set(!alternativeMode ? IniFile.F76Custom : IniFile.F76, "Camera", "fOverShoulderCombatPosX", 0); + IniFiles.F76Custom.Set("Camera", "fOverShoulderCombatPosX", 0); //IniFiles.Instance.Set(IniFile.F76Custom, "Camera", "fOverShoulderCombatAddY", value); - IniFiles.Instance.Set(!alternativeMode ? IniFile.F76Custom : IniFile.F76, "Camera", "fOverShoulderCombatPosZ", 0); + IniFiles.F76Custom.Set("Camera", "fOverShoulderCombatPosZ", 0); break; case CameraPositionMode.MeleeCombat: - IniFiles.Instance.Set(!alternativeMode ? IniFile.F76Custom : IniFile.F76, "Camera", "fOverShoulderMeleeCombatPosX", 0); + IniFiles.F76Custom.Set("Camera", "fOverShoulderMeleeCombatPosX", 0); //IniFiles.Instance.Set(IniFile.F76Custom, "Camera", "fOverShoulderMeleeCombatAddY", value); - IniFiles.Instance.Set(!alternativeMode ? IniFile.F76Custom : IniFile.F76, "Camera", "fOverShoulderMeleeCombatPosZ", 0); + IniFiles.F76Custom.Set("Camera", "fOverShoulderMeleeCombatPosZ", 0); break; } this.checkBoxbApplyCameraNodeAnimations.Checked = false; - IniFiles.Instance.Set(!alternativeMode ? IniFile.F76Custom : IniFile.F76, "Camera", "bApplyCameraNodeAnimations", false); + IniFiles.F76Custom.Set("Camera", "bApplyCameraNodeAnimations", false); UpdateCameraPositionUI(); } @@ -248,5 +211,6 @@ private void radioButtonCameraPositionMeleeCombat_CheckedChanged(object sender, camPosMode = CameraPositionMode.MeleeCombat; UpdateCameraPositionUI(); } +#endif } } diff --git a/Fo76ini/Forms/Form1/Form1.Colors.cs b/Fo76ini/Forms/Form1/Form1.Colors.cs deleted file mode 100644 index d4ced1d..0000000 --- a/Fo76ini/Forms/Form1/Form1.Colors.cs +++ /dev/null @@ -1,217 +0,0 @@ -using IniParser.Model; -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows.Forms; - -namespace Fo76ini -{ - partial class Form1 - { - bool colorQuickboyIsDefault = true; // Depending on this value, the Quickboy values will be set or unset. - bool colorPAPipboyIsDefault = true; - - /// - /// This will set all values for the "Color" tab. - /// - private void ColorIni2Ui() - { - // Pip-Boy Color - this.colorPreviewPipboy.BackColor = this.PipboyColor; - - // Quick-Boy Color - this.colorPreviewQuickboy.BackColor = this.QuickboyColor; - this.colorQuickboyIsDefault = !IniFiles.Instance.Exists("Pipboy", "fQuickBoyEffectColorR"); - - // Power Armor Pip-Boy Color - this.colorPreviewPAPipboy.BackColor = this.PowerArmorPipboyColor; - this.colorPAPipboyIsDefault = !IniFiles.Instance.Exists("Pipboy", "fPAEffectColorR"); - } - - /// - /// This will write all changes made in the "Color" tab to the INI. - /// - private void ColorUi2Ini() - { - bool alternativeMode = IniFiles.Instance.GetBool(IniFile.Config, "Preferences", "bAlternativeINIMode", false); - - // Pip-Boy Color - this.PipboyColor = this.colorPreviewPipboy.BackColor; - - // Quick-Boy Color - if (!this.colorQuickboyIsDefault) - { - this.QuickboyColor = this.colorPreviewQuickboy.BackColor; - } - else - { - IniFiles.Instance.Remove(IniFile.F76Custom, "Pipboy", "fQuickBoyEffectColorR"); - IniFiles.Instance.Remove(IniFile.F76Custom, "Pipboy", "fQuickBoyEffectColorG"); - IniFiles.Instance.Remove(IniFile.F76Custom, "Pipboy", "fQuickBoyEffectColorB"); - if (alternativeMode) - { - IniFiles.Instance.Set(IniFile.F76, "Pipboy", "fQuickBoyEffectColorR", 0.97f); - IniFiles.Instance.Set(IniFile.F76, "Pipboy", "fQuickBoyEffectColorG", 0.94f); - IniFiles.Instance.Set(IniFile.F76, "Pipboy", "fQuickBoyEffectColorB", 0.72f); - } - } - - // Power Armor Pip-Boy Color - if (!this.colorPAPipboyIsDefault) - { - this.PowerArmorPipboyColor = this.colorPreviewPAPipboy.BackColor; - } - else - { - IniFiles.Instance.Remove(IniFile.F76Custom, "Pipboy", "fPAEffectColorR"); - IniFiles.Instance.Remove(IniFile.F76Custom, "Pipboy", "fPAEffectColorG"); - IniFiles.Instance.Remove(IniFile.F76Custom, "Pipboy", "fPAEffectColorB"); - if (alternativeMode) - { - IniFiles.Instance.Set(IniFile.F76, "Pipboy", "fPAEffectColorR", 1.0f); - IniFiles.Instance.Set(IniFile.F76, "Pipboy", "fPAEffectColorG", 0.82f); - IniFiles.Instance.Set(IniFile.F76, "Pipboy", "fPAEffectColorB", 0.41f); - } - } - } - - - - /* - * Getter & Setter - */ - - public Color PipboyColor - { - get - { - float r = Utils.Clamp(IniFiles.Instance.GetFloat("Pipboy", "fPipboyEffectColorR", 0.1f), 0f, 1f); - float g = Utils.Clamp(IniFiles.Instance.GetFloat("Pipboy", "fPipboyEffectColorG", 1.0f), 0f, 1f); - float b = Utils.Clamp(IniFiles.Instance.GetFloat("Pipboy", "fPipboyEffectColorB", 0.5f), 0f, 1f); - return Color.FromArgb( - Convert.ToInt32(r * 255), - Convert.ToInt32(g * 255), - Convert.ToInt32(b * 255) - ); - } - set - { - float r = Convert.ToSingle(value.R) / 255f; - float g = Convert.ToSingle(value.G) / 255f; - float b = Convert.ToSingle(value.B) / 255f; - IniFiles.Instance.Set(IniFile.F76Prefs, "Pipboy", "fPipboyEffectColorR", r); - IniFiles.Instance.Set(IniFile.F76Prefs, "Pipboy", "fPipboyEffectColorG", g); - IniFiles.Instance.Set(IniFile.F76Prefs, "Pipboy", "fPipboyEffectColorB", b); - } - } - - - public Color QuickboyColor - { - get - { - float r = Utils.Clamp(IniFiles.Instance.GetFloat("Pipboy", "fQuickBoyEffectColorR", 1.0f), 0f, 1f); - float g = Utils.Clamp(IniFiles.Instance.GetFloat("Pipboy", "fQuickBoyEffectColorG", 0.78f), 0f, 1f); - float b = Utils.Clamp(IniFiles.Instance.GetFloat("Pipboy", "fQuickBoyEffectColorB", 0.0f), 0f, 1f); - return Color.FromArgb( - Convert.ToInt32(r * 255), - Convert.ToInt32(g * 255), - Convert.ToInt32(b * 255) - ); - } - set - { - float r = Convert.ToSingle(value.R) / 255f; - float g = Convert.ToSingle(value.G) / 255f; - float b = Convert.ToSingle(value.B) / 255f; - bool alternativeMode = IniFiles.Instance.GetBool(IniFile.Config, "Preferences", "bAlternativeINIMode", false); - IniFiles.Instance.Set(!alternativeMode ? IniFile.F76Custom : IniFile.F76, "Pipboy", "fQuickBoyEffectColorR", r); - IniFiles.Instance.Set(!alternativeMode ? IniFile.F76Custom : IniFile.F76, "Pipboy", "fQuickBoyEffectColorG", g); - IniFiles.Instance.Set(!alternativeMode ? IniFile.F76Custom : IniFile.F76, "Pipboy", "fQuickBoyEffectColorB", b); - } - } - - - public Color PowerArmorPipboyColor - { - get - { - float r = Utils.Clamp(IniFiles.Instance.GetFloat("Pipboy", "fPAEffectColorR", 1.0f), 0f, 1f); - float g = Utils.Clamp(IniFiles.Instance.GetFloat("Pipboy", "fPAEffectColorG", 0.78f), 0f, 1f); - float b = Utils.Clamp(IniFiles.Instance.GetFloat("Pipboy", "fPAEffectColorB", 0.0f), 0f, 1f); - return Color.FromArgb( - Convert.ToInt32(r * 255), - Convert.ToInt32(g * 255), - Convert.ToInt32(b * 255) - ); - } - set - { - float r = Convert.ToSingle(value.R) / 255f; - float g = Convert.ToSingle(value.G) / 255f; - float b = Convert.ToSingle(value.B) / 255f; - bool alternativeMode = IniFiles.Instance.GetBool(IniFile.Config, "Preferences", "bAlternativeINIMode", false); - IniFiles.Instance.Set(!alternativeMode ? IniFile.F76Custom : IniFile.F76, "Pipboy", "fPAEffectColorR", r); - IniFiles.Instance.Set(!alternativeMode ? IniFile.F76Custom : IniFile.F76, "Pipboy", "fPAEffectColorG", g); - IniFiles.Instance.Set(!alternativeMode ? IniFile.F76Custom : IniFile.F76, "Pipboy", "fPAEffectColorB", b); - } - } - - - - - /* - * Event handler - */ - - private void buttonColorPickPipboy_Click(object sender, EventArgs e) - { - // Pip-Boy Color - if (this.colorDialog.ShowDialog() == DialogResult.OK) - this.colorPreviewPipboy.BackColor = this.colorDialog.Color; - } - - private void buttonColorResetPipboy_Click(object sender, EventArgs e) - { - // Pip-Boy Color - this.colorPreviewPipboy.BackColor = Color.FromArgb(26, 255, 128); - } - - private void buttonColorPickQuickboy_Click(object sender, EventArgs e) - { - // Quick-Boy Color - if (this.colorDialog.ShowDialog() == DialogResult.OK) - { - this.colorPreviewQuickboy.BackColor = this.colorDialog.Color; - this.colorQuickboyIsDefault = false; - } - } - - private void buttonColorResetQuickboy_Click(object sender, EventArgs e) - { - // Quick-Boy Color - this.colorPreviewQuickboy.BackColor = Color.FromArgb(255, 200, 0); // These are guessed - this.colorQuickboyIsDefault = true; - } - - private void buttonColorPickPAPipboy_Click(object sender, EventArgs e) - { - // Power armor color - if (this.colorDialog.ShowDialog() == DialogResult.OK) - { - this.colorPreviewPAPipboy.BackColor = this.colorDialog.Color; - this.colorPAPipboyIsDefault = false; - } - } - - private void buttonColorResetPAPipboy_Click(object sender, EventArgs e) - { - // Power armor color - this.colorPreviewPAPipboy.BackColor = Color.FromArgb(255, 200, 0); // These are guessed - this.colorPAPipboyIsDefault = true; - } - } -} diff --git a/Fo76ini/Forms/Form1/Form1.Designer.cs b/Fo76ini/Forms/Form1/Form1.Designer.cs index 397ba43..786a7ae 100644 --- a/Fo76ini/Forms/Form1/Form1.Designer.cs +++ b/Fo76ini/Forms/Form1/Form1.Designer.cs @@ -36,22 +36,15 @@ private void InitializeComponent() this.labelFirstPersonFOV = new System.Windows.Forms.Label(); this.labelWorldFOV = new System.Windows.Forms.Label(); this.labelADSFOV = new System.Windows.Forms.Label(); - this.labelPipboyColor = new System.Windows.Forms.Label(); - this.labelQuickboyColor = new System.Windows.Forms.Label(); - this.label1 = new System.Windows.Forms.Label(); this.radioButtonPipboy = new System.Windows.Forms.RadioButton(); this.radioButtonQuickboy = new System.Windows.Forms.RadioButton(); this.numPipboyTargetWidth = new System.Windows.Forms.NumericUpDown(); this.numPipboyTargetHeight = new System.Windows.Forms.NumericUpDown(); this.buttonPipboyTargetReset = new System.Windows.Forms.Button(); this.buttonPipboyTargetSetRecommended = new System.Windows.Forms.Button(); - this.labelDisplayMode = new System.Windows.Forms.Label(); this.numCustomResH = new System.Windows.Forms.NumericUpDown(); this.numCustomResW = new System.Windows.Forms.NumericUpDown(); - this.checkBoxTopMostWindow = new System.Windows.Forms.CheckBox(); - this.labelResolution = new System.Windows.Forms.Label(); this.checkBoxAlwaysActive = new System.Windows.Forms.CheckBox(); - this.labelCustomResolution = new System.Windows.Forms.Label(); this.checkBoxFixHUDFor5_4and4_3 = new System.Windows.Forms.CheckBox(); this.labelAntiAliasing = new System.Windows.Forms.Label(); this.checkBoxVSync = new System.Windows.Forms.CheckBox(); @@ -62,25 +55,12 @@ private void InitializeComponent() this.checkBoxLensFlare = new System.Windows.Forms.CheckBox(); this.checkBoxRadialBlur = new System.Windows.Forms.CheckBox(); this.checkBoxMotionBlur = new System.Windows.Forms.CheckBox(); - this.checkBoxDepthOfField = new System.Windows.Forms.CheckBox(); this.checkBoxAmbientOcclusion = new System.Windows.Forms.CheckBox(); this.checkBoxWaterDisplacement = new System.Windows.Forms.CheckBox(); this.labelShadowTextureResolution = new System.Windows.Forms.Label(); this.labelShadowBlurriness = new System.Windows.Forms.Label(); this.checkBoxGodrays = new System.Windows.Forms.CheckBox(); this.checkBoxGrass = new System.Windows.Forms.CheckBox(); - this.checkBoxIntroVideos = new System.Windows.Forms.CheckBox(); - this.checkBoxShowSplash = new System.Windows.Forms.CheckBox(); - this.checkBoxShowDamageNumbersA = new System.Windows.Forms.CheckBox(); - this.checkBoxShowDamageNumbersNW = new System.Windows.Forms.CheckBox(); - this.checkBoxShowCompass = new System.Windows.Forms.CheckBox(); - this.checkBoxAutoApply = new System.Windows.Forms.CheckBox(); - this.checkBoxSkipBackupQuestion = new System.Windows.Forms.CheckBox(); - this.checkBoxQuitOnGameLaunch = new System.Windows.Forms.CheckBox(); - this.checkBoxReadOnly = new System.Windows.Forms.CheckBox(); - this.checkBoxMultipleGameEditionsUsed = new System.Windows.Forms.CheckBox(); - this.checkBoxDenyNTFSWritePermission = new System.Windows.Forms.CheckBox(); - this.checkBoxFixMouseSensitivity = new System.Windows.Forms.CheckBox(); this.checkBoxFixAimSensitivity = new System.Windows.Forms.CheckBox(); this.checkBoxMouseAcceleration = new System.Windows.Forms.CheckBox(); this.checkBoxGamepadRumble = new System.Windows.Forms.CheckBox(); @@ -109,39 +89,96 @@ private void InitializeComponent() this.checkBoxPushToTalk = new System.Windows.Forms.CheckBox(); this.checkBoxMouseInvertY = new System.Windows.Forms.CheckBox(); this.checkBoxMouseInvertX = new System.Windows.Forms.CheckBox(); - this.checkBoxEnableQuestAutoTrackMain = new System.Windows.Forms.CheckBox(); - this.checkBoxEnableQuestAutoTrackSide = new System.Windows.Forms.CheckBox(); - this.checkBoxEnableQuestAutoTrackMisc = new System.Windows.Forms.CheckBox(); - this.checkBoxEnableQuestAutoTrackEvent = new System.Windows.Forms.CheckBox(); - this.checkBoxEnableQuestAutoTrackDaily = new System.Windows.Forms.CheckBox(); this.checkBoxDialogueHistory = new System.Windows.Forms.CheckBox(); - this.checkBoxEnablePowerArmorHUD = new System.Windows.Forms.CheckBox(); - this.checkBoxShowCrosshair = new System.Windows.Forms.CheckBox(); - this.checkBoxItemRarityColorsNW = new System.Windows.Forms.CheckBox(); - this.checkBoxShowPublicTeamNotifications = new System.Windows.Forms.CheckBox(); - this.checkBoxShowFloatingQuestMarkers = new System.Windows.Forms.CheckBox(); this.sliderFloatingQuestMarkersDistance = new System.Windows.Forms.TrackBar(); - this.checkBoxShowFloatingQuestText = new System.Windows.Forms.CheckBox(); this.sliderConversationHistorySize = new System.Windows.Forms.TrackBar(); - this.checkBoxShowOtherPlayersNames = new System.Windows.Forms.CheckBox(); this.sliderHUDOpacity = new System.Windows.Forms.TrackBar(); this.labelShowActiveEffectsOnHUD = new System.Windows.Forms.Label(); this.labelfDefaultFOV = new System.Windows.Forms.Label(); - this.label2 = new System.Windows.Forms.Label(); - this.sliderfBlendSplitDirShadow = new System.Windows.Forms.TrackBar(); this.labelSwitchDelay = new System.Windows.Forms.Label(); this.labelPitchZoomOutMaxDist = new System.Windows.Forms.Label(); this.labelCameraDistanceMaximum = new System.Windows.Forms.Label(); this.labelCameraDistanceMinimum = new System.Windows.Forms.Label(); this.checkBoxbApplyCameraNodeAnimations = new System.Windows.Forms.CheckBox(); + this.checkBoxDisableGore = new System.Windows.Forms.CheckBox(); + this.labelPhotomodeTranslationSpeed = new System.Windows.Forms.Label(); + this.labelPhotomodeRange = new System.Windows.Forms.Label(); + this.labelPhotomodeRotationSpeed = new System.Windows.Forms.Label(); + this.checkBoxScreenSpaceReflections = new System.Windows.Forms.CheckBox(); + this.sliderfBlendSplitDirShadow = new System.Windows.Forms.TrackBar(); + this.labeliDirShadowSplits = new System.Windows.Forms.Label(); + this.checkBoxTopMostWindow = new System.Windows.Forms.CheckBox(); this.labelScreenshotIndex = new System.Windows.Forms.Label(); - this.checkBoxAlternativeINIMode = new System.Windows.Forms.CheckBox(); - this.checkBoxAutoSignin = new System.Windows.Forms.CheckBox(); - this.checkBoxDisableSteam = new System.Windows.Forms.CheckBox(); + this.labelPipboyColor = new System.Windows.Forms.Label(); + this.labelQuickboyColor = new System.Windows.Forms.Label(); + this.labelPowerArmorColor = new System.Windows.Forms.Label(); + this.checkBoxDepthOfField = new System.Windows.Forms.CheckBox(); + this.labelDisplayMode = new System.Windows.Forms.Label(); + this.checkBoxFixMouseSensitivity = new System.Windows.Forms.CheckBox(); + this.checkBoxEnableQuestAutoTrackMain = new System.Windows.Forms.CheckBox(); + this.checkBoxEnableQuestAutoTrackSide = new System.Windows.Forms.CheckBox(); + this.checkBoxEnableQuestAutoTrackMisc = new System.Windows.Forms.CheckBox(); + this.checkBoxEnableQuestAutoTrackEvent = new System.Windows.Forms.CheckBox(); + this.checkBoxEnableQuestAutoTrackDaily = new System.Windows.Forms.CheckBox(); + this.checkBoxEnablePowerArmorHUD = new System.Windows.Forms.CheckBox(); + this.checkBoxShowOtherPlayersNames = new System.Windows.Forms.CheckBox(); + this.labelResolution = new System.Windows.Forms.Label(); + this.checkBoxIntroVideos = new System.Windows.Forms.CheckBox(); + this.checkBoxShowDamageNumbersA = new System.Windows.Forms.CheckBox(); + this.checkBoxShowDamageNumbersNW = new System.Windows.Forms.CheckBox(); + this.checkBoxShowCompass = new System.Windows.Forms.CheckBox(); + this.checkBoxShowCrosshair = new System.Windows.Forms.CheckBox(); + this.checkBoxItemRarityColorsNW = new System.Windows.Forms.CheckBox(); + this.checkBoxShowPublicTeamNotifications = new System.Windows.Forms.CheckBox(); + this.checkBoxShowFloatingQuestMarkers = new System.Windows.Forms.CheckBox(); + this.checkBoxShowFloatingQuestText = new System.Windows.Forms.CheckBox(); + this.checkBoxSkipSplash = new System.Windows.Forms.CheckBox(); this.colorDialog = new System.Windows.Forms.ColorDialog(); this.timerCheckFiles = new System.Windows.Forms.Timer(this.components); this.openFileDialogGamePath = new System.Windows.Forms.OpenFileDialog(); this.tabPageCamera = new System.Windows.Forms.TabPage(); + this.panel2 = new System.Windows.Forms.Panel(); + this.groupBoxCameraPosition = new System.Windows.Forms.GroupBox(); + this.groupBox3 = new System.Windows.Forms.GroupBox(); + this.numfOverShoulderMeleeCombatAddY = new System.Windows.Forms.NumericUpDown(); + this.labelfOverShoulderMeleeCombatAddY = new System.Windows.Forms.Label(); + this.numfOverShoulderMeleeCombatPosX = new System.Windows.Forms.NumericUpDown(); + this.numfOverShoulderMeleeCombatPosZ = new System.Windows.Forms.NumericUpDown(); + this.trackBarfOverShoulderMeleeCombatAddY = new System.Windows.Forms.TrackBar(); + this.labelfOverShoulderMeleeCombatPosX = new System.Windows.Forms.Label(); + this.trackBarfOverShoulderMeleeCombatPosX = new System.Windows.Forms.TrackBar(); + this.labelfOverShoulderMeleeCombatPosZ = new System.Windows.Forms.Label(); + this.trackBarfOverShoulderMeleeCombatPosZ = new System.Windows.Forms.TrackBar(); + this.groupBox2 = new System.Windows.Forms.GroupBox(); + this.numfOverShoulderCombatAddY = new System.Windows.Forms.NumericUpDown(); + this.numfOverShoulderCombatPosX = new System.Windows.Forms.NumericUpDown(); + this.numfOverShoulderCombatPosZ = new System.Windows.Forms.NumericUpDown(); + this.labelfOverShoulderCombatAddY = new System.Windows.Forms.Label(); + this.trackBarfOverShoulderCombatAddY = new System.Windows.Forms.TrackBar(); + this.labelfOverShoulderCombatPosX = new System.Windows.Forms.Label(); + this.trackBarfOverShoulderCombatPosX = new System.Windows.Forms.TrackBar(); + this.labelfOverShoulderCombatPosZ = new System.Windows.Forms.Label(); + this.trackBarfOverShoulderCombatPosZ = new System.Windows.Forms.TrackBar(); + this.buttonCameraPositionReset = new System.Windows.Forms.Button(); + this.groupBoxUnarmedCameraPosition = new System.Windows.Forms.GroupBox(); + this.numfOverShoulderPosX = new System.Windows.Forms.NumericUpDown(); + this.numfOverShoulderPosZ = new System.Windows.Forms.NumericUpDown(); + this.labelfOverShoulderPosX = new System.Windows.Forms.Label(); + this.trackBarfOverShoulderPosX = new System.Windows.Forms.TrackBar(); + this.labelfOverShoulderPosZ = new System.Windows.Forms.Label(); + this.trackBarfOverShoulderPosZ = new System.Windows.Forms.TrackBar(); + this.groupBoxSelfieCamera = new System.Windows.Forms.GroupBox(); + this.trackBarPhotomodeRange = new System.Windows.Forms.TrackBar(); + this.numericUpDownPhotomodeRotationSpeed = new System.Windows.Forms.NumericUpDown(); + this.trackBarPhotomodeRotationSpeed = new System.Windows.Forms.TrackBar(); + this.numericUpDownPhotomodeRange = new System.Windows.Forms.NumericUpDown(); + this.numericUpDownPhotomodeTranslationSpeed = new System.Windows.Forms.NumericUpDown(); + this.trackBarPhotomodeTranslationSpeed = new System.Windows.Forms.TrackBar(); + this.groupBoxFieldOfView = new System.Windows.Forms.GroupBox(); + this.numfDefaultFOV = new System.Windows.Forms.NumericUpDown(); + this.numADSFOV = new System.Windows.Forms.NumericUpDown(); + this.numWorldFOV = new System.Windows.Forms.NumericUpDown(); + this.numFirstPersonFOV = new System.Windows.Forms.NumericUpDown(); this.groupBoxCameraOptions = new System.Windows.Forms.GroupBox(); this.numCameraSwitchDelay = new System.Windows.Forms.NumericUpDown(); this.groupBoxCameraDistance = new System.Windows.Forms.GroupBox(); @@ -151,42 +188,34 @@ private void InitializeComponent() this.numCameraDistanceMinimum = new System.Windows.Forms.NumericUpDown(); this.sliderCameraDistanceMaximum = new System.Windows.Forms.TrackBar(); this.sliderCameraDistanceMinimum = new System.Windows.Forms.TrackBar(); - this.groupBoxCameraPositionWIP = new System.Windows.Forms.GroupBox(); - this.buttonCameraPositionCenter = new System.Windows.Forms.Button(); - this.buttonCameraPositionReset = new System.Windows.Forms.Button(); - this.labelCameraPositionPlayer = new System.Windows.Forms.Label(); - this.labelCameraPositionFor = new System.Windows.Forms.Label(); - this.radioButtonCameraPositionMeleeCombat = new System.Windows.Forms.RadioButton(); - this.radioButtonCameraPositionCombat = new System.Windows.Forms.RadioButton(); - this.radioButtonCameraPositionUnarmed = new System.Windows.Forms.RadioButton(); - this.labelCameraFurther = new System.Windows.Forms.Label(); - this.labelCameraCloser = new System.Windows.Forms.Label(); - this.labelCameraUp = new System.Windows.Forms.Label(); - this.labelCameraDown = new System.Windows.Forms.Label(); - this.labelCameraRight = new System.Windows.Forms.Label(); - this.labelCameraLeft = new System.Windows.Forms.Label(); - this.trackBarCameraX = new System.Windows.Forms.TrackBar(); - this.trackBarCameraZ = new System.Windows.Forms.TrackBar(); - this.trackBarCameraY = new System.Windows.Forms.TrackBar(); - this.pictureBoxVaultBoy = new System.Windows.Forms.PictureBox(); - this.groupBoxFieldOfView = new System.Windows.Forms.GroupBox(); - this.numfDefaultFOV = new System.Windows.Forms.NumericUpDown(); - this.numADSFOV = new System.Windows.Forms.NumericUpDown(); - this.numWorldFOV = new System.Windows.Forms.NumericUpDown(); - this.numFirstPersonFOV = new System.Windows.Forms.NumericUpDown(); - this.groupBoxCameraVanity = new System.Windows.Forms.GroupBox(); this.tabPagePipBoy = new System.Windows.Forms.TabPage(); + this.groupBoxPipboyColorPresets = new System.Windows.Forms.GroupBox(); + this.colorPreviewPresetFo76Green = new Fo76ini.Forms.Form1.ColorPreview(); + this.colorPreviewPresetFo3Green = new Fo76ini.Forms.Form1.ColorPreview(); + this.colorPreviewPresetFo3White = new Fo76ini.Forms.Form1.ColorPreview(); + this.buttonPresetFo3Green = new System.Windows.Forms.Button(); + this.buttonPresetFo3White = new System.Windows.Forms.Button(); + this.buttonPresetFoNVAmber = new System.Windows.Forms.Button(); + this.buttonPresetFo76Green = new System.Windows.Forms.Button(); + this.colorPreviewPresetFoNVAmber = new Fo76ini.Forms.Form1.ColorPreview(); + this.colorPreviewPresetFo3Blue = new Fo76ini.Forms.Form1.ColorPreview(); + this.buttonPresetFo4Green = new System.Windows.Forms.Button(); + this.colorPreviewPresetFo4Green = new Fo76ini.Forms.Form1.ColorPreview(); + this.buttonPresetFo3Blue = new System.Windows.Forms.Button(); + this.groupBoxPipboyColorPreview = new System.Windows.Forms.GroupBox(); + this.labelPipboyColorPreviewNotice = new System.Windows.Forms.Label(); + this.pictureBoxPipboyPreview = new System.Windows.Forms.PictureBox(); this.groupBoxPipboyResolution = new System.Windows.Forms.GroupBox(); this.labelPipboyResolutionSideNote = new System.Windows.Forms.Label(); this.labelPipboyResolutionSpacer = new System.Windows.Forms.Label(); this.groupBoxPipboyMode = new System.Windows.Forms.GroupBox(); this.groupBoxPipboyColors = new System.Windows.Forms.GroupBox(); - this.colorPreviewPAPipboy = new System.Windows.Forms.PictureBox(); + this.colorPreviewQuickboy = new Fo76ini.Forms.Form1.ColorPreview(); + this.colorPreviewPAPipboy = new Fo76ini.Forms.Form1.ColorPreview(); + this.colorPreviewPipboy = new Fo76ini.Forms.Form1.ColorPreview(); this.buttonColorPickPAPipboy = new System.Windows.Forms.Button(); this.buttonColorResetPipboy = new System.Windows.Forms.Button(); this.buttonColorResetPAPipboy = new System.Windows.Forms.Button(); - this.colorPreviewPipboy = new System.Windows.Forms.PictureBox(); - this.colorPreviewQuickboy = new System.Windows.Forms.PictureBox(); this.buttonColorPickQuickboy = new System.Windows.Forms.Button(); this.buttonColorResetQuickboy = new System.Windows.Forms.Button(); this.buttonColorPickPipboy = new System.Windows.Forms.Button(); @@ -198,6 +227,7 @@ private void InitializeComponent() this.tabPageVideo = new System.Windows.Forms.TabPage(); this.panel3 = new System.Windows.Forms.Panel(); this.groupBoxGraphics = new System.Windows.Forms.GroupBox(); + this.groupBoxGraphicEffects = new System.Windows.Forms.GroupBox(); this.groupBoxTAASharpening = new System.Windows.Forms.GroupBox(); this.labelTAAPostSharpen = new System.Windows.Forms.Label(); this.numTAAPostSharpen = new System.Windows.Forms.NumericUpDown(); @@ -217,9 +247,6 @@ private void InitializeComponent() this.labelLODObjects = new System.Windows.Forms.Label(); this.groupBoxLighting = new System.Windows.Forms.GroupBox(); this.groupBoxShadows = new System.Windows.Forms.GroupBox(); - this.numfBlendSplitDirShadow = new System.Windows.Forms.NumericUpDown(); - this.labelfBlendSplitDirShadow = new System.Windows.Forms.Label(); - this.comboBoxiDirShadowSplits = new System.Windows.Forms.ComboBox(); this.comboBoxShadowBlurriness = new System.Windows.Forms.ComboBox(); this.numShadowDistance = new System.Windows.Forms.NumericUpDown(); this.labelShadowDistance = new System.Windows.Forms.Label(); @@ -232,6 +259,7 @@ private void InitializeComponent() this.comboBoxDisplayMode = new System.Windows.Forms.ComboBox(); this.comboBoxResolution = new System.Windows.Forms.ComboBox(); this.buttonDetectResolution = new System.Windows.Forms.Button(); + this.labelCustomResolution = new System.Windows.Forms.Label(); this.labelCustomResolutionSpacer = new System.Windows.Forms.Label(); this.tabPageGeneral = new System.Windows.Forms.TabPage(); this.panel4 = new System.Windows.Forms.Panel(); @@ -244,15 +272,26 @@ private void InitializeComponent() this.groupBoxQuests = new System.Windows.Forms.GroupBox(); this.groupBoxMainMenu = new System.Windows.Forms.GroupBox(); this.groupBoxLogin = new System.Windows.Forms.GroupBox(); - this.radioButtonAccount8 = new System.Windows.Forms.RadioButton(); - this.radioButtonAccount7 = new System.Windows.Forms.RadioButton(); - this.radioButtonAccount6 = new System.Windows.Forms.RadioButton(); - this.radioButtonAccount5 = new System.Windows.Forms.RadioButton(); - this.radioButtonAccount4 = new System.Windows.Forms.RadioButton(); - this.radioButtonAccount3 = new System.Windows.Forms.RadioButton(); - this.radioButtonAccount2 = new System.Windows.Forms.RadioButton(); + this.groupBoxLoginProfiles = new System.Windows.Forms.GroupBox(); + this.radioButtonAccountNone = new System.Windows.Forms.RadioButton(); this.radioButtonAccount1 = new System.Windows.Forms.RadioButton(); - this.labelAccountProfiles = new System.Windows.Forms.Label(); + this.radioButtonAccount16 = new System.Windows.Forms.RadioButton(); + this.radioButtonAccount2 = new System.Windows.Forms.RadioButton(); + this.radioButtonAccount15 = new System.Windows.Forms.RadioButton(); + this.radioButtonAccount3 = new System.Windows.Forms.RadioButton(); + this.radioButtonAccount14 = new System.Windows.Forms.RadioButton(); + this.radioButtonAccount4 = new System.Windows.Forms.RadioButton(); + this.radioButtonAccount13 = new System.Windows.Forms.RadioButton(); + this.radioButtonAccount5 = new System.Windows.Forms.RadioButton(); + this.radioButtonAccount12 = new System.Windows.Forms.RadioButton(); + this.radioButtonAccount6 = new System.Windows.Forms.RadioButton(); + this.radioButtonAccount11 = new System.Windows.Forms.RadioButton(); + this.radioButtonAccount7 = new System.Windows.Forms.RadioButton(); + this.radioButtonAccount10 = new System.Windows.Forms.RadioButton(); + this.radioButtonAccount8 = new System.Windows.Forms.RadioButton(); + this.radioButtonAccount9 = new System.Windows.Forms.RadioButton(); + this.checkBoxAutoSignin = new System.Windows.Forms.CheckBox(); + this.checkBoxEnableSteam = new System.Windows.Forms.CheckBox(); this.labelCredentialsExplanation = new System.Windows.Forms.Label(); this.textBoxPassword = new System.Windows.Forms.TextBox(); this.textBoxUserName = new System.Windows.Forms.TextBox(); @@ -260,6 +299,9 @@ private void InitializeComponent() this.labelPassword = new System.Windows.Forms.Label(); this.labelUserName = new System.Windows.Forms.Label(); this.tabPageInfo = new System.Windows.Forms.TabPage(); + this.groupBoxSettings = new System.Windows.Forms.GroupBox(); + this.linkLabelOpenSettings = new System.Windows.Forms.LinkLabel(); + this.labelSettingsNotice = new System.Windows.Forms.Label(); this.linkLabelWhatsNew = new System.Windows.Forms.LinkLabel(); this.linkLabelAttribution = new System.Windows.Forms.LinkLabel(); this.panelUpdate = new System.Windows.Forms.Panel(); @@ -268,46 +310,6 @@ private void InitializeComponent() this.pictureBoxUpdateButton = new System.Windows.Forms.PictureBox(); this.labelNWModeActive = new System.Windows.Forms.Label(); this.pictureBoxSpinnerCheckForUpdates = new System.Windows.Forms.PictureBox(); - this.panel1 = new System.Windows.Forms.Panel(); - this.groupBoxNuclearWinterMode = new System.Windows.Forms.GroupBox(); - this.checkBoxNWAutoDeployMods = new System.Windows.Forms.CheckBox(); - this.labelNWmodoptions = new System.Windows.Forms.Label(); - this.labelNWdlloptions = new System.Windows.Forms.Label(); - this.labelNWinioptions = new System.Windows.Forms.Label(); - this.radioButtonNWRemoveLists = new System.Windows.Forms.RadioButton(); - this.radioButtonNWRenameINI = new System.Windows.Forms.RadioButton(); - this.checkBoxNWAutoDisableMods = new System.Windows.Forms.CheckBox(); - this.checkBoxNWRenameDLL = new System.Windows.Forms.CheckBox(); - this.groupBoxLocalization = new System.Windows.Forms.GroupBox(); - this.buttonRefreshLanguage = new System.Windows.Forms.Button(); - this.pictureBoxSpinnerDownloadLanguages = new System.Windows.Forms.PictureBox(); - this.labelOutdatedLanguage = new System.Windows.Forms.Label(); - this.labelLanguage = new System.Windows.Forms.Label(); - this.buttonDownloadLanguages = new System.Windows.Forms.Button(); - this.comboBoxLanguage = new System.Windows.Forms.ComboBox(); - this.groupBoxGameEdition = new System.Windows.Forms.GroupBox(); - this.pictureBoxMSStore = new System.Windows.Forms.PictureBox(); - this.pictureBoxSteam = new System.Windows.Forms.PictureBox(); - this.pictureBoxBethesdaNetPTS = new System.Windows.Forms.PictureBox(); - this.pictureBoxBethesdaNet = new System.Windows.Forms.PictureBox(); - this.radioButtonEditionMSStore = new System.Windows.Forms.RadioButton(); - this.radioButtonEditionBethesdaNetPTS = new System.Windows.Forms.RadioButton(); - this.radioButtonEditionSteam = new System.Windows.Forms.RadioButton(); - this.radioButtonEditionBethesdaNet = new System.Windows.Forms.RadioButton(); - this.groupBoxLaunchOptions = new System.Windows.Forms.GroupBox(); - this.labelLaunchOptionMSStoreNotice = new System.Windows.Forms.Label(); - this.labelLaunchOptionTip = new System.Windows.Forms.Label(); - this.radioButtonLaunchViaExecutable = new System.Windows.Forms.RadioButton(); - this.radioButtonLaunchViaLink = new System.Windows.Forms.RadioButton(); - this.groupBoxGamePaths = new System.Windows.Forms.GroupBox(); - this.labelGamePath = new System.Windows.Forms.Label(); - this.textBoxGamePath = new System.Windows.Forms.TextBox(); - this.buttonPickGamePath = new System.Windows.Forms.Button(); - this.groupBoxOptions = new System.Windows.Forms.GroupBox(); - this.groupBoxBehavior = new System.Windows.Forms.GroupBox(); - this.checkBoxPlayNotificationSound = new System.Windows.Forms.CheckBox(); - this.checkBoxIgnoreUpdates = new System.Windows.Forms.CheckBox(); - this.checkBoxOpenManageModsOnLaunch = new System.Windows.Forms.CheckBox(); this.labelGameEdition = new System.Windows.Forms.Label(); this.pictureBoxGameEdition = new System.Windows.Forms.PictureBox(); this.pictureBox1 = new System.Windows.Forms.PictureBox(); @@ -367,20 +369,34 @@ private void InitializeComponent() this.comboBoxCustomFile = new System.Windows.Forms.ComboBox(); this.labelCustomFile = new System.Windows.Forms.Label(); this.textBoxCustom = new System.Windows.Forms.TextBox(); + this.tabPageDangerZone = new System.Windows.Forms.TabPage(); + this.groupBoxVideoDZ = new System.Windows.Forms.GroupBox(); + this.groupBoxShadows2 = new System.Windows.Forms.GroupBox(); + this.comboBoxiDirShadowSplits = new System.Windows.Forms.ComboBox(); + this.labelfBlendSplitDirShadow = new System.Windows.Forms.Label(); + this.numfBlendSplitDirShadow = new System.Windows.Forms.NumericUpDown(); + this.groupBox4 = new System.Windows.Forms.GroupBox(); + this.backgroundWorkerLoadGallery = new System.ComponentModel.BackgroundWorker(); + this.backgroundWorkerGetLatestVersion = new System.ComponentModel.BackgroundWorker(); + this.contextMenuStripGallery = new System.Windows.Forms.ContextMenuStrip(this.components); + this.openToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.openFolderToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.toolStripSeparator7 = new System.Windows.Forms.ToolStripSeparator(); + this.cutToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.copyToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.toolStripSeparator8 = new System.Windows.Forms.ToolStripSeparator(); + this.deleteToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.toolStripSeparator3 = new System.Windows.Forms.ToolStripSeparator(); + this.toolStripSeparator9 = new System.Windows.Forms.ToolStripSeparator(); this.toolStrip1 = new System.Windows.Forms.ToolStrip(); this.toolStripButtonApply = new System.Windows.Forms.ToolStripButton(); - this.toolStripButtonToggleNuclearWinterMode = new System.Windows.Forms.ToolStripButton(); - this.toolStripSplitButtonLaunchGame = new System.Windows.Forms.ToolStripSplitButton(); - this.launchViaSteamToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.launchViaBethesdanetToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.launchViaBethesdanetPTSToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.toolStripSeparator1 = new System.Windows.Forms.ToolStripSeparator(); + this.toolStripButtonLaunchGame = new System.Windows.Forms.ToolStripButton(); this.toolStripButtonManageMods = new System.Windows.Forms.ToolStripButton(); - this.toolStripSeparator2 = new System.Windows.Forms.ToolStripSeparator(); + this.toolStripButtonToggleNuclearWinterMode = new System.Windows.Forms.ToolStripButton(); + this.toolStripButtonSettings = new System.Windows.Forms.ToolStripButton(); this.toolStripSplitButtonUpdate = new System.Windows.Forms.ToolStripSplitButton(); this.updateToolToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.checkForUpdatesToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.downloadUpdateLanguageFilesToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.showUpdaterlogtxtToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.toolStripDropDownButtonExplore = new System.Windows.Forms.ToolStripDropDownButton(); this.gameFolderToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); @@ -396,21 +412,13 @@ private void InitializeComponent() this.editFallout76iniToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.editFallout76PrefsiniToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.editFallout76CustominiToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.toolStripSeparator3 = new System.Windows.Forms.ToolStripSeparator(); - this.toolStripButtonNexusMods = new System.Windows.Forms.ToolStripButton(); - this.backgroundWorkerLoadGallery = new System.ComponentModel.BackgroundWorker(); - this.backgroundWorkerGetLatestVersion = new System.ComponentModel.BackgroundWorker(); - this.backgroundWorkerDownloadLanguages = new System.ComponentModel.BackgroundWorker(); - this.contextMenuStripGallery = new System.Windows.Forms.ContextMenuStrip(this.components); - this.openToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.openFolderToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.toolStripSeparator7 = new System.Windows.Forms.ToolStripSeparator(); - this.cutToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.copyToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.toolStripSeparator8 = new System.Windows.Forms.ToolStripSeparator(); - this.deleteToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.backgroundWorkerEnableNWMode = new System.ComponentModel.BackgroundWorker(); - this.backgroundWorkerDisableNWMode = new System.ComponentModel.BackgroundWorker(); + this.statusStrip1 = new System.Windows.Forms.StatusStrip(); + this.toolStripStatusLabelGame = new System.Windows.Forms.ToolStripStatusLabel(); + this.toolStripStatusLabelGameText = new System.Windows.Forms.ToolStripStatusLabel(); + this.toolStripStatusLabelEdition = new System.Windows.Forms.ToolStripStatusLabel(); + this.toolStripStatusLabelEditionText = new System.Windows.Forms.ToolStripStatusLabel(); + this.toolStripStatusLabel1 = new System.Windows.Forms.ToolStripStatusLabel(); + this.toolStripStatusLabelNuclearWinterModeActive = new System.Windows.Forms.ToolStripStatusLabel(); this.pictureBoxLoadingGIF = new System.Windows.Forms.PictureBox(); ((System.ComponentModel.ISupportInitialize)(this.numPipboyTargetWidth)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.numPipboyTargetHeight)).BeginInit(); @@ -438,6 +446,39 @@ private void InitializeComponent() ((System.ComponentModel.ISupportInitialize)(this.sliderHUDOpacity)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.sliderfBlendSplitDirShadow)).BeginInit(); this.tabPageCamera.SuspendLayout(); + this.panel2.SuspendLayout(); + this.groupBoxCameraPosition.SuspendLayout(); + this.groupBox3.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.numfOverShoulderMeleeCombatAddY)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.numfOverShoulderMeleeCombatPosX)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.numfOverShoulderMeleeCombatPosZ)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.trackBarfOverShoulderMeleeCombatAddY)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.trackBarfOverShoulderMeleeCombatPosX)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.trackBarfOverShoulderMeleeCombatPosZ)).BeginInit(); + this.groupBox2.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.numfOverShoulderCombatAddY)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.numfOverShoulderCombatPosX)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.numfOverShoulderCombatPosZ)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.trackBarfOverShoulderCombatAddY)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.trackBarfOverShoulderCombatPosX)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.trackBarfOverShoulderCombatPosZ)).BeginInit(); + this.groupBoxUnarmedCameraPosition.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.numfOverShoulderPosX)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.numfOverShoulderPosZ)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.trackBarfOverShoulderPosX)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.trackBarfOverShoulderPosZ)).BeginInit(); + this.groupBoxSelfieCamera.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.trackBarPhotomodeRange)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.numericUpDownPhotomodeRotationSpeed)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.trackBarPhotomodeRotationSpeed)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.numericUpDownPhotomodeRange)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.numericUpDownPhotomodeTranslationSpeed)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.trackBarPhotomodeTranslationSpeed)).BeginInit(); + this.groupBoxFieldOfView.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.numfDefaultFOV)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.numADSFOV)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.numWorldFOV)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.numFirstPersonFOV)).BeginInit(); this.groupBoxCameraOptions.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.numCameraSwitchDelay)).BeginInit(); this.groupBoxCameraDistance.SuspendLayout(); @@ -447,24 +488,22 @@ private void InitializeComponent() ((System.ComponentModel.ISupportInitialize)(this.numCameraDistanceMinimum)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.sliderCameraDistanceMaximum)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.sliderCameraDistanceMinimum)).BeginInit(); - this.groupBoxCameraPositionWIP.SuspendLayout(); - ((System.ComponentModel.ISupportInitialize)(this.trackBarCameraX)).BeginInit(); - ((System.ComponentModel.ISupportInitialize)(this.trackBarCameraZ)).BeginInit(); - ((System.ComponentModel.ISupportInitialize)(this.trackBarCameraY)).BeginInit(); - ((System.ComponentModel.ISupportInitialize)(this.pictureBoxVaultBoy)).BeginInit(); - this.groupBoxFieldOfView.SuspendLayout(); - ((System.ComponentModel.ISupportInitialize)(this.numfDefaultFOV)).BeginInit(); - ((System.ComponentModel.ISupportInitialize)(this.numADSFOV)).BeginInit(); - ((System.ComponentModel.ISupportInitialize)(this.numWorldFOV)).BeginInit(); - ((System.ComponentModel.ISupportInitialize)(this.numFirstPersonFOV)).BeginInit(); - this.groupBoxCameraVanity.SuspendLayout(); this.tabPagePipBoy.SuspendLayout(); + this.groupBoxPipboyColorPresets.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.colorPreviewPresetFo76Green)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.colorPreviewPresetFo3Green)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.colorPreviewPresetFo3White)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.colorPreviewPresetFoNVAmber)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.colorPreviewPresetFo3Blue)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.colorPreviewPresetFo4Green)).BeginInit(); + this.groupBoxPipboyColorPreview.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBoxPipboyPreview)).BeginInit(); this.groupBoxPipboyResolution.SuspendLayout(); this.groupBoxPipboyMode.SuspendLayout(); this.groupBoxPipboyColors.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.colorPreviewQuickboy)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.colorPreviewPAPipboy)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.colorPreviewPipboy)).BeginInit(); - ((System.ComponentModel.ISupportInitialize)(this.colorPreviewQuickboy)).BeginInit(); this.tabPageControls.SuspendLayout(); this.groupBoxGamepad.SuspendLayout(); this.groupBoxMouse.SuspendLayout(); @@ -472,6 +511,7 @@ private void InitializeComponent() this.tabPageVideo.SuspendLayout(); this.panel3.SuspendLayout(); this.groupBoxGraphics.SuspendLayout(); + this.groupBoxGraphicEffects.SuspendLayout(); this.groupBoxTAASharpening.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.numTAAPostSharpen)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.numTAAPostOverlay)).BeginInit(); @@ -483,7 +523,6 @@ private void InitializeComponent() ((System.ComponentModel.ISupportInitialize)(this.numLODObjects)).BeginInit(); this.groupBoxLighting.SuspendLayout(); this.groupBoxShadows.SuspendLayout(); - ((System.ComponentModel.ISupportInitialize)(this.numfBlendSplitDirShadow)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.numShadowDistance)).BeginInit(); this.groupBoxWater.SuspendLayout(); this.groupBoxWeather.SuspendLayout(); @@ -497,23 +536,12 @@ private void InitializeComponent() this.groupBoxQuests.SuspendLayout(); this.groupBoxMainMenu.SuspendLayout(); this.groupBoxLogin.SuspendLayout(); + this.groupBoxLoginProfiles.SuspendLayout(); this.tabPageInfo.SuspendLayout(); + this.groupBoxSettings.SuspendLayout(); this.panelUpdate.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.pictureBoxUpdateButton)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.pictureBoxSpinnerCheckForUpdates)).BeginInit(); - this.panel1.SuspendLayout(); - this.groupBoxNuclearWinterMode.SuspendLayout(); - this.groupBoxLocalization.SuspendLayout(); - ((System.ComponentModel.ISupportInitialize)(this.pictureBoxSpinnerDownloadLanguages)).BeginInit(); - this.groupBoxGameEdition.SuspendLayout(); - ((System.ComponentModel.ISupportInitialize)(this.pictureBoxMSStore)).BeginInit(); - ((System.ComponentModel.ISupportInitialize)(this.pictureBoxSteam)).BeginInit(); - ((System.ComponentModel.ISupportInitialize)(this.pictureBoxBethesdaNetPTS)).BeginInit(); - ((System.ComponentModel.ISupportInitialize)(this.pictureBoxBethesdaNet)).BeginInit(); - this.groupBoxLaunchOptions.SuspendLayout(); - this.groupBoxGamePaths.SuspendLayout(); - this.groupBoxOptions.SuspendLayout(); - this.groupBoxBehavior.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.pictureBoxGameEdition)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.pictureBox2)).BeginInit(); @@ -540,15 +568,22 @@ private void InitializeComponent() ((System.ComponentModel.ISupportInitialize)(this.sliderGalleryThumbnailSize)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.numScreenshotIndex)).BeginInit(); this.tabPageCustom.SuspendLayout(); - this.toolStrip1.SuspendLayout(); + this.tabPageDangerZone.SuspendLayout(); + this.groupBoxVideoDZ.SuspendLayout(); + this.groupBoxShadows2.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.numfBlendSplitDirShadow)).BeginInit(); + this.groupBox4.SuspendLayout(); this.contextMenuStripGallery.SuspendLayout(); + this.toolStrip1.SuspendLayout(); + this.statusStrip1.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.pictureBoxLoadingGIF)).BeginInit(); this.SuspendLayout(); // // toolTip // - this.toolTip.AutoPopDelay = 10000; + this.toolTip.AutoPopDelay = 20000; this.toolTip.InitialDelay = 500; + this.toolTip.IsBalloon = true; this.toolTip.ReshowDelay = 100; // // checkBoxVanityMode @@ -556,11 +591,11 @@ private void InitializeComponent() this.checkBoxVanityMode.AutoSize = true; this.checkBoxVanityMode.Checked = true; this.checkBoxVanityMode.CheckState = System.Windows.Forms.CheckState.Checked; - this.checkBoxVanityMode.Location = new System.Drawing.Point(9, 22); + this.checkBoxVanityMode.Location = new System.Drawing.Point(9, 55); this.checkBoxVanityMode.Name = "checkBoxVanityMode"; - this.checkBoxVanityMode.Size = new System.Drawing.Size(143, 17); + this.checkBoxVanityMode.Size = new System.Drawing.Size(208, 17); this.checkBoxVanityMode.TabIndex = 3; - this.checkBoxVanityMode.Text = "Enable auto vanity mode"; + this.checkBoxVanityMode.Text = "Enable spinning camera when inactive"; this.toolTip.SetToolTip(this.checkBoxVanityMode, resources.GetString("checkBoxVanityMode.ToolTip")); this.checkBoxVanityMode.UseVisualStyleBackColor = true; // @@ -569,7 +604,7 @@ private void InitializeComponent() this.checkBoxForceVanityMode.AutoSize = true; this.checkBoxForceVanityMode.Checked = true; this.checkBoxForceVanityMode.CheckState = System.Windows.Forms.CheckState.Checked; - this.checkBoxForceVanityMode.Location = new System.Drawing.Point(28, 45); + this.checkBoxForceVanityMode.Location = new System.Drawing.Point(28, 78); this.checkBoxForceVanityMode.Name = "checkBoxForceVanityMode"; this.checkBoxForceVanityMode.Size = new System.Drawing.Size(137, 17); this.checkBoxForceVanityMode.TabIndex = 4; @@ -611,45 +646,11 @@ private void InitializeComponent() this.labelADSFOV.Text = "3rd person aim FOV:"; this.toolTip.SetToolTip(this.labelADSFOV, "Changes the field of view of the 3rd person perspective while aiming.\r\n\r\nDefault:" + " 50\r\nAffected values: f3rdPersonAimFOV\r\nAffected files: Fallout76Custom.ini"); - // - // labelPipboyColor - // - this.labelPipboyColor.AutoSize = true; - this.labelPipboyColor.Location = new System.Drawing.Point(39, 24); - this.labelPipboyColor.Name = "labelPipboyColor"; - this.labelPipboyColor.Size = new System.Drawing.Size(70, 13); - this.labelPipboyColor.TabIndex = 32; - this.labelPipboyColor.Text = "Pip-Boy Color"; - this.toolTip.SetToolTip(this.labelPipboyColor, "Affected values: fPipboyEffectColorR, fPipboyEffectColorG, fPipboyEffectColorB\r\nA" + - "ffected files: Fallout76Prefs.ini"); - // - // labelQuickboyColor - // - this.labelQuickboyColor.AutoSize = true; - this.labelQuickboyColor.Location = new System.Drawing.Point(39, 53); - this.labelQuickboyColor.Name = "labelQuickboyColor"; - this.labelQuickboyColor.Size = new System.Drawing.Size(83, 13); - this.labelQuickboyColor.TabIndex = 34; - this.labelQuickboyColor.Text = "Quick-Boy Color"; - this.toolTip.SetToolTip(this.labelQuickboyColor, "Affected values: fQuickBoyEffectColorR, fQuickBoyEffectColorG, fQuickBoyEffectCol" + - "orB\r\nAffected files: Fallout76Custom.ini"); - // - // label1 - // - this.label1.AutoSize = true; - this.label1.Location = new System.Drawing.Point(39, 82); - this.label1.Name = "label1"; - this.label1.Size = new System.Drawing.Size(94, 13); - this.label1.TabIndex = 37; - this.label1.Text = "Power Armor Color"; - this.toolTip.SetToolTip(this.label1, "Changes the color of the Pip-Boy which is accessed from the Power Armor.\r\n\r\nAffec" + - "ted values: fPAEffectColorR, fPAEffectColorG, fPAEffectColorB\r\nAffected files: F" + - "allout76Custom.ini"); // // radioButtonPipboy // this.radioButtonPipboy.AutoSize = true; - this.radioButtonPipboy.Location = new System.Drawing.Point(11, 19); + this.radioButtonPipboy.Location = new System.Drawing.Point(11, 17); this.radioButtonPipboy.Name = "radioButtonPipboy"; this.radioButtonPipboy.Size = new System.Drawing.Size(80, 17); this.radioButtonPipboy.TabIndex = 36; @@ -661,7 +662,7 @@ private void InitializeComponent() // radioButtonQuickboy // this.radioButtonQuickboy.AutoSize = true; - this.radioButtonQuickboy.Location = new System.Drawing.Point(11, 42); + this.radioButtonQuickboy.Location = new System.Drawing.Point(11, 40); this.radioButtonQuickboy.Name = "radioButtonQuickboy"; this.radioButtonQuickboy.Size = new System.Drawing.Size(93, 17); this.radioButtonQuickboy.TabIndex = 37; @@ -672,37 +673,39 @@ private void InitializeComponent() // // numPipboyTargetWidth // - this.numPipboyTargetWidth.Location = new System.Drawing.Point(6, 19); + this.numPipboyTargetWidth.Location = new System.Drawing.Point(7, 23); this.numPipboyTargetWidth.Maximum = new decimal(new int[] { 10000, 0, 0, 0}); this.numPipboyTargetWidth.Name = "numPipboyTargetWidth"; - this.numPipboyTargetWidth.Size = new System.Drawing.Size(197, 20); + this.numPipboyTargetWidth.Size = new System.Drawing.Size(115, 20); this.numPipboyTargetWidth.TabIndex = 1; + this.numPipboyTargetWidth.TextAlign = System.Windows.Forms.HorizontalAlignment.Center; this.toolTip.SetToolTip(this.numPipboyTargetWidth, "Changes the resolution width of the Pipboy/Quickboy.\r\n\r\nAffected values: uPipboyT" + "argetWidth\r\nAffected files: Fallout76Prefs.ini"); // // numPipboyTargetHeight // - this.numPipboyTargetHeight.Location = new System.Drawing.Point(246, 19); + this.numPipboyTargetHeight.Location = new System.Drawing.Point(160, 23); this.numPipboyTargetHeight.Maximum = new decimal(new int[] { 10000, 0, 0, 0}); this.numPipboyTargetHeight.Name = "numPipboyTargetHeight"; - this.numPipboyTargetHeight.Size = new System.Drawing.Size(197, 20); + this.numPipboyTargetHeight.Size = new System.Drawing.Size(115, 20); this.numPipboyTargetHeight.TabIndex = 2; + this.numPipboyTargetHeight.TextAlign = System.Windows.Forms.HorizontalAlignment.Center; this.toolTip.SetToolTip(this.numPipboyTargetHeight, "Changes the resolution height of the Pipboy/Quickboy.\r\n\r\nAffected values: uPipboy" + "TargetHeight\r\nAffected files: Fallout76Prefs.ini"); // // buttonPipboyTargetReset // - this.buttonPipboyTargetReset.Location = new System.Drawing.Point(6, 45); + this.buttonPipboyTargetReset.Location = new System.Drawing.Point(6, 56); this.buttonPipboyTargetReset.Name = "buttonPipboyTargetReset"; - this.buttonPipboyTargetReset.Size = new System.Drawing.Size(213, 23); + this.buttonPipboyTargetReset.Size = new System.Drawing.Size(270, 23); this.buttonPipboyTargetReset.TabIndex = 3; this.buttonPipboyTargetReset.Text = "Reset to default"; this.toolTip.SetToolTip(this.buttonPipboyTargetReset, "Default values: 876x700"); @@ -711,29 +714,19 @@ private void InitializeComponent() // // buttonPipboyTargetSetRecommended // - this.buttonPipboyTargetSetRecommended.Location = new System.Drawing.Point(230, 45); + this.buttonPipboyTargetSetRecommended.Location = new System.Drawing.Point(6, 85); this.buttonPipboyTargetSetRecommended.Name = "buttonPipboyTargetSetRecommended"; - this.buttonPipboyTargetSetRecommended.Size = new System.Drawing.Size(213, 23); + this.buttonPipboyTargetSetRecommended.Size = new System.Drawing.Size(270, 23); this.buttonPipboyTargetSetRecommended.TabIndex = 4; this.buttonPipboyTargetSetRecommended.Text = "Set recommended resolution"; this.toolTip.SetToolTip(this.buttonPipboyTargetSetRecommended, "Recommended values: 1752x1400"); this.buttonPipboyTargetSetRecommended.UseVisualStyleBackColor = true; this.buttonPipboyTargetSetRecommended.Click += new System.EventHandler(this.buttonPipboyTargetSetRecommended_Click); // - // labelDisplayMode - // - this.labelDisplayMode.AutoSize = true; - this.labelDisplayMode.Location = new System.Drawing.Point(6, 23); - this.labelDisplayMode.Name = "labelDisplayMode"; - this.labelDisplayMode.Size = new System.Drawing.Size(73, 13); - this.labelDisplayMode.TabIndex = 1; - this.labelDisplayMode.Text = "Display mode:"; - this.toolTip.SetToolTip(this.labelDisplayMode, resources.GetString("labelDisplayMode.ToolTip")); - // // numCustomResH // this.numCustomResH.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); - this.numCustomResH.Location = new System.Drawing.Point(296, 72); + this.numCustomResH.Location = new System.Drawing.Point(283, 71); this.numCustomResH.Maximum = new decimal(new int[] { 8192, 0, @@ -745,19 +738,21 @@ private void InitializeComponent() 0, 0}); this.numCustomResH.Name = "numCustomResH"; - this.numCustomResH.Size = new System.Drawing.Size(107, 20); + this.numCustomResH.Size = new System.Drawing.Size(120, 20); this.numCustomResH.TabIndex = 8; + this.numCustomResH.TextAlign = System.Windows.Forms.HorizontalAlignment.Center; this.toolTip.SetToolTip(this.numCustomResH, "Changes the vertical resolution (height).\r\n\r\nAffected values: iSize H"); this.numCustomResH.Value = new decimal(new int[] { 1080, 0, 0, 0}); + this.numCustomResH.ValueChanged += new System.EventHandler(this.numCustomRes_ValueChanged); // // numCustomResW // this.numCustomResW.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); - this.numCustomResW.Location = new System.Drawing.Point(157, 72); + this.numCustomResW.Location = new System.Drawing.Point(146, 71); this.numCustomResW.Maximum = new decimal(new int[] { 8192, 0, @@ -769,36 +764,16 @@ private void InitializeComponent() 0, 0}); this.numCustomResW.Name = "numCustomResW"; - this.numCustomResW.Size = new System.Drawing.Size(107, 20); + this.numCustomResW.Size = new System.Drawing.Size(120, 20); this.numCustomResW.TabIndex = 5; + this.numCustomResW.TextAlign = System.Windows.Forms.HorizontalAlignment.Center; this.toolTip.SetToolTip(this.numCustomResW, "Changes the horizontal resolution (width).\r\n\r\nAffected values: iSize W"); this.numCustomResW.Value = new decimal(new int[] { 1920, 0, 0, 0}); - // - // checkBoxTopMostWindow - // - this.checkBoxTopMostWindow.AutoSize = true; - this.checkBoxTopMostWindow.Location = new System.Drawing.Point(9, 129); - this.checkBoxTopMostWindow.Name = "checkBoxTopMostWindow"; - this.checkBoxTopMostWindow.Size = new System.Drawing.Size(109, 17); - this.checkBoxTopMostWindow.TabIndex = 21; - this.checkBoxTopMostWindow.Text = "Top-most window"; - this.toolTip.SetToolTip(this.checkBoxTopMostWindow, resources.GetString("checkBoxTopMostWindow.ToolTip")); - this.checkBoxTopMostWindow.UseVisualStyleBackColor = true; - // - // labelResolution - // - this.labelResolution.AutoSize = true; - this.labelResolution.Location = new System.Drawing.Point(6, 48); - this.labelResolution.Name = "labelResolution"; - this.labelResolution.Size = new System.Drawing.Size(60, 13); - this.labelResolution.TabIndex = 3; - this.labelResolution.Text = "Resolution:"; - this.toolTip.SetToolTip(this.labelResolution, "Changes the resolution.\r\nSetting it to \"Custom\" will allow you to set your own va" + - "lues.\r\n\r\nAffected values: iSize W, iSize H\r\nAffected files: Fallout76Prefsini"); + this.numCustomResW.ValueChanged += new System.EventHandler(this.numCustomRes_ValueChanged); // // checkBoxAlwaysActive // @@ -812,16 +787,6 @@ private void InitializeComponent() "cted values: bAlwaysActive\r\nAffected files: Fallout76Custom.ini"); this.checkBoxAlwaysActive.UseVisualStyleBackColor = true; // - // labelCustomResolution - // - this.labelCustomResolution.AutoSize = true; - this.labelCustomResolution.Location = new System.Drawing.Point(6, 74); - this.labelCustomResolution.Name = "labelCustomResolution"; - this.labelCustomResolution.Size = new System.Drawing.Size(93, 13); - this.labelCustomResolution.TabIndex = 2; - this.labelCustomResolution.Text = "Custom resolution:"; - this.toolTip.SetToolTip(this.labelCustomResolution, "Set resolution to \"Custom\" for this option to become available."); - // // checkBoxFixHUDFor5_4and4_3 // this.checkBoxFixHUDFor5_4and4_3.AutoSize = true; @@ -948,19 +913,6 @@ private void InitializeComponent() "cted files: Fallout76Custom.ini"); this.checkBoxMotionBlur.UseVisualStyleBackColor = true; // - // checkBoxDepthOfField - // - this.checkBoxDepthOfField.AutoSize = true; - this.checkBoxDepthOfField.Checked = true; - this.checkBoxDepthOfField.CheckState = System.Windows.Forms.CheckState.Checked; - this.checkBoxDepthOfField.Location = new System.Drawing.Point(9, 19); - this.checkBoxDepthOfField.Name = "checkBoxDepthOfField"; - this.checkBoxDepthOfField.Size = new System.Drawing.Size(92, 17); - this.checkBoxDepthOfField.TabIndex = 10; - this.checkBoxDepthOfField.Text = "Depth of Field"; - this.toolTip.SetToolTip(this.checkBoxDepthOfField, resources.GetString("checkBoxDepthOfField.ToolTip")); - this.checkBoxDepthOfField.UseVisualStyleBackColor = true; - // // checkBoxAmbientOcclusion // this.checkBoxAmbientOcclusion.AutoSize = true; @@ -1038,155 +990,6 @@ private void InitializeComponent() "d files: Fallout76Custom.ini"); this.checkBoxGrass.UseVisualStyleBackColor = true; // - // checkBoxIntroVideos - // - this.checkBoxIntroVideos.AutoSize = true; - this.checkBoxIntroVideos.Checked = true; - this.checkBoxIntroVideos.CheckState = System.Windows.Forms.CheckState.Checked; - this.checkBoxIntroVideos.Location = new System.Drawing.Point(7, 19); - this.checkBoxIntroVideos.Name = "checkBoxIntroVideos"; - this.checkBoxIntroVideos.Size = new System.Drawing.Size(103, 17); - this.checkBoxIntroVideos.TabIndex = 0; - this.checkBoxIntroVideos.Text = "Play intro videos"; - this.toolTip.SetToolTip(this.checkBoxIntroVideos, "When this option is unchecked, the game will start without displaying the Bethesd" + - "a logo video.\r\n\r\nAffected values: sIntroSequence, uMainMenuDelayBeforeAllowSkip\r" + - "\nAffected files: Fallout76Custom.ini"); - this.checkBoxIntroVideos.UseVisualStyleBackColor = true; - // - // checkBoxShowSplash - // - this.checkBoxShowSplash.AutoSize = true; - this.checkBoxShowSplash.Checked = true; - this.checkBoxShowSplash.CheckState = System.Windows.Forms.CheckState.Checked; - this.checkBoxShowSplash.Location = new System.Drawing.Point(7, 42); - this.checkBoxShowSplash.Name = "checkBoxShowSplash"; - this.checkBoxShowSplash.Size = new System.Drawing.Size(221, 17); - this.checkBoxShowSplash.TabIndex = 2; - this.checkBoxShowSplash.Text = "Show splash screen with news on startup"; - this.toolTip.SetToolTip(this.checkBoxShowSplash, "If unchecked, the game won\'t bother you with news on startup.\r\n\r\nAffected values:" + - " bShowSplash\r\nAffected files: Fallout76Custom.ini"); - this.checkBoxShowSplash.UseVisualStyleBackColor = true; - // - // checkBoxShowDamageNumbersA - // - this.checkBoxShowDamageNumbersA.AutoSize = true; - this.checkBoxShowDamageNumbersA.Location = new System.Drawing.Point(7, 19); - this.checkBoxShowDamageNumbersA.Name = "checkBoxShowDamageNumbersA"; - this.checkBoxShowDamageNumbersA.Size = new System.Drawing.Size(261, 17); - this.checkBoxShowDamageNumbersA.TabIndex = 2; - this.checkBoxShowDamageNumbersA.Text = "Show floating damage numbers (Adventure mode)"; - this.toolTip.SetToolTip(this.checkBoxShowDamageNumbersA, "Affected values: bShowDamageNumbers\r\nAffected files: Fallout76Prefs.ini"); - this.checkBoxShowDamageNumbersA.UseVisualStyleBackColor = true; - // - // checkBoxShowDamageNumbersNW - // - this.checkBoxShowDamageNumbersNW.AutoSize = true; - this.checkBoxShowDamageNumbersNW.Location = new System.Drawing.Point(7, 42); - this.checkBoxShowDamageNumbersNW.Name = "checkBoxShowDamageNumbersNW"; - this.checkBoxShowDamageNumbersNW.Size = new System.Drawing.Size(254, 17); - this.checkBoxShowDamageNumbersNW.TabIndex = 3; - this.checkBoxShowDamageNumbersNW.Text = "Show floating damage numbers (Nuclear Winter)"; - this.toolTip.SetToolTip(this.checkBoxShowDamageNumbersNW, "Affected values: bShowDamageNumbers\r\nAffected files: Fallout76Prefs.ini"); - this.checkBoxShowDamageNumbersNW.UseVisualStyleBackColor = true; - // - // checkBoxShowCompass - // - this.checkBoxShowCompass.AutoSize = true; - this.checkBoxShowCompass.Location = new System.Drawing.Point(7, 347); - this.checkBoxShowCompass.Name = "checkBoxShowCompass"; - this.checkBoxShowCompass.Size = new System.Drawing.Size(98, 17); - this.checkBoxShowCompass.TabIndex = 4; - this.checkBoxShowCompass.Text = "Show compass"; - this.toolTip.SetToolTip(this.checkBoxShowCompass, "Affected values: bShowCompass\r\nAffected files: Fallout76Prefs.ini"); - this.checkBoxShowCompass.UseVisualStyleBackColor = true; - // - // checkBoxAutoApply - // - this.checkBoxAutoApply.AutoSize = true; - this.checkBoxAutoApply.Location = new System.Drawing.Point(9, 42); - this.checkBoxAutoApply.Name = "checkBoxAutoApply"; - this.checkBoxAutoApply.Size = new System.Drawing.Size(354, 17); - this.checkBoxAutoApply.TabIndex = 21; - this.checkBoxAutoApply.Text = "Automatically apply changes when tool is closed or game is launched."; - this.toolTip.SetToolTip(this.checkBoxAutoApply, "No need to press apply anymore."); - this.checkBoxAutoApply.UseVisualStyleBackColor = true; - this.checkBoxAutoApply.CheckedChanged += new System.EventHandler(this.checkBoxAutoApply_CheckedChanged); - // - // checkBoxSkipBackupQuestion - // - this.checkBoxSkipBackupQuestion.AutoSize = true; - this.checkBoxSkipBackupQuestion.Location = new System.Drawing.Point(9, 65); - this.checkBoxSkipBackupQuestion.Name = "checkBoxSkipBackupQuestion"; - this.checkBoxSkipBackupQuestion.Size = new System.Drawing.Size(209, 17); - this.checkBoxSkipBackupQuestion.TabIndex = 22; - this.checkBoxSkipBackupQuestion.Text = "Don\'t ask me, when \"Apply\" is clicked."; - this.toolTip.SetToolTip(this.checkBoxSkipBackupQuestion, "Skips the backup question when \"Apply\" is clicked.\r\nNote: This way, it will NOT c" + - "reate a backup!"); - this.checkBoxSkipBackupQuestion.UseVisualStyleBackColor = true; - this.checkBoxSkipBackupQuestion.CheckedChanged += new System.EventHandler(this.checkBoxSkipBackupQuestion_CheckedChanged); - // - // checkBoxQuitOnGameLaunch - // - this.checkBoxQuitOnGameLaunch.AutoSize = true; - this.checkBoxQuitOnGameLaunch.Location = new System.Drawing.Point(9, 19); - this.checkBoxQuitOnGameLaunch.Name = "checkBoxQuitOnGameLaunch"; - this.checkBoxQuitOnGameLaunch.Size = new System.Drawing.Size(223, 17); - this.checkBoxQuitOnGameLaunch.TabIndex = 20; - this.checkBoxQuitOnGameLaunch.Text = "Close the tool when the game is launched"; - this.toolTip.SetToolTip(this.checkBoxQuitOnGameLaunch, "Does only work when the game is launched through the tool."); - this.checkBoxQuitOnGameLaunch.UseVisualStyleBackColor = true; - this.checkBoxQuitOnGameLaunch.CheckedChanged += new System.EventHandler(this.checkBoxQuitOnGameLaunch_CheckedChanged); - // - // checkBoxReadOnly - // - this.checkBoxReadOnly.AutoSize = true; - this.checkBoxReadOnly.Location = new System.Drawing.Point(10, 42); - this.checkBoxReadOnly.Name = "checkBoxReadOnly"; - this.checkBoxReadOnly.Size = new System.Drawing.Size(140, 17); - this.checkBoxReadOnly.TabIndex = 4; - this.checkBoxReadOnly.Text = "Make *.ini files read-only"; - this.toolTip.SetToolTip(this.checkBoxReadOnly, "This option will make all *.ini files read-only immediately.\r\nEnable this if your" + - " settings get reverted.\r\n\r\nAffected files: %UserProfile%\\Documents\\My Games\\Fall" + - "out 76\\*.ini"); - this.checkBoxReadOnly.UseVisualStyleBackColor = true; - this.checkBoxReadOnly.CheckedChanged += new System.EventHandler(this.checkBoxReadOnly_CheckedChanged); - // - // checkBoxMultipleGameEditionsUsed - // - this.checkBoxMultipleGameEditionsUsed.AutoSize = true; - this.checkBoxMultipleGameEditionsUsed.Location = new System.Drawing.Point(10, 19); - this.checkBoxMultipleGameEditionsUsed.Name = "checkBoxMultipleGameEditionsUsed"; - this.checkBoxMultipleGameEditionsUsed.Size = new System.Drawing.Size(186, 17); - this.checkBoxMultipleGameEditionsUsed.TabIndex = 18; - this.checkBoxMultipleGameEditionsUsed.Text = "I use more than one game edition."; - this.toolTip.SetToolTip(this.checkBoxMultipleGameEditionsUsed, "Check this, if you\'re modding more than one game edition.\r\nIf checked, sResourceI" + - "ndexFileList will be saved for every game edition separately."); - this.checkBoxMultipleGameEditionsUsed.UseVisualStyleBackColor = true; - // - // checkBoxDenyNTFSWritePermission - // - this.checkBoxDenyNTFSWritePermission.AutoSize = true; - this.checkBoxDenyNTFSWritePermission.Location = new System.Drawing.Point(10, 65); - this.checkBoxDenyNTFSWritePermission.Name = "checkBoxDenyNTFSWritePermission"; - this.checkBoxDenyNTFSWritePermission.Size = new System.Drawing.Size(231, 17); - this.checkBoxDenyNTFSWritePermission.TabIndex = 19; - this.checkBoxDenyNTFSWritePermission.Text = "[Experimental] Deny NTFS write permission."; - this.toolTip.SetToolTip(this.checkBoxDenyNTFSWritePermission, "This will deny write permission to the \"Fallout 76\" folder.\r\nUse this, if the rea" + - "d-only option doesn\'t work.\r\n\r\nAffected folder: %UserProfile%\\Documents\\My Games" + - "\\Fallout 76"); - this.checkBoxDenyNTFSWritePermission.UseVisualStyleBackColor = true; - // - // checkBoxFixMouseSensitivity - // - this.checkBoxFixMouseSensitivity.AutoSize = true; - this.checkBoxFixMouseSensitivity.Location = new System.Drawing.Point(9, 111); - this.checkBoxFixMouseSensitivity.Name = "checkBoxFixMouseSensitivity"; - this.checkBoxFixMouseSensitivity.Size = new System.Drawing.Size(208, 17); - this.checkBoxFixMouseSensitivity.TabIndex = 0; - this.checkBoxFixMouseSensitivity.Text = "Fix mouse horizontal/vertical sensitivity"; - this.toolTip.SetToolTip(this.checkBoxFixMouseSensitivity, resources.GetString("checkBoxFixMouseSensitivity.ToolTip")); - this.checkBoxFixMouseSensitivity.UseVisualStyleBackColor = true; - // // checkBoxFixAimSensitivity // this.checkBoxFixAimSensitivity.AutoSize = true; @@ -1218,9 +1021,9 @@ private void InitializeComponent() this.checkBoxGamepadRumble.CheckState = System.Windows.Forms.CheckState.Checked; this.checkBoxGamepadRumble.Location = new System.Drawing.Point(6, 40); this.checkBoxGamepadRumble.Name = "checkBoxGamepadRumble"; - this.checkBoxGamepadRumble.Size = new System.Drawing.Size(227, 17); + this.checkBoxGamepadRumble.Size = new System.Drawing.Size(149, 17); this.checkBoxGamepadRumble.TabIndex = 3; - this.checkBoxGamepadRumble.Text = "Enable gamepad rumble (Force Feedback)"; + this.checkBoxGamepadRumble.Text = "Enable gamepad vibration"; this.toolTip.SetToolTip(this.checkBoxGamepadRumble, "Enables rumbling (force feedback) of your gamepad.\r\n\r\nAffected values: bGamePadRu" + "mble\r\nAffected files: Fallout76Custom.ini"); this.checkBoxGamepadRumble.UseVisualStyleBackColor = true; @@ -1294,7 +1097,7 @@ private void InitializeComponent() | System.Windows.Forms.AnchorStyles.Right))); this.sliderShadowDistance.BackColor = System.Drawing.SystemColors.Window; this.sliderShadowDistance.LargeChange = 10000; - this.sliderShadowDistance.Location = new System.Drawing.Point(10, 121); + this.sliderShadowDistance.Location = new System.Drawing.Point(10, 96); this.sliderShadowDistance.Maximum = 200000; this.sliderShadowDistance.Name = "sliderShadowDistance"; this.sliderShadowDistance.Size = new System.Drawing.Size(285, 45); @@ -1605,62 +1408,7 @@ private void InitializeComponent() this.toolTip.SetToolTip(this.checkBoxMouseInvertX, "Affected values: bInvertXValues\r\nAffected files: Fallout76Prefs.ini"); this.checkBoxMouseInvertX.UseVisualStyleBackColor = true; // - // checkBoxEnableQuestAutoTrackMain - // - this.checkBoxEnableQuestAutoTrackMain.AutoSize = true; - this.checkBoxEnableQuestAutoTrackMain.Location = new System.Drawing.Point(7, 19); - this.checkBoxEnableQuestAutoTrackMain.Name = "checkBoxEnableQuestAutoTrackMain"; - this.checkBoxEnableQuestAutoTrackMain.Size = new System.Drawing.Size(182, 17); - this.checkBoxEnableQuestAutoTrackMain.TabIndex = 5; - this.checkBoxEnableQuestAutoTrackMain.Text = "Main Quests Active when started"; - this.toolTip.SetToolTip(this.checkBoxEnableQuestAutoTrackMain, "Affected values: bEnableQuestAutoTrackMain\r\nAffected files: Fallout76Prefs.ini"); - this.checkBoxEnableQuestAutoTrackMain.UseVisualStyleBackColor = true; - // - // checkBoxEnableQuestAutoTrackSide - // - this.checkBoxEnableQuestAutoTrackSide.AutoSize = true; - this.checkBoxEnableQuestAutoTrackSide.Location = new System.Drawing.Point(7, 42); - this.checkBoxEnableQuestAutoTrackSide.Name = "checkBoxEnableQuestAutoTrackSide"; - this.checkBoxEnableQuestAutoTrackSide.Size = new System.Drawing.Size(180, 17); - this.checkBoxEnableQuestAutoTrackSide.TabIndex = 6; - this.checkBoxEnableQuestAutoTrackSide.Text = "Side Quests Active when started"; - this.toolTip.SetToolTip(this.checkBoxEnableQuestAutoTrackSide, "Affected values: bEnableQuestAutoTrackSide\r\nAffected files: Fallout76Prefs.ini"); - this.checkBoxEnableQuestAutoTrackSide.UseVisualStyleBackColor = true; - // - // checkBoxEnableQuestAutoTrackMisc - // - this.checkBoxEnableQuestAutoTrackMisc.AutoSize = true; - this.checkBoxEnableQuestAutoTrackMisc.Location = new System.Drawing.Point(7, 65); - this.checkBoxEnableQuestAutoTrackMisc.Name = "checkBoxEnableQuestAutoTrackMisc"; - this.checkBoxEnableQuestAutoTrackMisc.Size = new System.Drawing.Size(226, 17); - this.checkBoxEnableQuestAutoTrackMisc.TabIndex = 7; - this.checkBoxEnableQuestAutoTrackMisc.Text = "Miscellaneous Quests Active when started"; - this.toolTip.SetToolTip(this.checkBoxEnableQuestAutoTrackMisc, "Affected values: bEnableQuestAutoTrackMisc\r\nAffected files: Fallout76Prefs.ini"); - this.checkBoxEnableQuestAutoTrackMisc.UseVisualStyleBackColor = true; - // - // checkBoxEnableQuestAutoTrackEvent - // - this.checkBoxEnableQuestAutoTrackEvent.AutoSize = true; - this.checkBoxEnableQuestAutoTrackEvent.Location = new System.Drawing.Point(7, 88); - this.checkBoxEnableQuestAutoTrackEvent.Name = "checkBoxEnableQuestAutoTrackEvent"; - this.checkBoxEnableQuestAutoTrackEvent.Size = new System.Drawing.Size(187, 17); - this.checkBoxEnableQuestAutoTrackEvent.TabIndex = 8; - this.checkBoxEnableQuestAutoTrackEvent.Text = "Event Quests Active when started"; - this.toolTip.SetToolTip(this.checkBoxEnableQuestAutoTrackEvent, "Affected values: bEnableQuestAutoTrackEvent\r\nAffected files: Fallout76Prefs.ini"); - this.checkBoxEnableQuestAutoTrackEvent.UseVisualStyleBackColor = true; - // - // checkBoxEnableQuestAutoTrackDaily - // - this.checkBoxEnableQuestAutoTrackDaily.AutoSize = true; - this.checkBoxEnableQuestAutoTrackDaily.Location = new System.Drawing.Point(7, 111); - this.checkBoxEnableQuestAutoTrackDaily.Name = "checkBoxEnableQuestAutoTrackDaily"; - this.checkBoxEnableQuestAutoTrackDaily.Size = new System.Drawing.Size(182, 17); - this.checkBoxEnableQuestAutoTrackDaily.TabIndex = 9; - this.checkBoxEnableQuestAutoTrackDaily.Text = "Daily Quests Active when started"; - this.toolTip.SetToolTip(this.checkBoxEnableQuestAutoTrackDaily, "Affected values: bEnableQuestAutoTrackOther\r\nAffected files: Fallout76Prefs.ini"); - this.checkBoxEnableQuestAutoTrackDaily.UseVisualStyleBackColor = true; - // - // checkBoxDialogueHistory + // checkBoxDialogueHistory // this.checkBoxDialogueHistory.AutoSize = true; this.checkBoxDialogueHistory.Location = new System.Drawing.Point(10, 65); @@ -1671,62 +1419,6 @@ private void InitializeComponent() this.toolTip.SetToolTip(this.checkBoxDialogueHistory, "Affected values: bShowDialogueHistory\r\nAffected files: Fallout76Prefs.ini"); this.checkBoxDialogueHistory.UseVisualStyleBackColor = true; // - // checkBoxEnablePowerArmorHUD - // - this.checkBoxEnablePowerArmorHUD.AutoSize = true; - this.checkBoxEnablePowerArmorHUD.Location = new System.Drawing.Point(7, 324); - this.checkBoxEnablePowerArmorHUD.Name = "checkBoxEnablePowerArmorHUD"; - this.checkBoxEnablePowerArmorHUD.Size = new System.Drawing.Size(149, 17); - this.checkBoxEnablePowerArmorHUD.TabIndex = 5; - this.checkBoxEnablePowerArmorHUD.Text = "Enable Power Armor HUD"; - this.toolTip.SetToolTip(this.checkBoxEnablePowerArmorHUD, "Affected values: bEnablePowerArmorHUD\r\nAffected files: Fallout76Prefs.ini"); - this.checkBoxEnablePowerArmorHUD.UseVisualStyleBackColor = true; - // - // checkBoxShowCrosshair - // - this.checkBoxShowCrosshair.AutoSize = true; - this.checkBoxShowCrosshair.Location = new System.Drawing.Point(7, 301); - this.checkBoxShowCrosshair.Name = "checkBoxShowCrosshair"; - this.checkBoxShowCrosshair.Size = new System.Drawing.Size(98, 17); - this.checkBoxShowCrosshair.TabIndex = 6; - this.checkBoxShowCrosshair.Text = "Show crosshair"; - this.toolTip.SetToolTip(this.checkBoxShowCrosshair, "Affected values: bCrosshairEnabled\r\nAffected files: Fallout76Prefs.ini"); - this.checkBoxShowCrosshair.UseVisualStyleBackColor = true; - // - // checkBoxItemRarityColorsNW - // - this.checkBoxItemRarityColorsNW.AutoSize = true; - this.checkBoxItemRarityColorsNW.Location = new System.Drawing.Point(7, 65); - this.checkBoxItemRarityColorsNW.Name = "checkBoxItemRarityColorsNW"; - this.checkBoxItemRarityColorsNW.Size = new System.Drawing.Size(211, 17); - this.checkBoxItemRarityColorsNW.TabIndex = 7; - this.checkBoxItemRarityColorsNW.Text = "Show item rarity colors (Nuclear Winter)"; - this.toolTip.SetToolTip(this.checkBoxItemRarityColorsNW, "Affected values: bEnableItemRarityColors\r\nAffected files: Fallout76Prefs.ini"); - this.checkBoxItemRarityColorsNW.UseVisualStyleBackColor = true; - // - // checkBoxShowPublicTeamNotifications - // - this.checkBoxShowPublicTeamNotifications.AutoSize = true; - this.checkBoxShowPublicTeamNotifications.Location = new System.Drawing.Point(7, 88); - this.checkBoxShowPublicTeamNotifications.Name = "checkBoxShowPublicTeamNotifications"; - this.checkBoxShowPublicTeamNotifications.Size = new System.Drawing.Size(175, 17); - this.checkBoxShowPublicTeamNotifications.TabIndex = 8; - this.checkBoxShowPublicTeamNotifications.Text = "Enable public team notifications\r\n"; - this.toolTip.SetToolTip(this.checkBoxShowPublicTeamNotifications, "Affected values: bShowPublicTeamNotifications\r\nAffected files: Fallout76Prefs.ini" + - ""); - this.checkBoxShowPublicTeamNotifications.UseVisualStyleBackColor = true; - // - // checkBoxShowFloatingQuestMarkers - // - this.checkBoxShowFloatingQuestMarkers.AutoSize = true; - this.checkBoxShowFloatingQuestMarkers.Location = new System.Drawing.Point(7, 212); - this.checkBoxShowFloatingQuestMarkers.Name = "checkBoxShowFloatingQuestMarkers"; - this.checkBoxShowFloatingQuestMarkers.Size = new System.Drawing.Size(159, 17); - this.checkBoxShowFloatingQuestMarkers.TabIndex = 9; - this.checkBoxShowFloatingQuestMarkers.Text = "Show floating quest markers\r\n"; - this.toolTip.SetToolTip(this.checkBoxShowFloatingQuestMarkers, "Affected values: bShowFloatingQuestMarkers\r\nAffected files: Fallout76Prefs.ini"); - this.checkBoxShowFloatingQuestMarkers.UseVisualStyleBackColor = true; - // // sliderFloatingQuestMarkersDistance // this.sliderFloatingQuestMarkersDistance.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) @@ -1744,17 +1436,6 @@ private void InitializeComponent() "i"); this.sliderFloatingQuestMarkersDistance.Value = 1000; // - // checkBoxShowFloatingQuestText - // - this.checkBoxShowFloatingQuestText.AutoSize = true; - this.checkBoxShowFloatingQuestText.Location = new System.Drawing.Point(7, 235); - this.checkBoxShowFloatingQuestText.Name = "checkBoxShowFloatingQuestText"; - this.checkBoxShowFloatingQuestText.Size = new System.Drawing.Size(139, 17); - this.checkBoxShowFloatingQuestText.TabIndex = 32; - this.checkBoxShowFloatingQuestText.Text = "Show floating quest text"; - this.toolTip.SetToolTip(this.checkBoxShowFloatingQuestText, "Affected values: bShowFloatingQuestText\r\nAffected files: Fallout76Prefs.ini"); - this.checkBoxShowFloatingQuestText.UseVisualStyleBackColor = true; - // // sliderConversationHistorySize // this.sliderConversationHistorySize.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) @@ -1770,17 +1451,6 @@ private void InitializeComponent() this.toolTip.SetToolTip(this.sliderConversationHistorySize, "Affected values: fConversationHistorySize\r\nAffected files: Fallout76Prefs.ini"); this.sliderConversationHistorySize.Value = 4; // - // checkBoxShowOtherPlayersNames - // - this.checkBoxShowOtherPlayersNames.AutoSize = true; - this.checkBoxShowOtherPlayersNames.Location = new System.Drawing.Point(7, 378); - this.checkBoxShowOtherPlayersNames.Name = "checkBoxShowOtherPlayersNames"; - this.checkBoxShowOtherPlayersNames.Size = new System.Drawing.Size(152, 17); - this.checkBoxShowOtherPlayersNames.TabIndex = 33; - this.checkBoxShowOtherPlayersNames.Text = "Show other players\' names"; - this.toolTip.SetToolTip(this.checkBoxShowOtherPlayersNames, "Affected values: bShowOtherPlayersNames\r\nAffected files: Fallout76Prefs.ini"); - this.checkBoxShowOtherPlayersNames.UseVisualStyleBackColor = true; - // // sliderHUDOpacity // this.sliderHUDOpacity.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) @@ -1810,6 +1480,7 @@ private void InitializeComponent() // labelfDefaultFOV // this.labelfDefaultFOV.AutoSize = true; + this.labelfDefaultFOV.ForeColor = System.Drawing.Color.Red; this.labelfDefaultFOV.Location = new System.Drawing.Point(6, 122); this.labelfDefaultFOV.Name = "labelfDefaultFOV"; this.labelfDefaultFOV.Size = new System.Drawing.Size(193, 13); @@ -1817,39 +1488,11 @@ private void InitializeComponent() this.labelfDefaultFOV.Text = "fDefaultFOV (Causes issues with HUD):"; this.toolTip.SetToolTip(this.labelfDefaultFOV, "Causes issues with the GUI.\r\n\r\nDefault: 80\r\nAffected values: fDefaultFOV\r\nAffecte" + "d files: Fallout76Custom.ini"); - // - // label2 - // - this.label2.AutoSize = true; - this.label2.Location = new System.Drawing.Point(7, 77); - this.label2.Name = "label2"; - this.label2.Size = new System.Drawing.Size(104, 13); - this.label2.TabIndex = 31; - this.label2.Text = "Transition segments:"; - this.toolTip.SetToolTip(this.label2, resources.GetString("label2.ToolTip")); - // - // sliderfBlendSplitDirShadow - // - this.sliderfBlendSplitDirShadow.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.sliderfBlendSplitDirShadow.BackColor = System.Drawing.SystemColors.Window; - this.sliderfBlendSplitDirShadow.LargeChange = 10000; - this.sliderfBlendSplitDirShadow.Location = new System.Drawing.Point(10, 172); - this.sliderfBlendSplitDirShadow.Minimum = 1; - this.sliderfBlendSplitDirShadow.Name = "sliderfBlendSplitDirShadow"; - this.sliderfBlendSplitDirShadow.Size = new System.Drawing.Size(285, 45); - this.sliderfBlendSplitDirShadow.SmallChange = 1000; - this.sliderfBlendSplitDirShadow.TabIndex = 33; - this.sliderfBlendSplitDirShadow.TickStyle = System.Windows.Forms.TickStyle.None; - this.toolTip.SetToolTip(this.sliderfBlendSplitDirShadow, "Distance at which the game will transition to lower-res a shadow \"segment\".\r\nMUST" + - " be a multiple of 12.\r\n\r\nAffected values: fBlendSplitDirShadow\r\nAffected files: " + - "Fallout76Prefs.ini"); - this.sliderfBlendSplitDirShadow.Value = 4; // // labelSwitchDelay // this.labelSwitchDelay.AutoSize = true; - this.labelSwitchDelay.Location = new System.Drawing.Point(9, 23); + this.labelSwitchDelay.Location = new System.Drawing.Point(6, 23); this.labelSwitchDelay.Name = "labelSwitchDelay"; this.labelSwitchDelay.Size = new System.Drawing.Size(119, 13); this.labelSwitchDelay.TabIndex = 0; @@ -1890,7 +1533,7 @@ private void InitializeComponent() // checkBoxbApplyCameraNodeAnimations // this.checkBoxbApplyCameraNodeAnimations.AutoSize = true; - this.checkBoxbApplyCameraNodeAnimations.Location = new System.Drawing.Point(222, 429); + this.checkBoxbApplyCameraNodeAnimations.Location = new System.Drawing.Point(9, 22); this.checkBoxbApplyCameraNodeAnimations.Name = "checkBoxbApplyCameraNodeAnimations"; this.checkBoxbApplyCameraNodeAnimations.Size = new System.Drawing.Size(171, 17); this.checkBoxbApplyCameraNodeAnimations.TabIndex = 46; @@ -1898,6 +1541,105 @@ private void InitializeComponent() this.toolTip.SetToolTip(this.checkBoxbApplyCameraNodeAnimations, resources.GetString("checkBoxbApplyCameraNodeAnimations.ToolTip")); this.checkBoxbApplyCameraNodeAnimations.UseVisualStyleBackColor = true; // + // checkBoxDisableGore + // + this.checkBoxDisableGore.AutoSize = true; + this.checkBoxDisableGore.Location = new System.Drawing.Point(9, 19); + this.checkBoxDisableGore.Name = "checkBoxDisableGore"; + this.checkBoxDisableGore.Size = new System.Drawing.Size(85, 17); + this.checkBoxDisableGore.TabIndex = 0; + this.checkBoxDisableGore.Text = "Disable gore"; + this.toolTip.SetToolTip(this.checkBoxDisableGore, "Affected values: bDisableAllGore, bBloodSpatterEnabled\r\nAffected files: Fallout76" + + "Custom.ini"); + this.checkBoxDisableGore.UseVisualStyleBackColor = true; + // + // labelPhotomodeTranslationSpeed + // + this.labelPhotomodeTranslationSpeed.AutoSize = true; + this.labelPhotomodeTranslationSpeed.Location = new System.Drawing.Point(6, 23); + this.labelPhotomodeTranslationSpeed.Name = "labelPhotomodeTranslationSpeed"; + this.labelPhotomodeTranslationSpeed.Size = new System.Drawing.Size(94, 13); + this.labelPhotomodeTranslationSpeed.TabIndex = 57; + this.labelPhotomodeTranslationSpeed.Text = "Translation speed:"; + this.toolTip.SetToolTip(this.labelPhotomodeTranslationSpeed, "Default: 2.5\r\nAffected values: fSelfieCameraTranslationSpeed\r\nAffected files: Fal" + + "lout76Custom.ini"); + // + // labelPhotomodeRange + // + this.labelPhotomodeRange.AutoSize = true; + this.labelPhotomodeRange.Location = new System.Drawing.Point(6, 87); + this.labelPhotomodeRange.Name = "labelPhotomodeRange"; + this.labelPhotomodeRange.Size = new System.Drawing.Size(62, 13); + this.labelPhotomodeRange.TabIndex = 60; + this.labelPhotomodeRange.Text = "Range limit:"; + this.toolTip.SetToolTip(this.labelPhotomodeRange, "Default: 500\r\nAffected values: fSelfieModeRange\r\nAffected files: Fallout76Custom." + + "ini"); + // + // labelPhotomodeRotationSpeed + // + this.labelPhotomodeRotationSpeed.AutoSize = true; + this.labelPhotomodeRotationSpeed.Location = new System.Drawing.Point(6, 53); + this.labelPhotomodeRotationSpeed.Name = "labelPhotomodeRotationSpeed"; + this.labelPhotomodeRotationSpeed.Size = new System.Drawing.Size(82, 13); + this.labelPhotomodeRotationSpeed.TabIndex = 63; + this.labelPhotomodeRotationSpeed.Text = "Rotation speed:"; + this.toolTip.SetToolTip(this.labelPhotomodeRotationSpeed, "Default: 1.5\r\nAffected values: fSelfieCameraRotationSpeed\r\nAffected files: Fallou" + + "t76Custom.ini"); + // + // checkBoxScreenSpaceReflections + // + this.checkBoxScreenSpaceReflections.AutoSize = true; + this.checkBoxScreenSpaceReflections.Checked = true; + this.checkBoxScreenSpaceReflections.CheckState = System.Windows.Forms.CheckState.Checked; + this.checkBoxScreenSpaceReflections.ForeColor = System.Drawing.Color.Black; + this.checkBoxScreenSpaceReflections.Location = new System.Drawing.Point(9, 19); + this.checkBoxScreenSpaceReflections.Name = "checkBoxScreenSpaceReflections"; + this.checkBoxScreenSpaceReflections.Size = new System.Drawing.Size(150, 17); + this.checkBoxScreenSpaceReflections.TabIndex = 1; + this.checkBoxScreenSpaceReflections.Text = "Screen Space Reflections"; + this.toolTip.SetToolTip(this.checkBoxScreenSpaceReflections, "Enables/disables water displacement (ripples, waves).\r\n\r\nAffected values: bUseWat" + + "erDisplacements\r\nAffected files: Fallout76Prefs.ini"); + this.checkBoxScreenSpaceReflections.UseVisualStyleBackColor = true; + // + // sliderfBlendSplitDirShadow + // + this.sliderfBlendSplitDirShadow.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.sliderfBlendSplitDirShadow.BackColor = System.Drawing.SystemColors.Window; + this.sliderfBlendSplitDirShadow.LargeChange = 10000; + this.sliderfBlendSplitDirShadow.Location = new System.Drawing.Point(14, 76); + this.sliderfBlendSplitDirShadow.Minimum = 1; + this.sliderfBlendSplitDirShadow.Name = "sliderfBlendSplitDirShadow"; + this.sliderfBlendSplitDirShadow.Size = new System.Drawing.Size(255, 45); + this.sliderfBlendSplitDirShadow.SmallChange = 1000; + this.sliderfBlendSplitDirShadow.TabIndex = 36; + this.sliderfBlendSplitDirShadow.TickStyle = System.Windows.Forms.TickStyle.None; + this.toolTip.SetToolTip(this.sliderfBlendSplitDirShadow, "Distance at which the game will transition to lower-res a shadow \"segment\".\r\nMUST" + + " be a multiple of 12.\r\n\r\nAffected values: fBlendSplitDirShadow\r\nAffected files: " + + "Fallout76Prefs.ini"); + this.sliderfBlendSplitDirShadow.Value = 4; + // + // labeliDirShadowSplits + // + this.labeliDirShadowSplits.AutoSize = true; + this.labeliDirShadowSplits.ForeColor = System.Drawing.SystemColors.ControlText; + this.labeliDirShadowSplits.Location = new System.Drawing.Point(9, 24); + this.labeliDirShadowSplits.Name = "labeliDirShadowSplits"; + this.labeliDirShadowSplits.Size = new System.Drawing.Size(142, 13); + this.labeliDirShadowSplits.TabIndex = 33; + this.labeliDirShadowSplits.Text = "Shadow transition segments:"; + this.toolTip.SetToolTip(this.labeliDirShadowSplits, resources.GetString("labeliDirShadowSplits.ToolTip")); + // + // checkBoxTopMostWindow + // + this.checkBoxTopMostWindow.AutoSize = true; + this.checkBoxTopMostWindow.Location = new System.Drawing.Point(9, 129); + this.checkBoxTopMostWindow.Name = "checkBoxTopMostWindow"; + this.checkBoxTopMostWindow.Size = new System.Drawing.Size(109, 17); + this.checkBoxTopMostWindow.TabIndex = 21; + this.checkBoxTopMostWindow.Text = "Top-most window"; + this.checkBoxTopMostWindow.UseVisualStyleBackColor = true; + // // labelScreenshotIndex // this.labelScreenshotIndex.AutoSize = true; @@ -1906,267 +1648,595 @@ private void InitializeComponent() this.labelScreenshotIndex.Size = new System.Drawing.Size(92, 13); this.labelScreenshotIndex.TabIndex = 0; this.labelScreenshotIndex.Text = "Screenshot index:"; - this.toolTip.SetToolTip(this.labelScreenshotIndex, resources.GetString("labelScreenshotIndex.ToolTip")); - // - // checkBoxAlternativeINIMode - // - this.checkBoxAlternativeINIMode.AutoSize = true; - this.checkBoxAlternativeINIMode.Location = new System.Drawing.Point(10, 88); - this.checkBoxAlternativeINIMode.Name = "checkBoxAlternativeINIMode"; - this.checkBoxAlternativeINIMode.Size = new System.Drawing.Size(220, 17); - this.checkBoxAlternativeINIMode.TabIndex = 20; - this.checkBoxAlternativeINIMode.Text = "Don\'t use Fallout76Custom.ini for tweaks."; - this.toolTip.SetToolTip(this.checkBoxAlternativeINIMode, "Puts tweaks into Fallout76.ini and Fallout76Prefs.ini instead.\r\nDoes not affect t" + - "he mod manager.\r\nYou may need to remove tweaks from Fallout76Custom.ini manually" + - "."); - this.checkBoxAlternativeINIMode.UseVisualStyleBackColor = true; - this.checkBoxAlternativeINIMode.CheckedChanged += new System.EventHandler(this.checkBoxAlternativeINIMode_CheckedChanged); - // - // checkBoxAutoSignin - // - this.checkBoxAutoSignin.AutoSize = true; - this.checkBoxAutoSignin.Location = new System.Drawing.Point(12, 176); - this.checkBoxAutoSignin.Name = "checkBoxAutoSignin"; - this.checkBoxAutoSignin.Size = new System.Drawing.Size(121, 17); - this.checkBoxAutoSignin.TabIndex = 20; - this.checkBoxAutoSignin.Text = "Automatically sign-in"; - this.toolTip.SetToolTip(this.checkBoxAutoSignin, "Enabling this will skip the login prompt if you provide your login credentials.\r\n" + - "\r\nAffected values: bAutoSignin\r\nAffected files: Fallout76Custom.ini"); - this.checkBoxAutoSignin.UseVisualStyleBackColor = true; // - // checkBoxDisableSteam + // labelPipboyColor // - this.checkBoxDisableSteam.AutoSize = true; - this.checkBoxDisableSteam.Location = new System.Drawing.Point(12, 199); - this.checkBoxDisableSteam.Name = "checkBoxDisableSteam"; - this.checkBoxDisableSteam.Size = new System.Drawing.Size(94, 17); - this.checkBoxDisableSteam.TabIndex = 6; - this.checkBoxDisableSteam.Text = "Disable Steam"; - this.toolTip.SetToolTip(this.checkBoxDisableSteam, "Affected values: bSteamEnabled\r\nAffected files: Fallout76Custom.ini"); - this.checkBoxDisableSteam.UseVisualStyleBackColor = true; + this.labelPipboyColor.AutoSize = true; + this.labelPipboyColor.Location = new System.Drawing.Point(39, 24); + this.labelPipboyColor.Name = "labelPipboyColor"; + this.labelPipboyColor.Size = new System.Drawing.Size(70, 13); + this.labelPipboyColor.TabIndex = 32; + this.labelPipboyColor.Text = "Pip-Boy Color"; // - // timerCheckFiles + // labelQuickboyColor // - this.timerCheckFiles.Interval = 5000; - this.timerCheckFiles.Tick += new System.EventHandler(this.timerCheckFiles_Tick); + this.labelQuickboyColor.AutoSize = true; + this.labelQuickboyColor.Location = new System.Drawing.Point(39, 53); + this.labelQuickboyColor.Name = "labelQuickboyColor"; + this.labelQuickboyColor.Size = new System.Drawing.Size(83, 13); + this.labelQuickboyColor.TabIndex = 34; + this.labelQuickboyColor.Text = "Quick-Boy Color"; // - // openFileDialogGamePath + // labelPowerArmorColor // - this.openFileDialogGamePath.FileName = "Fallout76.exe"; - this.openFileDialogGamePath.Filter = "Fallout 76 executable|Fallout76.exe;Project76_GamePass.exe"; - this.openFileDialogGamePath.FilterIndex = 2; + this.labelPowerArmorColor.AutoSize = true; + this.labelPowerArmorColor.Location = new System.Drawing.Point(39, 82); + this.labelPowerArmorColor.Name = "labelPowerArmorColor"; + this.labelPowerArmorColor.Size = new System.Drawing.Size(94, 13); + this.labelPowerArmorColor.TabIndex = 37; + this.labelPowerArmorColor.Text = "Power Armor Color"; // - // tabPageCamera + // checkBoxDepthOfField // - this.tabPageCamera.AutoScroll = true; - this.tabPageCamera.Controls.Add(this.groupBoxCameraOptions); - this.tabPageCamera.Controls.Add(this.groupBoxCameraDistance); - this.tabPageCamera.Controls.Add(this.groupBoxCameraPositionWIP); - this.tabPageCamera.Controls.Add(this.groupBoxFieldOfView); - this.tabPageCamera.Controls.Add(this.groupBoxCameraVanity); - this.tabPageCamera.Location = new System.Drawing.Point(4, 22); - this.tabPageCamera.Name = "tabPageCamera"; - this.tabPageCamera.Padding = new System.Windows.Forms.Padding(3); - this.tabPageCamera.Size = new System.Drawing.Size(852, 464); - this.tabPageCamera.TabIndex = 7; - this.tabPageCamera.Text = "Camera"; - this.tabPageCamera.UseVisualStyleBackColor = true; + this.checkBoxDepthOfField.AutoSize = true; + this.checkBoxDepthOfField.Checked = true; + this.checkBoxDepthOfField.CheckState = System.Windows.Forms.CheckState.Checked; + this.checkBoxDepthOfField.Location = new System.Drawing.Point(9, 19); + this.checkBoxDepthOfField.Name = "checkBoxDepthOfField"; + this.checkBoxDepthOfField.Size = new System.Drawing.Size(92, 17); + this.checkBoxDepthOfField.TabIndex = 10; + this.checkBoxDepthOfField.Text = "Depth of Field"; + this.checkBoxDepthOfField.UseVisualStyleBackColor = true; // - // groupBoxCameraOptions + // labelDisplayMode // - this.groupBoxCameraOptions.Controls.Add(this.numCameraSwitchDelay); - this.groupBoxCameraOptions.Controls.Add(this.labelSwitchDelay); - this.groupBoxCameraOptions.Location = new System.Drawing.Point(413, 323); - this.groupBoxCameraOptions.Name = "groupBoxCameraOptions"; - this.groupBoxCameraOptions.Size = new System.Drawing.Size(433, 55); - this.groupBoxCameraOptions.TabIndex = 35; - this.groupBoxCameraOptions.TabStop = false; - this.groupBoxCameraOptions.Text = "Camera options"; + this.labelDisplayMode.AutoSize = true; + this.labelDisplayMode.Location = new System.Drawing.Point(6, 23); + this.labelDisplayMode.Name = "labelDisplayMode"; + this.labelDisplayMode.Size = new System.Drawing.Size(73, 13); + this.labelDisplayMode.TabIndex = 1; + this.labelDisplayMode.Text = "Display mode:"; // - // numCameraSwitchDelay + // checkBoxFixMouseSensitivity // - this.numCameraSwitchDelay.DecimalPlaces = 4; - this.numCameraSwitchDelay.Location = new System.Drawing.Point(304, 21); - this.numCameraSwitchDelay.Maximum = new decimal(new int[] { - 5, - 0, - 0, - 0}); - this.numCameraSwitchDelay.Minimum = new decimal(new int[] { - 1, - 0, - 0, - 262144}); - this.numCameraSwitchDelay.Name = "numCameraSwitchDelay"; - this.numCameraSwitchDelay.Size = new System.Drawing.Size(120, 20); - this.numCameraSwitchDelay.TabIndex = 1; - this.numCameraSwitchDelay.Value = new decimal(new int[] { - 25, - 0, - 0, - 131072}); + this.checkBoxFixMouseSensitivity.AutoSize = true; + this.checkBoxFixMouseSensitivity.Location = new System.Drawing.Point(9, 111); + this.checkBoxFixMouseSensitivity.Name = "checkBoxFixMouseSensitivity"; + this.checkBoxFixMouseSensitivity.Size = new System.Drawing.Size(208, 17); + this.checkBoxFixMouseSensitivity.TabIndex = 0; + this.checkBoxFixMouseSensitivity.Text = "Fix mouse horizontal/vertical sensitivity"; + this.checkBoxFixMouseSensitivity.UseVisualStyleBackColor = true; // - // groupBoxCameraDistance + // checkBoxEnableQuestAutoTrackMain // - this.groupBoxCameraDistance.Controls.Add(this.numfPitchZoomOutMaxDist); - this.groupBoxCameraDistance.Controls.Add(this.sliderfPitchZoomOutMaxDist); - this.groupBoxCameraDistance.Controls.Add(this.labelPitchZoomOutMaxDist); - this.groupBoxCameraDistance.Controls.Add(this.numCameraDistanceMaximum); - this.groupBoxCameraDistance.Controls.Add(this.numCameraDistanceMinimum); - this.groupBoxCameraDistance.Controls.Add(this.sliderCameraDistanceMaximum); - this.groupBoxCameraDistance.Controls.Add(this.labelCameraDistanceMaximum); - this.groupBoxCameraDistance.Controls.Add(this.labelCameraDistanceMinimum); - this.groupBoxCameraDistance.Controls.Add(this.sliderCameraDistanceMinimum); - this.groupBoxCameraDistance.Location = new System.Drawing.Point(413, 166); - this.groupBoxCameraDistance.Name = "groupBoxCameraDistance"; - this.groupBoxCameraDistance.Size = new System.Drawing.Size(433, 151); - this.groupBoxCameraDistance.TabIndex = 34; - this.groupBoxCameraDistance.TabStop = false; - this.groupBoxCameraDistance.Text = "Camera distance"; + this.checkBoxEnableQuestAutoTrackMain.AutoSize = true; + this.checkBoxEnableQuestAutoTrackMain.Location = new System.Drawing.Point(7, 19); + this.checkBoxEnableQuestAutoTrackMain.Name = "checkBoxEnableQuestAutoTrackMain"; + this.checkBoxEnableQuestAutoTrackMain.Size = new System.Drawing.Size(182, 17); + this.checkBoxEnableQuestAutoTrackMain.TabIndex = 5; + this.checkBoxEnableQuestAutoTrackMain.Text = "Main Quests Active when started"; + this.checkBoxEnableQuestAutoTrackMain.UseVisualStyleBackColor = true; // - // numfPitchZoomOutMaxDist + // checkBoxEnableQuestAutoTrackSide // - this.numfPitchZoomOutMaxDist.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); - this.numfPitchZoomOutMaxDist.Increment = new decimal(new int[] { - 10, + this.checkBoxEnableQuestAutoTrackSide.AutoSize = true; + this.checkBoxEnableQuestAutoTrackSide.Location = new System.Drawing.Point(7, 42); + this.checkBoxEnableQuestAutoTrackSide.Name = "checkBoxEnableQuestAutoTrackSide"; + this.checkBoxEnableQuestAutoTrackSide.Size = new System.Drawing.Size(180, 17); + this.checkBoxEnableQuestAutoTrackSide.TabIndex = 6; + this.checkBoxEnableQuestAutoTrackSide.Text = "Side Quests Active when started"; + this.checkBoxEnableQuestAutoTrackSide.UseVisualStyleBackColor = true; + // + // checkBoxEnableQuestAutoTrackMisc + // + this.checkBoxEnableQuestAutoTrackMisc.AutoSize = true; + this.checkBoxEnableQuestAutoTrackMisc.Location = new System.Drawing.Point(7, 65); + this.checkBoxEnableQuestAutoTrackMisc.Name = "checkBoxEnableQuestAutoTrackMisc"; + this.checkBoxEnableQuestAutoTrackMisc.Size = new System.Drawing.Size(226, 17); + this.checkBoxEnableQuestAutoTrackMisc.TabIndex = 7; + this.checkBoxEnableQuestAutoTrackMisc.Text = "Miscellaneous Quests Active when started"; + this.checkBoxEnableQuestAutoTrackMisc.UseVisualStyleBackColor = true; + // + // checkBoxEnableQuestAutoTrackEvent + // + this.checkBoxEnableQuestAutoTrackEvent.AutoSize = true; + this.checkBoxEnableQuestAutoTrackEvent.Location = new System.Drawing.Point(7, 88); + this.checkBoxEnableQuestAutoTrackEvent.Name = "checkBoxEnableQuestAutoTrackEvent"; + this.checkBoxEnableQuestAutoTrackEvent.Size = new System.Drawing.Size(187, 17); + this.checkBoxEnableQuestAutoTrackEvent.TabIndex = 8; + this.checkBoxEnableQuestAutoTrackEvent.Text = "Event Quests Active when started"; + this.checkBoxEnableQuestAutoTrackEvent.UseVisualStyleBackColor = true; + // + // checkBoxEnableQuestAutoTrackDaily + // + this.checkBoxEnableQuestAutoTrackDaily.AutoSize = true; + this.checkBoxEnableQuestAutoTrackDaily.Location = new System.Drawing.Point(7, 111); + this.checkBoxEnableQuestAutoTrackDaily.Name = "checkBoxEnableQuestAutoTrackDaily"; + this.checkBoxEnableQuestAutoTrackDaily.Size = new System.Drawing.Size(182, 17); + this.checkBoxEnableQuestAutoTrackDaily.TabIndex = 9; + this.checkBoxEnableQuestAutoTrackDaily.Text = "Daily Quests Active when started"; + this.checkBoxEnableQuestAutoTrackDaily.UseVisualStyleBackColor = true; + // + // checkBoxEnablePowerArmorHUD + // + this.checkBoxEnablePowerArmorHUD.AutoSize = true; + this.checkBoxEnablePowerArmorHUD.Location = new System.Drawing.Point(7, 324); + this.checkBoxEnablePowerArmorHUD.Name = "checkBoxEnablePowerArmorHUD"; + this.checkBoxEnablePowerArmorHUD.Size = new System.Drawing.Size(149, 17); + this.checkBoxEnablePowerArmorHUD.TabIndex = 5; + this.checkBoxEnablePowerArmorHUD.Text = "Enable Power Armor HUD"; + this.checkBoxEnablePowerArmorHUD.UseVisualStyleBackColor = true; + // + // checkBoxShowOtherPlayersNames + // + this.checkBoxShowOtherPlayersNames.AutoSize = true; + this.checkBoxShowOtherPlayersNames.Location = new System.Drawing.Point(7, 378); + this.checkBoxShowOtherPlayersNames.Name = "checkBoxShowOtherPlayersNames"; + this.checkBoxShowOtherPlayersNames.Size = new System.Drawing.Size(152, 17); + this.checkBoxShowOtherPlayersNames.TabIndex = 33; + this.checkBoxShowOtherPlayersNames.Text = "Show other players\' names"; + this.checkBoxShowOtherPlayersNames.UseVisualStyleBackColor = true; + // + // labelResolution + // + this.labelResolution.AutoSize = true; + this.labelResolution.Location = new System.Drawing.Point(6, 48); + this.labelResolution.Name = "labelResolution"; + this.labelResolution.Size = new System.Drawing.Size(60, 13); + this.labelResolution.TabIndex = 3; + this.labelResolution.Text = "Resolution:"; + // + // checkBoxIntroVideos + // + this.checkBoxIntroVideos.AutoSize = true; + this.checkBoxIntroVideos.Checked = true; + this.checkBoxIntroVideos.CheckState = System.Windows.Forms.CheckState.Checked; + this.checkBoxIntroVideos.Location = new System.Drawing.Point(7, 19); + this.checkBoxIntroVideos.Name = "checkBoxIntroVideos"; + this.checkBoxIntroVideos.Size = new System.Drawing.Size(103, 17); + this.checkBoxIntroVideos.TabIndex = 0; + this.checkBoxIntroVideos.Text = "Play intro videos"; + this.checkBoxIntroVideos.UseVisualStyleBackColor = true; + // + // checkBoxShowDamageNumbersA + // + this.checkBoxShowDamageNumbersA.AutoSize = true; + this.checkBoxShowDamageNumbersA.Location = new System.Drawing.Point(7, 19); + this.checkBoxShowDamageNumbersA.Name = "checkBoxShowDamageNumbersA"; + this.checkBoxShowDamageNumbersA.Size = new System.Drawing.Size(261, 17); + this.checkBoxShowDamageNumbersA.TabIndex = 2; + this.checkBoxShowDamageNumbersA.Text = "Show floating damage numbers (Adventure mode)"; + this.checkBoxShowDamageNumbersA.UseVisualStyleBackColor = true; + // + // checkBoxShowDamageNumbersNW + // + this.checkBoxShowDamageNumbersNW.AutoSize = true; + this.checkBoxShowDamageNumbersNW.Location = new System.Drawing.Point(7, 42); + this.checkBoxShowDamageNumbersNW.Name = "checkBoxShowDamageNumbersNW"; + this.checkBoxShowDamageNumbersNW.Size = new System.Drawing.Size(254, 17); + this.checkBoxShowDamageNumbersNW.TabIndex = 3; + this.checkBoxShowDamageNumbersNW.Text = "Show floating damage numbers (Nuclear Winter)"; + this.checkBoxShowDamageNumbersNW.UseVisualStyleBackColor = true; + // + // checkBoxShowCompass + // + this.checkBoxShowCompass.AutoSize = true; + this.checkBoxShowCompass.Location = new System.Drawing.Point(7, 347); + this.checkBoxShowCompass.Name = "checkBoxShowCompass"; + this.checkBoxShowCompass.Size = new System.Drawing.Size(98, 17); + this.checkBoxShowCompass.TabIndex = 4; + this.checkBoxShowCompass.Text = "Show compass"; + this.checkBoxShowCompass.UseVisualStyleBackColor = true; + // + // checkBoxShowCrosshair + // + this.checkBoxShowCrosshair.AutoSize = true; + this.checkBoxShowCrosshair.Location = new System.Drawing.Point(7, 301); + this.checkBoxShowCrosshair.Name = "checkBoxShowCrosshair"; + this.checkBoxShowCrosshair.Size = new System.Drawing.Size(98, 17); + this.checkBoxShowCrosshair.TabIndex = 6; + this.checkBoxShowCrosshair.Text = "Show crosshair"; + this.checkBoxShowCrosshair.UseVisualStyleBackColor = true; + // + // checkBoxItemRarityColorsNW + // + this.checkBoxItemRarityColorsNW.AutoSize = true; + this.checkBoxItemRarityColorsNW.Location = new System.Drawing.Point(7, 65); + this.checkBoxItemRarityColorsNW.Name = "checkBoxItemRarityColorsNW"; + this.checkBoxItemRarityColorsNW.Size = new System.Drawing.Size(211, 17); + this.checkBoxItemRarityColorsNW.TabIndex = 7; + this.checkBoxItemRarityColorsNW.Text = "Show item rarity colors (Nuclear Winter)"; + this.checkBoxItemRarityColorsNW.UseVisualStyleBackColor = true; + // + // checkBoxShowPublicTeamNotifications + // + this.checkBoxShowPublicTeamNotifications.AutoSize = true; + this.checkBoxShowPublicTeamNotifications.Location = new System.Drawing.Point(7, 88); + this.checkBoxShowPublicTeamNotifications.Name = "checkBoxShowPublicTeamNotifications"; + this.checkBoxShowPublicTeamNotifications.Size = new System.Drawing.Size(175, 17); + this.checkBoxShowPublicTeamNotifications.TabIndex = 8; + this.checkBoxShowPublicTeamNotifications.Text = "Enable public team notifications\r\n"; + this.checkBoxShowPublicTeamNotifications.UseVisualStyleBackColor = true; + // + // checkBoxShowFloatingQuestMarkers + // + this.checkBoxShowFloatingQuestMarkers.AutoSize = true; + this.checkBoxShowFloatingQuestMarkers.Location = new System.Drawing.Point(7, 212); + this.checkBoxShowFloatingQuestMarkers.Name = "checkBoxShowFloatingQuestMarkers"; + this.checkBoxShowFloatingQuestMarkers.Size = new System.Drawing.Size(159, 17); + this.checkBoxShowFloatingQuestMarkers.TabIndex = 9; + this.checkBoxShowFloatingQuestMarkers.Text = "Show floating quest markers\r\n"; + this.checkBoxShowFloatingQuestMarkers.UseVisualStyleBackColor = true; + // + // checkBoxShowFloatingQuestText + // + this.checkBoxShowFloatingQuestText.AutoSize = true; + this.checkBoxShowFloatingQuestText.Location = new System.Drawing.Point(7, 235); + this.checkBoxShowFloatingQuestText.Name = "checkBoxShowFloatingQuestText"; + this.checkBoxShowFloatingQuestText.Size = new System.Drawing.Size(139, 17); + this.checkBoxShowFloatingQuestText.TabIndex = 32; + this.checkBoxShowFloatingQuestText.Text = "Show floating quest text"; + this.checkBoxShowFloatingQuestText.UseVisualStyleBackColor = true; + // + // checkBoxSkipSplash + // + this.checkBoxSkipSplash.AutoSize = true; + this.checkBoxSkipSplash.Checked = true; + this.checkBoxSkipSplash.CheckState = System.Windows.Forms.CheckState.Checked; + this.checkBoxSkipSplash.Location = new System.Drawing.Point(7, 42); + this.checkBoxSkipSplash.Name = "checkBoxSkipSplash"; + this.checkBoxSkipSplash.Size = new System.Drawing.Size(215, 17); + this.checkBoxSkipSplash.TabIndex = 2; + this.checkBoxSkipSplash.Text = "Skip splash screen with news on startup"; + this.checkBoxSkipSplash.UseVisualStyleBackColor = true; + // + // colorDialog + // + this.colorDialog.AnyColor = true; + this.colorDialog.FullOpen = true; + this.colorDialog.SolidColorOnly = true; + // + // timerCheckFiles + // + this.timerCheckFiles.Interval = 5000; + this.timerCheckFiles.Tick += new System.EventHandler(this.timerCheckFiles_Tick); + // + // openFileDialogGamePath + // + this.openFileDialogGamePath.FileName = "Fallout76.exe"; + this.openFileDialogGamePath.Filter = "Fallout 76 executable|Fallout76.exe;Project76_GamePass.exe"; + this.openFileDialogGamePath.FilterIndex = 2; + // + // tabPageCamera + // + this.tabPageCamera.AutoScroll = true; + this.tabPageCamera.Controls.Add(this.panel2); + this.tabPageCamera.Location = new System.Drawing.Point(4, 22); + this.tabPageCamera.Name = "tabPageCamera"; + this.tabPageCamera.Padding = new System.Windows.Forms.Padding(3); + this.tabPageCamera.Size = new System.Drawing.Size(852, 464); + this.tabPageCamera.TabIndex = 7; + this.tabPageCamera.Text = "Camera"; + this.tabPageCamera.UseVisualStyleBackColor = true; + // + // panel2 + // + this.panel2.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.panel2.AutoScroll = true; + this.panel2.AutoScrollMargin = new System.Drawing.Size(6, 6); + this.panel2.Controls.Add(this.groupBoxCameraPosition); + this.panel2.Controls.Add(this.groupBoxSelfieCamera); + this.panel2.Controls.Add(this.groupBoxFieldOfView); + this.panel2.Controls.Add(this.groupBoxCameraOptions); + this.panel2.Controls.Add(this.groupBoxCameraDistance); + this.panel2.Location = new System.Drawing.Point(0, 0); + this.panel2.Name = "panel2"; + this.panel2.Size = new System.Drawing.Size(852, 464); + this.panel2.TabIndex = 36; + // + // groupBoxCameraPosition + // + this.groupBoxCameraPosition.Controls.Add(this.groupBox3); + this.groupBoxCameraPosition.Controls.Add(this.groupBox2); + this.groupBoxCameraPosition.Controls.Add(this.buttonCameraPositionReset); + this.groupBoxCameraPosition.Controls.Add(this.checkBoxbApplyCameraNodeAnimations); + this.groupBoxCameraPosition.Controls.Add(this.groupBoxUnarmedCameraPosition); + this.groupBoxCameraPosition.Location = new System.Drawing.Point(410, 307); + this.groupBoxCameraPosition.Name = "groupBoxCameraPosition"; + this.groupBoxCameraPosition.Size = new System.Drawing.Size(419, 588); + this.groupBoxCameraPosition.TabIndex = 33; + this.groupBoxCameraPosition.TabStop = false; + this.groupBoxCameraPosition.Text = "Camera position (Experimental)"; + // + // groupBox3 + // + this.groupBox3.Controls.Add(this.numfOverShoulderMeleeCombatAddY); + this.groupBox3.Controls.Add(this.labelfOverShoulderMeleeCombatAddY); + this.groupBox3.Controls.Add(this.numfOverShoulderMeleeCombatPosX); + this.groupBox3.Controls.Add(this.numfOverShoulderMeleeCombatPosZ); + this.groupBox3.Controls.Add(this.trackBarfOverShoulderMeleeCombatAddY); + this.groupBox3.Controls.Add(this.labelfOverShoulderMeleeCombatPosX); + this.groupBox3.Controls.Add(this.trackBarfOverShoulderMeleeCombatPosX); + this.groupBox3.Controls.Add(this.labelfOverShoulderMeleeCombatPosZ); + this.groupBox3.Controls.Add(this.trackBarfOverShoulderMeleeCombatPosZ); + this.groupBox3.Location = new System.Drawing.Point(6, 392); + this.groupBox3.Name = "groupBox3"; + this.groupBox3.Size = new System.Drawing.Size(407, 191); + this.groupBox3.TabIndex = 57; + this.groupBox3.TabStop = false; + this.groupBox3.Text = "Melee combat camera position"; + // + // numfOverShoulderMeleeCombatAddY + // + this.numfOverShoulderMeleeCombatAddY.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.numfOverShoulderMeleeCombatAddY.DecimalPlaces = 1; + this.numfOverShoulderMeleeCombatAddY.Location = new System.Drawing.Point(327, 134); + this.numfOverShoulderMeleeCombatAddY.Maximum = new decimal(new int[] { + 999999, 0, 0, 0}); - this.numfPitchZoomOutMaxDist.Location = new System.Drawing.Point(350, 99); - this.numfPitchZoomOutMaxDist.Maximum = new decimal(new int[] { - 9999, + this.numfOverShoulderMeleeCombatAddY.Minimum = new decimal(new int[] { + 999999, 0, 0, - 0}); - this.numfPitchZoomOutMaxDist.Name = "numfPitchZoomOutMaxDist"; - this.numfPitchZoomOutMaxDist.Size = new System.Drawing.Size(74, 20); - this.numfPitchZoomOutMaxDist.TabIndex = 59; - this.numfPitchZoomOutMaxDist.Value = new decimal(new int[] { - 100, + -2147483648}); + this.numfOverShoulderMeleeCombatAddY.Name = "numfOverShoulderMeleeCombatAddY"; + this.numfOverShoulderMeleeCombatAddY.Size = new System.Drawing.Size(74, 20); + this.numfOverShoulderMeleeCombatAddY.TabIndex = 71; + // + // labelfOverShoulderMeleeCombatAddY + // + this.labelfOverShoulderMeleeCombatAddY.AutoSize = true; + this.labelfOverShoulderMeleeCombatAddY.Location = new System.Drawing.Point(6, 118); + this.labelfOverShoulderMeleeCombatAddY.Name = "labelfOverShoulderMeleeCombatAddY"; + this.labelfOverShoulderMeleeCombatAddY.Size = new System.Drawing.Size(242, 13); + this.labelfOverShoulderMeleeCombatAddY.TabIndex = 56; + this.labelfOverShoulderMeleeCombatAddY.Text = "Further/Closer (fOverShoulderMeleeCombatAddY)"; + // + // numfOverShoulderMeleeCombatPosX + // + this.numfOverShoulderMeleeCombatPosX.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.numfOverShoulderMeleeCombatPosX.DecimalPlaces = 1; + this.numfOverShoulderMeleeCombatPosX.Location = new System.Drawing.Point(327, 84); + this.numfOverShoulderMeleeCombatPosX.Maximum = new decimal(new int[] { + 999999, 0, 0, 0}); + this.numfOverShoulderMeleeCombatPosX.Minimum = new decimal(new int[] { + 999999, + 0, + 0, + -2147483648}); + this.numfOverShoulderMeleeCombatPosX.Name = "numfOverShoulderMeleeCombatPosX"; + this.numfOverShoulderMeleeCombatPosX.Size = new System.Drawing.Size(74, 20); + this.numfOverShoulderMeleeCombatPosX.TabIndex = 70; // - // sliderfPitchZoomOutMaxDist + // numfOverShoulderMeleeCombatPosZ // - this.sliderfPitchZoomOutMaxDist.BackColor = System.Drawing.Color.White; - this.sliderfPitchZoomOutMaxDist.LargeChange = 50; - this.sliderfPitchZoomOutMaxDist.Location = new System.Drawing.Point(131, 101); - this.sliderfPitchZoomOutMaxDist.Maximum = 200; - this.sliderfPitchZoomOutMaxDist.Name = "sliderfPitchZoomOutMaxDist"; - this.sliderfPitchZoomOutMaxDist.Size = new System.Drawing.Size(213, 45); - this.sliderfPitchZoomOutMaxDist.SmallChange = 10; - this.sliderfPitchZoomOutMaxDist.TabIndex = 58; - this.sliderfPitchZoomOutMaxDist.TickStyle = System.Windows.Forms.TickStyle.None; - this.sliderfPitchZoomOutMaxDist.Value = 100; + this.numfOverShoulderMeleeCombatPosZ.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.numfOverShoulderMeleeCombatPosZ.DecimalPlaces = 1; + this.numfOverShoulderMeleeCombatPosZ.Location = new System.Drawing.Point(327, 36); + this.numfOverShoulderMeleeCombatPosZ.Maximum = new decimal(new int[] { + 999999, + 0, + 0, + 0}); + this.numfOverShoulderMeleeCombatPosZ.Minimum = new decimal(new int[] { + 999999, + 0, + 0, + -2147483648}); + this.numfOverShoulderMeleeCombatPosZ.Name = "numfOverShoulderMeleeCombatPosZ"; + this.numfOverShoulderMeleeCombatPosZ.Size = new System.Drawing.Size(74, 20); + this.numfOverShoulderMeleeCombatPosZ.TabIndex = 69; // - // numCameraDistanceMaximum + // trackBarfOverShoulderMeleeCombatAddY // - this.numCameraDistanceMaximum.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); - this.numCameraDistanceMaximum.Increment = new decimal(new int[] { - 10, + this.trackBarfOverShoulderMeleeCombatAddY.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.trackBarfOverShoulderMeleeCombatAddY.BackColor = System.Drawing.Color.White; + this.trackBarfOverShoulderMeleeCombatAddY.Location = new System.Drawing.Point(6, 134); + this.trackBarfOverShoulderMeleeCombatAddY.Maximum = 20; + this.trackBarfOverShoulderMeleeCombatAddY.Minimum = -20; + this.trackBarfOverShoulderMeleeCombatAddY.Name = "trackBarfOverShoulderMeleeCombatAddY"; + this.trackBarfOverShoulderMeleeCombatAddY.Size = new System.Drawing.Size(315, 45); + this.trackBarfOverShoulderMeleeCombatAddY.TabIndex = 55; + this.trackBarfOverShoulderMeleeCombatAddY.TickStyle = System.Windows.Forms.TickStyle.None; + // + // labelfOverShoulderMeleeCombatPosX + // + this.labelfOverShoulderMeleeCombatPosX.AutoSize = true; + this.labelfOverShoulderMeleeCombatPosX.Location = new System.Drawing.Point(6, 68); + this.labelfOverShoulderMeleeCombatPosX.Name = "labelfOverShoulderMeleeCombatPosX"; + this.labelfOverShoulderMeleeCombatPosX.Size = new System.Drawing.Size(222, 13); + this.labelfOverShoulderMeleeCombatPosX.TabIndex = 54; + this.labelfOverShoulderMeleeCombatPosX.Text = "Left/Right (fOverShoulderMeleeCombatPosX)"; + // + // trackBarfOverShoulderMeleeCombatPosX + // + this.trackBarfOverShoulderMeleeCombatPosX.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.trackBarfOverShoulderMeleeCombatPosX.BackColor = System.Drawing.Color.White; + this.trackBarfOverShoulderMeleeCombatPosX.Location = new System.Drawing.Point(6, 84); + this.trackBarfOverShoulderMeleeCombatPosX.Maximum = 25; + this.trackBarfOverShoulderMeleeCombatPosX.Minimum = -25; + this.trackBarfOverShoulderMeleeCombatPosX.Name = "trackBarfOverShoulderMeleeCombatPosX"; + this.trackBarfOverShoulderMeleeCombatPosX.Size = new System.Drawing.Size(315, 45); + this.trackBarfOverShoulderMeleeCombatPosX.TabIndex = 53; + this.trackBarfOverShoulderMeleeCombatPosX.TickStyle = System.Windows.Forms.TickStyle.None; + // + // labelfOverShoulderMeleeCombatPosZ + // + this.labelfOverShoulderMeleeCombatPosZ.AutoSize = true; + this.labelfOverShoulderMeleeCombatPosZ.Location = new System.Drawing.Point(6, 20); + this.labelfOverShoulderMeleeCombatPosZ.Name = "labelfOverShoulderMeleeCombatPosZ"; + this.labelfOverShoulderMeleeCombatPosZ.Size = new System.Drawing.Size(221, 13); + this.labelfOverShoulderMeleeCombatPosZ.TabIndex = 52; + this.labelfOverShoulderMeleeCombatPosZ.Text = "Down/Up (fOverShoulderMeleeCombatPosZ)"; + // + // trackBarfOverShoulderMeleeCombatPosZ + // + this.trackBarfOverShoulderMeleeCombatPosZ.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.trackBarfOverShoulderMeleeCombatPosZ.BackColor = System.Drawing.Color.White; + this.trackBarfOverShoulderMeleeCombatPosZ.Location = new System.Drawing.Point(6, 36); + this.trackBarfOverShoulderMeleeCombatPosZ.Maximum = 20; + this.trackBarfOverShoulderMeleeCombatPosZ.Minimum = -20; + this.trackBarfOverShoulderMeleeCombatPosZ.Name = "trackBarfOverShoulderMeleeCombatPosZ"; + this.trackBarfOverShoulderMeleeCombatPosZ.RightToLeft = System.Windows.Forms.RightToLeft.No; + this.trackBarfOverShoulderMeleeCombatPosZ.Size = new System.Drawing.Size(315, 45); + this.trackBarfOverShoulderMeleeCombatPosZ.TabIndex = 51; + this.trackBarfOverShoulderMeleeCombatPosZ.TickStyle = System.Windows.Forms.TickStyle.None; + // + // groupBox2 + // + this.groupBox2.Controls.Add(this.numfOverShoulderCombatAddY); + this.groupBox2.Controls.Add(this.numfOverShoulderCombatPosX); + this.groupBox2.Controls.Add(this.numfOverShoulderCombatPosZ); + this.groupBox2.Controls.Add(this.labelfOverShoulderCombatAddY); + this.groupBox2.Controls.Add(this.trackBarfOverShoulderCombatAddY); + this.groupBox2.Controls.Add(this.labelfOverShoulderCombatPosX); + this.groupBox2.Controls.Add(this.trackBarfOverShoulderCombatPosX); + this.groupBox2.Controls.Add(this.labelfOverShoulderCombatPosZ); + this.groupBox2.Controls.Add(this.trackBarfOverShoulderCombatPosZ); + this.groupBox2.Location = new System.Drawing.Point(6, 195); + this.groupBox2.Name = "groupBox2"; + this.groupBox2.Size = new System.Drawing.Size(407, 191); + this.groupBox2.TabIndex = 55; + this.groupBox2.TabStop = false; + this.groupBox2.Text = "Combat camera position"; + // + // numfOverShoulderCombatAddY + // + this.numfOverShoulderCombatAddY.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.numfOverShoulderCombatAddY.DecimalPlaces = 1; + this.numfOverShoulderCombatAddY.Location = new System.Drawing.Point(327, 134); + this.numfOverShoulderCombatAddY.Maximum = new decimal(new int[] { + 999999, 0, 0, 0}); - this.numCameraDistanceMaximum.Location = new System.Drawing.Point(350, 51); - this.numCameraDistanceMaximum.Maximum = new decimal(new int[] { - 9999, + this.numfOverShoulderCombatAddY.Minimum = new decimal(new int[] { + 999999, 0, 0, - 0}); - this.numCameraDistanceMaximum.Name = "numCameraDistanceMaximum"; - this.numCameraDistanceMaximum.Size = new System.Drawing.Size(74, 20); - this.numCameraDistanceMaximum.TabIndex = 56; - this.numCameraDistanceMaximum.Value = new decimal(new int[] { - 150, + -2147483648}); + this.numfOverShoulderCombatAddY.Name = "numfOverShoulderCombatAddY"; + this.numfOverShoulderCombatAddY.Size = new System.Drawing.Size(74, 20); + this.numfOverShoulderCombatAddY.TabIndex = 68; + // + // numfOverShoulderCombatPosX + // + this.numfOverShoulderCombatPosX.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.numfOverShoulderCombatPosX.DecimalPlaces = 1; + this.numfOverShoulderCombatPosX.Location = new System.Drawing.Point(327, 84); + this.numfOverShoulderCombatPosX.Maximum = new decimal(new int[] { + 999999, 0, 0, 0}); + this.numfOverShoulderCombatPosX.Minimum = new decimal(new int[] { + 999999, + 0, + 0, + -2147483648}); + this.numfOverShoulderCombatPosX.Name = "numfOverShoulderCombatPosX"; + this.numfOverShoulderCombatPosX.Size = new System.Drawing.Size(74, 20); + this.numfOverShoulderCombatPosX.TabIndex = 67; // - // numCameraDistanceMinimum + // numfOverShoulderCombatPosZ // - this.numCameraDistanceMinimum.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); - this.numCameraDistanceMinimum.Increment = new decimal(new int[] { - 10, + this.numfOverShoulderCombatPosZ.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.numfOverShoulderCombatPosZ.DecimalPlaces = 1; + this.numfOverShoulderCombatPosZ.Location = new System.Drawing.Point(327, 36); + this.numfOverShoulderCombatPosZ.Maximum = new decimal(new int[] { + 999999, 0, 0, 0}); - this.numCameraDistanceMinimum.Location = new System.Drawing.Point(350, 20); - this.numCameraDistanceMinimum.Maximum = new decimal(new int[] { - 9999, + this.numfOverShoulderCombatPosZ.Minimum = new decimal(new int[] { + 999999, 0, 0, - 0}); - this.numCameraDistanceMinimum.Name = "numCameraDistanceMinimum"; - this.numCameraDistanceMinimum.Size = new System.Drawing.Size(74, 20); - this.numCameraDistanceMinimum.TabIndex = 55; - // - // sliderCameraDistanceMaximum + -2147483648}); + this.numfOverShoulderCombatPosZ.Name = "numfOverShoulderCombatPosZ"; + this.numfOverShoulderCombatPosZ.Size = new System.Drawing.Size(74, 20); + this.numfOverShoulderCombatPosZ.TabIndex = 66; // - this.sliderCameraDistanceMaximum.BackColor = System.Drawing.Color.White; - this.sliderCameraDistanceMaximum.LargeChange = 200; - this.sliderCameraDistanceMaximum.Location = new System.Drawing.Point(131, 51); - this.sliderCameraDistanceMaximum.Maximum = 1000; - this.sliderCameraDistanceMaximum.Minimum = 100; - this.sliderCameraDistanceMaximum.Name = "sliderCameraDistanceMaximum"; - this.sliderCameraDistanceMaximum.Size = new System.Drawing.Size(213, 45); - this.sliderCameraDistanceMaximum.SmallChange = 50; - this.sliderCameraDistanceMaximum.TabIndex = 54; - this.sliderCameraDistanceMaximum.TickStyle = System.Windows.Forms.TickStyle.None; - this.sliderCameraDistanceMaximum.Value = 150; + // labelfOverShoulderCombatAddY // - // sliderCameraDistanceMinimum + this.labelfOverShoulderCombatAddY.AutoSize = true; + this.labelfOverShoulderCombatAddY.Location = new System.Drawing.Point(6, 118); + this.labelfOverShoulderCombatAddY.Name = "labelfOverShoulderCombatAddY"; + this.labelfOverShoulderCombatAddY.Size = new System.Drawing.Size(213, 13); + this.labelfOverShoulderCombatAddY.TabIndex = 56; + this.labelfOverShoulderCombatAddY.Text = "Further/Closer (fOverShoulderCombatAddY)"; // - this.sliderCameraDistanceMinimum.BackColor = System.Drawing.Color.White; - this.sliderCameraDistanceMinimum.LargeChange = 20; - this.sliderCameraDistanceMinimum.Location = new System.Drawing.Point(131, 19); - this.sliderCameraDistanceMinimum.Maximum = 100; - this.sliderCameraDistanceMinimum.Name = "sliderCameraDistanceMinimum"; - this.sliderCameraDistanceMinimum.Size = new System.Drawing.Size(213, 45); - this.sliderCameraDistanceMinimum.SmallChange = 10; - this.sliderCameraDistanceMinimum.TabIndex = 51; - this.sliderCameraDistanceMinimum.TickStyle = System.Windows.Forms.TickStyle.None; + // trackBarfOverShoulderCombatAddY // - // groupBoxCameraPositionWIP - // - this.groupBoxCameraPositionWIP.Controls.Add(this.buttonCameraPositionCenter); - this.groupBoxCameraPositionWIP.Controls.Add(this.buttonCameraPositionReset); - this.groupBoxCameraPositionWIP.Controls.Add(this.labelCameraPositionPlayer); - this.groupBoxCameraPositionWIP.Controls.Add(this.labelCameraPositionFor); - this.groupBoxCameraPositionWIP.Controls.Add(this.checkBoxbApplyCameraNodeAnimations); - this.groupBoxCameraPositionWIP.Controls.Add(this.radioButtonCameraPositionMeleeCombat); - this.groupBoxCameraPositionWIP.Controls.Add(this.radioButtonCameraPositionCombat); - this.groupBoxCameraPositionWIP.Controls.Add(this.radioButtonCameraPositionUnarmed); - this.groupBoxCameraPositionWIP.Controls.Add(this.labelCameraFurther); - this.groupBoxCameraPositionWIP.Controls.Add(this.labelCameraCloser); - this.groupBoxCameraPositionWIP.Controls.Add(this.labelCameraUp); - this.groupBoxCameraPositionWIP.Controls.Add(this.labelCameraDown); - this.groupBoxCameraPositionWIP.Controls.Add(this.labelCameraRight); - this.groupBoxCameraPositionWIP.Controls.Add(this.labelCameraLeft); - this.groupBoxCameraPositionWIP.Controls.Add(this.trackBarCameraX); - this.groupBoxCameraPositionWIP.Controls.Add(this.trackBarCameraZ); - this.groupBoxCameraPositionWIP.Controls.Add(this.trackBarCameraY); - this.groupBoxCameraPositionWIP.Controls.Add(this.pictureBoxVaultBoy); - this.groupBoxCameraPositionWIP.Location = new System.Drawing.Point(6, 6); - this.groupBoxCameraPositionWIP.Name = "groupBoxCameraPositionWIP"; - this.groupBoxCameraPositionWIP.Size = new System.Drawing.Size(398, 452); - this.groupBoxCameraPositionWIP.TabIndex = 33; - this.groupBoxCameraPositionWIP.TabStop = false; - this.groupBoxCameraPositionWIP.Text = "Camera position (WORK IN PROGRESS)"; - // - // buttonCameraPositionCenter - // - this.buttonCameraPositionCenter.Location = new System.Drawing.Point(221, 369); - this.buttonCameraPositionCenter.Name = "buttonCameraPositionCenter"; - this.buttonCameraPositionCenter.Size = new System.Drawing.Size(171, 23); - this.buttonCameraPositionCenter.TabIndex = 50; - this.buttonCameraPositionCenter.Text = "Center"; - this.buttonCameraPositionCenter.UseVisualStyleBackColor = true; - this.buttonCameraPositionCenter.Click += new System.EventHandler(this.buttonCameraPositionCenter_Click); + this.trackBarfOverShoulderCombatAddY.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.trackBarfOverShoulderCombatAddY.BackColor = System.Drawing.Color.White; + this.trackBarfOverShoulderCombatAddY.Location = new System.Drawing.Point(6, 134); + this.trackBarfOverShoulderCombatAddY.Maximum = 20; + this.trackBarfOverShoulderCombatAddY.Minimum = -20; + this.trackBarfOverShoulderCombatAddY.Name = "trackBarfOverShoulderCombatAddY"; + this.trackBarfOverShoulderCombatAddY.Size = new System.Drawing.Size(315, 45); + this.trackBarfOverShoulderCombatAddY.TabIndex = 55; + this.trackBarfOverShoulderCombatAddY.TickStyle = System.Windows.Forms.TickStyle.None; + // + // labelfOverShoulderCombatPosX + // + this.labelfOverShoulderCombatPosX.AutoSize = true; + this.labelfOverShoulderCombatPosX.Location = new System.Drawing.Point(6, 68); + this.labelfOverShoulderCombatPosX.Name = "labelfOverShoulderCombatPosX"; + this.labelfOverShoulderCombatPosX.Size = new System.Drawing.Size(193, 13); + this.labelfOverShoulderCombatPosX.TabIndex = 54; + this.labelfOverShoulderCombatPosX.Text = "Left/Right (fOverShoulderCombatPosX)"; + // + // trackBarfOverShoulderCombatPosX + // + this.trackBarfOverShoulderCombatPosX.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.trackBarfOverShoulderCombatPosX.BackColor = System.Drawing.Color.White; + this.trackBarfOverShoulderCombatPosX.Location = new System.Drawing.Point(6, 84); + this.trackBarfOverShoulderCombatPosX.Maximum = 25; + this.trackBarfOverShoulderCombatPosX.Minimum = -25; + this.trackBarfOverShoulderCombatPosX.Name = "trackBarfOverShoulderCombatPosX"; + this.trackBarfOverShoulderCombatPosX.Size = new System.Drawing.Size(315, 45); + this.trackBarfOverShoulderCombatPosX.TabIndex = 53; + this.trackBarfOverShoulderCombatPosX.TickStyle = System.Windows.Forms.TickStyle.None; + // + // labelfOverShoulderCombatPosZ + // + this.labelfOverShoulderCombatPosZ.AutoSize = true; + this.labelfOverShoulderCombatPosZ.Location = new System.Drawing.Point(6, 20); + this.labelfOverShoulderCombatPosZ.Name = "labelfOverShoulderCombatPosZ"; + this.labelfOverShoulderCombatPosZ.Size = new System.Drawing.Size(192, 13); + this.labelfOverShoulderCombatPosZ.TabIndex = 52; + this.labelfOverShoulderCombatPosZ.Text = "Down/Up (fOverShoulderCombatPosZ)"; + // + // trackBarfOverShoulderCombatPosZ + // + this.trackBarfOverShoulderCombatPosZ.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.trackBarfOverShoulderCombatPosZ.BackColor = System.Drawing.Color.White; + this.trackBarfOverShoulderCombatPosZ.Location = new System.Drawing.Point(6, 36); + this.trackBarfOverShoulderCombatPosZ.Maximum = 20; + this.trackBarfOverShoulderCombatPosZ.Minimum = -20; + this.trackBarfOverShoulderCombatPosZ.Name = "trackBarfOverShoulderCombatPosZ"; + this.trackBarfOverShoulderCombatPosZ.RightToLeft = System.Windows.Forms.RightToLeft.No; + this.trackBarfOverShoulderCombatPosZ.Size = new System.Drawing.Size(315, 45); + this.trackBarfOverShoulderCombatPosZ.TabIndex = 51; + this.trackBarfOverShoulderCombatPosZ.TickStyle = System.Windows.Forms.TickStyle.None; // // buttonCameraPositionReset // - this.buttonCameraPositionReset.Location = new System.Drawing.Point(221, 340); + this.buttonCameraPositionReset.Location = new System.Drawing.Point(242, 18); this.buttonCameraPositionReset.Name = "buttonCameraPositionReset"; this.buttonCameraPositionReset.Size = new System.Drawing.Size(171, 23); this.buttonCameraPositionReset.TabIndex = 49; @@ -2174,160 +2244,234 @@ private void InitializeComponent() this.buttonCameraPositionReset.UseVisualStyleBackColor = true; this.buttonCameraPositionReset.Click += new System.EventHandler(this.buttonCameraPositionReset_Click); // - // labelCameraPositionPlayer - // - this.labelCameraPositionPlayer.AutoSize = true; - this.labelCameraPositionPlayer.Location = new System.Drawing.Point(145, 110); - this.labelCameraPositionPlayer.Name = "labelCameraPositionPlayer"; - this.labelCameraPositionPlayer.Size = new System.Drawing.Size(39, 13); - this.labelCameraPositionPlayer.TabIndex = 48; - this.labelCameraPositionPlayer.Text = "Player:"; - // - // labelCameraPositionFor - // - this.labelCameraPositionFor.AutoSize = true; - this.labelCameraPositionFor.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.labelCameraPositionFor.Location = new System.Drawing.Point(6, 340); - this.labelCameraPositionFor.Name = "labelCameraPositionFor"; - this.labelCameraPositionFor.Size = new System.Drawing.Size(121, 13); - this.labelCameraPositionFor.TabIndex = 47; - this.labelCameraPositionFor.Text = "Change position for:"; - // - // radioButtonCameraPositionMeleeCombat - // - this.radioButtonCameraPositionMeleeCombat.AutoSize = true; - this.radioButtonCameraPositionMeleeCombat.Location = new System.Drawing.Point(9, 405); - this.radioButtonCameraPositionMeleeCombat.Name = "radioButtonCameraPositionMeleeCombat"; - this.radioButtonCameraPositionMeleeCombat.Size = new System.Drawing.Size(92, 17); - this.radioButtonCameraPositionMeleeCombat.TabIndex = 45; - this.radioButtonCameraPositionMeleeCombat.Text = "Melee combat"; - this.radioButtonCameraPositionMeleeCombat.UseVisualStyleBackColor = true; - this.radioButtonCameraPositionMeleeCombat.CheckedChanged += new System.EventHandler(this.radioButtonCameraPositionMeleeCombat_CheckedChanged); - // - // radioButtonCameraPositionCombat - // - this.radioButtonCameraPositionCombat.AutoSize = true; - this.radioButtonCameraPositionCombat.Location = new System.Drawing.Point(9, 382); - this.radioButtonCameraPositionCombat.Name = "radioButtonCameraPositionCombat"; - this.radioButtonCameraPositionCombat.Size = new System.Drawing.Size(61, 17); - this.radioButtonCameraPositionCombat.TabIndex = 44; - this.radioButtonCameraPositionCombat.Text = "Combat"; - this.radioButtonCameraPositionCombat.UseVisualStyleBackColor = true; - this.radioButtonCameraPositionCombat.CheckedChanged += new System.EventHandler(this.radioButtonCameraPositionCombat_CheckedChanged); - // - // radioButtonCameraPositionUnarmed - // - this.radioButtonCameraPositionUnarmed.AutoSize = true; - this.radioButtonCameraPositionUnarmed.Checked = true; - this.radioButtonCameraPositionUnarmed.Location = new System.Drawing.Point(9, 359); - this.radioButtonCameraPositionUnarmed.Name = "radioButtonCameraPositionUnarmed"; - this.radioButtonCameraPositionUnarmed.Size = new System.Drawing.Size(68, 17); - this.radioButtonCameraPositionUnarmed.TabIndex = 43; - this.radioButtonCameraPositionUnarmed.TabStop = true; - this.radioButtonCameraPositionUnarmed.Text = "Unarmed"; - this.radioButtonCameraPositionUnarmed.UseVisualStyleBackColor = true; - this.radioButtonCameraPositionUnarmed.CheckedChanged += new System.EventHandler(this.radioButtonCameraPositionUnarmed_CheckedChanged); - // - // labelCameraFurther - // - this.labelCameraFurther.AutoSize = true; - this.labelCameraFurther.Location = new System.Drawing.Point(341, 260); - this.labelCameraFurther.Name = "labelCameraFurther"; - this.labelCameraFurther.Size = new System.Drawing.Size(40, 13); - this.labelCameraFurther.TabIndex = 42; - this.labelCameraFurther.Text = "Further"; - // - // labelCameraCloser - // - this.labelCameraCloser.AutoSize = true; - this.labelCameraCloser.Location = new System.Drawing.Point(345, 14); - this.labelCameraCloser.Name = "labelCameraCloser"; - this.labelCameraCloser.Size = new System.Drawing.Size(36, 13); - this.labelCameraCloser.TabIndex = 41; - this.labelCameraCloser.Text = "Closer"; - // - // labelCameraUp - // - this.labelCameraUp.AutoSize = true; - this.labelCameraUp.Location = new System.Drawing.Point(21, 14); - this.labelCameraUp.Name = "labelCameraUp"; - this.labelCameraUp.Size = new System.Drawing.Size(21, 13); - this.labelCameraUp.TabIndex = 40; - this.labelCameraUp.Text = "Up"; - // - // labelCameraDown - // - this.labelCameraDown.AutoSize = true; - this.labelCameraDown.Location = new System.Drawing.Point(18, 260); - this.labelCameraDown.Name = "labelCameraDown"; - this.labelCameraDown.Size = new System.Drawing.Size(35, 13); - this.labelCameraDown.TabIndex = 39; - this.labelCameraDown.Text = "Down"; - // - // labelCameraRight - // - this.labelCameraRight.AutoSize = true; - this.labelCameraRight.Location = new System.Drawing.Point(357, 291); - this.labelCameraRight.Name = "labelCameraRight"; - this.labelCameraRight.Size = new System.Drawing.Size(32, 13); - this.labelCameraRight.TabIndex = 38; - this.labelCameraRight.Text = "Right"; - // - // labelCameraLeft - // - this.labelCameraLeft.AutoSize = true; - this.labelCameraLeft.Location = new System.Drawing.Point(6, 291); - this.labelCameraLeft.Name = "labelCameraLeft"; - this.labelCameraLeft.Size = new System.Drawing.Size(25, 13); - this.labelCameraLeft.TabIndex = 37; - this.labelCameraLeft.Text = "Left"; - // - // trackBarCameraX - // - this.trackBarCameraX.BackColor = System.Drawing.Color.White; - this.trackBarCameraX.Location = new System.Drawing.Point(37, 281); - this.trackBarCameraX.Maximum = 25; - this.trackBarCameraX.Minimum = -25; - this.trackBarCameraX.Name = "trackBarCameraX"; - this.trackBarCameraX.Size = new System.Drawing.Size(316, 45); - this.trackBarCameraX.TabIndex = 36; - this.trackBarCameraX.Scroll += new System.EventHandler(this.trackBarCameraX_Scroll); - // - // trackBarCameraZ - // - this.trackBarCameraZ.BackColor = System.Drawing.Color.White; - this.trackBarCameraZ.Location = new System.Drawing.Point(21, 30); - this.trackBarCameraZ.Maximum = 20; - this.trackBarCameraZ.Minimum = -20; - this.trackBarCameraZ.Name = "trackBarCameraZ"; - this.trackBarCameraZ.Orientation = System.Windows.Forms.Orientation.Vertical; - this.trackBarCameraZ.RightToLeft = System.Windows.Forms.RightToLeft.No; - this.trackBarCameraZ.Size = new System.Drawing.Size(45, 227); - this.trackBarCameraZ.TabIndex = 35; - this.trackBarCameraZ.Scroll += new System.EventHandler(this.trackBarCameraZ_Scroll); - // - // trackBarCameraY - // - this.trackBarCameraY.BackColor = System.Drawing.Color.White; - this.trackBarCameraY.Location = new System.Drawing.Point(348, 30); - this.trackBarCameraY.Maximum = 20; - this.trackBarCameraY.Minimum = -20; - this.trackBarCameraY.Name = "trackBarCameraY"; - this.trackBarCameraY.Orientation = System.Windows.Forms.Orientation.Vertical; - this.trackBarCameraY.Size = new System.Drawing.Size(45, 227); - this.trackBarCameraY.TabIndex = 34; - this.trackBarCameraY.TickStyle = System.Windows.Forms.TickStyle.TopLeft; - this.trackBarCameraY.Scroll += new System.EventHandler(this.trackBarCameraY_Scroll); - // - // pictureBoxVaultBoy - // - this.pictureBoxVaultBoy.Image = global::Fo76ini.Properties.Resources.VaultBoyThumbsUp_200px; - this.pictureBoxVaultBoy.Location = new System.Drawing.Point(148, 126); - this.pictureBoxVaultBoy.Name = "pictureBoxVaultBoy"; - this.pictureBoxVaultBoy.Size = new System.Drawing.Size(93, 121); - this.pictureBoxVaultBoy.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom; - this.pictureBoxVaultBoy.TabIndex = 33; - this.pictureBoxVaultBoy.TabStop = false; + // groupBoxUnarmedCameraPosition + // + this.groupBoxUnarmedCameraPosition.Controls.Add(this.numfOverShoulderPosX); + this.groupBoxUnarmedCameraPosition.Controls.Add(this.numfOverShoulderPosZ); + this.groupBoxUnarmedCameraPosition.Controls.Add(this.labelfOverShoulderPosX); + this.groupBoxUnarmedCameraPosition.Controls.Add(this.trackBarfOverShoulderPosX); + this.groupBoxUnarmedCameraPosition.Controls.Add(this.labelfOverShoulderPosZ); + this.groupBoxUnarmedCameraPosition.Controls.Add(this.trackBarfOverShoulderPosZ); + this.groupBoxUnarmedCameraPosition.Location = new System.Drawing.Point(6, 55); + this.groupBoxUnarmedCameraPosition.Name = "groupBoxUnarmedCameraPosition"; + this.groupBoxUnarmedCameraPosition.Size = new System.Drawing.Size(407, 134); + this.groupBoxUnarmedCameraPosition.TabIndex = 37; + this.groupBoxUnarmedCameraPosition.TabStop = false; + this.groupBoxUnarmedCameraPosition.Text = "Unarmed camera position"; + // + // numfOverShoulderPosX + // + this.numfOverShoulderPosX.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.numfOverShoulderPosX.DecimalPlaces = 1; + this.numfOverShoulderPosX.Location = new System.Drawing.Point(327, 84); + this.numfOverShoulderPosX.Maximum = new decimal(new int[] { + 999999, + 0, + 0, + 0}); + this.numfOverShoulderPosX.Minimum = new decimal(new int[] { + 999999, + 0, + 0, + -2147483648}); + this.numfOverShoulderPosX.Name = "numfOverShoulderPosX"; + this.numfOverShoulderPosX.Size = new System.Drawing.Size(74, 20); + this.numfOverShoulderPosX.TabIndex = 70; + // + // numfOverShoulderPosZ + // + this.numfOverShoulderPosZ.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.numfOverShoulderPosZ.DecimalPlaces = 1; + this.numfOverShoulderPosZ.Location = new System.Drawing.Point(327, 36); + this.numfOverShoulderPosZ.Maximum = new decimal(new int[] { + 999999, + 0, + 0, + 0}); + this.numfOverShoulderPosZ.Minimum = new decimal(new int[] { + 999999, + 0, + 0, + -2147483648}); + this.numfOverShoulderPosZ.Name = "numfOverShoulderPosZ"; + this.numfOverShoulderPosZ.Size = new System.Drawing.Size(74, 20); + this.numfOverShoulderPosZ.TabIndex = 69; + // + // labelfOverShoulderPosX + // + this.labelfOverShoulderPosX.AutoSize = true; + this.labelfOverShoulderPosX.Location = new System.Drawing.Point(6, 68); + this.labelfOverShoulderPosX.Name = "labelfOverShoulderPosX"; + this.labelfOverShoulderPosX.Size = new System.Drawing.Size(157, 13); + this.labelfOverShoulderPosX.TabIndex = 54; + this.labelfOverShoulderPosX.Text = "Left/Right (fOverShoulderPosX)"; + // + // trackBarfOverShoulderPosX + // + this.trackBarfOverShoulderPosX.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.trackBarfOverShoulderPosX.BackColor = System.Drawing.Color.White; + this.trackBarfOverShoulderPosX.Location = new System.Drawing.Point(6, 84); + this.trackBarfOverShoulderPosX.Maximum = 25; + this.trackBarfOverShoulderPosX.Minimum = -25; + this.trackBarfOverShoulderPosX.Name = "trackBarfOverShoulderPosX"; + this.trackBarfOverShoulderPosX.Size = new System.Drawing.Size(315, 45); + this.trackBarfOverShoulderPosX.TabIndex = 53; + this.trackBarfOverShoulderPosX.TickStyle = System.Windows.Forms.TickStyle.None; + // + // labelfOverShoulderPosZ + // + this.labelfOverShoulderPosZ.AutoSize = true; + this.labelfOverShoulderPosZ.Location = new System.Drawing.Point(6, 20); + this.labelfOverShoulderPosZ.Name = "labelfOverShoulderPosZ"; + this.labelfOverShoulderPosZ.Size = new System.Drawing.Size(156, 13); + this.labelfOverShoulderPosZ.TabIndex = 52; + this.labelfOverShoulderPosZ.Text = "Down/Up (fOverShoulderPosZ)"; + // + // trackBarfOverShoulderPosZ + // + this.trackBarfOverShoulderPosZ.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.trackBarfOverShoulderPosZ.BackColor = System.Drawing.Color.White; + this.trackBarfOverShoulderPosZ.Location = new System.Drawing.Point(6, 36); + this.trackBarfOverShoulderPosZ.Maximum = 20; + this.trackBarfOverShoulderPosZ.Minimum = -20; + this.trackBarfOverShoulderPosZ.Name = "trackBarfOverShoulderPosZ"; + this.trackBarfOverShoulderPosZ.RightToLeft = System.Windows.Forms.RightToLeft.No; + this.trackBarfOverShoulderPosZ.Size = new System.Drawing.Size(315, 45); + this.trackBarfOverShoulderPosZ.TabIndex = 51; + this.trackBarfOverShoulderPosZ.TickStyle = System.Windows.Forms.TickStyle.None; + // + // groupBoxSelfieCamera + // + this.groupBoxSelfieCamera.Controls.Add(this.trackBarPhotomodeRange); + this.groupBoxSelfieCamera.Controls.Add(this.numericUpDownPhotomodeRotationSpeed); + this.groupBoxSelfieCamera.Controls.Add(this.trackBarPhotomodeRotationSpeed); + this.groupBoxSelfieCamera.Controls.Add(this.labelPhotomodeRotationSpeed); + this.groupBoxSelfieCamera.Controls.Add(this.numericUpDownPhotomodeRange); + this.groupBoxSelfieCamera.Controls.Add(this.labelPhotomodeRange); + this.groupBoxSelfieCamera.Controls.Add(this.numericUpDownPhotomodeTranslationSpeed); + this.groupBoxSelfieCamera.Controls.Add(this.trackBarPhotomodeTranslationSpeed); + this.groupBoxSelfieCamera.Controls.Add(this.labelPhotomodeTranslationSpeed); + this.groupBoxSelfieCamera.Location = new System.Drawing.Point(410, 167); + this.groupBoxSelfieCamera.Name = "groupBoxSelfieCamera"; + this.groupBoxSelfieCamera.Size = new System.Drawing.Size(419, 134); + this.groupBoxSelfieCamera.TabIndex = 36; + this.groupBoxSelfieCamera.TabStop = false; + this.groupBoxSelfieCamera.Text = "Photomode options"; + // + // trackBarPhotomodeRange + // + this.trackBarPhotomodeRange.BackColor = System.Drawing.Color.White; + this.trackBarPhotomodeRange.LargeChange = 100; + this.trackBarPhotomodeRange.Location = new System.Drawing.Point(131, 85); + this.trackBarPhotomodeRange.Maximum = 2000; + this.trackBarPhotomodeRange.Minimum = 10; + this.trackBarPhotomodeRange.Name = "trackBarPhotomodeRange"; + this.trackBarPhotomodeRange.Size = new System.Drawing.Size(186, 45); + this.trackBarPhotomodeRange.SmallChange = 20; + this.trackBarPhotomodeRange.TabIndex = 61; + this.trackBarPhotomodeRange.TickStyle = System.Windows.Forms.TickStyle.None; + this.trackBarPhotomodeRange.Value = 500; + // + // numericUpDownPhotomodeRotationSpeed + // + this.numericUpDownPhotomodeRotationSpeed.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.numericUpDownPhotomodeRotationSpeed.DecimalPlaces = 1; + this.numericUpDownPhotomodeRotationSpeed.Location = new System.Drawing.Point(336, 51); + this.numericUpDownPhotomodeRotationSpeed.Maximum = new decimal(new int[] { + 9999, + 0, + 0, + 0}); + this.numericUpDownPhotomodeRotationSpeed.Minimum = new decimal(new int[] { + 1, + 0, + 0, + 65536}); + this.numericUpDownPhotomodeRotationSpeed.Name = "numericUpDownPhotomodeRotationSpeed"; + this.numericUpDownPhotomodeRotationSpeed.Size = new System.Drawing.Size(74, 20); + this.numericUpDownPhotomodeRotationSpeed.TabIndex = 65; + this.numericUpDownPhotomodeRotationSpeed.Value = new decimal(new int[] { + 15, + 0, + 0, + 65536}); + // + // trackBarPhotomodeRotationSpeed + // + this.trackBarPhotomodeRotationSpeed.BackColor = System.Drawing.Color.White; + this.trackBarPhotomodeRotationSpeed.LargeChange = 50; + this.trackBarPhotomodeRotationSpeed.Location = new System.Drawing.Point(131, 51); + this.trackBarPhotomodeRotationSpeed.Maximum = 50; + this.trackBarPhotomodeRotationSpeed.Minimum = 5; + this.trackBarPhotomodeRotationSpeed.Name = "trackBarPhotomodeRotationSpeed"; + this.trackBarPhotomodeRotationSpeed.Size = new System.Drawing.Size(186, 45); + this.trackBarPhotomodeRotationSpeed.SmallChange = 10; + this.trackBarPhotomodeRotationSpeed.TabIndex = 64; + this.trackBarPhotomodeRotationSpeed.TickStyle = System.Windows.Forms.TickStyle.None; + this.trackBarPhotomodeRotationSpeed.Value = 15; + // + // numericUpDownPhotomodeRange + // + this.numericUpDownPhotomodeRange.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.numericUpDownPhotomodeRange.Location = new System.Drawing.Point(336, 85); + this.numericUpDownPhotomodeRange.Maximum = new decimal(new int[] { + 9999999, + 0, + 0, + 0}); + this.numericUpDownPhotomodeRange.Minimum = new decimal(new int[] { + 1, + 0, + 0, + 0}); + this.numericUpDownPhotomodeRange.Name = "numericUpDownPhotomodeRange"; + this.numericUpDownPhotomodeRange.Size = new System.Drawing.Size(74, 20); + this.numericUpDownPhotomodeRange.TabIndex = 62; + this.numericUpDownPhotomodeRange.Value = new decimal(new int[] { + 500, + 0, + 0, + 0}); + // + // numericUpDownPhotomodeTranslationSpeed + // + this.numericUpDownPhotomodeTranslationSpeed.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.numericUpDownPhotomodeTranslationSpeed.DecimalPlaces = 1; + this.numericUpDownPhotomodeTranslationSpeed.Location = new System.Drawing.Point(336, 21); + this.numericUpDownPhotomodeTranslationSpeed.Maximum = new decimal(new int[] { + 9999, + 0, + 0, + 0}); + this.numericUpDownPhotomodeTranslationSpeed.Minimum = new decimal(new int[] { + 1, + 0, + 0, + 65536}); + this.numericUpDownPhotomodeTranslationSpeed.Name = "numericUpDownPhotomodeTranslationSpeed"; + this.numericUpDownPhotomodeTranslationSpeed.Size = new System.Drawing.Size(74, 20); + this.numericUpDownPhotomodeTranslationSpeed.TabIndex = 59; + this.numericUpDownPhotomodeTranslationSpeed.Value = new decimal(new int[] { + 25, + 0, + 0, + 65536}); + // + // trackBarPhotomodeTranslationSpeed + // + this.trackBarPhotomodeTranslationSpeed.BackColor = System.Drawing.Color.White; + this.trackBarPhotomodeTranslationSpeed.LargeChange = 50; + this.trackBarPhotomodeTranslationSpeed.Location = new System.Drawing.Point(131, 21); + this.trackBarPhotomodeTranslationSpeed.Maximum = 50; + this.trackBarPhotomodeTranslationSpeed.Minimum = 5; + this.trackBarPhotomodeTranslationSpeed.Name = "trackBarPhotomodeTranslationSpeed"; + this.trackBarPhotomodeTranslationSpeed.Size = new System.Drawing.Size(186, 45); + this.trackBarPhotomodeTranslationSpeed.SmallChange = 10; + this.trackBarPhotomodeTranslationSpeed.TabIndex = 58; + this.trackBarPhotomodeTranslationSpeed.TickStyle = System.Windows.Forms.TickStyle.None; + this.trackBarPhotomodeTranslationSpeed.Value = 25; // // groupBoxFieldOfView // @@ -2339,9 +2483,9 @@ private void InitializeComponent() this.groupBoxFieldOfView.Controls.Add(this.numFirstPersonFOV); this.groupBoxFieldOfView.Controls.Add(this.labelWorldFOV); this.groupBoxFieldOfView.Controls.Add(this.labelFirstPersonFOV); - this.groupBoxFieldOfView.Location = new System.Drawing.Point(413, 6); + this.groupBoxFieldOfView.Location = new System.Drawing.Point(6, 6); this.groupBoxFieldOfView.Name = "groupBoxFieldOfView"; - this.groupBoxFieldOfView.Size = new System.Drawing.Size(433, 154); + this.groupBoxFieldOfView.Size = new System.Drawing.Size(395, 154); this.groupBoxFieldOfView.TabIndex = 21; this.groupBoxFieldOfView.TabStop = false; this.groupBoxFieldOfView.Text = "Field of View"; @@ -2354,7 +2498,7 @@ private void InitializeComponent() 0, 0, 0}); - this.numfDefaultFOV.Location = new System.Drawing.Point(289, 120); + this.numfDefaultFOV.Location = new System.Drawing.Point(251, 120); this.numfDefaultFOV.Maximum = new decimal(new int[] { 180, 0, @@ -2382,95 +2526,243 @@ private void InitializeComponent() 0, 0, 0}); - this.numADSFOV.Location = new System.Drawing.Point(289, 82); + this.numADSFOV.Location = new System.Drawing.Point(251, 82); this.numADSFOV.Maximum = new decimal(new int[] { 180, 0, 0, 0}); - this.numADSFOV.Minimum = new decimal(new int[] { - 10, + this.numADSFOV.Minimum = new decimal(new int[] { + 10, + 0, + 0, + 0}); + this.numADSFOV.Name = "numADSFOV"; + this.numADSFOV.Size = new System.Drawing.Size(135, 20); + this.numADSFOV.TabIndex = 4; + this.numADSFOV.Value = new decimal(new int[] { + 50, + 0, + 0, + 0}); + // + // numWorldFOV + // + this.numWorldFOV.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.numWorldFOV.Increment = new decimal(new int[] { + 5, + 0, + 0, + 0}); + this.numWorldFOV.Location = new System.Drawing.Point(251, 45); + this.numWorldFOV.Maximum = new decimal(new int[] { + 180, + 0, + 0, + 0}); + this.numWorldFOV.Minimum = new decimal(new int[] { + 10, + 0, + 0, + 0}); + this.numWorldFOV.Name = "numWorldFOV"; + this.numWorldFOV.Size = new System.Drawing.Size(135, 20); + this.numWorldFOV.TabIndex = 3; + this.numWorldFOV.Value = new decimal(new int[] { + 80, + 0, + 0, + 0}); + // + // numFirstPersonFOV + // + this.numFirstPersonFOV.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.numFirstPersonFOV.Increment = new decimal(new int[] { + 5, + 0, + 0, + 0}); + this.numFirstPersonFOV.Location = new System.Drawing.Point(251, 19); + this.numFirstPersonFOV.Maximum = new decimal(new int[] { + 180, + 0, + 0, + 0}); + this.numFirstPersonFOV.Minimum = new decimal(new int[] { + 10, + 0, + 0, + 0}); + this.numFirstPersonFOV.Name = "numFirstPersonFOV"; + this.numFirstPersonFOV.Size = new System.Drawing.Size(135, 20); + this.numFirstPersonFOV.TabIndex = 2; + this.numFirstPersonFOV.Value = new decimal(new int[] { + 80, + 0, + 0, + 0}); + // + // groupBoxCameraOptions + // + this.groupBoxCameraOptions.Controls.Add(this.checkBoxForceVanityMode); + this.groupBoxCameraOptions.Controls.Add(this.numCameraSwitchDelay); + this.groupBoxCameraOptions.Controls.Add(this.checkBoxVanityMode); + this.groupBoxCameraOptions.Controls.Add(this.labelSwitchDelay); + this.groupBoxCameraOptions.Location = new System.Drawing.Point(6, 166); + this.groupBoxCameraOptions.Name = "groupBoxCameraOptions"; + this.groupBoxCameraOptions.Size = new System.Drawing.Size(395, 135); + this.groupBoxCameraOptions.TabIndex = 35; + this.groupBoxCameraOptions.TabStop = false; + this.groupBoxCameraOptions.Text = "Camera options"; + // + // numCameraSwitchDelay + // + this.numCameraSwitchDelay.DecimalPlaces = 4; + this.numCameraSwitchDelay.Location = new System.Drawing.Point(251, 16); + this.numCameraSwitchDelay.Maximum = new decimal(new int[] { + 5, + 0, + 0, + 0}); + this.numCameraSwitchDelay.Minimum = new decimal(new int[] { + 1, + 0, + 0, + 262144}); + this.numCameraSwitchDelay.Name = "numCameraSwitchDelay"; + this.numCameraSwitchDelay.Size = new System.Drawing.Size(135, 20); + this.numCameraSwitchDelay.TabIndex = 1; + this.numCameraSwitchDelay.Value = new decimal(new int[] { + 25, + 0, + 0, + 131072}); + // + // groupBoxCameraDistance + // + this.groupBoxCameraDistance.Controls.Add(this.numfPitchZoomOutMaxDist); + this.groupBoxCameraDistance.Controls.Add(this.sliderfPitchZoomOutMaxDist); + this.groupBoxCameraDistance.Controls.Add(this.labelPitchZoomOutMaxDist); + this.groupBoxCameraDistance.Controls.Add(this.numCameraDistanceMaximum); + this.groupBoxCameraDistance.Controls.Add(this.numCameraDistanceMinimum); + this.groupBoxCameraDistance.Controls.Add(this.sliderCameraDistanceMaximum); + this.groupBoxCameraDistance.Controls.Add(this.labelCameraDistanceMaximum); + this.groupBoxCameraDistance.Controls.Add(this.labelCameraDistanceMinimum); + this.groupBoxCameraDistance.Controls.Add(this.sliderCameraDistanceMinimum); + this.groupBoxCameraDistance.Location = new System.Drawing.Point(410, 6); + this.groupBoxCameraDistance.Name = "groupBoxCameraDistance"; + this.groupBoxCameraDistance.Size = new System.Drawing.Size(419, 154); + this.groupBoxCameraDistance.TabIndex = 34; + this.groupBoxCameraDistance.TabStop = false; + this.groupBoxCameraDistance.Text = "Camera distance"; + // + // numfPitchZoomOutMaxDist + // + this.numfPitchZoomOutMaxDist.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.numfPitchZoomOutMaxDist.Increment = new decimal(new int[] { + 10, + 0, + 0, + 0}); + this.numfPitchZoomOutMaxDist.Location = new System.Drawing.Point(336, 99); + this.numfPitchZoomOutMaxDist.Maximum = new decimal(new int[] { + 9999, 0, 0, 0}); - this.numADSFOV.Name = "numADSFOV"; - this.numADSFOV.Size = new System.Drawing.Size(135, 20); - this.numADSFOV.TabIndex = 4; - this.numADSFOV.Value = new decimal(new int[] { - 50, + this.numfPitchZoomOutMaxDist.Name = "numfPitchZoomOutMaxDist"; + this.numfPitchZoomOutMaxDist.Size = new System.Drawing.Size(74, 20); + this.numfPitchZoomOutMaxDist.TabIndex = 59; + this.numfPitchZoomOutMaxDist.Value = new decimal(new int[] { + 100, 0, 0, 0}); // - // numWorldFOV + // sliderfPitchZoomOutMaxDist // - this.numWorldFOV.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); - this.numWorldFOV.Increment = new decimal(new int[] { - 5, - 0, - 0, - 0}); - this.numWorldFOV.Location = new System.Drawing.Point(289, 45); - this.numWorldFOV.Maximum = new decimal(new int[] { - 180, + this.sliderfPitchZoomOutMaxDist.BackColor = System.Drawing.Color.White; + this.sliderfPitchZoomOutMaxDist.LargeChange = 50; + this.sliderfPitchZoomOutMaxDist.Location = new System.Drawing.Point(131, 101); + this.sliderfPitchZoomOutMaxDist.Maximum = 200; + this.sliderfPitchZoomOutMaxDist.Name = "sliderfPitchZoomOutMaxDist"; + this.sliderfPitchZoomOutMaxDist.Size = new System.Drawing.Size(186, 45); + this.sliderfPitchZoomOutMaxDist.SmallChange = 10; + this.sliderfPitchZoomOutMaxDist.TabIndex = 58; + this.sliderfPitchZoomOutMaxDist.TickStyle = System.Windows.Forms.TickStyle.None; + this.sliderfPitchZoomOutMaxDist.Value = 100; + // + // numCameraDistanceMaximum + // + this.numCameraDistanceMaximum.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.numCameraDistanceMaximum.Increment = new decimal(new int[] { + 10, 0, 0, 0}); - this.numWorldFOV.Minimum = new decimal(new int[] { - 10, + this.numCameraDistanceMaximum.Location = new System.Drawing.Point(336, 51); + this.numCameraDistanceMaximum.Maximum = new decimal(new int[] { + 9999, 0, 0, 0}); - this.numWorldFOV.Name = "numWorldFOV"; - this.numWorldFOV.Size = new System.Drawing.Size(135, 20); - this.numWorldFOV.TabIndex = 3; - this.numWorldFOV.Value = new decimal(new int[] { - 80, + this.numCameraDistanceMaximum.Name = "numCameraDistanceMaximum"; + this.numCameraDistanceMaximum.Size = new System.Drawing.Size(74, 20); + this.numCameraDistanceMaximum.TabIndex = 56; + this.numCameraDistanceMaximum.Value = new decimal(new int[] { + 150, 0, 0, 0}); // - // numFirstPersonFOV + // numCameraDistanceMinimum // - this.numFirstPersonFOV.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); - this.numFirstPersonFOV.Increment = new decimal(new int[] { - 5, - 0, - 0, - 0}); - this.numFirstPersonFOV.Location = new System.Drawing.Point(289, 19); - this.numFirstPersonFOV.Maximum = new decimal(new int[] { - 180, - 0, - 0, - 0}); - this.numFirstPersonFOV.Minimum = new decimal(new int[] { + this.numCameraDistanceMinimum.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.numCameraDistanceMinimum.Increment = new decimal(new int[] { 10, 0, 0, 0}); - this.numFirstPersonFOV.Name = "numFirstPersonFOV"; - this.numFirstPersonFOV.Size = new System.Drawing.Size(135, 20); - this.numFirstPersonFOV.TabIndex = 2; - this.numFirstPersonFOV.Value = new decimal(new int[] { - 80, + this.numCameraDistanceMinimum.Location = new System.Drawing.Point(336, 20); + this.numCameraDistanceMinimum.Maximum = new decimal(new int[] { + 9999, 0, 0, 0}); + this.numCameraDistanceMinimum.Name = "numCameraDistanceMinimum"; + this.numCameraDistanceMinimum.Size = new System.Drawing.Size(74, 20); + this.numCameraDistanceMinimum.TabIndex = 55; + // + // sliderCameraDistanceMaximum + // + this.sliderCameraDistanceMaximum.BackColor = System.Drawing.Color.White; + this.sliderCameraDistanceMaximum.LargeChange = 200; + this.sliderCameraDistanceMaximum.Location = new System.Drawing.Point(131, 51); + this.sliderCameraDistanceMaximum.Maximum = 1000; + this.sliderCameraDistanceMaximum.Minimum = 100; + this.sliderCameraDistanceMaximum.Name = "sliderCameraDistanceMaximum"; + this.sliderCameraDistanceMaximum.Size = new System.Drawing.Size(186, 45); + this.sliderCameraDistanceMaximum.SmallChange = 50; + this.sliderCameraDistanceMaximum.TabIndex = 54; + this.sliderCameraDistanceMaximum.TickStyle = System.Windows.Forms.TickStyle.None; + this.sliderCameraDistanceMaximum.Value = 150; // - // groupBoxCameraVanity + // sliderCameraDistanceMinimum // - this.groupBoxCameraVanity.Controls.Add(this.checkBoxForceVanityMode); - this.groupBoxCameraVanity.Controls.Add(this.checkBoxVanityMode); - this.groupBoxCameraVanity.Location = new System.Drawing.Point(413, 384); - this.groupBoxCameraVanity.Name = "groupBoxCameraVanity"; - this.groupBoxCameraVanity.Size = new System.Drawing.Size(433, 74); - this.groupBoxCameraVanity.TabIndex = 16; - this.groupBoxCameraVanity.TabStop = false; - this.groupBoxCameraVanity.Text = "Vanity (Spinning camera)"; + this.sliderCameraDistanceMinimum.BackColor = System.Drawing.Color.White; + this.sliderCameraDistanceMinimum.LargeChange = 20; + this.sliderCameraDistanceMinimum.Location = new System.Drawing.Point(131, 19); + this.sliderCameraDistanceMinimum.Maximum = 100; + this.sliderCameraDistanceMinimum.Name = "sliderCameraDistanceMinimum"; + this.sliderCameraDistanceMinimum.Size = new System.Drawing.Size(186, 45); + this.sliderCameraDistanceMinimum.SmallChange = 10; + this.sliderCameraDistanceMinimum.TabIndex = 51; + this.sliderCameraDistanceMinimum.TickStyle = System.Windows.Forms.TickStyle.None; // // tabPagePipBoy // + this.tabPagePipBoy.Controls.Add(this.groupBoxPipboyColorPresets); + this.tabPagePipBoy.Controls.Add(this.groupBoxPipboyColorPreview); this.tabPagePipBoy.Controls.Add(this.groupBoxPipboyResolution); this.tabPagePipBoy.Controls.Add(this.groupBoxPipboyMode); this.tabPagePipBoy.Controls.Add(this.groupBoxPipboyColors); @@ -2482,6 +2774,209 @@ private void InitializeComponent() this.tabPagePipBoy.Text = "Pipboy"; this.tabPagePipBoy.UseVisualStyleBackColor = true; // + // groupBoxPipboyColorPresets + // + this.groupBoxPipboyColorPresets.Controls.Add(this.colorPreviewPresetFo76Green); + this.groupBoxPipboyColorPresets.Controls.Add(this.colorPreviewPresetFo3Green); + this.groupBoxPipboyColorPresets.Controls.Add(this.colorPreviewPresetFo3White); + this.groupBoxPipboyColorPresets.Controls.Add(this.buttonPresetFo3Green); + this.groupBoxPipboyColorPresets.Controls.Add(this.buttonPresetFo3White); + this.groupBoxPipboyColorPresets.Controls.Add(this.buttonPresetFoNVAmber); + this.groupBoxPipboyColorPresets.Controls.Add(this.buttonPresetFo76Green); + this.groupBoxPipboyColorPresets.Controls.Add(this.colorPreviewPresetFoNVAmber); + this.groupBoxPipboyColorPresets.Controls.Add(this.colorPreviewPresetFo3Blue); + this.groupBoxPipboyColorPresets.Controls.Add(this.buttonPresetFo4Green); + this.groupBoxPipboyColorPresets.Controls.Add(this.colorPreviewPresetFo4Green); + this.groupBoxPipboyColorPresets.Controls.Add(this.buttonPresetFo3Blue); + this.groupBoxPipboyColorPresets.Location = new System.Drawing.Point(6, 135); + this.groupBoxPipboyColorPresets.Name = "groupBoxPipboyColorPresets"; + this.groupBoxPipboyColorPresets.Size = new System.Drawing.Size(451, 145); + this.groupBoxPipboyColorPresets.TabIndex = 2; + this.groupBoxPipboyColorPresets.TabStop = false; + this.groupBoxPipboyColorPresets.Text = "Presets"; + // + // colorPreviewPresetFo76Green + // + this.colorPreviewPresetFo76Green.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(26)))), ((int)(((byte)(255)))), ((int)(((byte)(128))))); + this.colorPreviewPresetFo76Green.Location = new System.Drawing.Point(246, 49); + this.colorPreviewPresetFo76Green.Name = "colorPreviewPresetFo76Green"; + this.colorPreviewPresetFo76Green.Size = new System.Drawing.Size(24, 24); + this.colorPreviewPresetFo76Green.TabIndex = 62; + this.colorPreviewPresetFo76Green.TabStop = false; + // + // colorPreviewPresetFo3Green + // + this.colorPreviewPresetFo3Green.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(26)))), ((int)(((byte)(255)))), ((int)(((byte)(128))))); + this.colorPreviewPresetFo3Green.Location = new System.Drawing.Point(11, 19); + this.colorPreviewPresetFo3Green.Name = "colorPreviewPresetFo3Green"; + this.colorPreviewPresetFo3Green.Size = new System.Drawing.Size(24, 24); + this.colorPreviewPresetFo3Green.TabIndex = 52; + this.colorPreviewPresetFo3Green.TabStop = false; + // + // colorPreviewPresetFo3White + // + this.colorPreviewPresetFo3White.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(192)))), ((int)(((byte)(255)))), ((int)(((byte)(255))))); + this.colorPreviewPresetFo3White.Location = new System.Drawing.Point(11, 109); + this.colorPreviewPresetFo3White.Name = "colorPreviewPresetFo3White"; + this.colorPreviewPresetFo3White.Size = new System.Drawing.Size(24, 24); + this.colorPreviewPresetFo3White.TabIndex = 58; + this.colorPreviewPresetFo3White.TabStop = false; + // + // buttonPresetFo3Green + // + this.buttonPresetFo3Green.BackColor = System.Drawing.Color.White; + this.buttonPresetFo3Green.FlatAppearance.BorderColor = System.Drawing.Color.LightGray; + this.buttonPresetFo3Green.FlatAppearance.MouseDownBackColor = System.Drawing.Color.Gainsboro; + this.buttonPresetFo3Green.FlatAppearance.MouseOverBackColor = System.Drawing.Color.FromArgb(((int)(((byte)(240)))), ((int)(((byte)(240)))), ((int)(((byte)(240))))); + this.buttonPresetFo3Green.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.buttonPresetFo3Green.Location = new System.Drawing.Point(41, 19); + this.buttonPresetFo3Green.Name = "buttonPresetFo3Green"; + this.buttonPresetFo3Green.Size = new System.Drawing.Size(166, 24); + this.buttonPresetFo3Green.TabIndex = 51; + this.buttonPresetFo3Green.Text = "Capital Wasteland Green"; + this.buttonPresetFo3Green.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; + this.buttonPresetFo3Green.UseVisualStyleBackColor = false; + this.buttonPresetFo3Green.Click += new System.EventHandler(this.buttonPresetFo3Green_Click); + // + // buttonPresetFo3White + // + this.buttonPresetFo3White.BackColor = System.Drawing.Color.White; + this.buttonPresetFo3White.FlatAppearance.BorderColor = System.Drawing.Color.LightGray; + this.buttonPresetFo3White.FlatAppearance.MouseDownBackColor = System.Drawing.Color.Gainsboro; + this.buttonPresetFo3White.FlatAppearance.MouseOverBackColor = System.Drawing.Color.FromArgb(((int)(((byte)(240)))), ((int)(((byte)(240)))), ((int)(((byte)(240))))); + this.buttonPresetFo3White.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.buttonPresetFo3White.Location = new System.Drawing.Point(41, 109); + this.buttonPresetFo3White.Name = "buttonPresetFo3White"; + this.buttonPresetFo3White.Size = new System.Drawing.Size(166, 24); + this.buttonPresetFo3White.TabIndex = 57; + this.buttonPresetFo3White.Text = "Classic White"; + this.buttonPresetFo3White.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; + this.buttonPresetFo3White.UseVisualStyleBackColor = false; + this.buttonPresetFo3White.Click += new System.EventHandler(this.buttonPresetFo3White_Click); + // + // buttonPresetFoNVAmber + // + this.buttonPresetFoNVAmber.BackColor = System.Drawing.Color.White; + this.buttonPresetFoNVAmber.FlatAppearance.BorderColor = System.Drawing.Color.LightGray; + this.buttonPresetFoNVAmber.FlatAppearance.MouseDownBackColor = System.Drawing.Color.Gainsboro; + this.buttonPresetFoNVAmber.FlatAppearance.MouseOverBackColor = System.Drawing.Color.FromArgb(((int)(((byte)(240)))), ((int)(((byte)(240)))), ((int)(((byte)(240))))); + this.buttonPresetFoNVAmber.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.buttonPresetFoNVAmber.Location = new System.Drawing.Point(41, 49); + this.buttonPresetFoNVAmber.Name = "buttonPresetFoNVAmber"; + this.buttonPresetFoNVAmber.Size = new System.Drawing.Size(166, 24); + this.buttonPresetFoNVAmber.TabIndex = 53; + this.buttonPresetFoNVAmber.Text = "Mojave Wasteland Amber"; + this.buttonPresetFoNVAmber.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; + this.buttonPresetFoNVAmber.UseVisualStyleBackColor = false; + this.buttonPresetFoNVAmber.Click += new System.EventHandler(this.buttonPresetFoNVAmber_Click); + // + // buttonPresetFo76Green + // + this.buttonPresetFo76Green.BackColor = System.Drawing.Color.White; + this.buttonPresetFo76Green.FlatAppearance.BorderColor = System.Drawing.Color.LightGray; + this.buttonPresetFo76Green.FlatAppearance.MouseDownBackColor = System.Drawing.Color.Gainsboro; + this.buttonPresetFo76Green.FlatAppearance.MouseOverBackColor = System.Drawing.Color.FromArgb(((int)(((byte)(240)))), ((int)(((byte)(240)))), ((int)(((byte)(240))))); + this.buttonPresetFo76Green.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.buttonPresetFo76Green.Location = new System.Drawing.Point(276, 49); + this.buttonPresetFo76Green.Name = "buttonPresetFo76Green"; + this.buttonPresetFo76Green.Size = new System.Drawing.Size(166, 24); + this.buttonPresetFo76Green.TabIndex = 61; + this.buttonPresetFo76Green.Text = "Appalachia Green"; + this.buttonPresetFo76Green.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; + this.buttonPresetFo76Green.UseVisualStyleBackColor = false; + this.buttonPresetFo76Green.Click += new System.EventHandler(this.buttonPresetFo76Green_Click); + // + // colorPreviewPresetFoNVAmber + // + this.colorPreviewPresetFoNVAmber.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(255)))), ((int)(((byte)(182)))), ((int)(((byte)(66))))); + this.colorPreviewPresetFoNVAmber.Location = new System.Drawing.Point(11, 49); + this.colorPreviewPresetFoNVAmber.Name = "colorPreviewPresetFoNVAmber"; + this.colorPreviewPresetFoNVAmber.Size = new System.Drawing.Size(24, 24); + this.colorPreviewPresetFoNVAmber.TabIndex = 54; + this.colorPreviewPresetFoNVAmber.TabStop = false; + // + // colorPreviewPresetFo3Blue + // + this.colorPreviewPresetFo3Blue.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(46)))), ((int)(((byte)(207)))), ((int)(((byte)(255))))); + this.colorPreviewPresetFo3Blue.Location = new System.Drawing.Point(11, 79); + this.colorPreviewPresetFo3Blue.Name = "colorPreviewPresetFo3Blue"; + this.colorPreviewPresetFo3Blue.Size = new System.Drawing.Size(24, 24); + this.colorPreviewPresetFo3Blue.TabIndex = 56; + this.colorPreviewPresetFo3Blue.TabStop = false; + // + // buttonPresetFo4Green + // + this.buttonPresetFo4Green.BackColor = System.Drawing.Color.White; + this.buttonPresetFo4Green.FlatAppearance.BorderColor = System.Drawing.Color.LightGray; + this.buttonPresetFo4Green.FlatAppearance.MouseDownBackColor = System.Drawing.Color.Gainsboro; + this.buttonPresetFo4Green.FlatAppearance.MouseOverBackColor = System.Drawing.Color.FromArgb(((int)(((byte)(240)))), ((int)(((byte)(240)))), ((int)(((byte)(240))))); + this.buttonPresetFo4Green.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.buttonPresetFo4Green.Location = new System.Drawing.Point(276, 19); + this.buttonPresetFo4Green.Name = "buttonPresetFo4Green"; + this.buttonPresetFo4Green.Size = new System.Drawing.Size(166, 24); + this.buttonPresetFo4Green.TabIndex = 59; + this.buttonPresetFo4Green.Text = "Commonwealth Green"; + this.buttonPresetFo4Green.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; + this.buttonPresetFo4Green.UseVisualStyleBackColor = false; + this.buttonPresetFo4Green.Click += new System.EventHandler(this.buttonPresetFo4Green_Click); + // + // colorPreviewPresetFo4Green + // + this.colorPreviewPresetFo4Green.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(18)))), ((int)(((byte)(255)))), ((int)(((byte)(21))))); + this.colorPreviewPresetFo4Green.Location = new System.Drawing.Point(246, 19); + this.colorPreviewPresetFo4Green.Name = "colorPreviewPresetFo4Green"; + this.colorPreviewPresetFo4Green.Size = new System.Drawing.Size(24, 24); + this.colorPreviewPresetFo4Green.TabIndex = 60; + this.colorPreviewPresetFo4Green.TabStop = false; + // + // buttonPresetFo3Blue + // + this.buttonPresetFo3Blue.BackColor = System.Drawing.Color.White; + this.buttonPresetFo3Blue.FlatAppearance.BorderColor = System.Drawing.Color.LightGray; + this.buttonPresetFo3Blue.FlatAppearance.MouseDownBackColor = System.Drawing.Color.Gainsboro; + this.buttonPresetFo3Blue.FlatAppearance.MouseOverBackColor = System.Drawing.Color.FromArgb(((int)(((byte)(240)))), ((int)(((byte)(240)))), ((int)(((byte)(240))))); + this.buttonPresetFo3Blue.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.buttonPresetFo3Blue.Location = new System.Drawing.Point(41, 79); + this.buttonPresetFo3Blue.Name = "buttonPresetFo3Blue"; + this.buttonPresetFo3Blue.Size = new System.Drawing.Size(166, 24); + this.buttonPresetFo3Blue.TabIndex = 55; + this.buttonPresetFo3Blue.Text = "Classic Blue"; + this.buttonPresetFo3Blue.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; + this.buttonPresetFo3Blue.UseVisualStyleBackColor = false; + this.buttonPresetFo3Blue.Click += new System.EventHandler(this.buttonPresetFo3Blue_Click); + // + // groupBoxPipboyColorPreview + // + this.groupBoxPipboyColorPreview.Controls.Add(this.labelPipboyColorPreviewNotice); + this.groupBoxPipboyColorPreview.Controls.Add(this.pictureBoxPipboyPreview); + this.groupBoxPipboyColorPreview.Location = new System.Drawing.Point(464, 6); + this.groupBoxPipboyColorPreview.Name = "groupBoxPipboyColorPreview"; + this.groupBoxPipboyColorPreview.Size = new System.Drawing.Size(382, 452); + this.groupBoxPipboyColorPreview.TabIndex = 40; + this.groupBoxPipboyColorPreview.TabStop = false; + this.groupBoxPipboyColorPreview.Text = "Preview"; + // + // labelPipboyColorPreviewNotice + // + this.labelPipboyColorPreviewNotice.ForeColor = System.Drawing.SystemColors.ControlDarkDark; + this.labelPipboyColorPreviewNotice.Location = new System.Drawing.Point(6, 246); + this.labelPipboyColorPreviewNotice.Name = "labelPipboyColorPreviewNotice"; + this.labelPipboyColorPreviewNotice.Size = new System.Drawing.Size(370, 46); + this.labelPipboyColorPreviewNotice.TabIndex = 1; + this.labelPipboyColorPreviewNotice.Text = "The preview is only an approximation,\r\nso it might not look exactly like this in " + + "game."; + this.labelPipboyColorPreviewNotice.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + // + // pictureBoxPipboyPreview + // + this.pictureBoxPipboyPreview.Image = global::Fo76ini.Properties.Resources.pipboy_preview_bg; + this.pictureBoxPipboyPreview.Location = new System.Drawing.Point(6, 18); + this.pictureBoxPipboyPreview.Name = "pictureBoxPipboyPreview"; + this.pictureBoxPipboyPreview.Size = new System.Drawing.Size(370, 225); + this.pictureBoxPipboyPreview.SizeMode = System.Windows.Forms.PictureBoxSizeMode.CenterImage; + this.pictureBoxPipboyPreview.TabIndex = 0; + this.pictureBoxPipboyPreview.TabStop = false; + // // groupBoxPipboyResolution // this.groupBoxPipboyResolution.Controls.Add(this.labelPipboyResolutionSideNote); @@ -2490,9 +2985,9 @@ private void InitializeComponent() this.groupBoxPipboyResolution.Controls.Add(this.numPipboyTargetHeight); this.groupBoxPipboyResolution.Controls.Add(this.numPipboyTargetWidth); this.groupBoxPipboyResolution.Controls.Add(this.labelPipboyResolutionSpacer); - this.groupBoxPipboyResolution.Location = new System.Drawing.Point(6, 215); + this.groupBoxPipboyResolution.Location = new System.Drawing.Point(175, 286); this.groupBoxPipboyResolution.Name = "groupBoxPipboyResolution"; - this.groupBoxPipboyResolution.Size = new System.Drawing.Size(451, 122); + this.groupBoxPipboyResolution.Size = new System.Drawing.Size(282, 172); this.groupBoxPipboyResolution.TabIndex = 39; this.groupBoxPipboyResolution.TabStop = false; this.groupBoxPipboyResolution.Text = "Resolution"; @@ -2500,17 +2995,17 @@ private void InitializeComponent() // labelPipboyResolutionSideNote // this.labelPipboyResolutionSideNote.ForeColor = System.Drawing.SystemColors.ControlDarkDark; - this.labelPipboyResolutionSideNote.Location = new System.Drawing.Point(3, 83); + this.labelPipboyResolutionSideNote.Location = new System.Drawing.Point(6, 111); this.labelPipboyResolutionSideNote.Name = "labelPipboyResolutionSideNote"; - this.labelPipboyResolutionSideNote.Size = new System.Drawing.Size(448, 28); + this.labelPipboyResolutionSideNote.Size = new System.Drawing.Size(270, 50); this.labelPipboyResolutionSideNote.TabIndex = 5; this.labelPipboyResolutionSideNote.Text = "These settings affect both the Pipboy and the Quickboy."; - this.labelPipboyResolutionSideNote.TextAlign = System.Drawing.ContentAlignment.TopCenter; + this.labelPipboyResolutionSideNote.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; // // labelPipboyResolutionSpacer // this.labelPipboyResolutionSpacer.AutoSize = true; - this.labelPipboyResolutionSpacer.Location = new System.Drawing.Point(218, 22); + this.labelPipboyResolutionSpacer.Location = new System.Drawing.Point(134, 26); this.labelPipboyResolutionSpacer.Name = "labelPipboyResolutionSpacer"; this.labelPipboyResolutionSpacer.Size = new System.Drawing.Size(14, 13); this.labelPipboyResolutionSpacer.TabIndex = 0; @@ -2520,22 +3015,22 @@ private void InitializeComponent() // this.groupBoxPipboyMode.Controls.Add(this.radioButtonQuickboy); this.groupBoxPipboyMode.Controls.Add(this.radioButtonPipboy); - this.groupBoxPipboyMode.Location = new System.Drawing.Point(6, 129); + this.groupBoxPipboyMode.Location = new System.Drawing.Point(6, 286); this.groupBoxPipboyMode.Name = "groupBoxPipboyMode"; - this.groupBoxPipboyMode.Size = new System.Drawing.Size(451, 80); + this.groupBoxPipboyMode.Size = new System.Drawing.Size(163, 172); this.groupBoxPipboyMode.TabIndex = 38; this.groupBoxPipboyMode.TabStop = false; this.groupBoxPipboyMode.Text = "Mode"; // // groupBoxPipboyColors // + this.groupBoxPipboyColors.Controls.Add(this.colorPreviewQuickboy); this.groupBoxPipboyColors.Controls.Add(this.colorPreviewPAPipboy); - this.groupBoxPipboyColors.Controls.Add(this.label1); + this.groupBoxPipboyColors.Controls.Add(this.labelPowerArmorColor); + this.groupBoxPipboyColors.Controls.Add(this.colorPreviewPipboy); this.groupBoxPipboyColors.Controls.Add(this.buttonColorPickPAPipboy); this.groupBoxPipboyColors.Controls.Add(this.buttonColorResetPipboy); this.groupBoxPipboyColors.Controls.Add(this.buttonColorResetPAPipboy); - this.groupBoxPipboyColors.Controls.Add(this.colorPreviewPipboy); - this.groupBoxPipboyColors.Controls.Add(this.colorPreviewQuickboy); this.groupBoxPipboyColors.Controls.Add(this.labelQuickboyColor); this.groupBoxPipboyColors.Controls.Add(this.buttonColorPickQuickboy); this.groupBoxPipboyColors.Controls.Add(this.buttonColorResetQuickboy); @@ -2543,20 +3038,38 @@ private void InitializeComponent() this.groupBoxPipboyColors.Controls.Add(this.buttonColorPickPipboy); this.groupBoxPipboyColors.Location = new System.Drawing.Point(6, 6); this.groupBoxPipboyColors.Name = "groupBoxPipboyColors"; - this.groupBoxPipboyColors.Size = new System.Drawing.Size(451, 117); + this.groupBoxPipboyColors.Size = new System.Drawing.Size(451, 123); this.groupBoxPipboyColors.TabIndex = 35; this.groupBoxPipboyColors.TabStop = false; this.groupBoxPipboyColors.Text = "Colors"; // + // colorPreviewQuickboy + // + this.colorPreviewQuickboy.BackColor = System.Drawing.Color.Fuchsia; + this.colorPreviewQuickboy.Location = new System.Drawing.Point(11, 50); + this.colorPreviewQuickboy.Name = "colorPreviewQuickboy"; + this.colorPreviewQuickboy.Size = new System.Drawing.Size(20, 20); + this.colorPreviewQuickboy.TabIndex = 42; + this.colorPreviewQuickboy.TabStop = false; + // // colorPreviewPAPipboy // - this.colorPreviewPAPipboy.BackColor = System.Drawing.Color.Red; - this.colorPreviewPAPipboy.Location = new System.Drawing.Point(12, 78); + this.colorPreviewPAPipboy.BackColor = System.Drawing.Color.Fuchsia; + this.colorPreviewPAPipboy.Location = new System.Drawing.Point(11, 79); this.colorPreviewPAPipboy.Name = "colorPreviewPAPipboy"; this.colorPreviewPAPipboy.Size = new System.Drawing.Size(20, 20); - this.colorPreviewPAPipboy.TabIndex = 35; + this.colorPreviewPAPipboy.TabIndex = 41; this.colorPreviewPAPipboy.TabStop = false; // + // colorPreviewPipboy + // + this.colorPreviewPipboy.BackColor = System.Drawing.Color.Fuchsia; + this.colorPreviewPipboy.Location = new System.Drawing.Point(11, 21); + this.colorPreviewPipboy.Name = "colorPreviewPipboy"; + this.colorPreviewPipboy.Size = new System.Drawing.Size(20, 20); + this.colorPreviewPipboy.TabIndex = 40; + this.colorPreviewPipboy.TabStop = false; + // // buttonColorPickPAPipboy // this.buttonColorPickPAPipboy.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); @@ -2566,7 +3079,6 @@ private void InitializeComponent() this.buttonColorPickPAPipboy.TabIndex = 36; this.buttonColorPickPAPipboy.Text = "Pick color"; this.buttonColorPickPAPipboy.UseVisualStyleBackColor = true; - this.buttonColorPickPAPipboy.Click += new System.EventHandler(this.buttonColorPickPAPipboy_Click); // // buttonColorResetPipboy // @@ -2577,7 +3089,6 @@ private void InitializeComponent() this.buttonColorResetPipboy.TabIndex = 3; this.buttonColorResetPipboy.Text = "Reset"; this.buttonColorResetPipboy.UseVisualStyleBackColor = true; - this.buttonColorResetPipboy.Click += new System.EventHandler(this.buttonColorResetPipboy_Click); // // buttonColorResetPAPipboy // @@ -2588,25 +3099,6 @@ private void InitializeComponent() this.buttonColorResetPAPipboy.TabIndex = 35; this.buttonColorResetPAPipboy.Text = "Reset"; this.buttonColorResetPAPipboy.UseVisualStyleBackColor = true; - this.buttonColorResetPAPipboy.Click += new System.EventHandler(this.buttonColorResetPAPipboy_Click); - // - // colorPreviewPipboy - // - this.colorPreviewPipboy.BackColor = System.Drawing.Color.Red; - this.colorPreviewPipboy.Location = new System.Drawing.Point(12, 20); - this.colorPreviewPipboy.Name = "colorPreviewPipboy"; - this.colorPreviewPipboy.Size = new System.Drawing.Size(20, 20); - this.colorPreviewPipboy.TabIndex = 0; - this.colorPreviewPipboy.TabStop = false; - // - // colorPreviewQuickboy - // - this.colorPreviewQuickboy.BackColor = System.Drawing.Color.Red; - this.colorPreviewQuickboy.Location = new System.Drawing.Point(12, 49); - this.colorPreviewQuickboy.Name = "colorPreviewQuickboy"; - this.colorPreviewQuickboy.Size = new System.Drawing.Size(20, 20); - this.colorPreviewQuickboy.TabIndex = 5; - this.colorPreviewQuickboy.TabStop = false; // // buttonColorPickQuickboy // @@ -2617,7 +3109,6 @@ private void InitializeComponent() this.buttonColorPickQuickboy.TabIndex = 7; this.buttonColorPickQuickboy.Text = "Pick color"; this.buttonColorPickQuickboy.UseVisualStyleBackColor = true; - this.buttonColorPickQuickboy.Click += new System.EventHandler(this.buttonColorPickQuickboy_Click); // // buttonColorResetQuickboy // @@ -2628,7 +3119,6 @@ private void InitializeComponent() this.buttonColorResetQuickboy.TabIndex = 8; this.buttonColorResetQuickboy.Text = "Reset"; this.buttonColorResetQuickboy.UseVisualStyleBackColor = true; - this.buttonColorResetQuickboy.Click += new System.EventHandler(this.buttonColorResetQuickboy_Click); // // buttonColorPickPipboy // @@ -2639,7 +3129,6 @@ private void InitializeComponent() this.buttonColorPickPipboy.TabIndex = 2; this.buttonColorPickPipboy.Text = "Pick color"; this.buttonColorPickPipboy.UseVisualStyleBackColor = true; - this.buttonColorPickPipboy.Click += new System.EventHandler(this.buttonColorPickPipboy_Click); // // tabPageControls // @@ -2655,13 +3144,11 @@ private void InitializeComponent() // // groupBoxGamepad // - this.groupBoxGamepad.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); this.groupBoxGamepad.Controls.Add(this.checkBoxGamepadEnabled); this.groupBoxGamepad.Controls.Add(this.checkBoxGamepadRumble); this.groupBoxGamepad.Location = new System.Drawing.Point(451, 6); this.groupBoxGamepad.Name = "groupBoxGamepad"; - this.groupBoxGamepad.Size = new System.Drawing.Size(395, 92); + this.groupBoxGamepad.Size = new System.Drawing.Size(395, 452); this.groupBoxGamepad.TabIndex = 5; this.groupBoxGamepad.TabStop = false; this.groupBoxGamepad.Text = "Gamepad"; @@ -2678,7 +3165,7 @@ private void InitializeComponent() this.groupBoxMouse.Controls.Add(this.checkBoxFixMouseSensitivity); this.groupBoxMouse.Location = new System.Drawing.Point(6, 6); this.groupBoxMouse.Name = "groupBoxMouse"; - this.groupBoxMouse.Size = new System.Drawing.Size(438, 226); + this.groupBoxMouse.Size = new System.Drawing.Size(438, 452); this.groupBoxMouse.TabIndex = 4; this.groupBoxMouse.TabStop = false; this.groupBoxMouse.Text = "Mouse"; @@ -2748,6 +3235,7 @@ private void InitializeComponent() // // groupBoxGraphics // + this.groupBoxGraphics.Controls.Add(this.groupBoxGraphicEffects); this.groupBoxGraphics.Controls.Add(this.groupBoxTAASharpening); this.groupBoxGraphics.Controls.Add(this.labelAntiAliasing); this.groupBoxGraphics.Controls.Add(this.groupBoxGrass); @@ -2763,11 +3251,21 @@ private void InitializeComponent() this.groupBoxGraphics.Controls.Add(this.groupBoxPostProcessing); this.groupBoxGraphics.Location = new System.Drawing.Point(3, 6); this.groupBoxGraphics.Name = "groupBoxGraphics"; - this.groupBoxGraphics.Size = new System.Drawing.Size(402, 1004); + this.groupBoxGraphics.Size = new System.Drawing.Size(402, 915); this.groupBoxGraphics.TabIndex = 26; this.groupBoxGraphics.TabStop = false; this.groupBoxGraphics.Text = "Graphics"; // + // groupBoxGraphicEffects + // + this.groupBoxGraphicEffects.Controls.Add(this.checkBoxDisableGore); + this.groupBoxGraphicEffects.Location = new System.Drawing.Point(9, 261); + this.groupBoxGraphicEffects.Name = "groupBoxGraphicEffects"; + this.groupBoxGraphicEffects.Size = new System.Drawing.Size(187, 46); + this.groupBoxGraphicEffects.TabIndex = 39; + this.groupBoxGraphicEffects.TabStop = false; + this.groupBoxGraphicEffects.Text = "Effects"; + // // groupBoxTAASharpening // this.groupBoxTAASharpening.Controls.Add(this.sliderTAAPostSharpen); @@ -2776,7 +3274,7 @@ private void InitializeComponent() this.groupBoxTAASharpening.Controls.Add(this.sliderTAAPostOverlay); this.groupBoxTAASharpening.Controls.Add(this.numTAAPostOverlay); this.groupBoxTAASharpening.Controls.Add(this.labelTAAPostOverlay); - this.groupBoxTAASharpening.Location = new System.Drawing.Point(9, 845); + this.groupBoxTAASharpening.Location = new System.Drawing.Point(9, 758); this.groupBoxTAASharpening.Name = "groupBoxTAASharpening"; this.groupBoxTAASharpening.Size = new System.Drawing.Size(381, 145); this.groupBoxTAASharpening.TabIndex = 38; @@ -2855,7 +3353,7 @@ private void InitializeComponent() this.groupBoxGrass.Controls.Add(this.numGrassFadeDistance); this.groupBoxGrass.Controls.Add(this.labelGrassFadeDistance); this.groupBoxGrass.Controls.Add(this.checkBoxGrass); - this.groupBoxGrass.Location = new System.Drawing.Point(9, 720); + this.groupBoxGrass.Location = new System.Drawing.Point(9, 629); this.groupBoxGrass.Name = "groupBoxGrass"; this.groupBoxGrass.Size = new System.Drawing.Size(381, 119); this.groupBoxGrass.TabIndex = 35; @@ -2915,7 +3413,7 @@ private void InitializeComponent() this.groupBoxLOD.Controls.Add(this.labelLODActors); this.groupBoxLOD.Controls.Add(this.labelLODItems); this.groupBoxLOD.Controls.Add(this.labelLODObjects); - this.groupBoxLOD.Location = new System.Drawing.Point(9, 558); + this.groupBoxLOD.Location = new System.Drawing.Point(9, 467); this.groupBoxLOD.Name = "groupBoxLOD"; this.groupBoxLOD.Size = new System.Drawing.Size(381, 156); this.groupBoxLOD.TabIndex = 37; @@ -3018,20 +3516,15 @@ private void InitializeComponent() // groupBoxLighting // this.groupBoxLighting.Controls.Add(this.checkBoxGodrays); - this.groupBoxLighting.Location = new System.Drawing.Point(9, 261); + this.groupBoxLighting.Location = new System.Drawing.Point(202, 261); this.groupBoxLighting.Name = "groupBoxLighting"; - this.groupBoxLighting.Size = new System.Drawing.Size(381, 46); + this.groupBoxLighting.Size = new System.Drawing.Size(188, 46); this.groupBoxLighting.TabIndex = 28; this.groupBoxLighting.TabStop = false; this.groupBoxLighting.Text = "Lighting"; // // groupBoxShadows // - this.groupBoxShadows.Controls.Add(this.sliderfBlendSplitDirShadow); - this.groupBoxShadows.Controls.Add(this.numfBlendSplitDirShadow); - this.groupBoxShadows.Controls.Add(this.labelfBlendSplitDirShadow); - this.groupBoxShadows.Controls.Add(this.comboBoxiDirShadowSplits); - this.groupBoxShadows.Controls.Add(this.label2); this.groupBoxShadows.Controls.Add(this.sliderShadowDistance); this.groupBoxShadows.Controls.Add(this.comboBoxShadowBlurriness); this.groupBoxShadows.Controls.Add(this.labelShadowBlurriness); @@ -3041,54 +3534,11 @@ private void InitializeComponent() this.groupBoxShadows.Controls.Add(this.labelShadowTextureResolution); this.groupBoxShadows.Location = new System.Drawing.Point(9, 313); this.groupBoxShadows.Name = "groupBoxShadows"; - this.groupBoxShadows.Size = new System.Drawing.Size(381, 239); + this.groupBoxShadows.Size = new System.Drawing.Size(381, 147); this.groupBoxShadows.TabIndex = 30; this.groupBoxShadows.TabStop = false; this.groupBoxShadows.Text = "Shadows"; // - // numfBlendSplitDirShadow - // - this.numfBlendSplitDirShadow.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); - this.numfBlendSplitDirShadow.Increment = new decimal(new int[] { - 1000, - 0, - 0, - 0}); - this.numfBlendSplitDirShadow.Location = new System.Drawing.Point(301, 175); - this.numfBlendSplitDirShadow.Maximum = new decimal(new int[] { - 9999999, - 0, - 0, - 0}); - this.numfBlendSplitDirShadow.Name = "numfBlendSplitDirShadow"; - this.numfBlendSplitDirShadow.Size = new System.Drawing.Size(74, 20); - this.numfBlendSplitDirShadow.TabIndex = 35; - this.numfBlendSplitDirShadow.Value = new decimal(new int[] { - 48, - 0, - 0, - 0}); - // - // labelfBlendSplitDirShadow - // - this.labelfBlendSplitDirShadow.AutoSize = true; - this.labelfBlendSplitDirShadow.Location = new System.Drawing.Point(7, 155); - this.labelfBlendSplitDirShadow.Name = "labelfBlendSplitDirShadow"; - this.labelfBlendSplitDirShadow.Size = new System.Drawing.Size(147, 13); - this.labelfBlendSplitDirShadow.TabIndex = 34; - this.labelfBlendSplitDirShadow.Text = "\"Segment\" transition distance"; - // - // comboBoxiDirShadowSplits - // - this.comboBoxiDirShadowSplits.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.comboBoxiDirShadowSplits.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; - this.comboBoxiDirShadowSplits.FormattingEnabled = true; - this.comboBoxiDirShadowSplits.Location = new System.Drawing.Point(156, 74); - this.comboBoxiDirShadowSplits.Name = "comboBoxiDirShadowSplits"; - this.comboBoxiDirShadowSplits.Size = new System.Drawing.Size(219, 21); - this.comboBoxiDirShadowSplits.TabIndex = 32; - // // comboBoxShadowBlurriness // this.comboBoxShadowBlurriness.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) @@ -3108,7 +3558,7 @@ private void InitializeComponent() 0, 0, 0}); - this.numShadowDistance.Location = new System.Drawing.Point(301, 124); + this.numShadowDistance.Location = new System.Drawing.Point(301, 99); this.numShadowDistance.Maximum = new decimal(new int[] { 9999999, 0, @@ -3126,7 +3576,7 @@ private void InitializeComponent() // labelShadowDistance // this.labelShadowDistance.AutoSize = true; - this.labelShadowDistance.Location = new System.Drawing.Point(7, 104); + this.labelShadowDistance.Location = new System.Drawing.Point(7, 79); this.labelShadowDistance.Name = "labelShadowDistance"; this.labelShadowDistance.Size = new System.Drawing.Size(74, 13); this.labelShadowDistance.TabIndex = 26; @@ -3216,37 +3666,48 @@ private void InitializeComponent() this.comboBoxDisplayMode.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); this.comboBoxDisplayMode.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; this.comboBoxDisplayMode.FormattingEnabled = true; - this.comboBoxDisplayMode.Location = new System.Drawing.Point(157, 20); + this.comboBoxDisplayMode.Location = new System.Drawing.Point(146, 20); this.comboBoxDisplayMode.Name = "comboBoxDisplayMode"; - this.comboBoxDisplayMode.Size = new System.Drawing.Size(246, 21); + this.comboBoxDisplayMode.Size = new System.Drawing.Size(257, 21); this.comboBoxDisplayMode.TabIndex = 0; // // comboBoxResolution // this.comboBoxResolution.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); this.comboBoxResolution.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.comboBoxResolution.Font = new System.Drawing.Font("Lucida Console", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.comboBoxResolution.FormattingEnabled = true; - this.comboBoxResolution.Location = new System.Drawing.Point(157, 45); + this.comboBoxResolution.Location = new System.Drawing.Point(146, 45); this.comboBoxResolution.Name = "comboBoxResolution"; - this.comboBoxResolution.Size = new System.Drawing.Size(246, 21); + this.comboBoxResolution.Size = new System.Drawing.Size(257, 20); this.comboBoxResolution.TabIndex = 4; + this.comboBoxResolution.SelectedIndexChanged += new System.EventHandler(this.comboBoxResolution_SelectedIndexChanged); // // buttonDetectResolution // this.buttonDetectResolution.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); - this.buttonDetectResolution.Location = new System.Drawing.Point(157, 98); + this.buttonDetectResolution.Location = new System.Drawing.Point(146, 97); this.buttonDetectResolution.Name = "buttonDetectResolution"; - this.buttonDetectResolution.Size = new System.Drawing.Size(246, 23); + this.buttonDetectResolution.Size = new System.Drawing.Size(257, 23); this.buttonDetectResolution.TabIndex = 23; this.buttonDetectResolution.Text = "Detect resolution"; this.buttonDetectResolution.UseVisualStyleBackColor = true; this.buttonDetectResolution.Click += new System.EventHandler(this.buttonDetectResolution_Click); // + // labelCustomResolution + // + this.labelCustomResolution.AutoSize = true; + this.labelCustomResolution.Location = new System.Drawing.Point(6, 74); + this.labelCustomResolution.Name = "labelCustomResolution"; + this.labelCustomResolution.Size = new System.Drawing.Size(93, 13); + this.labelCustomResolution.TabIndex = 2; + this.labelCustomResolution.Text = "Custom resolution:"; + // // labelCustomResolutionSpacer // this.labelCustomResolutionSpacer.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); this.labelCustomResolutionSpacer.AutoSize = true; - this.labelCustomResolutionSpacer.Location = new System.Drawing.Point(274, 75); + this.labelCustomResolutionSpacer.Location = new System.Drawing.Point(268, 74); this.labelCustomResolutionSpacer.Name = "labelCustomResolutionSpacer"; this.labelCustomResolutionSpacer.Size = new System.Drawing.Size(14, 13); this.labelCustomResolutionSpacer.TabIndex = 7; @@ -3382,154 +3843,274 @@ private void InitializeComponent() this.comboBoxShowActiveEffectsOnHUD.Size = new System.Drawing.Size(166, 21); this.comboBoxShowActiveEffectsOnHUD.TabIndex = 38; // - // groupBoxQuests + // groupBoxQuests + // + this.groupBoxQuests.Controls.Add(this.checkBoxEnableQuestAutoTrackDaily); + this.groupBoxQuests.Controls.Add(this.checkBoxEnableQuestAutoTrackEvent); + this.groupBoxQuests.Controls.Add(this.checkBoxEnableQuestAutoTrackMisc); + this.groupBoxQuests.Controls.Add(this.checkBoxEnableQuestAutoTrackSide); + this.groupBoxQuests.Controls.Add(this.checkBoxEnableQuestAutoTrackMain); + this.groupBoxQuests.Location = new System.Drawing.Point(6, 494); + this.groupBoxQuests.Name = "groupBoxQuests"; + this.groupBoxQuests.Size = new System.Drawing.Size(368, 142); + this.groupBoxQuests.TabIndex = 27; + this.groupBoxQuests.TabStop = false; + this.groupBoxQuests.Text = "Quests"; + // + // groupBoxMainMenu + // + this.groupBoxMainMenu.Controls.Add(this.checkBoxSkipSplash); + this.groupBoxMainMenu.Controls.Add(this.checkBoxIntroVideos); + this.groupBoxMainMenu.Location = new System.Drawing.Point(6, 6); + this.groupBoxMainMenu.Name = "groupBoxMainMenu"; + this.groupBoxMainMenu.Size = new System.Drawing.Size(368, 68); + this.groupBoxMainMenu.TabIndex = 5; + this.groupBoxMainMenu.TabStop = false; + this.groupBoxMainMenu.Text = "Main Menu"; + // + // groupBoxLogin + // + this.groupBoxLogin.Controls.Add(this.groupBoxLoginProfiles); + this.groupBoxLogin.Controls.Add(this.checkBoxAutoSignin); + this.groupBoxLogin.Controls.Add(this.checkBoxEnableSteam); + this.groupBoxLogin.Controls.Add(this.labelCredentialsExplanation); + this.groupBoxLogin.Controls.Add(this.textBoxPassword); + this.groupBoxLogin.Controls.Add(this.textBoxUserName); + this.groupBoxLogin.Controls.Add(this.checkBoxShowPassword); + this.groupBoxLogin.Controls.Add(this.labelPassword); + this.groupBoxLogin.Controls.Add(this.labelUserName); + this.groupBoxLogin.Location = new System.Drawing.Point(6, 6); + this.groupBoxLogin.Name = "groupBoxLogin"; + this.groupBoxLogin.Size = new System.Drawing.Size(443, 452); + this.groupBoxLogin.TabIndex = 14; + this.groupBoxLogin.TabStop = false; + this.groupBoxLogin.Text = "Login with Bethesda.net"; + // + // groupBoxLoginProfiles + // + this.groupBoxLoginProfiles.Controls.Add(this.radioButtonAccountNone); + this.groupBoxLoginProfiles.Controls.Add(this.radioButtonAccount1); + this.groupBoxLoginProfiles.Controls.Add(this.radioButtonAccount16); + this.groupBoxLoginProfiles.Controls.Add(this.radioButtonAccount2); + this.groupBoxLoginProfiles.Controls.Add(this.radioButtonAccount15); + this.groupBoxLoginProfiles.Controls.Add(this.radioButtonAccount3); + this.groupBoxLoginProfiles.Controls.Add(this.radioButtonAccount14); + this.groupBoxLoginProfiles.Controls.Add(this.radioButtonAccount4); + this.groupBoxLoginProfiles.Controls.Add(this.radioButtonAccount13); + this.groupBoxLoginProfiles.Controls.Add(this.radioButtonAccount5); + this.groupBoxLoginProfiles.Controls.Add(this.radioButtonAccount12); + this.groupBoxLoginProfiles.Controls.Add(this.radioButtonAccount6); + this.groupBoxLoginProfiles.Controls.Add(this.radioButtonAccount11); + this.groupBoxLoginProfiles.Controls.Add(this.radioButtonAccount7); + this.groupBoxLoginProfiles.Controls.Add(this.radioButtonAccount10); + this.groupBoxLoginProfiles.Controls.Add(this.radioButtonAccount8); + this.groupBoxLoginProfiles.Controls.Add(this.radioButtonAccount9); + this.groupBoxLoginProfiles.Location = new System.Drawing.Point(11, 296); + this.groupBoxLoginProfiles.Name = "groupBoxLoginProfiles"; + this.groupBoxLoginProfiles.Size = new System.Drawing.Size(421, 143); + this.groupBoxLoginProfiles.TabIndex = 29; + this.groupBoxLoginProfiles.TabStop = false; + this.groupBoxLoginProfiles.Text = "Profiles"; + // + // radioButtonAccountNone + // + this.radioButtonAccountNone.AutoSize = true; + this.radioButtonAccountNone.Location = new System.Drawing.Point(14, 20); + this.radioButtonAccountNone.Name = "radioButtonAccountNone"; + this.radioButtonAccountNone.Size = new System.Drawing.Size(51, 17); + this.radioButtonAccountNone.TabIndex = 29; + this.radioButtonAccountNone.TabStop = true; + this.radioButtonAccountNone.Text = "None"; + this.radioButtonAccountNone.UseVisualStyleBackColor = true; + this.radioButtonAccountNone.CheckedChanged += new System.EventHandler(this.radioButtonAccountNone_CheckedChanged); + // + // radioButtonAccount1 + // + this.radioButtonAccount1.AutoSize = true; + this.radioButtonAccount1.Location = new System.Drawing.Point(14, 46); + this.radioButtonAccount1.Name = "radioButtonAccount1"; + this.radioButtonAccount1.Size = new System.Drawing.Size(81, 17); + this.radioButtonAccount1.TabIndex = 12; + this.radioButtonAccount1.Text = "Account #1"; + this.radioButtonAccount1.UseVisualStyleBackColor = true; + // + // radioButtonAccount16 + // + this.radioButtonAccount16.AutoSize = true; + this.radioButtonAccount16.Location = new System.Drawing.Point(320, 115); + this.radioButtonAccount16.Name = "radioButtonAccount16"; + this.radioButtonAccount16.Size = new System.Drawing.Size(87, 17); + this.radioButtonAccount16.TabIndex = 28; + this.radioButtonAccount16.Text = "Account #16"; + this.radioButtonAccount16.UseVisualStyleBackColor = true; + // + // radioButtonAccount2 + // + this.radioButtonAccount2.AutoSize = true; + this.radioButtonAccount2.Location = new System.Drawing.Point(116, 46); + this.radioButtonAccount2.Name = "radioButtonAccount2"; + this.radioButtonAccount2.Size = new System.Drawing.Size(81, 17); + this.radioButtonAccount2.TabIndex = 13; + this.radioButtonAccount2.Text = "Account #2"; + this.radioButtonAccount2.UseVisualStyleBackColor = true; + // + // radioButtonAccount15 + // + this.radioButtonAccount15.AutoSize = true; + this.radioButtonAccount15.Location = new System.Drawing.Point(218, 115); + this.radioButtonAccount15.Name = "radioButtonAccount15"; + this.radioButtonAccount15.Size = new System.Drawing.Size(87, 17); + this.radioButtonAccount15.TabIndex = 27; + this.radioButtonAccount15.Text = "Account #15"; + this.radioButtonAccount15.UseVisualStyleBackColor = true; + // + // radioButtonAccount3 + // + this.radioButtonAccount3.AutoSize = true; + this.radioButtonAccount3.Location = new System.Drawing.Point(218, 46); + this.radioButtonAccount3.Name = "radioButtonAccount3"; + this.radioButtonAccount3.Size = new System.Drawing.Size(81, 17); + this.radioButtonAccount3.TabIndex = 14; + this.radioButtonAccount3.Text = "Account #3"; + this.radioButtonAccount3.UseVisualStyleBackColor = true; + // + // radioButtonAccount14 // - this.groupBoxQuests.Controls.Add(this.checkBoxEnableQuestAutoTrackDaily); - this.groupBoxQuests.Controls.Add(this.checkBoxEnableQuestAutoTrackEvent); - this.groupBoxQuests.Controls.Add(this.checkBoxEnableQuestAutoTrackMisc); - this.groupBoxQuests.Controls.Add(this.checkBoxEnableQuestAutoTrackSide); - this.groupBoxQuests.Controls.Add(this.checkBoxEnableQuestAutoTrackMain); - this.groupBoxQuests.Location = new System.Drawing.Point(6, 494); - this.groupBoxQuests.Name = "groupBoxQuests"; - this.groupBoxQuests.Size = new System.Drawing.Size(368, 142); - this.groupBoxQuests.TabIndex = 27; - this.groupBoxQuests.TabStop = false; - this.groupBoxQuests.Text = "Quests"; + this.radioButtonAccount14.AutoSize = true; + this.radioButtonAccount14.Location = new System.Drawing.Point(116, 115); + this.radioButtonAccount14.Name = "radioButtonAccount14"; + this.radioButtonAccount14.Size = new System.Drawing.Size(87, 17); + this.radioButtonAccount14.TabIndex = 26; + this.radioButtonAccount14.Text = "Account #14"; + this.radioButtonAccount14.UseVisualStyleBackColor = true; // - // groupBoxMainMenu + // radioButtonAccount4 // - this.groupBoxMainMenu.Controls.Add(this.checkBoxShowSplash); - this.groupBoxMainMenu.Controls.Add(this.checkBoxIntroVideos); - this.groupBoxMainMenu.Location = new System.Drawing.Point(6, 6); - this.groupBoxMainMenu.Name = "groupBoxMainMenu"; - this.groupBoxMainMenu.Size = new System.Drawing.Size(368, 68); - this.groupBoxMainMenu.TabIndex = 5; - this.groupBoxMainMenu.TabStop = false; - this.groupBoxMainMenu.Text = "Main Menu"; + this.radioButtonAccount4.AutoSize = true; + this.radioButtonAccount4.Location = new System.Drawing.Point(320, 46); + this.radioButtonAccount4.Name = "radioButtonAccount4"; + this.radioButtonAccount4.Size = new System.Drawing.Size(81, 17); + this.radioButtonAccount4.TabIndex = 15; + this.radioButtonAccount4.Text = "Account #4"; + this.radioButtonAccount4.UseVisualStyleBackColor = true; // - // groupBoxLogin + // radioButtonAccount13 // - this.groupBoxLogin.Controls.Add(this.checkBoxAutoSignin); - this.groupBoxLogin.Controls.Add(this.radioButtonAccount8); - this.groupBoxLogin.Controls.Add(this.radioButtonAccount7); - this.groupBoxLogin.Controls.Add(this.radioButtonAccount6); - this.groupBoxLogin.Controls.Add(this.radioButtonAccount5); - this.groupBoxLogin.Controls.Add(this.radioButtonAccount4); - this.groupBoxLogin.Controls.Add(this.radioButtonAccount3); - this.groupBoxLogin.Controls.Add(this.radioButtonAccount2); - this.groupBoxLogin.Controls.Add(this.radioButtonAccount1); - this.groupBoxLogin.Controls.Add(this.labelAccountProfiles); - this.groupBoxLogin.Controls.Add(this.checkBoxDisableSteam); - this.groupBoxLogin.Controls.Add(this.labelCredentialsExplanation); - this.groupBoxLogin.Controls.Add(this.textBoxPassword); - this.groupBoxLogin.Controls.Add(this.textBoxUserName); - this.groupBoxLogin.Controls.Add(this.checkBoxShowPassword); - this.groupBoxLogin.Controls.Add(this.labelPassword); - this.groupBoxLogin.Controls.Add(this.labelUserName); - this.groupBoxLogin.Location = new System.Drawing.Point(6, 6); - this.groupBoxLogin.Name = "groupBoxLogin"; - this.groupBoxLogin.Size = new System.Drawing.Size(443, 452); - this.groupBoxLogin.TabIndex = 14; - this.groupBoxLogin.TabStop = false; - this.groupBoxLogin.Text = "Login with Bethesda.net"; + this.radioButtonAccount13.AutoSize = true; + this.radioButtonAccount13.Location = new System.Drawing.Point(14, 115); + this.radioButtonAccount13.Name = "radioButtonAccount13"; + this.radioButtonAccount13.Size = new System.Drawing.Size(87, 17); + this.radioButtonAccount13.TabIndex = 25; + this.radioButtonAccount13.Text = "Account #13"; + this.radioButtonAccount13.UseVisualStyleBackColor = true; // - // radioButtonAccount8 + // radioButtonAccount5 // - this.radioButtonAccount8.AutoSize = true; - this.radioButtonAccount8.Location = new System.Drawing.Point(353, 131); - this.radioButtonAccount8.Name = "radioButtonAccount8"; - this.radioButtonAccount8.Size = new System.Drawing.Size(81, 17); - this.radioButtonAccount8.TabIndex = 19; - this.radioButtonAccount8.Text = "Account #8"; - this.radioButtonAccount8.UseVisualStyleBackColor = true; + this.radioButtonAccount5.AutoSize = true; + this.radioButtonAccount5.Location = new System.Drawing.Point(14, 69); + this.radioButtonAccount5.Name = "radioButtonAccount5"; + this.radioButtonAccount5.Size = new System.Drawing.Size(81, 17); + this.radioButtonAccount5.TabIndex = 16; + this.radioButtonAccount5.Text = "Account #5"; + this.radioButtonAccount5.UseVisualStyleBackColor = true; // - // radioButtonAccount7 + // radioButtonAccount12 // - this.radioButtonAccount7.AutoSize = true; - this.radioButtonAccount7.Location = new System.Drawing.Point(266, 131); - this.radioButtonAccount7.Name = "radioButtonAccount7"; - this.radioButtonAccount7.Size = new System.Drawing.Size(81, 17); - this.radioButtonAccount7.TabIndex = 18; - this.radioButtonAccount7.Text = "Account #7"; - this.radioButtonAccount7.UseVisualStyleBackColor = true; + this.radioButtonAccount12.AutoSize = true; + this.radioButtonAccount12.Location = new System.Drawing.Point(320, 92); + this.radioButtonAccount12.Name = "radioButtonAccount12"; + this.radioButtonAccount12.Size = new System.Drawing.Size(87, 17); + this.radioButtonAccount12.TabIndex = 24; + this.radioButtonAccount12.Text = "Account #12"; + this.radioButtonAccount12.UseVisualStyleBackColor = true; // // radioButtonAccount6 // this.radioButtonAccount6.AutoSize = true; - this.radioButtonAccount6.Location = new System.Drawing.Point(179, 131); + this.radioButtonAccount6.Location = new System.Drawing.Point(116, 69); this.radioButtonAccount6.Name = "radioButtonAccount6"; this.radioButtonAccount6.Size = new System.Drawing.Size(81, 17); this.radioButtonAccount6.TabIndex = 17; this.radioButtonAccount6.Text = "Account #6"; this.radioButtonAccount6.UseVisualStyleBackColor = true; // - // radioButtonAccount5 + // radioButtonAccount11 // - this.radioButtonAccount5.AutoSize = true; - this.radioButtonAccount5.Location = new System.Drawing.Point(92, 131); - this.radioButtonAccount5.Name = "radioButtonAccount5"; - this.radioButtonAccount5.Size = new System.Drawing.Size(81, 17); - this.radioButtonAccount5.TabIndex = 16; - this.radioButtonAccount5.Text = "Account #5"; - this.radioButtonAccount5.UseVisualStyleBackColor = true; + this.radioButtonAccount11.AutoSize = true; + this.radioButtonAccount11.Location = new System.Drawing.Point(218, 92); + this.radioButtonAccount11.Name = "radioButtonAccount11"; + this.radioButtonAccount11.Size = new System.Drawing.Size(87, 17); + this.radioButtonAccount11.TabIndex = 23; + this.radioButtonAccount11.Text = "Account #11"; + this.radioButtonAccount11.UseVisualStyleBackColor = true; // - // radioButtonAccount4 + // radioButtonAccount7 // - this.radioButtonAccount4.AutoSize = true; - this.radioButtonAccount4.Location = new System.Drawing.Point(353, 108); - this.radioButtonAccount4.Name = "radioButtonAccount4"; - this.radioButtonAccount4.Size = new System.Drawing.Size(81, 17); - this.radioButtonAccount4.TabIndex = 15; - this.radioButtonAccount4.Text = "Account #4"; - this.radioButtonAccount4.UseVisualStyleBackColor = true; + this.radioButtonAccount7.AutoSize = true; + this.radioButtonAccount7.Location = new System.Drawing.Point(218, 69); + this.radioButtonAccount7.Name = "radioButtonAccount7"; + this.radioButtonAccount7.Size = new System.Drawing.Size(81, 17); + this.radioButtonAccount7.TabIndex = 18; + this.radioButtonAccount7.Text = "Account #7"; + this.radioButtonAccount7.UseVisualStyleBackColor = true; // - // radioButtonAccount3 + // radioButtonAccount10 // - this.radioButtonAccount3.AutoSize = true; - this.radioButtonAccount3.Location = new System.Drawing.Point(266, 108); - this.radioButtonAccount3.Name = "radioButtonAccount3"; - this.radioButtonAccount3.Size = new System.Drawing.Size(81, 17); - this.radioButtonAccount3.TabIndex = 14; - this.radioButtonAccount3.Text = "Account #3"; - this.radioButtonAccount3.UseVisualStyleBackColor = true; + this.radioButtonAccount10.AutoSize = true; + this.radioButtonAccount10.Location = new System.Drawing.Point(116, 92); + this.radioButtonAccount10.Name = "radioButtonAccount10"; + this.radioButtonAccount10.Size = new System.Drawing.Size(87, 17); + this.radioButtonAccount10.TabIndex = 22; + this.radioButtonAccount10.Text = "Account #10"; + this.radioButtonAccount10.UseVisualStyleBackColor = true; // - // radioButtonAccount2 + // radioButtonAccount8 // - this.radioButtonAccount2.AutoSize = true; - this.radioButtonAccount2.Location = new System.Drawing.Point(179, 108); - this.radioButtonAccount2.Name = "radioButtonAccount2"; - this.radioButtonAccount2.Size = new System.Drawing.Size(81, 17); - this.radioButtonAccount2.TabIndex = 13; - this.radioButtonAccount2.Text = "Account #2"; - this.radioButtonAccount2.UseVisualStyleBackColor = true; + this.radioButtonAccount8.AutoSize = true; + this.radioButtonAccount8.Location = new System.Drawing.Point(320, 69); + this.radioButtonAccount8.Name = "radioButtonAccount8"; + this.radioButtonAccount8.Size = new System.Drawing.Size(81, 17); + this.radioButtonAccount8.TabIndex = 19; + this.radioButtonAccount8.Text = "Account #8"; + this.radioButtonAccount8.UseVisualStyleBackColor = true; // - // radioButtonAccount1 + // radioButtonAccount9 // - this.radioButtonAccount1.AutoSize = true; - this.radioButtonAccount1.Location = new System.Drawing.Point(92, 108); - this.radioButtonAccount1.Name = "radioButtonAccount1"; - this.radioButtonAccount1.Size = new System.Drawing.Size(81, 17); - this.radioButtonAccount1.TabIndex = 12; - this.radioButtonAccount1.Text = "Account #1"; - this.radioButtonAccount1.UseVisualStyleBackColor = true; + this.radioButtonAccount9.AutoSize = true; + this.radioButtonAccount9.Location = new System.Drawing.Point(14, 92); + this.radioButtonAccount9.Name = "radioButtonAccount9"; + this.radioButtonAccount9.Size = new System.Drawing.Size(81, 17); + this.radioButtonAccount9.TabIndex = 21; + this.radioButtonAccount9.Text = "Account #9"; + this.radioButtonAccount9.UseVisualStyleBackColor = true; + // + // checkBoxAutoSignin + // + this.checkBoxAutoSignin.AutoSize = true; + this.checkBoxAutoSignin.Location = new System.Drawing.Point(12, 103); + this.checkBoxAutoSignin.Name = "checkBoxAutoSignin"; + this.checkBoxAutoSignin.Size = new System.Drawing.Size(121, 17); + this.checkBoxAutoSignin.TabIndex = 20; + this.checkBoxAutoSignin.Text = "Automatically sign-in"; + this.checkBoxAutoSignin.UseVisualStyleBackColor = true; // - // labelAccountProfiles + // checkBoxEnableSteam // - this.labelAccountProfiles.AutoSize = true; - this.labelAccountProfiles.Location = new System.Drawing.Point(9, 110); - this.labelAccountProfiles.Name = "labelAccountProfiles"; - this.labelAccountProfiles.Size = new System.Drawing.Size(44, 13); - this.labelAccountProfiles.TabIndex = 7; - this.labelAccountProfiles.Text = "Profiles:"; + this.checkBoxEnableSteam.AutoSize = true; + this.checkBoxEnableSteam.Location = new System.Drawing.Point(12, 126); + this.checkBoxEnableSteam.Name = "checkBoxEnableSteam"; + this.checkBoxEnableSteam.Size = new System.Drawing.Size(92, 17); + this.checkBoxEnableSteam.TabIndex = 6; + this.checkBoxEnableSteam.Text = "Enable Steam"; + this.checkBoxEnableSteam.UseVisualStyleBackColor = true; // // labelCredentialsExplanation // - this.labelCredentialsExplanation.AutoSize = true; this.labelCredentialsExplanation.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.labelCredentialsExplanation.ForeColor = System.Drawing.Color.DimGray; - this.labelCredentialsExplanation.Location = new System.Drawing.Point(9, 235); + this.labelCredentialsExplanation.Location = new System.Drawing.Point(9, 153); this.labelCredentialsExplanation.Name = "labelCredentialsExplanation"; - this.labelCredentialsExplanation.Size = new System.Drawing.Size(349, 91); + this.labelCredentialsExplanation.Size = new System.Drawing.Size(428, 144); this.labelCredentialsExplanation.TabIndex = 5; this.labelCredentialsExplanation.Text = resources.GetString("labelCredentialsExplanation.Text"); // @@ -3587,12 +4168,12 @@ private void InitializeComponent() // tabPageInfo // this.tabPageInfo.AutoScroll = true; + this.tabPageInfo.Controls.Add(this.groupBoxSettings); this.tabPageInfo.Controls.Add(this.linkLabelWhatsNew); this.tabPageInfo.Controls.Add(this.linkLabelAttribution); this.tabPageInfo.Controls.Add(this.panelUpdate); this.tabPageInfo.Controls.Add(this.labelNWModeActive); this.tabPageInfo.Controls.Add(this.pictureBoxSpinnerCheckForUpdates); - this.tabPageInfo.Controls.Add(this.panel1); this.tabPageInfo.Controls.Add(this.labelGameEdition); this.tabPageInfo.Controls.Add(this.pictureBoxGameEdition); this.tabPageInfo.Controls.Add(this.pictureBox1); @@ -3613,10 +4194,42 @@ private void InitializeComponent() this.tabPageInfo.Text = "Info"; this.tabPageInfo.UseVisualStyleBackColor = true; // + // groupBoxSettings + // + this.groupBoxSettings.Controls.Add(this.linkLabelOpenSettings); + this.groupBoxSettings.Controls.Add(this.labelSettingsNotice); + this.groupBoxSettings.Location = new System.Drawing.Point(454, 6); + this.groupBoxSettings.Name = "groupBoxSettings"; + this.groupBoxSettings.Size = new System.Drawing.Size(390, 91); + this.groupBoxSettings.TabIndex = 44; + this.groupBoxSettings.TabStop = false; + this.groupBoxSettings.Text = "Settings"; + // + // linkLabelOpenSettings + // + this.linkLabelOpenSettings.Location = new System.Drawing.Point(5, 56); + this.linkLabelOpenSettings.Name = "linkLabelOpenSettings"; + this.linkLabelOpenSettings.Size = new System.Drawing.Size(380, 23); + this.linkLabelOpenSettings.TabIndex = 3; + this.linkLabelOpenSettings.TabStop = true; + this.linkLabelOpenSettings.Text = "Open settings"; + this.linkLabelOpenSettings.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + this.linkLabelOpenSettings.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.showSettings_OnClick); + // + // labelSettingsNotice + // + this.labelSettingsNotice.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64))))); + this.labelSettingsNotice.Location = new System.Drawing.Point(5, 16); + this.labelSettingsNotice.Name = "labelSettingsNotice"; + this.labelSettingsNotice.Size = new System.Drawing.Size(380, 46); + this.labelSettingsNotice.TabIndex = 2; + this.labelSettingsNotice.Text = "Everything that was here before has been moved into the settings."; + this.labelSettingsNotice.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + // // linkLabelWhatsNew // this.linkLabelWhatsNew.AutoSize = true; - this.linkLabelWhatsNew.Location = new System.Drawing.Point(90, 205); + this.linkLabelWhatsNew.Location = new System.Drawing.Point(90, 222); this.linkLabelWhatsNew.Name = "linkLabelWhatsNew"; this.linkLabelWhatsNew.Size = new System.Drawing.Size(69, 13); this.linkLabelWhatsNew.TabIndex = 42; @@ -3627,7 +4240,7 @@ private void InitializeComponent() // linkLabelAttribution // this.linkLabelAttribution.AutoSize = true; - this.linkLabelAttribution.Location = new System.Drawing.Point(90, 232); + this.linkLabelAttribution.Location = new System.Drawing.Point(90, 249); this.linkLabelAttribution.Name = "linkLabelAttribution"; this.linkLabelAttribution.Size = new System.Drawing.Size(76, 13); this.linkLabelAttribution.TabIndex = 41; @@ -3641,7 +4254,7 @@ private void InitializeComponent() this.panelUpdate.Controls.Add(this.labelNewVersion); this.panelUpdate.Controls.Add(this.linkLabelManualDownloadPage); this.panelUpdate.Controls.Add(this.pictureBoxUpdateButton); - this.panelUpdate.Location = new System.Drawing.Point(93, 357); + this.panelUpdate.Location = new System.Drawing.Point(93, 338); this.panelUpdate.Name = "panelUpdate"; this.panelUpdate.Size = new System.Drawing.Size(287, 100); this.panelUpdate.TabIndex = 39; @@ -3666,7 +4279,7 @@ private void InitializeComponent() this.linkLabelManualDownloadPage.TabIndex = 2; this.linkLabelManualDownloadPage.TabStop = true; this.linkLabelManualDownloadPage.Text = "Or download and install manually..."; - this.linkLabelManualDownloadPage.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.linkLabel1_LinkClicked); + this.linkLabelManualDownloadPage.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.linkLabelManualDownloadPage_LinkClicked); // // pictureBoxUpdateButton // @@ -3677,14 +4290,14 @@ private void InitializeComponent() this.pictureBoxUpdateButton.SizeMode = System.Windows.Forms.PictureBoxSizeMode.CenterImage; this.pictureBoxUpdateButton.TabIndex = 38; this.pictureBoxUpdateButton.TabStop = false; - this.pictureBoxUpdateButton.Click += new System.EventHandler(this.pictureBoxUpdateButton_Click); + this.pictureBoxUpdateButton.Click += new System.EventHandler(this.buttonUpdateNow_Click); // // labelNWModeActive // this.labelNWModeActive.AutoSize = true; this.labelNWModeActive.Font = new System.Drawing.Font("Microsoft Sans Serif", 9F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.labelNWModeActive.ForeColor = System.Drawing.Color.OrangeRed; - this.labelNWModeActive.Location = new System.Drawing.Point(90, 172); + this.labelNWModeActive.Location = new System.Drawing.Point(90, 189); this.labelNWModeActive.Name = "labelNWModeActive"; this.labelNWModeActive.Size = new System.Drawing.Size(202, 15); this.labelNWModeActive.TabIndex = 40; @@ -3693,7 +4306,7 @@ private void InitializeComponent() // pictureBoxSpinnerCheckForUpdates // this.pictureBoxSpinnerCheckForUpdates.Image = global::Fo76ini.Properties.Resources.Spinner_24; - this.pictureBoxSpinnerCheckForUpdates.Location = new System.Drawing.Point(173, 110); + this.pictureBoxSpinnerCheckForUpdates.Location = new System.Drawing.Point(173, 127); this.pictureBoxSpinnerCheckForUpdates.Name = "pictureBoxSpinnerCheckForUpdates"; this.pictureBoxSpinnerCheckForUpdates.Size = new System.Drawing.Size(24, 24); this.pictureBoxSpinnerCheckForUpdates.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom; @@ -3701,489 +4314,32 @@ private void InitializeComponent() this.pictureBoxSpinnerCheckForUpdates.TabStop = false; this.pictureBoxSpinnerCheckForUpdates.Visible = false; // - // panel1 - // - this.panel1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) - | System.Windows.Forms.AnchorStyles.Right))); - this.panel1.AutoScroll = true; - this.panel1.AutoScrollMargin = new System.Drawing.Size(0, 6); - this.panel1.Controls.Add(this.groupBoxNuclearWinterMode); - this.panel1.Controls.Add(this.groupBoxLocalization); - this.panel1.Controls.Add(this.groupBoxGameEdition); - this.panel1.Controls.Add(this.groupBoxLaunchOptions); - this.panel1.Controls.Add(this.groupBoxGamePaths); - this.panel1.Controls.Add(this.groupBoxOptions); - this.panel1.Controls.Add(this.groupBoxBehavior); - this.panel1.Location = new System.Drawing.Point(415, 0); - this.panel1.Name = "panel1"; - this.panel1.Size = new System.Drawing.Size(437, 468); - this.panel1.TabIndex = 36; - // - // groupBoxNuclearWinterMode - // - this.groupBoxNuclearWinterMode.Controls.Add(this.checkBoxNWAutoDeployMods); - this.groupBoxNuclearWinterMode.Controls.Add(this.labelNWmodoptions); - this.groupBoxNuclearWinterMode.Controls.Add(this.labelNWdlloptions); - this.groupBoxNuclearWinterMode.Controls.Add(this.labelNWinioptions); - this.groupBoxNuclearWinterMode.Controls.Add(this.radioButtonNWRemoveLists); - this.groupBoxNuclearWinterMode.Controls.Add(this.radioButtonNWRenameINI); - this.groupBoxNuclearWinterMode.Controls.Add(this.checkBoxNWAutoDisableMods); - this.groupBoxNuclearWinterMode.Controls.Add(this.checkBoxNWRenameDLL); - this.groupBoxNuclearWinterMode.Location = new System.Drawing.Point(22, 548); - this.groupBoxNuclearWinterMode.Name = "groupBoxNuclearWinterMode"; - this.groupBoxNuclearWinterMode.Size = new System.Drawing.Size(392, 224); - this.groupBoxNuclearWinterMode.TabIndex = 40; - this.groupBoxNuclearWinterMode.TabStop = false; - this.groupBoxNuclearWinterMode.Text = "Nuclear Winter options"; - // - // checkBoxNWAutoDeployMods - // - this.checkBoxNWAutoDeployMods.AutoSize = true; - this.checkBoxNWAutoDeployMods.Location = new System.Drawing.Point(10, 193); - this.checkBoxNWAutoDeployMods.Name = "checkBoxNWAutoDeployMods"; - this.checkBoxNWAutoDeployMods.Size = new System.Drawing.Size(158, 17); - this.checkBoxNWAutoDeployMods.TabIndex = 25; - this.checkBoxNWAutoDeployMods.Text = "Deploy mods upon disabling"; - this.checkBoxNWAutoDeployMods.UseVisualStyleBackColor = true; - // - // labelNWmodoptions - // - this.labelNWmodoptions.AutoSize = true; - this.labelNWmodoptions.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.labelNWmodoptions.Location = new System.Drawing.Point(7, 152); - this.labelNWmodoptions.Name = "labelNWmodoptions"; - this.labelNWmodoptions.Size = new System.Drawing.Size(80, 13); - this.labelNWmodoptions.TabIndex = 24; - this.labelNWmodoptions.Text = "Mod options:"; - // - // labelNWdlloptions - // - this.labelNWdlloptions.AutoSize = true; - this.labelNWdlloptions.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.labelNWdlloptions.Location = new System.Drawing.Point(7, 99); - this.labelNWdlloptions.Name = "labelNWdlloptions"; - this.labelNWdlloptions.Size = new System.Drawing.Size(78, 13); - this.labelNWdlloptions.TabIndex = 23; - this.labelNWdlloptions.Text = "*.dll options:"; - // - // labelNWinioptions - // - this.labelNWinioptions.AutoSize = true; - this.labelNWinioptions.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.labelNWinioptions.Location = new System.Drawing.Point(7, 23); - this.labelNWinioptions.Name = "labelNWinioptions"; - this.labelNWinioptions.Size = new System.Drawing.Size(78, 13); - this.labelNWinioptions.TabIndex = 22; - this.labelNWinioptions.Text = "*.ini options:"; - // - // radioButtonNWRemoveLists - // - this.radioButtonNWRemoveLists.AutoSize = true; - this.radioButtonNWRemoveLists.Location = new System.Drawing.Point(10, 64); - this.radioButtonNWRemoveLists.Name = "radioButtonNWRemoveLists"; - this.radioButtonNWRemoveLists.Size = new System.Drawing.Size(184, 17); - this.radioButtonNWRemoveLists.TabIndex = 21; - this.radioButtonNWRemoveLists.TabStop = true; - this.radioButtonNWRemoveLists.Text = "Just remove archive resource lists"; - this.radioButtonNWRemoveLists.UseVisualStyleBackColor = true; - // - // radioButtonNWRenameINI - // - this.radioButtonNWRenameINI.AutoSize = true; - this.radioButtonNWRenameINI.Location = new System.Drawing.Point(10, 41); - this.radioButtonNWRenameINI.Name = "radioButtonNWRenameINI"; - this.radioButtonNWRenameINI.Size = new System.Drawing.Size(159, 17); - this.radioButtonNWRenameINI.TabIndex = 20; - this.radioButtonNWRenameINI.TabStop = true; - this.radioButtonNWRenameINI.Text = "Rename Fallout76Custom.ini"; - this.radioButtonNWRenameINI.UseVisualStyleBackColor = true; - // - // checkBoxNWAutoDisableMods - // - this.checkBoxNWAutoDisableMods.AutoSize = true; - this.checkBoxNWAutoDisableMods.Location = new System.Drawing.Point(10, 170); - this.checkBoxNWAutoDisableMods.Name = "checkBoxNWAutoDisableMods"; - this.checkBoxNWAutoDisableMods.Size = new System.Drawing.Size(164, 17); - this.checkBoxNWAutoDisableMods.TabIndex = 19; - this.checkBoxNWAutoDisableMods.Text = "Remove mods upon enabling"; - this.checkBoxNWAutoDisableMods.UseVisualStyleBackColor = true; - // - // checkBoxNWRenameDLL - // - this.checkBoxNWRenameDLL.AutoSize = true; - this.checkBoxNWRenameDLL.Location = new System.Drawing.Point(10, 117); - this.checkBoxNWRenameDLL.Name = "checkBoxNWRenameDLL"; - this.checkBoxNWRenameDLL.Size = new System.Drawing.Size(140, 17); - this.checkBoxNWRenameDLL.TabIndex = 18; - this.checkBoxNWRenameDLL.Text = "Rename added *.dll files"; - this.checkBoxNWRenameDLL.UseVisualStyleBackColor = true; - // - // groupBoxLocalization - // - this.groupBoxLocalization.Controls.Add(this.buttonRefreshLanguage); - this.groupBoxLocalization.Controls.Add(this.pictureBoxSpinnerDownloadLanguages); - this.groupBoxLocalization.Controls.Add(this.labelOutdatedLanguage); - this.groupBoxLocalization.Controls.Add(this.labelLanguage); - this.groupBoxLocalization.Controls.Add(this.buttonDownloadLanguages); - this.groupBoxLocalization.Controls.Add(this.comboBoxLanguage); - this.groupBoxLocalization.Location = new System.Drawing.Point(22, 6); - this.groupBoxLocalization.Name = "groupBoxLocalization"; - this.groupBoxLocalization.Size = new System.Drawing.Size(392, 111); - this.groupBoxLocalization.TabIndex = 30; - this.groupBoxLocalization.TabStop = false; - this.groupBoxLocalization.Text = "Localization"; - // - // buttonRefreshLanguage - // - this.buttonRefreshLanguage.Location = new System.Drawing.Point(295, 77); - this.buttonRefreshLanguage.Name = "buttonRefreshLanguage"; - this.buttonRefreshLanguage.Size = new System.Drawing.Size(90, 23); - this.buttonRefreshLanguage.TabIndex = 40; - this.buttonRefreshLanguage.Text = "Refresh"; - this.buttonRefreshLanguage.UseVisualStyleBackColor = true; - this.buttonRefreshLanguage.Click += new System.EventHandler(this.buttonRefreshLanguage_Click); - // - // pictureBoxSpinnerDownloadLanguages - // - this.pictureBoxSpinnerDownloadLanguages.Image = global::Fo76ini.Properties.Resources.Spinner_24; - this.pictureBoxSpinnerDownloadLanguages.Location = new System.Drawing.Point(68, 48); - this.pictureBoxSpinnerDownloadLanguages.Name = "pictureBoxSpinnerDownloadLanguages"; - this.pictureBoxSpinnerDownloadLanguages.Size = new System.Drawing.Size(24, 24); - this.pictureBoxSpinnerDownloadLanguages.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom; - this.pictureBoxSpinnerDownloadLanguages.TabIndex = 40; - this.pictureBoxSpinnerDownloadLanguages.TabStop = false; - this.pictureBoxSpinnerDownloadLanguages.Visible = false; - // - // labelOutdatedLanguage - // - this.labelOutdatedLanguage.AutoSize = true; - this.labelOutdatedLanguage.ForeColor = System.Drawing.Color.Firebrick; - this.labelOutdatedLanguage.Location = new System.Drawing.Point(7, 75); - this.labelOutdatedLanguage.Name = "labelOutdatedLanguage"; - this.labelOutdatedLanguage.Size = new System.Drawing.Size(209, 26); - this.labelOutdatedLanguage.TabIndex = 21; - this.labelOutdatedLanguage.Text = "This language is out-dated.\r\nSome elements might not be translated yet."; - // - // labelLanguage - // - this.labelLanguage.AutoSize = true; - this.labelLanguage.Location = new System.Drawing.Point(7, 25); - this.labelLanguage.Name = "labelLanguage"; - this.labelLanguage.Size = new System.Drawing.Size(58, 13); - this.labelLanguage.TabIndex = 16; - this.labelLanguage.Text = "Language:"; - // - // buttonDownloadLanguages - // - this.buttonDownloadLanguages.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.buttonDownloadLanguages.Location = new System.Drawing.Point(98, 48); - this.buttonDownloadLanguages.Name = "buttonDownloadLanguages"; - this.buttonDownloadLanguages.Size = new System.Drawing.Size(287, 23); - this.buttonDownloadLanguages.TabIndex = 20; - this.buttonDownloadLanguages.Text = "Download / update language files"; - this.buttonDownloadLanguages.UseVisualStyleBackColor = true; - this.buttonDownloadLanguages.Click += new System.EventHandler(this.buttonDownloadLanguages_Click); - // - // comboBoxLanguage - // - this.comboBoxLanguage.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.comboBoxLanguage.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; - this.comboBoxLanguage.FormattingEnabled = true; - this.comboBoxLanguage.Location = new System.Drawing.Point(98, 22); - this.comboBoxLanguage.Name = "comboBoxLanguage"; - this.comboBoxLanguage.Size = new System.Drawing.Size(287, 21); - this.comboBoxLanguage.TabIndex = 17; - this.comboBoxLanguage.SelectedIndexChanged += new System.EventHandler(this.comboBoxLanguage_SelectedIndexChanged); - // - // groupBoxGameEdition - // - this.groupBoxGameEdition.Controls.Add(this.pictureBoxMSStore); - this.groupBoxGameEdition.Controls.Add(this.pictureBoxSteam); - this.groupBoxGameEdition.Controls.Add(this.pictureBoxBethesdaNetPTS); - this.groupBoxGameEdition.Controls.Add(this.pictureBoxBethesdaNet); - this.groupBoxGameEdition.Controls.Add(this.radioButtonEditionMSStore); - this.groupBoxGameEdition.Controls.Add(this.radioButtonEditionBethesdaNetPTS); - this.groupBoxGameEdition.Controls.Add(this.radioButtonEditionSteam); - this.groupBoxGameEdition.Controls.Add(this.radioButtonEditionBethesdaNet); - this.groupBoxGameEdition.Location = new System.Drawing.Point(22, 123); - this.groupBoxGameEdition.Name = "groupBoxGameEdition"; - this.groupBoxGameEdition.Size = new System.Drawing.Size(392, 144); - this.groupBoxGameEdition.TabIndex = 27; - this.groupBoxGameEdition.TabStop = false; - this.groupBoxGameEdition.Text = "Game edition"; - // - // pictureBoxMSStore - // - this.pictureBoxMSStore.BackColor = System.Drawing.Color.Transparent; - this.pictureBoxMSStore.Image = global::Fo76ini.Properties.Resources.msstore_24; - this.pictureBoxMSStore.Location = new System.Drawing.Point(11, 109); - this.pictureBoxMSStore.Name = "pictureBoxMSStore"; - this.pictureBoxMSStore.Size = new System.Drawing.Size(24, 24); - this.pictureBoxMSStore.TabIndex = 29; - this.pictureBoxMSStore.TabStop = false; - // - // pictureBoxSteam - // - this.pictureBoxSteam.BackColor = System.Drawing.Color.Transparent; - this.pictureBoxSteam.Image = global::Fo76ini.Properties.Resources.steam_24px; - this.pictureBoxSteam.Location = new System.Drawing.Point(11, 79); - this.pictureBoxSteam.Name = "pictureBoxSteam"; - this.pictureBoxSteam.Size = new System.Drawing.Size(24, 24); - this.pictureBoxSteam.TabIndex = 28; - this.pictureBoxSteam.TabStop = false; - // - // pictureBoxBethesdaNetPTS - // - this.pictureBoxBethesdaNetPTS.BackColor = System.Drawing.Color.Transparent; - this.pictureBoxBethesdaNetPTS.Image = global::Fo76ini.Properties.Resources.bethesda_24; - this.pictureBoxBethesdaNetPTS.Location = new System.Drawing.Point(11, 49); - this.pictureBoxBethesdaNetPTS.Name = "pictureBoxBethesdaNetPTS"; - this.pictureBoxBethesdaNetPTS.Size = new System.Drawing.Size(24, 24); - this.pictureBoxBethesdaNetPTS.TabIndex = 27; - this.pictureBoxBethesdaNetPTS.TabStop = false; - // - // pictureBoxBethesdaNet - // - this.pictureBoxBethesdaNet.BackColor = System.Drawing.Color.Transparent; - this.pictureBoxBethesdaNet.Image = global::Fo76ini.Properties.Resources.bethesda_24; - this.pictureBoxBethesdaNet.Location = new System.Drawing.Point(11, 19); - this.pictureBoxBethesdaNet.Name = "pictureBoxBethesdaNet"; - this.pictureBoxBethesdaNet.Size = new System.Drawing.Size(24, 24); - this.pictureBoxBethesdaNet.TabIndex = 26; - this.pictureBoxBethesdaNet.TabStop = false; - // - // radioButtonEditionMSStore - // - this.radioButtonEditionMSStore.AutoSize = true; - this.radioButtonEditionMSStore.Location = new System.Drawing.Point(43, 112); - this.radioButtonEditionMSStore.Name = "radioButtonEditionMSStore"; - this.radioButtonEditionMSStore.Size = new System.Drawing.Size(188, 17); - this.radioButtonEditionMSStore.TabIndex = 3; - this.radioButtonEditionMSStore.Text = "Microsoft Store / Xbox Game Pass"; - this.radioButtonEditionMSStore.UseVisualStyleBackColor = true; - this.radioButtonEditionMSStore.CheckedChanged += new System.EventHandler(this.radioButtonEditionMSStore_CheckedChanged); - // - // radioButtonEditionBethesdaNetPTS - // - this.radioButtonEditionBethesdaNetPTS.AutoSize = true; - this.radioButtonEditionBethesdaNetPTS.Location = new System.Drawing.Point(43, 52); - this.radioButtonEditionBethesdaNetPTS.Name = "radioButtonEditionBethesdaNetPTS"; - this.radioButtonEditionBethesdaNetPTS.Size = new System.Drawing.Size(118, 17); - this.radioButtonEditionBethesdaNetPTS.TabIndex = 2; - this.radioButtonEditionBethesdaNetPTS.Text = "Bethesda.net (PTS)"; - this.radioButtonEditionBethesdaNetPTS.UseVisualStyleBackColor = true; - this.radioButtonEditionBethesdaNetPTS.CheckedChanged += new System.EventHandler(this.radioButtonEditionBethesdaNetPTS_CheckedChanged); - // - // radioButtonEditionSteam - // - this.radioButtonEditionSteam.AutoSize = true; - this.radioButtonEditionSteam.Location = new System.Drawing.Point(43, 82); - this.radioButtonEditionSteam.Name = "radioButtonEditionSteam"; - this.radioButtonEditionSteam.Size = new System.Drawing.Size(55, 17); - this.radioButtonEditionSteam.TabIndex = 1; - this.radioButtonEditionSteam.Text = "Steam"; - this.radioButtonEditionSteam.UseVisualStyleBackColor = true; - this.radioButtonEditionSteam.CheckedChanged += new System.EventHandler(this.radioButtonEditionSteam_CheckedChanged); - // - // radioButtonEditionBethesdaNet - // - this.radioButtonEditionBethesdaNet.AutoSize = true; - this.radioButtonEditionBethesdaNet.Location = new System.Drawing.Point(43, 22); - this.radioButtonEditionBethesdaNet.Name = "radioButtonEditionBethesdaNet"; - this.radioButtonEditionBethesdaNet.Size = new System.Drawing.Size(88, 17); - this.radioButtonEditionBethesdaNet.TabIndex = 0; - this.radioButtonEditionBethesdaNet.Text = "Bethesda.net"; - this.radioButtonEditionBethesdaNet.UseVisualStyleBackColor = true; - this.radioButtonEditionBethesdaNet.CheckedChanged += new System.EventHandler(this.radioButtonEditionBethesdaNet_CheckedChanged); - // - // groupBoxLaunchOptions - // - this.groupBoxLaunchOptions.Controls.Add(this.labelLaunchOptionMSStoreNotice); - this.groupBoxLaunchOptions.Controls.Add(this.labelLaunchOptionTip); - this.groupBoxLaunchOptions.Controls.Add(this.radioButtonLaunchViaExecutable); - this.groupBoxLaunchOptions.Controls.Add(this.radioButtonLaunchViaLink); - this.groupBoxLaunchOptions.Location = new System.Drawing.Point(22, 324); - this.groupBoxLaunchOptions.Name = "groupBoxLaunchOptions"; - this.groupBoxLaunchOptions.Size = new System.Drawing.Size(392, 93); - this.groupBoxLaunchOptions.TabIndex = 34; - this.groupBoxLaunchOptions.TabStop = false; - this.groupBoxLaunchOptions.Text = "Launch options"; - // - // labelLaunchOptionMSStoreNotice - // - this.labelLaunchOptionMSStoreNotice.AutoSize = true; - this.labelLaunchOptionMSStoreNotice.ForeColor = System.Drawing.Color.Red; - this.labelLaunchOptionMSStoreNotice.Location = new System.Drawing.Point(12, 67); - this.labelLaunchOptionMSStoreNotice.Name = "labelLaunchOptionMSStoreNotice"; - this.labelLaunchOptionMSStoreNotice.Size = new System.Drawing.Size(344, 13); - this.labelLaunchOptionMSStoreNotice.TabIndex = 3; - this.labelLaunchOptionMSStoreNotice.Text = "Fallout 76 cannot be run directly, if installed through the Microsoft Store."; - this.labelLaunchOptionMSStoreNotice.Visible = false; - // - // labelLaunchOptionTip - // - this.labelLaunchOptionTip.AutoSize = true; - this.labelLaunchOptionTip.ForeColor = System.Drawing.SystemColors.ControlDarkDark; - this.labelLaunchOptionTip.Location = new System.Drawing.Point(10, 67); - this.labelLaunchOptionTip.Name = "labelLaunchOptionTip"; - this.labelLaunchOptionTip.Size = new System.Drawing.Size(274, 13); - this.labelLaunchOptionTip.TabIndex = 2; - this.labelLaunchOptionTip.Text = "Tip: Enter your login credentials under the \"General\" tab."; - this.labelLaunchOptionTip.Visible = false; - // - // radioButtonLaunchViaExecutable - // - this.radioButtonLaunchViaExecutable.AutoSize = true; - this.radioButtonLaunchViaExecutable.Location = new System.Drawing.Point(10, 43); - this.radioButtonLaunchViaExecutable.Name = "radioButtonLaunchViaExecutable"; - this.radioButtonLaunchViaExecutable.Size = new System.Drawing.Size(157, 17); - this.radioButtonLaunchViaExecutable.TabIndex = 1; - this.radioButtonLaunchViaExecutable.TabStop = true; - this.radioButtonLaunchViaExecutable.Text = "Run \"Fallout76.exe\" directly"; - this.radioButtonLaunchViaExecutable.UseVisualStyleBackColor = true; - this.radioButtonLaunchViaExecutable.CheckedChanged += new System.EventHandler(this.radioButtonLaunchViaExecutable_CheckedChanged); - // - // radioButtonLaunchViaLink - // - this.radioButtonLaunchViaLink.AutoSize = true; - this.radioButtonLaunchViaLink.Location = new System.Drawing.Point(10, 20); - this.radioButtonLaunchViaLink.Name = "radioButtonLaunchViaLink"; - this.radioButtonLaunchViaLink.Size = new System.Drawing.Size(316, 17); - this.radioButtonLaunchViaLink.TabIndex = 0; - this.radioButtonLaunchViaLink.TabStop = true; - this.radioButtonLaunchViaLink.Text = "Launch via Steam / Bethesda.net / MS Store (recommended)"; - this.radioButtonLaunchViaLink.UseVisualStyleBackColor = true; - // - // groupBoxGamePaths - // - this.groupBoxGamePaths.Controls.Add(this.labelGamePath); - this.groupBoxGamePaths.Controls.Add(this.textBoxGamePath); - this.groupBoxGamePaths.Controls.Add(this.buttonPickGamePath); - this.groupBoxGamePaths.Location = new System.Drawing.Point(22, 273); - this.groupBoxGamePaths.Name = "groupBoxGamePaths"; - this.groupBoxGamePaths.Size = new System.Drawing.Size(392, 45); - this.groupBoxGamePaths.TabIndex = 33; - this.groupBoxGamePaths.TabStop = false; - this.groupBoxGamePaths.Text = "Paths"; - // - // labelGamePath - // - this.labelGamePath.AutoSize = true; - this.labelGamePath.Location = new System.Drawing.Point(7, 19); - this.labelGamePath.Name = "labelGamePath"; - this.labelGamePath.Size = new System.Drawing.Size(78, 13); - this.labelGamePath.TabIndex = 17; - this.labelGamePath.Text = "Game location:"; - // - // textBoxGamePath - // - this.textBoxGamePath.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.textBoxGamePath.Location = new System.Drawing.Point(111, 16); - this.textBoxGamePath.Name = "textBoxGamePath"; - this.textBoxGamePath.Size = new System.Drawing.Size(240, 20); - this.textBoxGamePath.TabIndex = 18; - this.textBoxGamePath.TextChanged += new System.EventHandler(this.textBoxGamePath_TextChanged); - // - // buttonPickGamePath - // - this.buttonPickGamePath.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); - this.buttonPickGamePath.Location = new System.Drawing.Point(357, 14); - this.buttonPickGamePath.Name = "buttonPickGamePath"; - this.buttonPickGamePath.Size = new System.Drawing.Size(28, 23); - this.buttonPickGamePath.TabIndex = 19; - this.buttonPickGamePath.Text = "..."; - this.buttonPickGamePath.UseVisualStyleBackColor = true; - this.buttonPickGamePath.Click += new System.EventHandler(this.buttonPickGamePath_Click); - // - // groupBoxOptions - // - this.groupBoxOptions.Controls.Add(this.checkBoxAlternativeINIMode); - this.groupBoxOptions.Controls.Add(this.checkBoxDenyNTFSWritePermission); - this.groupBoxOptions.Controls.Add(this.checkBoxMultipleGameEditionsUsed); - this.groupBoxOptions.Controls.Add(this.checkBoxReadOnly); - this.groupBoxOptions.Location = new System.Drawing.Point(22, 423); - this.groupBoxOptions.Name = "groupBoxOptions"; - this.groupBoxOptions.Size = new System.Drawing.Size(392, 119); - this.groupBoxOptions.TabIndex = 28; - this.groupBoxOptions.TabStop = false; - this.groupBoxOptions.Text = "Options"; - // - // groupBoxBehavior - // - this.groupBoxBehavior.Controls.Add(this.checkBoxPlayNotificationSound); - this.groupBoxBehavior.Controls.Add(this.checkBoxIgnoreUpdates); - this.groupBoxBehavior.Controls.Add(this.checkBoxOpenManageModsOnLaunch); - this.groupBoxBehavior.Controls.Add(this.checkBoxQuitOnGameLaunch); - this.groupBoxBehavior.Controls.Add(this.checkBoxSkipBackupQuestion); - this.groupBoxBehavior.Controls.Add(this.checkBoxAutoApply); - this.groupBoxBehavior.Location = new System.Drawing.Point(22, 778); - this.groupBoxBehavior.Name = "groupBoxBehavior"; - this.groupBoxBehavior.Size = new System.Drawing.Size(392, 168); - this.groupBoxBehavior.TabIndex = 31; - this.groupBoxBehavior.TabStop = false; - this.groupBoxBehavior.Text = "Behavior"; - // - // checkBoxPlayNotificationSound - // - this.checkBoxPlayNotificationSound.AutoSize = true; - this.checkBoxPlayNotificationSound.Checked = true; - this.checkBoxPlayNotificationSound.CheckState = System.Windows.Forms.CheckState.Checked; - this.checkBoxPlayNotificationSound.Location = new System.Drawing.Point(9, 135); - this.checkBoxPlayNotificationSound.Name = "checkBoxPlayNotificationSound"; - this.checkBoxPlayNotificationSound.Size = new System.Drawing.Size(132, 17); - this.checkBoxPlayNotificationSound.TabIndex = 25; - this.checkBoxPlayNotificationSound.Text = "Play notification sound"; - this.checkBoxPlayNotificationSound.UseVisualStyleBackColor = true; - // - // checkBoxIgnoreUpdates - // - this.checkBoxIgnoreUpdates.AutoSize = true; - this.checkBoxIgnoreUpdates.Location = new System.Drawing.Point(9, 111); - this.checkBoxIgnoreUpdates.Name = "checkBoxIgnoreUpdates"; - this.checkBoxIgnoreUpdates.Size = new System.Drawing.Size(143, 17); - this.checkBoxIgnoreUpdates.TabIndex = 24; - this.checkBoxIgnoreUpdates.Text = "Don\'t check for updates."; - this.checkBoxIgnoreUpdates.UseVisualStyleBackColor = true; - this.checkBoxIgnoreUpdates.CheckedChanged += new System.EventHandler(this.checkBoxIgnoreUpdates_CheckedChanged); - // - // checkBoxOpenManageModsOnLaunch - // - this.checkBoxOpenManageModsOnLaunch.AutoSize = true; - this.checkBoxOpenManageModsOnLaunch.Location = new System.Drawing.Point(9, 88); - this.checkBoxOpenManageModsOnLaunch.Name = "checkBoxOpenManageModsOnLaunch"; - this.checkBoxOpenManageModsOnLaunch.Size = new System.Drawing.Size(172, 17); - this.checkBoxOpenManageModsOnLaunch.TabIndex = 23; - this.checkBoxOpenManageModsOnLaunch.Text = "Open mod manager on startup."; - this.checkBoxOpenManageModsOnLaunch.UseVisualStyleBackColor = true; - this.checkBoxOpenManageModsOnLaunch.CheckedChanged += new System.EventHandler(this.checkBoxOpenManageModsOnLaunch_CheckedChanged); - // // labelGameEdition // this.labelGameEdition.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); this.labelGameEdition.BackColor = System.Drawing.Color.Black; this.labelGameEdition.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.labelGameEdition.ForeColor = System.Drawing.Color.White; - this.labelGameEdition.Location = new System.Drawing.Point(0, 424); + this.labelGameEdition.Location = new System.Drawing.Point(0, 405); this.labelGameEdition.Name = "labelGameEdition"; this.labelGameEdition.Size = new System.Drawing.Size(73, 36); this.labelGameEdition.TabIndex = 22; this.labelGameEdition.Text = "Unknown"; this.labelGameEdition.TextAlign = System.Drawing.ContentAlignment.TopCenter; + this.labelGameEdition.Click += new System.EventHandler(this.showProfiles_OnClick); // // pictureBoxGameEdition // this.pictureBoxGameEdition.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); this.pictureBoxGameEdition.BackColor = System.Drawing.Color.Black; this.pictureBoxGameEdition.Image = global::Fo76ini.Properties.Resources.help_128; - this.pictureBoxGameEdition.Location = new System.Drawing.Point(6, 357); + this.pictureBoxGameEdition.Location = new System.Drawing.Point(6, 338); this.pictureBoxGameEdition.Name = "pictureBoxGameEdition"; this.pictureBoxGameEdition.Size = new System.Drawing.Size(60, 60); this.pictureBoxGameEdition.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom; this.pictureBoxGameEdition.TabIndex = 21; this.pictureBoxGameEdition.TabStop = false; + this.pictureBoxGameEdition.Click += new System.EventHandler(this.showProfiles_OnClick); // // pictureBox1 // @@ -4203,7 +4359,7 @@ private void InitializeComponent() this.pictureBox2.BackColor = System.Drawing.Color.Black; this.pictureBox2.Location = new System.Drawing.Point(-4, 0); this.pictureBox2.Name = "pictureBox2"; - this.pictureBox2.Size = new System.Drawing.Size(77, 657); + this.pictureBox2.Size = new System.Drawing.Size(77, 468); this.pictureBox2.TabIndex = 18; this.pictureBox2.TabStop = false; // @@ -4212,7 +4368,7 @@ private void InitializeComponent() this.labelTranslationAuthor.AutoSize = true; this.labelTranslationAuthor.Font = new System.Drawing.Font("Microsoft Sans Serif", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.labelTranslationAuthor.ForeColor = System.Drawing.SystemColors.ControlText; - this.labelTranslationAuthor.Location = new System.Drawing.Point(203, 149); + this.labelTranslationAuthor.Location = new System.Drawing.Point(203, 166); this.labelTranslationAuthor.Name = "labelTranslationAuthor"; this.labelTranslationAuthor.Size = new System.Drawing.Size(64, 15); this.labelTranslationAuthor.TabIndex = 12; @@ -4223,7 +4379,7 @@ private void InitializeComponent() this.labelTranslationBy.AutoSize = true; this.labelTranslationBy.Font = new System.Drawing.Font("Microsoft Sans Serif", 9F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.labelTranslationBy.ForeColor = System.Drawing.SystemColors.ControlText; - this.labelTranslationBy.Location = new System.Drawing.Point(90, 149); + this.labelTranslationBy.Location = new System.Drawing.Point(90, 166); this.labelTranslationBy.Name = "labelTranslationBy"; this.labelTranslationBy.Size = new System.Drawing.Size(101, 15); this.labelTranslationBy.TabIndex = 11; @@ -4233,7 +4389,7 @@ private void InitializeComponent() // this.labelAuthorName.AutoSize = true; this.labelAuthorName.Font = new System.Drawing.Font("Microsoft Sans Serif", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.labelAuthorName.Location = new System.Drawing.Point(203, 131); + this.labelAuthorName.Location = new System.Drawing.Point(203, 148); this.labelAuthorName.Name = "labelAuthorName"; this.labelAuthorName.Size = new System.Drawing.Size(64, 15); this.labelAuthorName.TabIndex = 10; @@ -4243,7 +4399,7 @@ private void InitializeComponent() // this.labelConfigVersion.AutoSize = true; this.labelConfigVersion.Font = new System.Drawing.Font("Microsoft Sans Serif", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.labelConfigVersion.Location = new System.Drawing.Point(203, 114); + this.labelConfigVersion.Location = new System.Drawing.Point(203, 131); this.labelConfigVersion.Name = "labelConfigVersion"; this.labelConfigVersion.Size = new System.Drawing.Size(14, 15); this.labelConfigVersion.TabIndex = 9; @@ -4253,7 +4409,7 @@ private void InitializeComponent() // this.labelAuthor.AutoSize = true; this.labelAuthor.Font = new System.Drawing.Font("Microsoft Sans Serif", 9F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.labelAuthor.Location = new System.Drawing.Point(90, 131); + this.labelAuthor.Location = new System.Drawing.Point(90, 148); this.labelAuthor.Name = "labelAuthor"; this.labelAuthor.Size = new System.Drawing.Size(52, 15); this.labelAuthor.TabIndex = 8; @@ -4263,7 +4419,7 @@ private void InitializeComponent() // this.labelVersion.AutoSize = true; this.labelVersion.Font = new System.Drawing.Font("Microsoft Sans Serif", 9F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.labelVersion.Location = new System.Drawing.Point(90, 114); + this.labelVersion.Location = new System.Drawing.Point(90, 131); this.labelVersion.Name = "labelVersion"; this.labelVersion.Size = new System.Drawing.Size(59, 15); this.labelVersion.TabIndex = 7; @@ -4271,14 +4427,13 @@ private void InitializeComponent() // // labelDescription // - this.labelDescription.AutoSize = true; this.labelDescription.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.labelDescription.Location = new System.Drawing.Point(90, 59); this.labelDescription.Name = "labelDescription"; - this.labelDescription.Size = new System.Drawing.Size(268, 26); + this.labelDescription.Size = new System.Drawing.Size(342, 65); this.labelDescription.TabIndex = 6; - this.labelDescription.Text = "This tool allows you to quickly tweak INI settings.\r\nTip: Hover over an option, i" + - "f you\'re unsure what it does."; + this.labelDescription.Text = "This tool allows you to change various game settings and install mods.\r\nTip: Hove" + + "r over an option, if you\'re unsure what it does."; // // labelTitle // @@ -4304,6 +4459,7 @@ private void InitializeComponent() this.tabControl1.Controls.Add(this.tabPagePipBoy); this.tabControl1.Controls.Add(this.tabPageGallery); this.tabControl1.Controls.Add(this.tabPageCustom); + this.tabControl1.Controls.Add(this.tabPageDangerZone); this.tabControl1.Location = new System.Drawing.Point(12, 59); this.tabControl1.Multiline = true; this.tabControl1.Name = "tabControl1"; @@ -4768,9 +4924,9 @@ private void InitializeComponent() | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); this.pictureBoxGalleryLoadingGIF.Image = global::Fo76ini.Properties.Resources.Spinner_200; - this.pictureBoxGalleryLoadingGIF.Location = new System.Drawing.Point(7, 21); + this.pictureBoxGalleryLoadingGIF.Location = new System.Drawing.Point(7, 18); this.pictureBoxGalleryLoadingGIF.Name = "pictureBoxGalleryLoadingGIF"; - this.pictureBoxGalleryLoadingGIF.Size = new System.Drawing.Size(530, 424); + this.pictureBoxGalleryLoadingGIF.Size = new System.Drawing.Size(533, 427); this.pictureBoxGalleryLoadingGIF.SizeMode = System.Windows.Forms.PictureBoxSizeMode.CenterImage; this.pictureBoxGalleryLoadingGIF.TabIndex = 3; this.pictureBoxGalleryLoadingGIF.TabStop = false; @@ -4782,7 +4938,7 @@ private void InitializeComponent() | System.Windows.Forms.AnchorStyles.Right))); this.labelGalleryTip.Font = new System.Drawing.Font("Microsoft Sans Serif", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.labelGalleryTip.ForeColor = System.Drawing.SystemColors.ControlDarkDark; - this.labelGalleryTip.Location = new System.Drawing.Point(17, 211); + this.labelGalleryTip.Location = new System.Drawing.Point(18, 197); this.labelGalleryTip.Name = "labelGalleryTip"; this.labelGalleryTip.Size = new System.Drawing.Size(511, 39); this.labelGalleryTip.TabIndex = 2; @@ -4794,10 +4950,11 @@ private void InitializeComponent() this.listViewScreenshots.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); + this.listViewScreenshots.BorderStyle = System.Windows.Forms.BorderStyle.None; this.listViewScreenshots.HideSelection = false; - this.listViewScreenshots.Location = new System.Drawing.Point(6, 19); + this.listViewScreenshots.Location = new System.Drawing.Point(6, 20); this.listViewScreenshots.Name = "listViewScreenshots"; - this.listViewScreenshots.Size = new System.Drawing.Size(534, 427); + this.listViewScreenshots.Size = new System.Drawing.Size(534, 425); this.listViewScreenshots.TabIndex = 1; this.listViewScreenshots.UseCompatibleStateImageBehavior = false; // @@ -4942,56 +5099,229 @@ private void InitializeComponent() this.buttonCustomSave.UseVisualStyleBackColor = true; this.buttonCustomSave.Click += new System.EventHandler(this.buttonCustomSave_Click); // - // comboBoxCustomFile + // comboBoxCustomFile + // + this.comboBoxCustomFile.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.comboBoxCustomFile.FormattingEnabled = true; + this.comboBoxCustomFile.Location = new System.Drawing.Point(204, 6); + this.comboBoxCustomFile.Name = "comboBoxCustomFile"; + this.comboBoxCustomFile.Size = new System.Drawing.Size(188, 21); + this.comboBoxCustomFile.TabIndex = 2; + this.comboBoxCustomFile.SelectedIndexChanged += new System.EventHandler(this.comboBoxCustomFile_SelectedIndexChanged); + // + // labelCustomFile + // + this.labelCustomFile.AutoSize = true; + this.labelCustomFile.Location = new System.Drawing.Point(6, 9); + this.labelCustomFile.Name = "labelCustomFile"; + this.labelCustomFile.Size = new System.Drawing.Size(106, 13); + this.labelCustomFile.TabIndex = 1; + this.labelCustomFile.Text = "Overwrite lines in file:"; + // + // textBoxCustom + // + this.textBoxCustom.AcceptsTab = true; + this.textBoxCustom.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.textBoxCustom.Font = new System.Drawing.Font("Consolas", 11.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.textBoxCustom.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(30)))), ((int)(((byte)(30)))), ((int)(((byte)(30))))); + this.textBoxCustom.Location = new System.Drawing.Point(6, 33); + this.textBoxCustom.Multiline = true; + this.textBoxCustom.Name = "textBoxCustom"; + this.textBoxCustom.ScrollBars = System.Windows.Forms.ScrollBars.Both; + this.textBoxCustom.Size = new System.Drawing.Size(840, 425); + this.textBoxCustom.TabIndex = 0; + this.textBoxCustom.WordWrap = false; + this.textBoxCustom.TextChanged += new System.EventHandler(this.textBoxCustom_TextChanged); + // + // tabPageDangerZone + // + this.tabPageDangerZone.Controls.Add(this.groupBoxVideoDZ); + this.tabPageDangerZone.ForeColor = System.Drawing.Color.Red; + this.tabPageDangerZone.Location = new System.Drawing.Point(4, 22); + this.tabPageDangerZone.Name = "tabPageDangerZone"; + this.tabPageDangerZone.Padding = new System.Windows.Forms.Padding(3); + this.tabPageDangerZone.Size = new System.Drawing.Size(852, 464); + this.tabPageDangerZone.TabIndex = 11; + this.tabPageDangerZone.Text = "⚠️ Danger Zone"; + this.tabPageDangerZone.UseVisualStyleBackColor = true; + // + // groupBoxVideoDZ + // + this.groupBoxVideoDZ.Controls.Add(this.groupBoxShadows2); + this.groupBoxVideoDZ.Controls.Add(this.groupBox4); + this.groupBoxVideoDZ.ForeColor = System.Drawing.Color.Red; + this.groupBoxVideoDZ.Location = new System.Drawing.Point(6, 6); + this.groupBoxVideoDZ.Name = "groupBoxVideoDZ"; + this.groupBoxVideoDZ.Size = new System.Drawing.Size(381, 245); + this.groupBoxVideoDZ.TabIndex = 41; + this.groupBoxVideoDZ.TabStop = false; + this.groupBoxVideoDZ.Text = "⚠️ Video"; + // + // groupBoxShadows2 + // + this.groupBoxShadows2.Controls.Add(this.labeliDirShadowSplits); + this.groupBoxShadows2.Controls.Add(this.comboBoxiDirShadowSplits); + this.groupBoxShadows2.Controls.Add(this.sliderfBlendSplitDirShadow); + this.groupBoxShadows2.Controls.Add(this.labelfBlendSplitDirShadow); + this.groupBoxShadows2.Controls.Add(this.numfBlendSplitDirShadow); + this.groupBoxShadows2.ForeColor = System.Drawing.Color.Red; + this.groupBoxShadows2.Location = new System.Drawing.Point(10, 19); + this.groupBoxShadows2.Name = "groupBoxShadows2"; + this.groupBoxShadows2.Size = new System.Drawing.Size(359, 140); + this.groupBoxShadows2.TabIndex = 40; + this.groupBoxShadows2.TabStop = false; + this.groupBoxShadows2.Text = "Shadows"; + // + // comboBoxiDirShadowSplits + // + this.comboBoxiDirShadowSplits.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.comboBoxiDirShadowSplits.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.comboBoxiDirShadowSplits.FormattingEnabled = true; + this.comboBoxiDirShadowSplits.Location = new System.Drawing.Point(195, 21); + this.comboBoxiDirShadowSplits.Name = "comboBoxiDirShadowSplits"; + this.comboBoxiDirShadowSplits.Size = new System.Drawing.Size(154, 21); + this.comboBoxiDirShadowSplits.TabIndex = 34; + // + // labelfBlendSplitDirShadow + // + this.labelfBlendSplitDirShadow.AutoSize = true; + this.labelfBlendSplitDirShadow.ForeColor = System.Drawing.SystemColors.ControlText; + this.labelfBlendSplitDirShadow.Location = new System.Drawing.Point(11, 59); + this.labelfBlendSplitDirShadow.Name = "labelfBlendSplitDirShadow"; + this.labelfBlendSplitDirShadow.Size = new System.Drawing.Size(187, 13); + this.labelfBlendSplitDirShadow.TabIndex = 37; + this.labelfBlendSplitDirShadow.Text = "Shadow \"segment\" transition distance"; + // + // numfBlendSplitDirShadow + // + this.numfBlendSplitDirShadow.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.numfBlendSplitDirShadow.Increment = new decimal(new int[] { + 1000, + 0, + 0, + 0}); + this.numfBlendSplitDirShadow.Location = new System.Drawing.Point(275, 76); + this.numfBlendSplitDirShadow.Maximum = new decimal(new int[] { + 9999999, + 0, + 0, + 0}); + this.numfBlendSplitDirShadow.Name = "numfBlendSplitDirShadow"; + this.numfBlendSplitDirShadow.Size = new System.Drawing.Size(74, 20); + this.numfBlendSplitDirShadow.TabIndex = 38; + this.numfBlendSplitDirShadow.Value = new decimal(new int[] { + 48, + 0, + 0, + 0}); + // + // groupBox4 + // + this.groupBox4.Controls.Add(this.checkBoxScreenSpaceReflections); + this.groupBox4.ForeColor = System.Drawing.Color.Red; + this.groupBox4.Location = new System.Drawing.Point(10, 164); + this.groupBox4.Name = "groupBox4"; + this.groupBox4.Size = new System.Drawing.Size(359, 67); + this.groupBox4.TabIndex = 39; + this.groupBox4.TabStop = false; + this.groupBox4.Text = "Water"; + // + // backgroundWorkerLoadGallery + // + this.backgroundWorkerLoadGallery.DoWork += new System.ComponentModel.DoWorkEventHandler(this.backgroundWorkerLoadGallery_DoWork); + // + // backgroundWorkerGetLatestVersion + // + this.backgroundWorkerGetLatestVersion.DoWork += new System.ComponentModel.DoWorkEventHandler(this.backgroundWorkerGetLatestVersion_DoWork); + // + // contextMenuStripGallery + // + this.contextMenuStripGallery.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.openToolStripMenuItem, + this.openFolderToolStripMenuItem, + this.toolStripSeparator7, + this.cutToolStripMenuItem, + this.copyToolStripMenuItem, + this.toolStripSeparator8, + this.deleteToolStripMenuItem}); + this.contextMenuStripGallery.Name = "contextMenuStrip1"; + this.contextMenuStripGallery.Size = new System.Drawing.Size(138, 126); + // + // openToolStripMenuItem + // + this.openToolStripMenuItem.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.openToolStripMenuItem.Name = "openToolStripMenuItem"; + this.openToolStripMenuItem.Size = new System.Drawing.Size(137, 22); + this.openToolStripMenuItem.Text = "Open"; + this.openToolStripMenuItem.Click += new System.EventHandler(this.openToolStripMenuItem_Click); + // + // openFolderToolStripMenuItem + // + this.openFolderToolStripMenuItem.Name = "openFolderToolStripMenuItem"; + this.openFolderToolStripMenuItem.Size = new System.Drawing.Size(137, 22); + this.openFolderToolStripMenuItem.Text = "Open folder"; + this.openFolderToolStripMenuItem.Click += new System.EventHandler(this.openFolderToolStripMenuItem_Click); + // + // toolStripSeparator7 + // + this.toolStripSeparator7.Name = "toolStripSeparator7"; + this.toolStripSeparator7.Size = new System.Drawing.Size(134, 6); + // + // cutToolStripMenuItem + // + this.cutToolStripMenuItem.Name = "cutToolStripMenuItem"; + this.cutToolStripMenuItem.Size = new System.Drawing.Size(137, 22); + this.cutToolStripMenuItem.Text = "Cut"; + this.cutToolStripMenuItem.Click += new System.EventHandler(this.cutToolStripMenuItem_Click); + // + // copyToolStripMenuItem + // + this.copyToolStripMenuItem.Name = "copyToolStripMenuItem"; + this.copyToolStripMenuItem.Size = new System.Drawing.Size(137, 22); + this.copyToolStripMenuItem.Text = "Copy"; + this.copyToolStripMenuItem.Click += new System.EventHandler(this.copyToolStripMenuItem_Click); + // + // toolStripSeparator8 // - this.comboBoxCustomFile.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; - this.comboBoxCustomFile.FormattingEnabled = true; - this.comboBoxCustomFile.Location = new System.Drawing.Point(204, 6); - this.comboBoxCustomFile.Name = "comboBoxCustomFile"; - this.comboBoxCustomFile.Size = new System.Drawing.Size(188, 21); - this.comboBoxCustomFile.TabIndex = 2; - this.comboBoxCustomFile.SelectedIndexChanged += new System.EventHandler(this.comboBoxCustomFile_SelectedIndexChanged); + this.toolStripSeparator8.Name = "toolStripSeparator8"; + this.toolStripSeparator8.Size = new System.Drawing.Size(134, 6); // - // labelCustomFile + // deleteToolStripMenuItem // - this.labelCustomFile.AutoSize = true; - this.labelCustomFile.Location = new System.Drawing.Point(6, 9); - this.labelCustomFile.Name = "labelCustomFile"; - this.labelCustomFile.Size = new System.Drawing.Size(106, 13); - this.labelCustomFile.TabIndex = 1; - this.labelCustomFile.Text = "Overwrite lines in file:"; + this.deleteToolStripMenuItem.Name = "deleteToolStripMenuItem"; + this.deleteToolStripMenuItem.Size = new System.Drawing.Size(137, 22); + this.deleteToolStripMenuItem.Text = "Delete"; + this.deleteToolStripMenuItem.Click += new System.EventHandler(this.deleteToolStripMenuItem_Click); // - // textBoxCustom + // toolStripSeparator3 // - this.textBoxCustom.AcceptsTab = true; - this.textBoxCustom.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) - | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.textBoxCustom.Font = new System.Drawing.Font("Consolas", 11.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.textBoxCustom.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(30)))), ((int)(((byte)(30)))), ((int)(((byte)(30))))); - this.textBoxCustom.Location = new System.Drawing.Point(6, 33); - this.textBoxCustom.Multiline = true; - this.textBoxCustom.Name = "textBoxCustom"; - this.textBoxCustom.ScrollBars = System.Windows.Forms.ScrollBars.Both; - this.textBoxCustom.Size = new System.Drawing.Size(840, 425); - this.textBoxCustom.TabIndex = 0; - this.textBoxCustom.WordWrap = false; - this.textBoxCustom.TextChanged += new System.EventHandler(this.textBoxCustom_TextChanged); + this.toolStripSeparator3.Margin = new System.Windows.Forms.Padding(10, 0, 10, 0); + this.toolStripSeparator3.Name = "toolStripSeparator3"; + this.toolStripSeparator3.Padding = new System.Windows.Forms.Padding(10, 0, 10, 0); + this.toolStripSeparator3.Size = new System.Drawing.Size(6, 46); + // + // toolStripSeparator9 + // + this.toolStripSeparator9.Margin = new System.Windows.Forms.Padding(10, 0, 10, 0); + this.toolStripSeparator9.Name = "toolStripSeparator9"; + this.toolStripSeparator9.Size = new System.Drawing.Size(6, 46); // // toolStrip1 // this.toolStrip1.GripStyle = System.Windows.Forms.ToolStripGripStyle.Hidden; this.toolStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { this.toolStripButtonApply, - this.toolStripButtonToggleNuclearWinterMode, - this.toolStripSplitButtonLaunchGame, - this.toolStripSeparator1, + this.toolStripButtonLaunchGame, + this.toolStripSeparator3, this.toolStripButtonManageMods, - this.toolStripSeparator2, + this.toolStripButtonToggleNuclearWinterMode, + this.toolStripSeparator9, + this.toolStripButtonSettings, this.toolStripSplitButtonUpdate, - this.toolStripDropDownButtonExplore, - this.toolStripSeparator3, - this.toolStripButtonNexusMods}); + this.toolStripDropDownButtonExplore}); this.toolStrip1.Location = new System.Drawing.Point(0, 0); this.toolStrip1.Name = "toolStrip1"; this.toolStrip1.Padding = new System.Windows.Forms.Padding(5, 5, 1, 5); @@ -5011,61 +5341,17 @@ private void InitializeComponent() this.toolStripButtonApply.TextImageRelation = System.Windows.Forms.TextImageRelation.ImageAboveText; this.toolStripButtonApply.Click += new System.EventHandler(this.toolStripButtonApply_Click); // - // toolStripButtonToggleNuclearWinterMode - // - this.toolStripButtonToggleNuclearWinterMode.Image = global::Fo76ini.Properties.Resources.fire; - this.toolStripButtonToggleNuclearWinterMode.ImageScaling = System.Windows.Forms.ToolStripItemImageScaling.None; - this.toolStripButtonToggleNuclearWinterMode.ImageTransparentColor = System.Drawing.Color.Magenta; - this.toolStripButtonToggleNuclearWinterMode.Name = "toolStripButtonToggleNuclearWinterMode"; - this.toolStripButtonToggleNuclearWinterMode.Padding = new System.Windows.Forms.Padding(10, 0, 10, 0); - this.toolStripButtonToggleNuclearWinterMode.Size = new System.Drawing.Size(110, 43); - this.toolStripButtonToggleNuclearWinterMode.Text = "Nuclear Winter"; - this.toolStripButtonToggleNuclearWinterMode.TextImageRelation = System.Windows.Forms.TextImageRelation.ImageAboveText; - this.toolStripButtonToggleNuclearWinterMode.Click += new System.EventHandler(this.toolStripButtonToggleNuclearWinterMode_Click); - // - // toolStripSplitButtonLaunchGame - // - this.toolStripSplitButtonLaunchGame.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.launchViaSteamToolStripMenuItem, - this.launchViaBethesdanetToolStripMenuItem, - this.launchViaBethesdanetPTSToolStripMenuItem}); - this.toolStripSplitButtonLaunchGame.Image = global::Fo76ini.Properties.Resources.play; - this.toolStripSplitButtonLaunchGame.ImageScaling = System.Windows.Forms.ToolStripItemImageScaling.None; - this.toolStripSplitButtonLaunchGame.ImageTransparentColor = System.Drawing.Color.Magenta; - this.toolStripSplitButtonLaunchGame.Name = "toolStripSplitButtonLaunchGame"; - this.toolStripSplitButtonLaunchGame.Padding = new System.Windows.Forms.Padding(20, 0, 20, 0); - this.toolStripSplitButtonLaunchGame.Size = new System.Drawing.Size(102, 43); - this.toolStripSplitButtonLaunchGame.Text = "Launch"; - this.toolStripSplitButtonLaunchGame.TextImageRelation = System.Windows.Forms.TextImageRelation.ImageAboveText; - this.toolStripSplitButtonLaunchGame.ButtonClick += new System.EventHandler(this.toolStripSplitButtonLaunchGame_ButtonClick); - // - // launchViaSteamToolStripMenuItem - // - this.launchViaSteamToolStripMenuItem.Name = "launchViaSteamToolStripMenuItem"; - this.launchViaSteamToolStripMenuItem.Size = new System.Drawing.Size(255, 22); - this.launchViaSteamToolStripMenuItem.Text = "Launch Steam version"; - this.launchViaSteamToolStripMenuItem.Click += new System.EventHandler(this.launchViaSteamToolStripMenuItem_Click); + // toolStripButtonLaunchGame // - // launchViaBethesdanetToolStripMenuItem - // - this.launchViaBethesdanetToolStripMenuItem.Name = "launchViaBethesdanetToolStripMenuItem"; - this.launchViaBethesdanetToolStripMenuItem.Size = new System.Drawing.Size(255, 22); - this.launchViaBethesdanetToolStripMenuItem.Text = "Launch Bethesda.net version"; - this.launchViaBethesdanetToolStripMenuItem.Click += new System.EventHandler(this.launchViaBethesdanetToolStripMenuItem_Click); - // - // launchViaBethesdanetPTSToolStripMenuItem - // - this.launchViaBethesdanetPTSToolStripMenuItem.Name = "launchViaBethesdanetPTSToolStripMenuItem"; - this.launchViaBethesdanetPTSToolStripMenuItem.Size = new System.Drawing.Size(255, 22); - this.launchViaBethesdanetPTSToolStripMenuItem.Text = "Launch Bethesda.net (PTS) version"; - this.launchViaBethesdanetPTSToolStripMenuItem.Click += new System.EventHandler(this.launchViaBethesdanetPTSToolStripMenuItem_Click); - // - // toolStripSeparator1 - // - this.toolStripSeparator1.Margin = new System.Windows.Forms.Padding(10, 0, 10, 0); - this.toolStripSeparator1.Name = "toolStripSeparator1"; - this.toolStripSeparator1.Padding = new System.Windows.Forms.Padding(10, 0, 10, 0); - this.toolStripSeparator1.Size = new System.Drawing.Size(6, 46); + this.toolStripButtonLaunchGame.Image = global::Fo76ini.Properties.Resources.play; + this.toolStripButtonLaunchGame.ImageScaling = System.Windows.Forms.ToolStripItemImageScaling.None; + this.toolStripButtonLaunchGame.ImageTransparentColor = System.Drawing.Color.Magenta; + this.toolStripButtonLaunchGame.Name = "toolStripButtonLaunchGame"; + this.toolStripButtonLaunchGame.Padding = new System.Windows.Forms.Padding(20, 0, 20, 0); + this.toolStripButtonLaunchGame.Size = new System.Drawing.Size(90, 43); + this.toolStripButtonLaunchGame.Text = "Launch"; + this.toolStripButtonLaunchGame.TextImageRelation = System.Windows.Forms.TextImageRelation.ImageAboveText; + this.toolStripButtonLaunchGame.Click += new System.EventHandler(this.toolStripButtonLaunchGame_Click); // // toolStripButtonManageMods // @@ -5079,18 +5365,35 @@ private void InitializeComponent() this.toolStripButtonManageMods.TextImageRelation = System.Windows.Forms.TextImageRelation.ImageAboveText; this.toolStripButtonManageMods.Click += new System.EventHandler(this.toolStripButtonManageMods_Click); // - // toolStripSeparator2 + // toolStripButtonToggleNuclearWinterMode + // + this.toolStripButtonToggleNuclearWinterMode.Image = global::Fo76ini.Properties.Resources.fire; + this.toolStripButtonToggleNuclearWinterMode.ImageScaling = System.Windows.Forms.ToolStripItemImageScaling.None; + this.toolStripButtonToggleNuclearWinterMode.ImageTransparentColor = System.Drawing.Color.Magenta; + this.toolStripButtonToggleNuclearWinterMode.Name = "toolStripButtonToggleNuclearWinterMode"; + this.toolStripButtonToggleNuclearWinterMode.Padding = new System.Windows.Forms.Padding(10, 0, 10, 0); + this.toolStripButtonToggleNuclearWinterMode.Size = new System.Drawing.Size(110, 43); + this.toolStripButtonToggleNuclearWinterMode.Text = "Nuclear Winter"; + this.toolStripButtonToggleNuclearWinterMode.TextImageRelation = System.Windows.Forms.TextImageRelation.ImageAboveText; + this.toolStripButtonToggleNuclearWinterMode.Click += new System.EventHandler(this.toolStripButtonToggleNuclearWinterMode_Click); + // + // toolStripButtonSettings // - this.toolStripSeparator2.Margin = new System.Windows.Forms.Padding(10, 0, 10, 0); - this.toolStripSeparator2.Name = "toolStripSeparator2"; - this.toolStripSeparator2.Size = new System.Drawing.Size(6, 46); + this.toolStripButtonSettings.Image = global::Fo76ini.Properties.Resources.cog_24; + this.toolStripButtonSettings.ImageScaling = System.Windows.Forms.ToolStripItemImageScaling.None; + this.toolStripButtonSettings.ImageTransparentColor = System.Drawing.Color.Magenta; + this.toolStripButtonSettings.Name = "toolStripButtonSettings"; + this.toolStripButtonSettings.Padding = new System.Windows.Forms.Padding(20, 0, 20, 0); + this.toolStripButtonSettings.Size = new System.Drawing.Size(93, 43); + this.toolStripButtonSettings.Text = "Settings"; + this.toolStripButtonSettings.TextImageRelation = System.Windows.Forms.TextImageRelation.ImageAboveText; + this.toolStripButtonSettings.Click += new System.EventHandler(this.showSettings_OnClick); // // toolStripSplitButtonUpdate // this.toolStripSplitButtonUpdate.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { this.updateToolToolStripMenuItem, this.checkForUpdatesToolStripMenuItem, - this.downloadUpdateLanguageFilesToolStripMenuItem, this.showUpdaterlogtxtToolStripMenuItem}); this.toolStripSplitButtonUpdate.Image = global::Fo76ini.Properties.Resources.available_updates; this.toolStripSplitButtonUpdate.ImageScaling = System.Windows.Forms.ToolStripItemImageScaling.None; @@ -5105,28 +5408,21 @@ private void InitializeComponent() // updateToolToolStripMenuItem // this.updateToolToolStripMenuItem.Name = "updateToolToolStripMenuItem"; - this.updateToolToolStripMenuItem.Size = new System.Drawing.Size(252, 22); + this.updateToolToolStripMenuItem.Size = new System.Drawing.Size(180, 22); this.updateToolToolStripMenuItem.Text = "Update tool"; this.updateToolToolStripMenuItem.Click += new System.EventHandler(this.buttonUpdateNow_Click); // // checkForUpdatesToolStripMenuItem // this.checkForUpdatesToolStripMenuItem.Name = "checkForUpdatesToolStripMenuItem"; - this.checkForUpdatesToolStripMenuItem.Size = new System.Drawing.Size(252, 22); + this.checkForUpdatesToolStripMenuItem.Size = new System.Drawing.Size(180, 22); this.checkForUpdatesToolStripMenuItem.Text = "Check for updates"; this.checkForUpdatesToolStripMenuItem.Click += new System.EventHandler(this.checkForUpdatesToolStripMenuItem_Click); // - // downloadUpdateLanguageFilesToolStripMenuItem - // - this.downloadUpdateLanguageFilesToolStripMenuItem.Name = "downloadUpdateLanguageFilesToolStripMenuItem"; - this.downloadUpdateLanguageFilesToolStripMenuItem.Size = new System.Drawing.Size(252, 22); - this.downloadUpdateLanguageFilesToolStripMenuItem.Text = "Download / update language files"; - this.downloadUpdateLanguageFilesToolStripMenuItem.Click += new System.EventHandler(this.buttonDownloadLanguages_Click); - // // showUpdaterlogtxtToolStripMenuItem // this.showUpdaterlogtxtToolStripMenuItem.Name = "showUpdaterlogtxtToolStripMenuItem"; - this.showUpdaterlogtxtToolStripMenuItem.Size = new System.Drawing.Size(252, 22); + this.showUpdaterlogtxtToolStripMenuItem.Size = new System.Drawing.Size(180, 22); this.showUpdaterlogtxtToolStripMenuItem.Text = "Show update.log.txt"; this.showUpdaterlogtxtToolStripMenuItem.Click += new System.EventHandler(this.showUpdaterlogtxtToolStripMenuItem_Click); // @@ -5240,102 +5536,62 @@ private void InitializeComponent() this.editFallout76CustominiToolStripMenuItem.Text = "Edit Fallout76Custom.ini"; this.editFallout76CustominiToolStripMenuItem.Click += new System.EventHandler(this.editFallout76CustominiToolStripMenuItem_Click); // - // toolStripSeparator3 - // - this.toolStripSeparator3.Margin = new System.Windows.Forms.Padding(10, 0, 10, 0); - this.toolStripSeparator3.Name = "toolStripSeparator3"; - this.toolStripSeparator3.Size = new System.Drawing.Size(6, 46); - // - // toolStripButtonNexusMods - // - this.toolStripButtonNexusMods.Image = global::Fo76ini.Properties.Resources.nexus_24; - this.toolStripButtonNexusMods.ImageScaling = System.Windows.Forms.ToolStripItemImageScaling.None; - this.toolStripButtonNexusMods.ImageTransparentColor = System.Drawing.Color.Magenta; - this.toolStripButtonNexusMods.Name = "toolStripButtonNexusMods"; - this.toolStripButtonNexusMods.Padding = new System.Windows.Forms.Padding(10, 0, 10, 0); - this.toolStripButtonNexusMods.Size = new System.Drawing.Size(94, 43); - this.toolStripButtonNexusMods.Text = "NexusMods"; - this.toolStripButtonNexusMods.TextImageRelation = System.Windows.Forms.TextImageRelation.ImageAboveText; - this.toolStripButtonNexusMods.Click += new System.EventHandler(this.toolStripButtonNexusMods_Click); - // - // backgroundWorkerLoadGallery - // - this.backgroundWorkerLoadGallery.DoWork += new System.ComponentModel.DoWorkEventHandler(this.backgroundWorkerLoadGallery_DoWork); - // - // backgroundWorkerGetLatestVersion - // - this.backgroundWorkerGetLatestVersion.DoWork += new System.ComponentModel.DoWorkEventHandler(this.backgroundWorkerGetLatestVersion_DoWork); - // - // backgroundWorkerDownloadLanguages - // - this.backgroundWorkerDownloadLanguages.DoWork += new System.ComponentModel.DoWorkEventHandler(this.backgroundWorkerDownloadLanguages_DoWork); - // - // contextMenuStripGallery - // - this.contextMenuStripGallery.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.openToolStripMenuItem, - this.openFolderToolStripMenuItem, - this.toolStripSeparator7, - this.cutToolStripMenuItem, - this.copyToolStripMenuItem, - this.toolStripSeparator8, - this.deleteToolStripMenuItem}); - this.contextMenuStripGallery.Name = "contextMenuStrip1"; - this.contextMenuStripGallery.Size = new System.Drawing.Size(138, 126); - // - // openToolStripMenuItem - // - this.openToolStripMenuItem.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.openToolStripMenuItem.Name = "openToolStripMenuItem"; - this.openToolStripMenuItem.Size = new System.Drawing.Size(137, 22); - this.openToolStripMenuItem.Text = "Open"; - this.openToolStripMenuItem.Click += new System.EventHandler(this.openToolStripMenuItem_Click); - // - // openFolderToolStripMenuItem - // - this.openFolderToolStripMenuItem.Name = "openFolderToolStripMenuItem"; - this.openFolderToolStripMenuItem.Size = new System.Drawing.Size(137, 22); - this.openFolderToolStripMenuItem.Text = "Open folder"; - this.openFolderToolStripMenuItem.Click += new System.EventHandler(this.openFolderToolStripMenuItem_Click); - // - // toolStripSeparator7 + // statusStrip1 // - this.toolStripSeparator7.Name = "toolStripSeparator7"; - this.toolStripSeparator7.Size = new System.Drawing.Size(134, 6); + this.statusStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.toolStripStatusLabelGame, + this.toolStripStatusLabelGameText, + this.toolStripStatusLabelEdition, + this.toolStripStatusLabelEditionText, + this.toolStripStatusLabel1, + this.toolStripStatusLabelNuclearWinterModeActive}); + this.statusStrip1.Location = new System.Drawing.Point(0, 559); + this.statusStrip1.Name = "statusStrip1"; + this.statusStrip1.Size = new System.Drawing.Size(884, 22); + this.statusStrip1.TabIndex = 16; + this.statusStrip1.Text = "statusStrip1"; // - // cutToolStripMenuItem + // toolStripStatusLabelGame // - this.cutToolStripMenuItem.Name = "cutToolStripMenuItem"; - this.cutToolStripMenuItem.Size = new System.Drawing.Size(137, 22); - this.cutToolStripMenuItem.Text = "Cut"; - this.cutToolStripMenuItem.Click += new System.EventHandler(this.cutToolStripMenuItem_Click); + this.toolStripStatusLabelGame.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.toolStripStatusLabelGame.Margin = new System.Windows.Forms.Padding(10, 3, 0, 2); + this.toolStripStatusLabelGame.Name = "toolStripStatusLabelGame"; + this.toolStripStatusLabelGame.Size = new System.Drawing.Size(83, 17); + this.toolStripStatusLabelGame.Text = "Game profile:"; // - // copyToolStripMenuItem + // toolStripStatusLabelGameText // - this.copyToolStripMenuItem.Name = "copyToolStripMenuItem"; - this.copyToolStripMenuItem.Size = new System.Drawing.Size(137, 22); - this.copyToolStripMenuItem.Text = "Copy"; - this.copyToolStripMenuItem.Click += new System.EventHandler(this.copyToolStripMenuItem_Click); + this.toolStripStatusLabelGameText.Name = "toolStripStatusLabelGameText"; + this.toolStripStatusLabelGameText.Size = new System.Drawing.Size(12, 17); + this.toolStripStatusLabelGameText.Text = "?"; // - // toolStripSeparator8 + // toolStripStatusLabelEdition // - this.toolStripSeparator8.Name = "toolStripSeparator8"; - this.toolStripSeparator8.Size = new System.Drawing.Size(134, 6); + this.toolStripStatusLabelEdition.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.toolStripStatusLabelEdition.Margin = new System.Windows.Forms.Padding(30, 3, 0, 2); + this.toolStripStatusLabelEdition.Name = "toolStripStatusLabelEdition"; + this.toolStripStatusLabelEdition.Size = new System.Drawing.Size(48, 17); + this.toolStripStatusLabelEdition.Text = "Edition:"; // - // deleteToolStripMenuItem + // toolStripStatusLabelEditionText // - this.deleteToolStripMenuItem.Name = "deleteToolStripMenuItem"; - this.deleteToolStripMenuItem.Size = new System.Drawing.Size(137, 22); - this.deleteToolStripMenuItem.Text = "Delete"; - this.deleteToolStripMenuItem.Click += new System.EventHandler(this.deleteToolStripMenuItem_Click); + this.toolStripStatusLabelEditionText.Name = "toolStripStatusLabelEditionText"; + this.toolStripStatusLabelEditionText.Size = new System.Drawing.Size(12, 17); + this.toolStripStatusLabelEditionText.Text = "?"; // - // backgroundWorkerEnableNWMode + // toolStripStatusLabel1 // - this.backgroundWorkerEnableNWMode.DoWork += new System.ComponentModel.DoWorkEventHandler(this.backgroundWorkerEnableNWMode_DoWork); + this.toolStripStatusLabel1.Name = "toolStripStatusLabel1"; + this.toolStripStatusLabel1.Size = new System.Drawing.Size(499, 17); + this.toolStripStatusLabel1.Spring = true; // - // backgroundWorkerDisableNWMode + // toolStripStatusLabelNuclearWinterModeActive // - this.backgroundWorkerDisableNWMode.DoWork += new System.ComponentModel.DoWorkEventHandler(this.backgroundWorkerDisableNWMode_DoWork); + this.toolStripStatusLabelNuclearWinterModeActive.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.toolStripStatusLabelNuclearWinterModeActive.ForeColor = System.Drawing.Color.OrangeRed; + this.toolStripStatusLabelNuclearWinterModeActive.Name = "toolStripStatusLabelNuclearWinterModeActive"; + this.toolStripStatusLabelNuclearWinterModeActive.Size = new System.Drawing.Size(175, 17); + this.toolStripStatusLabelNuclearWinterModeActive.Text = "Nuclear Winter mode is active"; // // pictureBoxLoadingGIF // @@ -5346,7 +5602,7 @@ private void InitializeComponent() this.pictureBoxLoadingGIF.Image = global::Fo76ini.Properties.Resources.Spinner_200; this.pictureBoxLoadingGIF.Location = new System.Drawing.Point(0, 0); this.pictureBoxLoadingGIF.Name = "pictureBoxLoadingGIF"; - this.pictureBoxLoadingGIF.Size = new System.Drawing.Size(16, 563); + this.pictureBoxLoadingGIF.Size = new System.Drawing.Size(16, 583); this.pictureBoxLoadingGIF.SizeMode = System.Windows.Forms.PictureBoxSizeMode.CenterImage; this.pictureBoxLoadingGIF.TabIndex = 15; this.pictureBoxLoadingGIF.TabStop = false; @@ -5356,14 +5612,16 @@ private void InitializeComponent() // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(884, 561); + this.ClientSize = new System.Drawing.Size(884, 581); + this.Controls.Add(this.statusStrip1); this.Controls.Add(this.pictureBoxLoadingGIF); this.Controls.Add(this.toolStrip1); this.Controls.Add(this.tabControl1); this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); this.KeyPreview = true; - this.MinimumSize = new System.Drawing.Size(900, 600); + this.MinimumSize = new System.Drawing.Size(900, 620); this.Name = "Form1"; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; this.Text = "Fallout 76 Quick Configuration"; this.Load += new System.EventHandler(this.Form1_Load); ((System.ComponentModel.ISupportInitialize)(this.numPipboyTargetWidth)).EndInit(); @@ -5392,6 +5650,45 @@ private void InitializeComponent() ((System.ComponentModel.ISupportInitialize)(this.sliderHUDOpacity)).EndInit(); ((System.ComponentModel.ISupportInitialize)(this.sliderfBlendSplitDirShadow)).EndInit(); this.tabPageCamera.ResumeLayout(false); + this.panel2.ResumeLayout(false); + this.groupBoxCameraPosition.ResumeLayout(false); + this.groupBoxCameraPosition.PerformLayout(); + this.groupBox3.ResumeLayout(false); + this.groupBox3.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.numfOverShoulderMeleeCombatAddY)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.numfOverShoulderMeleeCombatPosX)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.numfOverShoulderMeleeCombatPosZ)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.trackBarfOverShoulderMeleeCombatAddY)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.trackBarfOverShoulderMeleeCombatPosX)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.trackBarfOverShoulderMeleeCombatPosZ)).EndInit(); + this.groupBox2.ResumeLayout(false); + this.groupBox2.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.numfOverShoulderCombatAddY)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.numfOverShoulderCombatPosX)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.numfOverShoulderCombatPosZ)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.trackBarfOverShoulderCombatAddY)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.trackBarfOverShoulderCombatPosX)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.trackBarfOverShoulderCombatPosZ)).EndInit(); + this.groupBoxUnarmedCameraPosition.ResumeLayout(false); + this.groupBoxUnarmedCameraPosition.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.numfOverShoulderPosX)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.numfOverShoulderPosZ)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.trackBarfOverShoulderPosX)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.trackBarfOverShoulderPosZ)).EndInit(); + this.groupBoxSelfieCamera.ResumeLayout(false); + this.groupBoxSelfieCamera.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.trackBarPhotomodeRange)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.numericUpDownPhotomodeRotationSpeed)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.trackBarPhotomodeRotationSpeed)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.numericUpDownPhotomodeRange)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.numericUpDownPhotomodeTranslationSpeed)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.trackBarPhotomodeTranslationSpeed)).EndInit(); + this.groupBoxFieldOfView.ResumeLayout(false); + this.groupBoxFieldOfView.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.numfDefaultFOV)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.numADSFOV)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.numWorldFOV)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.numFirstPersonFOV)).EndInit(); this.groupBoxCameraOptions.ResumeLayout(false); this.groupBoxCameraOptions.PerformLayout(); ((System.ComponentModel.ISupportInitialize)(this.numCameraSwitchDelay)).EndInit(); @@ -5403,30 +5700,25 @@ private void InitializeComponent() ((System.ComponentModel.ISupportInitialize)(this.numCameraDistanceMinimum)).EndInit(); ((System.ComponentModel.ISupportInitialize)(this.sliderCameraDistanceMaximum)).EndInit(); ((System.ComponentModel.ISupportInitialize)(this.sliderCameraDistanceMinimum)).EndInit(); - this.groupBoxCameraPositionWIP.ResumeLayout(false); - this.groupBoxCameraPositionWIP.PerformLayout(); - ((System.ComponentModel.ISupportInitialize)(this.trackBarCameraX)).EndInit(); - ((System.ComponentModel.ISupportInitialize)(this.trackBarCameraZ)).EndInit(); - ((System.ComponentModel.ISupportInitialize)(this.trackBarCameraY)).EndInit(); - ((System.ComponentModel.ISupportInitialize)(this.pictureBoxVaultBoy)).EndInit(); - this.groupBoxFieldOfView.ResumeLayout(false); - this.groupBoxFieldOfView.PerformLayout(); - ((System.ComponentModel.ISupportInitialize)(this.numfDefaultFOV)).EndInit(); - ((System.ComponentModel.ISupportInitialize)(this.numADSFOV)).EndInit(); - ((System.ComponentModel.ISupportInitialize)(this.numWorldFOV)).EndInit(); - ((System.ComponentModel.ISupportInitialize)(this.numFirstPersonFOV)).EndInit(); - this.groupBoxCameraVanity.ResumeLayout(false); - this.groupBoxCameraVanity.PerformLayout(); this.tabPagePipBoy.ResumeLayout(false); + this.groupBoxPipboyColorPresets.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)(this.colorPreviewPresetFo76Green)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.colorPreviewPresetFo3Green)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.colorPreviewPresetFo3White)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.colorPreviewPresetFoNVAmber)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.colorPreviewPresetFo3Blue)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.colorPreviewPresetFo4Green)).EndInit(); + this.groupBoxPipboyColorPreview.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)(this.pictureBoxPipboyPreview)).EndInit(); this.groupBoxPipboyResolution.ResumeLayout(false); this.groupBoxPipboyResolution.PerformLayout(); this.groupBoxPipboyMode.ResumeLayout(false); this.groupBoxPipboyMode.PerformLayout(); this.groupBoxPipboyColors.ResumeLayout(false); this.groupBoxPipboyColors.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.colorPreviewQuickboy)).EndInit(); ((System.ComponentModel.ISupportInitialize)(this.colorPreviewPAPipboy)).EndInit(); ((System.ComponentModel.ISupportInitialize)(this.colorPreviewPipboy)).EndInit(); - ((System.ComponentModel.ISupportInitialize)(this.colorPreviewQuickboy)).EndInit(); this.tabPageControls.ResumeLayout(false); this.groupBoxGamepad.ResumeLayout(false); this.groupBoxGamepad.PerformLayout(); @@ -5437,6 +5729,8 @@ private void InitializeComponent() this.panel3.ResumeLayout(false); this.groupBoxGraphics.ResumeLayout(false); this.groupBoxGraphics.PerformLayout(); + this.groupBoxGraphicEffects.ResumeLayout(false); + this.groupBoxGraphicEffects.PerformLayout(); this.groupBoxTAASharpening.ResumeLayout(false); this.groupBoxTAASharpening.PerformLayout(); ((System.ComponentModel.ISupportInitialize)(this.numTAAPostSharpen)).EndInit(); @@ -5453,7 +5747,6 @@ private void InitializeComponent() this.groupBoxLighting.PerformLayout(); this.groupBoxShadows.ResumeLayout(false); this.groupBoxShadows.PerformLayout(); - ((System.ComponentModel.ISupportInitialize)(this.numfBlendSplitDirShadow)).EndInit(); ((System.ComponentModel.ISupportInitialize)(this.numShadowDistance)).EndInit(); this.groupBoxWater.ResumeLayout(false); this.groupBoxWater.PerformLayout(); @@ -5475,32 +5768,15 @@ private void InitializeComponent() this.groupBoxMainMenu.PerformLayout(); this.groupBoxLogin.ResumeLayout(false); this.groupBoxLogin.PerformLayout(); + this.groupBoxLoginProfiles.ResumeLayout(false); + this.groupBoxLoginProfiles.PerformLayout(); this.tabPageInfo.ResumeLayout(false); this.tabPageInfo.PerformLayout(); + this.groupBoxSettings.ResumeLayout(false); this.panelUpdate.ResumeLayout(false); this.panelUpdate.PerformLayout(); ((System.ComponentModel.ISupportInitialize)(this.pictureBoxUpdateButton)).EndInit(); ((System.ComponentModel.ISupportInitialize)(this.pictureBoxSpinnerCheckForUpdates)).EndInit(); - this.panel1.ResumeLayout(false); - this.groupBoxNuclearWinterMode.ResumeLayout(false); - this.groupBoxNuclearWinterMode.PerformLayout(); - this.groupBoxLocalization.ResumeLayout(false); - this.groupBoxLocalization.PerformLayout(); - ((System.ComponentModel.ISupportInitialize)(this.pictureBoxSpinnerDownloadLanguages)).EndInit(); - this.groupBoxGameEdition.ResumeLayout(false); - this.groupBoxGameEdition.PerformLayout(); - ((System.ComponentModel.ISupportInitialize)(this.pictureBoxMSStore)).EndInit(); - ((System.ComponentModel.ISupportInitialize)(this.pictureBoxSteam)).EndInit(); - ((System.ComponentModel.ISupportInitialize)(this.pictureBoxBethesdaNetPTS)).EndInit(); - ((System.ComponentModel.ISupportInitialize)(this.pictureBoxBethesdaNet)).EndInit(); - this.groupBoxLaunchOptions.ResumeLayout(false); - this.groupBoxLaunchOptions.PerformLayout(); - this.groupBoxGamePaths.ResumeLayout(false); - this.groupBoxGamePaths.PerformLayout(); - this.groupBoxOptions.ResumeLayout(false); - this.groupBoxOptions.PerformLayout(); - this.groupBoxBehavior.ResumeLayout(false); - this.groupBoxBehavior.PerformLayout(); ((System.ComponentModel.ISupportInitialize)(this.pictureBoxGameEdition)).EndInit(); ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit(); ((System.ComponentModel.ISupportInitialize)(this.pictureBox2)).EndInit(); @@ -5533,9 +5809,18 @@ private void InitializeComponent() ((System.ComponentModel.ISupportInitialize)(this.numScreenshotIndex)).EndInit(); this.tabPageCustom.ResumeLayout(false); this.tabPageCustom.PerformLayout(); + this.tabPageDangerZone.ResumeLayout(false); + this.groupBoxVideoDZ.ResumeLayout(false); + this.groupBoxShadows2.ResumeLayout(false); + this.groupBoxShadows2.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.numfBlendSplitDirShadow)).EndInit(); + this.groupBox4.ResumeLayout(false); + this.groupBox4.PerformLayout(); + this.contextMenuStripGallery.ResumeLayout(false); this.toolStrip1.ResumeLayout(false); this.toolStrip1.PerformLayout(); - this.contextMenuStripGallery.ResumeLayout(false); + this.statusStrip1.ResumeLayout(false); + this.statusStrip1.PerformLayout(); ((System.ComponentModel.ISupportInitialize)(this.pictureBoxLoadingGIF)).EndInit(); this.ResumeLayout(false); this.PerformLayout(); @@ -5548,24 +5833,9 @@ private void InitializeComponent() private System.Windows.Forms.Timer timerCheckFiles; private System.Windows.Forms.OpenFileDialog openFileDialogGamePath; private System.Windows.Forms.TabPage tabPageCamera; - private System.Windows.Forms.GroupBox groupBoxCameraPositionWIP; + private System.Windows.Forms.GroupBox groupBoxCameraPosition; private System.Windows.Forms.Button buttonCameraPositionReset; - private System.Windows.Forms.Label labelCameraPositionPlayer; - private System.Windows.Forms.Label labelCameraPositionFor; private System.Windows.Forms.CheckBox checkBoxbApplyCameraNodeAnimations; - private System.Windows.Forms.RadioButton radioButtonCameraPositionMeleeCombat; - private System.Windows.Forms.RadioButton radioButtonCameraPositionCombat; - private System.Windows.Forms.RadioButton radioButtonCameraPositionUnarmed; - private System.Windows.Forms.Label labelCameraFurther; - private System.Windows.Forms.Label labelCameraCloser; - private System.Windows.Forms.Label labelCameraUp; - private System.Windows.Forms.Label labelCameraDown; - private System.Windows.Forms.Label labelCameraRight; - private System.Windows.Forms.Label labelCameraLeft; - private System.Windows.Forms.TrackBar trackBarCameraX; - private System.Windows.Forms.TrackBar trackBarCameraZ; - private System.Windows.Forms.TrackBar trackBarCameraY; - private System.Windows.Forms.PictureBox pictureBoxVaultBoy; private System.Windows.Forms.GroupBox groupBoxFieldOfView; private System.Windows.Forms.Label labelADSFOV; private System.Windows.Forms.NumericUpDown numADSFOV; @@ -5573,7 +5843,6 @@ private void InitializeComponent() private System.Windows.Forms.NumericUpDown numFirstPersonFOV; private System.Windows.Forms.Label labelWorldFOV; private System.Windows.Forms.Label labelFirstPersonFOV; - private System.Windows.Forms.GroupBox groupBoxCameraVanity; private System.Windows.Forms.CheckBox checkBoxForceVanityMode; private System.Windows.Forms.CheckBox checkBoxVanityMode; private System.Windows.Forms.TabPage tabPagePipBoy; @@ -5588,13 +5857,10 @@ private void InitializeComponent() private System.Windows.Forms.RadioButton radioButtonQuickboy; private System.Windows.Forms.RadioButton radioButtonPipboy; private System.Windows.Forms.GroupBox groupBoxPipboyColors; - private System.Windows.Forms.PictureBox colorPreviewPAPipboy; - private System.Windows.Forms.Label label1; + private System.Windows.Forms.Label labelPowerArmorColor; private System.Windows.Forms.Button buttonColorPickPAPipboy; private System.Windows.Forms.Button buttonColorResetPipboy; private System.Windows.Forms.Button buttonColorResetPAPipboy; - private System.Windows.Forms.PictureBox colorPreviewPipboy; - private System.Windows.Forms.PictureBox colorPreviewQuickboy; private System.Windows.Forms.Label labelQuickboyColor; private System.Windows.Forms.Button buttonColorPickQuickboy; private System.Windows.Forms.Button buttonColorResetQuickboy; @@ -5651,7 +5917,6 @@ private void InitializeComponent() private System.Windows.Forms.CheckBox checkBoxFixHUDFor5_4and4_3; private System.Windows.Forms.ComboBox comboBoxResolution; private System.Windows.Forms.Button buttonDetectResolution; - private System.Windows.Forms.Label labelCustomResolution; private System.Windows.Forms.CheckBox checkBoxAlwaysActive; private System.Windows.Forms.Label labelResolution; private System.Windows.Forms.CheckBox checkBoxTopMostWindow; @@ -5664,52 +5929,10 @@ private void InitializeComponent() private System.Windows.Forms.CheckBox checkBoxShowCompass; private System.Windows.Forms.CheckBox checkBoxShowDamageNumbersNW; private System.Windows.Forms.CheckBox checkBoxShowDamageNumbersA; - private System.Windows.Forms.GroupBox groupBoxLogin; - private System.Windows.Forms.CheckBox checkBoxDisableSteam; - private System.Windows.Forms.Label labelCredentialsExplanation; - private System.Windows.Forms.TextBox textBoxPassword; - private System.Windows.Forms.TextBox textBoxUserName; - private System.Windows.Forms.CheckBox checkBoxShowPassword; - private System.Windows.Forms.Label labelPassword; - private System.Windows.Forms.Label labelUserName; private System.Windows.Forms.GroupBox groupBoxMainMenu; - private System.Windows.Forms.CheckBox checkBoxShowSplash; + private System.Windows.Forms.CheckBox checkBoxSkipSplash; private System.Windows.Forms.CheckBox checkBoxIntroVideos; private System.Windows.Forms.TabPage tabPageInfo; - private System.Windows.Forms.Panel panel1; - private System.Windows.Forms.GroupBox groupBoxLocalization; - public System.Windows.Forms.Label labelOutdatedLanguage; - private System.Windows.Forms.Label labelLanguage; - private System.Windows.Forms.Button buttonDownloadLanguages; - private System.Windows.Forms.ComboBox comboBoxLanguage; - private System.Windows.Forms.GroupBox groupBoxGameEdition; - private System.Windows.Forms.PictureBox pictureBoxMSStore; - private System.Windows.Forms.PictureBox pictureBoxSteam; - private System.Windows.Forms.PictureBox pictureBoxBethesdaNetPTS; - private System.Windows.Forms.PictureBox pictureBoxBethesdaNet; - private System.Windows.Forms.RadioButton radioButtonEditionMSStore; - private System.Windows.Forms.RadioButton radioButtonEditionBethesdaNetPTS; - private System.Windows.Forms.RadioButton radioButtonEditionSteam; - private System.Windows.Forms.RadioButton radioButtonEditionBethesdaNet; - private System.Windows.Forms.GroupBox groupBoxLaunchOptions; - private System.Windows.Forms.Label labelLaunchOptionMSStoreNotice; - private System.Windows.Forms.Label labelLaunchOptionTip; - private System.Windows.Forms.RadioButton radioButtonLaunchViaExecutable; - private System.Windows.Forms.RadioButton radioButtonLaunchViaLink; - private System.Windows.Forms.GroupBox groupBoxGamePaths; - private System.Windows.Forms.Label labelGamePath; - private System.Windows.Forms.TextBox textBoxGamePath; - private System.Windows.Forms.Button buttonPickGamePath; - private System.Windows.Forms.GroupBox groupBoxOptions; - private System.Windows.Forms.CheckBox checkBoxDenyNTFSWritePermission; - private System.Windows.Forms.CheckBox checkBoxMultipleGameEditionsUsed; - private System.Windows.Forms.CheckBox checkBoxReadOnly; - private System.Windows.Forms.GroupBox groupBoxBehavior; - private System.Windows.Forms.CheckBox checkBoxIgnoreUpdates; - private System.Windows.Forms.CheckBox checkBoxOpenManageModsOnLaunch; - private System.Windows.Forms.CheckBox checkBoxQuitOnGameLaunch; - private System.Windows.Forms.CheckBox checkBoxSkipBackupQuestion; - private System.Windows.Forms.CheckBox checkBoxAutoApply; private System.Windows.Forms.Label labelGameEdition; private System.Windows.Forms.PictureBox pictureBoxGameEdition; private System.Windows.Forms.Label labelNewVersion; @@ -5726,7 +5949,6 @@ private void InitializeComponent() private System.Windows.Forms.Label labelTitle; private System.Windows.Forms.TabControl tabControl1; private System.Windows.Forms.TabPage tabPageAudio; - private System.Windows.Forms.Button buttonCameraPositionCenter; private System.Windows.Forms.GroupBox groupBoxGamepad; private System.Windows.Forms.CheckBox checkBoxGamepadEnabled; private System.Windows.Forms.CheckBox checkBoxGamepadRumble; @@ -5736,25 +5958,6 @@ private void InitializeComponent() private System.Windows.Forms.NumericUpDown numMouseSensitivity; private System.Windows.Forms.Label labelMouseSensitivity; private System.Windows.Forms.CheckBox checkBoxFixMouseSensitivity; - private System.Windows.Forms.ToolStrip toolStrip1; - private System.Windows.Forms.ToolStripButton toolStripButtonApply; - private System.Windows.Forms.ToolStripSeparator toolStripSeparator1; - private System.Windows.Forms.ToolStripButton toolStripButtonManageMods; - private System.Windows.Forms.ToolStripSeparator toolStripSeparator2; - private System.Windows.Forms.ToolStripSeparator toolStripSeparator3; - private System.Windows.Forms.ToolStripButton toolStripButtonNexusMods; - private System.Windows.Forms.ToolStripDropDownButton toolStripDropDownButtonExplore; - private System.Windows.Forms.ToolStripMenuItem gameFolderToolStripMenuItem; - private System.Windows.Forms.ToolStripMenuItem gamesConfigurationFolderToolStripMenuItem; - private System.Windows.Forms.ToolStripSeparator toolStripSeparator4; - private System.Windows.Forms.ToolStripMenuItem toolConfigurationFolderToolStripMenuItem; - private System.Windows.Forms.ToolStripMenuItem toolLanguagesFolderToolStripMenuItem; - private System.Windows.Forms.ToolStripMenuItem toolInstallationFolderToolStripMenuItem; - private System.Windows.Forms.ToolStripSplitButton toolStripSplitButtonUpdate; - private System.Windows.Forms.ToolStripMenuItem downloadUpdateLanguageFilesToolStripMenuItem; - private System.Windows.Forms.ToolStripMenuItem checkForUpdatesToolStripMenuItem; - private System.Windows.Forms.ToolStripMenuItem updateToolToolStripMenuItem; - private System.Windows.Forms.ToolStripMenuItem showUpdaterlogtxtToolStripMenuItem; private System.Windows.Forms.TabPage tabPageCustom; private System.Windows.Forms.TextBox textBoxCustom; private System.Windows.Forms.ComboBox comboBoxCustomFile; @@ -5843,13 +6046,6 @@ private void InitializeComponent() private System.Windows.Forms.TrackBar sliderGalleryThumbnailSize; private System.Windows.Forms.Label labelGalleryThumbnailSize; private System.Windows.Forms.Label labelGalleryTip; - private System.Windows.Forms.ToolStripSeparator toolStripSeparator5; - private System.Windows.Forms.ToolStripMenuItem editFallout76iniToolStripMenuItem; - private System.Windows.Forms.ToolStripMenuItem editFallout76PrefsiniToolStripMenuItem; - private System.Windows.Forms.ToolStripMenuItem editFallout76CustominiToolStripMenuItem; - private System.Windows.Forms.ToolStripMenuItem steamScreenshotFolderToolStripMenuItem; - private System.Windows.Forms.ToolStripMenuItem gamePhotosFolderToolStripMenuItem; - private System.Windows.Forms.ToolStripSeparator toolStripSeparator6; private System.Windows.Forms.PictureBox pictureBoxGalleryLoadingGIF; private System.Windows.Forms.GroupBox groupBoxCameraDistance; private System.Windows.Forms.TrackBar sliderCameraDistanceMaximum; @@ -5868,31 +6064,11 @@ private void InitializeComponent() private System.Windows.Forms.NumericUpDown numfDefaultFOV; private System.Windows.Forms.Label labelfDefaultFOV; private System.Windows.Forms.Panel panel4; - private System.Windows.Forms.Label labelAccountProfiles; - private System.Windows.Forms.RadioButton radioButtonAccount4; - private System.Windows.Forms.RadioButton radioButtonAccount3; - private System.Windows.Forms.RadioButton radioButtonAccount2; - private System.Windows.Forms.RadioButton radioButtonAccount1; - private System.Windows.Forms.RadioButton radioButtonAccount8; - private System.Windows.Forms.RadioButton radioButtonAccount7; - private System.Windows.Forms.RadioButton radioButtonAccount6; - private System.Windows.Forms.RadioButton radioButtonAccount5; private System.Windows.Forms.Panel panel3; - private System.Windows.Forms.ComboBox comboBoxiDirShadowSplits; - private System.Windows.Forms.Label label2; - private System.Windows.Forms.TrackBar sliderfBlendSplitDirShadow; - private System.Windows.Forms.NumericUpDown numfBlendSplitDirShadow; - private System.Windows.Forms.Label labelfBlendSplitDirShadow; private System.ComponentModel.BackgroundWorker backgroundWorkerGetLatestVersion; private System.Windows.Forms.PictureBox pictureBoxSpinnerCheckForUpdates; private System.Windows.Forms.PictureBox pictureBoxUpdateButton; private System.Windows.Forms.Panel panelUpdate; - private System.ComponentModel.BackgroundWorker backgroundWorkerDownloadLanguages; - private System.Windows.Forms.PictureBox pictureBoxSpinnerDownloadLanguages; - private System.Windows.Forms.ToolStripSplitButton toolStripSplitButtonLaunchGame; - private System.Windows.Forms.ToolStripMenuItem launchViaSteamToolStripMenuItem; - private System.Windows.Forms.ToolStripMenuItem launchViaBethesdanetToolStripMenuItem; - private System.Windows.Forms.ToolStripMenuItem launchViaBethesdanetPTSToolStripMenuItem; private System.Windows.Forms.ContextMenuStrip contextMenuStripGallery; private System.Windows.Forms.ToolStripMenuItem openToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem copyToolStripMenuItem; @@ -5901,30 +6077,147 @@ private void InitializeComponent() private System.Windows.Forms.ToolStripSeparator toolStripSeparator8; private System.Windows.Forms.ToolStripMenuItem deleteToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem openFolderToolStripMenuItem; - private System.Windows.Forms.Button buttonRefreshLanguage; - private System.Windows.Forms.CheckBox checkBoxAlternativeINIMode; private System.Windows.Forms.TextBox textBoxGalleryPaths; private System.Windows.Forms.Label label3; private System.Windows.Forms.CheckBox checkBoxGallerySearchRecursively; private System.Windows.Forms.Button buttonGalleryDeleteThumbnails; - private System.Windows.Forms.ToolStripButton toolStripButtonToggleNuclearWinterMode; - private System.Windows.Forms.GroupBox groupBoxNuclearWinterMode; - private System.Windows.Forms.CheckBox checkBoxNWAutoDeployMods; - private System.Windows.Forms.Label labelNWmodoptions; - private System.Windows.Forms.Label labelNWdlloptions; - private System.Windows.Forms.Label labelNWinioptions; - private System.Windows.Forms.RadioButton radioButtonNWRemoveLists; - private System.Windows.Forms.RadioButton radioButtonNWRenameINI; - private System.Windows.Forms.CheckBox checkBoxNWAutoDisableMods; - private System.Windows.Forms.CheckBox checkBoxNWRenameDLL; - private System.ComponentModel.BackgroundWorker backgroundWorkerEnableNWMode; - private System.ComponentModel.BackgroundWorker backgroundWorkerDisableNWMode; private System.Windows.Forms.Label labelNWModeActive; private System.Windows.Forms.PictureBox pictureBoxLoadingGIF; private System.Windows.Forms.LinkLabel linkLabelAttribution; - private System.Windows.Forms.CheckBox checkBoxPlayNotificationSound; - private System.Windows.Forms.CheckBox checkBoxAutoSignin; private System.Windows.Forms.LinkLabel linkLabelWhatsNew; + private System.Windows.Forms.GroupBox groupBoxGraphicEffects; + private System.Windows.Forms.CheckBox checkBoxDisableGore; + private System.Windows.Forms.Panel panel2; + private System.Windows.Forms.GroupBox groupBoxSelfieCamera; + private System.Windows.Forms.NumericUpDown numericUpDownPhotomodeTranslationSpeed; + private System.Windows.Forms.TrackBar trackBarPhotomodeTranslationSpeed; + private System.Windows.Forms.Label labelPhotomodeTranslationSpeed; + private System.Windows.Forms.NumericUpDown numericUpDownPhotomodeRange; + private System.Windows.Forms.TrackBar trackBarPhotomodeRange; + private System.Windows.Forms.Label labelPhotomodeRange; + private System.Windows.Forms.NumericUpDown numericUpDownPhotomodeRotationSpeed; + private System.Windows.Forms.TrackBar trackBarPhotomodeRotationSpeed; + private System.Windows.Forms.Label labelPhotomodeRotationSpeed; + private Forms.Form1.ColorPreview colorPreviewPipboy; + private Forms.Form1.ColorPreview colorPreviewQuickboy; + private Forms.Form1.ColorPreview colorPreviewPAPipboy; + private System.Windows.Forms.ToolStripButton toolStripButtonApply; + private System.Windows.Forms.ToolStripButton toolStripButtonToggleNuclearWinterMode; + private System.Windows.Forms.ToolStripSeparator toolStripSeparator3; + private System.Windows.Forms.ToolStripButton toolStripButtonManageMods; + private System.Windows.Forms.ToolStripSeparator toolStripSeparator9; + private System.Windows.Forms.ToolStripButton toolStripButtonSettings; + private System.Windows.Forms.ToolStripSplitButton toolStripSplitButtonUpdate; + private System.Windows.Forms.ToolStripMenuItem updateToolToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem checkForUpdatesToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem showUpdaterlogtxtToolStripMenuItem; + private System.Windows.Forms.ToolStripDropDownButton toolStripDropDownButtonExplore; + private System.Windows.Forms.ToolStripMenuItem gameFolderToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem gamesConfigurationFolderToolStripMenuItem; + private System.Windows.Forms.ToolStripSeparator toolStripSeparator4; + private System.Windows.Forms.ToolStripMenuItem toolConfigurationFolderToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem toolLanguagesFolderToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem toolInstallationFolderToolStripMenuItem; + private System.Windows.Forms.ToolStripSeparator toolStripSeparator5; + private System.Windows.Forms.ToolStripMenuItem steamScreenshotFolderToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem gamePhotosFolderToolStripMenuItem; + private System.Windows.Forms.ToolStripSeparator toolStripSeparator6; + private System.Windows.Forms.ToolStripMenuItem editFallout76iniToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem editFallout76PrefsiniToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem editFallout76CustominiToolStripMenuItem; + private System.Windows.Forms.ToolStrip toolStrip1; + private System.Windows.Forms.Label labelCustomResolution; + private System.Windows.Forms.StatusStrip statusStrip1; + private System.Windows.Forms.ToolStripStatusLabel toolStripStatusLabelGame; + private System.Windows.Forms.ToolStripStatusLabel toolStripStatusLabelGameText; + private System.Windows.Forms.ToolStripStatusLabel toolStripStatusLabelEdition; + private System.Windows.Forms.ToolStripStatusLabel toolStripStatusLabelEditionText; + private System.Windows.Forms.GroupBox groupBoxPipboyColorPreview; + private System.Windows.Forms.PictureBox pictureBoxPipboyPreview; + private System.Windows.Forms.Label labelPipboyColorPreviewNotice; + private Forms.Form1.ColorPreview colorPreviewPresetFo3Green; + private System.Windows.Forms.Button buttonPresetFo3Green; + private Forms.Form1.ColorPreview colorPreviewPresetFo76Green; + private Forms.Form1.ColorPreview colorPreviewPresetFo3White; + private System.Windows.Forms.Button buttonPresetFo3White; + private System.Windows.Forms.Button buttonPresetFo76Green; + private Forms.Form1.ColorPreview colorPreviewPresetFo3Blue; + private Forms.Form1.ColorPreview colorPreviewPresetFo4Green; + private System.Windows.Forms.Button buttonPresetFo3Blue; + private System.Windows.Forms.Button buttonPresetFo4Green; + private Forms.Form1.ColorPreview colorPreviewPresetFoNVAmber; + private System.Windows.Forms.Button buttonPresetFoNVAmber; + private System.Windows.Forms.GroupBox groupBoxPipboyColorPresets; + private System.Windows.Forms.GroupBox groupBoxUnarmedCameraPosition; + private System.Windows.Forms.GroupBox groupBox2; + private System.Windows.Forms.Label labelfOverShoulderCombatAddY; + private System.Windows.Forms.TrackBar trackBarfOverShoulderCombatAddY; + private System.Windows.Forms.Label labelfOverShoulderCombatPosX; + private System.Windows.Forms.TrackBar trackBarfOverShoulderCombatPosX; + private System.Windows.Forms.Label labelfOverShoulderCombatPosZ; + private System.Windows.Forms.TrackBar trackBarfOverShoulderCombatPosZ; + private System.Windows.Forms.Label labelfOverShoulderPosX; + private System.Windows.Forms.TrackBar trackBarfOverShoulderPosX; + private System.Windows.Forms.Label labelfOverShoulderPosZ; + private System.Windows.Forms.TrackBar trackBarfOverShoulderPosZ; + private System.Windows.Forms.GroupBox groupBox3; + private System.Windows.Forms.Label labelfOverShoulderMeleeCombatAddY; + private System.Windows.Forms.TrackBar trackBarfOverShoulderMeleeCombatAddY; + private System.Windows.Forms.Label labelfOverShoulderMeleeCombatPosX; + private System.Windows.Forms.TrackBar trackBarfOverShoulderMeleeCombatPosX; + private System.Windows.Forms.Label labelfOverShoulderMeleeCombatPosZ; + private System.Windows.Forms.TrackBar trackBarfOverShoulderMeleeCombatPosZ; + private System.Windows.Forms.NumericUpDown numfOverShoulderMeleeCombatAddY; + private System.Windows.Forms.NumericUpDown numfOverShoulderMeleeCombatPosX; + private System.Windows.Forms.NumericUpDown numfOverShoulderMeleeCombatPosZ; + private System.Windows.Forms.NumericUpDown numfOverShoulderCombatAddY; + private System.Windows.Forms.NumericUpDown numfOverShoulderCombatPosX; + private System.Windows.Forms.NumericUpDown numfOverShoulderCombatPosZ; + private System.Windows.Forms.NumericUpDown numfOverShoulderPosX; + private System.Windows.Forms.NumericUpDown numfOverShoulderPosZ; + private System.Windows.Forms.GroupBox groupBoxSettings; + private System.Windows.Forms.LinkLabel linkLabelOpenSettings; + private System.Windows.Forms.Label labelSettingsNotice; + private System.Windows.Forms.ToolStripButton toolStripButtonLaunchGame; + private System.Windows.Forms.ToolStripStatusLabel toolStripStatusLabelNuclearWinterModeActive; + private System.Windows.Forms.ToolStripStatusLabel toolStripStatusLabel1; + private System.Windows.Forms.GroupBox groupBoxLogin; + private System.Windows.Forms.GroupBox groupBoxLoginProfiles; + private System.Windows.Forms.RadioButton radioButtonAccount1; + private System.Windows.Forms.RadioButton radioButtonAccount16; + private System.Windows.Forms.RadioButton radioButtonAccount2; + private System.Windows.Forms.RadioButton radioButtonAccount15; + private System.Windows.Forms.RadioButton radioButtonAccount3; + private System.Windows.Forms.RadioButton radioButtonAccount14; + private System.Windows.Forms.RadioButton radioButtonAccount4; + private System.Windows.Forms.RadioButton radioButtonAccount13; + private System.Windows.Forms.RadioButton radioButtonAccount5; + private System.Windows.Forms.RadioButton radioButtonAccount12; + private System.Windows.Forms.RadioButton radioButtonAccount6; + private System.Windows.Forms.RadioButton radioButtonAccount11; + private System.Windows.Forms.RadioButton radioButtonAccount7; + private System.Windows.Forms.RadioButton radioButtonAccount10; + private System.Windows.Forms.RadioButton radioButtonAccount8; + private System.Windows.Forms.RadioButton radioButtonAccount9; + private System.Windows.Forms.CheckBox checkBoxAutoSignin; + private System.Windows.Forms.CheckBox checkBoxEnableSteam; + private System.Windows.Forms.Label labelCredentialsExplanation; + private System.Windows.Forms.TextBox textBoxPassword; + private System.Windows.Forms.TextBox textBoxUserName; + private System.Windows.Forms.CheckBox checkBoxShowPassword; + private System.Windows.Forms.Label labelPassword; + private System.Windows.Forms.Label labelUserName; + private System.Windows.Forms.TabPage tabPageDangerZone; + private System.Windows.Forms.GroupBox groupBoxVideoDZ; + private System.Windows.Forms.GroupBox groupBoxShadows2; + private System.Windows.Forms.Label labeliDirShadowSplits; + private System.Windows.Forms.ComboBox comboBoxiDirShadowSplits; + private System.Windows.Forms.TrackBar sliderfBlendSplitDirShadow; + private System.Windows.Forms.Label labelfBlendSplitDirShadow; + private System.Windows.Forms.NumericUpDown numfBlendSplitDirShadow; + private System.Windows.Forms.GroupBox groupBox4; + private System.Windows.Forms.CheckBox checkBoxScreenSpaceReflections; + private System.Windows.Forms.RadioButton radioButtonAccountNone; } } diff --git a/Fo76ini/Forms/Form1/Form1.Gallery.cs b/Fo76ini/Forms/Form1/Form1.Gallery.cs index 203ead6..bebee62 100644 --- a/Fo76ini/Forms/Form1/Form1.Gallery.cs +++ b/Fo76ini/Forms/Form1/Form1.Gallery.cs @@ -1,23 +1,22 @@ -using System; +using Fo76ini.Interface; +using Fo76ini.Utilities; +using System; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.Drawing; using System.IO; using System.Linq; -using System.Text; -using System.Threading; -using System.Threading.Tasks; using System.Windows.Forms; namespace Fo76ini { public partial class Form1 { - private List galleryImagePaths = new List(); + private List galleryImagePaths = new List(); private ImageList galleryImageList = new ImageList(); - private static String[] ValidImageFormats = new String[] { + private static string[] ValidImageFormats = new string[] { ".png", ".jpg", ".gif", @@ -39,8 +38,8 @@ private void LoadGallery() this.listViewScreenshots.MouseUp += listViewScreenshots_MouseUp; //this.sliderGalleryThumbnailSize.ValueChanged += sliderGalleryThumbnailSize_ValueChanged; - this.textBoxGalleryPaths.Text = IniFiles.Instance.GetString(IniFile.Config, "Gallery", "sCustomPathsList", "").Replace(",", "\r\n"); - this.checkBoxGallerySearchRecursively.Checked = IniFiles.Instance.GetBool(IniFile.Config, "Gallery", "bSearchDirectoriesRecursively", false); + this.textBoxGalleryPaths.Text = IniFiles.Config.GetString("Gallery", "sCustomPathsList", "").Replace(",", "\r\n"); + this.checkBoxGallerySearchRecursively.Checked = IniFiles.Config.GetBool("Gallery", "bSearchDirectoriesRecursively", false); } private void UpdateScreenShotGalleryThreaded() @@ -87,7 +86,7 @@ private void UpdateScreenShotGallery() /* * Thumbnails folder: */ - String thumbnailsPath = Path.Combine(Shared.AppConfigFolder, "thumbnails", "screenshots"); + string thumbnailsPath = Path.Combine(Shared.AppConfigFolder, "thumbnails", "screenshots"); if (!Directory.Exists(thumbnailsPath)) Directory.CreateDirectory(thumbnailsPath); @@ -95,24 +94,24 @@ private void UpdateScreenShotGallery() * Search the game folders for screenshots: * C:\...\Fallout76\*.png */ - String[] gamePaths = new String[] { - IniFiles.Instance.GetString(IniFile.Config, "Preferences", "sGamePathSteam", ""), - IniFiles.Instance.GetString(IniFile.Config, "Preferences", "sGamePathBethesdaNet", ""), - IniFiles.Instance.GetString(IniFile.Config, "Preferences", "sGamePathBethesdaNetPTS", "") + string[] gamePaths = new string[] { + IniFiles.Config.GetString("Preferences", "sGamePathSteam", ""), + IniFiles.Config.GetString("Preferences", "sGamePathBethesdaNet", ""), + IniFiles.Config.GetString("Preferences", "sGamePathBethesdaNetPTS", "") }; - foreach (String gamePath in gamePaths) + foreach (string gamePath in gamePaths) { if (Directory.Exists(gamePath)) { - IEnumerable screenshots = Directory.EnumerateFiles(gamePath, "*.png", SearchOption.TopDirectoryOnly); - foreach (String filePath in screenshots) + IEnumerable screenshots = Directory.EnumerateFiles(gamePath, "*.png", SearchOption.TopDirectoryOnly); + foreach (string filePath in screenshots) { - String fileName = Path.GetFileName(filePath); - String thumbPath = Path.Combine(thumbnailsPath, fileName) + ".jpg"; + string fileName = Path.GetFileName(filePath); + string thumbPath = Path.Combine(thumbnailsPath, fileName) + ".jpg"; Bitmap thumbnail; if (!File.Exists(thumbPath)) - thumbnail = new Bitmap(Utils.MakeThumbnail(filePath, thumbPath)); + thumbnail = new Bitmap(Utils.MakeThumbnail(filePath, thumbPath, true)); else thumbnail = new Bitmap(thumbPath); @@ -133,23 +132,23 @@ private void UpdateScreenShotGallery() * C:\Users\\Documents\My Games\Fallout 76\Photos\\*.png * C:\Users\\Documents\My Games\Fallout 76\Photos\\*-thumbnail.png */ - String photosFolder = Path.Combine(IniFiles.Instance.iniParentPath, "Photos"); + string photosFolder = Path.Combine(IniFiles.ParentPath, "Photos"); if (Directory.Exists(photosFolder)) { - IEnumerable photos = Directory.EnumerateFiles(photosFolder, "*.png", SearchOption.AllDirectories); - foreach (String filePath in photos) + IEnumerable photos = Directory.EnumerateFiles(photosFolder, "*.png", SearchOption.AllDirectories); + foreach (string filePath in photos) { - String fileName = Path.GetFileName(filePath); + string fileName = Path.GetFileName(filePath); if (fileName.EndsWith("-thumbnail.png")) continue; - String thumbnailFilePath = fileName.Replace(".png", "-thumbnail.png"); + string thumbnailFilePath = fileName.Replace(".png", "-thumbnail.png"); if (!File.Exists(thumbnailFilePath)) { thumbnailFilePath = Path.Combine(thumbnailsPath, fileName + ".jpg"); if (!File.Exists(thumbnailFilePath)) - Utils.MakeThumbnail(filePath, thumbnailFilePath); + Utils.MakeThumbnail(filePath, thumbnailFilePath, true); //thumbnailFilePath = filePath; } @@ -170,25 +169,25 @@ private void UpdateScreenShotGallery() * C:\Program Files (x86)\Steam\userdata\\760\remote\1151340\screenshots\*.jpg * C:\Program Files (x86)\Steam\userdata\\760\remote\1151340\screenshots\thumbnails\*.jpg */ - String steamFolder = @"C:\Program Files (x86)\Steam\userdata\"; + string steamFolder = @"C:\Program Files (x86)\Steam\userdata\"; if (Directory.Exists(steamFolder)) { steamFolder = Path.Combine(Directory.GetDirectories(steamFolder)[0], @"760\remote\1151340\screenshots"); - String steamThumbnailFolder = Path.Combine(steamFolder, "thumbnails"); + string steamThumbnailFolder = Path.Combine(steamFolder, "thumbnails"); if (Directory.Exists(steamFolder)) { - List screenshots = Directory.GetFiles(steamFolder, "*.jpg", SearchOption.TopDirectoryOnly).ToList(); - foreach (String filePath in screenshots) + List screenshots = Directory.GetFiles(steamFolder, "*.jpg", SearchOption.TopDirectoryOnly).ToList(); + foreach (string filePath in screenshots) { - String fileName = Path.GetFileName(filePath); + string fileName = Path.GetFileName(filePath); - String thumbnailFilePath = Path.Combine(steamThumbnailFolder, fileName); + string thumbnailFilePath = Path.Combine(steamThumbnailFolder, fileName); if (!File.Exists(thumbnailFilePath)) { thumbnailFilePath = Path.Combine(thumbnailsPath, fileName + ".jpg"); if (!File.Exists(thumbnailFilePath)) - Utils.MakeThumbnail(filePath, thumbnailFilePath); + Utils.MakeThumbnail(filePath, thumbnailFilePath, true); //thumbnailFilePath = filePath; } @@ -208,24 +207,24 @@ private void UpdateScreenShotGallery() /* * Search additional paths added by the user: */ - foreach (String path in GetAdditionalPathList()) + foreach (string path in GetAdditionalPathList()) { Console.WriteLine(path); - String folderName = new DirectoryInfo(path).Name; - IEnumerable pictures = Directory.EnumerateFiles(path, "*.*", + string folderName = new DirectoryInfo(path).Name; + IEnumerable pictures = Directory.EnumerateFiles(path, "*.*", this.checkBoxGallerySearchRecursively.Checked ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly ); - foreach (String filePath in pictures) + foreach (string filePath in pictures) { FileInfo info = new FileInfo(filePath); - String fileName = info.Name; + string fileName = info.Name; if (!ValidImageFormats.Contains(info.Extension)) continue; - String thumbnailFilePath = Path.Combine(thumbnailsPath, folderName + "-" + fileName + ".jpg"); + string thumbnailFilePath = Path.Combine(thumbnailsPath, folderName + "-" + fileName + ".jpg"); if (!File.Exists(thumbnailFilePath)) - Utils.MakeThumbnail(filePath, thumbnailFilePath); + Utils.MakeThumbnail(filePath, thumbnailFilePath, true); Bitmap thumbnail = new Bitmap(thumbnailFilePath); this.Invoke(() => galleryImageList.Images.Add(fileName, thumbnail)); @@ -243,10 +242,10 @@ private void UpdateScreenShotGallery() this.Invoke(() => this.buttonRefreshGallery.Enabled = true); } - private List GetAdditionalPathList() + private List GetAdditionalPathList() { - List paths = new List(); - foreach (String path in this.textBoxGalleryPaths.Text.Replace("\r\n", "\n").Split('\n')) + List paths = new List(); + foreach (string path in this.textBoxGalleryPaths.Text.Replace("\r\n", "\n").Split('\n')) { if (Directory.Exists(path.Trim())) paths.Add(path.Trim()); @@ -285,7 +284,7 @@ private void buttonGalleryDeleteThumbnails_Click(object sender, EventArgs e) this.listViewScreenshots.Items.Clear(); // Delete thumbnails: - String thumbnailsPath = Path.Combine(Shared.AppConfigFolder, "thumbnails", "screenshots"); + string thumbnailsPath = Path.Combine(Shared.AppConfigFolder, "thumbnails", "screenshots"); try { Directory.Delete(thumbnailsPath, true); @@ -303,12 +302,12 @@ private void buttonGalleryDeleteThumbnails_Click(object sender, EventArgs e) private void textBoxGalleryPaths_TextChanged(object sender, EventArgs e) { - IniFiles.Instance.Set(IniFile.Config, "Gallery", "sCustomPathsList", this.textBoxGalleryPaths.Text.Replace("\r\n", ",").Replace("\n", ",")); + IniFiles.Config.Set("Gallery", "sCustomPathsList", this.textBoxGalleryPaths.Text.Replace("\r\n", ",").Replace("\n", ",")); } private void checkBoxGallerySearchRecursively_CheckedChanged(object sender, EventArgs e) { - IniFiles.Instance.Set(IniFile.Config, "Gallery", "bSearchDirectoriesRecursively", this.checkBoxGallerySearchRecursively.Checked); + IniFiles.Config.Set("Gallery", "bSearchDirectoriesRecursively", this.checkBoxGallerySearchRecursively.Checked); } private void Invoke(Action func) @@ -349,20 +348,20 @@ private void openToolStripMenuItem_Click(object sender, EventArgs e) private void openFolderToolStripMenuItem_Click(object sender, EventArgs e) { // Open all folders, but no duplicates: - List folders = new List(); + List folders = new List(); foreach (int index in galleryContextMenuItems) { - String folder = Path.GetDirectoryName(galleryImagePaths[index]); + string folder = Path.GetDirectoryName(galleryImagePaths[index]); if (!folders.Contains(folder)) folders.Add(folder); } - foreach (String folder in folders) + foreach (string folder in folders) Utils.OpenExplorer(folder); } private void cutToolStripMenuItem_Click(object sender, EventArgs e) { - List files = new List(); + List files = new List(); foreach (int index in galleryContextMenuItems) files.Add(galleryImagePaths[index]); ClipboardUtils.CutFiles(files); @@ -370,7 +369,7 @@ private void cutToolStripMenuItem_Click(object sender, EventArgs e) private void copyToolStripMenuItem_Click(object sender, EventArgs e) { - List files = new List(); + List files = new List(); foreach (int index in galleryContextMenuItems) files.Add(galleryImagePaths[index]); ClipboardUtils.CopyFiles(files); @@ -381,19 +380,19 @@ private void deleteToolStripMenuItem_Click(object sender, EventArgs e) bool ok = false; if (galleryContextMenuItems.Count == 1) { - String fileName = Path.GetFileName(galleryImagePaths[galleryContextMenuItems[0]]); - ok = MsgBox.Get("galleryDeleteScreenshot").FormatTitle(fileName).FormatText(fileName).Show(MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes; + string fileName = Path.GetFileName(galleryImagePaths[galleryContextMenuItems[0]]); + ok = MsgBox.Get("deleteQuestion").FormatTitle(fileName).FormatText(fileName).Show(MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes; } else { - ok = MsgBox.Get("galleryDeleteScreenshots").FormatTitle(galleryContextMenuItems.Count.ToString()).FormatText(galleryContextMenuItems.Count.ToString()).Show(MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes; + ok = MsgBox.Get("deleteMultipleQuestion").FormatTitle(galleryContextMenuItems.Count.ToString()).FormatText(galleryContextMenuItems.Count.ToString()).Show(MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes; } if (ok) { foreach (int index in galleryContextMenuItems) { - String path = galleryImagePaths[index]; + string path = galleryImagePaths[index]; if (File.Exists(path)) File.Delete(path); } diff --git a/Fo76ini/Forms/Form1/Form1.Language.cs b/Fo76ini/Forms/Form1/Form1.Language.cs index aeb9ef3..31e259c 100644 --- a/Fo76ini/Forms/Form1/Form1.Language.cs +++ b/Fo76ini/Forms/Form1/Form1.Language.cs @@ -1,129 +1,31 @@ -using IniParser.Model; +using Fo76ini.Interface; +using Fo76ini.Profiles; using System; -using System.Collections.Generic; using System.ComponentModel; -using System.Globalization; using System.IO; -using System.Linq; using System.Net; using System.Text; -using System.Text.RegularExpressions; -using System.Threading; -using System.Threading.Tasks; using System.Windows.Forms; -using System.Xml; -using System.Xml.Linq; namespace Fo76ini { partial class Form1 { - public void ChangeLanguage(Form1 form1, FormMods formMods) + public void OnLanguageChanged(object sender, TranslationEventArgs e) { - // Apply translation to forms: - Translation translation = Localization.GetTranslation(); - translation.Apply(); + Translation translation = (Translation)sender; // Set labels and stuff: - form1.labelOutdatedLanguage.Visible = translation.IsOutdated(); + this.labelTranslationAuthor.Visible = e.HasAuthor; + this.labelTranslationBy.Visible = e.HasAuthor; + this.labelTranslationAuthor.Text = e.HasAuthor ? translation.Author : ""; - form1.labelTranslationAuthor.Visible = false; - form1.labelTranslationBy.Visible = false; - if (translation.Author != "") - { - form1.labelTranslationAuthor.Visible = true; - form1.labelTranslationBy.Visible = true; - form1.labelTranslationAuthor.Text = translation.Author; - } - - form1.RefreshNWModeButtonAppearance(); - form1.CheckVersion(); - formMods.UpdateUI(); - - // Force redraw: - form1.Refresh(); - formMods.Refresh(); - - // Set sLanguage in config.ini: - IniFiles.Instance.Set(IniFile.Config, "Preferences", "sLanguage", translation.ISO); - Localization.locale = translation.ISO; - - if (translation.ISO != "en-US") - Localization.GenerateTemplate(translation); - } - - private void comboBoxLanguage_SelectedIndexChanged(object sender, EventArgs e) - { - ChangeLanguage(this, this.formMods); - } - - private void buttonDownloadLanguages_Click(object sender, EventArgs e) - { - if (this.backgroundWorkerDownloadLanguages.IsBusy) - return; - this.groupBoxLocalization.Focus(); - this.buttonDownloadLanguages.Enabled = false; - this.pictureBoxSpinnerDownloadLanguages.Visible = true; - this.backgroundWorkerDownloadLanguages.RunWorkerAsync(); - } - - private String errorMessageDownloadLanguages = null; - private String messageDownloadLanguages = null; - private void backgroundWorkerDownloadLanguages_DoWork(object sender, DoWorkEventArgs e) - { - // Download / update languages: - try - { - System.Net.WebClient wc = new System.Net.WebClient(); - wc.CachePolicy = new System.Net.Cache.RequestCachePolicy(System.Net.Cache.RequestCacheLevel.BypassCache); - - byte[] raw = wc.DownloadData("https://raw.githubusercontent.com/FelisDiligens/Fallout76-QuickConfiguration/master/Fo76ini/languages/list.txt"); - String encoded = Encoding.UTF8.GetString(raw).Trim(); - - String[] list = encoded.Split('\n', ','); - - foreach (String file in list) - { - wc.DownloadFile("https://raw.githubusercontent.com/FelisDiligens/Fallout76-QuickConfiguration/master/Fo76ini/languages/" + file, Path.Combine(Localization.languageFolder, file)); - } - - errorMessageDownloadLanguages = null; - messageDownloadLanguages = String.Join(", ", list); - //MsgBox.Get("downloadLanguagesFinished").FormatText(String.Join(", ", list)).Popup(MessageBoxIcon.Information); - } - catch (WebException ex) - { - errorMessageDownloadLanguages = ex.ToString(); - messageDownloadLanguages = null; - //MsgBox.Get("downloadLanguagesFailed").FormatText(ex.ToString()).Popup(MessageBoxIcon.Error); - } - catch - { - errorMessageDownloadLanguages = "Unknown error"; - messageDownloadLanguages = null; - //MsgBox.Get("downloadLanguagesFailed").FormatText("Unknown error").Popup(MessageBoxIcon.Error); - } - } - - private void backgroundWorkerDownloadLanguages_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) - { - if (errorMessageDownloadLanguages != null) - MsgBox.Get("downloadLanguagesFailed").FormatText(errorMessageDownloadLanguages).Popup(MessageBoxIcon.Error); - else - MsgBox.Get("downloadLanguagesFinished").FormatText(messageDownloadLanguages).Popup(MessageBoxIcon.Information); - this.buttonDownloadLanguages.Enabled = true; - this.pictureBoxSpinnerDownloadLanguages.Visible = false; - Localization.LookupLanguages(); - } - - private void buttonRefreshLanguage_Click(object sender, EventArgs e) - { - Localization.LookupLanguages(); - this.RefreshNWModeButtonAppearance(); + // TODO: UpdateUI? this.CheckVersion(); - formMods.UpdateUI(); - this.Refresh(); - this.formMods.Refresh(); + + this.Refresh(); // Forces redraw } + // TODO: FormMods needs OnLanguageChanged code. + // formMods.UpdateUI(); // TODO: Changing the language before loading mods crashes the tool on startup. } } diff --git a/Fo76ini/Forms/Form1/Form1.LinkControls.cs b/Fo76ini/Forms/Form1/Form1.LinkControls.cs new file mode 100644 index 0000000..1b8b6ac --- /dev/null +++ b/Fo76ini/Forms/Form1/Form1.LinkControls.cs @@ -0,0 +1,808 @@ +using Fo76ini.Tweaks; +using Fo76ini.Tweaks.Audio; +using Fo76ini.Tweaks.Camera; +using Fo76ini.Tweaks.Colors; +using Fo76ini.Tweaks.Config; +using Fo76ini.Tweaks.Controls; +using Fo76ini.Tweaks.General; +using Fo76ini.Tweaks.Graphics; +using Fo76ini.Tweaks.Inis; +using Fo76ini.Tweaks.Interface; +using Fo76ini.Tweaks.Pipboy; +using Fo76ini.Tweaks.Video; +using Fo76ini.Tweaks.Volume; + +namespace Fo76ini +{ + /* + * A bit similar to the *.Designer.cs, adds event handlers to (almost) all controls. + * That is, instantiate classes that implement ITweak, and link the controls to it's value (among other things). + */ + partial class Form1 + { + /// + /// Adds tooltip information (ITweakInfo) + /// + public void LinkInfo() + { + // Info tab + /*LinkedTweaks.LinkInfo(checkBoxReadOnly, iniReadOnlyTweak); + LinkedTweaks.LinkInfo(checkBoxAutoApply, autoApplyTweak); + LinkedTweaks.LinkInfo(checkBoxIgnoreUpdates, ignoreUpdatesTweak); + LinkedTweaks.LinkInfo(checkBoxPlayNotificationSound, playNotificationSoundsTweak); + LinkedTweaks.LinkInfo(checkBoxQuitOnGameLaunch, toolQuitOnLaunchTweak);*/ + + // General tab + LinkedTweaks.LinkInfo(checkBoxEnableSteam, toolTip, enableSteamTweak); + LinkedTweaks.LinkInfo(checkBoxAutoSignin, toolTip, autoSigninTweak); + LinkedTweaks.LinkInfo(checkBoxIntroVideos, toolTip, introVideoTweak); + LinkedTweaks.LinkInfo(checkBoxSkipSplash, toolTip, skipStartupSplash); + + LinkedTweaks.LinkInfo(checkBoxShowDamageNumbersNW, toolTip, showDamageNumbersNuclearWinterTweak); + LinkedTweaks.LinkInfo(checkBoxShowDamageNumbersA, toolTip, showDamageNumbersAdventureTweak); + LinkedTweaks.LinkInfo(checkBoxItemRarityColorsNW, toolTip, enableItemRarityColorsTweak); + LinkedTweaks.LinkInfo(checkBoxShowPublicTeamNotifications, toolTip, showPublicTeamNotificationsTweak); + LinkedTweaks.LinkInfo(checkBoxShowFloatingQuestMarkers, toolTip, showFloatingQuestMarkersTweak); + LinkedTweaks.LinkInfo(checkBoxShowFloatingQuestText, toolTip, showFloatingQuestTextTweak); + LinkedTweaks.LinkInfo(checkBoxShowCrosshair, toolTip, showCrosshairTweak); + LinkedTweaks.LinkInfo(checkBoxEnablePowerArmorHUD, toolTip, enablePowerArmorHUDTweak); + LinkedTweaks.LinkInfo(checkBoxShowCompass, toolTip, showCompassTweak); + LinkedTweaks.LinkInfo(checkBoxShowOtherPlayersNames, toolTip, showOtherPlayersNamesTweak); + LinkedTweaks.LinkInfo(comboBoxShowActiveEffectsOnHUD, toolTip, activeEffectsOnHUDTweak); + LinkedTweaks.LinkInfo(labelShowActiveEffectsOnHUD, toolTip, activeEffectsOnHUDTweak); + LinkedTweaks.LinkInfo(numFloatingQuestMarkersDistance, toolTip, floatingQuestMarkersDistanceTweak); + LinkedTweaks.LinkInfo(sliderFloatingQuestMarkersDistance, toolTip, floatingQuestMarkersDistanceTweak); + LinkedTweaks.LinkInfo(labelFloatingQuestMarkersDistance, toolTip, floatingQuestMarkersDistanceTweak); + LinkedTweaks.LinkInfo(numHUDOpacity, toolTip, hudOpacityTweak); + LinkedTweaks.LinkInfo(sliderHUDOpacity, toolTip, hudOpacityTweak); + LinkedTweaks.LinkInfo(labelHUDOpacity, toolTip, hudOpacityTweak); + + LinkedTweaks.LinkInfo(checkBoxEnableQuestAutoTrackMain, toolTip, autoTrackMainQuestWhenStartedTweak); + LinkedTweaks.LinkInfo(checkBoxEnableQuestAutoTrackSide, toolTip, autoTrackSideQuestWhenStartedTweak); + LinkedTweaks.LinkInfo(checkBoxEnableQuestAutoTrackMisc, toolTip, autoTrackMiscQuestWhenStartedTweak); + LinkedTweaks.LinkInfo(checkBoxEnableQuestAutoTrackEvent, toolTip, autoTrackEventQuestWhenStartedTweak); + LinkedTweaks.LinkInfo(checkBoxEnableQuestAutoTrackDaily, toolTip, autoTrackOtherQuestWhenStartedTweak); + + // Video tab + LinkedTweaks.LinkInfo(numCustomResW, toolTip, displaySizeTweak); + LinkedTweaks.LinkInfo(numCustomResH, toolTip, displaySizeTweak); + LinkedTweaks.LinkInfo(labelResolution, toolTip, displaySizeTweak); + LinkedTweaks.LinkInfo(labelCustomResolution, toolTip, displaySizeTweak); + LinkedTweaks.LinkInfo(comboBoxResolution, toolTip, displaySizeTweak); + LinkedTweaks.LinkInfo(comboBoxDisplayMode, toolTip, displayModeTweak); + LinkedTweaks.LinkInfo(labelDisplayMode, toolTip, displayModeTweak); + LinkedTweaks.LinkInfo(checkBoxVSync, toolTip, presentIntervalTweak); + LinkedTweaks.LinkInfo(checkBoxAlwaysActive, toolTip, windowAlwaysActiveTweak); + LinkedTweaks.LinkInfo(checkBoxTopMostWindow, toolTip, topMostWindowTweak); + LinkedTweaks.LinkInfo(checkBoxFixHUDFor5_4and4_3, toolTip, fixHUD4to3RatioTweak); + + // Graphics: + LinkedTweaks.LinkInfo(labelAntiAliasing, toolTip, antiAliasingTweak); + LinkedTweaks.LinkInfo(comboBoxAntiAliasing, toolTip, antiAliasingTweak); + LinkedTweaks.LinkInfo(labelAnisotropicFiltering, toolTip, anisotropicFilteringTweak); + LinkedTweaks.LinkInfo(comboBoxAnisotropicFiltering, toolTip, anisotropicFilteringTweak); + LinkedTweaks.LinkInfo(checkBoxDepthOfField, toolTip, enableDepthOfFieldTweak); + LinkedTweaks.LinkInfo(checkBoxMotionBlur, toolTip, motionBlurTweak); + LinkedTweaks.LinkInfo(checkBoxRadialBlur, toolTip, radialBlurTweak); + LinkedTweaks.LinkInfo(checkBoxLensFlare, toolTip, lensFlareTweak); + LinkedTweaks.LinkInfo(checkBoxAmbientOcclusion, toolTip, ambientOcclusionTweak); + LinkedTweaks.LinkInfo(checkBoxWaterDisplacement, toolTip, waterDisplacementsTweak); + LinkedTweaks.LinkInfo(checkBoxFogEnabled, toolTip, fogTweak); + LinkedTweaks.LinkInfo(checkBoxWeatherRainOcclusion, toolTip, rainOcclusionTweak); + LinkedTweaks.LinkInfo(checkBoxWeatherWetnessOcclusion, toolTip, wetnessOcclusionTweak); + LinkedTweaks.LinkInfo(checkBoxGodrays, toolTip, volumetricLightingTweak); + LinkedTweaks.LinkInfo(checkBoxDisableGore, toolTip, disableAllGoreTweak); + LinkedTweaks.LinkInfo(labelShadowTextureResolution, toolTip, shadowMapResolutionTweak); + LinkedTweaks.LinkInfo(comboBoxShadowTextureResolution, toolTip, shadowMapResolutionTweak); + LinkedTweaks.LinkInfo(comboBoxShadowBlurriness, toolTip, shadowBlurrinessTweak); + LinkedTweaks.LinkInfo(labelShadowBlurriness, toolTip, shadowBlurrinessTweak); + LinkedTweaks.LinkInfo(numShadowDistance, toolTip, shadowDistanceTweak); + LinkedTweaks.LinkInfo(sliderShadowDistance, toolTip, shadowDistanceTweak); + LinkedTweaks.LinkInfo(numLODObjects, toolTip, lodFadeOutMultObjectsTweak); + LinkedTweaks.LinkInfo(numLODItems, toolTip, lodFadeOutMultItemsTweak); + LinkedTweaks.LinkInfo(numLODActors, toolTip, lodFadeOutMultActorsTweak); + LinkedTweaks.LinkInfo(sliderLODObjects, toolTip, lodFadeOutMultObjectsTweak); + LinkedTweaks.LinkInfo(sliderLODItems, toolTip, lodFadeOutMultItemsTweak); + LinkedTweaks.LinkInfo(sliderLODActors, toolTip, lodFadeOutMultActorsTweak); + LinkedTweaks.LinkInfo(checkBoxGrass, toolTip, enableGrassTweak); + LinkedTweaks.LinkInfo(comboBoxiDirShadowSplits, toolTip, dirShadowSplitsTweak); + LinkedTweaks.LinkInfo(labeliDirShadowSplits, toolTip, dirShadowSplitsTweak); + LinkedTweaks.LinkInfo(numfBlendSplitDirShadow, toolTip, blendSplitDirShadowTweak); + LinkedTweaks.LinkInfo(sliderfBlendSplitDirShadow, toolTip, blendSplitDirShadowTweak); + LinkedTweaks.LinkInfo(numTAAPostOverlay, toolTip, taaPostOverlayTweak); + LinkedTweaks.LinkInfo(numTAAPostSharpen, toolTip, taaPostSharpenTweak); + LinkedTweaks.LinkInfo(sliderTAAPostOverlay, toolTip, taaPostOverlayTweak); + LinkedTweaks.LinkInfo(sliderTAAPostSharpen, toolTip, taaPostSharpenTweak); + LinkedTweaks.LinkInfo(checkBoxScreenSpaceReflections, toolTip, screenSpaceReflectionsTweak); + LinkedTweaks.LinkInfo(numGrassFadeDistance, toolTip, grassFadeDistanceTweak); + + // Audio tab + LinkedTweaks.LinkInfo(checkBoxEnableAudio, toolTip, enableAudioTweak); + LinkedTweaks.LinkInfo(checkBoxMainMenuMusic, toolTip, playMainMenuMusicTweak); + LinkedTweaks.LinkInfo(comboBoxVoiceChatMode, toolTip, voiceChatModeTweak); + LinkedTweaks.LinkInfo(labelVoiceChatMode, toolTip, voiceChatModeTweak); + LinkedTweaks.LinkInfo(checkBoxGeneralSubtitles, toolTip, generalSubtitlesTweak); + LinkedTweaks.LinkInfo(checkBoxDialogueSubtitles, toolTip, dialogueSubtitlesTweak); + LinkedTweaks.LinkInfo(checkBoxDialogueHistory, toolTip, showDialogueHistoryTweak); + LinkedTweaks.LinkInfo(checkBoxPushToTalk, toolTip, voicePushToTalkEnabledTweak); + LinkedTweaks.LinkInfo(numConversationHistorySize, toolTip, conversationHistorySizeTweak); + LinkedTweaks.LinkInfo(sliderConversationHistorySize, toolTip, conversationHistorySizeTweak); + LinkedTweaks.LinkInfo(labelConversationHistorySize, toolTip, conversationHistorySizeTweak); + LinkedTweaks.LinkInfo(numVolumeMaster, toolTip, masterVolumeTweak); + LinkedTweaks.LinkInfo(numAudioChat, toolTip, vivoxVoiceVolumeTweak); + LinkedTweaks.LinkInfo(sliderVolumeMaster, toolTip, masterVolumeTweak); + LinkedTweaks.LinkInfo(sliderAudioChat, toolTip, vivoxVoiceVolumeTweak); + + // Volume: + LinkedTweaks.LinkInfo(labelVolumeMaster, toolTip, masterVolumeTweak); + LinkedTweaks.LinkInfo(labelAudioChat, toolTip, vivoxVoiceVolumeTweak); + + LinkedTweaks.LinkInfo(numAudiofVal0, toolTip, val0Tweak); + LinkedTweaks.LinkInfo(numAudiofVal1, toolTip, val1Tweak); + LinkedTweaks.LinkInfo(numAudiofVal2, toolTip, val2Tweak); + LinkedTweaks.LinkInfo(numAudiofVal3, toolTip, val3Tweak); + LinkedTweaks.LinkInfo(numAudiofVal4, toolTip, val4Tweak); + LinkedTweaks.LinkInfo(numAudiofVal5, toolTip, val5Tweak); + LinkedTweaks.LinkInfo(numAudiofVal6, toolTip, val6Tweak); + LinkedTweaks.LinkInfo(sliderAudiofVal0, toolTip, val0Tweak); + LinkedTweaks.LinkInfo(sliderAudiofVal1, toolTip, val1Tweak); + LinkedTweaks.LinkInfo(sliderAudiofVal2, toolTip, val2Tweak); + LinkedTweaks.LinkInfo(sliderAudiofVal3, toolTip, val3Tweak); + LinkedTweaks.LinkInfo(sliderAudiofVal4, toolTip, val4Tweak); + LinkedTweaks.LinkInfo(sliderAudiofVal5, toolTip, val5Tweak); + LinkedTweaks.LinkInfo(sliderAudiofVal6, toolTip, val6Tweak); + + // Controls tab + LinkedTweaks.LinkInfo(numMouseSensitivity, toolTip, mouseSensitivityTweak); + LinkedTweaks.LinkInfo(sliderMouseSensitivity, toolTip, mouseSensitivityTweak); + LinkedTweaks.LinkInfo(checkBoxFixMouseSensitivity, toolTip, fixMouseSensitivityTweak); + LinkedTweaks.LinkInfo(checkBoxFixAimSensitivity, toolTip, fixAimSensitivityTweak); + LinkedTweaks.LinkInfo(checkBoxMouseAcceleration, toolTip, mouseAccelerationTweak); + LinkedTweaks.LinkInfo(checkBoxMouseInvertX, toolTip, mouseInvertXTweak); + LinkedTweaks.LinkInfo(checkBoxMouseInvertY, toolTip, mouseInvertYTweak); + LinkedTweaks.LinkInfo(checkBoxGamepadEnabled, toolTip, gamepadEnableTweak); + LinkedTweaks.LinkInfo(checkBoxGamepadRumble, toolTip, enableGamepadRumbleTweak); + + // Camera tab + LinkedTweaks.LinkInfo(this.checkBoxbApplyCameraNodeAnimations, toolTip, applyCameraNodeAnimationsTweak); + LinkedTweaks.LinkInfo(this.numfOverShoulderPosX, toolTip, cameraOverShoulderPosXTweak); + LinkedTweaks.LinkInfo(this.numfOverShoulderPosZ, toolTip, cameraOverShoulderPosZTweak); + LinkedTweaks.LinkInfo(this.numfOverShoulderCombatPosX, toolTip, cameraOverShoulderCombatPosXTweak); + LinkedTweaks.LinkInfo(this.numfOverShoulderCombatPosZ, toolTip, cameraOverShoulderCombatPosZTweak); + LinkedTweaks.LinkInfo(this.numfOverShoulderCombatAddY, toolTip, cameraOverShoulderCombatAddYTweak); + LinkedTweaks.LinkInfo(this.numfOverShoulderMeleeCombatPosX, toolTip, cameraOverShoulderMeleeCombatPosXTweak); + LinkedTweaks.LinkInfo(this.numfOverShoulderMeleeCombatPosZ, toolTip, cameraOverShoulderMeleeCombatPosZTweak); + LinkedTweaks.LinkInfo(this.numfOverShoulderMeleeCombatAddY, toolTip, cameraOverShoulderMeleeCombatAddYTweak); + LinkedTweaks.LinkInfo(this.trackBarfOverShoulderPosX, toolTip, cameraOverShoulderPosXTweak); + LinkedTweaks.LinkInfo(this.trackBarfOverShoulderPosZ, toolTip, cameraOverShoulderPosZTweak); + LinkedTweaks.LinkInfo(this.trackBarfOverShoulderCombatPosX, toolTip, cameraOverShoulderCombatPosXTweak); + LinkedTweaks.LinkInfo(this.trackBarfOverShoulderCombatPosZ, toolTip, cameraOverShoulderCombatPosZTweak); + LinkedTweaks.LinkInfo(this.trackBarfOverShoulderCombatAddY, toolTip, cameraOverShoulderCombatAddYTweak); + LinkedTweaks.LinkInfo(this.trackBarfOverShoulderMeleeCombatPosX, toolTip, cameraOverShoulderMeleeCombatPosXTweak); + LinkedTweaks.LinkInfo(this.trackBarfOverShoulderMeleeCombatPosZ, toolTip, cameraOverShoulderMeleeCombatPosZTweak); + LinkedTweaks.LinkInfo(this.trackBarfOverShoulderMeleeCombatAddY, toolTip, cameraOverShoulderMeleeCombatAddYTweak); + LinkedTweaks.LinkInfo(this.numericUpDownPhotomodeRange, toolTip, selfieModeRangeTweak); + LinkedTweaks.LinkInfo(this.numericUpDownPhotomodeTranslationSpeed, toolTip, selfieCameraTranslationSpeedTweak); + LinkedTweaks.LinkInfo(this.numericUpDownPhotomodeRotationSpeed, toolTip, selfieCameraRotationSpeedTweak); + LinkedTweaks.LinkInfo(this.labelPhotomodeRange, toolTip, selfieModeRangeTweak); + LinkedTweaks.LinkInfo(this.labelPhotomodeTranslationSpeed, toolTip, selfieCameraTranslationSpeedTweak); + LinkedTweaks.LinkInfo(this.labelPhotomodeRotationSpeed, toolTip, selfieCameraRotationSpeedTweak); + LinkedTweaks.LinkInfo(this.trackBarPhotomodeRange, toolTip, selfieModeRangeTweak); + LinkedTweaks.LinkInfo(this.trackBarPhotomodeTranslationSpeed, toolTip, selfieCameraTranslationSpeedTweak); + LinkedTweaks.LinkInfo(this.trackBarPhotomodeRotationSpeed, toolTip, selfieCameraRotationSpeedTweak); + LinkedTweaks.LinkInfo(this.checkBoxVanityMode, toolTip, disableAutoVanityModeTweak); + LinkedTweaks.LinkInfo(this.checkBoxForceVanityMode, toolTip, forceAutoVanityModeTweak); + LinkedTweaks.LinkInfo(this.numCameraSwitchDelay, toolTip, firstThirdPerspectiveSwitchDelayTweak); + LinkedTweaks.LinkInfo(this.labelSwitchDelay, toolTip, firstThirdPerspectiveSwitchDelayTweak); + LinkedTweaks.LinkInfo(numFirstPersonFOV, toolTip, fov1stPersonTweak); + LinkedTweaks.LinkInfo(numWorldFOV, toolTip, fov3rdPersonTweak); + LinkedTweaks.LinkInfo(numADSFOV, toolTip, fov3rdADSTweak); + LinkedTweaks.LinkInfo(numfDefaultFOV, toolTip, defaultFOVTweak); + LinkedTweaks.LinkInfo(labelFirstPersonFOV, toolTip, fov1stPersonTweak); + LinkedTweaks.LinkInfo(labelWorldFOV, toolTip, fov3rdPersonTweak); + LinkedTweaks.LinkInfo(labelADSFOV, toolTip, fov3rdADSTweak); + LinkedTweaks.LinkInfo(labelfDefaultFOV, toolTip, defaultFOVTweak); + LinkedTweaks.LinkInfo(numCameraDistanceMinimum, toolTip, vanityModeMinDistTweak); + LinkedTweaks.LinkInfo(numCameraDistanceMaximum, toolTip, vanityModeMaxDistTweak); + LinkedTweaks.LinkInfo(numfPitchZoomOutMaxDist, toolTip, pitchZoomOutMaxDistTweak); + LinkedTweaks.LinkInfo(labelCameraDistanceMinimum, toolTip, vanityModeMinDistTweak); + LinkedTweaks.LinkInfo(labelCameraDistanceMaximum, toolTip, vanityModeMaxDistTweak); + LinkedTweaks.LinkInfo(labelPitchZoomOutMaxDist, toolTip, pitchZoomOutMaxDistTweak); + + // Pipboy tab + LinkedTweaks.LinkInfo(buttonColorPickPipboy, toolTip, pipboyColorTweak); + LinkedTweaks.LinkInfo(buttonColorPickQuickboy, toolTip, quickboyColorTweak); + LinkedTweaks.LinkInfo(buttonColorPickPAPipboy, toolTip, powerArmorPipboyColorTweak); + LinkedTweaks.LinkInfo(labelPipboyColor, toolTip, pipboyColorTweak); + LinkedTweaks.LinkInfo(labelQuickboyColor, toolTip, quickboyColorTweak); + LinkedTweaks.LinkInfo(labelPowerArmorColor, toolTip, powerArmorPipboyColorTweak); + LinkedTweaks.LinkInfo(numPipboyTargetHeight, toolTip, pipboyTargetResolutionTweak); + LinkedTweaks.LinkInfo(numPipboyTargetWidth, toolTip, pipboyTargetResolutionTweak); + LinkedTweaks.LinkInfo(radioButtonQuickboy, toolTip, quickboyModeEnabledTweak); + LinkedTweaks.LinkInfo(radioButtonPipboy, toolTip, quickboyModeEnabledTweak); + + // Gallery tab + LinkedTweaks.LinkInfo(numScreenshotIndex, toolTip, screenshotIndexTweak); + LinkedTweaks.LinkInfo(labelScreenshotIndex, toolTip, screenshotIndexTweak); + } + + /// + /// Links trackbars to numericupdowns (and vice-versa) + /// + public void LinkSliders() + { + // Link numericUpDown and sliders: + LinkedTweaks.LinkSlider(this.sliderGrassFadeDistance, this.numGrassFadeDistance, 1); + //LinkSlider(this.sliderGrassDensity, this.numGrassDensity, 1, true); + LinkedTweaks.LinkSlider(this.sliderLODObjects, this.numLODObjects, 10); + LinkedTweaks.LinkSlider(this.sliderLODItems, this.numLODItems, 10); + LinkedTweaks.LinkSlider(this.sliderLODActors, this.numLODActors, 10); + LinkedTweaks.LinkSlider(this.sliderShadowDistance, this.numShadowDistance, 1); + LinkedTweaks.LinkSlider(this.sliderfBlendSplitDirShadow, this.numfBlendSplitDirShadow, 0.0833333); + LinkedTweaks.LinkSlider(this.sliderMouseSensitivity, this.numMouseSensitivity, 10000.0); + LinkedTweaks.LinkSlider(this.sliderTAAPostOverlay, this.numTAAPostOverlay, 100); + LinkedTweaks.LinkSlider(this.sliderTAAPostSharpen, this.numTAAPostSharpen, 100); + + LinkedTweaks.LinkSlider(this.sliderVolumeMaster, this.numVolumeMaster, 100); + LinkedTweaks.LinkSlider(this.sliderAudioChat, this.numAudioChat, 1); + LinkedTweaks.LinkSlider(this.sliderAudiofVal0, this.numAudiofVal0, 100); + LinkedTweaks.LinkSlider(this.sliderAudiofVal1, this.numAudiofVal1, 100); + LinkedTweaks.LinkSlider(this.sliderAudiofVal2, this.numAudiofVal2, 100); + LinkedTweaks.LinkSlider(this.sliderAudiofVal3, this.numAudiofVal3, 100); + LinkedTweaks.LinkSlider(this.sliderAudiofVal4, this.numAudiofVal4, 100); + LinkedTweaks.LinkSlider(this.sliderAudiofVal5, this.numAudiofVal5, 100); + LinkedTweaks.LinkSlider(this.sliderAudiofVal6, this.numAudiofVal6, 100); + + LinkedTweaks.LinkSlider(this.sliderFloatingQuestMarkersDistance, this.numFloatingQuestMarkersDistance, 10); + LinkedTweaks.LinkSlider(this.sliderConversationHistorySize, this.numConversationHistorySize, 1); + LinkedTweaks.LinkSlider(this.sliderHUDOpacity, this.numHUDOpacity, 100); + + LinkedTweaks.LinkSlider(this.sliderCameraDistanceMinimum, this.numCameraDistanceMinimum, 1); + LinkedTweaks.LinkSlider(this.sliderCameraDistanceMaximum, this.numCameraDistanceMaximum, 1); + LinkedTweaks.LinkSlider(this.sliderfPitchZoomOutMaxDist, this.numfPitchZoomOutMaxDist, 1); + + LinkedTweaks.LinkSlider(this.trackBarPhotomodeTranslationSpeed, this.numericUpDownPhotomodeTranslationSpeed, 10); + LinkedTweaks.LinkSlider(this.trackBarPhotomodeRotationSpeed, this.numericUpDownPhotomodeRotationSpeed, 10); + LinkedTweaks.LinkSlider(this.trackBarPhotomodeRange, this.numericUpDownPhotomodeRange, 1); + + + LinkedTweaks.LinkSlider(this.trackBarfOverShoulderPosX, this.numfOverShoulderPosX, 1); + LinkedTweaks.LinkSlider(this.trackBarfOverShoulderPosZ, this.numfOverShoulderPosZ, 1); + LinkedTweaks.LinkSlider(this.trackBarfOverShoulderCombatPosX, this.numfOverShoulderCombatPosX, 1); + LinkedTweaks.LinkSlider(this.trackBarfOverShoulderCombatPosZ, this.numfOverShoulderCombatPosZ, 1); + LinkedTweaks.LinkSlider(this.trackBarfOverShoulderCombatAddY, this.numfOverShoulderCombatAddY, 1); + LinkedTweaks.LinkSlider(this.trackBarfOverShoulderMeleeCombatPosX, this.numfOverShoulderMeleeCombatPosX, 1); + LinkedTweaks.LinkSlider(this.trackBarfOverShoulderMeleeCombatPosZ, this.numfOverShoulderMeleeCombatPosZ, 1); + LinkedTweaks.LinkSlider(this.trackBarfOverShoulderMeleeCombatAddY, this.numfOverShoulderMeleeCombatAddY, 1); + } + + /// + /// Link controls to tweaks, that means: + /// -> If a control's value changes, change the value of a tweak. + /// -> If the UI is being (re)loaded, set each value according to that of the linked tweak. + /// + public void LinkControlsToTweaks() + { + /* + * Info tab + */ + + // Make *.ini files read-only + /*LinkedTweaks.LinkTweak(checkBoxReadOnly, iniReadOnlyTweak); + + // Automatically apply changes when tool is closed or game is launched + LinkedTweaks.LinkTweak(checkBoxAutoApply, autoApplyTweak); + + // Don't check for updates on startup. + LinkedTweaks.LinkTweak(checkBoxIgnoreUpdates, ignoreUpdatesTweak); + + // Play notification sounds + LinkedTweaks.LinkTweak(checkBoxPlayNotificationSound, playNotificationSoundsTweak); + + // Close the tool when the game is launched. + LinkedTweaks.LinkTweak(checkBoxQuitOnGameLaunch, toolQuitOnLaunchTweak);*/ + + + + /* + * General tab + */ + + // Enable Steam + LinkedTweaks.LinkTweak(checkBoxEnableSteam, enableSteamTweak); + + // Automatically sign-in + LinkedTweaks.LinkTweak(checkBoxAutoSignin, autoSigninTweak); + + // Play intro videos + LinkedTweaks.LinkTweak(checkBoxIntroVideos, introVideoTweak); + + + // Show splash screen with news on startup + LinkedTweaks.LinkTweak(checkBoxSkipSplash, skipStartupSplash); + + // Show damage numbers in Nuclear Winter + LinkedTweaks.LinkTweak(checkBoxShowDamageNumbersNW, showDamageNumbersNuclearWinterTweak); + + // Show damage numbers in Adventure mode + LinkedTweaks.LinkTweak(checkBoxShowDamageNumbersA, showDamageNumbersAdventureTweak); + + // Show item rarity colors + LinkedTweaks.LinkTweak(checkBoxItemRarityColorsNW, enableItemRarityColorsTweak); + + // Show Public Team Notifications + LinkedTweaks.LinkTweak(checkBoxShowPublicTeamNotifications, showPublicTeamNotificationsTweak); + + // Show Floating Quest Markers + LinkedTweaks.LinkTweak(checkBoxShowFloatingQuestMarkers, showFloatingQuestMarkersTweak); + + // Show Floating Quest Text + LinkedTweaks.LinkTweak(checkBoxShowFloatingQuestText, showFloatingQuestTextTweak); + + // Show crosshair + LinkedTweaks.LinkTweak(checkBoxShowCrosshair, showCrosshairTweak); + + // Enable Power Armor HUD + LinkedTweaks.LinkTweak(checkBoxEnablePowerArmorHUD, enablePowerArmorHUDTweak); + + // Show compass + LinkedTweaks.LinkTweak(checkBoxShowCompass, showCompassTweak); + + // Show Other Players' Names + LinkedTweaks.LinkTweak(checkBoxShowOtherPlayersNames, showOtherPlayersNamesTweak); + + // Show active effects on HUD + LinkedTweaks.LinkTweak(comboBoxShowActiveEffectsOnHUD, activeEffectsOnHUDTweak); + + // Floating Quest Markers Draw Distance + LinkedTweaks.LinkTweak(numFloatingQuestMarkersDistance, floatingQuestMarkersDistanceTweak); + + // HUD Opacity + LinkedTweaks.LinkTweak(numHUDOpacity, hudOpacityTweak); + + + // XYZ Quest Active when started + LinkedTweaks.LinkTweak(checkBoxEnableQuestAutoTrackMain, autoTrackMainQuestWhenStartedTweak); + LinkedTweaks.LinkTweak(checkBoxEnableQuestAutoTrackSide, autoTrackSideQuestWhenStartedTweak); + LinkedTweaks.LinkTweak(checkBoxEnableQuestAutoTrackMisc, autoTrackMiscQuestWhenStartedTweak); + LinkedTweaks.LinkTweak(checkBoxEnableQuestAutoTrackEvent, autoTrackEventQuestWhenStartedTweak); + LinkedTweaks.LinkTweak(checkBoxEnableQuestAutoTrackDaily, autoTrackOtherQuestWhenStartedTweak); + + + + /* + * Video tab + */ + + // Custom resolution + LinkedTweaks.LinkSize(numCustomResW, numCustomResH, displaySizeTweak); + + // Display mode + LinkedTweaks.LinkTweak(comboBoxDisplayMode, displayModeTweak); + + // iPresentInterval + LinkedTweaks.LinkTweak(checkBoxVSync, presentIntervalTweak); + + // Always active + LinkedTweaks.LinkTweak(checkBoxAlwaysActive, windowAlwaysActiveTweak); + + // Top most window + LinkedTweaks.LinkTweak(checkBoxTopMostWindow, topMostWindowTweak); + + // Fix HUD for 5:4 and 4:3 screens + LinkedTweaks.LinkTweak(checkBoxFixHUDFor5_4and4_3, fixHUD4to3RatioTweak); + + + + /* + * Graphics + */ + + // Anti aliasing + LinkedTweaks.LinkTweak(comboBoxAntiAliasing, antiAliasingTweak); + + // Anisotropic filtering + LinkedTweaks.LinkTweak( + comboBoxAnisotropicFiltering, + new int[] { 0, 2, 4, 8, 16 }, + anisotropicFilteringTweak); + + // Depth of Field + LinkedTweaks.LinkTweak(checkBoxDepthOfField, enableDepthOfFieldTweak); + + // Motion Blur + LinkedTweaks.LinkTweak(checkBoxMotionBlur, motionBlurTweak); + + // Radial Blur + LinkedTweaks.LinkTweak(checkBoxRadialBlur, radialBlurTweak); + + // Lens Flare + LinkedTweaks.LinkTweak(checkBoxLensFlare, lensFlareTweak); + + // Ambient Occlusion + LinkedTweaks.LinkTweak(checkBoxAmbientOcclusion, ambientOcclusionTweak); + + // Water / Displacement + LinkedTweaks.LinkTweak(checkBoxWaterDisplacement, waterDisplacementsTweak); + + // Weather / Fog + LinkedTweaks.LinkTweak(checkBoxFogEnabled, fogTweak); + + // Weather / Rain Occlusion + LinkedTweaks.LinkTweak(checkBoxWeatherRainOcclusion, rainOcclusionTweak); + + // Weather / Wetness Occlusion + LinkedTweaks.LinkTweak(checkBoxWeatherWetnessOcclusion, wetnessOcclusionTweak); + + // Lighting / Volumetric Lighting + LinkedTweaks.LinkTweak(checkBoxGodrays, volumetricLightingTweak); + + // Effects / Disable gore + LinkedTweaks.LinkTweak(checkBoxDisableGore, disableAllGoreTweak); + + // Shadow texture map resolution + LinkedTweaks.LinkTweak( + comboBoxShadowTextureResolution, + new int[] { 512, 1024, 2048, 4096 }, + shadowMapResolutionTweak); + + // Shadows / Blurriness + LinkedTweaks.LinkTweak( + comboBoxShadowBlurriness, + new int[] { 1, 2, 3 }, + shadowBlurrinessTweak); + + // Shadow distance + LinkedTweaks.LinkTweak(numShadowDistance, shadowDistanceTweak); + + // Enable grass + LinkedTweaks.LinkTweak(checkBoxGrass, enableGrassTweak); + + // Grass fade distance + LinkedTweaks.LinkTweak(numGrassFadeDistance, grassFadeDistanceTweak); + + // LOD Fade Distances + LinkedTweaks.LinkTweak(numLODObjects, lodFadeOutMultObjectsTweak); + LinkedTweaks.LinkTweak(numLODItems, lodFadeOutMultItemsTweak); + LinkedTweaks.LinkTweak(numLODActors, lodFadeOutMultActorsTweak); + + // TAA Sharpening + LinkedTweaks.LinkTweak(numTAAPostOverlay, taaPostOverlayTweak); + LinkedTweaks.LinkTweak(numTAAPostSharpen, taaPostSharpenTweak); + + + + /* + * Audio tab + */ + + // Enable audio + LinkedTweaks.LinkTweak(checkBoxEnableAudio, enableAudioTweak); + + // Play music in main menu + LinkedTweaks.LinkTweak(checkBoxMainMenuMusic, playMainMenuMusicTweak); + + + // Voice Chat Mode + LinkedTweaks.LinkTweak(comboBoxVoiceChatMode, voiceChatModeTweak); + + // Push-To-Talk + LinkedTweaks.LinkTweak(checkBoxPushToTalk, voicePushToTalkEnabledTweak); + + + // General subtitles + LinkedTweaks.LinkTweak(checkBoxGeneralSubtitles, generalSubtitlesTweak); + + // Dialogue subtitles + LinkedTweaks.LinkTweak(checkBoxDialogueSubtitles, dialogueSubtitlesTweak); + + // Dialogue history + LinkedTweaks.LinkTweak(checkBoxDialogueHistory, showDialogueHistoryTweak); + + // Conversation History Size + LinkedTweaks.LinkTweak(numConversationHistorySize, conversationHistorySizeTweak); + + + // Master volume + LinkedTweaks.LinkTweak(numVolumeMaster, masterVolumeTweak); + + // Voice chat volume + LinkedTweaks.LinkTweak(numAudioChat, vivoxVoiceVolumeTweak); + + // Audio menu: + LinkedTweaks.LinkTweak(numAudiofVal0, val0Tweak); + LinkedTweaks.LinkTweak(numAudiofVal1, val1Tweak); + LinkedTweaks.LinkTweak(numAudiofVal2, val2Tweak); + LinkedTweaks.LinkTweak(numAudiofVal3, val3Tweak); + LinkedTweaks.LinkTweak(numAudiofVal4, val4Tweak); + LinkedTweaks.LinkTweak(numAudiofVal5, val5Tweak); + LinkedTweaks.LinkTweak(numAudiofVal6, val6Tweak); + + + + /* + * Controls tab + */ + + // Mouse sensitivity + LinkedTweaks.LinkTweak(numMouseSensitivity, mouseSensitivityTweak); + + // Fix mouse sensitivity + LinkedTweaks.LinkTweak(checkBoxFixMouseSensitivity, fixMouseSensitivityTweak); + + // Fix aim sensitivity + LinkedTweaks.LinkTweak(checkBoxFixAimSensitivity, fixAimSensitivityTweak); + + // Mouse acceleration + LinkedTweaks.LinkTweak(checkBoxMouseAcceleration, mouseAccelerationTweak); + + // Invert mouse: + LinkedTweaks.LinkTweak(checkBoxMouseInvertX, mouseInvertXTweak); + LinkedTweaks.LinkTweak(checkBoxMouseInvertY, mouseInvertYTweak); + + // Gamepad enabled + LinkedTweaks.LinkTweak(checkBoxGamepadEnabled, gamepadEnableTweak); + + // Vibration + LinkedTweaks.LinkTweak(checkBoxGamepadRumble, enableGamepadRumbleTweak); + + + + /* + * Pipboy tab + */ + + // Pipboy color + LinkedTweaks.LinkColor( + buttonColorPickPipboy, // "Pick color" button + buttonColorResetPipboy, // "Reset" button + colorDialog, // The color picking dialog that should open when clicking on "Pick color" + colorPreviewPipboy, // The little, colored square that is left to the label. + pipboyColorTweak); + + // Quickboy color + LinkedTweaks.LinkColor( + buttonColorPickQuickboy, + buttonColorResetQuickboy, + colorDialog, + colorPreviewQuickboy, + quickboyColorTweak); + + // Power Armor Pipboy color + LinkedTweaks.LinkColor( + buttonColorPickPAPipboy, + buttonColorResetPAPipboy, + colorDialog, + colorPreviewPAPipboy, + powerArmorPipboyColorTweak); + + // Radiobuttons, Quickboy or Pipboy mode + LinkedTweaks.LinkTweak(this.radioButtonQuickboy, this.radioButtonPipboy, quickboyModeEnabledTweak); + + // Pipboy resolution + LinkedTweaks.LinkSize(numPipboyTargetWidth, numPipboyTargetHeight, pipboyTargetResolutionTweak); + + + + /* + * Camera tab + */ + + // 1st person FOV + LinkedTweaks.LinkTweak(numFirstPersonFOV, fov1stPersonTweak); + + // World FOV + LinkedTweaks.LinkTweak(numWorldFOV, fov3rdPersonTweak); + + // 3rd person ADS FOV + LinkedTweaks.LinkTweak(numADSFOV, fov3rdADSTweak); + + // fDefaultFOV + LinkedTweaks.LinkTweak(numfDefaultFOV, defaultFOVTweak); + + // Camera distance + LinkedTweaks.LinkTweak(numCameraDistanceMinimum, vanityModeMinDistTweak); + LinkedTweaks.LinkTweak(numCameraDistanceMaximum, vanityModeMaxDistTweak); + + // fPitchZoomOutMaxDist + LinkedTweaks.LinkTweak(numfPitchZoomOutMaxDist, pitchZoomOutMaxDistTweak); + + // Switch delay + LinkedTweaks.LinkTweak(this.numCameraSwitchDelay, firstThirdPerspectiveSwitchDelayTweak); + + // Photomode options: + LinkedTweaks.LinkTweak(this.numericUpDownPhotomodeRange, selfieModeRangeTweak); + LinkedTweaks.LinkTweak(this.numericUpDownPhotomodeTranslationSpeed, selfieCameraTranslationSpeedTweak); + LinkedTweaks.LinkTweak(this.numericUpDownPhotomodeRotationSpeed, selfieCameraRotationSpeedTweak); + + // Vanity mode + LinkedTweaks.LinkTweakNegated(this.checkBoxVanityMode, disableAutoVanityModeTweak); + LinkedTweaks.LinkTweak(this.checkBoxForceVanityMode, forceAutoVanityModeTweak); + + // bApplyCameraNodeAnimations + LinkedTweaks.LinkTweak(this.checkBoxbApplyCameraNodeAnimations, applyCameraNodeAnimationsTweak); + + // OverShoulder sliders: + LinkedTweaks.LinkTweak(this.numfOverShoulderPosX, cameraOverShoulderPosXTweak); + LinkedTweaks.LinkTweak(this.numfOverShoulderPosZ, cameraOverShoulderPosZTweak); + LinkedTweaks.LinkTweak(this.numfOverShoulderCombatPosX, cameraOverShoulderCombatPosXTweak); + LinkedTweaks.LinkTweak(this.numfOverShoulderCombatPosZ, cameraOverShoulderCombatPosZTweak); + LinkedTweaks.LinkTweak(this.numfOverShoulderCombatAddY, cameraOverShoulderCombatAddYTweak); + LinkedTweaks.LinkTweak(this.numfOverShoulderMeleeCombatPosX, cameraOverShoulderMeleeCombatPosXTweak); + LinkedTweaks.LinkTweak(this.numfOverShoulderMeleeCombatPosZ, cameraOverShoulderMeleeCombatPosZTweak); + LinkedTweaks.LinkTweak(this.numfOverShoulderMeleeCombatAddY, cameraOverShoulderMeleeCombatAddYTweak); + + + + /* + * Gallery tab + */ + + // Screenshot index + LinkedTweaks.LinkTweak(numScreenshotIndex, screenshotIndexTweak); + } + + + public void LinkDangerZoneControls () + { + // Screen Space Reflections: + LinkedTweaks.LinkTweak(checkBoxScreenSpaceReflections, screenSpaceReflectionsTweak); + + // Amount of shadow "segments": iDirShadowSplits + LinkedTweaks.LinkTweak( + comboBoxiDirShadowSplits, + new int[] { 1, 2, 3 }, + dirShadowSplitsTweak); + + // BlendSplitDirShadowTweak / Shadow "segment" transition distance + LinkedTweaks.LinkTweak(numfBlendSplitDirShadow, blendSplitDirShadowTweak); + } + + + /* + * Define and instantiate all tweaks: + */ + + // Info tab + /*private INIReadOnlyTweak iniReadOnlyTweak = new INIReadOnlyTweak(); + private AutoApplyTweak autoApplyTweak = new AutoApplyTweak(); + private IgnoreUpdatesTweak ignoreUpdatesTweak = new IgnoreUpdatesTweak(); + private PlayNotificationSoundsTweak playNotificationSoundsTweak = new PlayNotificationSoundsTweak(); + private ToolQuitOnLaunchTweak toolQuitOnLaunchTweak = new ToolQuitOnLaunchTweak();*/ + + // General tab + private EnableSteamTweak enableSteamTweak = new EnableSteamTweak(); + private AutoSigninTweak autoSigninTweak = new AutoSigninTweak(); + private IntroVideoTweak introVideoTweak = new IntroVideoTweak(); + private SkipStartupSplash skipStartupSplash = new SkipStartupSplash(); + + private ShowDamageNumbersNuclearWinterTweak showDamageNumbersNuclearWinterTweak = new ShowDamageNumbersNuclearWinterTweak(); + private ShowDamageNumbersAdventureTweak showDamageNumbersAdventureTweak = new ShowDamageNumbersAdventureTweak(); + private EnableItemRarityColorsTweak enableItemRarityColorsTweak = new EnableItemRarityColorsTweak(); + private ShowPublicTeamNotificationsTweak showPublicTeamNotificationsTweak = new ShowPublicTeamNotificationsTweak(); + private ShowFloatingQuestMarkersTweak showFloatingQuestMarkersTweak = new ShowFloatingQuestMarkersTweak(); + private ShowFloatingQuestTextTweak showFloatingQuestTextTweak = new ShowFloatingQuestTextTweak(); + private ShowCompassTweak showCompassTweak = new ShowCompassTweak(); + private EnablePowerArmorHUDTweak enablePowerArmorHUDTweak = new EnablePowerArmorHUDTweak(); + private ShowCrosshairTweak showCrosshairTweak = new ShowCrosshairTweak(); + private ShowOtherPlayersNamesTweak showOtherPlayersNamesTweak = new ShowOtherPlayersNamesTweak(); + private ActiveEffectsOnHUDTweak activeEffectsOnHUDTweak = new ActiveEffectsOnHUDTweak(); + private FloatingQuestMarkersDistanceTweak floatingQuestMarkersDistanceTweak = new FloatingQuestMarkersDistanceTweak(); + private HUDOpacityTweak hudOpacityTweak = new HUDOpacityTweak(); + + private AutoTrackQuestWhenStartedTweak autoTrackMainQuestWhenStartedTweak = new AutoTrackQuestWhenStartedTweak("Main", "Main"); + private AutoTrackQuestWhenStartedTweak autoTrackSideQuestWhenStartedTweak = new AutoTrackQuestWhenStartedTweak("Side", "Side"); + private AutoTrackQuestWhenStartedTweak autoTrackMiscQuestWhenStartedTweak = new AutoTrackQuestWhenStartedTweak("Misc", "Miscellaneous"); + private AutoTrackQuestWhenStartedTweak autoTrackEventQuestWhenStartedTweak = new AutoTrackQuestWhenStartedTweak("Event", "Event"); + private AutoTrackQuestWhenStartedTweak autoTrackOtherQuestWhenStartedTweak = new AutoTrackQuestWhenStartedTweak("Other", "Daily"); + + // Video tab + private DisplaySizeTweak displaySizeTweak = new DisplaySizeTweak(); + private DisplayModeTweak displayModeTweak = new DisplayModeTweak(); + private PresentIntervalTweak presentIntervalTweak = new PresentIntervalTweak(); + private WindowAlwaysActiveTweak windowAlwaysActiveTweak = new WindowAlwaysActiveTweak(); + private TopMostWindowTweak topMostWindowTweak = new TopMostWindowTweak(); + private FixHUD4to3RatioTweak fixHUD4to3RatioTweak = new FixHUD4to3RatioTweak(); + + // Graphics + private AntiAliasingTweak antiAliasingTweak = new AntiAliasingTweak(); + private AnisotropicFilteringTweak anisotropicFilteringTweak = new AnisotropicFilteringTweak(); + private EnableDepthOfFieldTweak enableDepthOfFieldTweak = new EnableDepthOfFieldTweak(); + private MotionBlurTweak motionBlurTweak = new MotionBlurTweak(); + private RadialBlurTweak radialBlurTweak = new RadialBlurTweak(); + private LensFlareTweak lensFlareTweak = new LensFlareTweak(); + private AmbientOcclusionTweak ambientOcclusionTweak = new AmbientOcclusionTweak(); + private WaterDisplacementsTweak waterDisplacementsTweak = new WaterDisplacementsTweak(); + private FogTweak fogTweak = new FogTweak(); + private RainOcclusionTweak rainOcclusionTweak = new RainOcclusionTweak(); + private WetnessOcclusionTweak wetnessOcclusionTweak = new WetnessOcclusionTweak(); + private VolumetricLightingTweak volumetricLightingTweak = new VolumetricLightingTweak(); + private DisableAllGoreTweak disableAllGoreTweak = new DisableAllGoreTweak(); + private ShadowMapResolutionTweak shadowMapResolutionTweak = new ShadowMapResolutionTweak(); + private ShadowBlurrinessTweak shadowBlurrinessTweak = new ShadowBlurrinessTweak(); + private ShadowDistanceTweak shadowDistanceTweak = new ShadowDistanceTweak(); + private DirShadowSplitsTweak dirShadowSplitsTweak = new DirShadowSplitsTweak(); + private LODFadeOutMultObjectsTweak lodFadeOutMultObjectsTweak = new LODFadeOutMultObjectsTweak(); + private LODFadeOutMultItemsTweak lodFadeOutMultItemsTweak = new LODFadeOutMultItemsTweak(); + private LODFadeOutMultActorsTweak lodFadeOutMultActorsTweak = new LODFadeOutMultActorsTweak(); + private EnableGrassTweak enableGrassTweak = new EnableGrassTweak(); + private GrassFadeDistanceTweak grassFadeDistanceTweak = new GrassFadeDistanceTweak(); + private BlendSplitDirShadowTweak blendSplitDirShadowTweak = new BlendSplitDirShadowTweak(); + private TAAPostOverlayTweak taaPostOverlayTweak = new TAAPostOverlayTweak(); + private TAAPostSharpenTweak taaPostSharpenTweak = new TAAPostSharpenTweak(); + private ScreenSpaceReflectionsTweak screenSpaceReflectionsTweak = new ScreenSpaceReflectionsTweak(); + + // Audio tab + private EnableAudioTweak enableAudioTweak = new EnableAudioTweak(); + private PlayMainMenuMusicTweak playMainMenuMusicTweak = new PlayMainMenuMusicTweak(); + + private VoiceChatModeTweak voiceChatModeTweak = new VoiceChatModeTweak(); + private VoicePushToTalkEnabledTweak voicePushToTalkEnabledTweak = new VoicePushToTalkEnabledTweak(); + + private GeneralSubtitlesTweak generalSubtitlesTweak = new GeneralSubtitlesTweak(); + private DialogueSubtitlesTweak dialogueSubtitlesTweak = new DialogueSubtitlesTweak(); + private ShowDialogueHistoryTweak showDialogueHistoryTweak = new ShowDialogueHistoryTweak(); + private ConversationHistorySizeTweak conversationHistorySizeTweak = new ConversationHistorySizeTweak(); + + private MasterVolumeTweak masterVolumeTweak = new MasterVolumeTweak(); + private VivoxVoiceVolumeTweak vivoxVoiceVolumeTweak = new VivoxVoiceVolumeTweak(); + + private AudioMenuValTweak val0Tweak = new AudioMenuValTweak("0", "Menu Music"); + private AudioMenuValTweak val1Tweak = new AudioMenuValTweak("1", "World Radios"); + private AudioMenuValTweak val2Tweak = new AudioMenuValTweak("2", "Voice"); + private AudioMenuValTweak val3Tweak = new AudioMenuValTweak("3", "Music"); + private AudioMenuValTweak val4Tweak = new AudioMenuValTweak("4", "Effects"); + private AudioMenuValTweak val5Tweak = new AudioMenuValTweak("5", "Footsteps"); + private AudioMenuValTweak val6Tweak = new AudioMenuValTweak("6", "Pip-Boy Radio"); + + // Controls tab + private MouseSensitivityTweak mouseSensitivityTweak = new MouseSensitivityTweak(); + private FixMouseSensitivityTweak fixMouseSensitivityTweak = new FixMouseSensitivityTweak(); + private FixAimSensitivityTweak fixAimSensitivityTweak = new FixAimSensitivityTweak(); + private MouseAccelerationTweak mouseAccelerationTweak = new MouseAccelerationTweak(); + private MouseInvertXTweak mouseInvertXTweak = new MouseInvertXTweak(); + private MouseInvertYTweak mouseInvertYTweak = new MouseInvertYTweak(); + private GamepadEnableTweak gamepadEnableTweak = new GamepadEnableTweak(); + private EnableGamepadRumbleTweak enableGamepadRumbleTweak = new EnableGamepadRumbleTweak(); + + // Pipboy tab + private PipboyColorTweak pipboyColorTweak = new PipboyColorTweak(); + private QuickboyColorTweak quickboyColorTweak = new QuickboyColorTweak(); + private PowerArmorPipboyColorTweak powerArmorPipboyColorTweak = new PowerArmorPipboyColorTweak(); + + private QuickboyModeEnabledTweak quickboyModeEnabledTweak = new QuickboyModeEnabledTweak(); + private PipboyTargetResolutionTweak pipboyTargetResolutionTweak = new PipboyTargetResolutionTweak(); + + // Camera + private FOV1stPersonTweak fov1stPersonTweak = new FOV1stPersonTweak(); + private FOV3rdPersonTweak fov3rdPersonTweak = new FOV3rdPersonTweak(); + private FOV3rdADSTweak fov3rdADSTweak = new FOV3rdADSTweak(); + private DefaultFOVTweak defaultFOVTweak = new DefaultFOVTweak(); + + private VanityModeMinDistTweak vanityModeMinDistTweak = new VanityModeMinDistTweak(); + private VanityModeMaxDistTweak vanityModeMaxDistTweak = new VanityModeMaxDistTweak(); + private PitchZoomOutMaxDistTweak pitchZoomOutMaxDistTweak = new PitchZoomOutMaxDistTweak(); + + private FirstThirdPerspectiveSwitchDelayTweak firstThirdPerspectiveSwitchDelayTweak = new FirstThirdPerspectiveSwitchDelayTweak(); + + private DisableAutoVanityModeTweak disableAutoVanityModeTweak = new DisableAutoVanityModeTweak(); + private ForceAutoVanityModeTweak forceAutoVanityModeTweak = new ForceAutoVanityModeTweak(); + + private SelfieModeRangeTweak selfieModeRangeTweak = new SelfieModeRangeTweak(); + private SelfieCameraTranslationSpeedTweak selfieCameraTranslationSpeedTweak = new SelfieCameraTranslationSpeedTweak(); + private SelfieCameraRotationSpeedTweak selfieCameraRotationSpeedTweak = new SelfieCameraRotationSpeedTweak(); + + private ApplyCameraNodeAnimationsTweak applyCameraNodeAnimationsTweak = new ApplyCameraNodeAnimationsTweak(); + private CameraOverShoulderPosXTweak cameraOverShoulderPosXTweak = new CameraOverShoulderPosXTweak(); + private CameraOverShoulderPosZTweak cameraOverShoulderPosZTweak = new CameraOverShoulderPosZTweak(); + private CameraOverShoulderCombatPosXTweak cameraOverShoulderCombatPosXTweak = new CameraOverShoulderCombatPosXTweak(); + private CameraOverShoulderCombatPosZTweak cameraOverShoulderCombatPosZTweak = new CameraOverShoulderCombatPosZTweak(); + private CameraOverShoulderCombatAddYTweak cameraOverShoulderCombatAddYTweak = new CameraOverShoulderCombatAddYTweak(); + private CameraOverShoulderMeleeCombatPosXTweak cameraOverShoulderMeleeCombatPosXTweak = new CameraOverShoulderMeleeCombatPosXTweak(); + private CameraOverShoulderMeleeCombatPosZTweak cameraOverShoulderMeleeCombatPosZTweak = new CameraOverShoulderMeleeCombatPosZTweak(); + private CameraOverShoulderMeleeCombatAddYTweak cameraOverShoulderMeleeCombatAddYTweak = new CameraOverShoulderMeleeCombatAddYTweak(); + + // Gallery tab + private ScreenshotIndexTweak screenshotIndexTweak = new ScreenshotIndexTweak(); + } +} diff --git a/Fo76ini/Forms/Form1/Form1.cs b/Fo76ini/Forms/Form1/Form1.cs index 5dfde7b..f987f3d 100644 --- a/Fo76ini/Forms/Form1/Form1.cs +++ b/Fo76ini/Forms/Form1/Form1.cs @@ -1,5 +1,15 @@ -using Fo76ini.Forms.FormWhatsNew; +using Fo76ini.Forms.FormIniError; +using Fo76ini.Forms.FormSettings; +using Fo76ini.Forms.FormWelcome; +using Fo76ini.Forms.FormWhatsNew; +using Fo76ini.Ini; +using Fo76ini.Interface; +using Fo76ini.Mods; +using Fo76ini.NexusAPI; +using Fo76ini.Profiles; using Fo76ini.Properties; +using Fo76ini.Tweaks; +using Fo76ini.Utilities; using IniParser.Model; using System; using System.Collections.Generic; @@ -8,67 +18,180 @@ using System.Drawing; using System.IO; using System.Linq; -using System.Media; using System.Text; +using System.Text.RegularExpressions; using System.Windows.Forms; namespace Fo76ini { public partial class Form1 : Form { - private UILoader uiLoader = new UILoader(); - - private FormWhatsNew formWhatsNew = null; - private FormMods formMods; - private bool formModsBackupCreated = false; + private FormWhatsNew formWhatsNew = new FormWhatsNew(); + private FormSettings formSettings; - private RadioButton[] accountProfileRadioButtons; + private GameInstance game; - private static Form1 instance; - public static Form1 Instance - { - get { return Form1.instance; } - } + public readonly bool FirstStart; public Form1() { - Form1.instance = this; - InitializeComponent(); + // Determine whether this is the very first start of the tool on the system: + FirstStart = !File.Exists(IniFiles.ConfigPath) && !File.Exists(ProfileManager.XMLPath); + + // Handle changes: + ProfileManager.ProfileChanged += OnProfileChanged; + + // Create FormMods: + formMods = new FormMods(); + FormMods.NWModeUpdated += OnNWModeUpdated; + + /* + * Translations + */ + + // Make this form translatable: LocalizedForm form = new LocalizedForm(this, this.toolTip); form.SpecialControls.Add(this.contextMenuStripGallery); Localization.LocalizedForms.Add(form); + // Handle translations: + Translation.LanguageChanged += OnLanguageChanged; + + // Add control elements to blacklist: + Translation.BlackList.AddRange(new string[] { + "labelConfigVersion", + "labelAuthorName", + "labelTranslationAuthor", + "groupBoxWIP", + "labelNewVersion", + "labelGameEdition", + "toolStripStatusLabelGameText", + "toolStripStatusLabelEditionText", + "toolStripStatusLabel1", + "labelPipboyResolutionSpacer" + }); + + + /* + * Dropdowns + */ + + #region Dropdowns + // Let's add options to the drop-down menus: + // Display resolution usage statistics (and lists): + // https://store.steampowered.com/hwsurvey/Steam-Hardware-Software-Survey-Welcome-to-Steam + // https://www.rapidtables.com/web/dev/screen-resolution-statistics.html + // https://w3codemasters.in/most-common-screen-resolutions/ + // https://www.reneelab.com/video-with-4-3-format.html + // https://www.overclock.net/threads/list-of-display-resolutions-aspect-ratios.539967/ // https://en.wikipedia.org/wiki/List_of_common_resolutions DropDown.Add("Resolution", new DropDown( this.comboBoxResolution, - new String[] { + new string[] { "Custom", - "640x480", - "800x600", - "1280x720", - "1280x768", - "1152x864", - "1440x900", - "1600x900", - "1280x960", - "1920x1080", - "2560x1080", - "3440x1440", - "2560x1440", - "3200x1800", - "5120x2160", - "5120x2880" + "", + "┌───────────────────────────────┐", + "│ 4:3 │", + "├───────────────────────────────┤", + "│ [4:3] 640 x 480 (VGA) │", + "│ [4:3] 800 x 600 (SVGA) │", + "│ [4:3] 960 x 720 │", + "│ [4:3] 1024 x 768 (XGA) │", + "│ [4:3] 1152 x 864 │", + "│ [4:3] 1280 x 960 │", + "│ [4:3] 1400 x 1050 │", + "│ [4:3] 1440 x 1080 │", + "│ [4:3] 1600 x 1200 │", + "│ [4:3] 1920 x 1440 │", + "│ [4:3] 2048 x 1536 │", + "│ [4:3] 2880 x 2160 │", + "│ │", + "│ │", + "├───────────────────────────────┤", + "│ 5:3 │", + "├───────────────────────────────┤", + "│ [5:3] 800 x 480 │", + "│ [5:3] 1280 x 768 (WXGA) │", + "│ │", + "│ │", + "├───────────────────────────────┤", + "│ 5:4 │", + "├───────────────────────────────┤", + "│ [5:4] 1152 x 960 │", + "│ [5:4] 1280 x 1024 │", + "│ [5:4] 2560 x 2048 │", + "│ [5:4] 5120 x 4096 │", + "│ │", + "│ │", + "├───────────────────────────────┤", + "│ 8:5 │", + "├───────────────────────────────┤", + "│ [8:5] 1280 x 800 │", + "│ [8:5] 1440 x 900 │", + "│ [8:5] 1680 x 1050 │", + "│ [8:5] 1920 x 1200 │", + "│ │", + "│ │", + "├───────────────────────────────┤", + "│ 16:9 │", + "├───────────────────────────────┤", + "│ [16:9] 1024 x 576 │", + "│ [16:9] 1152 x 648 │", + "│ [16:9] 1280 x 720 (HD) │", + "│ [16:9] 1360 x 768 │", + "│ [16:9] 1365 x 768 │", + "│ [16:9] 1366 x 768 │", + "│ [16:9] 1536 x 864 │", + "│ [16:9] 1600 x 900 │", + "│ [16:9] 1920 x 1080 (Full HD) │", + "│ [16:9] 2560 x 1440 (WQHD) │", + "│ [16:9] 3200 x 1800 │", + "│ [16:9] 3840 x 2160 (4K UHD1) │", + "│ [16:9] 5120 x 2880 (5K) │", + "│ [16:9] 7680 x 4320 (8K UHD2) │", + "│ │", + "│ │", + "├───────────────────────────────┤", + "│ 16:10 │", + "├───────────────────────────────┤", + "│ [16:10] 640 x 400 │", + "│ [16:10] 1280 x 800 │", + "│ [16:10] 1440 x 900 │", + "│ [16:10] 1680 x 1050 │", + "│ [16:10] 1920 x 1200 │", + "│ [16:10] 2560 x 1600 │", + "│ [16:10] 3840 x 2400 │", + "│ │", + "│ │", + "├───────────────────────────────┤", + "│ 17:9 │", + "├───────────────────────────────┤", + "│ [17:9] 2048 x 1080 │", + "│ │", + "│ │", + "├───────────────────────────────┤", + "│ 21:9 │", + "├───────────────────────────────┤", + "│ [21:9] 1920 x 800 │", + "│ [21:9] 2560 x 1080 │", + "│ [21:9] 3440 x 1440 │", + "│ [21:9] 3840 x 1600 │", + "│ [21:9] 5120 x 2160 │", + "│ │", + "│ │", + "└───────────────────────────────┘", + "" } )); DropDown.Add("DisplayMode", new DropDown( this.comboBoxDisplayMode, - new String[] { + new string[] { "Fullscreen", "Windowed", "Borderless windowed", @@ -78,7 +201,7 @@ public Form1() DropDown.Add("AntiAliasing", new DropDown( this.comboBoxAntiAliasing, - new String[] { + new string[] { "TAA (default)", "FXAA", "Disabled" @@ -87,7 +210,7 @@ public Form1() DropDown.Add("AnisotropicFiltering", new DropDown( this.comboBoxAnisotropicFiltering, - new String[] { + new string[] { "None", "2x", "4x", @@ -98,7 +221,7 @@ public Form1() DropDown.Add("ShadowTextureResolution", new DropDown( this.comboBoxShadowTextureResolution, - new String[] { + new string[] { "512 = Potato", "1024 = Low", "2048 = High (default)", @@ -108,26 +231,16 @@ public Form1() DropDown.Add("ShadowBlurriness", new DropDown( this.comboBoxShadowBlurriness, - new String[] { + new string[] { "1x", "2x", "3x = Default, recommended" } )); - DropDown.Add("Files", new DropDown( - this.comboBoxCustomFile, - new String[] { - "Fallout76.ini", - "Fallout76Prefs.ini", - "Fallout76Custom.ini" - } - )); - this.comboBoxCustomFile.SelectedIndex = 0; - DropDown.Add("VoiceChatMode", new DropDown( this.comboBoxVoiceChatMode, - new String[] { + new string[] { "Auto", "Area", "Team", @@ -137,7 +250,7 @@ public Form1() DropDown.Add("ShowActiveEffectsOnHUD", new DropDown( this.comboBoxShowActiveEffectsOnHUD, - new String[] { + new string[] { "Disabled", "Detrimental", "All" @@ -146,16 +259,21 @@ public Form1() DropDown.Add("iDirShadowSplits", new DropDown( this.comboBoxiDirShadowSplits, - new String[] { + new string[] { "1 - Low", "2 - High / Medium", "3 - Ultra" } )); + #endregion + + /* + * Event handlers: + */ // Disable scroll wheel on UI elements to prevent the user from accidentally changing values: - PreventChangeOnMouseWheelForAllElements(this); + Utils.PreventChangeOnMouseWheelForAllElements(this); // Event handler: this.FormClosing += this.Form1_FormClosing; @@ -163,190 +281,207 @@ public Form1() this.KeyDown += this.Form1_KeyDown; this.backgroundWorkerGetLatestVersion.RunWorkerCompleted += backgroundWorkerGetLatestVersion_RunWorkerCompleted; - this.backgroundWorkerDownloadLanguages.RunWorkerCompleted += backgroundWorkerDownloadLanguages_RunWorkerCompleted; - this.backgroundWorkerEnableNWMode.RunWorkerCompleted += backgroundWorkerEnableNWMode_RunWorkerCompleted; - this.backgroundWorkerDisableNWMode.RunWorkerCompleted += backgroundWorkerDisableNWMode_RunWorkerCompleted; - } + InitAccountProfileRadiobuttons(); - // Winforms Double Buffering - // https://stackoverflow.com/questions/3718380/winforms-double-buffering/3718648#3718648 - // fixes the visual artifacts when scrolling - protected override CreateParams CreateParams - { - get - { - CreateParams cp = base.CreateParams; - cp.ExStyle |= 0x02000000; // Turn on WS_EX_COMPOSITED - return cp; - } - } + // Pipboy screen preview: + InitPipboyScreen(); + this.colorPreviewPipboy.BackColorChanged += colorPreviewPipboy_BackColorChanged; - /// - /// Disable scroll wheel on UI elements (NumericUpDown and ComboBox) to prevent the user from accidentally changing values - /// - /// - private void PreventChangeOnMouseWheelForAllElements(Control control) - { - foreach (Control subControl in control.Controls) + // Danger Zone: + this.tabControl1.TabPages.Remove(this.tabPageDangerZone); + FormSettings.SettingsClosing += (object sender, EventArgs e) => { - // NumericUpDown and ComboBox: - if (subControl.Name.StartsWith("num") || subControl.Name.StartsWith("comboBox") || subControl.Name.StartsWith("slider")) - subControl.MouseWheel += (object sender, MouseEventArgs e) => ((HandledMouseEventArgs)e).Handled = true; - - // TabControl, TabPage, and GroupBox: - if (subControl.Name.StartsWith("tab") || subControl.Name.StartsWith("groupBox") || subControl.Name.StartsWith("panel")) - PreventChangeOnMouseWheelForAllElements(subControl); - } + if (FormSettings.DangerZoneEnabled && !this.tabControl1.TabPages.Contains(this.tabPageDangerZone)) + { + this.tabControl1.TabPages.Add(this.tabPageDangerZone); + LinkDangerZoneControls(); + } + }; } private void Form1_Load(object sender, EventArgs e) { // Create folders, if not present: - if (!Directory.Exists(Shared.AppConfigFolder)) - Directory.CreateDirectory(Shared.AppConfigFolder); + Directory.CreateDirectory(Shared.AppConfigFolder); + Directory.CreateDirectory(Localization.LanguageFolder); + Directory.CreateDirectory(IniFiles.ParentPath); - if (!Directory.Exists(Localization.languageFolder)) - Directory.CreateDirectory(Localization.languageFolder); + // Link tweaks + LinkInfo(); + LinkSliders(); + LinkControlsToTweaks(); - // Create note to old config folder to inform users, if present: - if (Directory.Exists(Shared.OldAppConfigFolder)) - { - try - { - using (StreamWriter f = new StreamWriter(Path.Combine(Shared.OldAppConfigFolder, "READ ME - CONFIG FOLDER HAS BEEN MOVED.txt"))) - { - f.Write( - "Hi,\n\n"+ - "the entire configuration folder has been moved from\n" + - "C:\\Users\\USERNAME\\Documents\\Fallout 76 Quick Configuration\\\n" + - "to\n" + - "C:\\Users\\USERNAME\\AppData\\Local\\Fallout 76 Quick Configuration\\\n" + - "due to write-permission issues.\n\n" + - "Therefore changes to these files won't have any effect.\n" + - "It's safe to delete this folder, if you don't need the log files.\n\n" + - "Users reported that the tool is crashing for them, because it can't write to the aforementioned folder.\n" + - "So I moved it in the hope that it'll fix the issue, at least in part.\n" + - "Also, it's a better place anyway, as the Documents folder is supposed to contain documents. (Who knew?)\n\n" + - "Anyways, happy hunting!" - ); - } - } - catch - { - MessageBox.Show(@"All configuration files have been moved to 'C:\Users\\AppData\Local\Fallout 76 Quick Configuration'. Delete the old folder to stop this message from displaying.", "Old configuration path found"); - } - } + // Load config.ini + IniFiles.LoadConfig(); - this.formMods = new FormMods(); + // Load game instances + ProfileManager.Load(); + formSettings = new FormSettings(); - // Load config.ini - IniFiles.Instance.LoadConfig(); + this.timerCheckFiles.Enabled = true; - // Load the languages - Localization.AssignDropBox(this.comboBoxLanguage); - Localization.GenerateTemplate(); + // Load translations + Localization.GenerateDefaultTemplate(); Localization.LookupLanguages(); - // Load *.ini files: + Configuration.LoadWindowState("Form1", this); + + // Remove updater, if present: try { - Shared.LoadGameEdition(); - IniFiles.Instance.LoadGameInis(); - } - catch (IniParser.Exceptions.ParsingException exc) - { - //MessageBox.Show(exc.Message, "Couldn't parse *.ini files", MessageBoxButtons.OK, MessageBoxIcon.Error); - MsgBox.Get("iniParsingError").FormatText(exc.Message).Show(MessageBoxIcon.Error); - Application.Exit(); - return; + string updaterPath = Path.Combine(Shared.AppConfigFolder, "Updater"); + if (Directory.Exists(updaterPath)) + Directory.Delete(updaterPath, true); } - catch (FileNotFoundException exc) + catch { - MsgBox.Get("runGameToGenerateINI").FormatTitle(IniFiles.Instance.GetIniName(IniFile.F76), IniFiles.Instance.GetIniName(IniFile.F76Prefs)).Show(MessageBoxButtons.OK, MessageBoxIcon.Error); - Application.Exit(); - return; + // Yeah, well or not. } - this.timerCheckFiles.Enabled = true; - - LoadNuclearWinterConfiguration(); - - // Load mods: - ManagedMods.Instance.Load(); - this.formMods.UpdateUI(); + this.LoadGallery(); - // Account profiles: - this.accountProfileRadioButtons = new RadioButton[] { this.radioButtonAccount1, this.radioButtonAccount2, this.radioButtonAccount3, this.radioButtonAccount4, this.radioButtonAccount5, this.radioButtonAccount6, this.radioButtonAccount7, this.radioButtonAccount8 }; - foreach (RadioButton rbutton in this.accountProfileRadioButtons) - rbutton.CheckedChanged += new System.EventHandler(this.radioButtonAccount_CheckedChanged); + MakePictureBoxButton(this.pictureBoxUpdateButton, "updateNowButton"); + } - // Setup UI: - CheckAllINIValues(); - ColorIni2Ui(); - UpdateCameraPositionUI(); - AddAllEventHandler(); - uiLoader.Update(); + private void Form1_Shown(object sender, EventArgs e) + { + // Show welcome dialog: + if (FirstStart) + FormWelcome.OpenDialog(); + // Check for updates CheckVersion(); - if (IniFiles.Instance.GetBool(IniFile.Config, "Preferences", "bOpenModManagerOnLaunch", false)) - this.formMods.OpenUI(); + // Display "What's new?" dialog + if (!IniFiles.Config.GetBool("Preferences", "bIgnoreUpdates", false)) + ShowWhatsNewConditionally(); - IniFiles.Instance.LoadWindowState("Form1", this); + IniFiles.Config.Set("General", "sPreviousVersion", Shared.VERSION); + } - // Remove updater, if present: - try + private void OnProfileChanged(object sender, ProfileEventArgs e) + { + this.game = e.ActiveGameInstance; + this.timerCheckFiles.Enabled = false; + while (true) { - String updaterPath = Path.Combine(Shared.AppConfigFolder, "Updater"); - if (Directory.Exists(updaterPath)) - Directory.Delete(updaterPath, true); + try + { + IniFiles.Load(game); + break; + } + catch (IniParsingException exc) + { + DialogResult result = FormIniError.OpenDialog(exc); + if (result == DialogResult.Retry) + { + continue; + } + else if (result == DialogResult.Ignore) + { + continue; + } + else if (result == DialogResult.Abort) + { + Environment.Exit(-1); + return; + } + //MsgBox.Get("iniParsingError").FormatText(exc.Message).Show(MessageBoxIcon.Error); + //Application.Exit(); + //return; + } } - catch + LinkedTweaks.LoadValues(); + // TODO: For some reason, it won't update the resolution combobox, unless I add this workaround: + numCustomRes_ValueChanged(null, null); + + // Change image + switch (e.ActiveGameInstance.Edition) { - // Yeah, well or not. + case GameEdition.Steam: + this.pictureBoxGameEdition.Image = Resources.steam; + this.toolStripStatusLabelEditionText.Text = "Steam"; + this.labelGameEdition.Text = "Steam"; + break; + case GameEdition.BethesdaNet: + this.pictureBoxGameEdition.Image = Resources.bethesda; + this.toolStripStatusLabelEditionText.Text = "Bethesda.net"; + this.labelGameEdition.Text = "Bethesda"; + break; + case GameEdition.BethesdaNetPTS: + this.pictureBoxGameEdition.Image = Resources.bethesda_pts; + this.toolStripStatusLabelEditionText.Text = "Bethesda.net (PTS)"; + this.labelGameEdition.Text = "Bethesda\n(PTS)"; + break; + case GameEdition.MSStore: + this.pictureBoxGameEdition.Image = Resources.msstore; + this.toolStripStatusLabelEditionText.Text = "Microsoft Store"; + this.labelGameEdition.Text = "Microsoft\nStore"; + break; + default: + this.pictureBoxGameEdition.Image = Resources.help_128; + this.toolStripStatusLabelEditionText.Text = Localization.GetString("unknown"); + this.labelGameEdition.Text = Localization.GetString("unknown"); + break; } - this.LoadGallery(); + LoadAccountProfile(); + LoadCustomTab(); - MakePictureBoxButton(this.pictureBoxUpdateButton, "updateNowButton"); + this.toolStripStatusLabelGameText.Text = e.ActiveGameInstance?.Title; + this.timerCheckFiles.Enabled = true; } - private void Form1_Shown(Object sender, EventArgs e) + + // Winforms Double Buffering + // https://stackoverflow.com/questions/3718380/winforms-double-buffering/3718648#3718648 + // fixes the visual artifacts when scrolling + protected override CreateParams CreateParams { - // Check display resolution - int[] res = Utils.GetDisplayResolution(); - if (res[0] < 920 || res[1] < 750) - MsgBox.Get("displayResolutionTooLow").FormatText($"{res[0]} x {res[1]}", "920 x 750").Show(MessageBoxIcon.Warning); + get + { + CreateParams cp = base.CreateParams; + cp.ExStyle |= 0x02000000; // Turn on WS_EX_COMPOSITED + return cp; + } + } - // Display "What's new?" dialog - if (!IniFiles.Instance.GetBool(IniFile.Config, "Preferences", "bDisableWhatsNew", false) && - Utils.CompareVersions(Shared.VERSION, IniFiles.Instance.GetString(IniFile.Config, "General", "sPreviousVersion", "1.0.0")) > 0) + private void ShowWhatsNewConditionally() + { + /* + * Show "What's new" dialog when: + * -> What's new dialog hasn't been disabled AND + * -> The previously opened version is older than the current one AND + * -> There is no newer version available AND + * -> The tool hasn't been started for the first time. + */ + if (!IniFiles.Config.GetBool("Preferences", "bDisableWhatsNew", false) && + Utils.CompareVersions(Shared.VERSION, IniFiles.Config.GetString("General", "sPreviousVersion", "1.0.0")) > 0 && + (Shared.LatestVersion == null || Utils.CompareVersions(Shared.LatestVersion, Shared.VERSION) == 0) && + !FirstStart) ShowWhatsNew(); } private void ShowWhatsNew() { - if (this.formWhatsNew == null) - this.formWhatsNew = new FormWhatsNew(); this.formWhatsNew.ShowDialog(); } private void Form1_KeyDown(object sender, KeyEventArgs e) { - /*if (e.Control == true && e.Shift && e.KeyCode == Keys.F12) + if (e.KeyCode == Keys.F1) { - FormConsole.Instance.OpenUI(); - }*/ + Process.Start("https://github.com/FelisDiligens/Fallout76-QuickConfiguration/wiki"); + } } private void Form1_FormClosing(object sender, FormClosingEventArgs e) { if (e.CloseReason == CloseReason.UserClosing) { - IniFiles.Instance.Set(IniFile.Config, "General", "sPreviousVersion", Shared.VERSION); - IniFiles.Instance.SaveWindowState("Form1", this); - if (IniFiles.Instance.GetBool(IniFile.Config, "Preferences", "bAutoApply", false)) + Configuration.SaveWindowState("Form1", this); + if (IniFiles.Config.GetBool("Preferences", "bAutoApply", false)) ApplyChanges(); } } @@ -359,52 +494,55 @@ private void Form1_FormClosing(object sender, FormClosingEventArgs e) #region Check version - private String latestVersion = null; - private void backgroundWorkerGetLatestVersion_DoWork(object sender, DoWorkEventArgs e) + public void CheckVersion(bool force = false) { - //this.latestVersion = VERSION; - try - { - System.Net.WebClient wc = new System.Net.WebClient(); - // wc.CachePolicy = new System.Net.Cache.RequestCachePolicy(System.Net.Cache.RequestCacheLevel.BypassCache); - byte[] raw = wc.DownloadData("https://raw.githubusercontent.com/FelisDiligens/Fallout76-QuickConfiguration/master/VERSION"); - this.latestVersion = Encoding.UTF8.GetString(raw).Trim(); - } - catch (System.Net.WebException exc) + if (this.backgroundWorkerGetLatestVersion.IsBusy) + return; + + this.labelConfigVersion.Text = Shared.VERSION; + IniFiles.Config.Set("General", "sVersion", Shared.VERSION); + + panelUpdate.Visible = false; + + if (!force && IniFiles.Config.GetBool("Preferences", "bIgnoreUpdates", false)) { - this.latestVersion = null; + this.labelConfigVersion.ForeColor = Color.Black; return; } + + this.labelConfigVersion.ForeColor = Color.Gray; + this.pictureBoxSpinnerCheckForUpdates.Visible = true; + + // Checking version in background: + this.backgroundWorkerGetLatestVersion.RunWorkerAsync(); + } + + private void backgroundWorkerGetLatestVersion_DoWork(object sender, DoWorkEventArgs e) + { + Versioning.GetLatestVersion(); } private void backgroundWorkerGetLatestVersion_RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e) { this.pictureBoxSpinnerCheckForUpdates.Visible = false; + // ShowWhatsNewConditionally(); // TODO: Why is this here though? + // Failed: - if (this.latestVersion == null) + if (Shared.LatestVersion == null) { this.labelConfigVersion.ForeColor = Color.Black; panelUpdate.Visible = false; return; } - // Compare versions: - int cmp = Utils.CompareVersions(this.latestVersion, Shared.VERSION); - if (cmp > 0) + if (Versioning.UpdateAvailable) { - // Update available: panelUpdate.Visible = true; - labelNewVersion.Text = String.Format(Localization.GetString("newVersionAvailable"), latestVersion); + labelNewVersion.Text = string.Format(Localization.GetString("newVersionAvailable"), Shared.LatestVersion); labelNewVersion.ForeColor = Color.Crimson; this.labelConfigVersion.ForeColor = Color.Red; } - else if (cmp < 0) - { - // We're using a pre-release version: - panelUpdate.Visible = false; - this.labelConfigVersion.ForeColor = Color.DarkBlue; - } else { // All good, latest version: @@ -413,1595 +551,463 @@ private void backgroundWorkerGetLatestVersion_RunWorkerCompleted(object sender, } } - public void CheckVersion(bool force = false) - { - if (this.backgroundWorkerGetLatestVersion.IsBusy) - return; + #endregion - this.labelConfigVersion.Text = Shared.VERSION; - /*using (StreamWriter f = new StreamWriter(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "Fallout 76 Quick Configuration", "VERSION"))) - f.Write(VERSION);*/ - IniFiles.Instance.Set(IniFile.Config, "General", "sVersion", Shared.VERSION); + /* + ************************************************************** + * Event handlers + ************************************************************** + */ - panelUpdate.Visible = false; + #region Nuclear Winter Mode - if (!force && IniFiles.Instance.GetBool(IniFile.Config, "Preferences", "bIgnoreUpdates", false)) + private void OnNWModeUpdated(object sender, NuclearWinterEventArgs e) + { + this.labelNWModeActive.Invoke(new Action(() => { + UpdateNWModeUI(e.NuclearWinterModeEnabled); + })); + } + + private void UpdateNWModeUI (bool nwModeEnabled) + { + if (nwModeEnabled) { - this.labelConfigVersion.ForeColor = Color.Black; - return; + this.toolStripButtonToggleNuclearWinterMode.Text = Localization.GetString("adventuremode"); + this.toolStripButtonToggleNuclearWinterMode.Image = Resources.adventures; + } + else + { + this.toolStripButtonToggleNuclearWinterMode.Text = Localization.GetString("nuclearwintermode"); + this.toolStripButtonToggleNuclearWinterMode.Image = Resources.fire; } - this.labelConfigVersion.ForeColor = Color.Gray; - this.pictureBoxSpinnerCheckForUpdates.Visible = true; + this.labelNWModeActive.Visible = nwModeEnabled; + this.toolStripStatusLabelNuclearWinterModeActive.Visible = nwModeEnabled; - // Checking version in background: - this.backgroundWorkerGetLatestVersion.RunWorkerAsync(); + EnableUI(); + Focus(); + } + + private void toolStripButtonToggleNuclearWinterMode_Click(object sender, EventArgs e) + { + DisableUI(); + formMods.ToggleNuclearWinterModeThreaded(); } #endregion - /* - ************************************************************** - * *.ini values - ************************************************************** - */ + #region Apply, Launch, and so on. + public void ApplyChanges() + { + // Add custom lines to *.ini files: + try + { + IniFile addF76 = new IniFile(Path.Combine(IniFiles.ParentPath, $"{game.IniPrefix}.add.ini")); + addF76.Load(); + IniFiles.F76.Merge(addF76); - #region *.ini values integrity check + IniFile addF76Prefs = new IniFile(Path.Combine(IniFiles.ParentPath, $"{game.IniPrefix}Prefs.add.ini")); + addF76Prefs.Load(); + IniFiles.F76Prefs.Merge(addF76Prefs); - private void ExpectBool(List errors, String section, String key) - { - if (!IniFiles.Instance.Exists(section, key)) - return; - if (!IniFiles.Instance.ExpectBool(section, key)) - errors.Add($"[{section}] {key}: expected boolean (0 or 1), got {IniFiles.Instance.GetString(section, key, "")}"); + IniFile addF76Custom = new IniFile(Path.Combine(IniFiles.ParentPath, $"{game.IniPrefix}Custom.add.ini")); + addF76Custom.Load(); + IniFiles.F76Custom.Merge(addF76Custom); + } + catch (IniParsingException exc) + { + MsgBox.Get("customIniFilesParsingError").FormatText(exc.Message).Show(MessageBoxIcon.Error); + } + + // Save changes: + IniFiles.Save(); } - private void ExpectInt(List errors, String section, String key) + // "Apply" button: + private void toolStripButtonApply_Click(object sender, EventArgs e) { - if (!IniFiles.Instance.Exists(section, key)) - return; - if (!IniFiles.Instance.ExpectInt(section, key)) - errors.Add($"[{section}] {key}: expected integer, got {IniFiles.Instance.GetString(section, key)}"); + ApplyChanges(); + MsgBox.Get("changesApplied").Popup(MessageBoxIcon.Information); } - private void ExpectUInt(List errors, String section, String key) + private void toolStripButtonLaunchGame_Click(object sender, EventArgs e) { - if (!IniFiles.Instance.Exists(section, key)) - return; - if (!IniFiles.Instance.ExpectUInt(section, key)) - errors.Add($"[{section}] {key}: expected unsigned integer, got {IniFiles.Instance.GetString(section, key)}"); + this.game.LaunchGame(); } - private void ExpectFloat(List errors, String section, String key) + #endregion + + // "Get the latest version from NexusMods" link: + private void linkLabelManualDownloadPage_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) { - if (!IniFiles.Instance.Exists(section, key)) - return; - if (!IniFiles.Instance.ExpectFloat(section, key)) - errors.Add($"[{section}] {key}: expected floating point number, got {IniFiles.Instance.GetString(section, key)}"); + linkLabelManualDownloadPage.LinkVisited = true; + Process.Start("https://www.nexusmods.com/fallout76/mods/546?tab=files"); } - private void CheckAllINIValues() + private void buttonUpdateNow_Click(object sender, EventArgs e) { - List errors = new List(); + // Set sInstallationPath: + //string installationPath = Path.GetFullPath(AppContext.BaseDirectory); + IniFiles.Config.Set("Updater", "sInstallationPath", Shared.AppInstallationFolder); + IniFiles.Config.Save(); - /* - * Check values: - */ - ExpectBool(errors, "General", "bSteamEnabled"); - // TODO: Add more checks - - ExpectFloat(errors, "GamePlay", "fFloatingQuestMarkersDistance"); - ExpectFloat(errors, "Display", "fConversationHistorySize"); - ExpectFloat(errors, "MAIN", "fHUDOpacity"); - ExpectFloat(errors, "Display", "fDirShadowDistance"); - ExpectFloat(errors, "LOD", "fLODFadeOutMultObjects"); - ExpectFloat(errors, "LOD", "fLODFadeOutMultItems"); - ExpectFloat(errors, "LOD", "fLODFadeOutMultActors"); - ExpectFloat(errors, "Grass", "fGrassStartFadeDistance"); - ExpectFloat(errors, "Display", "fTAAPostOverlay"); - ExpectFloat(errors, "Display", "fTAAPostSharpen"); - ExpectFloat(errors, "AudioMenu", "fAudioMasterVolume"); - ExpectFloat(errors, "AudioMenu", "fVal0"); - ExpectFloat(errors, "AudioMenu", "fVal1"); - ExpectFloat(errors, "AudioMenu", "fVal2"); - ExpectFloat(errors, "AudioMenu", "fVal3"); - ExpectFloat(errors, "AudioMenu", "fVal4"); - ExpectFloat(errors, "AudioMenu", "fVal5"); - ExpectFloat(errors, "AudioMenu", "fVal6"); - ExpectFloat(errors, "Controls", "fMouseHeadingXScale"); - ExpectFloat(errors, "Controls", "fMouseHeadingSensitivity"); - ExpectFloat(errors, "Interface", "fLockPositionY"); - ExpectFloat(errors, "Interface", "fUIPowerArmorGeometry_TranslateZ"); - ExpectFloat(errors, "Interface", "fUIPowerArmorGeometry_TranslateY"); - ExpectFloat(errors, "Main", "fIronSightsFOVRotateMult"); - ExpectFloat(errors, "Display", "fDefault1stPersonFOV"); - ExpectFloat(errors, "Display", "fDefaultWorldFOV"); - ExpectFloat(errors, "Display", "fDefaultFOV"); - ExpectFloat(errors, "Camera", "f3rdPersonAimFOV"); - ExpectFloat(errors, "Camera", "fVanityModeMinDist"); - ExpectFloat(errors, "Camera", "fVanityModeMaxDist"); - ExpectFloat(errors, "Camera", "fPitchZoomOutMaxDist"); - ExpectFloat(errors, "Camera", "f1st3rdSwitchDelay"); - - ExpectUInt(errors, "Display", "iSize W"); - ExpectUInt(errors, "Display", "iSize H"); - ExpectUInt(errors, "Interface", "uHUDActiveEffectWidget"); - ExpectUInt(errors, "Display", "uiOrthoShadowFilter"); - ExpectUInt(errors, "Voice", "uTransmitPreference"); - ExpectUInt(errors, "Display", "uPipboyTargetWidth"); - ExpectUInt(errors, "Display", "uPipboyTargetHeight"); - - ExpectInt(errors, "Display", "iScreenShotIndex"); - ExpectInt(errors, "Display", "iShadowMapResolution"); - ExpectInt(errors, "Display", "iDirShadowSplits"); - ExpectInt(errors, "Display", "iPresentInterval"); - ExpectInt(errors, "Display", "iMaxAnisotropy"); - - if (errors.Count > 0) + // Copy updater.exe to \Updater\: + string updaterPath = Path.Combine(Shared.AppConfigFolder, "Updater"); + Directory.CreateDirectory(updaterPath); + Directory.CreateDirectory(Path.Combine(updaterPath, "7z")); + foreach (string filePath in Directory.EnumerateFiles(Shared.AppInstallationFolder, "*", SearchOption.AllDirectories)) { - MsgBox.Get("iniValuesInvalid").FormatText(errors.Count.ToString(), string.Join("\n", errors.ToArray())).Show(MessageBoxIcon.Warning); + string relPath = Utils.MakeRelativePath(Shared.AppInstallationFolder, filePath); + string destPath = Path.Combine(updaterPath, relPath); + Directory.CreateDirectory(Path.GetDirectoryName(destPath)); + File.Copy(filePath, destPath, true); } - } - #endregion + // Run updater.exe: + ProcessStartInfo startInfo = new ProcessStartInfo(); + startInfo.FileName = Path.Combine(updaterPath, "updater.exe"); + // If the program is installed into C:\Program Files (x86)\ then run the updater as admin: + if (Shared.AppInstallationFolder.Contains("C:\\Program Files")) + startInfo.Verb = "runas"; + Process.Start(startInfo); + Environment.Exit(0); + } - #region Linking *.ini values to control elements - private void AddAllEventHandler() - { - // Link numericUpDown and sliders: - UILoader.LinkSlider(this.sliderGrassFadeDistance, this.numGrassFadeDistance, 1); - //LinkSlider(this.sliderGrassDensity, this.numGrassDensity, 1, true); - UILoader.LinkSlider(this.sliderLODObjects, this.numLODObjects, 10); - UILoader.LinkSlider(this.sliderLODItems, this.numLODItems, 10); - UILoader.LinkSlider(this.sliderLODActors, this.numLODActors, 10); - UILoader.LinkSlider(this.sliderShadowDistance, this.numShadowDistance, 1); - UILoader.LinkSlider(this.sliderfBlendSplitDirShadow, this.numfBlendSplitDirShadow, 0.0833333); - UILoader.LinkSlider(this.sliderMouseSensitivity, this.numMouseSensitivity, 10000.0); - UILoader.LinkSlider(this.sliderTAAPostOverlay, this.numTAAPostOverlay, 100); - UILoader.LinkSlider(this.sliderTAAPostSharpen, this.numTAAPostSharpen, 100); - - UILoader.LinkSlider(this.sliderVolumeMaster, this.numVolumeMaster, 100); - UILoader.LinkSlider(this.sliderAudioChat, this.numAudioChat, 1); - UILoader.LinkSlider(this.sliderAudiofVal0, this.numAudiofVal0, 100); - UILoader.LinkSlider(this.sliderAudiofVal1, this.numAudiofVal1, 100); - UILoader.LinkSlider(this.sliderAudiofVal2, this.numAudiofVal2, 100); - UILoader.LinkSlider(this.sliderAudiofVal3, this.numAudiofVal3, 100); - UILoader.LinkSlider(this.sliderAudiofVal4, this.numAudiofVal4, 100); - UILoader.LinkSlider(this.sliderAudiofVal5, this.numAudiofVal5, 100); - UILoader.LinkSlider(this.sliderAudiofVal6, this.numAudiofVal6, 100); - - UILoader.LinkSlider(this.sliderFloatingQuestMarkersDistance, this.numFloatingQuestMarkersDistance, 10); - UILoader.LinkSlider(this.sliderConversationHistorySize, this.numConversationHistorySize, 1); - UILoader.LinkSlider(this.sliderHUDOpacity, this.numHUDOpacity, 100); - - UILoader.LinkSlider(this.sliderCameraDistanceMinimum, this.numCameraDistanceMinimum, 1); - UILoader.LinkSlider(this.sliderCameraDistanceMaximum, this.numCameraDistanceMaximum, 1); - UILoader.LinkSlider(this.sliderfPitchZoomOutMaxDist, this.numfPitchZoomOutMaxDist, 1); + #region Tool strip + /* + * Tool strip: + */ - /* - ******************************************** - * Link control elements: - ******************************************** - */ + private void toolStripButtonManageMods_Click(object sender, EventArgs e) + { + this.formMods.OpenUI(); + } - // ALTERNATIVE MODE - bool alternativeMode = IniFiles.Instance.GetBool(IniFile.Config, "Preferences", "bAlternativeINIMode", false); - this.checkBoxAlternativeINIMode.Checked = alternativeMode; - IniFiles.Instance.fixCustomIniDuplicateValues = IniFiles.Instance.fixCustomIniDuplicateValues && !alternativeMode; // Disable a fix, if alternative mode is enabled. + private void toolConfigurationFolderToolStripMenuItem_Click(object sender, EventArgs e) + { + Utils.OpenExplorer(Shared.AppConfigFolder); + } + private void toolLanguagesFolderToolStripMenuItem_Click(object sender, EventArgs e) + { + Utils.OpenExplorer(Localization.LanguageFolder); + } - // Make *.ini files read-only - uiLoader.LinkCustom(this.checkBoxReadOnly, - IniFiles.Instance.AreINIsReadOnly, - IniFiles.Instance.SetINIsReadOnly - ); - - // Deny NTFS write-permission - uiLoader.LinkBool(this.checkBoxDenyNTFSWritePermission, IniFile.Config, "Preferences", "bDenyNTFSWritePermission", false); - - /* - * Settings - */ - - // Game Edition - /*uiLoader.LinkList( - new RadioButton[] { this.radioButtonEditionBethesdaNet, this.radioButtonEditionSteam, this.radioButtonEditionBethesdaNetPTS, this.radioButtonEditionMSStore }, - new String[] { "1", "2", "3", "4" }, - IniFile.Config, "Preferences", "uGameEdition", - "0" - );*/ - uiLoader.Add(() => - { - switch (Shared.GameEdition) - { - case GameEdition.Steam: - this.radioButtonEditionSteam.Checked = true; - break; - case GameEdition.BethesdaNet: - this.radioButtonEditionBethesdaNet.Checked = true; - break; - case GameEdition.BethesdaNetPTS: - this.radioButtonEditionBethesdaNetPTS.Checked = true; - break; - case GameEdition.MSStore: - this.radioButtonEditionMSStore.Checked = true; - break; - } - }); - - // Launch options - uiLoader.LinkList( - new RadioButton[] { this.radioButtonLaunchViaLink, this.radioButtonLaunchViaExecutable }, - new String[] { "1", "2" }, - IniFile.Config, "Preferences", "uLaunchOption", - "1" - ); - - // Nuclear winter mode - //uiLoader.LinkBool(this.checkBoxNWMode, IniFile.Config, "Preferences", "bNWMode", false); - - // Close the tool when the game is launched - uiLoader.LinkBool(this.checkBoxQuitOnGameLaunch, IniFile.Config, "Preferences", "bQuitOnLaunch", false); - - // Automatically apply changes when tool is closed or game is launched - uiLoader.LinkBool(this.checkBoxAutoApply, IniFile.Config, "Preferences", "bAutoApply", false); - - // Don't ask me, when "Apply" is clicked. - uiLoader.LinkBool(this.checkBoxSkipBackupQuestion, IniFile.Config, "Preferences", "bSkipBackupQuestion", false); - - // Open mod manager when tool is launched. - uiLoader.LinkBool(this.checkBoxOpenManageModsOnLaunch, IniFile.Config, "Preferences", "bOpenModManagerOnLaunch", false); - - // Don't check for updates on startup. - uiLoader.LinkBool(this.checkBoxIgnoreUpdates, IniFile.Config, "Preferences", "bIgnoreUpdates", false); - - // Does the user use multiple game editions when modding? - uiLoader.LinkBool(this.checkBoxMultipleGameEditionsUsed, IniFile.Config, "Preferences", "bMultipleGameEditionsUsed", false); - - // Play alert sound: - uiLoader.LinkBool(this.checkBoxPlayNotificationSound, IniFile.Config, "Preferences", "bPlayNotificationSound", true); - - - // NW: Fallout76Custom.ini options - uiLoader.LinkBool(this.radioButtonNWRenameINI, this.radioButtonNWRemoveLists, IniFile.Config, "NuclearWinter", "bRenameCustomINI", true); - - // NW: *.dll options - uiLoader.LinkBool(this.checkBoxNWRenameDLL, IniFile.Config, "NuclearWinter", "bRenameDLLs", true); - - // NW: Mod options - uiLoader.LinkBool(this.checkBoxNWAutoDeployMods, IniFile.Config, "NuclearWinter", "bAutoDeployMods", false); - uiLoader.LinkBool(this.checkBoxNWAutoDisableMods, IniFile.Config, "NuclearWinter", "bAutoDisableMods", false); - - - /* - * General - */ - - // Credentials - uiLoader.LinkString(this.textBoxUserName, !alternativeMode ? IniFile.F76Custom : IniFile.F76, "Login", "s76UserName", ""); - uiLoader.LinkString(this.textBoxPassword, !alternativeMode ? IniFile.F76Custom : IniFile.F76, "Login", "s76Password", ""); - - uiLoader.LinkList( - this.accountProfileRadioButtons, - new String[] { "1", "2", "3", "4", "5", "6", "7", "8" }, - IniFile.Config, "Login", "uActiveAccountProfile", - "1" - ); - - // Disable Steam: - uiLoader.LinkBoolNegated(this.checkBoxDisableSteam, !alternativeMode ? IniFile.F76Custom : IniFile.F76, "General", "bSteamEnabled", true); - - // Automatically sign-in: - uiLoader.LinkBool(this.checkBoxAutoSignin, !alternativeMode ? IniFile.F76Custom : IniFile.F76, "Login", "bAutoSignin", false); - - // Play intro videos - uiLoader.LinkCustom(this.checkBoxIntroVideos, - () => { - String sIntroSequence = IniFiles.Instance.GetString("General", "sIntroSequence", "BGSLogo4k.bk2").Trim(); - return sIntroSequence.Length > 0 && sIntroSequence != "0"; - }, - (value) => { - if (value) - { - IniFiles.Instance.Remove(IniFile.F76Custom, "General", "sIntroSequence"); - IniFiles.Instance.Remove(IniFile.F76Custom, "General", "uMainMenuDelayBeforeAllowSkip"); - if (alternativeMode) - { - IniFiles.Instance.Set(IniFile.F76, "General", "sIntroSequence", true); - IniFiles.Instance.Set(IniFile.F76, "General", "uMainMenuDelayBeforeAllowSkip", 5000); - } - } - else - { - IniFiles.Instance.Set(!alternativeMode ? IniFile.F76Custom : IniFile.F76, "General", "sIntroSequence", ""); - IniFiles.Instance.Set(!alternativeMode ? IniFile.F76Custom : IniFile.F76, "General", "uMainMenuDelayBeforeAllowSkip", "0"); - } - } - ); - - // Play music in main menu - uiLoader.LinkBool(this.checkBoxMainMenuMusic, !alternativeMode ? IniFile.F76Custom : IniFile.F76, "General", "bPlayMainMenuMusic", true); - - // Show splash screen with news on startup - uiLoader.LinkBoolNegated(this.checkBoxShowSplash, !alternativeMode ? IniFile.F76Custom : IniFile.F76, "General", "bSkipSplash", false); - - // General subtitles - uiLoader.LinkBool(this.checkBoxGeneralSubtitles, IniFile.F76Prefs, "Interface", "bGeneralSubtitles", false); - - // Dialogue subtitles - uiLoader.LinkBool(this.checkBoxDialogueSubtitles, IniFile.F76Prefs, "Interface", "bDialogueSubtitles", false); - - // Dialogue history - uiLoader.LinkBool(this.checkBoxDialogueHistory, IniFile.F76Prefs, "MAIN", "bShowDialogueHistory", false); - - // Show damage numbers in nuclear winter - uiLoader.LinkBool(this.checkBoxShowDamageNumbersNW, IniFile.F76Prefs, "NuclearWinter", "bShowDamageNumbers", true); - - // Show damage numbers in adventure mode - uiLoader.LinkBool(this.checkBoxShowDamageNumbersA, IniFile.F76Prefs, "Adventure", "bShowDamageNumbers", false); - - // Show item rarity colors - uiLoader.LinkBool(this.checkBoxItemRarityColorsNW, IniFile.F76Prefs, "NuclearWinter", "bEnableItemRarityColors", true); - - // Show Public Team Notifications - uiLoader.LinkBool(this.checkBoxShowPublicTeamNotifications, IniFile.F76Prefs, "GamePlay", "bShowPublicTeamNotifications", true); - - // Show Floating Quest Markers - uiLoader.LinkBool(this.checkBoxShowFloatingQuestMarkers, IniFile.F76Prefs, "GamePlay", "bShowFloatingQuestMarkers", true); - - // Show Floating Quest Text - uiLoader.LinkBool(this.checkBoxShowFloatingQuestText, IniFile.F76Prefs, "GamePlay", "bShowFloatingQuestText", true); - - // Floating Quest Markers Draw Distance - uiLoader.LinkFloat(this.numFloatingQuestMarkersDistance, IniFile.F76Prefs, "GamePlay", "fFloatingQuestMarkersDistance", 100.0f); - - // Show compass - uiLoader.LinkBool(this.checkBoxShowCompass, IniFile.F76Prefs, "Interface", "bShowCompass", true); - - // Show crosshair - uiLoader.LinkBool(this.checkBoxShowCrosshair, IniFile.F76Prefs, "MAIN", "bCrosshairEnabled", true); - - // Enable Power Armor HUD - uiLoader.LinkBool(this.checkBoxEnablePowerArmorHUD, IniFile.F76Prefs, "MAIN", "bEnablePowerArmorHUD", true); - - // Show Other Players' Names - uiLoader.LinkBool(this.checkBoxShowOtherPlayersNames, IniFile.F76Prefs, "Display", "bShowOtherPlayersNames", true); - - // Quests: - uiLoader.LinkBool(this.checkBoxEnableQuestAutoTrackMain, IniFile.F76Prefs, "MAIN", "bEnableQuestAutoTrackMain", true); - uiLoader.LinkBool(this.checkBoxEnableQuestAutoTrackSide, IniFile.F76Prefs, "MAIN", "bEnableQuestAutoTrackSide", true); - uiLoader.LinkBool(this.checkBoxEnableQuestAutoTrackMisc, IniFile.F76Prefs, "MAIN", "bEnableQuestAutoTrackMisc", true); - uiLoader.LinkBool(this.checkBoxEnableQuestAutoTrackEvent, IniFile.F76Prefs, "MAIN", "bEnableQuestAutoTrackEvent", true); - uiLoader.LinkBool(this.checkBoxEnableQuestAutoTrackDaily, IniFile.F76Prefs, "MAIN", "bEnableQuestAutoTrackOther", false); - - // Conversation History Size - uiLoader.LinkFloat(this.numConversationHistorySize, IniFile.F76Prefs, "Display", "fConversationHistorySize", 4.0f); - - // HUD Opacity - uiLoader.LinkFloat(this.numHUDOpacity, IniFile.F76Prefs, "MAIN", "fHUDOpacity", 1.0f); - - // Show active effects on HUD - uiLoader.LinkList( - this.comboBoxShowActiveEffectsOnHUD, - new String[] { "0", "1", "2" }, - IniFile.F76Prefs, "Interface", "uHUDActiveEffectWidget", - "2", 2 - ); - - // Screenshot index - uiLoader.LinkInt(this.numScreenshotIndex, IniFile.F76Prefs, "Display", "iScreenShotIndex", 0); - - - /* - * Display - */ - - // Display mode - uiLoader.LinkCustom(this.comboBoxDisplayMode, - () => { - bool bFullScreen = IniFiles.Instance.GetBool("Display", "bFull Screen", true); - bool bBorderless = IniFiles.Instance.GetBool("Display", "bBorderless", true); - bool bMaximizeWindow = IniFiles.Instance.GetBool("Display", "bMaximizeWindow", true); - - if (bFullScreen) - return 0; // Fullscreen - else if (!bBorderless) - return 1; // Windowed - else if (bBorderless && !bMaximizeWindow) - return 2; // Borderless windowed - else - return 3; // Borderless windowed (Fullscreen) - }, - (value) => { - bool bFullScreen, bBorderless, bMaximizeWindow; - switch (this.comboBoxDisplayMode.SelectedIndex) - { - case 0: // Fullscreen - bBorderless = true; - bFullScreen = true; - bMaximizeWindow = false; - break; - case 1: // Windowed - bBorderless = false; - bFullScreen = false; - bMaximizeWindow = false; - break; - case 3: // Borderless windowed (Fullscreen) - bBorderless = true; - bFullScreen = false; - bMaximizeWindow = true; - break; - default: // Borderless windowed: Default settings - bBorderless = true; - bFullScreen = false; - bMaximizeWindow = false; - break; - } - IniFiles.Instance.Set(IniFile.F76Prefs, "Display", "bFull Screen", bFullScreen); - IniFiles.Instance.Set(IniFile.F76Prefs, "Display", "bBorderless", bBorderless); - IniFiles.Instance.Set(IniFile.F76Prefs, "Display", "bMaximizeWindow", bMaximizeWindow); - } - ); - - // Resolution - uiLoader.LinkCustom(this.comboBoxResolution, - () => { - int width = IniFiles.Instance.GetInt("Display", "iSize W", 1920); - int height = IniFiles.Instance.GetInt("Display", "iSize H", 1080); - int resIndex = Array.IndexOf(DropDown.Get("Resolution").Items.ToArray(), $"{width}x{height}"); - this.numCustomResW.Value = width; - this.numCustomResH.Value = height; - return resIndex > -1 ? resIndex : 0; - }, - (value) => { - bool isCustomSelected = value == 0; - this.numCustomResW.Enabled = isCustomSelected; - this.numCustomResH.Enabled = isCustomSelected; - - if (value != 0) - { - String[] splitted = this.comboBoxResolution.SelectedItem.ToString().Split(new String[] { "x" }, StringSplitOptions.RemoveEmptyEntries); - int width = Convert.ToInt32(splitted[0]); - int height = Convert.ToInt32(splitted[1]); - IniFiles.Instance.Set(IniFile.F76Prefs, "Display", "iSize W", width); - IniFiles.Instance.Set(IniFile.F76Prefs, "Display", "iSize H", height); - this.numCustomResW.Value = width; - this.numCustomResH.Value = height; - } - } - ); - - // Custom Resolution - uiLoader.LinkInt(this.numCustomResW, IniFile.F76Prefs, "Display", "iSize W", 1920); - uiLoader.LinkInt(this.numCustomResH, IniFile.F76Prefs, "Display", "iSize H", 1080); - - // Hide (or show) custom resolution on load: - uiLoader.Add(() => - { - bool isCustomSelected = this.comboBoxResolution.SelectedIndex == 0; - this.numCustomResW.Enabled = isCustomSelected; - this.numCustomResH.Enabled = isCustomSelected; - }); - - // Top most window - uiLoader.LinkBool(this.checkBoxTopMostWindow, IniFile.F76Prefs, "Display", "bTopMostWindow", false); - - // Always active - uiLoader.LinkBool(this.checkBoxAlwaysActive, !alternativeMode ? IniFile.F76Custom : IniFile.F76, "General", "bAlwaysActive", true); - - // Fix HUD for 5:4 and 4:3 screens - uiLoader.LinkCustom(this.checkBoxFixHUDFor5_4and4_3, - () => { - return - Math.Abs(IniFiles.Instance.GetFloat("Interface", "fLockPositionY", 0f) - 100f) < 0.1 && - Math.Abs(IniFiles.Instance.GetFloat("Interface", "fUIPowerArmorGeometry_TranslateZ", 0f) - -18.5f) < 0.1 && - Math.Abs(IniFiles.Instance.GetFloat("Interface", "fUIPowerArmorGeometry_TranslateY", 0f) - 460f) < 0.1; - }, - (value) => { - if (value) - { - IniFiles.Instance.Set(!alternativeMode ? IniFile.F76Custom : IniFile.F76, "Interface", "fLockPositionY", 100f); - IniFiles.Instance.Set(!alternativeMode ? IniFile.F76Custom : IniFile.F76, "Interface", "fUIPowerArmorGeometry_TranslateZ", -18.5f); - IniFiles.Instance.Set(!alternativeMode ? IniFile.F76Custom : IniFile.F76, "Interface", "fUIPowerArmorGeometry_TranslateY", 460f); - } - else - { - IniFiles.Instance.Remove(IniFile.F76Custom, "Interface", "fLockPositionY"); - IniFiles.Instance.Remove(IniFile.F76Custom, "Interface", "fUIPowerArmorGeometry_TranslateZ"); - IniFiles.Instance.Remove(IniFile.F76Custom, "Interface", "fUIPowerArmorGeometry_TranslateY"); - if (alternativeMode) - { - IniFiles.Instance.Set(IniFile.F76, "Interface", "fLockPositionY", -10.0f); - IniFiles.Instance.Set(IniFile.F76, "Interface", "fUIPowerArmorGeometry_TranslateZ", 0.0); - IniFiles.Instance.Set(IniFile.F76, "Interface", "fUIPowerArmorGeometry_TranslateY", 350.0); - } - } - } - ); - - - - /* - * Graphics - */ - - // Anti-Aliasing - uiLoader.LinkList(this.comboBoxAntiAliasing, - new String[] { "TAA", "FXAA", "" }, - IniFile.F76Prefs, "Display", "sAntiAliasing", - "TAA", 2); - - // Anisotropic filtering - uiLoader.LinkList(this.comboBoxAnisotropicFiltering, - new String[] { "0", "2", "4", "8", "16" }, - IniFile.F76Prefs, "Display", "iMaxAnisotropy", - "8", 3); - - // iPresentInterval - // I'm not so sure about this anymore:!alternativeMode ? IniFile.F76Custom : IniFile.F76 - // Actually, it's not VSync but a fps cap, which is determined this way: Monitor refresh rate divided by iPresentInterval - // A 120 Hz monitor and iPresentInterval set to 2 will result in a 60fps cap. - //uiLoader.LinkBool(this.checkBoxVSync, IniFile.F76Prefs, "Display", "iPresentInterval", true); - uiLoader.LinkCustom(this.checkBoxVSync, - () => IniFiles.Instance.GetInt("Display", "iPresentInterval", 1) != 0, - (value) => { - if (value) - { - int defaultValue = IniFiles.Instance.GetInt(IniFile.Config, "Display", "iPresentInterval", -1); - if (defaultValue <= 0) - { - defaultValue = 1; - // Values of 2 and above cause black screen: - //int refreshRate = Utils.GetDisplayRefreshRate(); - //defaultValue = Utils.Clamp(Convert.ToInt32(Math.Round(Convert.ToSingle(refreshRate) / 60f)), 1, 4); - } - IniFiles.Instance.Set(IniFile.F76Prefs, "Display", "iPresentInterval", defaultValue); - } - else - { - int defaultValue = IniFiles.Instance.GetInt("Display", "iPresentInterval", -1); - if (defaultValue > 0) - IniFiles.Instance.Set(IniFile.Config, "Display", "iPresentInterval", defaultValue); - IniFiles.Instance.Set(IniFile.F76Prefs, "Display", "iPresentInterval", 0); - } - } - ); - - // Depth of Field - uiLoader.LinkCustom(this.checkBoxDepthOfField, - () => IniFiles.Instance.GetBool("ImageSpace", "bDynamicDepthOfField", true), - (value) => { - if (value) - { - if (alternativeMode) - { - IniFiles.Instance.Set(IniFile.F76, "ImageSpace", "bDynamicDepthOfField", true); - IniFiles.Instance.Set(IniFile.F76, "Display", "fDOFBlendRatio", 10.0f); - IniFiles.Instance.Set(IniFile.F76, "Display", "fDOFMinFocalCoefDist", 500.0f); - IniFiles.Instance.Set(IniFile.F76, "Display", "fDOFMaxFocalCoefDist", 15000.0f); - IniFiles.Instance.Set(IniFile.F76, "Display", "fDOFDynamicFarRange", 120000.0f); - IniFiles.Instance.Set(IniFile.F76, "Display", "fDOFCenterWeightInt", 38.0f); - IniFiles.Instance.Set(IniFile.F76, "Display", "fDOFFarDistance", 15000.0f); - } - IniFiles.Instance.Remove(IniFile.F76Custom, "ImageSpace", "bDynamicDepthOfField"); - IniFiles.Instance.Remove(IniFile.F76Custom, "Display", "fDOFBlendRatio"); - IniFiles.Instance.Remove(IniFile.F76Custom, "Display", "fDOFMinFocalCoefDist"); - IniFiles.Instance.Remove(IniFile.F76Custom, "Display", "fDOFMaxFocalCoefDist"); - IniFiles.Instance.Remove(IniFile.F76Custom, "Display", "fDOFDynamicFarRange"); - IniFiles.Instance.Remove(IniFile.F76Custom, "Display", "fDOFCenterWeightInt"); - IniFiles.Instance.Remove(IniFile.F76Custom, "Display", "fDOFFarDistance"); - } - else - { - IniFiles.Instance.Set(!alternativeMode ? IniFile.F76Custom : IniFile.F76, "ImageSpace", "bDynamicDepthOfField", false); - IniFiles.Instance.Set(!alternativeMode ? IniFile.F76Custom : IniFile.F76, "Display", "fDOFBlendRatio", 0); - IniFiles.Instance.Set(!alternativeMode ? IniFile.F76Custom : IniFile.F76, "Display", "fDOFMinFocalCoefDist", 999999); - IniFiles.Instance.Set(!alternativeMode ? IniFile.F76Custom : IniFile.F76, "Display", "fDOFMaxFocalCoefDist", 99999999); - IniFiles.Instance.Set(!alternativeMode ? IniFile.F76Custom : IniFile.F76, "Display", "fDOFDynamicFarRange", 99999999); - IniFiles.Instance.Set(!alternativeMode ? IniFile.F76Custom : IniFile.F76, "Display", "fDOFCenterWeightInt", 0); - IniFiles.Instance.Set(!alternativeMode ? IniFile.F76Custom : IniFile.F76, "Display", "fDOFFarDistance", 99999999); - - /* - Things I wanted to add: - - bDoDepthOfField - DO NOT set this to 0. It will cause underwater effects to disappear. - bScreenSpaceBokeh - Apparently some blur effect. Is it related to DOF? - bUseBlurShader - ? - */ - } - } - ); - - // Motion Blur - uiLoader.LinkBool(this.checkBoxMotionBlur, !alternativeMode ? IniFile.F76Custom : IniFile.F76Prefs, "ImageSpace", "bMBEnable", true); - - // Radial Blur - uiLoader.LinkBool(this.checkBoxRadialBlur, !alternativeMode ? IniFile.F76Custom : IniFile.F76, "ImageSpace", "bDoRadialBlur", true); - - // Lens Flare - uiLoader.LinkBool(this.checkBoxLensFlare, IniFile.F76Prefs, "ImageSpace", "bLensFlare", true); - - // Ambient Occlusion - uiLoader.LinkBool(this.checkBoxAmbientOcclusion, IniFile.F76Prefs, "Display", "bSAOEnable", true); - - // Water / Displacement - uiLoader.LinkBool(this.checkBoxWaterDisplacement, IniFile.F76Prefs, "Water", "bUseWaterDisplacements", true); - - // Weather / Fog - uiLoader.LinkBool(this.checkBoxFogEnabled, IniFile.F76Prefs, "Weather", "bFogEnabled", true); - - // Weather / Rain Occlusion - uiLoader.LinkBool(this.checkBoxWeatherRainOcclusion, IniFile.F76, "Weather", "bRainOcclusion", true); - - // Weather / Wetness Occlusion - uiLoader.LinkBool(this.checkBoxWeatherWetnessOcclusion, IniFile.F76, "Weather", "bWetnessOcclusion", true); - - // Lighting / Volumetric Lighting - uiLoader.LinkBool(this.checkBoxGodrays, IniFile.F76Prefs, "Display", "bVolumetricLightingEnable", true); - - // Shadows / Texture map resolution - uiLoader.LinkList(this.comboBoxShadowTextureResolution, - new String[] { "512", "1024", "2048", "4096" }, - IniFile.F76Prefs, "Display", "iShadowMapResolution", - "2048", 1); - - // Shadows / Blurriness - uiLoader.LinkList(this.comboBoxShadowBlurriness, - new String[] { "1", "2", "3" }, - IniFile.F76Prefs, "Display", "uiOrthoShadowFilter", - "3", 2); - - // Amount of shadow "segments": iDirShadowSplits - uiLoader.LinkList(this.comboBoxiDirShadowSplits, - new String[] { "1", "2", "3" }, - IniFile.F76Prefs, "Display", "iDirShadowSplits", - "3", 2); - - // Shadow / Shadow distance - // fShadowDistance was replaced by fDirShadowDistance in Fallout 4 - uiLoader.LinkInt(this.numShadowDistance, IniFile.F76Prefs, "Display", "fDirShadowDistance", 3000); - - // LOD Fade Distances - uiLoader.LinkFloat(this.numLODObjects, IniFile.F76Prefs, "LOD", "fLODFadeOutMultObjects", 6.0f); - uiLoader.LinkFloat(this.numLODItems, IniFile.F76Prefs, "LOD", "fLODFadeOutMultItems", 2.5f); - uiLoader.LinkFloat(this.numLODActors, IniFile.F76Prefs, "LOD", "fLODFadeOutMultActors", 4.5f); - - // Grass / Enable grass - uiLoader.LinkBool(this.checkBoxGrass, !alternativeMode ? IniFile.F76Custom : IniFile.F76, "Grass", "bAllowCreateGrass", true); - - // Grass / Fade distance - uiLoader.LinkCustom(this.numGrassFadeDistance, - () => IniFiles.Instance.GetFloat("Grass", "fGrassStartFadeDistance", 3000), - (value) => { - IniFiles.Instance.Set(IniFile.F76Prefs, "Grass", "fGrassStartFadeDistance", value); - IniFiles.Instance.Set(IniFile.F76Prefs, "Grass", "fGrassMinStartFadeDistance", 0); - IniFiles.Instance.Set(IniFile.F76Prefs, "Grass", "fGrassMaxStartFadeDistance", value); - } - ); - - // Grass / Density - //LinkInt(this.numGrassDensity, IniFile.F76Custom, "Grass", "iMinGrassSize", 20); - - // TAA Sharpening - - uiLoader.LinkFloat(this.numTAAPostOverlay, !alternativeMode ? IniFile.F76Custom : IniFile.F76, "Display", "fTAAPostOverlay", 0.21f); - uiLoader.LinkFloat(this.numTAAPostSharpen, !alternativeMode ? IniFile.F76Custom : IniFile.F76, "Display", "fTAAPostSharpen", 0.21f); - - - - /* - * Audio - */ - - uiLoader.LinkBool(this.checkBoxEnableAudio, !alternativeMode ? IniFile.F76Custom : IniFile.F76, "Audio", "bEnableAudio", true); - - uiLoader.LinkBool(this.checkBoxPushToTalk, IniFile.F76Prefs, "Voice", "bVoicePushToTalkEnabled", true); - - uiLoader.LinkFloat(this.numVolumeMaster, IniFile.F76Prefs, "AudioMenu", "fAudioMasterVolume", 1.0f); - uiLoader.LinkInt(this.numAudioChat, IniFile.F76Prefs, "Voice", "uVivoxVoiceVolume", 100); - uiLoader.LinkFloat(this.numAudiofVal0, IniFile.F76Prefs, "AudioMenu", "fVal0", 1.0f); - uiLoader.LinkFloat(this.numAudiofVal1, IniFile.F76Prefs, "AudioMenu", "fVal1", 1.0f); - uiLoader.LinkFloat(this.numAudiofVal2, IniFile.F76Prefs, "AudioMenu", "fVal2", 1.0f); - uiLoader.LinkFloat(this.numAudiofVal3, IniFile.F76Prefs, "AudioMenu", "fVal3", 1.0f); - uiLoader.LinkFloat(this.numAudiofVal4, IniFile.F76Prefs, "AudioMenu", "fVal4", 1.0f); - uiLoader.LinkFloat(this.numAudiofVal5, IniFile.F76Prefs, "AudioMenu", "fVal5", 1.0f); - uiLoader.LinkFloat(this.numAudiofVal6, IniFile.F76Prefs, "AudioMenu", "fVal6", 1.0f); - - uiLoader.LinkList(this.comboBoxVoiceChatMode, - new String[] { "0", "1", "2", "3" }, - IniFile.F76Prefs, "Voice", "uTransmitPreference", - "0", 0); - - - /* - * Controls - */ - - uiLoader.LinkBool(this.checkBoxMouseAcceleration, !alternativeMode ? IniFile.F76Custom : IniFile.F76, "Controls", "bMouseAcceleration", true); - - // Fix mouse sensitivity - uiLoader.LinkCustom(this.checkBoxFixMouseSensitivity, - () => IniFiles.Instance.GetFloat("Controls", "fMouseHeadingXScale", 0.021f) != IniFiles.Instance.GetFloat("Controls", "fMouseHeadingYScale", 0.021f), - (value) => { - if (value) - { - int width = IniFiles.Instance.GetInt("Display", "iSize W", 1920); - int height = IniFiles.Instance.GetInt("Display", "iSize H", 1080); - float aspectRatio = width / height; - float YScale = 0.0f; - - // 16:9 - if (Math.Abs(aspectRatio - 16 / 9) < 0.01) - YScale = 0.03738f; - - // 16:10 - else if (Math.Abs(aspectRatio - 16 / 10) < 0.01) - YScale = 0.0336f; - - // 21:9 - else if (Math.Abs(aspectRatio - 21 / 9) < 0.01) - YScale = 0.042f; - - // 4:3 - else if (Math.Abs(aspectRatio - 4 / 3) < 0.01) - YScale = 0.028f; - - // Unknown aspect ratio - else - YScale = aspectRatio * 0.021f; - - IniFiles.Instance.Set(!alternativeMode ? IniFile.F76Custom : IniFile.F76, "Controls", "fMouseHeadingXScale", 0.021f); - IniFiles.Instance.Set(!alternativeMode ? IniFile.F76Custom : IniFile.F76, "Controls", "fMouseHeadingYScale", YScale); - - IniFiles.Instance.Set(!alternativeMode ? IniFile.F76Custom : IniFile.F76, "Controls", "fPitchSpeedRatio", 1.0f); - IniFiles.Instance.Set(!alternativeMode ? IniFile.F76Custom : IniFile.F76, "Controls", "fIronSightsPitchSpeedRatio", 1.0f); - } - else - { - IniFiles.Instance.Remove(IniFile.F76Custom, "Controls", "fMouseHeadingXScale"); - IniFiles.Instance.Remove(IniFile.F76Custom, "Controls", "fMouseHeadingYScale"); - IniFiles.Instance.Remove(IniFile.F76Custom, "Controls", "fPitchSpeedRatio"); - IniFiles.Instance.Remove(IniFile.F76Custom, "Controls", "fIronSightsPitchSpeedRatio"); - if (alternativeMode) - { - IniFiles.Instance.Set(IniFile.F76Custom, "Controls", "fMouseHeadingXScale", 0.021f); - IniFiles.Instance.Set(IniFile.F76Custom, "Controls", "fMouseHeadingYScale", 0.021f); - IniFiles.Instance.Set(IniFile.F76Custom, "Controls", "fPitchSpeedRatio", 0.5625f); - IniFiles.Instance.Set(IniFile.F76Custom, "Controls", "fIronSightsPitchSpeedRatio", 0.8f); - } - } - } - ); - - // Fix aim sensitivity - uiLoader.LinkCustom(this.checkBoxFixAimSensitivity, - () => Math.Abs(IniFiles.Instance.GetFloat("Main", "fIronSightsFOVRotateMult", 0f) - 2.14f) < 0.1f, - (value) => { - if (value) - { - IniFiles.Instance.Set(!alternativeMode ? IniFile.F76Custom : IniFile.F76, "Controls", "fIronSightsFOVRotateMult", 2.136363636f); - IniFiles.Instance.Set(!alternativeMode ? IniFile.F76Custom : IniFile.F76, "Main", "fIronSightsFOVRotateMult", 2.136363636f); - } - else - { - IniFiles.Instance.Remove(IniFile.F76Custom, "Controls", "fIronSightsFOVRotateMult"); - IniFiles.Instance.Remove(IniFile.F76Custom, "Main", "fIronSightsFOVRotateMult"); - if (alternativeMode) - { - IniFiles.Instance.Set(IniFile.F76, "Controls", "fIronSightsFOVRotateMult", 1.0f); - IniFiles.Instance.Set(IniFile.F76, "Main", "fIronSightsFOVRotateMult", 1.0f); - } - } - } - ); - - // Mouse sensitivity slider - uiLoader.LinkCustom(this.numMouseSensitivity, - () => IniFiles.Instance.GetFloat("Controls", "fMouseHeadingSensitivity", 0.03f), - (value) => { - // Fallout76Custom.ini had no effect. I hope Fallout76Prefs.ini will have an effect this time: - IniFiles.Instance.Set(IniFile.F76Prefs, "Controls", "fMouseHeadingSensitivity", value); - IniFiles.Instance.Set(IniFile.F76Prefs, "Controls", "fMouseHeadingSensitivityY", value); - } - ); - - // Gamepad - uiLoader.LinkBool(this.checkBoxGamepadEnabled, IniFile.F76Prefs, "General", "bGamepadEnable", true); - uiLoader.LinkBool(this.checkBoxGamepadRumble, !alternativeMode ? IniFile.F76Custom : IniFile.F76Prefs, "Controls", "bGamePadRumble", true); - - uiLoader.LinkBool(this.checkBoxMouseInvertX, IniFile.F76Prefs, "Controls", "bInvertXValues", false); - uiLoader.LinkBool(this.checkBoxMouseInvertY, IniFile.F76Prefs, "Controls", "bInvertYValues", false); - - - - /* - * Pipboy - */ - - // Radiobuttons, Quickboy or Pipboy - uiLoader.LinkBool(this.radioButtonQuickboy, this.radioButtonPipboy, IniFile.F76Prefs, "Pipboy", "bQuickboyMode", false); - - // Resolution - uiLoader.LinkInt(this.numPipboyTargetWidth, IniFile.F76Prefs, "Display", "uPipboyTargetWidth", 876); - uiLoader.LinkInt(this.numPipboyTargetHeight, IniFile.F76Prefs, "Display", "uPipboyTargetHeight", 700); - - - /* - * Camera - */ - - - // Vanity mode - uiLoader.LinkBool(this.checkBoxVanityMode, !alternativeMode ? IniFile.F76Custom : IniFile.F76, "Camera", "bDisableAutoVanityMode", false, true); - uiLoader.LinkBool(this.checkBoxForceVanityMode, !alternativeMode ? IniFile.F76Custom : IniFile.F76, "Camera", "bForceAutoVanityMode", false); - uiLoader.LinkCustom(this.checkBoxVanityMode, - () => this.checkBoxVanityMode.Checked, - (value) => - { - this.checkBoxForceVanityMode.Enabled = this.checkBoxVanityMode.Checked; - if (!this.checkBoxVanityMode.Checked) - { - this.checkBoxForceVanityMode.Checked = false; - IniFiles.Instance.Remove(IniFile.F76Custom, "Camera", "bForceAutoVanityMode"); - if (alternativeMode) - IniFiles.Instance.Set(IniFile.F76, "Camera", "bForceAutoVanityMode", false); - } - } - ); - uiLoader.Add(() => this.checkBoxForceVanityMode.Enabled = this.checkBoxVanityMode.Checked); - - // 1st person FOV - uiLoader.LinkCustom(this.numFirstPersonFOV, - () => IniFiles.Instance.GetFloat("Display", "fDefault1stPersonFOV", 80), - (value) => { - if (!alternativeMode) - { - IniFiles.Instance.Set(IniFile.F76Custom, "Display", "fDefault1stPersonFOV", value); - IniFiles.Instance.Set(IniFile.F76Custom, "Interface", "fDefault1stPersonFOV", value); - } - IniFiles.Instance.Set(IniFile.F76Prefs, "Display", "fDefault1stPersonFOV", value); - IniFiles.Instance.Set(IniFile.F76Prefs, "Interface", "fDefault1stPersonFOV", value); - } - ); - - // World FOV - uiLoader.LinkCustom(this.numWorldFOV, - () => IniFiles.Instance.GetFloat("Display", "fDefaultWorldFOV", 80), - (value) => { - if (!alternativeMode) - { - IniFiles.Instance.Set(IniFile.F76Custom, "Display", "fDefaultWorldFOV", value); - IniFiles.Instance.Set(IniFile.F76Custom, "Interface", "fDefaultWorldFOV", value); - } - IniFiles.Instance.Set(IniFile.F76Prefs, "Display", "fDefaultWorldFOV", value); - IniFiles.Instance.Set(IniFile.F76Prefs, "Interface", "fDefaultWorldFOV", value); - } - ); - - // 3rd person ADS FOV - uiLoader.LinkInt(this.numADSFOV, !alternativeMode ? IniFile.F76Custom : IniFile.F76, "Camera", "f3rdPersonAimFOV", 50); - - // fDefaultFOV - uiLoader.LinkInt(this.numfDefaultFOV, !alternativeMode ? IniFile.F76Custom : IniFile.F76, "Display", "fDefaultFOV", 80); - - // bApplyCameraNodeAnimations - uiLoader.LinkBool(this.checkBoxbApplyCameraNodeAnimations, !alternativeMode ? IniFile.F76Custom : IniFile.F76, "Camera", "bApplyCameraNodeAnimations", true); - - // Camera distance - uiLoader.LinkInt(this.numCameraDistanceMinimum, !alternativeMode ? IniFile.F76Custom : IniFile.F76, "Camera", "fVanityModeMinDist", 0); - uiLoader.LinkInt(this.numCameraDistanceMaximum, !alternativeMode ? IniFile.F76Custom : IniFile.F76, "Camera", "fVanityModeMaxDist", 150); - - // fPitchZoomOutMaxDist - uiLoader.LinkInt(this.numfPitchZoomOutMaxDist, !alternativeMode ? IniFile.F76Custom : IniFile.F76, "Camera", "fPitchZoomOutMaxDist", 100); - - // Switch delay - uiLoader.LinkFloat(this.numCameraSwitchDelay, !alternativeMode ? IniFile.F76Custom : IniFile.F76, "Camera", "f1st3rdSwitchDelay", 0.25f); - } - - #endregion - - - /* - ************************************************************** - * Event handlers - ************************************************************** - */ - - #region Nuclear Winter Mode - // Nuclear Winter mode - - private void toolStripButtonToggleNuclearWinterMode_Click(object sender, EventArgs e) - { - if (Shared.NuclearWinterMode) - DisableNuclearWinterMode(); - else - EnableNuclearWinterMode(); - } - - private void RefreshNWModeButtonAppearance() - { - if (Shared.NuclearWinterMode) - { - this.toolStripButtonToggleNuclearWinterMode.Text = Localization.GetString("adventuremode"); - this.toolStripButtonToggleNuclearWinterMode.Image = Resources.adventures; - } - else - { - this.toolStripButtonToggleNuclearWinterMode.Text = Localization.GetString("nuclearwintermode"); - this.toolStripButtonToggleNuclearWinterMode.Image = Resources.fire; - } - } - - private void LoadNuclearWinterConfiguration() - { - // NW mode enabled? - Shared.NuclearWinterMode = IniFiles.Instance.GetBool(IniFile.Config, "NuclearWinter", "bNWMode", - IniFiles.Instance.GetBool(IniFile.Config, "Preferences", "bNWMode", false) // backward compatibility - ); - - // Show label: - this.labelNWModeActive.Visible = Shared.NuclearWinterMode; - - // Fallout76Custom.ini renamed? - IniFiles.Instance.renameF76Custom = Shared.NuclearWinterMode && IniFiles.Instance.GetBool(IniFile.Config, "NuclearWinter", "bRenameCustomINI", true); - - // Change button appearance: - RefreshNWModeButtonAppearance(); - } - - public void DisableUI() - { - this.pictureBoxLoadingGIF.Visible = true; - this.pictureBoxLoadingGIF.Width = this.Width; - } - - public void EnableUI() - { - this.pictureBoxLoadingGIF.Visible = false; - } - - private void EnableNuclearWinterMode() - { - DisableUI(); - this.backgroundWorkerEnableNWMode.RunWorkerAsync(); - this.labelNWModeActive.Visible = true; - } - - private void DisableNuclearWinterMode() - { - DisableUI(); - this.backgroundWorkerDisableNWMode.RunWorkerAsync(); - this.labelNWModeActive.Visible = false; - } - - private void backgroundWorkerEnableNWMode_DoWork(object sender, DoWorkEventArgs e) - { - Shared.NuclearWinterMode = true; - - /* - * Fallout76Custom.ini: - */ - // Remove resource lists: - ManagedMods.Instance.WriteToF76Custom = false; - ManagedMods.Instance.ResolveNWResourceLists(); - - // Rename *.ini: - IniFiles.Instance.renameF76Custom = IniFiles.Instance.GetBool(IniFile.Config, "NuclearWinter", "bRenameCustomINI", true); - IniFiles.Instance.ResolveNWMode(); - - - /* - * Mods: - */ - - // Mods are deployed, automatically disable mods? - if (!ManagedMods.Instance.ModsDisabled && - IniFiles.Instance.GetBool(IniFile.Config, "NuclearWinter", "bAutoDisableMods", false)) - { - ManagedMods.Instance.ModsDisabled = true; - this.Invoke(this.formMods.OpenUI); - this.formMods.Deploy(); - this.Invoke(this.formMods.Hide); - this.Invoke(() => { this.Focus(); }); - } - - - /* - * *.dll's: - */ - - // Rename added *.dll files: - if (IniFiles.Instance.GetBool(IniFile.Config, "NuclearWinter", "bRenameDLLs", true)) - ManagedMods.Instance.RenameAddedDLLs(); - - - /* - * Configuration: - */ - - // Save configuration: - IniFiles.Instance.Set(IniFile.Config, "NuclearWinter", "bNWMode", true); - //IniFiles.Instance.Set(IniFile.Config, "Preferences", "bNWMode", true); - IniFiles.Instance.Remove(IniFile.Config, "Preferences", "bNWMode"); - IniFiles.Instance.SaveAll(); - } - - private void backgroundWorkerDisableNWMode_DoWork(object sender, DoWorkEventArgs e) - { - Shared.NuclearWinterMode = false; - - /* - * Fallout76Custom.ini: - */ - // Restore archive lists: - ManagedMods.Instance.WriteToF76Custom = true; - ManagedMods.Instance.ResolveNWResourceLists(); - - // Restore *.ini: - IniFiles.Instance.renameF76Custom = false; - IniFiles.Instance.ResolveNWMode(); - - - /* - * Mods: - */ - - // Mods haven't been deployed yet, automatically enable mods? - if (ManagedMods.Instance.ModsDisabled && - ManagedMods.Instance.Mods.Count() > 0 && - IniFiles.Instance.GetBool(IniFile.Config, "NuclearWinter", "bAutoDeployMods", false)) - { - ManagedMods.Instance.ModsDisabled = false; - this.Invoke(this.formMods.OpenUI); - this.formMods.Deploy(); - this.Invoke(this.formMods.Hide); - this.Invoke(() => { this.Focus(); }); - } - - - /* - * *.dll's: - */ - - // Restore added *.dll files: - ManagedMods.Instance.RestoreAddedDLLs(); - - - /* - * Configuration: - */ - - // Save configuration: - IniFiles.Instance.Set(IniFile.Config, "NuclearWinter", "bNWMode", false); - //IniFiles.Instance.Set(IniFile.Config, "Preferences", "bNWMode", false); - IniFiles.Instance.Remove(IniFile.Config, "Preferences", "bNWMode"); - IniFiles.Instance.SaveAll(); - } - - private void backgroundWorkerEnableNWMode_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) + private void toolInstallationFolderToolStripMenuItem_Click(object sender, EventArgs e) { - // Popup: - MsgBox.Get("nwModeEnabled").Popup(MessageBoxIcon.Information); - - RefreshNWModeButtonAppearance(); - EnableUI(); + Utils.OpenExplorer(Directory.GetParent(Application.ExecutablePath).ToString()); } - private void backgroundWorkerDisableNWMode_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) + private void gameFolderToolStripMenuItem_Click(object sender, EventArgs e) { - // Popup: - MsgBox.Get("nwModeDisabled").Popup(MessageBoxIcon.Information); - - RefreshNWModeButtonAppearance(); - EnableUI(); + Utils.OpenExplorer(this.game.GamePath); } - #endregion - - #region Apply, Launch, and so on. - public void ApplyChanges() - { - // Add custom lines to *.ini files: - try - { - String f76Path = Path.Combine(IniFiles.Instance.iniParentPath, "Fallout76.add.ini"); - if (File.Exists(f76Path)) - { - IniData f76Data = IniFiles.Instance.LoadIni(f76Path, false); - IniFiles.Instance.Merge(IniFile.F76, f76Data); - } - - String f76PPath = Path.Combine(IniFiles.Instance.iniParentPath, "Fallout76Prefs.add.ini"); - if (File.Exists(f76PPath)) - { - IniData f76PData = IniFiles.Instance.LoadIni(f76PPath, false); - IniFiles.Instance.Merge(IniFile.F76Prefs, f76PData); - } - String f76CPath = Path.Combine(IniFiles.Instance.iniParentPath, "Fallout76Custom.add.ini"); - if (File.Exists(f76CPath)) - { - IniData f76CData = IniFiles.Instance.LoadIni(f76CPath, false); - IniFiles.Instance.Merge(IniFile.F76Custom, f76CData); - } - } - catch (IniParser.Exceptions.ParsingException e) - { - MsgBox.Get("customIniFilesParsingError").FormatText(e.Message).Show(MessageBoxIcon.Error); - } - - // Save changes: - ColorUi2Ini(); - IniFiles.Instance.SaveAll(this.checkBoxReadOnly.Checked); - IniFiles.Instance.ResolveNWMode(); - } - - // "Apply" button: - private void toolStripButtonApply_Click(object sender, EventArgs e) + private void gamesConfigurationFolderToolStripMenuItem_Click(object sender, EventArgs e) { - // Show a messagebox to ask the user, if they want to make a backup. - if (!IniFiles.Instance.GetBool(IniFile.Config, "Preferences", "bSkipBackupQuestion", false)) - { - DialogResult res = MsgBox.Get("backupAndSave").Show(MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question); - if (res == DialogResult.Cancel) - return; - else if (res == DialogResult.Yes) - // Make backups - IniFiles.Instance.BackupAll(); - } - - // Save stuff to INI - ApplyChanges(); - MsgBox.Get("changesApplied").Popup(MessageBoxIcon.Information); + Utils.OpenExplorer(IniFiles.ParentPath); } - // [ ] "Make *.ini files read-only" checkbox: - private void checkBoxReadOnly_CheckedChanged(object sender, EventArgs e) + private void toolStripButtonNexusMods_Click(object sender, EventArgs e) { - IniFiles.Instance.SetINIsReadOnly(this.checkBoxReadOnly.Checked); + System.Diagnostics.Process.Start("https://www.nexusmods.com/fallout76/mods/546"); } - // "Launch Game" button: - private void toolStripSplitButtonLaunchGame_ButtonClick(object sender, EventArgs e) + private void checkForUpdatesToolStripMenuItem_Click(object sender, EventArgs e) { - uint uGameEdition = IniFiles.Instance.GetUInt(IniFile.Config, "Preferences", "uGameEdition", 0); - uint uLaunchOption = IniFiles.Instance.GetUInt(IniFile.Config, "Preferences", "uLaunchOption", 1); - String process = null; - bool runExecutable = false; - if (uLaunchOption == 1) - { - switch (uGameEdition) - { - case (uint)GameEdition.BethesdaNet: - process = "bethesdanet://run/20"; - break; - case (uint)GameEdition.Steam: - process = "steam://run/1151340"; // "steam://runappid/1151340" - break; - case (uint)GameEdition.BethesdaNetPTS: - process = "bethesdanet://run/57"; - break; - case (uint)GameEdition.MSStore: - process = "ms-windows-store://pdp/?ProductId=9nkgnmnk3k3z"; - break; - default: - MsgBox.Get("chooseGameEdition").Show(MessageBoxButtons.OK, MessageBoxIcon.Information); - return; - } - } - else if (uLaunchOption == 2) - { - if (!ManagedMods.Instance.ValidateGamePath()) - { - MsgBox.Get("modsGamePathNotSet").Show(MessageBoxButtons.OK, MessageBoxIcon.Information); - return; - } - process = Path.GetFullPath(Path.Combine(Shared.GamePath, Shared.GameEdition == GameEdition.MSStore ? "Project76_GamePass.exe" : "Fallout76.exe")); - runExecutable = true; - } - if (process != null) - { - if (IniFiles.Instance.GetBool(IniFile.Config, "Preferences", "bAutoApply", false)) - ApplyChanges(); - try - { - if (runExecutable) - { - // https://stackoverflow.com/questions/8720594/application-crashing-on-startup-using-process-start - // https://www.vbforums.com/showthread.php?489619-RESOLVED-2-0-Process-Start()-crashing-external-app - Process pr = new Process(); - pr.StartInfo.FileName = process; // Shared.GameEdition == GameEdition.MSStore ? "Project76_GamePass.exe" : "Fallout76.exe"; - pr.StartInfo.WorkingDirectory = Shared.GamePath; - pr.StartInfo.UseShellExecute = false; - pr.Start(); - } - else - { - System.Diagnostics.Process.Start(process); - } - if (IniFiles.Instance.GetBool(IniFile.Config, "Preferences", "bQuitOnLaunch", false)) - this.Close(); - } - catch (Exception ex) - { - if (Shared.GameEdition == GameEdition.MSStore) - { - MsgBox.Get("msstoreRunExecutableFailed").FormatTitle(ex.Message).Show(MessageBoxIcon.Error); - return; - } - } - } + CheckVersion(true); } - #endregion - - #region Event handlers - - // "Get the latest version from NexusMods" link: - private void linkLabel1_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) + private void showUpdaterlogtxtToolStripMenuItem_Click(object sender, EventArgs e) { - linkLabelManualDownloadPage.LinkVisited = true; - System.Diagnostics.Process.Start("https://www.nexusmods.com/fallout76/mods/546?tab=files"); + if (File.Exists(Path.Combine(Shared.AppConfigFolder, "update.log.txt"))) + Utils.OpenNotepad(Path.Combine(Shared.AppConfigFolder, "update.log.txt")); } - - /* - * Pipboy - */ - - private void buttonPipboyTargetReset_Click(object sender, EventArgs e) + private void editFallout76iniToolStripMenuItem_Click(object sender, EventArgs e) { - this.numPipboyTargetWidth.Value = 876; - this.numPipboyTargetHeight.Value = 700; + if (File.Exists(IniFiles.F76.FilePath)) + Utils.OpenFile(IniFiles.F76.FilePath); } - private void buttonPipboyTargetSetRecommended_Click(object sender, EventArgs e) + private void editFallout76PrefsiniToolStripMenuItem_Click(object sender, EventArgs e) { - this.numPipboyTargetWidth.Value = 1752; - this.numPipboyTargetHeight.Value = 1400; + if (File.Exists(IniFiles.F76Prefs.FilePath)) + Utils.OpenFile(IniFiles.F76Prefs.FilePath); } - - - private void toolStripButtonManageMods_Click(object sender, EventArgs e) + private void editFallout76CustominiToolStripMenuItem_Click(object sender, EventArgs e) { - /*if (!formModsBackupCreated) - { - IniFiles.Instance.BackupAll("Backup_BeforeManageMods"); // Just to be sure... - formModsBackupCreated = true; - }*/ - this.formMods.OpenUI(); + if (File.Exists(IniFiles.F76Custom.FilePath)) + Utils.OpenFile(IniFiles.F76Custom.FilePath); } - /* - * Game edition - */ - - private void ChangeGameEdition(GameEdition edition) + private void steamScreenshotFolderToolStripMenuItem_Click(object sender, EventArgs e) { - bool restartRequired = Shared.GameEdition != GameEdition.Unknown && ((Shared.GameEdition == GameEdition.MSStore && edition != GameEdition.MSStore) || (Shared.GameEdition != GameEdition.MSStore && edition == GameEdition.MSStore)); - - if (restartRequired && MsgBox.Get("msstoreRestartRequired").Show(MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.No) - { - switch (Shared.GameEdition) - { - case GameEdition.Steam: - this.radioButtonEditionSteam.Checked = true; - break; - case GameEdition.BethesdaNet: - this.radioButtonEditionBethesdaNet.Checked = true; - break; - case GameEdition.BethesdaNetPTS: - this.radioButtonEditionBethesdaNetPTS.Checked = true; - break; - case GameEdition.MSStore: - this.radioButtonEditionMSStore.Checked = true; - break; - } - return; - } - - // Change image - switch (edition) - { - case GameEdition.Steam: - this.pictureBoxGameEdition.Image = Properties.Resources.steam; - this.labelGameEdition.Text = "Steam"; - break; - case GameEdition.BethesdaNet: - this.pictureBoxGameEdition.Image = Properties.Resources.bethesda; - this.labelGameEdition.Text = "Bethesda"; - break; - case GameEdition.BethesdaNetPTS: - this.pictureBoxGameEdition.Image = Properties.Resources.bethesda_pts; - this.labelGameEdition.Text = "Bethesda\n(PTS)"; - break; - case GameEdition.MSStore: - this.pictureBoxGameEdition.Image = Properties.Resources.msstore; - this.labelGameEdition.Text = "Microsoft\nStore"; - break; - default: - this.pictureBoxGameEdition.Image = Properties.Resources.help_128; - this.labelGameEdition.Text = "Unknown"; - break; - } - - // Currently, no way to launch game executable, if installed via MS Store: - /*if (edition == GameEdition.MSStore) - { - IniFiles.Instance.Set(IniFile.Config, "Preferences", "uLaunchOption", 1); - - this.radioButtonLaunchViaExecutable.Checked = false; - this.radioButtonLaunchViaExecutable.Enabled = false; - this.radioButtonLaunchViaLink.Checked = true; - } - else - { - this.radioButtonLaunchViaExecutable.Enabled = true; - }*/ - - Shared.ChangeGameEdition(edition); - //this.formMods.ChangeGameEdition(edition); - this.formMods.UpdateUI(); - this.textBoxGamePath.Text = Shared.GamePath; - - if (restartRequired) + string steamFolder = @"C:\Program Files (x86)\Steam\userdata\"; + if (Directory.Exists(steamFolder)) { - IniFiles.Instance.SaveWindowState("Form1", this); - Application.Restart(); + steamFolder = Path.Combine(Directory.GetDirectories(steamFolder)[0], @"760\remote\1151340\screenshots"); + Utils.OpenExplorer(steamFolder); } } - private void radioButtonEditionSteam_CheckedChanged(object sender, EventArgs e) - { - if (this.radioButtonEditionSteam.Checked) - ChangeGameEdition(GameEdition.Steam); - } - - private void radioButtonEditionBethesdaNet_CheckedChanged(object sender, EventArgs e) - { - if (this.radioButtonEditionBethesdaNet.Checked) - ChangeGameEdition(GameEdition.BethesdaNet); - } - - private void radioButtonEditionBethesdaNetPTS_CheckedChanged(object sender, EventArgs e) - { - if (this.radioButtonEditionBethesdaNetPTS.Checked) - ChangeGameEdition(GameEdition.BethesdaNetPTS); - } - - private void radioButtonEditionMSStore_CheckedChanged(object sender, EventArgs e) - { - if (this.radioButtonEditionMSStore.Checked) - ChangeGameEdition(GameEdition.MSStore); - } - - // Show password: - private void checkBoxShowPassword_CheckedChanged(object sender, EventArgs e) - { - // https://stackoverflow.com/questions/8185747/how-can-i-unmask-password-text-box-and-mask-it-back-to-password - this.textBoxPassword.UseSystemPasswordChar = !this.checkBoxShowPassword.Checked; - this.textBoxPassword.PasswordChar = !this.checkBoxShowPassword.Checked ? '\u2022' : '\0'; - } - - // Detect resolution: - private void buttonDetectResolution_Click(object sender, EventArgs e) + private void gamePhotosFolderToolStripMenuItem_Click(object sender, EventArgs e) { - int[] res = Utils.GetDisplayResolution(); - String resStr = $"{res[0]}x{res[1]}"; - - DropDown resolution = DropDown.Get("Resolution"); - if (resolution.Contains(resStr)) - { - int index = resolution.FindIndex(resStr); - resolution.SelectedIndex = index; - } - else + string photosFolder = Path.Combine(IniFiles.ParentPath, "Photos"); + if (Directory.Exists(photosFolder)) { - resolution.SelectedIndex = 0; + photosFolder = Directory.GetDirectories(photosFolder)[0]; + Utils.OpenExplorer(photosFolder); } - this.numCustomResW.Value = res[0]; - this.numCustomResH.Value = res[1]; } - private void checkBoxQuitOnGameLaunch_CheckedChanged(object sender, EventArgs e) + private void showSettings_OnClick(object sender, EventArgs e) { - IniFiles.Instance.Set(IniFile.Config, "Preferences", "bQuitOnLaunch", this.checkBoxQuitOnGameLaunch.Checked); + formSettings.ShowSettings(); } - private void checkBoxAutoApply_CheckedChanged(object sender, EventArgs e) + private void showProfiles_OnClick(object sender, EventArgs e) { - IniFiles.Instance.Set(IniFile.Config, "Preferences", "bAutoApply", this.checkBoxAutoApply.Checked); + formSettings.ShowProfiles(); } - private void checkBoxSkipBackupQuestion_CheckedChanged(object sender, EventArgs e) + #endregion + + // Check, if *.ini files have been changed: + private void timerCheckFiles_Tick(object sender, EventArgs e) { - IniFiles.Instance.Set(IniFile.Config, "Preferences", "bSkipBackupQuestion", this.checkBoxSkipBackupQuestion.Checked); + // TODO: Give an option to reload the *.ini files. + // Check every 5 seconds, if files have been modified: + if (IniFiles.FilesHaveBeenModified()) + { + IniFiles.UpdateLastModifiedDates(); + + // Don't prompt, if Fallout 76 is running... + if (!Utils.IsProcessRunning("Project76") && // !Utils.IsProcessRunning("Project76_GamePass") && + !Utils.IsProcessRunning("Fallout76")) + MsgBox.Get("iniFilesModified").Popup(MessageBoxIcon.Warning); + } } - private void checkBoxOpenManageModsOnLaunch_CheckedChanged(object sender, EventArgs e) + private void linkLabelAttribution_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) { - IniFiles.Instance.Set(IniFile.Config, "Preferences", "bOpenModManagerOnLaunch", this.checkBoxOpenManageModsOnLaunch.Checked); + Utils.OpenNotepad(@"Attribution.txt"); } - private void buttonUpdateNow_Click(object sender, EventArgs e) + private void linkLabelWhatsNew_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) { - // Set sInstallationPath: - String installationPath = Path.GetFullPath(AppContext.BaseDirectory); - IniFiles.Instance.Set(IniFile.Config, "Updater", "sInstallationPath", installationPath); - IniFiles.Instance.SaveConfig(); + ShowWhatsNew(); + } - // Copy updater.exe to \Updater\: - String updaterPath = Path.Combine(Shared.AppConfigFolder, "Updater"); - List updaterFiles = new List() { - "7z\\7za.dll", - "7z\\7za.exe", - "7z\\7zxa.dll", - "INIFileParser.dll", - "INIFileParser.xml", - "Newtonsoft.Json.dll", - "Newtonsoft.Json.xml", - "updater.exe", - "updater.exe.config", - "updater.pdb" - }; - Directory.CreateDirectory(updaterPath); - Directory.CreateDirectory(Path.Combine(updaterPath, "7z")); - foreach (String file in updaterFiles) - File.Copy(file, Path.Combine(updaterPath, file), true); + private void MakePictureBoxButton(PictureBox pictureBox, string localizedStringID) + { + pictureBox.Paint += new PaintEventHandler((paintSender, paintEventArgs) => + { + paintEventArgs.Graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit; - // Run updater.exe: - ProcessStartInfo startInfo = new ProcessStartInfo(); - startInfo.FileName = Path.Combine(updaterPath, "updater.exe"); - // If the program is installed into C:\Program Files (x86)\ then run the updater as admin: - if (installationPath.Contains("C:\\Program Files")) - startInfo.Verb = "runas"; - Process.Start(startInfo); - Application.Exit(); - //Environment.Exit(0); + string text = Localization.GetString(localizedStringID); + + Font font = new Font("Microsoft Sans Serif", 12f, FontStyle.Bold); + + SizeF textSize = paintEventArgs.Graphics.MeasureString(text, font); + PointF locationToDraw = new PointF(); + locationToDraw.X = (pictureBox.Width / 2) - (textSize.Width / 2); + locationToDraw.Y = (pictureBox.Height / 2) - (textSize.Height / 2); + + paintEventArgs.Graphics.DrawString(text, font, Brushes.White, locationToDraw); + }); + pictureBox.MouseEnter += new EventHandler((mouseSender, mouseEventArgs) => + { + pictureBox.Image = Resources.button_hover; + pictureBox.Cursor = Cursors.Hand; + }); + pictureBox.MouseLeave += new EventHandler((mouseSender, mouseEventArgs) => + { + pictureBox.Image = Resources.button; + pictureBox.Cursor = Cursors.Default; + }); } - private void pictureBoxUpdateButton_Click(object sender, EventArgs e) + public void DisableUI() { - buttonUpdateNow_Click(sender, e); + this.pictureBoxLoadingGIF.Visible = true; + this.pictureBoxLoadingGIF.Width = this.Width; } - private void checkBoxIgnoreUpdates_CheckedChanged(object sender, EventArgs e) + public void EnableUI() { - IniFiles.Instance.Set(IniFile.Config, "Preferences", "bIgnoreUpdates", this.checkBoxIgnoreUpdates.Checked); - this.CheckVersion(); + this.pictureBoxLoadingGIF.Visible = false; } - + #region Credentials /* - * Game path + * Credentials */ - // Pick game path - private void buttonPickGamePath_Click(object sender, EventArgs e) + List accountProfileRadioButtons { - if (ManagedMods.Instance.isDeploymentNecessary()) - { - MsgBox.ShowID("modsDeploymentNecessary"); - return; - } - if (this.openFileDialogGamePath.ShowDialog() == DialogResult.OK) + get { - String path = Path.GetDirectoryName(this.openFileDialogGamePath.FileName); // We want the path where Fallout76.exe resides. - if (Directory.Exists(Path.Combine(path, "Data"))) - { - this.textBoxGamePath.Text = path; - Shared.GamePath = path; - Shared.SaveGamePath(); - ManagedMods.Instance.Load(); - } - else - MsgBox.ShowID("modsGamePathInvalid"); + return new List { + radioButtonAccount1, + radioButtonAccount2, + radioButtonAccount3, + radioButtonAccount4, + radioButtonAccount5, + radioButtonAccount6, + radioButtonAccount7, + radioButtonAccount8, + radioButtonAccount9, + radioButtonAccount10, + radioButtonAccount11, + radioButtonAccount12, + radioButtonAccount13, + radioButtonAccount14, + radioButtonAccount15, + radioButtonAccount16 + }; } } - // Game path textbox changed - private void textBoxGamePath_TextChanged(object sender, EventArgs e) + // Show password: + private void checkBoxShowPassword_CheckedChanged(object sender, EventArgs e) { - if (this.textBoxGamePath.Focused) - { - if (ManagedMods.Instance.isDeploymentNecessary()) - { - if (this.textBoxGamePath.Text != Shared.GamePath) - this.textBoxGamePath.Text = Shared.GamePath; - return; - } - else if (Directory.Exists(Path.Combine(this.textBoxGamePath.Text, "Data"))) - { - Shared.GamePath = this.textBoxGamePath.Text; - Shared.SaveGamePath(); - ManagedMods.Instance.Load(); - this.textBoxGamePath.ForeColor = Color.Black; - this.textBoxGamePath.BackColor = Color.White; - } - else - { - this.textBoxGamePath.ForeColor = Color.White; - this.textBoxGamePath.BackColor = Color.Red; - } - } + // https://stackoverflow.com/questions/8185747/how-can-i-unmask-password-text-box-and-mask-it-back-to-password + this.textBoxPassword.UseSystemPasswordChar = !this.checkBoxShowPassword.Checked; + this.textBoxPassword.PasswordChar = !this.checkBoxShowPassword.Checked ? '\u2022' : '\0'; } - private void radioButtonLaunchViaExecutable_CheckedChanged(object sender, EventArgs e) + private void textBoxUserName_TextChanged(object sender, EventArgs e) { - this.labelLaunchOptionTip.Visible = false; - this.labelLaunchOptionMSStoreNotice.Visible = false; - - if (Shared.GameEdition == GameEdition.BethesdaNet || Shared.GameEdition == GameEdition.BethesdaNetPTS) - this.labelLaunchOptionTip.Visible = this.radioButtonLaunchViaExecutable.Checked; - - else if (Shared.GameEdition == GameEdition.MSStore) - this.labelLaunchOptionMSStoreNotice.Visible = this.radioButtonLaunchViaExecutable.Checked; + int index = GetSelectedAccountProfileRadiobuttonIndex(); + if (this.textBoxUserName.Text == "") + { + IniFiles.Config.Remove("Login", $"s76UserName{index}"); + IniFiles.F76Custom.Remove("Login", "s76UserName"); + } + else + { + IniFiles.Config.Set("Login", $"s76UserName{index}", this.textBoxUserName.Text); + IniFiles.F76Custom.Set("Login", "s76UserName", this.textBoxUserName.Text); + } } - /* - * Tool strip: - */ - - private void toolConfigurationFolderToolStripMenuItem_Click(object sender, EventArgs e) + private void textBoxPassword_TextChanged(object sender, EventArgs e) { - Utils.OpenExplorer(Shared.AppConfigFolder); + int index = GetSelectedAccountProfileRadiobuttonIndex(); + if (this.textBoxPassword.Text == "") + { + IniFiles.Config.Remove("Login", $"s76Password{index}"); + IniFiles.F76Custom.Remove("Login", "s76Password"); + } + else + { + IniFiles.Config.Set("Login", $"s76Password{index}", this.textBoxPassword.Text); + IniFiles.F76Custom.Set("Login", "s76Password", this.textBoxPassword.Text); + } } - private void toolLanguagesFolderToolStripMenuItem_Click(object sender, EventArgs e) + // If a radiobuttons gets checked, load username and password of a profile. + private void radioButtonAccount_CheckedChanged(object sender, EventArgs e) { - Utils.OpenExplorer(Localization.languageFolder); + int index = GetSelectedAccountProfileRadiobuttonIndex(); + IniFiles.Config.Set("Login", "uActiveAccountProfile", index); + if (index == 0) + { + this.textBoxUserName.Text = IniFiles.GetString("Login", "s76UserName", ""); + this.textBoxPassword.Text = IniFiles.GetString("Login", "s76Password", ""); + } + else + { + this.textBoxUserName.Text = IniFiles.Config.GetString("Login", $"s76UserName{index}", ""); + this.textBoxPassword.Text = IniFiles.Config.GetString("Login", $"s76Password{index}", ""); + } } - private void toolInstallationFolderToolStripMenuItem_Click(object sender, EventArgs e) + private void radioButtonAccountNone_CheckedChanged(object sender, EventArgs e) { - Utils.OpenExplorer(Directory.GetParent(Application.ExecutablePath).ToString()); + this.textBoxUserName.Text = IniFiles.GetString("Login", "s76UserName", ""); + this.textBoxPassword.Text = IniFiles.GetString("Login", "s76Password", ""); } - private void gameFolderToolStripMenuItem_Click(object sender, EventArgs e) + private int GetSelectedAccountProfileRadiobuttonIndex() { - Utils.OpenExplorer(Shared.GamePath); + int index = 1; + foreach (RadioButton rbutton in accountProfileRadioButtons) + { + if (rbutton.Checked) + break; + index++; + } + if (index > accountProfileRadioButtons.Count) + index = 0; + return index; } - private void gamesConfigurationFolderToolStripMenuItem_Click(object sender, EventArgs e) + private void SetSelectedAccountProfileRadiobuttonIndex(int index) { - Utils.OpenExplorer(IniFiles.Instance.iniParentPath); + if (index <= 0) + { + this.radioButtonAccountNone.Checked = true; + return; + } + accountProfileRadioButtons[index - 1].Checked = true; } - private void toolStripButtonNexusMods_Click(object sender, EventArgs e) + // Assigns event handler to radiobuttons (Account #1, Account #2, ...): + private void InitAccountProfileRadiobuttons() { - System.Diagnostics.Process.Start("https://www.nexusmods.com/fallout76/mods/546"); + foreach (RadioButton rbutton in accountProfileRadioButtons) + rbutton.CheckedChanged += radioButtonAccount_CheckedChanged; } - private void checkForUpdatesToolStripMenuItem_Click(object sender, EventArgs e) + // Gets current account profile and sets the according radiobutton + private void LoadAccountProfile() { - CheckVersion(true); + //int index = IniFiles.Config.GetInt("Login", "uActiveAccountProfile", 0); + int index = 0; + string username = IniFiles.GetString("Login", "s76UserName", ""); + string password = IniFiles.GetString("Login", "s76Password", ""); + if (username != "" && password != "") + { + for (int i = 1; i <= accountProfileRadioButtons.Count(); i++) + { + if (username == IniFiles.Config.GetString("Login", $"s76UserName{i}", "") && + password == IniFiles.Config.GetString("Login", $"s76Password{i}", "")) + { + index = i; + break; + } + } + } + SetSelectedAccountProfileRadiobuttonIndex(index); } + #endregion - private void showUpdaterlogtxtToolStripMenuItem_Click(object sender, EventArgs e) - { - if (File.Exists(Path.Combine(Shared.AppConfigFolder, "update.log.txt"))) - Utils.OpenNotepad(Path.Combine(Shared.AppConfigFolder, "update.log.txt")); - } + #region Custom tab - private String customAddFilePath = ""; + private string customAddFilePath = null; private void comboBoxCustomFile_SelectedIndexChanged(object sender, EventArgs e) { - String fileName = "Invalid.add.ini"; + string fileName; switch (this.comboBoxCustomFile.SelectedIndex) { case 0: - fileName = "Fallout76.add.ini"; + fileName = $"{game.IniPrefix}.add.ini"; break; case 1: - fileName = "Fallout76Prefs.add.ini"; + fileName = $"{game.IniPrefix}Prefs.add.ini"; break; case 2: - fileName = "Fallout76Custom.add.ini"; + fileName = $"{game.IniPrefix}Custom.add.ini"; break; + default: + return; } - this.customAddFilePath = Path.Combine(IniFiles.Instance.iniParentPath, fileName); + this.customAddFilePath = Path.Combine(IniFiles.ParentPath, fileName); if (File.Exists(this.customAddFilePath)) this.textBoxCustom.Text = File.ReadAllText(this.customAddFilePath); @@ -2033,213 +1039,203 @@ private void buttonCustomSave_Click(object sender, EventArgs e) this.buttonCustomSave.Text = this.buttonCustomSave.Text.TrimEnd('*'); } - private void editFallout76iniToolStripMenuItem_Click(object sender, EventArgs e) + private void LoadCustomTab () { - if (File.Exists(IniFiles.Instance.GetIniPath(IniFile.F76))) - Utils.OpenNotepad(IniFiles.Instance.GetIniPath(IniFile.F76)); + this.comboBoxCustomFile.Items.Clear(); + this.comboBoxCustomFile.Items.AddRange(new string[] { + $"{game.IniPrefix}.ini", + $"{game.IniPrefix}Prefs.ini", + $"{game.IniPrefix}Custom.ini" + }); + this.comboBoxCustomFile.SelectedIndex = 0; } - private void editFallout76PrefsiniToolStripMenuItem_Click(object sender, EventArgs e) - { - if (File.Exists(IniFiles.Instance.GetIniPath(IniFile.F76Prefs))) - Utils.OpenNotepad(IniFiles.Instance.GetIniPath(IniFile.F76Prefs)); - } + #endregion - private void editFallout76CustominiToolStripMenuItem_Click(object sender, EventArgs e) + #region Resolution combobox + + // Detect resolution: + private void buttonDetectResolution_Click(object sender, EventArgs e) { - if (File.Exists(IniFiles.Instance.GetIniPath(IniFile.F76Custom))) - Utils.OpenNotepad(IniFiles.Instance.GetIniPath(IniFile.F76Custom)); + Size res = Utils.GetDisplayResolution(); + this.numCustomResW.Value = res.Width; + this.numCustomResH.Value = res.Height; } - private void steamScreenshotFolderToolStripMenuItem_Click(object sender, EventArgs e) + private void comboBoxResolution_SelectedIndexChanged(object sender, EventArgs e) { - String steamFolder = @"C:\Program Files (x86)\Steam\userdata\"; - if (Directory.Exists(steamFolder)) + // If "Custom" selected, skip: + if (this.comboBoxResolution.SelectedIndex == 0) + return; + + // If an invalid option has been selected, set to "Custom" and skip: + string res = this.comboBoxResolution.SelectedItem.ToString(); + Size? displaySize = GetResolutionFromString(res); + if (!displaySize.HasValue) { - steamFolder = Path.Combine(Directory.GetDirectories(steamFolder)[0], @"760\remote\1151340\screenshots"); - Utils.OpenExplorer(steamFolder); + this.comboBoxResolution.SelectedIndex = 0; + return; } + + int width = displaySize.Value.Width; + int height = displaySize.Value.Height; + + // Set the values of the NumericUpDowns (which in turn will trigger the event handlers which set the values in the *.ini files) + if (this.numCustomResW.Value != width) + this.numCustomResW.Value = width; + + if (this.numCustomResH.Value != height) + this.numCustomResH.Value = height; } - private void gamePhotosFolderToolStripMenuItem_Click(object sender, EventArgs e) + /// + /// Extracts width and height from a string that looks like this: "[16:9] 1920 x 1080 (Full HD)" + /// + /// Width and height if a valid option has been selected. Otherwise null. + private Size? GetResolutionFromString(String res) { - String photosFolder = Path.Combine(IniFiles.Instance.iniParentPath, "Photos"); - if (Directory.Exists(photosFolder)) - { - photosFolder = Directory.GetDirectories(photosFolder)[0]; - Utils.OpenExplorer(photosFolder); - } + if (!res.Contains("x")) + return null; + string[] split = res.Split('x').Select(x => x.Trim()).ToArray(); + int width = Convert.ToInt32(Regex.Match(split[0], @"[0-9]+$").Groups[0].Value); + int height = Convert.ToInt32(Regex.Match(split[1], @"^[0-9]+").Groups[0].Value); + return new Size(width, height); } - private int GetSelectedAccountProfile() + /// + /// Searches through the resolution combobox for an option that matches the given size. + /// + /// + /// The first occurence if a match was found. Otherwise -1. + private int FindIndexInResolutionComboBox(Size size) { - int index = 0; - foreach (RadioButton rbutton in this.accountProfileRadioButtons) + for (int i = 0; i < this.comboBoxResolution.Items.Count; i++) { - if (rbutton.Checked) - break; - index++; + string res = this.comboBoxResolution.Items[i].ToString(); + Size? s = GetResolutionFromString(res); + if (s?.Width == size.Width && s?.Height == size.Height) + return i; } - if (index >= this.accountProfileRadioButtons.Length) - index = 0; - return index; + return -1; } - private void checkBoxAlternativeINIMode_CheckedChanged(object sender, EventArgs e) + private void numCustomRes_ValueChanged(object sender, EventArgs e) { - bool altMode = IniFiles.Instance.GetBool(IniFile.Config, "Preferences", "bAlternativeINIMode", false); - - if (this.checkBoxAlternativeINIMode.Checked == altMode) - return; - - if (MsgBox.ShowID("restartRequired", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes) - { - IniFiles.Instance.Set(IniFile.Config, "Preferences", "bAlternativeINIMode", this.checkBoxAlternativeINIMode.Checked); - IniFiles.Instance.SaveConfig(); - //Application.Exit(); - Application.Restart(); - Environment.Exit(0); - } + Size size = new Size( + Convert.ToInt32(numCustomResW.Value), + Convert.ToInt32(numCustomResH.Value) + ); + int i = FindIndexInResolutionComboBox(size); + if (i > -1) + this.comboBoxResolution.SelectedIndex = i; else - { - this.checkBoxAlternativeINIMode.Checked = altMode; - } + this.comboBoxResolution.SelectedIndex = 0; } + #endregion - /* - * Credentials - */ + #region Pipboy - private void textBoxUserName_TextChanged(object sender, EventArgs e) + private void buttonPresetFo3Green_Click(object sender, EventArgs e) { - int index = GetSelectedAccountProfile(); - if (this.textBoxUserName.Text == "") - IniFiles.Instance.Remove(IniFile.Config, "Login", $"s76UserName{index + 1}"); - else - IniFiles.Instance.Set(IniFile.Config, "Login", $"s76UserName{index + 1}", this.textBoxUserName.Text); + this.colorPreviewPipboy.BackColor = Color.FromArgb(26, 255, 128); } - private void textBoxPassword_TextChanged(object sender, EventArgs e) + private void buttonPresetFoNVAmber_Click(object sender, EventArgs e) { - int index = GetSelectedAccountProfile(); - if (this.textBoxPassword.Text == "") - IniFiles.Instance.Remove(IniFile.Config, "Login", $"s76Password{index + 1}"); - else - IniFiles.Instance.Set(IniFile.Config, "Login", $"s76Password{index + 1}", this.textBoxPassword.Text); + this.colorPreviewPipboy.BackColor = Color.FromArgb(255, 182, 66); } - private void radioButtonAccount_CheckedChanged(object sender, EventArgs e) + private void buttonPresetFo3Blue_Click(object sender, EventArgs e) { - int index = GetSelectedAccountProfile(); - this.textBoxUserName.Text = IniFiles.Instance.GetString(IniFile.Config, "Login", $"s76UserName{index + 1}", ""); - this.textBoxPassword.Text = IniFiles.Instance.GetString(IniFile.Config, "Login", $"s76Password{index + 1}", ""); + this.colorPreviewPipboy.BackColor = Color.FromArgb(46, 207, 255); } - private void MakePictureBoxButton(PictureBox pictureBox, String localizedStringID) + private void buttonPresetFo3White_Click(object sender, EventArgs e) { - pictureBox.Paint += new PaintEventHandler((paintSender, paintEventArgs) => - { - paintEventArgs.Graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit; - - string text = Localization.GetString(localizedStringID); - - Font font = new Font("Microsoft Sans Serif", 12f, FontStyle.Bold); - - SizeF textSize = paintEventArgs.Graphics.MeasureString(text, font); - PointF locationToDraw = new PointF(); - locationToDraw.X = (pictureBox.Width / 2) - (textSize.Width / 2); - locationToDraw.Y = (pictureBox.Height / 2) - (textSize.Height / 2); + this.colorPreviewPipboy.BackColor = Color.FromArgb(192, 255, 255); + } - paintEventArgs.Graphics.DrawString(text, font, Brushes.White, locationToDraw); - }); - pictureBox.MouseEnter += new EventHandler((mouseSender, mouseEventArgs) => - { - pictureBox.Image = Resources.button_hover; - pictureBox.Cursor = Cursors.Hand; - }); - pictureBox.MouseLeave += new EventHandler((mouseSender, mouseEventArgs) => - { - pictureBox.Image = Resources.button; - pictureBox.Cursor = Cursors.Default; - }); + private void buttonPresetFo4Green_Click(object sender, EventArgs e) + { + this.colorPreviewPipboy.BackColor = Color.FromArgb(18, 255, 21); } - private void launchViaSteamToolStripMenuItem_Click(object sender, EventArgs e) + private void buttonPresetFo76Green_Click(object sender, EventArgs e) { - // Launch Steam version: - System.Diagnostics.Process.Start("steam://run/1151340"); + this.colorPreviewPipboy.BackColor = Color.FromArgb(26, 255, 128); } - private void launchViaBethesdanetToolStripMenuItem_Click(object sender, EventArgs e) + private void buttonCameraPositionReset_Click(object sender, EventArgs e) { - // Launch Bethesda.net version: - String gamePath = IniFiles.Instance.GetString(IniFile.Config, "Preferences", "sGamePathBethesdaNet", ""); - String execPath = Path.GetFullPath(Path.Combine(gamePath, "Fallout76.exe")); + this.applyCameraNodeAnimationsTweak.ResetValue(); + this.cameraOverShoulderPosXTweak.ResetValue(); + this.cameraOverShoulderPosZTweak.ResetValue(); + this.cameraOverShoulderCombatPosXTweak.ResetValue(); + this.cameraOverShoulderCombatPosZTweak.ResetValue(); + this.cameraOverShoulderCombatAddYTweak.ResetValue(); + this.cameraOverShoulderMeleeCombatPosXTweak.ResetValue(); + this.cameraOverShoulderMeleeCombatPosZTweak.ResetValue(); + this.cameraOverShoulderMeleeCombatAddYTweak.ResetValue(); + LinkedTweaks.LoadValues(); + } - uint uLaunchOption = IniFiles.Instance.GetUInt(IniFile.Config, "Preferences", "uLaunchOption", 1); - if (uLaunchOption == 1 || !File.Exists(execPath)) - System.Diagnostics.Process.Start("bethesdanet://run/20"); - else - { - Process pr = new Process(); - pr.StartInfo.FileName = execPath; - pr.StartInfo.WorkingDirectory = gamePath; - pr.StartInfo.UseShellExecute = false; - pr.Start(); - } - } + private PictureBox maskedPipScreen; + private PictureBox colorizedPipScreen; - private void launchViaBethesdanetPTSToolStripMenuItem_Click(object sender, EventArgs e) + private void InitPipboyScreen() { - // Launch Bethesda.net (PTS) version: - String gamePath = IniFiles.Instance.GetString(IniFile.Config, "Preferences", "sGamePathBethesdaNetPTS", ""); - String execPath = Path.GetFullPath(Path.Combine(gamePath, "Fallout76.exe")); + maskedPipScreen = new PictureBox(); + maskedPipScreen.Image = Resources.pipboy_preview_fg_masked; + maskedPipScreen.SizeMode = this.pictureBoxPipboyPreview.SizeMode; + maskedPipScreen.Size = this.pictureBoxPipboyPreview.Size; - uint uLaunchOption = IniFiles.Instance.GetUInt(IniFile.Config, "Preferences", "uLaunchOption", 1); + colorizedPipScreen = new PictureBox(); + colorizedPipScreen.Image = Resources.pipboy_preview_fg; + colorizedPipScreen.SizeMode = this.pictureBoxPipboyPreview.SizeMode; + colorizedPipScreen.Size = this.pictureBoxPipboyPreview.Size; - if (uLaunchOption == 1 || !File.Exists(execPath)) - System.Diagnostics.Process.Start("bethesdanet://run/57"); - else - { - Process pr = new Process(); - pr.StartInfo.FileName = execPath; - pr.StartInfo.WorkingDirectory = gamePath; - pr.StartInfo.UseShellExecute = false; - pr.Start(); - } + colorizedPipScreen.Controls.Add(maskedPipScreen); + this.pictureBoxPipboyPreview.Controls.Add(colorizedPipScreen); } - - - // Check, if *.ini files have been changed: - private void timerCheckFiles_Tick(object sender, EventArgs e) + private void UpdatePipboyScreen(Color targetColor) { - // Check every 5 seconds, if files have been modified: - if (IniFiles.Instance.FilesHaveBeenModified()) + Bitmap bmp = new Bitmap(Resources.pipboy_preview_fg); + for (int x = 0; x < bmp.Width; x++) { - IniFiles.Instance.UpdateLastModifiedDates(); - - // Don't prompt, if Fallout 76 is running.... - if (Shared.GameEdition == GameEdition.MSStore ? - //!Utils.IsProcessRunning("Project76_GamePass") : - !Utils.IsProcessRunning("Project76") : - !Utils.IsProcessRunning("Fallout76")) - MsgBox.Get("iniFilesModified").Popup(MessageBoxIcon.Warning); + for (int y = 0; y < bmp.Height; y++) + { + Color oldColor = bmp.GetPixel(x, y); + int r = (int)Utils.Clamp(oldColor.R / 255.0 * targetColor.R, 0, 255); + int g = (int)Utils.Clamp(oldColor.G / 255.0 * targetColor.G, 0, 255); + int b = (int)Utils.Clamp(oldColor.B / 255.0 * targetColor.B, 0, 255); + Color newColor = Color.FromArgb(oldColor.A, r, g, b); + bmp.SetPixel(x, y, newColor); + } } + colorizedPipScreen.Image = bmp; } - private void linkLabelAttribution_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) + private void colorPreviewPipboy_BackColorChanged(object sender, EventArgs e) { - Utils.OpenNotepad(@"Attribution.txt"); + UpdatePipboyScreen(this.colorPreviewPipboy.BackColor); } - private void linkLabelWhatsNew_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) + private void buttonPipboyTargetReset_Click(object sender, EventArgs e) { - ShowWhatsNew(); + this.numPipboyTargetWidth.Value = 876; + this.numPipboyTargetHeight.Value = 700; + } + + private void buttonPipboyTargetSetRecommended_Click(object sender, EventArgs e) + { + this.numPipboyTargetWidth.Value = 1752; + this.numPipboyTargetHeight.Value = 1400; } + #endregion } } diff --git a/Fo76ini/Forms/Form1/Form1.resx b/Fo76ini/Forms/Form1/Form1.resx index 6b8344b..f620a86 100644 --- a/Fo76ini/Forms/Form1/Form1.resx +++ b/Fo76ini/Forms/Form1/Form1.resx @@ -126,30 +126,6 @@ Not sure if it does anything, though. I stood around for 5 minutes and the camer Affected values: bDisableAutoVanityMode Affected files: Fallout76Custom.ini - - - Changes the display mode. - - -Fullscreen: Real fullscreen mode - -Windowed: Windowed mode with border - -Borderless windowed: Make sure, the resolution matches your display's resolution. - -Borderless windowed (Fullscreen): Window will be maximized to fit your screen. -Looks pixelated (it uses Nearest Neighbor), if the resolution is low. - - -Affected values: bFull Screen, bBorderless -Affected files: Fallout76Prefs.ini - - - Checking this will keep the game's window in foreground. -NOTE: This will prevent you from being able to Alt+Tab on single monitors. - -Affected values: bTopMostWindow -Affected files: Fallout76Prefs.ini Fixes hidden / borked @@ -203,41 +179,12 @@ Unchecking this might result in a clear view underwater. Affected values: bDoRadialBlur, iRadialBlurLevel Affected files: Fallout76Custom.ini - - Unchecking this will disable all Depth of Field effects. - -Affected files: Fallout76Custom.ini -Affected values: - bDynamicDepthOfField - fDOFBlendRatio - fDOFMinFocalCoefDist - fDOFMaxFocalCoefDist - fDOFDynamicFarRange - fDOFCenterWeightInt - fDOFFarDistance - Unchecking this will disable ambient occlusion. Ambient occlusion basically adds fake shadows to places light sources can't reach (concave edges). Affected values: bSAOEnable Affected files: Fallout76Prefs.ini - - - If checked, the sensitivity for looking up/down and left/right will be equal. -If unchecked (default), the sensitivity for looking left/right will likely be higher than up/down. - -When checked, your mouse sensitivity might increase. - -The sensitivity depends on your display's aspect ratio: - For 4:3, the value of X is .028 - For 16:9, the value of X is .03738 - For 16:10, the value of X is .0336 - For 21:9, the value of X is .042 - -Default: Disabled (.021 for both) -Affected values: fMouseHeadingXScale, fMouseHeadingYScale, fPitchSpeedRatio, fIronSightsPitchSpeedRatio -Affected files: Fallout76Custom.ini If checked, the aim sensitivity will be equal to normal sensitivity. @@ -275,13 +222,6 @@ I think, setting it to a low value will disable shadows. Needs more testing. Affected values: fShadowDistance, fDirShadowDistance Affected files: Fallout76Prefs.ini - - - Amount of "segments" of lower-res shadows at a distance. -A value of 1 forces the game to render only the lowest resolution shadows. - -Affected values: iDirShadowSplits -Affected files: Fallout76Prefs.ini When disabled, sets the camera's position into the characters head. @@ -295,21 +235,21 @@ Affected values: bApplyCameraNodeAnimations Affected files: Fallout76Custom.ini - - When you take screenshots ingame with the print screen button, it saves them in the game directory as "ScreenShotX.png". -The "X" being the screenshot index. + + Amount of "segments" of lower-res shadows at a distance. +A value of 1 forces the game to render only the lowest resolution shadows. -Affected values: iScreenShotIndex +Affected values: iDirShadowSplits Affected files: Fallout76Prefs.ini - 107, 17 + 123, 17 - 221, 17 + 500, 96 - 864, 17 + 120, 46 Your credentials are saved into Fallout76Custom.ini @@ -317,32 +257,26 @@ This way, you don't have to enter your username and password manually if you start Fallout 76 without the launcher. If you use Steam and want to use your Bethesda.net account -(e.g. to spent Atoms), tick Disable Steam. +(e.g. to spent Atoms), untick Enable Steam. NOTE: Your achievements will be disabled as well! - - 1054, 17 - - 1159, 17 + 498, 13 - 1380, 17 - - - 1629, 17 + 495, 45 - 1900, 17 + 306, 74 - - 561, 11 + + 298, 15 - - 550, 47 + + 302, 43 - 82 + 171 diff --git a/Fo76ini/Forms/FormIniError/FormIniError.Designer.cs b/Fo76ini/Forms/FormIniError/FormIniError.Designer.cs new file mode 100644 index 0000000..6f2d580 --- /dev/null +++ b/Fo76ini/Forms/FormIniError/FormIniError.Designer.cs @@ -0,0 +1,358 @@ + +namespace Fo76ini.Forms.FormIniError +{ + partial class FormIniError + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(FormIniError)); + this.label1 = new System.Windows.Forms.Label(); + this.pictureBox1 = new System.Windows.Forms.PictureBox(); + this.label2 = new System.Windows.Forms.Label(); + this.richTextBox = new System.Windows.Forms.RichTextBox(); + this.panel1 = new System.Windows.Forms.Panel(); + this.buttonResetFile = new System.Windows.Forms.Button(); + this.buttonTryAgain = new System.Windows.Forms.Button(); + this.linkLabelShowHelp = new System.Windows.Forms.LinkLabel(); + this.buttonOpenEditor = new System.Windows.Forms.Button(); + this.labelErrorMessage = new System.Windows.Forms.Label(); + this.label5 = new System.Windows.Forms.Label(); + this.pictureBox2 = new System.Windows.Forms.PictureBox(); + this.buttonCloseProgram = new System.Windows.Forms.Button(); + this.label8 = new System.Windows.Forms.Label(); + this.label6 = new System.Windows.Forms.Label(); + this.labelFileName = new System.Windows.Forms.Label(); + this.label9 = new System.Windows.Forms.Label(); + this.labelLineNumber = new System.Windows.Forms.Label(); + this.label3 = new System.Windows.Forms.Label(); + this.panelDetails = new System.Windows.Forms.Panel(); + this.buttonToggleDetails = new System.Windows.Forms.Button(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit(); + this.panel1.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox2)).BeginInit(); + this.panelDetails.SuspendLayout(); + this.SuspendLayout(); + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Font = new System.Drawing.Font("Microsoft Sans Serif", 11.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label1.Location = new System.Drawing.Point(83, 12); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(203, 18); + this.label1.TabIndex = 0; + this.label1.Text = "Could not read an *.ini file"; + // + // pictureBox1 + // + this.pictureBox1.Image = global::Fo76ini.Properties.Resources.error_64; + this.pictureBox1.Location = new System.Drawing.Point(12, 12); + this.pictureBox1.Name = "pictureBox1"; + this.pictureBox1.Size = new System.Drawing.Size(64, 64); + this.pictureBox1.TabIndex = 5; + this.pictureBox1.TabStop = false; + // + // label2 + // + this.label2.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.label2.Location = new System.Drawing.Point(85, 34); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(327, 42); + this.label2.TabIndex = 6; + this.label2.Text = "The tool failed to read an *.ini file, either because it is corrupted or contains" + + " a typo."; + // + // richTextBox + // + this.richTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.richTextBox.BackColor = System.Drawing.Color.White; + this.richTextBox.BorderStyle = System.Windows.Forms.BorderStyle.None; + this.richTextBox.Cursor = System.Windows.Forms.Cursors.IBeam; + this.richTextBox.Font = new System.Drawing.Font("Consolas", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.richTextBox.HideSelection = false; + this.richTextBox.Location = new System.Drawing.Point(2, 2); + this.richTextBox.Name = "richTextBox"; + this.richTextBox.ReadOnly = true; + this.richTextBox.ScrollBars = System.Windows.Forms.RichTextBoxScrollBars.None; + this.richTextBox.Size = new System.Drawing.Size(383, 115); + this.richTextBox.TabIndex = 0; + this.richTextBox.Text = ""; + this.richTextBox.WordWrap = false; + // + // panel1 + // + this.panel1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.panel1.BackColor = System.Drawing.Color.White; + this.panel1.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + this.panel1.Controls.Add(this.richTextBox); + this.panel1.Location = new System.Drawing.Point(16, 126); + this.panel1.Name = "panel1"; + this.panel1.Size = new System.Drawing.Size(390, 122); + this.panel1.TabIndex = 9; + // + // buttonResetFile + // + this.buttonResetFile.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.buttonResetFile.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.buttonResetFile.Location = new System.Drawing.Point(17, 88); + this.buttonResetFile.Name = "buttonResetFile"; + this.buttonResetFile.Size = new System.Drawing.Size(237, 32); + this.buttonResetFile.TabIndex = 900; + this.buttonResetFile.Text = "Reset *.ini file to default"; + this.buttonResetFile.UseVisualStyleBackColor = true; + this.buttonResetFile.Click += new System.EventHandler(this.buttonResetFile_Click); + // + // buttonTryAgain + // + this.buttonTryAgain.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.buttonTryAgain.Location = new System.Drawing.Point(264, 311); + this.buttonTryAgain.Name = "buttonTryAgain"; + this.buttonTryAgain.Size = new System.Drawing.Size(142, 32); + this.buttonTryAgain.TabIndex = 1; + this.buttonTryAgain.Text = "Try again"; + this.buttonTryAgain.UseVisualStyleBackColor = true; + this.buttonTryAgain.Click += new System.EventHandler(this.buttonTryAgain_Click); + // + // linkLabelShowHelp + // + this.linkLabelShowHelp.AutoSize = true; + this.linkLabelShowHelp.Location = new System.Drawing.Point(46, 286); + this.linkLabelShowHelp.Name = "linkLabelShowHelp"; + this.linkLabelShowHelp.Size = new System.Drawing.Size(117, 13); + this.linkLabelShowHelp.TabIndex = 2; + this.linkLabelShowHelp.TabStop = true; + this.linkLabelShowHelp.Text = "Help! Show me a guide"; + this.linkLabelShowHelp.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.linkLabelShowHelp_LinkClicked); + // + // buttonOpenEditor + // + this.buttonOpenEditor.Location = new System.Drawing.Point(16, 311); + this.buttonOpenEditor.Name = "buttonOpenEditor"; + this.buttonOpenEditor.Size = new System.Drawing.Size(242, 32); + this.buttonOpenEditor.TabIndex = 11; + this.buttonOpenEditor.Text = "Open *.ini file in text editor"; + this.buttonOpenEditor.UseVisualStyleBackColor = true; + this.buttonOpenEditor.Click += new System.EventHandler(this.buttonOpenEditor_Click); + // + // labelErrorMessage + // + this.labelErrorMessage.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(80)))), ((int)(((byte)(80)))), ((int)(((byte)(80))))); + this.labelErrorMessage.Location = new System.Drawing.Point(16, 28); + this.labelErrorMessage.Name = "labelErrorMessage"; + this.labelErrorMessage.Size = new System.Drawing.Size(390, 30); + this.labelErrorMessage.TabIndex = 16; + this.labelErrorMessage.Text = "< Error message goes here >"; + this.labelErrorMessage.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; + // + // label5 + // + this.label5.AutoSize = true; + this.label5.Font = new System.Drawing.Font("Microsoft Sans Serif", 9F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label5.Location = new System.Drawing.Point(13, 9); + this.label5.Name = "label5"; + this.label5.Size = new System.Drawing.Size(86, 15); + this.label5.TabIndex = 15; + this.label5.Text = "Error details"; + // + // pictureBox2 + // + this.pictureBox2.Image = global::Fo76ini.Properties.Resources.help_24; + this.pictureBox2.Location = new System.Drawing.Point(16, 281); + this.pictureBox2.Name = "pictureBox2"; + this.pictureBox2.Size = new System.Drawing.Size(24, 24); + this.pictureBox2.SizeMode = System.Windows.Forms.PictureBoxSizeMode.CenterImage; + this.pictureBox2.TabIndex = 17; + this.pictureBox2.TabStop = false; + // + // buttonCloseProgram + // + this.buttonCloseProgram.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.buttonCloseProgram.Location = new System.Drawing.Point(260, 88); + this.buttonCloseProgram.Name = "buttonCloseProgram"; + this.buttonCloseProgram.Size = new System.Drawing.Size(147, 32); + this.buttonCloseProgram.TabIndex = 18; + this.buttonCloseProgram.Text = "Close program"; + this.buttonCloseProgram.UseVisualStyleBackColor = true; + this.buttonCloseProgram.Click += new System.EventHandler(this.buttonCloseProgram_Click); + // + // label8 + // + this.label8.AutoSize = true; + this.label8.Font = new System.Drawing.Font("Microsoft Sans Serif", 9F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label8.Location = new System.Drawing.Point(13, 260); + this.label8.Name = "label8"; + this.label8.Size = new System.Drawing.Size(91, 15); + this.label8.TabIndex = 901; + this.label8.Text = "More options"; + // + // label6 + // + this.label6.AutoSize = true; + this.label6.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label6.Location = new System.Drawing.Point(13, 65); + this.label6.Name = "label6"; + this.label6.Size = new System.Drawing.Size(66, 13); + this.label6.TabIndex = 19; + this.label6.Text = "Affected file:"; + // + // labelFileName + // + this.labelFileName.AutoSize = true; + this.labelFileName.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.labelFileName.Location = new System.Drawing.Point(115, 65); + this.labelFileName.Name = "labelFileName"; + this.labelFileName.Size = new System.Drawing.Size(94, 13); + this.labelFileName.TabIndex = 20; + this.labelFileName.Text = "< File name here >"; + // + // label9 + // + this.label9.AutoSize = true; + this.label9.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label9.Location = new System.Drawing.Point(13, 82); + this.label9.Name = "label9"; + this.label9.Size = new System.Drawing.Size(68, 13); + this.label9.TabIndex = 21; + this.label9.Text = "Line number:"; + // + // labelLineNumber + // + this.labelLineNumber.AutoSize = true; + this.labelLineNumber.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.labelLineNumber.Location = new System.Drawing.Point(115, 82); + this.labelLineNumber.Name = "labelLineNumber"; + this.labelLineNumber.Size = new System.Drawing.Size(107, 13); + this.labelLineNumber.TabIndex = 22; + this.labelLineNumber.Text = "< Line number here >"; + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label3.Location = new System.Drawing.Point(13, 110); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(168, 13); + this.label3.TabIndex = 7; + this.label3.Text = "Couldn\'t parse the highlighted line:"; + // + // panelDetails + // + this.panelDetails.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.panelDetails.BackColor = System.Drawing.Color.White; + this.panelDetails.Controls.Add(this.label5); + this.panelDetails.Controls.Add(this.label8); + this.panelDetails.Controls.Add(this.pictureBox2); + this.panelDetails.Controls.Add(this.panel1); + this.panelDetails.Controls.Add(this.linkLabelShowHelp); + this.panelDetails.Controls.Add(this.label3); + this.panelDetails.Controls.Add(this.buttonOpenEditor); + this.panelDetails.Controls.Add(this.buttonTryAgain); + this.panelDetails.Controls.Add(this.labelErrorMessage); + this.panelDetails.Controls.Add(this.labelLineNumber); + this.panelDetails.Controls.Add(this.label6); + this.panelDetails.Controls.Add(this.label9); + this.panelDetails.Controls.Add(this.labelFileName); + this.panelDetails.Location = new System.Drawing.Point(1, 148); + this.panelDetails.Name = "panelDetails"; + this.panelDetails.Size = new System.Drawing.Size(423, 354); + this.panelDetails.TabIndex = 902; + // + // buttonToggleDetails + // + this.buttonToggleDetails.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.buttonToggleDetails.Location = new System.Drawing.Point(-1, 127); + this.buttonToggleDetails.Name = "buttonToggleDetails"; + this.buttonToggleDetails.Size = new System.Drawing.Size(426, 21); + this.buttonToggleDetails.TabIndex = 903; + this.buttonToggleDetails.Text = "/\\ Hide details"; + this.buttonToggleDetails.UseVisualStyleBackColor = true; + this.buttonToggleDetails.Click += new System.EventHandler(this.buttonToggleDetails_Click); + // + // FormIniError + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(424, 502); + this.Controls.Add(this.buttonToggleDetails); + this.Controls.Add(this.panelDetails); + this.Controls.Add(this.buttonResetFile); + this.Controls.Add(this.label2); + this.Controls.Add(this.buttonCloseProgram); + this.Controls.Add(this.pictureBox1); + this.Controls.Add(this.label1); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; + this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "FormIniError"; + this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; + this.Text = "*.ini parsing error"; + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit(); + this.panel1.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox2)).EndInit(); + this.panelDetails.ResumeLayout(false); + this.panelDetails.PerformLayout(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Label label1; + private System.Windows.Forms.PictureBox pictureBox1; + private System.Windows.Forms.Label label2; + private System.Windows.Forms.RichTextBox richTextBox; + private System.Windows.Forms.Panel panel1; + private System.Windows.Forms.Button buttonResetFile; + private System.Windows.Forms.Button buttonTryAgain; + private System.Windows.Forms.LinkLabel linkLabelShowHelp; + private System.Windows.Forms.Button buttonOpenEditor; + private System.Windows.Forms.Label labelErrorMessage; + private System.Windows.Forms.Label label5; + private System.Windows.Forms.PictureBox pictureBox2; + private System.Windows.Forms.Button buttonCloseProgram; + private System.Windows.Forms.Label label8; + private System.Windows.Forms.Label label6; + private System.Windows.Forms.Label labelFileName; + private System.Windows.Forms.Label label9; + private System.Windows.Forms.Label labelLineNumber; + private System.Windows.Forms.Label label3; + private System.Windows.Forms.Panel panelDetails; + private System.Windows.Forms.Button buttonToggleDetails; + } +} \ No newline at end of file diff --git a/Fo76ini/Forms/FormIniError/FormIniError.cs b/Fo76ini/Forms/FormIniError/FormIniError.cs new file mode 100644 index 0000000..91ec2a1 --- /dev/null +++ b/Fo76ini/Forms/FormIniError/FormIniError.cs @@ -0,0 +1,156 @@ +using Fo76ini.Ini; +using Fo76ini.Interface; +using Fo76ini.Utilities; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace Fo76ini.Forms.FormIniError +{ + public partial class FormIniError : Form + { + IniParsingException Exception; + + public FormIniError() + { + InitializeComponent(); + + this.FormClosing += FormIniError_FormClosing; + } + + public static DialogResult OpenDialog(IniParsingException exc) + { + FormIniError form = new FormIniError(); + form.Exception = exc; + + form.labelErrorMessage.Text = exc.Message; + form.labelFileName.Text = exc.FileName; + form.labelLineNumber.Text = exc.LineNumber.ToString(); + + // Fill rich text box: + StreamReader reader = File.OpenText(exc.FilePath); + int lineNumber = 0; + while (!reader.EndOfStream) + { + string line = reader.ReadLine(); + if (line == null) + break; + lineNumber++; + + string lineNumStr = $"{lineNumber} ".PadLeft(4); + if (lineNumber == exc.LineNumber) + { + form.richTextBox.AppendRichText(lineNumStr, false, Color.Red); + form.richTextBox.AppendRichText(line.PadRight(48), true, Color.White, Color.Red); + } + else if (Math.Abs(lineNumber - exc.LineNumber) <= 3) + { + form.richTextBox.AppendRichText(lineNumStr, false, Color.FromArgb(120, 120, 120)); + form.richTextBox.AppendRichText(line, true); + } + } + reader.Close(); + + form.HideDetails(); + + return form.ShowDialog(); + } + + private void buttonResetFile_Click(object sender, EventArgs e) + { + DialogResult result = MsgBox.Show("Warning", "This will reset (some if not all) of your settings.\nAre you sure?", MessageBoxButtons.YesNo, MessageBoxIcon.Warning); + + if (result == DialogResult.Yes) + { + // Reset Fallout76Prefs.ini: + if (Exception.FileName.EndsWith("Prefs.ini")) + { + File.Copy( + IniFiles.DefaultF76PrefsPath, + Exception.FilePath, + true + ); + } + + // Delete Fallout76Custom.ini: + else if (Exception.FileName.EndsWith("Custom.ini")) + { + File.Delete(Exception.FilePath); + } + + // Reset Fallout76.ini: + else + { + File.Copy( + IniFiles.DefaultF76Path, + Exception.FilePath, + true + ); + } + + this.DialogResult = DialogResult.Ignore; + } + } + + private void buttonOpenEditor_Click(object sender, EventArgs e) + { + Utils.OpenFile(Exception.FilePath); + } + + private void buttonCloseProgram_Click(object sender, EventArgs e) + { + // this.DialogResult = DialogResult.Abort; + // Application.Exit(); // Doesn't immediately terminate program. + Environment.Exit(Exception.HResult); // Does immediately terminate program. + } + + private void buttonTryAgain_Click(object sender, EventArgs e) + { + this.DialogResult = DialogResult.Retry; + } + + private void linkLabelShowHelp_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) + { + Utils.OpenURL("https://github.com/FelisDiligens/Fallout76-QuickConfiguration/wiki/Troubleshooting:-*.ini-files"); + } + + private void buttonToggleDetails_Click(object sender, EventArgs e) + { + if (this.panelDetails.Visible) + HideDetails(); + else + ShowDetails(); + } + + private void FormIniError_FormClosing(object sender, FormClosingEventArgs e) + { + if (e.CloseReason == CloseReason.UserClosing) + { + Environment.Exit(Exception.HResult); + } + } + + private void ShowDetails() + { + this.panelDetails.Visible = true; + this.buttonToggleDetails.Text = "/\\ Hide details"; + this.Height = this.panelDetails.Top + this.panelDetails.Height + 38; + this.Top -= 200; + } + + private void HideDetails() + { + this.panelDetails.Visible = false; + this.buttonToggleDetails.Text = "\\/ Show details"; + this.Height = this.panelDetails.Top + 38; + this.Top += 200; + } + } +} diff --git a/Fo76ini/Forms/FormIniError/FormIniError.resx b/Fo76ini/Forms/FormIniError/FormIniError.resx new file mode 100644 index 0000000..816f916 --- /dev/null +++ b/Fo76ini/Forms/FormIniError/FormIniError.resx @@ -0,0 +1,700 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + + AAABAAUAEBAAAAEAIABoBAAAVgAAABgYAAABACAAiAkAAL4EAAAgIAAAAQAgAKgQAABGDgAAMDAAAAEA + IACoJQAA7h4AAEBAAAABACAAKEIAAJZEAAAoAAAAEAAAACAAAAABACAAAAAAAAAEAADYDgAA2A4AAAAA + AAAAAAAAAAAAAAAR9QAAEfUAABH1HAAR9bgAEfX7ABH1+QAR9fkAEfX5ABH1+QAR9fsAEfW4ABH1HAAR + 9QAAEfUAAAAAAAAR9QAAEfUAABH1GAAR9agAEfX+ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/gAR + 9agAEfUYABH1AAAR9QAAEfUAABH1GAAR9akAEfX+ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX+ABH1qQAR9RgAEfUAABH1GwAR9agAEfX+ABH1/wAR9f0AEfX0ABH1/gAR9f8AEfX/ABH1/wAR + 9fQAEfX9ABH1/wAR9f4AEfWoABH1GwAR9bgAEfX9ABH1/wAR9f8AEfW6ABH1UwAR9c0AEfX/ABH1/wAR + 9dYAEfVVABH1rQAR9f8AEfX/ABH1/QAR9bgAEfX5ABH1/wAR9f8AEfX8ABH1cAAR9QAAEfUzABH1zwAR + 9dgAEfU+ABH1AAAR9WAAEfX4ABH1/wAR9f8AEfX5ABH1+QAR9f8AEfX/ABH1/wAR9eYAEfVVABH1AAAR + 9S0AEfUzABH1AAAR9UkAEfXfABH1/wAR9f8AEfX/ABH1+QAR9fkAEfX/ABH1/wAR9f8AEfX/ABH16AAR + 9UgAEfUAABH1AAAR9TsAEfXgABH1/wAR9f8AEfX/ABH1/wAR9fkAEfX5ABH1/wAR9f8AEfX/ABH1/wAR + 9dgAEfU5ABH1AAAR9QAAEfUuABH1zwAR9f8AEfX/ABH1/wAR9f8AEfX5ABH1+QAR9f8AEfX/ABH1/wAR + 9dYAEfU+ABH1AAAR9UMAEfVLABH1AAAR9TMAEfXNABH1/wAR9f8AEfX/ABH1+QAR9fkAEfX/ABH1/wAR + 9fsAEfVqABH1AAAR9UkAEfXhABH16AAR9VUAEfUAABH1WgAR9fcAEfX/ABH1/wAR9fkAEfW3ABH1/QAR + 9f8AEfX/ABH1zgAR9XMAEfXeABH1/wAR9f8AEfXlABH1dQAR9cQAEfX/ABH1/wAR9f0AEfW3ABH1GwAR + 9acAEfX+ABH1/wAR9f8AEfX8ABH1/wAR9f8AEfX/ABH1/wAR9fwAEfX+ABH1/wAR9f4AEfWnABH1GwAR + 9QAAEfUXABH1qQAR9f4AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f4AEfWpABH1FwAR + 9QAAEfUAABH1AAAR9RcAEfWnABH1/gAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f4AEfWnABH1FwAR + 9QAAEfUAAAAAAAAR9QAAEfUAABH1GwAR9bcAEfX7ABH1+QAR9fkAEfX5ABH1+QAR9fsAEfW3ABH1GwAR + 9QAAEfUAAAAAAOAHAADAAwAAgAEAAAAAAAAAAAAABCAAAAJAAAABgAAAAYAAAAJAAAAEIAAAAAAAAAAA + AACAAQAAwAMAAOAHAAAoAAAAGAAAADAAAAABACAAAAAAAAAJAADYDgAA2A4AAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAR9QAAEfUFABH1dwAR9fAAEfX2ABH19QAR9fUAEfX1ABH19QAR9fUAEfX1ABH19gAR + 9fAAEfV3ABH1BQAR9QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABH1AAAR9QQAEfVqABH17wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfXvABH1agAR9QQAEfUAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAEfUAABH1BQAR9WsAEfXvABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH17wAR9WsAEfUFABH1AAAAAAAAAAAAAAAAAAAR9QAAEfUEABH1awAR + 9e8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9e8AEfVrABH1BAAR9QAAAAAAABH1AAAR9QQAEfVrABH18AAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfXwABH1awAR9QQAEfUAABH1BQAR + 9WoAEfXvABH1/wAR9f8AEfX/ABH1/wAR9fkAEfX1ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH19gAR + 9fcAEfX/ABH1/wAR9f8AEfX/ABH17wAR9WoAEfUFABH1dwAR9e4AEfX/ABH1/wAR9f8AEfX/ABH1+QAR + 9YwAEfViABH15wAR9f8AEfX/ABH1/wAR9f8AEfXwABH1cAAR9XkAEfX0ABH1/wAR9f8AEfX/ABH1/wAR + 9e4AEfV3ABH17wAR9f8AEfX/ABH1/wAR9f8AEfX+ABH1kgAR9QsAEfUBABH1WQAR9egAEfX/ABH1/wAR + 9fAAEfVsABH1BAAR9QUAEfV8ABH1+gAR9f8AEfX/ABH1/wAR9f8AEfXvABH19gAR9f8AEfX/ABH1/wAR + 9f8AEfX+ABH1mAAR9Q8AEfUAABH1AgAR9VkAEfXnABH18AAR9WwAEfUFABH1AAAR9QgAEfWDABH1+wAR + 9f8AEfX/ABH1/wAR9f8AEfX2ABH19QAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1+gAR9ZQAEfUQABH1AAAR + 9QIAEfVSABH1XwAR9QUAEfUAABH1CQAR9YAAEfX2ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX1ABH19QAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9fsAEfWUABH1DwAR9QAAEfUAABH1AAAR9QAAEfUJABH1fwAR + 9fcAEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX1ABH19QAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX8ABH1hgAR9QQAEfUAABH1AAAR9QAAEfVwABH19wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX1ABH19QAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfXwABH1aAAR9QEAEfUAABH1AAAR + 9QAAEfVUABH15wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX1ABH19QAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9fAAEfVsABH1BAAR9QAAEfUFABH1BwAR9QAAEfUBABH1WQAR9egAEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX1ABH19QAR9f8AEfX/ABH1/wAR9f8AEfX/ABH17wAR9WwAEfUFABH1AAAR + 9QkAEfV7ABH1igAR9RAAEfUAABH1AgAR9VkAEfXnABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX1ABH19gAR + 9f8AEfX/ABH1/wAR9f8AEfX9ABH1fgAR9QMAEfUAABH1CQAR9YAAEfX3ABH1+wAR9ZQAEfUQABH1AAAR + 9QAAEfVoABH1+AAR9f8AEfX/ABH1/wAR9f8AEfX2ABH17wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1sQAR + 9R0AEfUIABH1gAAR9fYAEfX/ABH1/wAR9fsAEfWUABH1DgAR9RMAEfWeABH1/QAR9f8AEfX/ABH1/wAR + 9f8AEfXvABH1dgAR9e0AEfX/ABH1/wAR9f8AEfX/ABH1/gAR9bMAEfWRABH19QAR9f8AEfX/ABH1/wAR + 9f8AEfX6ABH1mwAR9aMAEfX8ABH1/wAR9f8AEfX/ABH1/wAR9e0AEfV2ABH1BQAR9WkAEfXvABH1/wAR + 9f8AEfX/ABH1/wAR9f4AEfX+ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/QAR9f4AEfX/ABH1/wAR + 9f8AEfX/ABH17wAR9WkAEfUFABH1AAAR9QQAEfVqABH17wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfXvABH1agAR9QQAEfUAAAAAAAAR + 9QAAEfUEABH1agAR9e8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9e8AEfVqABH1BAAR9QAAAAAAAAAAAAAAAAAAEfUAABH1BAAR9WoAEfXvABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH17wAR9WoAEfUEABH1AAAA + AAAAAAAAAAAAAAAAAAAAAAAAABH1AAAR9QQAEfVpABH17gAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfXuABH1aQAR9QQAEfUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAR + 9QAAEfUFABH1dgAR9fAAEfX2ABH19QAR9fUAEfX1ABH19QAR9fUAEfX1ABH19gAR9fAAEfV2ABH1BQAR + 9QAAAAAAAAAAAAAAAAAAAAAA+AAfAPAADwDgAAcAwAADAIAAAQAAAAAAAAAAAAAAAAAAgQAAAEIAAAA8 + AAAAHAAAABwAAAAkAAAAQgAAAIGAAAAAAAAAAAAAAAAAAIAAAQDAAAMA4AAHAPAADwD4AB8AKAAAACAA + AABAAAAAAQAgAAAAAAAAEAAA2A4AANgOAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAR + 9QAAEfUAABH1PAAR9dEAEfXzABH18QAR9fEAEfXxABH18QAR9fEAEfXxABH18QAR9fEAEfXxABH18QAR + 9fMAEfXRABH1PAAR9QAAEfUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAEfUAABH1AAAR9TUAEfXJABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfXJABH1NQAR9QAAEfUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAABH1AAAR9QAAEfU1ABH1ywAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfXLABH1NQAR9QAAEfUAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAR9QAAEfUAABH1NQAR9csAEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfXLABH1NQAR9QAAEfUAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAEfUAABH1AAAR9TUAEfXLABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfXLABH1NQAR + 9QAAEfUAAAAAAAAAAAAAAAAAABH1AAAR9QAAEfU1ABH1ywAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfXLABH1NQAR9QAAEfUAAAAAAAAR9QAAEfUAABH1NQAR9csAEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfXLABH1NQAR9QAAEfUAABH1AAAR9TUAEfXLABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9fMAEfX4ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX6ABH18QAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfXLABH1NQAR9QAAEfU8ABH1yQAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfXmABH1YQAR9YQAEfX1ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1+wAR + 9ZsAEfVTABH11gAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfXJABH1PAAR9dEAEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH15QAR9VoAEfUBABH1CwAR9YMAEfX2ABH1/wAR9f8AEfX/ABH1/wAR + 9fsAEfWdABH1FQAR9QAAEfVDABH11gAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfXRABH18gAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9fwAEfV+ABH1AgAR9QAAEfUAABH1DAAR9YMAEfX1ABH1/wAR + 9f8AEfX7ABH1nQAR9RUAEfUAABH1AAAR9QAAEfVfABH19gAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9fIAEfXxABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9cgAEfU0ABH1AAAR9QAAEfUAABH1DAAR + 9YIAEfX1ABH1/AAR9ZwAEfUVABH1AAAR9QAAEfUAABH1IgAR9bMAEfX+ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH18QAR9fEAEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9coAEfU0ABH1AAAR + 9QAAEfUAABH1CwAR9XsAEfWRABH1FAAR9QAAEfUAABH1AAAR9SMAEfW1ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfXxABH18QAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9coAEfU0ABH1AAAR9QAAEfUAABH1BgAR9QkAEfUAABH1AAAR9QAAEfUiABH1tQAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9fEAEfXxABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9ckAEfUzABH1AAAR9QAAAAAAAAAAAAAR9QAAEfUAABH1IAAR9bMAEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH18QAR9fEAEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9cEAEfUcABH1AAAAAAAAAAAAABH1AAAR9Q0AEfWnABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfXxABH18QAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX7ABH1mgAR9Q8AEfUAAAAAAAAAAAAAEfUAABH1BgAR + 9X4AEfX1ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9fEAEfXxABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/AAR9ZwAEfUUABH1AAAAAAAAAAAAAAAAAAAA + AAAAEfUAABH1CwAR9YIAEfX1ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH18QAR + 9fEAEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9fsAEfWdABH1FQAR9QAAEfUAABH1AAAR + 9RkAEfUiABH1AAAR9QAAEfUAABH1DAAR9YMAEfX2ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfXxABH18QAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX7ABH1nQAR9RUAEfUAABH1AAAR + 9QAAEfUhABH1sQAR9cQAEfUzABH1AAAR9QAAEfUAABH1DAAR9YMAEfX2ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9fEAEfXxABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/gAR9aEAEfUUABH1AAAR + 9QAAEfUAABH1IgAR9bQAEfX/ABH1/wAR9ckAEfU0ABH1AAAR9QAAEfUAABH1CwAR9YYAEfX6ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH18QAR9fIAEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX9ABH1lQAR + 9Q0AEfUAABH1AAAR9SIAEfW0ABH1/wAR9f8AEfX/ABH1/wAR9coAEfU0ABH1AAAR9QAAEfUGABH1eAAR + 9fkAEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfXyABH10AAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX4ABH1jQAR9Q4AEfUiABH1tQAR9f4AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9coAEfU0ABH1BgAR + 9XIAEfXwABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9dAAEfU6ABH1yAAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX3ABH1ngAR9bkAEfX+ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9ckAEfWQABH17wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfXIABH1OgAR9QAAEfU0ABH1yQAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX+ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/gAR9f0AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1yQAR9TQAEfUAABH1AAAR + 9QAAEfU0ABH1yQAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9ckAEfU0ABH1AAAR + 9QAAAAAAABH1AAAR9QAAEfU0ABH1yQAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfXJABH1NAAR + 9QAAEfUAAAAAAAAAAAAAAAAAABH1AAAR9QAAEfU0ABH1yQAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1yQAR + 9TQAEfUAABH1AAAAAAAAAAAAAAAAAAAAAAAAAAAAABH1AAAR9QAAEfU0ABH1yQAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9ckAEfU0ABH1AAAR9QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABH1AAAR9QAAEfU0ABH1yQAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfXJABH1NAAR9QAAEfUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABH1AAAR + 9QAAEfU0ABH1yAAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1yAAR9TQAEfUAABH1AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAABH1AAAR9QAAEfU7ABH10AAR9fMAEfXxABH18QAR9fEAEfXxABH18QAR9fEAEfXxABH18QAR + 9fEAEfXxABH18wAR9dAAEfU7ABH1AAAR9QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AAD//gAAf/wA + AD/4AAAf8AAAD+AAAAfAAAADgAAAAQAAAAAAAAQAADAOAAA4HAAAHDgAAA5wAAAH4AAAA8AAAAPAAAAH + 4AAADnAAABw4AAA4HAAAMAwAAAAAAAAAAACAAAABwAAAA+AAAAfwAAAP+AAAH/wAAD/+AAB//wAA/ygA + AAAwAAAAYAAAAAEAIAAAAAAAACQAANgOAADYDgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAR9QAAEfUGABH1YwAR9dkAEfXqABH16AAR9egAEfXoABH16AAR + 9egAEfXoABH16AAR9egAEfXoABH16AAR9egAEfXoABH16AAR9egAEfXoABH16AAR9eoAEfXZABH1YwAR + 9QYAEfUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABH1AAAR9QMAEfVbABH13wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH13wAR9VsAEfUDABH1AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEfUAABH1BAAR9VkAEfXhABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9eEAEfVZABH1BAAR9QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAR9QAAEfUFABH1XAAR + 9eEAEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfXhABH1XAAR9QUAEfUAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABH1AAAR + 9QMAEfVcABH14AAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH14AAR + 9VwAEfUDABH1AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAEfUAABH1BAAR9VkAEfXhABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9eEAEfVZABH1BAAR9QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAR9QAAEfUFABH1XAAR9eEAEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfXhABH1XAAR9QUAEfUAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAABH1AAAR9QMAEfVcABH14AAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH14AAR9VwAEfUDABH1AAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEfUAABH1BAAR9VkAEfXhABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9eEAEfVZABH1BAAR9QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAR9QAAEfUFABH1XAAR9eEAEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfXhABH1XAAR9QUAEfUAAAAAAAAAAAAAAAAAABH1AAAR9QMAEfVcABH14AAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH14AAR9VwAEfUDABH1AAAAAAAAEfUAABH1BAAR + 9VkAEfXhABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX4ABH17wAR + 9f4AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH18AAR + 9fQAEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9eEAEfVZABH1BAAR + 9QAAEfUGABH1WwAR9eEAEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9foAEfWUABH1TgAR9cgAEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfXiABH1YAAR9XMAEfXsABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfXhABH1WwAR9QYAEfVjABH13wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1+AAR9ZgAEfUVABH1AAAR9T0AEfXLABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9eMAEfVcABH1BAAR9QcAEfV0ABH16wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH13wAR9WMAEfXYABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX4ABH1mAAR9RcAEfUAABH1AAAR9QAAEfU+ABH1ywAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH14wAR9V4AEfUDABH1AAAR9QAAEfUKABH1dAAR9ewAEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9dgAEfXqABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f4AEfWmABH1FAAR9QAAAAAAAAAAAAAR9QAAEfUAABH1PAAR + 9ckAEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfXiABH1XAAR9QQAEfUAAAAAAAAAAAAAEfUAABH1CAAR + 9XoAEfX4ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9eoAEfXoABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f0AEfWpABH1HwAR9QAAAAAAAAAAAAAA + AAAAAAAAABH1AAAR9TwAEfXKABH1/wAR9f8AEfX/ABH1/wAR9eMAEfVbABH1BAAR9QAAAAAAAAAAAAAA + AAAAEfUAABH1DwAR9YEAEfX4ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9egAEfXoABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX6ABH1owAR + 9R4AEfUAABH1AAAAAAAAAAAAABH1AAAR9QAAEfU9ABH1yQAR9f8AEfX/ABH14gAR9V0AEfUDABH1AAAA + AAAAAAAAABH1AAAR9QAAEfUNABH1fwAR9fMAEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9egAEfXoABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1+wAR9aYAEfUeABH1AAAAAAAAAAAAAAAAAAAR9QAAEfUAABH1OAAR9cMAEfXdABH1WAAR + 9QMAEfUAAAAAAAAAAAAAAAAAABH1AAAR9Q4AEfWBABH18wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9egAEfXoABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9fwAEfWjABH1HwAR9QAAAAAAAAAAAAAAAAAAAAAAABH1AAAR + 9S8AEfVEABH1AwAR9QAAAAAAAAAAAAAAAAAAEfUAABH1DwAR9X8AEfX0ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9egAEfXoABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX6ABH1owAR9R0AEfUAABH1AAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABH1AAAR9QAAEfUMABH1fgAR9fMAEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9egAEfXoABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1+wAR + 9aQAEfUdABH1AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABH1AAAR9QwAEfV+ABH18wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9egAEfXoABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9fwAEfWfABH1HAAR9QAAEfUAAAAAAAAAAAAAAAAAAAAAAAAR9QAAEfUAABH1DAAR + 9XkAEfXzABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9egAEfXoABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX5ABH1hQAR9QkAEfUAAAAAAAAAAAAAAAAAAAAAAAAR + 9QAAEfUAABH1XAAR9e4AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9egAEfXoABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfXgABH1UwAR9QAAEfUAAAAAAAAA + AAAAAAAAAAAAAAAR9QAAEfUAABH1MgAR9cQAEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9egAEfXoABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9eIAEfVZABH1AwAR + 9QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABH1AAAR9TgAEfXIABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9egAEfXoABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH15AAR + 9V0AEfUDABH1AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABH1AAAR9QAAEfU9ABH1ywAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9egAEfXoABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfXiABH1WwAR9QQAEfUAAAAAAAAAAAAAAAAAABH1AAAR9QcAEfUOABH1AAAAAAAAAAAAAAAAAAAR + 9QAAEfUAABH1PAAR9ckAEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9egAEfXoABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9eMAEfVcABH1BAAR9QAAAAAAAAAAAAAAAAAAEfUAABH1DAAR9XMAEfWPABH1HAAR + 9QAAAAAAAAAAAAAAAAAAAAAAABH1AAAR9T0AEfXLABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9egAEfXoABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH14wAR9V4AEfUDABH1AAAAAAAAAAAAABH1AAAR9QAAEfUMABH1ewAR + 9fIAEfX6ABH1nwAR9RwAEfUAABH1AAAAAAAAAAAAABH1AAAR9QAAEfU+ABH1ywAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9egAEfXoABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfXfABH1XAAR9QQAEfUAAAAAAAAAAAAAAAAAABH1AAAR + 9Q0AEfWAABH18wAR9f8AEfX/ABH1+wAR9aQAEfUeABH1AAAAAAAAAAAAAAAAAAAR9QAAEfUAABH1PAAR + 9cgAEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9egAEfXoABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9fwAEfWQABH1BQAR9QAAAAAAAAAAAAAA + AAAAEfUAABH1DgAR9X4AEfX0ABH1/wAR9f8AEfX/ABH1/wAR9fwAEfWjABH1HwAR9QAAAAAAAAAAAAAA + AAAAAAAAABH1AAAR9WAAEfX1ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9egAEfXqABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfXQABH1RwAR + 9QEAEfUAABH1AAAR9QAAEfUNABH1fgAR9fIAEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX6ABH1owAR + 9R4AEfUAABH1AAAR9QAAEfUAABH1KwAR9bMAEfX9ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9eoAEfXYABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH11AAR9UkAEfUBABH1AAAR9Q4AEfWBABH18wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1+wAR9aYAEfUeABH1AAAR9QAAEfUsABH1uAAR9f4AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9dgAEfVhABH13gAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9dUAEfVJABH1EQAR9YAAEfX0ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9fwAEfWjABH1HwAR9SkAEfW4ABH1/gAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH13gAR9WEAEfUFABH1WQAR9eAAEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfXVABH1rQAR9fEAEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX5ABH1swAR9cAAEfX9ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfXgABH1WQAR9QUAEfUAABH1BAAR + 9VYAEfXfABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/gAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/QAR + 9f4AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9d8AEfVWABH1BAAR + 9QAAAAAAABH1AAAR9QMAEfVZABH13gAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH13gAR + 9VkAEfUDABH1AAAAAAAAAAAAAAAAAAAR9QAAEfUFABH1WQAR9eAAEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfXgABH1WQAR9QUAEfUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEfUAABH1BAAR9VYAEfXfABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9d8AEfVWABH1BAAR9QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABH1AAAR + 9QMAEfVZABH13gAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH13gAR9VkAEfUDABH1AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAR9QAAEfUFABH1WQAR9eAAEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfXgABH1WQAR9QUAEfUAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEfUAABH1BAAR9VYAEfXfABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9d8AEfVWABH1BAAR9QAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABH1AAAR9QMAEfVZABH13gAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH13gAR9VkAEfUDABH1AAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAR + 9QAAEfUFABH1WQAR9eAAEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfXgABH1WQAR + 9QUAEfUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAEfUAABH1BAAR9VYAEfXfABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9d8AEfVWABH1BAAR9QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABH1AAAR9QMAEfVZABH13gAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH13gAR9VkAEfUDABH1AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAR9QAAEfUFABH1YQAR + 9dkAEfXqABH16AAR9egAEfXoABH16AAR9egAEfXoABH16AAR9egAEfXoABH16AAR9egAEfXoABH16AAR + 9egAEfXoABH16AAR9eoAEfXZABH1YQAR9QUAEfUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAD/8AAAD/8AAP/gAAAH/wAA/8AAAAP/AAD/gAAAAf8AAP8AAAAA/wAA/gAAAAB/ + AAD8AAAAAD8AAPgAAAAAHwAA8AAAAAAPAADgAAAAAAcAAMAAAAAAAwAAgAAAAAABAAAAAAAAAAAAAAAA + gAAAAAAAAAHAAYAAAAAAA+ADwAAAAAAD8AfAAAAAAAH4D4AAAAAAAPwfAAAAAAAAfj4AAAAAAAA//AAA + AAAAAB/4AAAAAAAAD/AAAAAAAAAH8AAAAAAAAA/wAAAAAAAAD/gAAAAAAAAf/AAAAAAAAD5+AAAAAAAA + fD8AAAAAAAD4H4AAAAAAAfAPwAAAAAAD4AfgAAAAAAHAA8AAAAAAAIABgAAAAAAAAAAAAAAAAAAAAAAA + AACAAAAAAAEAAMAAAAAAAwAA4AAAAAAHAADwAAAAAA8AAPgAAAAAHwAA/AAAAAA/AAD+AAAAAH8AAP8A + AAAA/wAA/4AAAAH/AAD/wAAAA/8AAP/gAAAH/wAA//AAAA//AAAoAAAAQAAAAIAAAAABACAAAAAAAABA + AADYDgAA2A4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABH1fgAR9d8AEfXfABH13wAR9d8AEfXfABH13wAR + 9d8AEfXfABH13wAR9d8AEfXfABH13wAR9d8AEfXfABH13wAR9d8AEfXfABH13wAR9d8AEfXfABH13wAR + 9d8AEfXfABH13wAR9d8AEfXfABH1fgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABH1gQAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfWBAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABH1gQAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9YEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAABH1gQAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1gQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAABH1gQAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfWBAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABH1gQAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9YEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABH1gQAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1gQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABH1gQAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfWBAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAABH1gQAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9YEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAABH1gQAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1gQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABH1gQAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfWBAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABH1gQAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9YEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABH1gQAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1gQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAABH1gQAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfWBAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAABH1gQAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9YEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABH1gQAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH18wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH18QAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1gQAAAAAAAAAAAAAAAAAAAAAAAAAAABH1gQAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH14wAR + 9SYAEfWLABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1yQAR9RgAEfWvABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfWBAAAAAAAAAAAAAAAAABH1gQAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH14wAR9SYAAAAAAAAAAAAR9YsAEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1yQAR9RIAAAAAABH1BgAR9a8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9YEAAAAAABH1fgAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH14wAR9SYAAAAAAAAAAAAAAAAAAAAAABH1iwAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1yQAR9RIAAAAAAAAAAAAA + AAAAEfUGABH1rwAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1fgAR9d8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH14wAR9SYAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAEfWLABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1yQAR + 9RIAAAAAAAAAAAAAAAAAAAAAAAAAAAAR9QYAEfWvABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9d8AEfXfABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH14wAR9SYAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAR9YsAEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1yQAR9RIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABH1BgAR9a8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfXfABH13wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9ZEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABH1iwAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1yQAR9RAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAEfVCABH1/QAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH13wAR9d8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1fgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAEfWJABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1yQAR9RAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAEfU8ABH18QAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9d8AEfXfABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfV+AAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAR9YUAEfX/ABH1/wAR9f8AEfX/ABH1xwAR9RAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEfU8ABH18QAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfXfABH13wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9X4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABH1fgAR9f8AEfX/ABH1wQAR + 9Q4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEfU8ABH18QAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH13wAR + 9d8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1fgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAEfV0ABH1uQAR9QwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEfU8ABH18QAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9d8AEfXfABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfV+AAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAR9QIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAEfU8ABH18QAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfXfABH13wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9X4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAEfU6ABH18QAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH13wAR9d8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1egAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEfU2ABH18QAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9d8AEfXfABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfV2AAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEfU0ABH17wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfXfABH13wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9XAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEfUuABH17QAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH13wAR9d8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX9ABH1SgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAEfUOABH15wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9d8AEfXfABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1vwAR9QoAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAR9XYAEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfXfABH13wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1xQAR9QwAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABH1fgAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH13wAR9d8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1xwAR + 9RAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAEfWFABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9d8AEfXfABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1ywAR9RAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAR9YkAEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfXfABH13wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1yQAR9RAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABH1iwAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH13wAR9d8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1yQAR9RAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAEfUsABH1XgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAEfWLABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9d8AEfXfABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1yQAR9RIAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEfUyABH16wAR9f0AEfVwAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAR9YsAEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfXfABH13wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1yQAR + 9RIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEfU2ABH17wAR9f8AEfX/ABH1/wAR + 9XYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABH1iwAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH13wAR + 9d8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1yQAR9RIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEfU6ABH18QAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1egAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAEfWLABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9d8AEfXfABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1yQAR9RIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAEfU6ABH18QAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfV+AAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAR9YsAEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfXfABH13wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9acAEfUEAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAEfU6ABH18QAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9X4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEfVcABH1/QAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH13wAR9d8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1owAR + 9QQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEfU6ABH18QAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1fgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEfVcABH1+wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9d8AEfXfABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfWjABH1BAAAAAAAAAAAAAAAAAAAAAAAEfU8ABH18QAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfV+AAAAAAAAAAAAAAAAAAAAAAAA + AAAAEfVcABH1+wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfXfABH1egAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9aMAEfUEAAAAAAAAAAAAEfU8ABH18QAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9X4AAAAAAAAAAAAAAAAAEfVcABH1+wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1egAAAAAAEfV8ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1qQAR + 9QYAEfVAABH18wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1fgAAAAAAEfVcABH1+wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1fAAAAAAAAAAAAAAAAAAR + 9XwAEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfXBABH18wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfWtABH1+wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1fAAA + AAAAAAAAAAAAAAAAAAAAAAAAABH1fAAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1fAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEfV8ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1fAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAR + 9XwAEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1fAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAABH1fAAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1fAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEfV8ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1fAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAR + 9XwAEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1fAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAABH1fAAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1fAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEfV8ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1fAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAR + 9XwAEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1fAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAABH1fAAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1fAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEfV8ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1fAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAR + 9XwAEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1fAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAABH1fAAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1fAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEfV8ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1fAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAR + 9XwAEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR + 9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1/wAR9f8AEfX/ABH1fAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAABH1egAR9d8AEfXfABH13wAR9d8AEfXfABH13wAR9d8AEfXfABH13wAR + 9d8AEfXfABH13wAR9d8AEfXfABH13wAR9d8AEfXfABH13wAR9d8AEfXfABH13wAR9d8AEfXfABH13wAR + 9d8AEfXfABH1egAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAP//wAAAA/////+AAAAB/////wAAAAD////+AAAAAH////wAAAAA + P///+AAAAAAf///wAAAAAA///+AAAAAAB///wAAAAAAD//+AAAAAAAH//wAAAAAAAP/+AAAAAAAAf/wA + AAAAAAA/+AAAAAAAAB/wAAAAAAAAD+AAAAAAAAAHwAAAAAAAAAOAAAYAACAAAQAADwAAcAAAAAAfgAD4 + AAAAAD/AAfwAAAAAf+AD/gAAAAA/8Af8AAAAAB/4D/gAAAAAD/wf8AAAAAAH/j/gAAAAAAP/f8AAAAAA + Af//gAAAAAAA//8AAAAAAAB//gAAAAAAAD/8AAAAAAAAH/gAAAAAAAAf/AAAAAAAAD/+AAAAAAAAf/8A + AAAAAAD//4AAAAAAAf//wAAAAAAD/n/gAAAAAAf8P/AAAAAAD/gf+AAAAAAf8A/8AAAAAD/gB/4AAAAA + P8AD/gAAAAAfgAH8AAAAAA8AAPgAAAAABgAAcAAAgAAAAAAgAAHAAAAAAAAAA+AAAAAAAAAH8AAAAAAA + AA/4AAAAAAAAH/wAAAAAAAA//gAAAAAAAH//AAAAAAAA//+AAAAAAAH//8AAAAAAA///4AAAAAAH///w + AAAAAA////gAAAAAH////AAAAAA////+AAAAAH////8AAAAA/////4AAAAH/////wAAAA/// + + + \ No newline at end of file diff --git a/Fo76ini/Forms/FormMods/FormMods.Designer.cs b/Fo76ini/Forms/FormMods/FormMods.Designer.cs index b236e33..8fb93b7 100644 --- a/Fo76ini/Forms/FormMods/FormMods.Designer.cs +++ b/Fo76ini/Forms/FormMods/FormMods.Designer.cs @@ -33,11 +33,13 @@ private void InitializeComponent() this.menuStrip1 = new System.Windows.Forms.MenuStrip(); this.fileToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.addModarchiveToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.emptyModToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.fromArchiveToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.fromba2ArchivefrozenToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.fromFolderToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.toolStripMenuItemModsImport = new System.Windows.Forms.ToolStripMenuItem(); this.toolStripSeparator1 = new System.Windows.Forms.ToolStripSeparator(); + this.saveToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.deployToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.editToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.showConflictingFilesToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); @@ -46,8 +48,11 @@ private void InitializeComponent() this.archive2ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.openArchive2ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.exploreba2ArchiveToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.nexusModsAPIToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.updateModInformationToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.endorseModsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.checkForUpdatesToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.helpToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.showREADMEToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.showGuideToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.logFilesToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.showModmanagerlogtxtToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); @@ -57,39 +62,54 @@ private void InitializeComponent() this.labelModsDeploy = new System.Windows.Forms.Label(); this.tabControl1 = new System.Windows.Forms.TabControl(); this.tabPageModOrder = new System.Windows.Forms.TabPage(); - this.pictureBoxModsLoadingGIF = new System.Windows.Forms.PictureBox(); this.pictureBoxCollapseDetails = new System.Windows.Forms.PictureBox(); this.panelModDetails = new System.Windows.Forms.Panel(); + this.panelModDetailsHeader = new System.Windows.Forms.Panel(); + this.buttonModAbstain = new System.Windows.Forms.Button(); + this.buttonModEndorse = new System.Windows.Forms.Button(); + this.labelModEndorseStatus = new System.Windows.Forms.Label(); + this.labelModTitle = new System.Windows.Forms.Label(); + this.checkBoxModDetailsEnabled = new System.Windows.Forms.CheckBox(); + this.panelModDetailsInner = new System.Windows.Forms.Panel(); + this.groupBoxModReplace = new System.Windows.Forms.GroupBox(); + this.labelModDetailsReplace = new System.Windows.Forms.Label(); + this.linkLabelModDeleteFolderContents = new System.Windows.Forms.LinkLabel(); + this.panelModDetailsReplaceDragAndDrop = new System.Windows.Forms.Panel(); + this.linkLabelModReplaceFilesWithFolder = new System.Windows.Forms.LinkLabel(); + this.linkLabelModReplaceFilesWithArchive = new System.Windows.Forms.LinkLabel(); this.groupBoxModDetailsInstallationOptions = new System.Windows.Forms.GroupBox(); + this.linkLabelModInvalidateFrozenArchive = new System.Windows.Forms.LinkLabel(); + this.linkLabelModAutoDetectInstallOptions = new System.Windows.Forms.LinkLabel(); + this.labelModInstallWarning = new System.Windows.Forms.Label(); this.buttonModPickRootDir = new System.Windows.Forms.Button(); this.labelModInstallAs = new System.Windows.Forms.Label(); this.labelModArchivePreset = new System.Windows.Forms.Label(); this.checkBoxFreezeArchive = new System.Windows.Forms.CheckBox(); this.labelModInstallInto = new System.Windows.Forms.Label(); this.comboBoxModInstallAs = new System.Windows.Forms.ComboBox(); + this.buttonModDetailsSuggestArchiveName = new System.Windows.Forms.Button(); this.textBoxModRootDir = new System.Windows.Forms.TextBox(); this.comboBoxModArchivePreset = new System.Windows.Forms.ComboBox(); - this.buttonModUnfreeze = new System.Windows.Forms.Button(); + this.textBoxModArchiveName = new System.Windows.Forms.TextBox(); + this.labelModArchiveName = new System.Windows.Forms.Label(); this.groupBoxModDetailsDetails = new System.Windows.Forms.GroupBox(); + this.buttonModOpenPage = new System.Windows.Forms.Button(); + this.panelModDetailsNexusMods = new System.Windows.Forms.Panel(); + this.linkLabelModSetLatestVersion = new System.Windows.Forms.LinkLabel(); + this.labelModAuthor = new System.Windows.Forms.Label(); + this.labelModLatestVersion = new System.Windows.Forms.Label(); + this.labelModLatestVersionDesc = new System.Windows.Forms.Label(); + this.labelModAuthorDesc = new System.Windows.Forms.Label(); this.textBoxModVersion = new System.Windows.Forms.TextBox(); this.labelModVersion = new System.Windows.Forms.Label(); this.textBoxModURL = new System.Windows.Forms.TextBox(); this.labelModName = new System.Windows.Forms.Label(); - this.buttonModDetailsSuggestArchiveName = new System.Windows.Forms.Button(); - this.textBoxModFolderName = new System.Windows.Forms.TextBox(); - this.labelModFolderName = new System.Windows.Forms.Label(); this.labelModURL = new System.Windows.Forms.Label(); - this.textBoxModArchiveName = new System.Windows.Forms.TextBox(); - this.labelModArchiveName = new System.Windows.Forms.Label(); this.textBoxModName = new System.Windows.Forms.TextBox(); - this.labelModUnfreeze = new System.Windows.Forms.Label(); - this.labelModTitle = new System.Windows.Forms.Label(); - this.checkBoxModDetailsEnabled = new System.Windows.Forms.CheckBox(); - this.labelModDetailsBulkFrozenModsWarning = new System.Windows.Forms.Label(); + this.labelModSummary = new System.Windows.Forms.Label(); this.pictureBoxModThumbnail = new System.Windows.Forms.PictureBox(); this.toolStrip1 = new System.Windows.Forms.ToolStrip(); this.toolStripButtonAddMod = new System.Windows.Forms.ToolStripButton(); - this.toolStripButtonAddModFrozen = new System.Windows.Forms.ToolStripButton(); this.toolStripButtonAddModFolder = new System.Windows.Forms.ToolStripButton(); this.toolStripSeparator4 = new System.Windows.Forms.ToolStripSeparator(); this.toolStripButtonCheckAll = new System.Windows.Forms.ToolStripButton(); @@ -97,10 +117,8 @@ private void InitializeComponent() this.toolStripButtonMoveUp = new System.Windows.Forms.ToolStripButton(); this.toolStripButtonMoveDown = new System.Windows.Forms.ToolStripButton(); this.toolStripSeparator3 = new System.Windows.Forms.ToolStripSeparator(); - this.toolStripButtonModEdit = new System.Windows.Forms.ToolStripButton(); - this.toolStripButtonUnfreeze = new System.Windows.Forms.ToolStripButton(); this.toolStripButtonModOpenFolder = new System.Windows.Forms.ToolStripButton(); - this.toolStripSeparator5 = new System.Windows.Forms.ToolStripSeparator(); + this.toolStripSeparator6 = new System.Windows.Forms.ToolStripSeparator(); this.toolStripButtonDeleteMod = new System.Windows.Forms.ToolStripButton(); this.listViewMods = new System.Windows.Forms.ListView(); this.columnHeaderModTitle = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); @@ -111,24 +129,21 @@ private void InitializeComponent() this.columnHeaderArchiveFormat = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); this.columnHeaderCompression = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); this.columnHeaderFrozenState = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); - this.panel2 = new System.Windows.Forms.Panel(); - this.buttonModDetailsApply = new System.Windows.Forms.Button(); - this.buttonModDetailsCancel = new System.Windows.Forms.Button(); - this.buttonModDetailsOK = new System.Windows.Forms.Button(); this.tabPageModsSettings = new System.Windows.Forms.TabPage(); this.groupBoxModsBehavior = new System.Windows.Forms.GroupBox(); - this.checkBoxModsWriteSResourceDataDirsFinal = new System.Windows.Forms.CheckBox(); this.checkBoxFreezeBundledArchives = new System.Windows.Forms.CheckBox(); this.checkBoxModsUseHardlinks = new System.Windows.Forms.CheckBox(); this.checkBoxAddArchivesAsBundled = new System.Windows.Forms.CheckBox(); this.groupBoxLists = new System.Windows.Forms.GroupBox(); - this.buttonModsResetTextboxes = new System.Windows.Forms.Button(); - this.buttonModsApplyTextBoxes = new System.Windows.Forms.Button(); - this.textBoxsResourceIndexFileList = new System.Windows.Forms.TextBox(); - this.buttonModsCleanLists = new System.Windows.Forms.Button(); + this.buttonModsResetTextbox = new System.Windows.Forms.Button(); + this.buttonModsApplyTextBox = new System.Windows.Forms.Button(); + this.textBoxResourceList = new System.Windows.Forms.TextBox(); + this.buttonModsCleanList = new System.Windows.Forms.Button(); this.labelsResourceIndexFileList = new System.Windows.Forms.Label(); - this.textBoxsResourceArchive2List = new System.Windows.Forms.TextBox(); - this.labelsResourceArchive2List = new System.Windows.Forms.Label(); + this.tabPageNexusMods = new System.Windows.Forms.TabPage(); + this.labelNexusModsMovedNotice2 = new System.Windows.Forms.Label(); + this.labelNexusModsMovedNotice = new System.Windows.Forms.Label(); + this.pictureBox1 = new System.Windows.Forms.PictureBox(); this.toolTip = new System.Windows.Forms.ToolTip(this.components); this.openFileDialogMod = new System.Windows.Forms.OpenFileDialog(); this.folderBrowserDialogMod = new System.Windows.Forms.FolderBrowserDialog(); @@ -137,23 +152,35 @@ private void InitializeComponent() this.panel1 = new System.Windows.Forms.Panel(); this.openFileDialogBA2 = new System.Windows.Forms.OpenFileDialog(); this.folderBrowserDialogPickRootDir = new System.Windows.Forms.FolderBrowserDialog(); - this.backgroundWorkerRetrieveModInfo = new System.ComponentModel.BackgroundWorker(); - this.backgroundWorkerRetrieveProfileInfo = new System.ComponentModel.BackgroundWorker(); + this.statusStrip1 = new System.Windows.Forms.StatusStrip(); + this.toolStripStatusLabelDescModCount = new System.Windows.Forms.ToolStripStatusLabel(); + this.toolStripStatusLabelModCount = new System.Windows.Forms.ToolStripStatusLabel(); + this.toolStripStatusLabelDescEnabledCount = new System.Windows.Forms.ToolStripStatusLabel(); + this.toolStripStatusLabelEnabledCount = new System.Windows.Forms.ToolStripStatusLabel(); + this.toolStripStatusLabelSpacer = new System.Windows.Forms.ToolStripStatusLabel(); + this.toolStripStatusLabelDeploymentStatus = new System.Windows.Forms.ToolStripStatusLabel(); + this.pictureBoxModsLoadingGIF = new System.Windows.Forms.PictureBox(); this.menuStrip1.SuspendLayout(); this.tabControl1.SuspendLayout(); this.tabPageModOrder.SuspendLayout(); - ((System.ComponentModel.ISupportInitialize)(this.pictureBoxModsLoadingGIF)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.pictureBoxCollapseDetails)).BeginInit(); this.panelModDetails.SuspendLayout(); + this.panelModDetailsHeader.SuspendLayout(); + this.panelModDetailsInner.SuspendLayout(); + this.groupBoxModReplace.SuspendLayout(); this.groupBoxModDetailsInstallationOptions.SuspendLayout(); this.groupBoxModDetailsDetails.SuspendLayout(); + this.panelModDetailsNexusMods.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.pictureBoxModThumbnail)).BeginInit(); this.toolStrip1.SuspendLayout(); - this.panel2.SuspendLayout(); this.tabPageModsSettings.SuspendLayout(); this.groupBoxModsBehavior.SuspendLayout(); this.groupBoxLists.SuspendLayout(); + this.tabPageNexusMods.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit(); this.panel1.SuspendLayout(); + this.statusStrip1.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBoxModsLoadingGIF)).BeginInit(); this.SuspendLayout(); // // menuStrip1 @@ -165,7 +192,7 @@ private void InitializeComponent() this.helpToolStripMenuItem}); this.menuStrip1.Location = new System.Drawing.Point(0, 0); this.menuStrip1.Name = "menuStrip1"; - this.menuStrip1.Size = new System.Drawing.Size(884, 24); + this.menuStrip1.Size = new System.Drawing.Size(784, 24); this.menuStrip1.TabIndex = 49; this.menuStrip1.Text = "menuStrip1"; // @@ -175,6 +202,7 @@ private void InitializeComponent() this.addModarchiveToolStripMenuItem, this.toolStripMenuItemModsImport, this.toolStripSeparator1, + this.saveToolStripMenuItem, this.deployToolStripMenuItem}); this.fileToolStripMenuItem.Name = "fileToolStripMenuItem"; this.fileToolStripMenuItem.Size = new System.Drawing.Size(37, 20); @@ -183,15 +211,26 @@ private void InitializeComponent() // addModarchiveToolStripMenuItem // this.addModarchiveToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.emptyModToolStripMenuItem, this.fromArchiveToolStripMenuItem, this.fromba2ArchivefrozenToolStripMenuItem, this.fromFolderToolStripMenuItem}); + this.addModarchiveToolStripMenuItem.Image = global::Fo76ini.Properties.Resources.plus_24; this.addModarchiveToolStripMenuItem.Name = "addModarchiveToolStripMenuItem"; this.addModarchiveToolStripMenuItem.Size = new System.Drawing.Size(190, 22); this.addModarchiveToolStripMenuItem.Text = "Add mod"; // + // emptyModToolStripMenuItem + // + this.emptyModToolStripMenuItem.Image = global::Fo76ini.Properties.Resources.plus_24; + this.emptyModToolStripMenuItem.Name = "emptyModToolStripMenuItem"; + this.emptyModToolStripMenuItem.Size = new System.Drawing.Size(217, 22); + this.emptyModToolStripMenuItem.Text = "Empty mod"; + this.emptyModToolStripMenuItem.Click += new System.EventHandler(this.emptyModToolStripMenuItem_Click); + // // fromArchiveToolStripMenuItem // + this.fromArchiveToolStripMenuItem.Image = global::Fo76ini.Properties.Resources.add_archive_3_24; this.fromArchiveToolStripMenuItem.Name = "fromArchiveToolStripMenuItem"; this.fromArchiveToolStripMenuItem.Size = new System.Drawing.Size(217, 22); this.fromArchiveToolStripMenuItem.Text = "From archive"; @@ -199,6 +238,7 @@ private void InitializeComponent() // // fromba2ArchivefrozenToolStripMenuItem // + this.fromba2ArchivefrozenToolStripMenuItem.Image = global::Fo76ini.Properties.Resources.add_snowflake_24; this.fromba2ArchivefrozenToolStripMenuItem.Name = "fromba2ArchivefrozenToolStripMenuItem"; this.fromba2ArchivefrozenToolStripMenuItem.Size = new System.Drawing.Size(217, 22); this.fromba2ArchivefrozenToolStripMenuItem.Text = "From *.ba2 archive (frozen)"; @@ -206,6 +246,7 @@ private void InitializeComponent() // // fromFolderToolStripMenuItem // + this.fromFolderToolStripMenuItem.Image = global::Fo76ini.Properties.Resources.add_folder_24; this.fromFolderToolStripMenuItem.Name = "fromFolderToolStripMenuItem"; this.fromFolderToolStripMenuItem.Size = new System.Drawing.Size(217, 22); this.fromFolderToolStripMenuItem.Text = "From folder"; @@ -223,11 +264,19 @@ private void InitializeComponent() this.toolStripSeparator1.Name = "toolStripSeparator1"; this.toolStripSeparator1.Size = new System.Drawing.Size(187, 6); // + // saveToolStripMenuItem + // + this.saveToolStripMenuItem.Image = global::Fo76ini.Properties.Resources.save_24; + this.saveToolStripMenuItem.Name = "saveToolStripMenuItem"; + this.saveToolStripMenuItem.Size = new System.Drawing.Size(190, 22); + this.saveToolStripMenuItem.Text = "Save changes"; + this.saveToolStripMenuItem.Click += new System.EventHandler(this.saveToolStripMenuItem_Click); + // // deployToolStripMenuItem // this.deployToolStripMenuItem.Name = "deployToolStripMenuItem"; this.deployToolStripMenuItem.Size = new System.Drawing.Size(190, 22); - this.deployToolStripMenuItem.Text = "Deploy"; + this.deployToolStripMenuItem.Text = "Deploy mods"; this.deployToolStripMenuItem.Click += new System.EventHandler(this.deployToolStripMenuItem_Click); // // editToolStripMenuItem @@ -248,6 +297,7 @@ private void InitializeComponent() // // reloadUIToolStripMenuItem // + this.reloadUIToolStripMenuItem.Image = global::Fo76ini.Properties.Resources.available_updates; this.reloadUIToolStripMenuItem.Name = "reloadUIToolStripMenuItem"; this.reloadUIToolStripMenuItem.Size = new System.Drawing.Size(187, 22); this.reloadUIToolStripMenuItem.Text = "Reload UI"; @@ -256,7 +306,8 @@ private void InitializeComponent() // toolsToolStripMenuItem // this.toolsToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.archive2ToolStripMenuItem}); + this.archive2ToolStripMenuItem, + this.nexusModsAPIToolStripMenuItem}); this.toolsToolStripMenuItem.Name = "toolsToolStripMenuItem"; this.toolsToolStripMenuItem.Size = new System.Drawing.Size(46, 20); this.toolsToolStripMenuItem.Text = "Tools"; @@ -267,7 +318,7 @@ private void InitializeComponent() this.openArchive2ToolStripMenuItem, this.exploreba2ArchiveToolStripMenuItem}); this.archive2ToolStripMenuItem.Name = "archive2ToolStripMenuItem"; - this.archive2ToolStripMenuItem.Size = new System.Drawing.Size(180, 22); + this.archive2ToolStripMenuItem.Size = new System.Drawing.Size(158, 22); this.archive2ToolStripMenuItem.Text = "Archive2"; // // openArchive2ToolStripMenuItem @@ -284,27 +335,51 @@ private void InitializeComponent() this.exploreba2ArchiveToolStripMenuItem.Text = "Explore *.ba2 archive"; this.exploreba2ArchiveToolStripMenuItem.Click += new System.EventHandler(this.exploreba2ArchiveToolStripMenuItem_Click); // + // nexusModsAPIToolStripMenuItem + // + this.nexusModsAPIToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.updateModInformationToolStripMenuItem, + this.endorseModsToolStripMenuItem, + this.checkForUpdatesToolStripMenuItem}); + this.nexusModsAPIToolStripMenuItem.Name = "nexusModsAPIToolStripMenuItem"; + this.nexusModsAPIToolStripMenuItem.Size = new System.Drawing.Size(158, 22); + this.nexusModsAPIToolStripMenuItem.Text = "NexusMods API"; + // + // updateModInformationToolStripMenuItem + // + this.updateModInformationToolStripMenuItem.Name = "updateModInformationToolStripMenuItem"; + this.updateModInformationToolStripMenuItem.Size = new System.Drawing.Size(206, 22); + this.updateModInformationToolStripMenuItem.Text = "Update mod information"; + this.updateModInformationToolStripMenuItem.Click += new System.EventHandler(this.updateModInformationToolStripMenuItem_Click); + // + // endorseModsToolStripMenuItem + // + this.endorseModsToolStripMenuItem.Name = "endorseModsToolStripMenuItem"; + this.endorseModsToolStripMenuItem.Size = new System.Drawing.Size(206, 22); + this.endorseModsToolStripMenuItem.Text = "Endorse mods"; + this.endorseModsToolStripMenuItem.Click += new System.EventHandler(this.endorseModsToolStripMenuItem_Click); + // + // checkForUpdatesToolStripMenuItem + // + this.checkForUpdatesToolStripMenuItem.Name = "checkForUpdatesToolStripMenuItem"; + this.checkForUpdatesToolStripMenuItem.Size = new System.Drawing.Size(206, 22); + this.checkForUpdatesToolStripMenuItem.Text = "Check for updates"; + this.checkForUpdatesToolStripMenuItem.Click += new System.EventHandler(this.checkForUpdatesToolStripMenuItem_Click); + // // helpToolStripMenuItem // this.helpToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.showREADMEToolStripMenuItem, this.showGuideToolStripMenuItem, this.logFilesToolStripMenuItem}); this.helpToolStripMenuItem.Name = "helpToolStripMenuItem"; this.helpToolStripMenuItem.Size = new System.Drawing.Size(44, 20); this.helpToolStripMenuItem.Text = "Help"; // - // showREADMEToolStripMenuItem - // - this.showREADMEToolStripMenuItem.Name = "showREADMEToolStripMenuItem"; - this.showREADMEToolStripMenuItem.Size = new System.Drawing.Size(180, 22); - this.showREADMEToolStripMenuItem.Text = "Show README"; - this.showREADMEToolStripMenuItem.Click += new System.EventHandler(this.showREADMEToolStripMenuItem_Click); - // // showGuideToolStripMenuItem // + this.showGuideToolStripMenuItem.Image = global::Fo76ini.Properties.Resources.help_24; this.showGuideToolStripMenuItem.Name = "showGuideToolStripMenuItem"; - this.showGuideToolStripMenuItem.Size = new System.Drawing.Size(180, 22); + this.showGuideToolStripMenuItem.Size = new System.Drawing.Size(136, 22); this.showGuideToolStripMenuItem.Text = "Show guide"; this.showGuideToolStripMenuItem.Click += new System.EventHandler(this.showGuideToolStripMenuItem_Click); // @@ -314,7 +389,7 @@ private void InitializeComponent() this.showModmanagerlogtxtToolStripMenuItem, this.showArchive2logtxtToolStripMenuItem}); this.logFilesToolStripMenuItem.Name = "logFilesToolStripMenuItem"; - this.logFilesToolStripMenuItem.Size = new System.Drawing.Size(180, 22); + this.logFilesToolStripMenuItem.Size = new System.Drawing.Size(136, 22); this.logFilesToolStripMenuItem.Text = "Log files"; // // showModmanagerlogtxtToolStripMenuItem @@ -335,18 +410,17 @@ private void InitializeComponent() // this.progressBarMods.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); - this.progressBarMods.Location = new System.Drawing.Point(12, 626); + this.progressBarMods.Location = new System.Drawing.Point(12, 543); this.progressBarMods.MarqueeAnimationSpeed = 15; this.progressBarMods.Name = "progressBarMods"; - this.progressBarMods.Size = new System.Drawing.Size(700, 23); + this.progressBarMods.Size = new System.Drawing.Size(600, 23); this.progressBarMods.TabIndex = 51; // // buttonModsDeploy // - this.buttonModsDeploy.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); - this.buttonModsDeploy.Location = new System.Drawing.Point(3, 22); + this.buttonModsDeploy.Location = new System.Drawing.Point(3, 21); this.buttonModsDeploy.Name = "buttonModsDeploy"; - this.buttonModsDeploy.Size = new System.Drawing.Size(154, 23); + this.buttonModsDeploy.Size = new System.Drawing.Size(154, 25); this.buttonModsDeploy.TabIndex = 50; this.buttonModsDeploy.Text = "Deploy"; this.buttonModsDeploy.UseVisualStyleBackColor = true; @@ -356,12 +430,12 @@ private void InitializeComponent() // this.labelModsDeploy.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); this.labelModsDeploy.AutoSize = true; - this.labelModsDeploy.ForeColor = System.Drawing.Color.Crimson; - this.labelModsDeploy.Location = new System.Drawing.Point(12, 610); + this.labelModsDeploy.ForeColor = System.Drawing.Color.DarkGreen; + this.labelModsDeploy.Location = new System.Drawing.Point(9, 527); this.labelModsDeploy.Name = "labelModsDeploy"; - this.labelModsDeploy.Size = new System.Drawing.Size(114, 13); + this.labelModsDeploy.Size = new System.Drawing.Size(38, 13); this.labelModsDeploy.TabIndex = 52; - this.labelModsDeploy.Text = "Deployment necessary"; + this.labelModsDeploy.Text = "Ready"; // // tabControl1 // @@ -370,42 +444,27 @@ private void InitializeComponent() | System.Windows.Forms.AnchorStyles.Right))); this.tabControl1.Controls.Add(this.tabPageModOrder); this.tabControl1.Controls.Add(this.tabPageModsSettings); + this.tabControl1.Controls.Add(this.tabPageNexusMods); this.tabControl1.Location = new System.Drawing.Point(12, 27); this.tabControl1.Name = "tabControl1"; this.tabControl1.SelectedIndex = 0; - this.tabControl1.Size = new System.Drawing.Size(860, 570); + this.tabControl1.Size = new System.Drawing.Size(760, 490); this.tabControl1.TabIndex = 54; // // tabPageModOrder // - this.tabPageModOrder.Controls.Add(this.pictureBoxModsLoadingGIF); this.tabPageModOrder.Controls.Add(this.pictureBoxCollapseDetails); this.tabPageModOrder.Controls.Add(this.panelModDetails); this.tabPageModOrder.Controls.Add(this.toolStrip1); this.tabPageModOrder.Controls.Add(this.listViewMods); - this.tabPageModOrder.Controls.Add(this.panel2); this.tabPageModOrder.Location = new System.Drawing.Point(4, 22); this.tabPageModOrder.Name = "tabPageModOrder"; this.tabPageModOrder.Padding = new System.Windows.Forms.Padding(3); - this.tabPageModOrder.Size = new System.Drawing.Size(852, 544); + this.tabPageModOrder.Size = new System.Drawing.Size(752, 464); this.tabPageModOrder.TabIndex = 0; this.tabPageModOrder.Text = "Mod order"; this.tabPageModOrder.UseVisualStyleBackColor = true; // - // pictureBoxModsLoadingGIF - // - this.pictureBoxModsLoadingGIF.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) - | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.pictureBoxModsLoadingGIF.Image = global::Fo76ini.Properties.Resources.Spinner_200; - this.pictureBoxModsLoadingGIF.Location = new System.Drawing.Point(39, 0); - this.pictureBoxModsLoadingGIF.Name = "pictureBoxModsLoadingGIF"; - this.pictureBoxModsLoadingGIF.Size = new System.Drawing.Size(813, 544); - this.pictureBoxModsLoadingGIF.SizeMode = System.Windows.Forms.PictureBoxSizeMode.CenterImage; - this.pictureBoxModsLoadingGIF.TabIndex = 57; - this.pictureBoxModsLoadingGIF.TabStop = false; - this.pictureBoxModsLoadingGIF.Visible = false; - // // pictureBoxCollapseDetails // this.pictureBoxCollapseDetails.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) @@ -413,9 +472,9 @@ private void InitializeComponent() this.pictureBoxCollapseDetails.BackColor = System.Drawing.SystemColors.ButtonShadow; this.pictureBoxCollapseDetails.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; this.pictureBoxCollapseDetails.Image = ((System.Drawing.Image)(resources.GetObject("pictureBoxCollapseDetails.Image"))); - this.pictureBoxCollapseDetails.Location = new System.Drawing.Point(476, 0); + this.pictureBoxCollapseDetails.Location = new System.Drawing.Point(333, 0); this.pictureBoxCollapseDetails.Name = "pictureBoxCollapseDetails"; - this.pictureBoxCollapseDetails.Size = new System.Drawing.Size(24, 544); + this.pictureBoxCollapseDetails.Size = new System.Drawing.Size(24, 464); this.pictureBoxCollapseDetails.SizeMode = System.Windows.Forms.PictureBoxSizeMode.CenterImage; this.pictureBoxCollapseDetails.TabIndex = 59; this.pictureBoxCollapseDetails.TabStop = false; @@ -428,42 +487,241 @@ private void InitializeComponent() this.panelModDetails.AutoScrollMargin = new System.Drawing.Size(0, 20); this.panelModDetails.BackColor = System.Drawing.SystemColors.Window; this.panelModDetails.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; - this.panelModDetails.Controls.Add(this.groupBoxModDetailsInstallationOptions); - this.panelModDetails.Controls.Add(this.buttonModUnfreeze); - this.panelModDetails.Controls.Add(this.groupBoxModDetailsDetails); - this.panelModDetails.Controls.Add(this.labelModUnfreeze); - this.panelModDetails.Controls.Add(this.labelModTitle); - this.panelModDetails.Controls.Add(this.checkBoxModDetailsEnabled); - this.panelModDetails.Controls.Add(this.labelModDetailsBulkFrozenModsWarning); + this.panelModDetails.Controls.Add(this.panelModDetailsHeader); + this.panelModDetails.Controls.Add(this.panelModDetailsInner); this.panelModDetails.Controls.Add(this.pictureBoxModThumbnail); - this.panelModDetails.Location = new System.Drawing.Point(496, 0); + this.panelModDetails.Location = new System.Drawing.Point(356, 0); this.panelModDetails.Name = "panelModDetails"; - this.panelModDetails.Size = new System.Drawing.Size(356, 503); + this.panelModDetails.Size = new System.Drawing.Size(396, 464); this.panelModDetails.TabIndex = 58; // + // panelModDetailsHeader + // + this.panelModDetailsHeader.Controls.Add(this.buttonModAbstain); + this.panelModDetailsHeader.Controls.Add(this.buttonModEndorse); + this.panelModDetailsHeader.Controls.Add(this.labelModEndorseStatus); + this.panelModDetailsHeader.Controls.Add(this.labelModTitle); + this.panelModDetailsHeader.Controls.Add(this.checkBoxModDetailsEnabled); + this.panelModDetailsHeader.Location = new System.Drawing.Point(0, 157); + this.panelModDetailsHeader.Name = "panelModDetailsHeader"; + this.panelModDetailsHeader.Size = new System.Drawing.Size(395, 62); + this.panelModDetailsHeader.TabIndex = 77; + // + // buttonModAbstain + // + this.buttonModAbstain.BackColor = System.Drawing.Color.Transparent; + this.buttonModAbstain.FlatAppearance.BorderColor = System.Drawing.Color.FromArgb(((int)(((byte)(255)))), ((int)(((byte)(128)))), ((int)(((byte)(128))))); + this.buttonModAbstain.FlatAppearance.BorderSize = 0; + this.buttonModAbstain.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.buttonModAbstain.Image = global::Fo76ini.Properties.Resources.dislike; + this.buttonModAbstain.ImageAlign = System.Drawing.ContentAlignment.BottomCenter; + this.buttonModAbstain.Location = new System.Drawing.Point(356, 1); + this.buttonModAbstain.Name = "buttonModAbstain"; + this.buttonModAbstain.Size = new System.Drawing.Size(36, 40); + this.buttonModAbstain.TabIndex = 73; + this.toolTip.SetToolTip(this.buttonModAbstain, "Abstain from endorsing this mod."); + this.buttonModAbstain.UseVisualStyleBackColor = false; + this.buttonModAbstain.Click += new System.EventHandler(this.buttonModAbstain_Click); + // + // buttonModEndorse + // + this.buttonModEndorse.BackColor = System.Drawing.Color.Transparent; + this.buttonModEndorse.FlatAppearance.BorderColor = System.Drawing.Color.FromArgb(((int)(((byte)(128)))), ((int)(((byte)(255)))), ((int)(((byte)(128))))); + this.buttonModEndorse.FlatAppearance.BorderSize = 0; + this.buttonModEndorse.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.buttonModEndorse.Image = global::Fo76ini.Properties.Resources.like; + this.buttonModEndorse.ImageAlign = System.Drawing.ContentAlignment.TopCenter; + this.buttonModEndorse.Location = new System.Drawing.Point(316, 1); + this.buttonModEndorse.Name = "buttonModEndorse"; + this.buttonModEndorse.Size = new System.Drawing.Size(36, 40); + this.buttonModEndorse.TabIndex = 72; + this.toolTip.SetToolTip(this.buttonModEndorse, "Endorse this mod."); + this.buttonModEndorse.UseVisualStyleBackColor = false; + this.buttonModEndorse.Click += new System.EventHandler(this.buttonModEndorse_Click); + // + // labelModEndorseStatus + // + this.labelModEndorseStatus.Location = new System.Drawing.Point(145, 38); + this.labelModEndorseStatus.Name = "labelModEndorseStatus"; + this.labelModEndorseStatus.Size = new System.Drawing.Size(246, 13); + this.labelModEndorseStatus.TabIndex = 71; + this.labelModEndorseStatus.Text = "< Whether or not the user has endorsed this mod >"; + this.labelModEndorseStatus.TextAlign = System.Drawing.ContentAlignment.TopRight; + // + // labelModTitle + // + this.labelModTitle.AutoEllipsis = true; + this.labelModTitle.Font = new System.Drawing.Font("Microsoft Sans Serif", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.labelModTitle.Location = new System.Drawing.Point(-12, 2); + this.labelModTitle.Name = "labelModTitle"; + this.labelModTitle.Padding = new System.Windows.Forms.Padding(16, 2, 0, 2); + this.labelModTitle.Size = new System.Drawing.Size(322, 25); + this.labelModTitle.TabIndex = 75; + this.labelModTitle.Text = "< Mod name goes here >"; + // + // checkBoxModDetailsEnabled + // + this.checkBoxModDetailsEnabled.AutoSize = true; + this.checkBoxModDetailsEnabled.Location = new System.Drawing.Point(8, 30); + this.checkBoxModDetailsEnabled.Name = "checkBoxModDetailsEnabled"; + this.checkBoxModDetailsEnabled.Size = new System.Drawing.Size(101, 17); + this.checkBoxModDetailsEnabled.TabIndex = 74; + this.checkBoxModDetailsEnabled.Text = "Enable this mod"; + this.checkBoxModDetailsEnabled.UseVisualStyleBackColor = true; + // + // panelModDetailsInner + // + this.panelModDetailsInner.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left))); + this.panelModDetailsInner.AutoScroll = true; + this.panelModDetailsInner.AutoScrollMargin = new System.Drawing.Size(0, 8); + this.panelModDetailsInner.BackColor = System.Drawing.SystemColors.Window; + this.panelModDetailsInner.Controls.Add(this.groupBoxModReplace); + this.panelModDetailsInner.Controls.Add(this.groupBoxModDetailsInstallationOptions); + this.panelModDetailsInner.Controls.Add(this.groupBoxModDetailsDetails); + this.panelModDetailsInner.Controls.Add(this.labelModSummary); + this.panelModDetailsInner.Location = new System.Drawing.Point(0, 218); + this.panelModDetailsInner.Name = "panelModDetailsInner"; + this.panelModDetailsInner.Size = new System.Drawing.Size(394, 246); + this.panelModDetailsInner.TabIndex = 76; + // + // groupBoxModReplace + // + this.groupBoxModReplace.Controls.Add(this.labelModDetailsReplace); + this.groupBoxModReplace.Controls.Add(this.linkLabelModDeleteFolderContents); + this.groupBoxModReplace.Controls.Add(this.panelModDetailsReplaceDragAndDrop); + this.groupBoxModReplace.Controls.Add(this.linkLabelModReplaceFilesWithFolder); + this.groupBoxModReplace.Controls.Add(this.linkLabelModReplaceFilesWithArchive); + this.groupBoxModReplace.Location = new System.Drawing.Point(6, 486); + this.groupBoxModReplace.Name = "groupBoxModReplace"; + this.groupBoxModReplace.Size = new System.Drawing.Size(365, 136); + this.groupBoxModReplace.TabIndex = 75; + this.groupBoxModReplace.TabStop = false; + this.groupBoxModReplace.Text = "Add / replace mod files"; + // + // labelModDetailsReplace + // + this.labelModDetailsReplace.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.labelModDetailsReplace.ForeColor = System.Drawing.Color.Gray; + this.labelModDetailsReplace.Location = new System.Drawing.Point(175, 76); + this.labelModDetailsReplace.Name = "labelModDetailsReplace"; + this.labelModDetailsReplace.Size = new System.Drawing.Size(168, 52); + this.labelModDetailsReplace.TabIndex = 0; + this.labelModDetailsReplace.Text = "Drag-and-drop files/folders into the left box to add/replace files."; + this.labelModDetailsReplace.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; + // + // linkLabelModDeleteFolderContents + // + this.linkLabelModDeleteFolderContents.AutoSize = true; + this.linkLabelModDeleteFolderContents.LinkBehavior = System.Windows.Forms.LinkBehavior.HoverUnderline; + this.linkLabelModDeleteFolderContents.Location = new System.Drawing.Point(173, 60); + this.linkLabelModDeleteFolderContents.Name = "linkLabelModDeleteFolderContents"; + this.linkLabelModDeleteFolderContents.Size = new System.Drawing.Size(111, 13); + this.linkLabelModDeleteFolderContents.TabIndex = 5; + this.linkLabelModDeleteFolderContents.TabStop = true; + this.linkLabelModDeleteFolderContents.Text = "Delete folder contents"; + this.linkLabelModDeleteFolderContents.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.linkLabelModDeleteFolderContents_LinkClicked); + // + // panelModDetailsReplaceDragAndDrop + // + this.panelModDetailsReplaceDragAndDrop.AllowDrop = true; + this.panelModDetailsReplaceDragAndDrop.BackgroundImage = global::Fo76ini.Properties.Resources.download_2_48; + this.panelModDetailsReplaceDragAndDrop.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Center; + this.panelModDetailsReplaceDragAndDrop.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + this.panelModDetailsReplaceDragAndDrop.Location = new System.Drawing.Point(6, 19); + this.panelModDetailsReplaceDragAndDrop.Name = "panelModDetailsReplaceDragAndDrop"; + this.panelModDetailsReplaceDragAndDrop.Size = new System.Drawing.Size(159, 108); + this.panelModDetailsReplaceDragAndDrop.TabIndex = 4; + // + // linkLabelModReplaceFilesWithFolder + // + this.linkLabelModReplaceFilesWithFolder.AutoSize = true; + this.linkLabelModReplaceFilesWithFolder.LinkBehavior = System.Windows.Forms.LinkBehavior.HoverUnderline; + this.linkLabelModReplaceFilesWithFolder.Location = new System.Drawing.Point(173, 39); + this.linkLabelModReplaceFilesWithFolder.Name = "linkLabelModReplaceFilesWithFolder"; + this.linkLabelModReplaceFilesWithFolder.Size = new System.Drawing.Size(65, 13); + this.linkLabelModReplaceFilesWithFolder.TabIndex = 1; + this.linkLabelModReplaceFilesWithFolder.TabStop = true; + this.linkLabelModReplaceFilesWithFolder.Text = "Import folder"; + this.linkLabelModReplaceFilesWithFolder.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.linkLabelModReplaceFilesWithFolder_LinkClicked); + // + // linkLabelModReplaceFilesWithArchive + // + this.linkLabelModReplaceFilesWithArchive.AutoSize = true; + this.linkLabelModReplaceFilesWithArchive.LinkBehavior = System.Windows.Forms.LinkBehavior.HoverUnderline; + this.linkLabelModReplaceFilesWithArchive.Location = new System.Drawing.Point(173, 19); + this.linkLabelModReplaceFilesWithArchive.Name = "linkLabelModReplaceFilesWithArchive"; + this.linkLabelModReplaceFilesWithArchive.Size = new System.Drawing.Size(74, 13); + this.linkLabelModReplaceFilesWithArchive.TabIndex = 0; + this.linkLabelModReplaceFilesWithArchive.TabStop = true; + this.linkLabelModReplaceFilesWithArchive.Text = "Import archive"; + this.linkLabelModReplaceFilesWithArchive.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.linkLabelModReplaceFilesWithArchive_LinkClicked); + // // groupBoxModDetailsInstallationOptions // + this.groupBoxModDetailsInstallationOptions.Controls.Add(this.linkLabelModInvalidateFrozenArchive); + this.groupBoxModDetailsInstallationOptions.Controls.Add(this.linkLabelModAutoDetectInstallOptions); + this.groupBoxModDetailsInstallationOptions.Controls.Add(this.labelModInstallWarning); this.groupBoxModDetailsInstallationOptions.Controls.Add(this.buttonModPickRootDir); this.groupBoxModDetailsInstallationOptions.Controls.Add(this.labelModInstallAs); this.groupBoxModDetailsInstallationOptions.Controls.Add(this.labelModArchivePreset); this.groupBoxModDetailsInstallationOptions.Controls.Add(this.checkBoxFreezeArchive); this.groupBoxModDetailsInstallationOptions.Controls.Add(this.labelModInstallInto); this.groupBoxModDetailsInstallationOptions.Controls.Add(this.comboBoxModInstallAs); + this.groupBoxModDetailsInstallationOptions.Controls.Add(this.buttonModDetailsSuggestArchiveName); this.groupBoxModDetailsInstallationOptions.Controls.Add(this.textBoxModRootDir); this.groupBoxModDetailsInstallationOptions.Controls.Add(this.comboBoxModArchivePreset); - this.groupBoxModDetailsInstallationOptions.Location = new System.Drawing.Point(8, 374); + this.groupBoxModDetailsInstallationOptions.Controls.Add(this.textBoxModArchiveName); + this.groupBoxModDetailsInstallationOptions.Controls.Add(this.labelModArchiveName); + this.groupBoxModDetailsInstallationOptions.Location = new System.Drawing.Point(6, 233); this.groupBoxModDetailsInstallationOptions.Name = "groupBoxModDetailsInstallationOptions"; - this.groupBoxModDetailsInstallationOptions.Size = new System.Drawing.Size(341, 120); + this.groupBoxModDetailsInstallationOptions.Size = new System.Drawing.Size(365, 247); this.groupBoxModDetailsInstallationOptions.TabIndex = 74; this.groupBoxModDetailsInstallationOptions.TabStop = false; this.groupBoxModDetailsInstallationOptions.Text = "Installation options"; // + // linkLabelModInvalidateFrozenArchive + // + this.linkLabelModInvalidateFrozenArchive.AutoSize = true; + this.linkLabelModInvalidateFrozenArchive.LinkBehavior = System.Windows.Forms.LinkBehavior.HoverUnderline; + this.linkLabelModInvalidateFrozenArchive.Location = new System.Drawing.Point(110, 131); + this.linkLabelModInvalidateFrozenArchive.Name = "linkLabelModInvalidateFrozenArchive"; + this.linkLabelModInvalidateFrozenArchive.Size = new System.Drawing.Size(123, 13); + this.linkLabelModInvalidateFrozenArchive.TabIndex = 51; + this.linkLabelModInvalidateFrozenArchive.TabStop = true; + this.linkLabelModInvalidateFrozenArchive.Text = "Invalidate frozen archive"; + this.linkLabelModInvalidateFrozenArchive.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.linkLabelModInvalidateFrozenArchive_LinkClicked); + // + // linkLabelModAutoDetectInstallOptions + // + this.linkLabelModAutoDetectInstallOptions.AutoSize = true; + this.linkLabelModAutoDetectInstallOptions.LinkBehavior = System.Windows.Forms.LinkBehavior.HoverUnderline; + this.linkLabelModAutoDetectInstallOptions.Location = new System.Drawing.Point(7, 220); + this.linkLabelModAutoDetectInstallOptions.Name = "linkLabelModAutoDetectInstallOptions"; + this.linkLabelModAutoDetectInstallOptions.Size = new System.Drawing.Size(189, 13); + this.linkLabelModAutoDetectInstallOptions.TabIndex = 50; + this.linkLabelModAutoDetectInstallOptions.TabStop = true; + this.linkLabelModAutoDetectInstallOptions.Text = "Attempt auto-detect installation options"; + this.linkLabelModAutoDetectInstallOptions.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.linkLabelModAutoDetectInstallOptions_LinkClicked); + // + // labelModInstallWarning + // + this.labelModInstallWarning.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.labelModInstallWarning.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(147)))), ((int)(((byte)(107)))), ((int)(((byte)(8))))); + this.labelModInstallWarning.Location = new System.Drawing.Point(7, 154); + this.labelModInstallWarning.Name = "labelModInstallWarning"; + this.labelModInstallWarning.Size = new System.Drawing.Size(352, 66); + this.labelModInstallWarning.TabIndex = 49; + this.labelModInstallWarning.Text = "< Warning here >"; + // // buttonModPickRootDir // this.buttonModPickRootDir.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); - this.buttonModPickRootDir.Location = new System.Drawing.Point(309, 44); + this.buttonModPickRootDir.Location = new System.Drawing.Point(333, 44); this.buttonModPickRootDir.Name = "buttonModPickRootDir"; - this.buttonModPickRootDir.Size = new System.Drawing.Size(26, 23); + this.buttonModPickRootDir.Size = new System.Drawing.Size(26, 24); this.buttonModPickRootDir.TabIndex = 5; this.buttonModPickRootDir.Text = "..."; this.buttonModPickRootDir.UseVisualStyleBackColor = true; @@ -472,7 +730,7 @@ private void InitializeComponent() // labelModInstallAs // this.labelModInstallAs.AutoSize = true; - this.labelModInstallAs.Location = new System.Drawing.Point(6, 22); + this.labelModInstallAs.Location = new System.Drawing.Point(6, 24); this.labelModInstallAs.Name = "labelModInstallAs"; this.labelModInstallAs.Size = new System.Drawing.Size(51, 13); this.labelModInstallAs.TabIndex = 41; @@ -490,7 +748,7 @@ private void InitializeComponent() // checkBoxFreezeArchive // this.checkBoxFreezeArchive.AutoSize = true; - this.checkBoxFreezeArchive.Location = new System.Drawing.Point(9, 98); + this.checkBoxFreezeArchive.Location = new System.Drawing.Point(10, 130); this.checkBoxFreezeArchive.Name = "checkBoxFreezeArchive"; this.checkBoxFreezeArchive.Size = new System.Drawing.Size(58, 17); this.checkBoxFreezeArchive.TabIndex = 9; @@ -504,7 +762,7 @@ private void InitializeComponent() // labelModInstallInto // this.labelModInstallInto.AutoSize = true; - this.labelModInstallInto.Location = new System.Drawing.Point(6, 49); + this.labelModInstallInto.Location = new System.Drawing.Point(6, 51); this.labelModInstallInto.Name = "labelModInstallInto"; this.labelModInstallInto.Size = new System.Drawing.Size(57, 13); this.labelModInstallInto.TabIndex = 38; @@ -516,19 +774,30 @@ private void InitializeComponent() | System.Windows.Forms.AnchorStyles.Right))); this.comboBoxModInstallAs.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; this.comboBoxModInstallAs.FormattingEnabled = true; - this.comboBoxModInstallAs.Location = new System.Drawing.Point(97, 19); + this.comboBoxModInstallAs.Location = new System.Drawing.Point(113, 21); this.comboBoxModInstallAs.Name = "comboBoxModInstallAs"; - this.comboBoxModInstallAs.Size = new System.Drawing.Size(238, 21); + this.comboBoxModInstallAs.Size = new System.Drawing.Size(246, 21); this.comboBoxModInstallAs.TabIndex = 3; this.comboBoxModInstallAs.SelectedIndexChanged += new System.EventHandler(this.comboBoxModInstallAs_SelectedIndexChanged); // + // buttonModDetailsSuggestArchiveName + // + this.buttonModDetailsSuggestArchiveName.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.buttonModDetailsSuggestArchiveName.Location = new System.Drawing.Point(290, 99); + this.buttonModDetailsSuggestArchiveName.Name = "buttonModDetailsSuggestArchiveName"; + this.buttonModDetailsSuggestArchiveName.Size = new System.Drawing.Size(69, 23); + this.buttonModDetailsSuggestArchiveName.TabIndex = 48; + this.buttonModDetailsSuggestArchiveName.Text = "Suggest"; + this.buttonModDetailsSuggestArchiveName.UseVisualStyleBackColor = true; + this.buttonModDetailsSuggestArchiveName.Click += new System.EventHandler(this.buttonModDetailsSuggestArchiveName_Click); + // // textBoxModRootDir // this.textBoxModRootDir.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); - this.textBoxModRootDir.Location = new System.Drawing.Point(97, 46); + this.textBoxModRootDir.Location = new System.Drawing.Point(113, 48); this.textBoxModRootDir.Name = "textBoxModRootDir"; - this.textBoxModRootDir.Size = new System.Drawing.Size(206, 20); + this.textBoxModRootDir.Size = new System.Drawing.Size(214, 20); this.textBoxModRootDir.TabIndex = 4; this.textBoxModRootDir.TextChanged += new System.EventHandler(this.textBoxModRootDir_TextChanged); // @@ -538,201 +807,205 @@ private void InitializeComponent() | System.Windows.Forms.AnchorStyles.Right))); this.comboBoxModArchivePreset.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; this.comboBoxModArchivePreset.FormattingEnabled = true; - this.comboBoxModArchivePreset.Location = new System.Drawing.Point(97, 72); + this.comboBoxModArchivePreset.Location = new System.Drawing.Point(113, 74); this.comboBoxModArchivePreset.Name = "comboBoxModArchivePreset"; - this.comboBoxModArchivePreset.Size = new System.Drawing.Size(238, 21); + this.comboBoxModArchivePreset.Size = new System.Drawing.Size(246, 21); this.comboBoxModArchivePreset.TabIndex = 6; this.comboBoxModArchivePreset.SelectedIndexChanged += new System.EventHandler(this.comboBoxModArchivePreset_SelectedIndexChanged); // - // buttonModUnfreeze + // textBoxModArchiveName + // + this.textBoxModArchiveName.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.textBoxModArchiveName.Location = new System.Drawing.Point(113, 101); + this.textBoxModArchiveName.Name = "textBoxModArchiveName"; + this.textBoxModArchiveName.Size = new System.Drawing.Size(171, 20); + this.textBoxModArchiveName.TabIndex = 7; + this.textBoxModArchiveName.TextChanged += new System.EventHandler(this.textBoxModArchiveName_TextChanged); + // + // labelModArchiveName // - this.buttonModUnfreeze.Location = new System.Drawing.Point(32, 434); - this.buttonModUnfreeze.Name = "buttonModUnfreeze"; - this.buttonModUnfreeze.Size = new System.Drawing.Size(296, 23); - this.buttonModUnfreeze.TabIndex = 64; - this.buttonModUnfreeze.TabStop = false; - this.buttonModUnfreeze.Text = "Unfreeze"; - this.buttonModUnfreeze.UseVisualStyleBackColor = true; - this.buttonModUnfreeze.Click += new System.EventHandler(this.buttonModUnfreeze_Click); + this.labelModArchiveName.AutoSize = true; + this.labelModArchiveName.Location = new System.Drawing.Point(7, 104); + this.labelModArchiveName.Name = "labelModArchiveName"; + this.labelModArchiveName.Size = new System.Drawing.Size(75, 13); + this.labelModArchiveName.TabIndex = 41; + this.labelModArchiveName.Text = "Archive name:"; // // groupBoxModDetailsDetails // + this.groupBoxModDetailsDetails.Controls.Add(this.buttonModOpenPage); + this.groupBoxModDetailsDetails.Controls.Add(this.panelModDetailsNexusMods); this.groupBoxModDetailsDetails.Controls.Add(this.textBoxModVersion); this.groupBoxModDetailsDetails.Controls.Add(this.labelModVersion); this.groupBoxModDetailsDetails.Controls.Add(this.textBoxModURL); this.groupBoxModDetailsDetails.Controls.Add(this.labelModName); - this.groupBoxModDetailsDetails.Controls.Add(this.buttonModDetailsSuggestArchiveName); - this.groupBoxModDetailsDetails.Controls.Add(this.textBoxModFolderName); - this.groupBoxModDetailsDetails.Controls.Add(this.labelModFolderName); this.groupBoxModDetailsDetails.Controls.Add(this.labelModURL); - this.groupBoxModDetailsDetails.Controls.Add(this.textBoxModArchiveName); - this.groupBoxModDetailsDetails.Controls.Add(this.labelModArchiveName); this.groupBoxModDetailsDetails.Controls.Add(this.textBoxModName); - this.groupBoxModDetailsDetails.Location = new System.Drawing.Point(8, 216); + this.groupBoxModDetailsDetails.Location = new System.Drawing.Point(6, 63); this.groupBoxModDetailsDetails.Name = "groupBoxModDetailsDetails"; - this.groupBoxModDetailsDetails.Size = new System.Drawing.Size(341, 153); + this.groupBoxModDetailsDetails.Size = new System.Drawing.Size(365, 164); this.groupBoxModDetailsDetails.TabIndex = 73; this.groupBoxModDetailsDetails.TabStop = false; this.groupBoxModDetailsDetails.Text = "Details"; // + // buttonModOpenPage + // + this.buttonModOpenPage.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.buttonModOpenPage.BackColor = System.Drawing.Color.Transparent; + this.buttonModOpenPage.Cursor = System.Windows.Forms.Cursors.Hand; + this.buttonModOpenPage.FlatAppearance.BorderSize = 0; + this.buttonModOpenPage.FlatAppearance.MouseOverBackColor = System.Drawing.Color.FromArgb(((int)(((byte)(224)))), ((int)(((byte)(224)))), ((int)(((byte)(224))))); + this.buttonModOpenPage.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.buttonModOpenPage.Image = global::Fo76ini.Properties.Resources.external_link_16; + this.buttonModOpenPage.Location = new System.Drawing.Point(331, 41); + this.buttonModOpenPage.Name = "buttonModOpenPage"; + this.buttonModOpenPage.Size = new System.Drawing.Size(28, 28); + this.buttonModOpenPage.TabIndex = 54; + this.buttonModOpenPage.UseVisualStyleBackColor = false; + this.buttonModOpenPage.Click += new System.EventHandler(this.buttonModOpenPage_Click); + // + // panelModDetailsNexusMods + // + this.panelModDetailsNexusMods.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.panelModDetailsNexusMods.Controls.Add(this.linkLabelModSetLatestVersion); + this.panelModDetailsNexusMods.Controls.Add(this.labelModAuthor); + this.panelModDetailsNexusMods.Controls.Add(this.labelModLatestVersion); + this.panelModDetailsNexusMods.Controls.Add(this.labelModLatestVersionDesc); + this.panelModDetailsNexusMods.Controls.Add(this.labelModAuthorDesc); + this.panelModDetailsNexusMods.Location = new System.Drawing.Point(1, 96); + this.panelModDetailsNexusMods.Name = "panelModDetailsNexusMods"; + this.panelModDetailsNexusMods.Size = new System.Drawing.Size(363, 57); + this.panelModDetailsNexusMods.TabIndex = 53; + // + // linkLabelModSetLatestVersion + // + this.linkLabelModSetLatestVersion.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.linkLabelModSetLatestVersion.LinkBehavior = System.Windows.Forms.LinkBehavior.HoverUnderline; + this.linkLabelModSetLatestVersion.Location = new System.Drawing.Point(220, 5); + this.linkLabelModSetLatestVersion.Name = "linkLabelModSetLatestVersion"; + this.linkLabelModSetLatestVersion.Size = new System.Drawing.Size(137, 13); + this.linkLabelModSetLatestVersion.TabIndex = 2; + this.linkLabelModSetLatestVersion.TabStop = true; + this.linkLabelModSetLatestVersion.Text = "Set latest version"; + this.linkLabelModSetLatestVersion.TextAlign = System.Drawing.ContentAlignment.TopRight; + this.linkLabelModSetLatestVersion.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.linkLabelModSetLatestVersion_LinkClicked); + // + // labelModAuthor + // + this.labelModAuthor.AutoSize = true; + this.labelModAuthor.Location = new System.Drawing.Point(138, 31); + this.labelModAuthor.Name = "labelModAuthor"; + this.labelModAuthor.Size = new System.Drawing.Size(135, 13); + this.labelModAuthor.TabIndex = 57; + this.labelModAuthor.Text = "< Author name goes here >"; + // + // labelModLatestVersion + // + this.labelModLatestVersion.AutoSize = true; + this.labelModLatestVersion.Location = new System.Drawing.Point(138, 5); + this.labelModLatestVersion.Name = "labelModLatestVersion"; + this.labelModLatestVersion.Size = new System.Drawing.Size(22, 13); + this.labelModLatestVersion.TabIndex = 56; + this.labelModLatestVersion.Text = "1.0"; + // + // labelModLatestVersionDesc + // + this.labelModLatestVersionDesc.AutoSize = true; + this.labelModLatestVersionDesc.Location = new System.Drawing.Point(6, 5); + this.labelModLatestVersionDesc.Name = "labelModLatestVersionDesc"; + this.labelModLatestVersionDesc.Size = new System.Drawing.Size(76, 13); + this.labelModLatestVersionDesc.TabIndex = 54; + this.labelModLatestVersionDesc.Text = "Latest version:"; + // + // labelModAuthorDesc + // + this.labelModAuthorDesc.AutoSize = true; + this.labelModAuthorDesc.Location = new System.Drawing.Point(6, 31); + this.labelModAuthorDesc.Name = "labelModAuthorDesc"; + this.labelModAuthorDesc.Size = new System.Drawing.Size(41, 13); + this.labelModAuthorDesc.TabIndex = 53; + this.labelModAuthorDesc.Text = "Author:"; + // // textBoxModVersion // this.textBoxModVersion.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); - this.textBoxModVersion.Location = new System.Drawing.Point(129, 74); + this.textBoxModVersion.Location = new System.Drawing.Point(142, 71); this.textBoxModVersion.Name = "textBoxModVersion"; - this.textBoxModVersion.Size = new System.Drawing.Size(206, 20); + this.textBoxModVersion.Size = new System.Drawing.Size(217, 20); this.textBoxModVersion.TabIndex = 52; this.textBoxModVersion.TextChanged += new System.EventHandler(this.textBoxModVersion_TextChanged); // // labelModVersion // this.labelModVersion.AutoSize = true; - this.labelModVersion.Location = new System.Drawing.Point(7, 77); + this.labelModVersion.Location = new System.Drawing.Point(7, 74); this.labelModVersion.Name = "labelModVersion"; - this.labelModVersion.Size = new System.Drawing.Size(45, 13); + this.labelModVersion.Size = new System.Drawing.Size(86, 13); this.labelModVersion.TabIndex = 51; - this.labelModVersion.Text = "Version:"; + this.labelModVersion.Text = "Installed version:"; // // textBoxModURL // this.textBoxModURL.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); - this.textBoxModURL.Location = new System.Drawing.Point(129, 48); + this.textBoxModURL.Location = new System.Drawing.Point(142, 45); this.textBoxModURL.Name = "textBoxModURL"; - this.textBoxModURL.Size = new System.Drawing.Size(206, 20); + this.textBoxModURL.Size = new System.Drawing.Size(186, 20); this.textBoxModURL.TabIndex = 50; this.textBoxModURL.TextChanged += new System.EventHandler(this.textBoxModURL_TextChanged); // // labelModName // this.labelModName.AutoSize = true; - this.labelModName.Location = new System.Drawing.Point(6, 25); + this.labelModName.Location = new System.Drawing.Point(6, 22); this.labelModName.Name = "labelModName"; this.labelModName.Size = new System.Drawing.Size(60, 13); this.labelModName.TabIndex = 25; this.labelModName.Text = "Mod name:"; // - // buttonModDetailsSuggestArchiveName - // - this.buttonModDetailsSuggestArchiveName.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); - this.buttonModDetailsSuggestArchiveName.Location = new System.Drawing.Point(266, 124); - this.buttonModDetailsSuggestArchiveName.Name = "buttonModDetailsSuggestArchiveName"; - this.buttonModDetailsSuggestArchiveName.Size = new System.Drawing.Size(69, 23); - this.buttonModDetailsSuggestArchiveName.TabIndex = 48; - this.buttonModDetailsSuggestArchiveName.Text = "Suggest"; - this.buttonModDetailsSuggestArchiveName.UseVisualStyleBackColor = true; - this.buttonModDetailsSuggestArchiveName.Click += new System.EventHandler(this.buttonModDetailsSuggestArchiveName_Click); - // - // textBoxModFolderName - // - this.textBoxModFolderName.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.textBoxModFolderName.Location = new System.Drawing.Point(129, 100); - this.textBoxModFolderName.Name = "textBoxModFolderName"; - this.textBoxModFolderName.Size = new System.Drawing.Size(206, 20); - this.textBoxModFolderName.TabIndex = 2; - this.textBoxModFolderName.TextChanged += new System.EventHandler(this.textBoxModFolderName_TextChanged); - // - // labelModFolderName - // - this.labelModFolderName.AutoSize = true; - this.labelModFolderName.Location = new System.Drawing.Point(7, 103); - this.labelModFolderName.Name = "labelModFolderName"; - this.labelModFolderName.Size = new System.Drawing.Size(89, 13); - this.labelModFolderName.TabIndex = 47; - this.labelModFolderName.Text = "Mod folder name:"; - // // labelModURL // this.labelModURL.AutoSize = true; - this.labelModURL.Location = new System.Drawing.Point(6, 51); + this.labelModURL.Location = new System.Drawing.Point(6, 48); this.labelModURL.Name = "labelModURL"; this.labelModURL.Size = new System.Drawing.Size(88, 13); this.labelModURL.TabIndex = 49; this.labelModURL.Text = "Webpage (URL):"; // - // textBoxModArchiveName - // - this.textBoxModArchiveName.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.textBoxModArchiveName.Location = new System.Drawing.Point(129, 126); - this.textBoxModArchiveName.Name = "textBoxModArchiveName"; - this.textBoxModArchiveName.Size = new System.Drawing.Size(131, 20); - this.textBoxModArchiveName.TabIndex = 7; - this.textBoxModArchiveName.TextChanged += new System.EventHandler(this.textBoxModArchiveName_TextChanged); - // - // labelModArchiveName - // - this.labelModArchiveName.AutoSize = true; - this.labelModArchiveName.Location = new System.Drawing.Point(7, 129); - this.labelModArchiveName.Name = "labelModArchiveName"; - this.labelModArchiveName.Size = new System.Drawing.Size(75, 13); - this.labelModArchiveName.TabIndex = 41; - this.labelModArchiveName.Text = "Archive name:"; - // // textBoxModName // this.textBoxModName.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); - this.textBoxModName.Location = new System.Drawing.Point(129, 22); + this.textBoxModName.Location = new System.Drawing.Point(142, 19); this.textBoxModName.Name = "textBoxModName"; - this.textBoxModName.Size = new System.Drawing.Size(206, 20); + this.textBoxModName.Size = new System.Drawing.Size(217, 20); this.textBoxModName.TabIndex = 1; this.textBoxModName.TextChanged += new System.EventHandler(this.textBoxModName_TextChanged); // - // labelModUnfreeze - // - this.labelModUnfreeze.ForeColor = System.Drawing.Color.Red; - this.labelModUnfreeze.Location = new System.Drawing.Point(3, 405); - this.labelModUnfreeze.Name = "labelModUnfreeze"; - this.labelModUnfreeze.Size = new System.Drawing.Size(349, 25); - this.labelModUnfreeze.TabIndex = 65; - this.labelModUnfreeze.Text = "Installation options are disabled, because the mod is frozen."; - this.labelModUnfreeze.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + // labelModSummary // - // labelModTitle - // - this.labelModTitle.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + this.labelModSummary.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); - this.labelModTitle.Font = new System.Drawing.Font("Microsoft Sans Serif", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.labelModTitle.Location = new System.Drawing.Point(-11, 163); - this.labelModTitle.Name = "labelModTitle"; - this.labelModTitle.Padding = new System.Windows.Forms.Padding(16, 2, 0, 2); - this.labelModTitle.Size = new System.Drawing.Size(370, 25); - this.labelModTitle.TabIndex = 70; - this.labelModTitle.Text = "< Mod name goes here >"; - // - // checkBoxModDetailsEnabled - // - this.checkBoxModDetailsEnabled.AutoSize = true; - this.checkBoxModDetailsEnabled.Location = new System.Drawing.Point(11, 191); - this.checkBoxModDetailsEnabled.Name = "checkBoxModDetailsEnabled"; - this.checkBoxModDetailsEnabled.Size = new System.Drawing.Size(101, 17); - this.checkBoxModDetailsEnabled.TabIndex = 61; - this.checkBoxModDetailsEnabled.Text = "Enable this mod"; - this.checkBoxModDetailsEnabled.UseVisualStyleBackColor = true; - this.checkBoxModDetailsEnabled.CheckedChanged += new System.EventHandler(this.checkBoxModDetailsEnabled_CheckedChanged); - // - // labelModDetailsBulkFrozenModsWarning - // - this.labelModDetailsBulkFrozenModsWarning.AutoSize = true; - this.labelModDetailsBulkFrozenModsWarning.ForeColor = System.Drawing.Color.Red; - this.labelModDetailsBulkFrozenModsWarning.Location = new System.Drawing.Point(11, 192); - this.labelModDetailsBulkFrozenModsWarning.Name = "labelModDetailsBulkFrozenModsWarning"; - this.labelModDetailsBulkFrozenModsWarning.Size = new System.Drawing.Size(176, 13); - this.labelModDetailsBulkFrozenModsWarning.TabIndex = 69; - this.labelModDetailsBulkFrozenModsWarning.Text = "NOTE: Frozen mods will be ignored."; + this.labelModSummary.ForeColor = System.Drawing.SystemColors.ControlDarkDark; + this.labelModSummary.Location = new System.Drawing.Point(6, 5); + this.labelModSummary.Name = "labelModSummary"; + this.labelModSummary.Size = new System.Drawing.Size(331, 55); + this.labelModSummary.TabIndex = 55; + this.labelModSummary.Text = "< Summary goes here >"; // // pictureBoxModThumbnail // this.pictureBoxModThumbnail.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); + this.pictureBoxModThumbnail.BackColor = System.Drawing.Color.Black; this.pictureBoxModThumbnail.Image = global::Fo76ini.Properties.Resources.bg; - this.pictureBoxModThumbnail.Location = new System.Drawing.Point(-1, -6); + this.pictureBoxModThumbnail.Location = new System.Drawing.Point(-2, -2); this.pictureBoxModThumbnail.Name = "pictureBoxModThumbnail"; - this.pictureBoxModThumbnail.Size = new System.Drawing.Size(356, 193); - this.pictureBoxModThumbnail.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage; + this.pictureBoxModThumbnail.Size = new System.Drawing.Size(400, 160); + this.pictureBoxModThumbnail.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom; this.pictureBoxModThumbnail.TabIndex = 71; this.pictureBoxModThumbnail.TabStop = false; // @@ -743,7 +1016,6 @@ private void InitializeComponent() this.toolStrip1.GripStyle = System.Windows.Forms.ToolStripGripStyle.Hidden; this.toolStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { this.toolStripButtonAddMod, - this.toolStripButtonAddModFrozen, this.toolStripButtonAddModFolder, this.toolStripSeparator4, this.toolStripButtonCheckAll, @@ -751,15 +1023,13 @@ private void InitializeComponent() this.toolStripButtonMoveUp, this.toolStripButtonMoveDown, this.toolStripSeparator3, - this.toolStripButtonModEdit, - this.toolStripButtonUnfreeze, this.toolStripButtonModOpenFolder, - this.toolStripSeparator5, + this.toolStripSeparator6, this.toolStripButtonDeleteMod}); this.toolStrip1.Location = new System.Drawing.Point(3, 3); this.toolStrip1.Name = "toolStrip1"; this.toolStrip1.RenderMode = System.Windows.Forms.ToolStripRenderMode.System; - this.toolStrip1.Size = new System.Drawing.Size(31, 538); + this.toolStrip1.Size = new System.Drawing.Size(31, 458); this.toolStrip1.TabIndex = 44; this.toolStrip1.Text = "toolStrip1"; // @@ -767,7 +1037,7 @@ private void InitializeComponent() // this.toolStripButtonAddMod.AutoSize = false; this.toolStripButtonAddMod.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image; - this.toolStripButtonAddMod.Image = global::Fo76ini.Properties.Resources.plus_24; + this.toolStripButtonAddMod.Image = global::Fo76ini.Properties.Resources.add_archive_3_24; this.toolStripButtonAddMod.ImageScaling = System.Windows.Forms.ToolStripItemImageScaling.None; this.toolStripButtonAddMod.ImageTransparentColor = System.Drawing.Color.Magenta; this.toolStripButtonAddMod.Name = "toolStripButtonAddMod"; @@ -775,18 +1045,6 @@ private void InitializeComponent() this.toolStripButtonAddMod.Text = "Add mod (from archive)"; this.toolStripButtonAddMod.Click += new System.EventHandler(this.toolStripButtonAddMod_Click); // - // toolStripButtonAddModFrozen - // - this.toolStripButtonAddModFrozen.AutoSize = false; - this.toolStripButtonAddModFrozen.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image; - this.toolStripButtonAddModFrozen.Image = global::Fo76ini.Properties.Resources.add_snowflake_24; - this.toolStripButtonAddModFrozen.ImageScaling = System.Windows.Forms.ToolStripItemImageScaling.None; - this.toolStripButtonAddModFrozen.ImageTransparentColor = System.Drawing.Color.Magenta; - this.toolStripButtonAddModFrozen.Name = "toolStripButtonAddModFrozen"; - this.toolStripButtonAddModFrozen.Size = new System.Drawing.Size(30, 30); - this.toolStripButtonAddModFrozen.Text = "Add mod (from *.ba2 archive)"; - this.toolStripButtonAddModFrozen.Click += new System.EventHandler(this.toolStripButtonAddModFrozen_Click); - // // toolStripButtonAddModFolder // this.toolStripButtonAddModFolder.AutoSize = false; @@ -809,7 +1067,7 @@ private void InitializeComponent() // this.toolStripButtonCheckAll.AutoSize = false; this.toolStripButtonCheckAll.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image; - this.toolStripButtonCheckAll.Image = global::Fo76ini.Properties.Resources.checked_checkbox_24; + this.toolStripButtonCheckAll.Image = global::Fo76ini.Properties.Resources.checkbox_24; this.toolStripButtonCheckAll.ImageScaling = System.Windows.Forms.ToolStripItemImageScaling.None; this.toolStripButtonCheckAll.ImageTransparentColor = System.Drawing.Color.Magenta; this.toolStripButtonCheckAll.Name = "toolStripButtonCheckAll"; @@ -853,30 +1111,6 @@ private void InitializeComponent() this.toolStripSeparator3.Name = "toolStripSeparator3"; this.toolStripSeparator3.Size = new System.Drawing.Size(28, 6); // - // toolStripButtonModEdit - // - this.toolStripButtonModEdit.AutoSize = false; - this.toolStripButtonModEdit.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image; - this.toolStripButtonModEdit.Image = global::Fo76ini.Properties.Resources.edit_24; - this.toolStripButtonModEdit.ImageScaling = System.Windows.Forms.ToolStripItemImageScaling.None; - this.toolStripButtonModEdit.ImageTransparentColor = System.Drawing.Color.Magenta; - this.toolStripButtonModEdit.Name = "toolStripButtonModEdit"; - this.toolStripButtonModEdit.Size = new System.Drawing.Size(30, 30); - this.toolStripButtonModEdit.Text = "Edit mod details"; - this.toolStripButtonModEdit.Click += new System.EventHandler(this.toolStripButtonModEdit_Click); - // - // toolStripButtonUnfreeze - // - this.toolStripButtonUnfreeze.AutoSize = false; - this.toolStripButtonUnfreeze.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image; - this.toolStripButtonUnfreeze.Image = global::Fo76ini.Properties.Resources.thaw_24; - this.toolStripButtonUnfreeze.ImageScaling = System.Windows.Forms.ToolStripItemImageScaling.None; - this.toolStripButtonUnfreeze.ImageTransparentColor = System.Drawing.Color.Magenta; - this.toolStripButtonUnfreeze.Name = "toolStripButtonUnfreeze"; - this.toolStripButtonUnfreeze.Size = new System.Drawing.Size(30, 30); - this.toolStripButtonUnfreeze.Text = "Unfreeze"; - this.toolStripButtonUnfreeze.Click += new System.EventHandler(this.toolStripButtonUnfreeze_Click); - // // toolStripButtonModOpenFolder // this.toolStripButtonModOpenFolder.AutoSize = false; @@ -889,11 +1123,11 @@ private void InitializeComponent() this.toolStripButtonModOpenFolder.Text = "Open mod folder"; this.toolStripButtonModOpenFolder.Click += new System.EventHandler(this.toolStripButtonModOpenFolder_Click); // - // toolStripSeparator5 + // toolStripSeparator6 // - this.toolStripSeparator5.Margin = new System.Windows.Forms.Padding(0, 8, 0, 8); - this.toolStripSeparator5.Name = "toolStripSeparator5"; - this.toolStripSeparator5.Size = new System.Drawing.Size(28, 6); + this.toolStripSeparator6.Margin = new System.Windows.Forms.Padding(0, 8, 0, 8); + this.toolStripSeparator6.Name = "toolStripSeparator6"; + this.toolStripSeparator6.Size = new System.Drawing.Size(28, 6); // // toolStripButtonDeleteMod // @@ -930,7 +1164,7 @@ private void InitializeComponent() this.listViewMods.LabelWrap = false; this.listViewMods.Location = new System.Drawing.Point(39, 0); this.listViewMods.Name = "listViewMods"; - this.listViewMods.Size = new System.Drawing.Size(441, 544); + this.listViewMods.Size = new System.Drawing.Size(300, 464); this.listViewMods.TabIndex = 41; this.listViewMods.TabStop = false; this.listViewMods.UseCompatibleStateImageBehavior = false; @@ -976,57 +1210,6 @@ private void InitializeComponent() this.columnHeaderFrozenState.Text = "Frozen?"; this.columnHeaderFrozenState.Width = 50; // - // panel2 - // - this.panel2.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.panel2.BackColor = System.Drawing.SystemColors.Control; - this.panel2.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; - this.panel2.Controls.Add(this.buttonModDetailsApply); - this.panel2.Controls.Add(this.buttonModDetailsCancel); - this.panel2.Controls.Add(this.buttonModDetailsOK); - this.panel2.Location = new System.Drawing.Point(496, 497); - this.panel2.Name = "panel2"; - this.panel2.Size = new System.Drawing.Size(356, 47); - this.panel2.TabIndex = 75; - // - // buttonModDetailsApply - // - this.buttonModDetailsApply.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); - this.buttonModDetailsApply.Location = new System.Drawing.Point(274, 13); - this.buttonModDetailsApply.Name = "buttonModDetailsApply"; - this.buttonModDetailsApply.Size = new System.Drawing.Size(75, 23); - this.buttonModDetailsApply.TabIndex = 74; - this.buttonModDetailsApply.TabStop = false; - this.buttonModDetailsApply.Text = "Apply"; - this.buttonModDetailsApply.UseVisualStyleBackColor = true; - this.buttonModDetailsApply.Click += new System.EventHandler(this.buttonModDetailsApply_Click); - // - // buttonModDetailsCancel - // - this.buttonModDetailsCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); - this.buttonModDetailsCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; - this.buttonModDetailsCancel.Location = new System.Drawing.Point(193, 13); - this.buttonModDetailsCancel.Name = "buttonModDetailsCancel"; - this.buttonModDetailsCancel.Size = new System.Drawing.Size(75, 23); - this.buttonModDetailsCancel.TabIndex = 73; - this.buttonModDetailsCancel.TabStop = false; - this.buttonModDetailsCancel.Text = "Cancel"; - this.buttonModDetailsCancel.UseVisualStyleBackColor = true; - this.buttonModDetailsCancel.Click += new System.EventHandler(this.buttonModDetailsCancel_Click); - // - // buttonModDetailsOK - // - this.buttonModDetailsOK.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); - this.buttonModDetailsOK.Location = new System.Drawing.Point(112, 13); - this.buttonModDetailsOK.Name = "buttonModDetailsOK"; - this.buttonModDetailsOK.Size = new System.Drawing.Size(75, 23); - this.buttonModDetailsOK.TabIndex = 72; - this.buttonModDetailsOK.TabStop = false; - this.buttonModDetailsOK.Text = "OK"; - this.buttonModDetailsOK.UseVisualStyleBackColor = true; - this.buttonModDetailsOK.Click += new System.EventHandler(this.buttonModDetailsOK_Click); - // // tabPageModsSettings // this.tabPageModsSettings.Controls.Add(this.groupBoxModsBehavior); @@ -1034,7 +1217,7 @@ private void InitializeComponent() this.tabPageModsSettings.Location = new System.Drawing.Point(4, 22); this.tabPageModsSettings.Name = "tabPageModsSettings"; this.tabPageModsSettings.Padding = new System.Windows.Forms.Padding(3); - this.tabPageModsSettings.Size = new System.Drawing.Size(852, 544); + this.tabPageModsSettings.Size = new System.Drawing.Size(752, 464); this.tabPageModsSettings.TabIndex = 1; this.tabPageModsSettings.Text = "Settings"; this.tabPageModsSettings.UseVisualStyleBackColor = true; @@ -1043,28 +1226,16 @@ private void InitializeComponent() // this.groupBoxModsBehavior.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); - this.groupBoxModsBehavior.Controls.Add(this.checkBoxModsWriteSResourceDataDirsFinal); this.groupBoxModsBehavior.Controls.Add(this.checkBoxFreezeBundledArchives); this.groupBoxModsBehavior.Controls.Add(this.checkBoxModsUseHardlinks); this.groupBoxModsBehavior.Controls.Add(this.checkBoxAddArchivesAsBundled); this.groupBoxModsBehavior.Location = new System.Drawing.Point(6, 6); this.groupBoxModsBehavior.Name = "groupBoxModsBehavior"; - this.groupBoxModsBehavior.Size = new System.Drawing.Size(840, 123); + this.groupBoxModsBehavior.Size = new System.Drawing.Size(740, 95); this.groupBoxModsBehavior.TabIndex = 60; this.groupBoxModsBehavior.TabStop = false; this.groupBoxModsBehavior.Text = "Behavior"; // - // checkBoxModsWriteSResourceDataDirsFinal - // - this.checkBoxModsWriteSResourceDataDirsFinal.AutoSize = true; - this.checkBoxModsWriteSResourceDataDirsFinal.Location = new System.Drawing.Point(6, 100); - this.checkBoxModsWriteSResourceDataDirsFinal.Name = "checkBoxModsWriteSResourceDataDirsFinal"; - this.checkBoxModsWriteSResourceDataDirsFinal.Size = new System.Drawing.Size(274, 17); - this.checkBoxModsWriteSResourceDataDirsFinal.TabIndex = 3; - this.checkBoxModsWriteSResourceDataDirsFinal.Text = "Write sResourceDataDirsFinal to Fallout76Custom.ini"; - this.checkBoxModsWriteSResourceDataDirsFinal.UseVisualStyleBackColor = true; - this.checkBoxModsWriteSResourceDataDirsFinal.CheckedChanged += new System.EventHandler(this.checkBoxModsWriteSResourceDataDirsFinal_CheckedChanged); - // // checkBoxFreezeBundledArchives // this.checkBoxFreezeBundledArchives.AutoSize = true; @@ -1093,7 +1264,7 @@ private void InitializeComponent() // checkBoxAddArchivesAsBundled // this.checkBoxAddArchivesAsBundled.AutoSize = true; - this.checkBoxAddArchivesAsBundled.Location = new System.Drawing.Point(6, 77); + this.checkBoxAddArchivesAsBundled.Location = new System.Drawing.Point(6, 65); this.checkBoxAddArchivesAsBundled.Name = "checkBoxAddArchivesAsBundled"; this.checkBoxAddArchivesAsBundled.Size = new System.Drawing.Size(167, 17); this.checkBoxAddArchivesAsBundled.TabIndex = 0; @@ -1106,101 +1277,129 @@ private void InitializeComponent() this.groupBoxLists.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); - this.groupBoxLists.Controls.Add(this.buttonModsResetTextboxes); - this.groupBoxLists.Controls.Add(this.buttonModsApplyTextBoxes); - this.groupBoxLists.Controls.Add(this.textBoxsResourceIndexFileList); - this.groupBoxLists.Controls.Add(this.buttonModsCleanLists); + this.groupBoxLists.Controls.Add(this.buttonModsResetTextbox); + this.groupBoxLists.Controls.Add(this.buttonModsApplyTextBox); + this.groupBoxLists.Controls.Add(this.textBoxResourceList); + this.groupBoxLists.Controls.Add(this.buttonModsCleanList); this.groupBoxLists.Controls.Add(this.labelsResourceIndexFileList); - this.groupBoxLists.Controls.Add(this.textBoxsResourceArchive2List); - this.groupBoxLists.Controls.Add(this.labelsResourceArchive2List); - this.groupBoxLists.Location = new System.Drawing.Point(6, 135); + this.groupBoxLists.Location = new System.Drawing.Point(6, 107); this.groupBoxLists.Name = "groupBoxLists"; - this.groupBoxLists.Size = new System.Drawing.Size(840, 403); + this.groupBoxLists.Size = new System.Drawing.Size(740, 351); this.groupBoxLists.TabIndex = 59; this.groupBoxLists.TabStop = false; this.groupBoxLists.Text = "Lists"; // - // buttonModsResetTextboxes + // buttonModsResetTextbox // - this.buttonModsResetTextboxes.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); - this.buttonModsResetTextboxes.Location = new System.Drawing.Point(603, 374); - this.buttonModsResetTextboxes.Name = "buttonModsResetTextboxes"; - this.buttonModsResetTextboxes.Size = new System.Drawing.Size(98, 23); - this.buttonModsResetTextboxes.TabIndex = 60; - this.buttonModsResetTextboxes.Text = "Reset"; - this.buttonModsResetTextboxes.UseVisualStyleBackColor = true; - this.buttonModsResetTextboxes.Click += new System.EventHandler(this.buttonModsResetTextboxes_Click); + this.buttonModsResetTextbox.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.buttonModsResetTextbox.Location = new System.Drawing.Point(503, 322); + this.buttonModsResetTextbox.Name = "buttonModsResetTextbox"; + this.buttonModsResetTextbox.Size = new System.Drawing.Size(98, 23); + this.buttonModsResetTextbox.TabIndex = 60; + this.buttonModsResetTextbox.Text = "Reset"; + this.buttonModsResetTextbox.UseVisualStyleBackColor = true; + this.buttonModsResetTextbox.Click += new System.EventHandler(this.buttonModsResetTextbox_Click); // - // buttonModsApplyTextBoxes + // buttonModsApplyTextBox // - this.buttonModsApplyTextBoxes.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); - this.buttonModsApplyTextBoxes.Location = new System.Drawing.Point(707, 374); - this.buttonModsApplyTextBoxes.Name = "buttonModsApplyTextBoxes"; - this.buttonModsApplyTextBoxes.Size = new System.Drawing.Size(127, 23); - this.buttonModsApplyTextBoxes.TabIndex = 59; - this.buttonModsApplyTextBoxes.Text = "Apply changes"; - this.buttonModsApplyTextBoxes.UseVisualStyleBackColor = true; - this.buttonModsApplyTextBoxes.Click += new System.EventHandler(this.buttonModsApplyTextBoxes_Click); + this.buttonModsApplyTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.buttonModsApplyTextBox.Location = new System.Drawing.Point(607, 322); + this.buttonModsApplyTextBox.Name = "buttonModsApplyTextBox"; + this.buttonModsApplyTextBox.Size = new System.Drawing.Size(127, 23); + this.buttonModsApplyTextBox.TabIndex = 59; + this.buttonModsApplyTextBox.Text = "Apply changes"; + this.buttonModsApplyTextBox.UseVisualStyleBackColor = true; + this.buttonModsApplyTextBox.Click += new System.EventHandler(this.buttonModsApplyTextBox_Click); // - // textBoxsResourceIndexFileList + // textBoxResourceList // - this.textBoxsResourceIndexFileList.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + this.textBoxResourceList.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); - this.textBoxsResourceIndexFileList.Location = new System.Drawing.Point(210, 37); - this.textBoxsResourceIndexFileList.Multiline = true; - this.textBoxsResourceIndexFileList.Name = "textBoxsResourceIndexFileList"; - this.textBoxsResourceIndexFileList.Size = new System.Drawing.Size(624, 331); - this.textBoxsResourceIndexFileList.TabIndex = 54; - // - // buttonModsCleanLists - // - this.buttonModsCleanLists.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); - this.buttonModsCleanLists.Location = new System.Drawing.Point(6, 374); - this.buttonModsCleanLists.Name = "buttonModsCleanLists"; - this.buttonModsCleanLists.Size = new System.Drawing.Size(98, 23); - this.buttonModsCleanLists.TabIndex = 58; - this.buttonModsCleanLists.Text = "Clean lists"; - this.buttonModsCleanLists.UseVisualStyleBackColor = true; - this.buttonModsCleanLists.Click += new System.EventHandler(this.buttonModsCleanLists_Click); + this.textBoxResourceList.Location = new System.Drawing.Point(6, 37); + this.textBoxResourceList.Multiline = true; + this.textBoxResourceList.Name = "textBoxResourceList"; + this.textBoxResourceList.Size = new System.Drawing.Size(728, 279); + this.textBoxResourceList.TabIndex = 54; + // + // buttonModsCleanList + // + this.buttonModsCleanList.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.buttonModsCleanList.Location = new System.Drawing.Point(6, 322); + this.buttonModsCleanList.Name = "buttonModsCleanList"; + this.buttonModsCleanList.Size = new System.Drawing.Size(98, 23); + this.buttonModsCleanList.TabIndex = 58; + this.buttonModsCleanList.Text = "Clean list"; + this.buttonModsCleanList.UseVisualStyleBackColor = true; + this.buttonModsCleanList.Click += new System.EventHandler(this.buttonModsCleanList_Click); // // labelsResourceIndexFileList // this.labelsResourceIndexFileList.AutoSize = true; - this.labelsResourceIndexFileList.Location = new System.Drawing.Point(210, 21); + this.labelsResourceIndexFileList.Location = new System.Drawing.Point(3, 21); this.labelsResourceIndexFileList.Name = "labelsResourceIndexFileList"; - this.labelsResourceIndexFileList.Size = new System.Drawing.Size(231, 13); + this.labelsResourceIndexFileList.Size = new System.Drawing.Size(71, 13); this.labelsResourceIndexFileList.TabIndex = 55; - this.labelsResourceIndexFileList.Text = "sResourceIndexFileList (Used by mod manager)"; + this.labelsResourceIndexFileList.Text = "Resource list:"; // - // textBoxsResourceArchive2List + // tabPageNexusMods // - this.textBoxsResourceArchive2List.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) - | System.Windows.Forms.AnchorStyles.Left))); - this.textBoxsResourceArchive2List.Location = new System.Drawing.Point(6, 37); - this.textBoxsResourceArchive2List.Multiline = true; - this.textBoxsResourceArchive2List.Name = "textBoxsResourceArchive2List"; - this.textBoxsResourceArchive2List.Size = new System.Drawing.Size(198, 331); - this.textBoxsResourceArchive2List.TabIndex = 57; + this.tabPageNexusMods.Controls.Add(this.labelNexusModsMovedNotice2); + this.tabPageNexusMods.Controls.Add(this.labelNexusModsMovedNotice); + this.tabPageNexusMods.Controls.Add(this.pictureBox1); + this.tabPageNexusMods.Location = new System.Drawing.Point(4, 22); + this.tabPageNexusMods.Name = "tabPageNexusMods"; + this.tabPageNexusMods.Padding = new System.Windows.Forms.Padding(3); + this.tabPageNexusMods.Size = new System.Drawing.Size(752, 464); + this.tabPageNexusMods.TabIndex = 2; + this.tabPageNexusMods.Text = "NexusMods"; + this.tabPageNexusMods.UseVisualStyleBackColor = true; // - // labelsResourceArchive2List + // labelNexusModsMovedNotice2 // - this.labelsResourceArchive2List.AutoSize = true; - this.labelsResourceArchive2List.Location = new System.Drawing.Point(6, 21); - this.labelsResourceArchive2List.Name = "labelsResourceArchive2List"; - this.labelsResourceArchive2List.Size = new System.Drawing.Size(116, 13); - this.labelsResourceArchive2List.TabIndex = 56; - this.labelsResourceArchive2List.Text = "sResourceArchive2List"; + this.labelNexusModsMovedNotice2.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.labelNexusModsMovedNotice2.Location = new System.Drawing.Point(6, 346); + this.labelNexusModsMovedNotice2.Name = "labelNexusModsMovedNotice2"; + this.labelNexusModsMovedNotice2.Size = new System.Drawing.Size(740, 23); + this.labelNexusModsMovedNotice2.TabIndex = 93; + this.labelNexusModsMovedNotice2.Text = "Other options such as \"Update mod information\" can be found in the menu under Too" + + "ls → NexusMods API."; + this.labelNexusModsMovedNotice2.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + // + // labelNexusModsMovedNotice + // + this.labelNexusModsMovedNotice.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.labelNexusModsMovedNotice.Font = new System.Drawing.Font("Microsoft Sans Serif", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.labelNexusModsMovedNotice.Location = new System.Drawing.Point(5, 91); + this.labelNexusModsMovedNotice.Name = "labelNexusModsMovedNotice"; + this.labelNexusModsMovedNotice.Size = new System.Drawing.Size(741, 102); + this.labelNexusModsMovedNotice.TabIndex = 91; + this.labelNexusModsMovedNotice.Text = "The NexusMods tab has been moved into the settings window."; + this.labelNexusModsMovedNotice.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + // + // pictureBox1 + // + this.pictureBox1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.pictureBox1.Image = global::Fo76ini.Properties.Resources.Fo76ini_LDu4jzf2p3; + this.pictureBox1.Location = new System.Drawing.Point(8, 196); + this.pictureBox1.Name = "pictureBox1"; + this.pictureBox1.Size = new System.Drawing.Size(737, 147); + this.pictureBox1.SizeMode = System.Windows.Forms.PictureBoxSizeMode.CenterImage; + this.pictureBox1.TabIndex = 92; + this.pictureBox1.TabStop = false; // // openFileDialogMod // - this.openFileDialogMod.Filter = "All Archives|*.zip;*.rar;*.7z;*.tar;*.tar.gz;*.gz;*.xz;*.lz;*.bz2|Archive2|*.ba2"; + this.openFileDialogMod.Filter = "All Archives|*.zip;*.rar;*.7z;*.tar;*.ba2"; this.openFileDialogMod.Title = "Add *.ba2 or any other archive."; // // checkBoxDisableMods // this.checkBoxDisableMods.AutoSize = true; - this.checkBoxDisableMods.Location = new System.Drawing.Point(3, 3); + this.checkBoxDisableMods.Location = new System.Drawing.Point(4, 3); this.checkBoxDisableMods.Name = "checkBoxDisableMods"; this.checkBoxDisableMods.Size = new System.Drawing.Size(89, 17); this.checkBoxDisableMods.TabIndex = 55; @@ -1217,9 +1416,9 @@ private void InitializeComponent() this.panel1.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); this.panel1.Controls.Add(this.buttonModsDeploy); this.panel1.Controls.Add(this.checkBoxDisableMods); - this.panel1.Location = new System.Drawing.Point(718, 604); + this.panel1.Location = new System.Drawing.Point(618, 521); this.panel1.Name = "panel1"; - this.panel1.Size = new System.Drawing.Size(166, 58); + this.panel1.Size = new System.Drawing.Size(166, 51); this.panel1.TabIndex = 56; // // openFileDialogBA2 @@ -1228,18 +1427,85 @@ private void InitializeComponent() this.openFileDialogBA2.Filter = "Archive2|*.ba2"; this.openFileDialogBA2.Title = "Add *.ba2 archive."; // - // backgroundWorkerRetrieveModInfo + // statusStrip1 + // + this.statusStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.toolStripStatusLabelDescModCount, + this.toolStripStatusLabelModCount, + this.toolStripStatusLabelDescEnabledCount, + this.toolStripStatusLabelEnabledCount, + this.toolStripStatusLabelSpacer, + this.toolStripStatusLabelDeploymentStatus}); + this.statusStrip1.Location = new System.Drawing.Point(0, 579); + this.statusStrip1.Name = "statusStrip1"; + this.statusStrip1.Size = new System.Drawing.Size(784, 22); + this.statusStrip1.TabIndex = 57; + this.statusStrip1.Text = "statusStrip1"; + // + // toolStripStatusLabelDescModCount + // + this.toolStripStatusLabelDescModCount.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.toolStripStatusLabelDescModCount.Margin = new System.Windows.Forms.Padding(8, 3, 3, 2); + this.toolStripStatusLabelDescModCount.Name = "toolStripStatusLabelDescModCount"; + this.toolStripStatusLabelDescModCount.Size = new System.Drawing.Size(70, 17); + this.toolStripStatusLabelDescModCount.Text = "Mod count:"; + // + // toolStripStatusLabelModCount // - this.backgroundWorkerRetrieveModInfo.WorkerReportsProgress = true; + this.toolStripStatusLabelModCount.Name = "toolStripStatusLabelModCount"; + this.toolStripStatusLabelModCount.Size = new System.Drawing.Size(13, 17); + this.toolStripStatusLabelModCount.Text = "0"; // - // backgroundWorkerRetrieveProfileInfo + // toolStripStatusLabelDescEnabledCount // + this.toolStripStatusLabelDescEnabledCount.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.toolStripStatusLabelDescEnabledCount.Margin = new System.Windows.Forms.Padding(50, 3, 3, 2); + this.toolStripStatusLabelDescEnabledCount.Name = "toolStripStatusLabelDescEnabledCount"; + this.toolStripStatusLabelDescEnabledCount.Size = new System.Drawing.Size(53, 17); + this.toolStripStatusLabelDescEnabledCount.Text = "Enabled:"; + // + // toolStripStatusLabelEnabledCount + // + this.toolStripStatusLabelEnabledCount.Name = "toolStripStatusLabelEnabledCount"; + this.toolStripStatusLabelEnabledCount.Size = new System.Drawing.Size(13, 17); + this.toolStripStatusLabelEnabledCount.Text = "0"; + // + // toolStripStatusLabelSpacer + // + this.toolStripStatusLabelSpacer.Name = "toolStripStatusLabelSpacer"; + this.toolStripStatusLabelSpacer.Size = new System.Drawing.Size(423, 17); + this.toolStripStatusLabelSpacer.Spring = true; + this.toolStripStatusLabelSpacer.Text = " "; + // + // toolStripStatusLabelDeploymentStatus + // + this.toolStripStatusLabelDeploymentStatus.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.toolStripStatusLabelDeploymentStatus.ForeColor = System.Drawing.Color.Crimson; + this.toolStripStatusLabelDeploymentStatus.Name = "toolStripStatusLabelDeploymentStatus"; + this.toolStripStatusLabelDeploymentStatus.Size = new System.Drawing.Size(133, 17); + this.toolStripStatusLabelDeploymentStatus.Text = "Deployment necessary"; + // + // pictureBoxModsLoadingGIF + // + this.pictureBoxModsLoadingGIF.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left))); + this.pictureBoxModsLoadingGIF.BackColor = System.Drawing.Color.White; + this.pictureBoxModsLoadingGIF.Image = global::Fo76ini.Properties.Resources.Spinner_200; + this.pictureBoxModsLoadingGIF.Location = new System.Drawing.Point(0, 27); + this.pictureBoxModsLoadingGIF.Name = "pictureBoxModsLoadingGIF"; + this.pictureBoxModsLoadingGIF.Size = new System.Drawing.Size(16, 490); + this.pictureBoxModsLoadingGIF.SizeMode = System.Windows.Forms.PictureBoxSizeMode.CenterImage; + this.pictureBoxModsLoadingGIF.TabIndex = 57; + this.pictureBoxModsLoadingGIF.TabStop = false; + this.pictureBoxModsLoadingGIF.Visible = false; // // FormMods // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(884, 661); + this.ClientSize = new System.Drawing.Size(784, 601); + this.Controls.Add(this.pictureBoxModsLoadingGIF); + this.Controls.Add(this.statusStrip1); this.Controls.Add(this.panel1); this.Controls.Add(this.tabControl1); this.Controls.Add(this.progressBarMods); @@ -1247,8 +1513,9 @@ private void InitializeComponent() this.Controls.Add(this.menuStrip1); this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); this.KeyPreview = true; - this.MinimumSize = new System.Drawing.Size(900, 700); + this.MinimumSize = new System.Drawing.Size(800, 640); this.Name = "FormMods"; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; this.Text = "Manage mods"; this.Load += new System.EventHandler(this.FormMods_Load); this.menuStrip1.ResumeLayout(false); @@ -1256,25 +1523,34 @@ private void InitializeComponent() this.tabControl1.ResumeLayout(false); this.tabPageModOrder.ResumeLayout(false); this.tabPageModOrder.PerformLayout(); - ((System.ComponentModel.ISupportInitialize)(this.pictureBoxModsLoadingGIF)).EndInit(); ((System.ComponentModel.ISupportInitialize)(this.pictureBoxCollapseDetails)).EndInit(); this.panelModDetails.ResumeLayout(false); - this.panelModDetails.PerformLayout(); + this.panelModDetailsHeader.ResumeLayout(false); + this.panelModDetailsHeader.PerformLayout(); + this.panelModDetailsInner.ResumeLayout(false); + this.groupBoxModReplace.ResumeLayout(false); + this.groupBoxModReplace.PerformLayout(); this.groupBoxModDetailsInstallationOptions.ResumeLayout(false); this.groupBoxModDetailsInstallationOptions.PerformLayout(); this.groupBoxModDetailsDetails.ResumeLayout(false); this.groupBoxModDetailsDetails.PerformLayout(); + this.panelModDetailsNexusMods.ResumeLayout(false); + this.panelModDetailsNexusMods.PerformLayout(); ((System.ComponentModel.ISupportInitialize)(this.pictureBoxModThumbnail)).EndInit(); this.toolStrip1.ResumeLayout(false); this.toolStrip1.PerformLayout(); - this.panel2.ResumeLayout(false); this.tabPageModsSettings.ResumeLayout(false); this.groupBoxModsBehavior.ResumeLayout(false); this.groupBoxModsBehavior.PerformLayout(); this.groupBoxLists.ResumeLayout(false); this.groupBoxLists.PerformLayout(); + this.tabPageNexusMods.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit(); this.panel1.ResumeLayout(false); this.panel1.PerformLayout(); + this.statusStrip1.ResumeLayout(false); + this.statusStrip1.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBoxModsLoadingGIF)).EndInit(); this.ResumeLayout(false); this.PerformLayout(); @@ -1304,7 +1580,6 @@ private void InitializeComponent() public System.Windows.Forms.ToolStrip toolStrip1; private System.Windows.Forms.ToolStripButton toolStripButtonMoveUp; private System.Windows.Forms.ToolStripButton toolStripButtonMoveDown; - private System.Windows.Forms.ToolStripButton toolStripButtonModEdit; private System.Windows.Forms.ToolStripButton toolStripButtonModOpenFolder; private System.Windows.Forms.ToolStripButton toolStripButtonAddModFolder; private System.Windows.Forms.ToolStripSeparator toolStripSeparator3; @@ -1315,7 +1590,6 @@ private void InitializeComponent() private System.Windows.Forms.ToolStripSeparator toolStripSeparator4; private System.Windows.Forms.ToolStripButton toolStripButtonAddMod; private System.Windows.Forms.ToolStripButton toolStripButtonCheckAll; - private System.Windows.Forms.ToolStripSeparator toolStripSeparator5; private System.Windows.Forms.ToolStripButton toolStripButtonDeleteMod; private System.Windows.Forms.OpenFileDialog openFileDialogMod; private System.Windows.Forms.FolderBrowserDialog folderBrowserDialogMod; @@ -1329,18 +1603,14 @@ private void InitializeComponent() private System.Windows.Forms.ToolStripMenuItem reloadUIToolStripMenuItem; private System.Windows.Forms.ColumnHeader columnHeaderFrozenState; private System.Windows.Forms.ColumnHeader columnHeaderCompression; - private System.Windows.Forms.ToolStripButton toolStripButtonAddModFrozen; private System.Windows.Forms.OpenFileDialog openFileDialogBA2; private System.Windows.Forms.ToolStripMenuItem fromba2ArchivefrozenToolStripMenuItem; private System.Windows.Forms.GroupBox groupBoxLists; - private System.Windows.Forms.TextBox textBoxsResourceIndexFileList; - private System.Windows.Forms.Button buttonModsCleanLists; + private System.Windows.Forms.TextBox textBoxResourceList; + private System.Windows.Forms.Button buttonModsCleanList; private System.Windows.Forms.Label labelsResourceIndexFileList; - private System.Windows.Forms.TextBox textBoxsResourceArchive2List; - private System.Windows.Forms.Label labelsResourceArchive2List; - private System.Windows.Forms.Button buttonModsResetTextboxes; - private System.Windows.Forms.Button buttonModsApplyTextBoxes; - private System.Windows.Forms.ToolStripButton toolStripButtonUnfreeze; + private System.Windows.Forms.Button buttonModsResetTextbox; + private System.Windows.Forms.Button buttonModsApplyTextBox; private System.Windows.Forms.GroupBox groupBoxModsBehavior; private System.Windows.Forms.CheckBox checkBoxAddArchivesAsBundled; private System.Windows.Forms.CheckBox checkBoxModsUseHardlinks; @@ -1351,10 +1621,8 @@ private void InitializeComponent() private System.Windows.Forms.ToolStripMenuItem showModmanagerlogtxtToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem showArchive2logtxtToolStripMenuItem; private System.Windows.Forms.CheckBox checkBoxFreezeBundledArchives; - private System.Windows.Forms.ToolStripMenuItem showREADMEToolStripMenuItem; private System.Windows.Forms.PictureBox pictureBoxModsLoadingGIF; private System.Windows.Forms.Panel panelModDetails; - private System.Windows.Forms.CheckBox checkBoxModDetailsEnabled; private System.Windows.Forms.Label labelModInstallAs; private System.Windows.Forms.Label labelModInstallInto; private System.Windows.Forms.TextBox textBoxModRootDir; @@ -1363,33 +1631,62 @@ private void InitializeComponent() private System.Windows.Forms.Label labelModArchivePreset; private System.Windows.Forms.Button buttonModPickRootDir; private System.Windows.Forms.ComboBox comboBoxModArchivePreset; - private System.Windows.Forms.Label labelModUnfreeze; private System.Windows.Forms.TextBox textBoxModName; private System.Windows.Forms.Label labelModName; - private System.Windows.Forms.TextBox textBoxModFolderName; - private System.Windows.Forms.Label labelModFolderName; private System.Windows.Forms.TextBox textBoxModArchiveName; private System.Windows.Forms.Label labelModArchiveName; - private System.Windows.Forms.Button buttonModUnfreeze; - private System.Windows.Forms.Label labelModDetailsBulkFrozenModsWarning; - private System.Windows.Forms.Label labelModTitle; private System.Windows.Forms.PictureBox pictureBoxCollapseDetails; private System.Windows.Forms.FolderBrowserDialog folderBrowserDialogPickRootDir; - private System.Windows.Forms.Button buttonModDetailsCancel; - private System.Windows.Forms.Button buttonModDetailsOK; - private System.Windows.Forms.Button buttonModDetailsApply; private System.Windows.Forms.Button buttonModDetailsSuggestArchiveName; - private System.Windows.Forms.Panel panel2; private System.Windows.Forms.TextBox textBoxModURL; private System.Windows.Forms.Label labelModURL; private System.Windows.Forms.PictureBox pictureBoxModThumbnail; + private System.Windows.Forms.TabPage tabPageNexusMods; private System.Windows.Forms.GroupBox groupBoxModDetailsInstallationOptions; private System.Windows.Forms.GroupBox groupBoxModDetailsDetails; private System.Windows.Forms.TextBox textBoxModVersion; private System.Windows.Forms.Label labelModVersion; private System.Windows.Forms.ColumnHeader columnHeaderVersion; - private System.ComponentModel.BackgroundWorker backgroundWorkerRetrieveModInfo; - private System.ComponentModel.BackgroundWorker backgroundWorkerRetrieveProfileInfo; - private System.Windows.Forms.CheckBox checkBoxModsWriteSResourceDataDirsFinal; + private System.Windows.Forms.ToolStripSeparator toolStripSeparator6; + private System.Windows.Forms.ToolStripMenuItem saveToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem nexusModsAPIToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem updateModInformationToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem endorseModsToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem checkForUpdatesToolStripMenuItem; + private System.Windows.Forms.Label labelNexusModsMovedNotice; + private System.Windows.Forms.PictureBox pictureBox1; + private System.Windows.Forms.Label labelNexusModsMovedNotice2; + private System.Windows.Forms.StatusStrip statusStrip1; + private System.Windows.Forms.ToolStripStatusLabel toolStripStatusLabelDescModCount; + private System.Windows.Forms.ToolStripStatusLabel toolStripStatusLabelModCount; + private System.Windows.Forms.ToolStripStatusLabel toolStripStatusLabelSpacer; + private System.Windows.Forms.ToolStripStatusLabel toolStripStatusLabelDeploymentStatus; + private System.Windows.Forms.ToolStripStatusLabel toolStripStatusLabelDescEnabledCount; + private System.Windows.Forms.ToolStripStatusLabel toolStripStatusLabelEnabledCount; + private System.Windows.Forms.Panel panelModDetailsNexusMods; + private System.Windows.Forms.Label labelModSummary; + private System.Windows.Forms.Label labelModLatestVersionDesc; + private System.Windows.Forms.Label labelModAuthorDesc; + private System.Windows.Forms.Label labelModLatestVersion; + private System.Windows.Forms.Label labelModAuthor; + private System.Windows.Forms.Panel panelModDetailsInner; + private System.Windows.Forms.Label labelModInstallWarning; + private System.Windows.Forms.GroupBox groupBoxModReplace; + private System.Windows.Forms.LinkLabel linkLabelModReplaceFilesWithFolder; + private System.Windows.Forms.LinkLabel linkLabelModReplaceFilesWithArchive; + private System.Windows.Forms.Label labelModDetailsReplace; + private System.Windows.Forms.LinkLabel linkLabelModDeleteFolderContents; + private System.Windows.Forms.LinkLabel linkLabelModSetLatestVersion; + private System.Windows.Forms.Panel panelModDetailsReplaceDragAndDrop; + private System.Windows.Forms.ToolStripMenuItem emptyModToolStripMenuItem; + private System.Windows.Forms.LinkLabel linkLabelModAutoDetectInstallOptions; + private System.Windows.Forms.LinkLabel linkLabelModInvalidateFrozenArchive; + private System.Windows.Forms.Button buttonModOpenPage; + private System.Windows.Forms.Panel panelModDetailsHeader; + private System.Windows.Forms.Button buttonModAbstain; + private System.Windows.Forms.Button buttonModEndorse; + private System.Windows.Forms.Label labelModEndorseStatus; + private System.Windows.Forms.Label labelModTitle; + private System.Windows.Forms.CheckBox checkBoxModDetailsEnabled; } } \ No newline at end of file diff --git a/Fo76ini/Forms/FormMods/FormMods.Details.cs b/Fo76ini/Forms/FormMods/FormMods.Details.cs index 15f2c16..af1dc9a 100644 --- a/Fo76ini/Forms/FormMods/FormMods.Details.cs +++ b/Fo76ini/Forms/FormMods/FormMods.Details.cs @@ -1,38 +1,54 @@ -using Fo76ini.Properties; -using Newtonsoft.Json.Linq; +using Fo76ini.Interface; +using Fo76ini.Mods; +using Fo76ini.NexusAPI; +using Fo76ini.Properties; +using Fo76ini.Utilities; using System; using System.Collections.Generic; -using System.ComponentModel; -using System.Data; using System.Diagnostics; using System.Drawing; using System.IO; using System.Linq; -using System.Media; -using System.Net; -using System.Text; using System.Threading; -using System.Threading.Tasks; using System.Windows.Forms; namespace Fo76ini { public partial class FormMods : Form { - private Mod changedMod; + private enum SidePanelStatus + { + Expanded, + Collapsed, + Closed + } + + private SidePanelStatus sidePanelStatus = SidePanelStatus.Closed; + + private bool isUpdatingSidePanel = false; + private int editedModCount = 1; + + private ManagedMod editedMod + { + get { return Mods[editedIndex]; } + } - private bool isUpdatingUI = false; - private bool bulk = false; - private int modCount = 1; + private bool editingBulk + { + get { return editedModCount > 1; } + } private int editedIndex; private List editedIndices; + /// + /// Sets up elements, adds event handlers, etc. + /// private void InitializeDetailControls() { DropDown.Add("ModInstallAs", new DropDown( this.comboBoxModInstallAs, - new String[] { + new string[] { "Bundled *.ba2 archive", "Separate *.ba2 archive", "Loose files" @@ -41,7 +57,7 @@ private void InitializeDetailControls() DropDown.Add("ModArchivePreset", new DropDown( this.comboBoxModArchivePreset, - new String[] { + new string[] { "-- Please select --", "Auto-detect", "General / Interface / Materials / Animations", /* Materials: *.bgsm; Interface: *.swf; */ @@ -61,7 +77,63 @@ private void InitializeDetailControls() this.pictureBoxCollapseDetails.Cursor = Cursors.Hand; }); - CollapseAndHideSidePanel(); + this.Resize += this.FormModsDetails_Resize; + + // Disable scroll wheel on UI elements to prevent the user from accidentally changing values: + Utils.PreventChangeOnMouseWheelForAllElements(this.panelModDetailsInner); + + /* + * Drag&Drop + */ + this.panelModDetailsReplaceDragAndDrop.AllowDrop = true; + this.panelModDetailsReplaceDragAndDrop.DragEnter += new DragEventHandler(panelModDetailsReplaceDragAndDrop_DragEnter); + this.panelModDetailsReplaceDragAndDrop.DragDrop += new DragEventHandler(panelModDetailsReplaceDragAndDrop_DragDrop); + + CloseSidePanel(); + } + + private void FormModsDetails_Resize(object sender, EventArgs e) + { + UpdateSidePanelGroupBoxesWidth(); + } + + private void EditMod(int index) + { + this.editedIndex = index; + this.editedIndices = new List { index }; + this.editedModCount = 1; + + if (editedIndex < 0 || editedIndex >= Mods.Count()) + { + CloseSidePanel(); + return; + } + + UpdateSidePanel(); + if (sidePanelStatus == SidePanelStatus.Closed) + ExpandSidePanel(); + } + + private void EditMods(List indices) + { + this.editedIndex = -1; + this.editedIndices = indices.ToList(); + this.editedModCount = editedIndices.Count(); + + if (this.editedModCount <= 0) + { + CloseSidePanel(); + return; + } + else if (this.editedModCount == 1) + { + EditMod(editedIndices[0]); + return; + } + + UpdateSidePanel(); + if (sidePanelStatus == SidePanelStatus.Closed) + ExpandSidePanel(); } @@ -71,31 +143,32 @@ Side panel private void pictureBoxCollapseDetails_Click(object sender, EventArgs e) { - if (this.panelModDetails.Visible) - //CloseSidePanel(); - CollapseSidePanel(); - else + if (sidePanelStatus != SidePanelStatus.Expanded) ExpandSidePanel(); + else + CollapseSidePanel(); } + /// + /// Hides the side panel with no way to open it again for the user. + /// private void CloseSidePanel() - { - this.ModDetailsClosed(); - this.CollapseAndHideSidePanel(); - - // Reset image, so the thumbnail gets unloaded: - this.pictureBoxModThumbnail.Image = Resources.bg; - } - - private void CollapseAndHideSidePanel() { this.pictureBoxCollapseDetails.Visible = false; this.panelModDetails.Visible = false; int tabWidth = this.tabPageModOrder.Width; this.listViewMods.Width = tabWidth - this.listViewMods.Location.X; + + // Reset image, so the thumbnail gets unloaded: + this.pictureBoxModThumbnail.Image = Resources.bg; + + sidePanelStatus = SidePanelStatus.Closed; } + /// + /// Collapses the side panel but it can be opened again by the user. + /// private void CollapseSidePanel() { this.pictureBoxCollapseDetails.Visible = true; @@ -106,8 +179,13 @@ private void CollapseSidePanel() int buttonWidth = this.pictureBoxCollapseDetails.Width; this.pictureBoxCollapseDetails.Location = new Point(tabWidth - buttonWidth, this.pictureBoxCollapseDetails.Location.Y); this.listViewMods.Width = tabWidth - this.listViewMods.Location.X - buttonWidth + 1; + + sidePanelStatus = SidePanelStatus.Collapsed; } + /// + /// Shows the side panel. + /// private void ExpandSidePanel() { this.pictureBoxCollapseDetails.Visible = true; @@ -119,6 +197,10 @@ private void ExpandSidePanel() int panelWidth = this.panelModDetails.Width; this.pictureBoxCollapseDetails.Location = new Point(tabWidth - panelWidth - buttonWidth + 1, this.pictureBoxCollapseDetails.Location.Y); this.listViewMods.Width = tabWidth - this.listViewMods.Location.X - panelWidth - buttonWidth + 2; + + sidePanelStatus = SidePanelStatus.Expanded; + + UpdateSidePanelControls(); } @@ -126,353 +208,850 @@ private void ExpandSidePanel() * Update UI: */ - public void UpdateSidePanel(Mod mod = null, int modCount = -1) + public void UpdateSidePanel() { - ExpandSidePanel(); - isUpdatingUI = true; + if (!editingBulk && (editedIndex < 0 || editedIndex >= Mods.Count())) + return; + if (editingBulk && editedIndices.Count() < 0) + return; - if (mod != null) - this.changedMod = mod.CreateCopy(); + isUpdatingSidePanel = true; - this.pictureBoxModThumbnail.Image = Resources.bg; + if (editingBulk) + UpdateSidePanelBulk(); + else + UpdateSidePanelOneMod(); - if (modCount > 1) - { - this.bulk = true; - this.modCount = modCount; - } - else if (modCount == 1) + UpdateWarningLabel(); + UpdateSidePanelControls(); + + isUpdatingSidePanel = false; + } + + private void UpdateSidePanelOneMod() + { + this.checkBoxModDetailsEnabled.Visible = true; + this.groupBoxModDetailsDetails.Visible = true; + this.groupBoxModReplace.Visible = true; + + // Update thumbnail: + if (this.editedMod.RemoteInfo != null && + this.editedMod.RemoteInfo.ThumbnailFileName != "" && + File.Exists(this.editedMod.RemoteInfo.ThumbnailFilePath)) { - this.bulk = false; - this.modCount = 1; + // Thumbnail exists, load it: + this.pictureBoxModThumbnail.Image = Image.FromFile(this.editedMod.RemoteInfo.ThumbnailFilePath); + this.pictureBoxModThumbnail.Visible = true; } - - // Not bulk? - if (!this.bulk) + else { - this.labelModArchiveName.Visible = true; - this.textBoxModArchiveName.Visible = true; + // No thumbnail for us: + this.pictureBoxModThumbnail.Image = Resources.bg; + this.pictureBoxModThumbnail.Visible = false; } - this.checkBoxModDetailsEnabled.Checked = this.changedMod.isEnabled; + // Populate values: + this.checkBoxModDetailsEnabled.Checked = this.editedMod.Enabled; + this.checkBoxFreezeArchive.Checked = this.editedMod.Freeze; + this.textBoxModArchiveName.Text = this.editedMod.ArchiveName; + this.textBoxModName.Text = this.editedMod.Title; + this.textBoxModRootDir.Text = this.editedMod.RootFolder; + this.textBoxModURL.Text = this.editedMod.URL; + this.textBoxModVersion.Text = this.editedMod.Version; - if (this.modCount > 1) - this.labelModTitle.Text = String.Format(Localization.localizedStrings["modDetailsTitleBulkSelected"], this.modCount); - else - this.labelModTitle.Text = this.changedMod.Title; - this.textBoxModName.Text = this.changedMod.Title; - this.textBoxModFolderName.Text = this.changedMod.ManagedFolder; - this.textBoxModRootDir.Text = this.changedMod.RootFolder; - this.textBoxModURL.Text = this.changedMod.URL; - this.textBoxModVersion.Text = this.changedMod.Version; - - switch (this.changedMod.Type) + switch (this.editedMod.Method) { - case Mod.FileType.BundledBA2: + case ManagedMod.DeploymentMethod.BundledBA2: this.comboBoxModInstallAs.SelectedIndex = 0; - - //this.checkBoxModBA2Compression.Checked = ManagedMods.Instance.bundledCompression != Archive2.Compression.None; - //this.checkBoxModBA2Compression.Checked = ManagedMods.Instance.bundledTexturesCompression != Archive2.Compression.None; - this.checkBoxFreezeArchive.Visible = false; - - //this.textBoxModArchiveName.Text = ""; - this.textBoxModArchiveName.Visible = false; - this.labelModArchiveName.Visible = false; - this.buttonModDetailsSuggestArchiveName.Visible = false; - - this.labelModUnfreeze.Visible = false; - this.buttonModUnfreeze.Visible = false; - - this.comboBoxModArchivePreset.Visible = false; - this.labelModArchivePreset.Visible = false; - - this.labelModInstallInto.Visible = false; - this.textBoxModRootDir.Visible = false; - this.buttonModPickRootDir.Visible = false; break; - case Mod.FileType.SeparateBA2: + case ManagedMod.DeploymentMethod.SeparateBA2: this.comboBoxModInstallAs.SelectedIndex = 1; - - this.checkBoxFreezeArchive.Checked = this.changedMod.freeze; - this.checkBoxFreezeArchive.Visible = true; - this.labelModUnfreeze.Visible = this.changedMod.isFrozen(); - this.buttonModUnfreeze.Visible = this.changedMod.isFrozen(); - - this.comboBoxModArchivePreset.Visible = true; - this.labelModArchivePreset.Visible = true; - - this.textBoxModArchiveName.Text = this.changedMod.ArchiveName; - this.textBoxModArchiveName.Visible = true; - this.buttonModDetailsSuggestArchiveName.Visible = true; - this.labelModArchiveName.Visible = true; - - this.labelModInstallInto.Enabled = false; - this.textBoxModRootDir.Enabled = false; - this.buttonModPickRootDir.Enabled = false; - this.labelModInstallInto.Visible = true; - this.textBoxModRootDir.Visible = true; - this.buttonModPickRootDir.Visible = true; break; - case Mod.FileType.Loose: + case ManagedMod.DeploymentMethod.LooseFiles: this.comboBoxModInstallAs.SelectedIndex = 2; - this.textBoxModArchiveName.Visible = false; - this.buttonModDetailsSuggestArchiveName.Visible = false; - this.labelModArchiveName.Visible = false; - this.comboBoxModArchivePreset.Visible = false; - this.labelModArchivePreset.Visible = false; - - this.checkBoxFreezeArchive.Visible = false; - this.labelModUnfreeze.Visible = false; - this.buttonModUnfreeze.Visible = false; - - this.labelModUnfreeze.Visible = false; - this.buttonModUnfreeze.Visible = false; - - this.labelModInstallInto.Enabled = true; - this.textBoxModRootDir.Enabled = true; - this.buttonModPickRootDir.Enabled = true; - this.labelModInstallInto.Visible = true; - this.textBoxModRootDir.Visible = true; - this.buttonModPickRootDir.Visible = true; break; } - // Is frozen? - bool isFrozen = this.changedMod.isFrozen(); - /*this.comboBoxModArchivePreset.Enabled = !isFrozen; - this.comboBoxModInstallAs.Enabled = !isFrozen; - this.buttonModRepairDDS.Enabled = !isFrozen;*/ - this.groupBoxModDetailsInstallationOptions.Visible = !isFrozen; + this.labelModTitle.Text = this.editedMod.RemoteInfo != null && this.editedMod.RemoteInfo.Title != "" ? this.editedMod.RemoteInfo.Title : this.editedMod.Title; + + // Install into visible? + this.labelModInstallInto.Enabled = this.editedMod.Method == ManagedMod.DeploymentMethod.LooseFiles; + this.textBoxModRootDir.Enabled = this.editedMod.Method == ManagedMod.DeploymentMethod.LooseFiles; + this.buttonModPickRootDir.Enabled = this.editedMod.Method == ManagedMod.DeploymentMethod.LooseFiles; + + bool installIntoVisible = this.editedMod.Method == ManagedMod.DeploymentMethod.LooseFiles || this.editedMod.Method == ManagedMod.DeploymentMethod.SeparateBA2; + this.labelModInstallInto.Visible = installIntoVisible; + this.textBoxModRootDir.Visible = installIntoVisible; + this.buttonModPickRootDir.Visible = installIntoVisible; + + if (this.editedMod.Method == ManagedMod.DeploymentMethod.SeparateBA2) + this.textBoxModRootDir.Text = "Data"; + + // Preset visible? + this.comboBoxModArchivePreset.Visible = this.editedMod.Method == ManagedMod.DeploymentMethod.SeparateBA2; + this.labelModArchivePreset.Visible = this.editedMod.Method == ManagedMod.DeploymentMethod.SeparateBA2; + + // Archive name visible? + this.labelModArchiveName.Visible = this.editedMod.Method == ManagedMod.DeploymentMethod.SeparateBA2; + this.textBoxModArchiveName.Visible = this.editedMod.Method == ManagedMod.DeploymentMethod.SeparateBA2; + this.buttonModDetailsSuggestArchiveName.Visible = this.editedMod.Method == ManagedMod.DeploymentMethod.SeparateBA2; + + // Frozen visible? + this.checkBoxFreezeArchive.Visible = this.editedMod.Method == ManagedMod.DeploymentMethod.SeparateBA2; + this.linkLabelModInvalidateFrozenArchive.Visible = this.editedMod.Method == ManagedMod.DeploymentMethod.SeparateBA2 && + this.editedMod.Frozen; // Preset - if (!isFrozen && this.changedMod.Type == Mod.FileType.SeparateBA2) + if (this.editedMod.Method == ManagedMod.DeploymentMethod.SeparateBA2) { - bool isCompressed = this.changedMod.Compression == Mod.ArchiveCompression.Compressed; - switch (this.changedMod.Format) + bool isCompressed = this.editedMod.Compression == ManagedMod.ArchiveCompression.Compressed; + switch (this.editedMod.Format) { - case Mod.ArchiveFormat.General: + case ManagedMod.ArchiveFormat.General: if (isCompressed) this.comboBoxModArchivePreset.SelectedIndex = 2; // General else this.comboBoxModArchivePreset.SelectedIndex = 4; // Sound FX break; - case Mod.ArchiveFormat.Textures: + case ManagedMod.ArchiveFormat.Textures: this.comboBoxModArchivePreset.SelectedIndex = 3; // Textures break; - case Mod.ArchiveFormat.Auto: + case ManagedMod.ArchiveFormat.Auto: this.comboBoxModArchivePreset.SelectedIndex = 1; // Auto-detect break; default: this.comboBoxModArchivePreset.SelectedIndex = 0; // Please select break; } - if (this.changedMod.Compression == Mod.ArchiveCompression.Auto) + if (this.editedMod.Compression == ManagedMod.ArchiveCompression.Auto) this.comboBoxModArchivePreset.SelectedIndex = 1; } - // Bulk? - this.checkBoxModDetailsEnabled.Visible = !this.bulk; - this.labelModName.Visible = !this.bulk; - this.textBoxModName.Visible = !this.bulk; - this.labelModFolderName.Visible = !this.bulk; - this.textBoxModFolderName.Visible = !this.bulk; + // NexusMods info: + if (this.editedMod.RemoteInfo != null) + { + this.panelModDetailsNexusMods.Visible = true; + this.buttonModEndorse.Visible = true; + this.buttonModAbstain.Visible = true; + this.labelModEndorseStatus.Visible = true; + this.labelModSummary.Visible = true; + + this.labelModLatestVersion.Text = this.editedMod.RemoteInfo.LatestVersion; + this.labelModAuthor.Text = this.editedMod.RemoteInfo.Author; + this.labelModSummary.Text = + this.editedMod.RemoteInfo.Summary + .Replace("
", "\n") + .Replace("
", "\n") + .Replace("
", "\n"); + this.buttonModEndorse.Enabled = true; + this.buttonModAbstain.Enabled = true; + switch (this.editedMod.RemoteInfo.Endorsement) + { + case NMMod.EndorseStatus.Endorsed: + this.labelModEndorseStatus.Text = Localization.GetString("endorsedText"); + this.labelModEndorseStatus.ForeColor = Color.DarkGreen; + this.buttonModEndorse.Enabled = false; + break; + case NMMod.EndorseStatus.Abstained: + this.labelModEndorseStatus.Text = Localization.GetString("abstainedText"); + this.labelModEndorseStatus.ForeColor = Color.DarkRed; + this.buttonModAbstain.Enabled = false; + break; + case NMMod.EndorseStatus.Undecided: + default: + this.labelModEndorseStatus.Text = Localization.GetString("notEndorsedText"); + this.labelModEndorseStatus.ForeColor = Color.DarkOrange; + break; + } + } + else + { + this.panelModDetailsNexusMods.Visible = false; + this.buttonModEndorse.Visible = false; + this.buttonModAbstain.Visible = false; + this.labelModEndorseStatus.Visible = false; + this.labelModSummary.Visible = false; + } + } + + private void UpdateSidePanelBulk() + { + this.checkBoxModDetailsEnabled.Visible = false; + this.groupBoxModDetailsDetails.Visible = false; + this.groupBoxModReplace.Visible = false; + + this.pictureBoxModThumbnail.Image = Resources.bg; + this.labelModTitle.Text = string.Format(Localization.localizedStrings["modDetailsTitleBulkSelected"], this.editedModCount); + + // Install into visible + this.labelModInstallInto.Visible = true; + this.textBoxModRootDir.Visible = true; + this.buttonModPickRootDir.Visible = true; + this.labelModInstallInto.Enabled = true; + this.textBoxModRootDir.Enabled = true; + this.buttonModPickRootDir.Enabled = true; + + // Preset visible + this.comboBoxModArchivePreset.Visible = true; + this.labelModArchivePreset.Visible = true; + + // Archive name not visible + this.labelModArchiveName.Visible = false; + this.textBoxModArchiveName.Visible = false; + this.buttonModDetailsSuggestArchiveName.Visible = false; + + // Frozen visible + this.checkBoxFreezeArchive.Visible = true; + + + // Populate values: + this.comboBoxModInstallAs.SelectedIndex = 0; // BundledBA2 + this.comboBoxModArchivePreset.SelectedIndex = 0; // Please select + + // NexusMods: + this.panelModDetailsNexusMods.Visible = false; + this.buttonModEndorse.Visible = false; + this.buttonModAbstain.Visible = false; + this.labelModEndorseStatus.Visible = false; + this.labelModSummary.Visible = false; + } + + /// + /// Resizes the group boxes within the side bar to fit, regardless of whether or not the scrollbar is shown. + /// + private void UpdateSidePanelGroupBoxesWidth() + { + int width; + if (this.panelModDetailsInner.VerticalScroll.Visible) + width = this.panelModDetailsInner.Width - 28; + else + width = this.panelModDetailsInner.Width - 14; - //this.buttonModOpenFolder.Visible = !this.bulk; - //this.buttonModRepairDDS.Visible = !this.bulk; - this.buttonModUnfreeze.Enabled = !this.bulk; + this.groupBoxModDetailsInstallationOptions.Width = width; + this.groupBoxModDetailsDetails.Width = width; + this.groupBoxModReplace.Width = width; + } - /*this.separator1.Visible = !this.bulk; - this.separator2.Visible = !this.bulk;*/ + private void UpdateSidePanelControls() + { + int groupboxMargin = 6; + int controlMargin = 8; + int groupboxBottomMargin = 12; - this.labelModDetailsBulkFrozenModsWarning.Visible = this.bulk; - if (this.bulk) + // Is thumbnail visible? + if (this.pictureBoxModThumbnail.Visible) { - this.labelModArchiveName.Visible = false; - this.textBoxModArchiveName.Visible = false; - this.buttonModDetailsSuggestArchiveName.Visible = false; + // Move header underneath thumbnail: + this.panelModDetailsHeader.Top = this.pictureBoxModThumbnail.Top + this.pictureBoxModThumbnail.Height; + this.panelModDetailsInner.Height = this.panelModDetails.Height - this.panelModDetailsHeader.Height - this.pictureBoxModThumbnail.Height; } + else + { + // Move header up: + this.panelModDetailsHeader.Top = 0; + this.panelModDetailsInner.Height = this.panelModDetails.Height - this.panelModDetailsHeader.Height; + } + this.panelModDetailsInner.Top = this.panelModDetailsHeader.Top + this.panelModDetailsHeader.Height; - this.groupBoxModDetailsDetails.Visible = !this.bulk; + // Is summary visible? + if (this.labelModSummary.Visible) + // Place first groupbox underneath summary: + this.groupBoxModDetailsDetails.Top = this.labelModSummary.Top + this.labelModSummary.Height + controlMargin; + else + // Place first groupbox on top: + this.groupBoxModDetailsDetails.Top = groupboxMargin; + + // Place controls on the bottom: + int newTop = 0; + foreach (Control control in new Control[] { comboBoxModInstallAs, textBoxModRootDir, comboBoxModArchivePreset, textBoxModArchiveName, checkBoxFreezeArchive }) + if (control.Visible && control.Top + control.Height > newTop) + newTop = control.Top + control.Height; + + this.labelModInstallWarning.Top = newTop + controlMargin; + if (this.labelModInstallWarning.Visible) + this.linkLabelModAutoDetectInstallOptions.Top = this.labelModInstallWarning.Top + this.labelModInstallWarning.Height + controlMargin; + else + this.linkLabelModAutoDetectInstallOptions.Top = newTop + controlMargin; - isUpdatingUI = false; + // Determine optimal height of groupboxes: + foreach (GroupBox box in new GroupBox[] { groupBoxModDetailsDetails, groupBoxModDetailsInstallationOptions }) + { + int newHeight = 0; + foreach (Control control in box.Controls) + { + if (control.Visible) + { + int temp = control.Top + control.Height + groupboxBottomMargin; + if (newHeight < temp) + newHeight = temp; + } + } + box.Height = newHeight; + } + + // Place groupboxes underneath each other: + GroupBox[] groupBoxes = new GroupBox[] { groupBoxModDetailsDetails, groupBoxModDetailsInstallationOptions, groupBoxModReplace }; + for (int i = 1; i < groupBoxes.Length; i++) + groupBoxes[i].Top = groupBoxes[i - 1].Top + groupBoxes[i - 1].Height + groupboxMargin; + + UpdateSidePanelGroupBoxesWidth(); } - private void UpdateModFolder() + /// + /// Attempt to detect whether the chosen mod installation options could cause the mod not to work properly. + /// Update the label with (hopefully) helpful information for troubleshooting. + /// + private void UpdateWarningLabel() { - this.changedMod.ManagedFolder = ManagedMods.Instance.RenameManagedFolder(this.changedMod.ManagedFolder, this.textBoxModFolderName.Text); + if (editingBulk) + { + this.labelModInstallWarning.Text = ""; + this.labelModInstallWarning.Visible = false; + return; + } + + this.labelModInstallWarning.Visible = true; + + /* + * "Index" the mod folder first: + */ + + bool resourceFoldersFound = false; + bool generalFoldersFound = false; + bool texturesFolderFound = false; + bool soundFoldersFound = false; + bool stringsFolderFound = false; + bool dllFound = false; + + foreach (string folderPath in Directory.EnumerateDirectories(editedMod.ManagedFolderPath)) + { + string folderName = Path.GetFileName(folderPath).ToLower(); + + if (ModHelpers.ResourceFolders.Contains(folderName)) + resourceFoldersFound = true; + if (ModHelpers.GeneralFolders.Contains(folderName)) + generalFoldersFound = true; + if (ModHelpers.TextureFolders.Contains(folderName)) + texturesFolderFound = true; + if (ModHelpers.SoundFolders.Contains(folderName)) + soundFoldersFound = true; + if (folderName == "strings") + stringsFolderFound = true; + } + + foreach (string filePath in Directory.EnumerateFiles(editedMod.ManagedFolderPath)) + { + string fileExtension = Path.GetExtension(filePath).ToLower(); + + if (fileExtension == ".dll") + dllFound = true; + } + + + /* + * Check for possible issues: + */ + + // No resource folders in the top directory? + if ((editedMod.Method == ManagedMod.DeploymentMethod.BundledBA2 || + editedMod.Method == ManagedMod.DeploymentMethod.SeparateBA2) && + !resourceFoldersFound) + { + this.labelModInstallWarning.Text = "Couldn't find common resource folders (meshes, textures, sounds, materials, interface, and so on). The mod might fail to load."; + return; + } + + // Mixed archives might cause issues: + if (editedMod.Method == ManagedMod.DeploymentMethod.SeparateBA2 && + (generalFoldersFound && texturesFolderFound || + generalFoldersFound && soundFoldersFound || + texturesFolderFound && soundFoldersFound)) + { + this.labelModInstallWarning.Text = "Tip: Mixing general, texture, and sound files *might* cause the mod not to load correctly.\nIn case the mod doesn't work, you could try to set it to \"Bundled *.ba2 archive\"."; + return; + } + + // General files found, but wrong format chosen: + if (generalFoldersFound && + editedMod.Method == ManagedMod.DeploymentMethod.SeparateBA2 && + editedMod.Format != ManagedMod.ArchiveFormat.General && editedMod.Format != ManagedMod.ArchiveFormat.Auto) + { + this.labelModInstallWarning.Text = "Tip: For general mods, select the general preset or leave it on \"Auto-detect\"."; + return; + } + + // Textures found, but wrong format chosen: + if (texturesFolderFound && + editedMod.Method == ManagedMod.DeploymentMethod.SeparateBA2 && + (editedMod.Format != ManagedMod.ArchiveFormat.Textures && editedMod.Format != ManagedMod.ArchiveFormat.Auto || + editedMod.Compression != ManagedMod.ArchiveCompression.Compressed && editedMod.Compression != ManagedMod.ArchiveCompression.Auto)) + { + this.labelModInstallWarning.Text = "Tip: For texture replacement mods, select the \"Textures (*.dds files)\" preset or leave it on \"Auto-detect\"."; + return; + } + + // Sound files found, but wrong format chosen: + if (soundFoldersFound && + editedMod.Method == ManagedMod.DeploymentMethod.SeparateBA2 && + (editedMod.Format != ManagedMod.ArchiveFormat.General && editedMod.Format != ManagedMod.ArchiveFormat.Auto || + editedMod.Compression != ManagedMod.ArchiveCompression.Uncompressed && editedMod.Compression != ManagedMod.ArchiveCompression.Auto)) + { + this.labelModInstallWarning.Text = "Tip: For sound replacement mods, select the \"Sound FX / Music / Voice\" preset or leave it on \"Auto-detect\"."; + return; + } + + // Any *.dll files? + if (dllFound && (editedMod.Method != ManagedMod.DeploymentMethod.LooseFiles || (editedMod.RootFolder != "." && editedMod.RootFolder != ""))) + { + this.labelModInstallWarning.Text = "Tip: *.dll files are usually installed as \"Loose files\" into the top directory (\".\")."; + return; + } + + // Strings not installed as loose files? + if (stringsFolderFound && (editedMod.Method != ManagedMod.DeploymentMethod.LooseFiles || editedMod.RootFolder != "Data")) + { + this.labelModInstallWarning.Text = "Tip: Strings are usually installed as \"Loose files\" into the \"Data\" folder."; + return; + } + + this.labelModInstallWarning.Text = ""; + this.labelModInstallWarning.Visible = false; } + /* * Properties changed: */ private void comboBoxModInstallAs_SelectedIndexChanged(object sender, EventArgs e) { - if (isUpdatingUI) + if (isUpdatingSidePanel) return; - switch (this.comboBoxModInstallAs.SelectedIndex) + foreach (int index in editedIndices) { - case 0: // Bundled *.ba2 archive - this.changedMod.Type = Mod.FileType.BundledBA2; - this.changedMod.freeze = false; - break; - case 1: // Separate *.ba2 archive - this.changedMod.Type = Mod.FileType.SeparateBA2; - break; - case 2: // Loose files - this.changedMod.Type = Mod.FileType.Loose; - this.changedMod.freeze = false; - break; + ManagedMod editedMod = Mods[index]; + switch (this.comboBoxModInstallAs.SelectedIndex) + { + case 0: // Bundled *.ba2 archive + editedMod.Method = ManagedMod.DeploymentMethod.BundledBA2; + break; + case 1: // Separate *.ba2 archive + editedMod.Method = ManagedMod.DeploymentMethod.SeparateBA2; + break; + case 2: // Loose files + editedMod.Method = ManagedMod.DeploymentMethod.LooseFiles; + break; + } + if (editedMod.Frozen && (editedMod.Method != ManagedMod.DeploymentMethod.SeparateBA2 && + editedMod.PreviousMethod == ManagedMod.DeploymentMethod.SeparateBA2)) + ModActions.Unfreeze(editedMod); } - UpdateSidePanel(); + if (!editingBulk) + UpdateSidePanel(); + UpdateModList(); + UpdateStatusStrip(); + UpdateWarningLabel(); + UpdateSidePanelControls(); + Mods.Save(); } private void comboBoxModArchivePreset_SelectedIndexChanged(object sender, EventArgs e) { - if (isUpdatingUI) + if (isUpdatingSidePanel) return; - switch (this.comboBoxModArchivePreset.SelectedIndex) + foreach (int index in editedIndices) { - case 0: // Please select - /*this.changedMod.Format = Mod.ArchiveFormat.Auto; - this.changedMod.Compression = Archive2.Compression.Default;*/ - break; - case 1: // Auto-detect - this.changedMod.Format = Mod.ArchiveFormat.Auto; - this.changedMod.Compression = Mod.ArchiveCompression.Auto; - break; - case 2: // General - this.changedMod.Format = Mod.ArchiveFormat.General; - this.changedMod.Compression = Mod.ArchiveCompression.Compressed; - break; - case 3: // Textures - this.changedMod.Format = Mod.ArchiveFormat.Textures; - this.changedMod.Compression = Mod.ArchiveCompression.Compressed; - break; - case 4: // Audio - this.changedMod.Format = Mod.ArchiveFormat.General; - this.changedMod.Compression = Mod.ArchiveCompression.Uncompressed; - break; + ManagedMod editedMod = Mods[index]; + switch (this.comboBoxModArchivePreset.SelectedIndex) + { + case 0: // Please select + case 1: // Auto-detect + editedMod.Format = ManagedMod.ArchiveFormat.Auto; + editedMod.Compression = ManagedMod.ArchiveCompression.Auto; + break; + case 2: // General + editedMod.Format = ManagedMod.ArchiveFormat.General; + editedMod.Compression = ManagedMod.ArchiveCompression.Compressed; + break; + case 3: // Textures + editedMod.Format = ManagedMod.ArchiveFormat.Textures; + editedMod.Compression = ManagedMod.ArchiveCompression.Compressed; + break; + case 4: // Audio + editedMod.Format = ManagedMod.ArchiveFormat.General; + editedMod.Compression = ManagedMod.ArchiveCompression.Uncompressed; + break; + } + if (editedMod.Frozen && + (editedMod.Format != editedMod.CurrentFormat || + editedMod.Compression != editedMod.CurrentCompression)) + ModActions.Unfreeze(editedMod); } - UpdateSidePanel(); + if (!editingBulk) + UpdateSidePanel(); + UpdateModList(); + UpdateStatusStrip(); + UpdateWarningLabel(); + UpdateSidePanelControls(); + Mods.Save(); } private void buttonModPickRootDir_Click(object sender, EventArgs e) { - this.folderBrowserDialogPickRootDir.SelectedPath = Path.Combine(Shared.GamePath, "Data"); + if (isUpdatingSidePanel) + return; + this.folderBrowserDialogPickRootDir.SelectedPath = Path.Combine(this.Mods.GamePath, "Data"); if (this.folderBrowserDialogPickRootDir.ShowDialog() == DialogResult.OK) { - String rootFolder = Utils.MakeRelativePath(Shared.GamePath, this.folderBrowserDialogPickRootDir.SelectedPath); + string rootFolder = Utils.MakeRelativePath(this.Mods.GamePath, this.folderBrowserDialogPickRootDir.SelectedPath); this.textBoxModRootDir.Text = rootFolder; - this.changedMod.RootFolder = rootFolder; + foreach (int index in editedIndices) + Mods[index].RootFolder = rootFolder; } + UpdateModList(); + UpdateStatusStrip(); + UpdateWarningLabel(); + UpdateSidePanelControls(); + Mods.Save(); } private void textBoxModRootDir_TextChanged(object sender, EventArgs e) { - if (this.textBoxModRootDir.Focused && Directory.Exists(this.textBoxModRootDir.Text)) - this.changedMod.RootFolder = this.textBoxModRootDir.Text; + if (isUpdatingSidePanel) + return; + if (this.textBoxModRootDir.Focused) + foreach (int index in editedIndices) + Mods[index].RootFolder = this.textBoxModRootDir.Text; + UpdateModList(); + UpdateStatusStrip(); + UpdateWarningLabel(); + UpdateSidePanelControls(); + Mods.Save(); } private void textBoxModArchiveName_TextChanged(object sender, EventArgs e) { + if (isUpdatingSidePanel) + return; if (this.textBoxModArchiveName.Focused) - this.changedMod.ArchiveName = this.textBoxModArchiveName.Text; + { + this.editedMod.ArchiveName = this.textBoxModArchiveName.Text; + UpdateModList(); + UpdateStatusStrip(); + Mods.Save(); + } } private void textBoxModName_TextChanged(object sender, EventArgs e) { + if (isUpdatingSidePanel) + return; if (textBoxModName.Focused) { - this.changedMod.Title = this.textBoxModName.Text; - this.labelModTitle.Text = this.changedMod.Title; + this.editedMod.Title = this.textBoxModName.Text; + if (this.editedMod.RemoteInfo == null || this.editedMod.RemoteInfo.Title == "") + this.labelModTitle.Text = this.editedMod.Title; + UpdateModList(); + Mods.Save(); } } private void checkBoxModDetailsEnabled_CheckedChanged(object sender, EventArgs e) { - this.changedMod.isEnabled = this.checkBoxModDetailsEnabled.Checked; + if (isUpdatingSidePanel) + return; + this.editedMod.Enabled = this.checkBoxModDetailsEnabled.Checked; + UpdateModList(); + UpdateStatusStrip(); + Mods.Save(); } private void checkBoxFreezeArchive_CheckedChanged(object sender, EventArgs e) { - this.changedMod.freeze = this.checkBoxFreezeArchive.Checked; + if (isUpdatingSidePanel) + return; + foreach (int index in editedIndices) + Mods[index].Freeze = this.checkBoxFreezeArchive.Checked; + UpdateModList(); + UpdateStatusStrip(); + Mods.Save(); } - private void textBoxModFolderName_TextChanged(object sender, EventArgs e) + private void textBoxModURL_TextChanged(object sender, EventArgs e) { + if (isUpdatingSidePanel) + return; + this.editedMod.URL = this.textBoxModURL.Text; + Mods.Save(); + } + private void textBoxModVersion_TextChanged(object sender, EventArgs e) + { + if (isUpdatingSidePanel) + return; + this.editedMod.Version = this.textBoxModVersion.Text; + UpdateModList(); + Mods.Save(); } - private void textBoxModURL_TextChanged(object sender, EventArgs e) + + /* + * Actions + */ + + // Suggest archive name + private void buttonModDetailsSuggestArchiveName_Click(object sender, EventArgs e) { - this.changedMod.URL = this.textBoxModURL.Text; + this.editedMod.ArchiveName = Utils.GetValidFileName(this.editedMod.Title, ".ba2"); + this.textBoxModArchiveName.Text = this.editedMod.ArchiveName; + UpdateSidePanel(); + UpdateModList(); + Mods.Save(); } - private void textBoxModVersion_TextChanged(object sender, EventArgs e) + // Open webpage + private void buttonModOpenPage_Click(object sender, EventArgs e) + { + if (editedMod.ID >= 0) + Process.Start("https://www.nexusmods.com/fallout76/mods/" + editedMod.ID.ToString()/* + "?tab=files"*/); + else if (editedMod.URL != "") + Process.Start(editedMod.URL); + } + + // Set latest version + private void linkLabelModSetLatestVersion_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) + { + if (!editingBulk && editedMod.RemoteInfo != null && editedMod.RemoteInfo.LatestVersion != "") + { + this.editedMod.Version = editedMod.RemoteInfo.LatestVersion; + this.textBoxModVersion.Text = editedMod.RemoteInfo.LatestVersion; + } + } + + // Delete folder contents + private void linkLabelModDeleteFolderContents_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) + { + if (MsgBox.Get("areYouSure").FormatText("Are you sure, you want to delete the folder contents?").Show(MessageBoxButtons.YesNo) == DialogResult.Yes) + { + if (Directory.Exists(editedMod.ManagedFolderPath)) + Directory.Delete(editedMod.ManagedFolderPath, true); + Directory.CreateDirectory(editedMod.ManagedFolderPath); + UpdateProgress(Progress.Done("Deleted files.")); + } + } + + // Import from archive + private void linkLabelModReplaceFilesWithArchive_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) + { + if (this.openFileDialogMod.ShowDialog() == DialogResult.OK) + AddArchiveToModThreaded(this.openFileDialogMod.FileName); + } + + // Import from folder + private void linkLabelModReplaceFilesWithFolder_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) + { + if (this.folderBrowserDialogMod.ShowDialog() == DialogResult.OK) + AddFolderToModThreaded(this.folderBrowserDialogMod.SelectedPath); + } + + // Auto-detect installation options + private void linkLabelModAutoDetectInstallOptions_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) + { + if (!editingBulk) + ModActions.DetectOptimalModInstallationOptions(editedMod); + else + { + foreach (int index in editedIndices) + ModActions.DetectOptimalModInstallationOptions(Mods[index]); + } + UpdateSidePanel(); + UpdateModList(); + } + + // Invalidate frozen archive + private void linkLabelModInvalidateFrozenArchive_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) { - this.changedMod.Version = this.textBoxModVersion.Text; + if (editingBulk) + return; + editedMod.Frozen = false; + UpdateModList(); + UpdateSidePanel(); } /* - * Actions + * NexusAPI */ - private void buttonModUnfreeze_Click(object sender, EventArgs e) + private void buttonModEndorse_Click(object sender, EventArgs e) { - Thread thread = new Thread(() => + if (editingBulk) + return; + + if (this.editedMod.Version == "") { - Invoke(() => ProgressBarMarquee()); - //Invoke(() => Display("Unfreezing...")); - this.changedMod.Unfreeze( - (text, percent) => - { - Invoke(() => Display(text)); - //Invoke(() => ProgressBarContinuous(percent)); - }, - (success) => - { - Invoke(() => - { - Invoke(() => ProgressBarContinuous(100)); - this.ModDetailsFeedback(this.changedMod); - UpdateSidePanel(); - if (success) - DisplayAllDone(); - else - DisplayFailState(); - }); - } - ); - }); - thread.IsBackground = true; - thread.Start(); + MsgBox.Show("Can't endorse", "Please enter a version and try again.", MessageBoxIcon.Information); + return; + } + + if (!NexusMods.User.IsLoggedIn) + { + MsgBox.ShowID("nexusModsNotLoggedIn", MessageBoxIcon.Information); + return; + } + + if (this.editedMod.RemoteInfo != null) + if (this.editedMod.RemoteInfo.Endorse(this.editedMod.Version)) + UpdateSidePanel(); } - private void buttonModDetailsSuggestArchiveName_Click(object sender, EventArgs e) + private void buttonModAbstain_Click(object sender, EventArgs e) { - this.changedMod.ArchiveName = Utils.GetValidFileName(this.changedMod.Title, ".ba2"); - this.textBoxModArchiveName.Text = this.changedMod.ArchiveName; + if (editingBulk) + return; + + if (this.editedMod.Version == "") + { + MsgBox.Show("Can't abstain from endorsing", "Please enter a version and try again.", MessageBoxIcon.Information); + return; + } + + if (!NexusMods.User.IsLoggedIn) + { + MsgBox.ShowID("nexusModsNotLoggedIn", MessageBoxIcon.Information); + return; + } + + if (this.editedMod.RemoteInfo != null) + if (this.editedMod.RemoteInfo.Abstain(this.editedMod.Version)) + UpdateSidePanel(); } - private void buttonModDetailsApply_Click(object sender, EventArgs e) + + /* + * Drag & drop + */ + + private void panelModDetailsReplaceDragAndDrop_DragEnter(object sender, DragEventArgs e) { - UpdateModFolder(); - this.ModDetailsFeedback(this.changedMod); + if (e.Data.GetDataPresent(DataFormats.FileDrop)) + e.Effect = DragDropEffects.Copy; } - private void buttonModDetailsCancel_Click(object sender, EventArgs e) + private void panelModDetailsReplaceDragAndDrop_DragDrop(object sender, DragEventArgs e) { - this.CloseSidePanel(); + string[] files = (string[])e.Data.GetData(DataFormats.FileDrop); + AddToModBulkThreaded(files); } - private void buttonModDetailsOK_Click(object sender, EventArgs e) + private void AddFolderToModThreaded(string folderPath) { - UpdateModFolder(); - this.ModDetailsFeedback(this.changedMod); - this.ModDetailsClosed(); - this.CollapseAndHideSidePanel(); + RunThreaded(() => { + DisableUI(); + }, () => { + try + { + ModInstallations.AddFolder(editedMod, folderPath, false, UpdateProgress); + } + catch (Exception exc) + { + MsgBox.Get("failed").FormatText(exc.Message).Show(MessageBoxIcon.Error); + return false; + } + return true; + }, (success) => { + EnableUI(); + UpdateSidePanel(); + }); + } + + private void AddArchiveToModThreaded(string filePath) + { + RunThreaded(() => { + DisableUI(); + }, () => { + try + { + ModInstallations.AddArchive(editedMod, filePath, UpdateProgress); + } + catch (Archive2RequirementsException exc) + { + MsgBox.ShowID("archive2InstallRequirements", MessageBoxIcon.Error); + return false; + } + catch (Archive2Exception exc) + { + MsgBox.ShowID("archive2Error", MessageBoxIcon.Error); + return false; + } + catch (Exception exc) + { + MsgBox.Get("failed").FormatText(exc.Message).Show(MessageBoxIcon.Error); + return false; + } + return true; + }, (success) => { + EnableUI(); + UpdateSidePanel(); + }); + } + + private void AddToModBulkThreaded(string[] files) + { + RunThreaded(() => { + DisableUI(); + }, () => { + try + { + AddToModBulk(files, UpdateProgress); + } + catch (Archive2RequirementsException exc) + { + MsgBox.ShowID("archive2InstallRequirements", MessageBoxIcon.Error); + return false; + } + catch (Archive2Exception exc) + { + MsgBox.ShowID("archive2Error", MessageBoxIcon.Error); + return false; + } + catch (Exception exc) + { + MsgBox.Get("failed").FormatText(exc.Message).Show(MessageBoxIcon.Error); + return false; + } + return true; + }, (success) => { + EnableUI(); + UpdateSidePanel(); + }); + } + + private void AddToModBulk(string[] files, Action ProgressChanged = null) + { + if (editingBulk) + return; + int i = 0; + string phaseStr = "Importing {0} of {1} files/folders - {2}"; + foreach (string filePath in files) + { + Action PhasedProgressChanged = Progress.BuildPhasedProgressChanged(ProgressChanged, phaseStr, i++, files.Length); + + string fileExtension = Path.GetExtension(filePath); + string fileName = Path.GetFileName(filePath); + string longFilePath = ModInstallations.EnsureLongPathSupport(filePath); + + if (Directory.Exists(longFilePath)) + ModInstallations.AddFolder(editedMod, filePath, true, PhasedProgressChanged); + else if ((new string[] { ".ba2", ".zip", ".rar", ".tar", ".7z" }).Contains(fileExtension.ToLower())) + ModInstallations.AddArchive(editedMod, filePath, PhasedProgressChanged); + else + { + PhasedProgressChanged.Invoke(Progress.Indetermined($"Copying '{fileName}'...")); + File.Copy(longFilePath, Path.Combine(editedMod.ManagedFolderPath, fileName), true); + } + } + ProgressChanged?.Invoke(Progress.Done("File(s)/folder(s) added.")); } } } diff --git a/Fo76ini/Forms/FormMods/FormMods.cs b/Fo76ini/Forms/FormMods/FormMods.cs index becafea..c38670d 100644 --- a/Fo76ini/Forms/FormMods/FormMods.cs +++ b/Fo76ini/Forms/FormMods/FormMods.cs @@ -1,4 +1,9 @@ -using Fo76ini.Mods; +using Fo76ini.Interface; +using Fo76ini.Mods; +using Fo76ini.NexusAPI; +using Fo76ini.Profiles; +using Fo76ini.Tweaks.ResourceLists; +using Fo76ini.Utilities; using System; using System.Collections.Generic; using System.ComponentModel; @@ -8,37 +13,57 @@ using System.IO; using System.Linq; using System.Media; -using System.Text; using System.Threading; -using System.Threading.Tasks; using System.Windows.Forms; +using System.Xml; namespace Fo76ini { public partial class FormMods : Form { - //private UILoader uiLoader = new UILoader(); - private int selectedIndex = -1; private List selectedIndices = new List(); + + private GameInstance game; + private ManagedMods Mods; + + public static event NuclearWinterEventHandler NWModeUpdated; + + /// + /// isUpdating is set to true when updating the UI. + /// The value is checked in event handlers and if it is true, the event will be ignored. + /// TODO: Messy workaround, find a better solution, plz! + /// private bool isUpdating = false; + #region Related to opening, closing, or (re)loading the entire form public FormMods() { InitializeComponent(); InitializeDetailControls(); + // Handle changes: + ProfileManager.ProfileChanged += OnProfileChanged; + + // Make this form translatable: LocalizedForm form = new LocalizedForm(this, this.toolTip); Localization.LocalizedForms.Add(form); - // Game Edition - /*uiLoader.LinkList( - new RadioButton[] { this.radioButtonEditionBethesdaNet, this.radioButtonEditionSteam }, - new String[] { "1", "2" }, - IniFile.Config, "Preferences", "uGameEdition", - "0" - );*/ - + // Add control elements to blacklist: + Translation.BlackList.AddRange(new string[] { + "labelModTitle", + "labelModsDeploy", + "labelModSummary", + "labelModLatestVersion", + "labelModAuthor", + "labelModEndorseStatus", + "labelModGUID", + "labelModInstallWarning", + "toolStripStatusLabelModCount", + "toolStripStatusLabelDeploymentStatus", + "toolStripStatusLabelSpacer", + "toolStripStatusLabelEnabledCount" + }); this.FormClosing += this.FormMods_FormClosing; this.KeyDown += this.FormMods_KeyDown; @@ -50,53 +75,175 @@ public FormMods() this.listViewMods.AllowDrop = true; this.listViewMods.DragEnter += new DragEventHandler(listViewMods_DragEnter); this.listViewMods.DragDrop += new DragEventHandler(listViewMods_DragDrop); - this.listViewMods.MouseUp += listViewMods_MouseUp; } + private void OnProfileChanged(object sender, ProfileEventArgs e) + { + this.game = e.ActiveGameInstance; + ReloadModManager(); + } + + private void FormMods_Load(object sender, EventArgs e) + { + Configuration.LoadWindowState("FormMods", this); + Configuration.LoadListViewState("FormMods", this.listViewMods); + } + + private void FormMods_FormClosing(object sender, FormClosingEventArgs e) + { + if (e.CloseReason == CloseReason.UserClosing) + { + CloseSidePanel(); + Configuration.SaveWindowState("FormMods", this); + Configuration.SaveListViewState("FormMods", this.listViewMods); + e.Cancel = true; + if (this.buttonModsDeploy.Enabled) + Hide(); + } + } + + private void LoadMods(string GamePath) + { + Mods = new ManagedMods(GamePath); + Mods.Load(); + } + + private void ReloadModManager() + { + if (!IniFiles.IsLoaded()) + return; + if (!game.ValidateGamePath()) + return; + try + { + CloseSidePanel(); + LoadMods(game.GamePath); + UpdateUI(); + TriggerNWModeUpdated(); + + if (!LegacyManagedMods.CheckLegacy(game.GamePath)) + Mods.SaveResources(); + } + catch (Exception exc) + { + MsgBox.Popup("Failed to load mods", $"Failed to load mods.\n{exc.GetType()}: {exc.Message}", MessageBoxIcon.Error); + } + } + + private bool ConvertLegacyConditional() + { + if (LegacyManagedMods.CheckLegacy(game.GamePath)) + { + DialogResult resp = MsgBox.ShowID("modsLegacyFormatDetected", MessageBoxButtons.YesNo, MessageBoxIcon.Question); + if (resp == DialogResult.No) + return false; + else if (resp == DialogResult.Yes) + ConvertLegacyThreaded(); + } + return true; + } + + private void ConvertLegacyThreaded() + { + RunThreaded(() => { + ShowLoadingUI(); + }, () => { + LegacyManagedMods.ConvertLegacy(Mods, game.Edition, UpdateProgress); + return true; + }, (success) => { + UpdateUI(); + EnableUI(); + }); + } + + /// + /// Checks whether the game path has been set, all required executables exist, and so on. + /// Displays messageboxes if something is amiss. + /// + /// true if all is good. false if something is amiss. + private bool CheckIntegrity() + { + if (this.game == null) + return false; + + if (!this.game.ValidateGamePath()) + { + MsgBox.ShowID("modsGamePathNotSet", MessageBoxIcon.Error); + return false; + } + if (!Archive2.ValidatePath()) + { + MsgBox.ShowID("modsArchive2Missing", MessageBoxIcon.Error); + return false; + } + if (!File.Exists(Utils.SevenZipPath)) + { + MsgBox.ShowID("7ZipMissing", MessageBoxIcon.Error); + return false; + } + + return true; + } + + /// + /// Opens the window and updates the form. + /// public void OpenUI() { - //Utils.SetFormPosition(this, Form1.Instance.Location.X + Form1.Instance.Width, Form1.Instance.Location.Y); - Utils.SetFormPosition(this, Form1.Instance.Location.X + 100, Form1.Instance.Location.Y + 50); + if (!CheckIntegrity()) + return; + this.WindowState = FormWindowState.Normal; - this.UpdateUI(); - this.Show(); - this.Focus(); + ReloadModManager(); + + Show(); + Focus(); + + if (!ConvertLegacyConditional()) + { + Hide(); + return; + } } - public void UpdateUI() + /// + /// Updates the form. + /// + private void UpdateUI() { + UpdateSelectedIndices(); UpdateModList(); UpdateSettings(); - UpdateLabel(); + UpdateStatusStrip(); } + #endregion + + #region User interface + /// + /// Goes through the mod list and updates the list view. + /// private void UpdateModList() { /* * Iterate one row at a time... */ isUpdating = true; + //UpdateSelectedIndices(); this.listViewMods.Items.Clear(); - for (int i = 0; i < ManagedMods.Instance.Mods.Count; i++) + for (int i = 0; i < Mods.Count; i++) { /* * Define sub-items */ - Mod mod = ManagedMods.Instance.Mods[i]; - - //bool isCompressed = mod.Compression == Mod.ArchiveCompression.Compressed; - bool enabled = ManagedMods.Instance.isModEnabled(i); var type = new ListViewItem.ListViewSubItem(); - //var size = new ListViewItem.ListViewSubItem(); var version = new ListViewItem.ListViewSubItem(); var format = new ListViewItem.ListViewSubItem(); var archiveName = new ListViewItem.ListViewSubItem(); var rootDir = new ListViewItem.ListViewSubItem(); var frozen = new ListViewItem.ListViewSubItem(); var compressed = new ListViewItem.ListViewSubItem(); - //compressed.Text = isCompressed ? Translation.localizedStrings["yes"] : Translation.localizedStrings["no"]; - //compressed.ForeColor = isCompressed ? Color.Black : Color.DarkGreen; /* @@ -112,49 +259,67 @@ private void UpdateModList() /* - * Fill sub-items + * Get some info */ - // Size? - /*long folderSize = Utils.GetSizeInBytes(mod.GetManagedPath()); - size.Text = Utils.GetFormatedSize(folderSize); - if (folderSize >= 1073741824) // > 1 GiB - size.ForeColor = Color.DarkRed; - else if (folderSize >= 209715200) // > 200 MiB - size.ForeColor = Color.OrangeRed; - else if (folderSize >= 104857600) // > 100 MiB - size.ForeColor = Color.DarkOrange; - else if (folderSize >= 10485760) // > 10 MiB - size.ForeColor = Color.Goldenrod; - else - size.ForeColor = Color.DarkGreen;*/ + ManagedMod mod = Mods[i]; + NMMod nmMod = mod.RemoteInfo; + + bool enabled = mod.Enabled; + + + /* + * Fill sub-items + */ // Version: - version.Text = $"{mod.Version}"; - version.ForeColor = Color.Gray; + if (mod.Version != "") + { + if (nmMod != null) + { + int cmp = Utils.CompareVersions(nmMod.LatestVersion, mod.Version); + if (cmp > 0) + { + // Update available: + version.Text = $"{mod.Version} ({nmMod.LatestVersion})"; + version.ForeColor = Color.DarkRed; + } + else + { + // Latest version: + version.Text = $"{mod.Version}"; + version.ForeColor = Color.DarkGreen; + } + } + else + { + version.Text = $"{mod.Version}"; + version.ForeColor = Color.Gray; + } + } // Frozen? - if (mod.isFrozen()) + if (mod.Frozen) { - frozen.Text = Localization.GetString("yes"); + frozen.Text = Localization.GetString("yes"); // "Frozen" frozen.ForeColor = Color.DarkCyan; } - else if (mod.freeze) + else if (mod.Freeze) { - frozen.Text = Localization.GetString("modTableFrozenPending"); + frozen.Text = Localization.GetString("modTableFrozenPending"); // "Pending" frozen.ForeColor = Color.DarkBlue; } else - frozen.Text = Localization.GetString("no"); + frozen.Text = Localization.GetString("no"); // "Thawed" // Archive format switch (mod.Format) { - case Mod.ArchiveFormat.General: + case ManagedMod.ArchiveFormat.General: format.Text = Localization.GetString("modsTableFormatGeneral"); format.ForeColor = Color.OrangeRed; break; - case Mod.ArchiveFormat.Textures: + case ManagedMod.ArchiveFormat.Textures: format.Text = Localization.GetString("modsTableFormatTextures"); format.ForeColor = Color.RoyalBlue; break; @@ -167,11 +332,11 @@ private void UpdateModList() // Archive compression switch (mod.Compression) { - case Mod.ArchiveCompression.Compressed: + case ManagedMod.ArchiveCompression.Compressed: compressed.Text = Localization.GetString("yes"); compressed.ForeColor = Color.DarkGreen; break; - case Mod.ArchiveCompression.Uncompressed: + case ManagedMod.ArchiveCompression.Uncompressed: compressed.Text = Localization.GetString("no"); compressed.ForeColor = Color.Black; break; @@ -182,12 +347,12 @@ private void UpdateModList() } // Fill stuff depending on installation type - switch (mod.Type) + switch (mod.Method) { /* * Bundled *.ba2 archive */ - case Mod.FileType.BundledBA2: + case ManagedMod.DeploymentMethod.BundledBA2: // Installation type type.Text = Localization.GetString("modsTableTypeBundled"); type.ForeColor = Color.OrangeRed; @@ -198,7 +363,7 @@ private void UpdateModList() format.ForeColor = Color.Silver; // Archive name - archiveName.Text = "bundled.ba2"; + archiveName.Text = "Bundled*.ba2"; archiveName.Font = notApplicable; archiveName.ForeColor = Color.Silver; @@ -221,9 +386,9 @@ private void UpdateModList() /* * Separate *.ba2 archive */ - case Mod.FileType.SeparateBA2: + case ManagedMod.DeploymentMethod.SeparateBA2: // Installation type - if (mod.isFrozen()) + if (mod.Freeze) { type.Text = Localization.GetString("modsTableTypeSeparateFrozen"); type.ForeColor = Color.Teal; @@ -246,7 +411,7 @@ private void UpdateModList() /* * Loose files */ - case Mod.FileType.Loose: + case ManagedMod.DeploymentMethod.LooseFiles: // Installation type type.Text = Localization.GetString("modsTableTypeLoose"); type.ForeColor = Color.MediumVioletRed; @@ -305,26 +470,12 @@ private void UpdateModList() private void UpdateSettings() { - if (!IniFiles.Instance.IsLoaded()) - return; - this.checkBoxDisableMods.Checked = ManagedMods.Instance.ModsDisabled; - this.checkBoxAddArchivesAsBundled.Checked = IniFiles.Instance.GetBool(IniFile.Config, "Mods", "bUnpackBA2ByDefault", false); - this.checkBoxModsUseHardlinks.Checked = IniFiles.Instance.GetBool(IniFile.Config, "Mods", "bUseHardlinks", true); - this.checkBoxFreezeBundledArchives.Checked = IniFiles.Instance.GetBool(IniFile.Config, "Mods", "bFreezeBundledArchives", false); - - //this.textBoxGamePath.Text = Shared.GamePath; - - LoadTextBoxResourceLists(); - } + this.checkBoxDisableMods.Checked = this.Mods.ModsDisabled; + this.checkBoxAddArchivesAsBundled.Checked = IniFiles.Config.GetBool("Mods", "bUnpackBA2ByDefault", false); + this.checkBoxModsUseHardlinks.Checked = IniFiles.Config.GetBool("Mods", "bUseHardlinks", true); + this.checkBoxFreezeBundledArchives.Checked = IniFiles.Config.GetBool("Mods", "bFreezeBundledArchives", false); - private void UpdateLabel(bool success = true) - { - if (ManagedMods.Instance.isDeploymentNecessary()) - this.DisplayDeploymentNecessary(); - else if (success) - this.DisplayAllDone(); - else - this.DisplayFailState(); + LoadTextBoxResourceList(Mods.Resources); } private void UpdateSelectedIndices() @@ -336,9 +487,12 @@ private void UpdateSelectedIndices() private void RestoreSelectedIndices() { - this.listViewMods.Clear(); - foreach (int index in this.selectedIndices) - this.listViewMods.Items[index].Selected = true; + // Doesn't work. + foreach (ListViewItem item in this.listViewMods.Items) + if (selectedIndices.Contains(item.Index)) + item.Selected = true; + else + item.Selected = false; } private void EnableUI() @@ -375,66 +529,180 @@ private void ShowLoadingUI() { DisableUI(); this.tabControl1.Enabled = true; - this.pictureBoxModsLoadingGIF.Visible = true; this.tabControl1.SelectedIndex = 0; this.tabPageModsSettings.Enabled = false; + + this.pictureBoxModsLoadingGIF.Visible = true; + this.pictureBoxModsLoadingGIF.Width = this.Width; + this.pictureBoxModsLoadingGIF.Height = this.tabControl1.Height; + this.pictureBoxModsLoadingGIF.Anchor = + AnchorStyles.Top | + AnchorStyles.Bottom | + AnchorStyles.Left | + AnchorStyles.Right; } - public void ModDetailsFeedback(Mod changedMod) + #endregion + + /* + ********************************************************************************** + * Nuclear Winter mode + ********************************************************************************** + */ + + #region Nuclear Winter mode + + public void ToggleNuclearWinterMode() { - if (editedIndices.Count() == 1) - ManagedMods.Instance.Mods[editedIndex] = changedMod.CreateCopy(); + if (Mods.NuclearWinterModeEnabled) + DisableNuclearWinterMode(); else + EnableNuclearWinterMode(); + } + + public void EnableNuclearWinterMode() + { + Mods.NuclearWinterModeEnabled = true; + + // Uninstall mods: + if (!Mods.ModsDisabled && + IniFiles.Config.GetBool("NuclearWinter", "bAutoDisableMods", true)) { - foreach (int index in editedIndices) - { - if (!ManagedMods.Instance.Mods[index].isFrozen()) - { - ManagedMods.Instance.Mods[index].Type = changedMod.Type; - ManagedMods.Instance.Mods[index].Compression = changedMod.Compression; - ManagedMods.Instance.Mods[index].Format = changedMod.Format; - ManagedMods.Instance.Mods[index].RootFolder = changedMod.RootFolder; - ManagedMods.Instance.Mods[index].freeze = changedMod.freeze; - } - } + Mods.ModsDisabled = true; + this.DeployMods(); } - UpdateModList(); + + // Rename added *.dll files: + if (IniFiles.Config.GetBool("NuclearWinter", "bRenameDLLs", true)) + ModDeployment.RenameAddedDLLs(Mods.GamePath); + + // Backwards-compatibility: + IniFiles.Config.Set("NuclearWinter", "bNWMode", true); + IniFiles.Config.Set("Preferences", "bNWMode", true); + + // Save and update UI: + Mods.Save(); + TriggerNWModeUpdated(); } - public void ModDetailsClosed() + public void DisableNuclearWinterMode() { - UpdateModList(); - EnableUI(); + Mods.NuclearWinterModeEnabled = false; + + // Install mods: + if (Mods.ModsDisabled && + IniFiles.Config.GetBool("NuclearWinter", "bAutoDeployMods", true)) + { + Mods.ModsDisabled = false; + if (Mods.Count() > 0) + this.DeployMods(); + } + + // Restore added *.dll files: + ModDeployment.RestoreAddedDLLs(Mods.GamePath); + + // Backwards-compatibility: + IniFiles.Config.Set("NuclearWinter", "bNWMode", false); + IniFiles.Config.Set("Preferences", "bNWMode", false); + + // Save and update UI: + Mods.Save(); + TriggerNWModeUpdated(); } + private void TriggerNWModeUpdated() + { + if (NWModeUpdated != null) + NWModeUpdated(null, BuildNuclearWinterEventArgs()); + } + + public bool IsNuclearWinterModeEnabled() + { + return Mods.NuclearWinterModeEnabled; + } + + public void ToggleNuclearWinterModeThreaded() + { + if (Mods.NuclearWinterModeEnabled) + DisableNuclearWinterModeThreaded(); + else + EnableNuclearWinterModeThreaded(); + } + + public void EnableNuclearWinterModeThreaded() + { + Show(); + Focus(); + RunThreaded(() => { + CloseSidePanel(); + ShowLoadingUI(); + }, () => { + EnableNuclearWinterMode(); + return true; + }, (success) => { + if (success) + MsgBox.Get("nwModeDisabled").Popup(MessageBoxIcon.Information); + UpdateUI(); + EnableUI(); + Hide(); + }); + } + + public void DisableNuclearWinterModeThreaded() + { + Show(); + Focus(); + RunThreaded(() => { + CloseSidePanel(); + ShowLoadingUI(); + }, () => { + DisableNuclearWinterMode(); + return true; + }, (success) => { + if (success) + MsgBox.Get("nwModeDisabled").Popup(MessageBoxIcon.Information); + UpdateUI(); + EnableUI(); + Hide(); + }); + } + + private NuclearWinterEventArgs BuildNuclearWinterEventArgs() + { + NuclearWinterEventArgs args = new NuclearWinterEventArgs(); + args.NuclearWinterModeEnabled = Mods.NuclearWinterModeEnabled; + return args; + } + + #endregion /* + ********************************************************************************** * Event handler + ********************************************************************************** */ - private void FormMods_Load(object sender, EventArgs e) + // Deploy + private void buttonModsDeploy_Click(object sender, EventArgs e) { - IniFiles.Instance.LoadWindowState("FormMods", this); - IniFiles.Instance.LoadListViewState("FormMods", this.listViewMods); + DeployModsThreaded(); } - private void FormMods_FormClosing(object sender, FormClosingEventArgs e) + // Disable mods + private void checkBoxDisableMods_CheckedChanged(object sender, EventArgs e) { - if (e.CloseReason == CloseReason.UserClosing) - { - IniFiles.Instance.SaveWindowState("FormMods", this); - IniFiles.Instance.SaveListViewState("FormMods", this.listViewMods); - e.Cancel = true; - if (this.buttonModsDeploy.Enabled && (true || MsgBox.ShowID("modsOnCloseDeploymentNecessary", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)) - Hide(); - } + this.Mods.ModsDisabled = checkBoxDisableMods.Checked; + this.Mods.Save(); + UpdateStatusStrip(); } + #region All event handler that control the ListView + private void FormMods_KeyDown(object sender, KeyEventArgs e) { if (e.KeyCode == Keys.F1) { - // Open README + // Open guide showGuideToolStripMenuItem_Click(sender, e); } else if (e.KeyCode == Keys.F5) @@ -442,10 +710,12 @@ private void FormMods_KeyDown(object sender, KeyEventArgs e) // Reload UI: reloadUIToolStripMenuItem_Click(sender, e); } - /*else if (e.Control == true && e.Shift && e.KeyCode == Keys.F12) + + if (e.Control && e.KeyCode == Keys.S) { - FormConsole.Instance.OpenUI(); - }*/ + // Save changes: + saveToolStripMenuItem_Click(sender, e); + } // These shortcuts only apply to the mod list: if (this.listViewMods.Focused) @@ -455,11 +725,6 @@ private void FormMods_KeyDown(object sender, KeyEventArgs e) // Delete mods: toolStripButtonDeleteMod_Click(sender, e); } - else if (e.KeyCode == Keys.Enter || e.KeyCode == Keys.Return) - { - // Edit mods: - toolStripButtonModEdit_Click(sender, e); - } else if (e.Control && e.KeyCode == Keys.Up) { // Move mods up: @@ -470,133 +735,80 @@ private void FormMods_KeyDown(object sender, KeyEventArgs e) // Move mods down: toolStripButtonMoveDown_Click(sender, e); } + else if (e.Control && e.KeyCode == Keys.A) + { + // Select all: + foreach (ListViewItem item in this.listViewMods.Items) + item.Selected = true; + UpdateSelectedIndices(); + } } } private void listViewMods_SelectedIndexChanged(object sender, EventArgs e) { + if (isUpdating) + return; + if (this.listViewMods.SelectedItems.Count > 0) selectedIndex = this.listViewMods.SelectedItems[0].Index; else selectedIndex = -1; - } - private void listViewMods_MouseUp(object sender, MouseEventArgs e) - { - if (e.Button == MouseButtons.Right) - toolStripButtonModEdit_Click(sender, (EventArgs)e); - } - - // Deploy - private void buttonModsDeploy_Click(object sender, EventArgs e) - { - if (!ManagedMods.Instance.ValidateGamePath()) - { - MsgBox.ShowID("modsGamePathNotSet", MessageBoxIcon.Information); - return; - } - Thread thread = new Thread(Deploy); - thread.IsBackground = true; - thread.Start(); - } - - // Disable mods - private void checkBoxDisableMods_CheckedChanged(object sender, EventArgs e) - { - ManagedMods.Instance.ModsDisabled = checkBoxDisableMods.Checked; - DisplayDeploymentNecessary(); + // Edit mod: + UpdateSelectedIndices(); + if (selectedIndices.Count() > 0) + EditMods(selectedIndices); } // Drag & Drop void listViewMods_DragEnter(object sender, DragEventArgs e) { - if (e.Data.GetDataPresent(DataFormats.FileDrop)) e.Effect = DragDropEffects.Copy; + if (e.Data.GetDataPresent(DataFormats.FileDrop)) + e.Effect = DragDropEffects.Copy; } void listViewMods_DragDrop(object sender, DragEventArgs e) { - if (!ManagedMods.Instance.ValidateGamePath()) - { - MsgBox.ShowID("modsGamePathNotSet", MessageBoxIcon.Information); - return; - } string[] files = (string[])e.Data.GetData(DataFormats.FileDrop); - Thread thread = new Thread(() => InstallBulk(files)); - thread.IsBackground = true; - thread.Start(); + InstallBulkThreaded(files); } - /* - * Mod order buttons - */ - - // Edit mod details: - private void toolStripButtonModEdit_Click(object sender, EventArgs e) + // Mod enabled/disabled + private void listViewMods_ItemCheck(object sender, ItemCheckEventArgs e) { - UpdateSelectedIndices(); - this.editedIndex = this.selectedIndex; - this.editedIndices = this.selectedIndices.ToList(); // Make a shallow copy + if (isUpdating) + return; - int modCount = editedIndices.Count(); - if (modCount <= 0 || editedIndex < 0) + if (e.NewValue == CheckState.Checked) { - SystemSounds.Beep.Play(); - return; + Mods.EnableMod(e.Index); + listViewMods.Items[e.Index].ForeColor = Color.DarkGreen; } - - if (modCount == 1) - UpdateSidePanel(ManagedMods.Instance.Mods[editedIndex], 1); - //this.formModDetails.UpdateUI(ManagedMods.Instance.Mods[selectedIndex], 1); - else + else if (e.NewValue == CheckState.Unchecked) { - Mod bulkMod = new Mod(); - Mod fallbackMod = null; - int realModCount = 0; - foreach (int index in editedIndices) - { - Mod mod = ManagedMods.Instance.Mods[index]; - if (mod.isFrozen()) - continue; - fallbackMod = mod; - bulkMod.Type = mod.Type; - bulkMod.Compression = mod.Compression; - bulkMod.Format = mod.Format; - bulkMod.freeze = false; - realModCount++; - } - bulkMod.RootFolder = "Data"; - if (realModCount == 0) - { - SystemSounds.Beep.Play(); - return; - } - else if (realModCount == 1) - UpdateSidePanel(fallbackMod != null ? fallbackMod : ManagedMods.Instance.Mods[editedIndex], 1); - //this.formModDetails.UpdateUI(fallbackMod != null ? fallbackMod : ManagedMods.Instance.Mods[editedIndex], 1); - else - UpdateSidePanel(bulkMod, realModCount); - //this.formModDetails.UpdateUI(bulkMod, realModCount); + Mods.DisableMod(e.Index); + listViewMods.Items[e.Index].ForeColor = Color.DarkRed; } - //DisableUI_SidePanelOpen(); - //Utils.SetFormPosition(this.formModDetails, this.Location.X + (int)(this.Width / 2 - this.formModDetails.Width / 2), this.Location.Y + (int)(this.Height / 2 - this.formModDetails.Height / 2)); - //this.formModDetails.Show(); + UpdateStatusStrip(); + if (sidePanelStatus != SidePanelStatus.Closed) + UpdateSidePanel(); } + #endregion + + #region Toolstrip event handler + // Open mod folder: private void toolStripButtonModOpenFolder_Click(object sender, EventArgs e) { - if (!ManagedMods.Instance.ValidateGamePath()) - { - MsgBox.ShowID("modsGamePathNotSet", MessageBoxIcon.Information); - return; - } UpdateSelectedIndices(); if (selectedIndices.Count > 0) { foreach (int index in selectedIndices) { - String path = ManagedMods.Instance.Mods[index].GetManagedPath(); + string path = Mods[index].ManagedFolderPath; if (Directory.Exists(path)) Utils.OpenExplorer(path); else @@ -605,7 +817,7 @@ private void toolStripButtonModOpenFolder_Click(object sender, EventArgs e) } else { - String path = Path.Combine(Shared.GamePath, "Mods"); + string path = Path.Combine(this.game.GamePath, "Mods"); if (Directory.Exists(path)) Utils.OpenExplorer(path); } @@ -615,76 +827,56 @@ private void toolStripButtonModOpenFolder_Click(object sender, EventArgs e) private void toolStripButtonMoveUp_Click(object sender, EventArgs e) { UpdateSelectedIndices(); - CloseSidePanel(); + //CloseSidePanel(); /*if (selectedIndex < 0) return; selectedIndex = ManagedMods.Instance.MoveModUp(selectedIndex);*/ + List newSelectedIndices = new List(); if (selectedIndices.Count <= 0) return; else if (selectedIndices.Count == 1) { - selectedIndex = ManagedMods.Instance.MoveModUp(selectedIndex); - selectedIndices.Clear(); + selectedIndex = Mods.MoveModUp(selectedIndex); + newSelectedIndices.Add(selectedIndex); } else { selectedIndex = -1; selectedIndices = selectedIndices.OrderBy(i => i).ToList(); - List newSelectedIndices = new List(); foreach (int index in selectedIndices) - newSelectedIndices.Add(ManagedMods.Instance.MoveModUp(index)); - selectedIndices = newSelectedIndices; + newSelectedIndices.Add(Mods.MoveModUp(index)); } + selectedIndices = newSelectedIndices; UpdateModList(); - UpdateLabel(); + UpdateStatusStrip(); } // Move down private void toolStripButtonMoveDown_Click(object sender, EventArgs e) { UpdateSelectedIndices(); - CloseSidePanel(); + //CloseSidePanel(); /*if (selectedIndex < 0) return; selectedIndex = ManagedMods.Instance.MoveModDown(selectedIndex);*/ + List newSelectedIndices = new List(); if (selectedIndices.Count <= 0) return; else if (selectedIndices.Count == 1) { - selectedIndex = ManagedMods.Instance.MoveModDown(selectedIndex); - selectedIndices.Clear(); + selectedIndex = Mods.MoveModDown(selectedIndex); + newSelectedIndices.Add(selectedIndex); } else { selectedIndex = -1; selectedIndices = selectedIndices.OrderByDescending(i => i).ToList(); - List newSelectedIndices = new List(); foreach (int index in selectedIndices) - newSelectedIndices.Add(ManagedMods.Instance.MoveModDown(index)); - selectedIndices = newSelectedIndices; + newSelectedIndices.Add(Mods.MoveModDown(index)); } + selectedIndices = newSelectedIndices; UpdateModList(); - UpdateLabel(); - } - - // Mod enabled/disabled - private void listViewMods_ItemCheck(object sender, ItemCheckEventArgs e) - { - if (isUpdating) - return; - - if (e.NewValue == CheckState.Checked) - { - ManagedMods.Instance.EnableMod(e.Index); - listViewMods.Items[e.Index].ForeColor = Color.DarkGreen; - } - else if (e.NewValue == CheckState.Unchecked) - { - ManagedMods.Instance.DisableMod(e.Index); - listViewMods.Items[e.Index].ForeColor = Color.DarkRed; - } - - UpdateLabel(); + UpdateStatusStrip(); } // Check/uncheck all @@ -703,8 +895,8 @@ private void toolStripButtonCheckAll_Click(object sender, EventArgs e) break; } } - foreach (Mod mod in ManagedMods.Instance.Mods) - mod.isEnabled = state; + foreach (ManagedMod mod in Mods) + mod.Enabled = state; } else { @@ -717,125 +909,70 @@ private void toolStripButtonCheckAll_Click(object sender, EventArgs e) } } foreach (ListViewItem item in this.listViewMods.SelectedItems) - ManagedMods.Instance.Mods[item.Index].isEnabled = state; + Mods[item.Index].Enabled = state; } + UpdateSelectedIndices(); UpdateModList(); - UpdateLabel(); + UpdateStatusStrip(); + if (sidePanelStatus != SidePanelStatus.Closed) + UpdateSidePanel(); } // Delete mod private void toolStripButtonDeleteMod_Click(object sender, EventArgs e) { - bool deleteAccepted = false; if (selectedIndex < 0) return; if (this.listViewMods.SelectedItems.Count > 1) { - DialogResult res = MsgBox.Get("modsDeleteBulkBtn").FormatText(this.listViewMods.SelectedItems.Count.ToString()).Show(MessageBoxButtons.YesNo, MessageBoxIcon.Question); + string count = this.listViewMods.SelectedItems.Count.ToString(); + DialogResult res = MsgBox.Get("deleteMultipleQuestion").FormatTitle(count).FormatText(count).Show(MessageBoxButtons.YesNo, MessageBoxIcon.Question); if (res == DialogResult.Yes) { - deleteAccepted = true; List indices = new List(); foreach (ListViewItem item in this.listViewMods.SelectedItems) indices.Add(item.Index); - Thread thread = new Thread(() => DeleteModsBulk(indices)); - thread.IsBackground = true; - thread.Start(); + DeleteModsBulkThreaded(indices); } } else { - Mod mod = ManagedMods.Instance.Mods[selectedIndex]; - DialogResult res = MsgBox.Get("modsDeleteBtn").FormatText(mod.Title).Show(MessageBoxButtons.YesNo, MessageBoxIcon.Question); + ManagedMod mod = Mods[selectedIndex]; + DialogResult res = MsgBox.Get("deleteQuestion").FormatTitle(mod.Title).FormatText(mod.Title).Show(MessageBoxButtons.YesNo, MessageBoxIcon.Question); if (res == DialogResult.Yes) - { - deleteAccepted = true; - Thread thread = new Thread(() => DeleteMod(selectedIndex)); - thread.IsBackground = true; - thread.Start(); - } + DeleteModThreaded(selectedIndex); } - if (deleteAccepted) - CloseSidePanel(); } // Add mod archive private void toolStripButtonAddMod_Click(object sender, EventArgs e) { - if (!ManagedMods.Instance.ValidateGamePath()) - { - MsgBox.ShowID("modsGamePathNotSet", MessageBoxIcon.Information); - return; - } if (this.openFileDialogMod.ShowDialog() == DialogResult.OK) - { - Thread thread = new Thread(() => InstallModArchive(this.openFileDialogMod.FileName)); - thread.IsBackground = true; - thread.Start(); - - CloseSidePanel(); - } + InstallModArchiveThreaded(this.openFileDialogMod.FileName, false); } // Add mod folder private void toolStripButtonAddModFolder_Click(object sender, EventArgs e) { - if (!ManagedMods.Instance.ValidateGamePath()) - { - MsgBox.ShowID("modsGamePathNotSet", MessageBoxIcon.Information); - return; - } if (this.folderBrowserDialogMod.ShowDialog() == DialogResult.OK) - { - Thread thread = new Thread(() => InstallModFolder(this.folderBrowserDialogMod.SelectedPath)); - thread.IsBackground = true; - thread.Start(); - - CloseSidePanel(); - } - } - - // Add frozen mod archive (*.ba2) - private void toolStripButtonAddModFrozen_Click(object sender, EventArgs e) - { - if (!ManagedMods.Instance.ValidateGamePath()) - { - MsgBox.ShowID("modsGamePathNotSet", MessageBoxIcon.Information); - return; - } - if (this.openFileDialogBA2.ShowDialog() == DialogResult.OK) - { - Thread thread = new Thread(() => InstallModArchiveFrozen(this.openFileDialogBA2.FileName)); - thread.IsBackground = true; - thread.Start(); - - CloseSidePanel(); - } - } - - // Unfreeze - private void toolStripButtonUnfreeze_Click(object sender, EventArgs e) - { - if (!ManagedMods.Instance.ValidateGamePath()) - { - MsgBox.ShowID("modsGamePathNotSet", MessageBoxIcon.Information); - return; - } - List indices = new List(); - foreach (ListViewItem item in this.listViewMods.SelectedItems) - indices.Add(item.Index); - Thread thread = new Thread(() => UnfreezeBulkMods(indices)); - thread.IsBackground = true; - thread.Start(); - CloseSidePanel(); + InstallModFolderThreaded(this.folderBrowserDialogMod.SelectedPath); } + #endregion + #region Menustrip /* * Menu */ + // File > Add mod > Empty mod + private void emptyModToolStripMenuItem_Click(object sender, EventArgs e) + { + ModInstallations.InstallBlank(Mods); + UpdateModList(); + } + // File > Add mod > From archive private void fromArchiveToolStripMenuItem_Click(object sender, EventArgs e) { @@ -851,20 +988,16 @@ private void fromFolderToolStripMenuItem_Click(object sender, EventArgs e) // File > Add mod > From *.ba2 archive (frozen) private void fromba2ArchivefrozenToolStripMenuItem_Click(object sender, EventArgs e) { - toolStripButtonAddModFrozen_Click(sender, e); + if (this.openFileDialogBA2.ShowDialog() == DialogResult.OK) + InstallModArchiveThreaded(this.openFileDialogBA2.FileName, true); } // File > Import installed mods private void toolStripMenuItemModsImport_Click(object sender, EventArgs e) { - if (!ManagedMods.Instance.ValidateGamePath()) - { - MsgBox.ShowID("modsGamePathNotSet", MessageBoxIcon.Information); - return; - } if (MsgBox.ShowID("modsImportQuestion", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes) { - ManagedMods.Instance.ImportInstalledMods(); + ImportInstalledModsThreaded(UpdateProgress); this.UpdateModList(); CloseSidePanel(); @@ -877,23 +1010,32 @@ private void deployToolStripMenuItem_Click(object sender, EventArgs e) buttonModsDeploy_Click(sender, e); } + // File > Save + private void saveToolStripMenuItem_Click(object sender, EventArgs e) + { + Mods.Save(); + this.labelModsDeploy.Text = "Changes saved."; + this.labelModsDeploy.ForeColor = Color.DarkGreen; + } + // View > Show conflicting files private void showConflictingFilesToolStripMenuItem_Click(object sender, EventArgs e) { - List conflicts = ManagedMods.Instance.GetConflictingFiles(); + // TODO: "Show conflicting files"... uhhh, well. As long as it works, I guess? + List conflicts = ModHelpers.GetConflictingFiles(Mods.Mods); if (conflicts.Count == 0) { MsgBox.ShowID("modsNoConflictingFiles", MessageBoxIcon.Information); return; } - String tempFile = Path.GetTempFileName(); + string tempFile = Path.GetTempFileName(); using (StreamWriter f = File.AppendText(tempFile)) { f.WriteLine("Conflicting mods:"); - foreach (ManagedMods.Conflict conflict in conflicts) + foreach (ModHelpers.Conflict conflict in conflicts) { - f.WriteLine("\n* " +conflict.conflictText + " (" + conflict.conflictingFiles.Count + " conflicting file" + (conflict.conflictingFiles.Count == 1 ? "" : "s") + ")"); - foreach (String conflictingFile in conflict.conflictingFiles) + f.WriteLine("\n* " + conflict.conflictText + " (" + conflict.conflictingFiles.Count + " conflicting file" + (conflict.conflictingFiles.Count == 1 ? "" : "s") + ")"); + foreach (string conflictingFile in conflict.conflictingFiles) f.WriteLine(" -> " + conflictingFile); } } @@ -905,6 +1047,28 @@ private void showConflictingFilesToolStripMenuItem_Click(object sender, EventArg private void reloadUIToolStripMenuItem_Click(object sender, EventArgs e) { this.UpdateUI(); + if (this.sidePanelStatus != SidePanelStatus.Closed) + UpdateSidePanel(); + } + + // View > Show loading animation + private void showLoadingAnimationToolStripMenuItem_Click(object sender, EventArgs e) + { + RunThreaded(() => { + ShowLoadingUI(); + }, () => { + for (int i = 1; i <= 5 * 2; i++) + { + this.progressBarMods.Invoke(new Action(() => { + this.progressBarMods.Value = (int)((float)i * 100 / 10); + })); + Thread.Sleep(500); + } + return true; + }, (success) => { + this.progressBarMods.Value = 0; + EnableUI(); + }); } // Tools > Archive2 > Open Archive2 @@ -922,354 +1086,568 @@ private void exploreba2ArchiveToolStripMenuItem_Click(object sender, EventArgs e } } - // Help > Show README - private void showGuideToolStripMenuItem_Click(object sender, EventArgs e) + // Tools > NexusMods > Update mod information + private void updateModInformationToolStripMenuItem_Click(object sender, EventArgs e) { - System.Diagnostics.Process.Start("https://www.nexusmods.com/fallout76/articles/40"); - // https://www.nexusmods.com/fallout76/mods/546 - // https://felisdiligens.github.io/Fo76ini/ManageMods.html + UpdateRemoteModInfoThreaded(); + } + + // Tools > NexusMods > Endorse mods + private void endorseModsToolStripMenuItem_Click(object sender, EventArgs e) + { + if (MsgBox.ShowID("nexusModsEndorseAllQuestion", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes) + EndorseModsThreaded(); } - private void showREADMEToolStripMenuItem_Click(object sender, EventArgs e) + // Tools > NexusMods > Check for updates + private void checkForUpdatesToolStripMenuItem_Click(object sender, EventArgs e) { - System.Diagnostics.Process.Start("https://www.nexusmods.com/fallout76/mods/546"); + CheckForUpdatesThreaded(); + } + + // Help > Show guide + private void showGuideToolStripMenuItem_Click(object sender, EventArgs e) + { + Process.Start("https://github.com/FelisDiligens/Fallout76-QuickConfiguration/wiki/Mod-Manager-Guide"); + // Previous pages: + // https://www.nexusmods.com/fallout76/articles/40 + // https://www.nexusmods.com/fallout76/mods/546 + // https://felisdiligens.github.io/Fo76ini/ManageMods.html + // Well, I have moved info pages a lot, lol. } // Help > Log files > Show modmanager.log.txt private void showModmanagerlogtxtToolStripMenuItem_Click(object sender, EventArgs e) { - if (File.Exists(ManagedMods.Instance.logFile.GetFilePath())) - Utils.OpenNotepad(ManagedMods.Instance.logFile.GetFilePath()); + if (File.Exists(ModDeployment.LogFile.GetFilePath())) + Utils.OpenNotepad(ModDeployment.LogFile.GetFilePath()); } // Help > Log files > Show archive2.log.txt private void showArchive2logtxtToolStripMenuItem_Click(object sender, EventArgs e) { - if (File.Exists(Archive2.logFile.GetFilePath())) - Utils.OpenNotepad(Archive2.logFile.GetFilePath()); + if (File.Exists(Archive2.LogFile.GetFilePath())) + Utils.OpenNotepad(Archive2.LogFile.GetFilePath()); } + #endregion /* * Settings */ - private void LoadTextBoxResourceLists() + #region Resource list textboxes + private void LoadTextBoxResourceList(ResourceList list) { - this.textBoxsResourceIndexFileList.Text = String.Join(Environment.NewLine, ManagedMods.Instance.LoadResourceList("sResourceIndexFileList")); - this.textBoxsResourceArchive2List.Text = String.Join(Environment.NewLine, ManagedMods.Instance.LoadResourceList("sResourceArchive2List")); + this.textBoxResourceList.Text = list.ToString("\n").Replace("\n", "\r\n"); } // Clean lists - private void buttonModsCleanLists_Click(object sender, EventArgs e) + private void buttonModsCleanList_Click(object sender, EventArgs e) { - List sResourceIndexFileList = this.textBoxsResourceIndexFileList.Text.Replace(Environment.NewLine, "\n").Split(new char[] { '\n', ',' }, StringSplitOptions.RemoveEmptyEntries).Distinct().Select(x => x.Trim()).ToList(); - List sResourceArchive2List = this.textBoxsResourceArchive2List.Text.Replace(Environment.NewLine, "\n").Split(new char[] { '\n', ',' }, StringSplitOptions.RemoveEmptyEntries).Distinct().Select(x => x.Trim()).ToList(); + // Load list: + ResourceList list = ResourceList.FromString(this.textBoxResourceList.Text.Replace("\r\n", "\n")); - String[] temp = new String[sResourceIndexFileList.Count()]; - sResourceIndexFileList.CopyTo(temp); - foreach (String ba2file in temp) - { - Console.WriteLine(ba2file); - if (!File.Exists(Path.Combine(Shared.GamePath, "Data", ba2file))) - sResourceIndexFileList.Remove(ba2file); - } + // Remove non-existing files: + list.CleanUp(this.game.GamePath); - temp = new String[sResourceArchive2List.Count()]; - sResourceArchive2List.CopyTo(temp); - foreach (String ba2file in temp) - { - if (!File.Exists(Path.Combine(Shared.GamePath, "Data", ba2file))) - sResourceArchive2List.Remove(ba2file); - if (sResourceIndexFileList.Contains(ba2file)) - sResourceArchive2List.Remove(ba2file); - } - this.textBoxsResourceIndexFileList.Text = String.Join(Environment.NewLine, sResourceIndexFileList); - this.textBoxsResourceArchive2List.Text = String.Join(Environment.NewLine, sResourceArchive2List); + LoadTextBoxResourceList(list); } // Apply changes - private void buttonModsApplyTextBoxes_Click(object sender, EventArgs e) + private void buttonModsApplyTextBox_Click(object sender, EventArgs e) { - /*IniFile iniFile = ManagedMods.Instance.WriteToF76Custom ? IniFile.F76Custom : IniFile.Config; - IniFiles.Instance.Set(iniFile, "Archive", "sResourceArchive2List", String.Join(",", this.textBoxsResourceArchive2List.Text.Replace(Environment.NewLine, "\n").Split(new char[] { '\n', ',' }, StringSplitOptions.RemoveEmptyEntries))); - IniFiles.Instance.Set(iniFile, "Archive", "sResourceIndexFileList", String.Join(",", this.textBoxsResourceIndexFileList.Text.Replace(Environment.NewLine, "\n").Split(new char[] { '\n', ',' }, StringSplitOptions.RemoveEmptyEntries)));*/ - ManagedMods.Instance.logFile.WriteLine("\n\nSaving changes to resource lists..."); - ManagedMods.Instance.SaveResourceList("sResourceIndexFileList", this.textBoxsResourceIndexFileList.Text.Replace(Environment.NewLine, "\n").Split(new char[] { '\n', ',' }, StringSplitOptions.RemoveEmptyEntries).ToList()); - ManagedMods.Instance.SaveResourceList("sResourceArchive2List", this.textBoxsResourceArchive2List.Text.Replace(Environment.NewLine, "\n").Split(new char[] { '\n', ',' }, StringSplitOptions.RemoveEmptyEntries).ToList()); - ManagedMods.Instance.CopyINILists(); - IniFiles.Instance.SaveAll(); + ResourceList list = ResourceList.FromString(this.textBoxResourceList.Text.Replace("\r\n", "\n")); + Mods.Resources.ReplaceRange(list); + Mods.Save(); + LoadTextBoxResourceList(Mods.Resources); } // Reset - private void buttonModsResetTextboxes_Click(object sender, EventArgs e) + private void buttonModsResetTextbox_Click(object sender, EventArgs e) { - LoadTextBoxResourceLists(); + LoadTextBoxResourceList(Mods.Resources); } + #endregion - /*public void ChangeGameEdition(GameEdition gameEdition) - { - ManagedMods.Instance.CopyINILists(); - ManagedMods.Instance.Unload(); - IniFiles.Instance.Set(IniFile.Config, "Preferences", "uGameEdition", (uint)gameEdition); - ManagedMods.Instance.GameEdition = gameEdition; - Shared.GamePath = IniFiles.Instance.GetString(IniFile.Config, "Preferences", Shared.GamePathKey, ""); - //this.textBoxGamePath.Text = Shared.GamePath; - ManagedMods.Instance.Load(); - UpdateUI(); - }*/ - + #region Settings - Checkboxes // Alternative *.ba2 import method private void checkBoxAddArchivesAsBundled_CheckedChanged(object sender, EventArgs e) { - IniFiles.Instance.Set(IniFile.Config, "Mods", "bUnpackBA2ByDefault", this.checkBoxAddArchivesAsBundled.Checked); - IniFiles.Instance.SaveConfig(); + IniFiles.Config.Set("Mods", "bUnpackBA2ByDefault", this.checkBoxAddArchivesAsBundled.Checked); + IniFiles.Config.Save(); } // Hard links private void checkBoxModsUseHardlinks_CheckedChanged(object sender, EventArgs e) { - IniFiles.Instance.Set(IniFile.Config, "Mods", "bUseHardlinks", this.checkBoxModsUseHardlinks.Checked); - IniFiles.Instance.SaveConfig(); + IniFiles.Config.Set("Mods", "bUseHardlinks", this.checkBoxModsUseHardlinks.Checked); + IniFiles.Config.Save(); } // Freeze bundled archives private void checkBoxFreezeBundledArchives_CheckedChanged(object sender, EventArgs e) { - IniFiles.Instance.Set(IniFile.Config, "Mods", "bFreezeBundledArchives", this.checkBoxFreezeBundledArchives.Checked); - IniFiles.Instance.SaveConfig(); + IniFiles.Config.Set("Mods", "bFreezeBundledArchives", this.checkBoxFreezeBundledArchives.Checked); + IniFiles.Config.Save(); } + #endregion - private void checkBoxModsWriteSResourceDataDirsFinal_CheckedChanged(object sender, EventArgs e) - { - ManagedMods.Instance.WriteDataDirs = this.checkBoxModsWriteSResourceDataDirsFinal.Checked; - IniFiles.Instance.Set(IniFile.Config, "Mods", "bWriteSResourceDataDirsFinal", this.checkBoxModsWriteSResourceDataDirsFinal.Checked); - IniFiles.Instance.SaveConfig(); - } /* - * Threads + ********************************************************************************** + * Threaded methods + ********************************************************************************** */ + #region Threaded methods - private void InstallModArchive(String path) - { - Invoke(() => DisableUI()); - Invoke(() => ProgressBarMarquee()); - ManagedMods.Instance.InstallModArchive(path, - (text, percent) => { - Invoke(() => Display(text)); - }, - (success) => { - Invoke(() => ProgressBarContinuous(100)); - Invoke(() => HideLabel()); - Invoke(() => EnableUI()); - Invoke(() => selectedIndex = ManagedMods.Instance.Mods.Count - 1); - Invoke(() => UpdateModList()); - Invoke(() => UpdateLabel(success)); + private void InstallModArchiveThreaded(string path, bool freeze) + { + RunThreaded(() => { + DisableUI(); + CloseSidePanel(); + }, () => { + try + { + ModInstallations.InstallArchive(Mods, path, freeze, UpdateProgress); + } + catch (Archive2RequirementsException exc) + { + MsgBox.ShowID("archive2InstallRequirements", MessageBoxIcon.Error); + UpdateProgress(Progress.Aborted("Archive2 installation requirements not met.", exc)); + return false; + } + catch (Archive2Exception exc) + { + MsgBox.ShowID("archive2Error", MessageBoxIcon.Error); + UpdateProgress(Progress.Aborted("Archive2 error", exc)); + return false; } - ); - } - - private void InstallModArchiveFrozen(String path) - { - Invoke(() => DisableUI()); - Invoke(() => ProgressBarMarquee()); - ManagedMods.Instance.InstallModArchiveFrozen(path, - (text, percent) => { - Invoke(() => Display(text)); - }, - (success) => { - Invoke(() => ProgressBarContinuous(100)); - Invoke(() => HideLabel()); - Invoke(() => EnableUI()); - Invoke(() => selectedIndex = ManagedMods.Instance.Mods.Count - 1); - Invoke(() => UpdateModList()); - Invoke(() => UpdateLabel(success)); + catch (NotSupportedException exc) + { + MsgBox.ShowID("modsArchiveTypeNotSupported", MessageBoxIcon.Error); + UpdateProgress(Progress.Aborted("Failed", exc)); + return false; } - ); - } - - private void InstallModFolder(String path) - { - Invoke(() => DisableUI()); - Invoke(() => ProgressBarContinuous(0)); - ManagedMods.Instance.InstallModFolder(path, - (text, percent) => { - Invoke(() => Display(text)); - Invoke(() => { if (percent >= 0) { ProgressBarContinuous(percent); } else { ProgressBarMarquee(); } }); - }, - (success) => { - Invoke(() => ProgressBarContinuous(100)); - Invoke(() => HideLabel()); - Invoke(() => EnableUI()); - Invoke(() => selectedIndex = ManagedMods.Instance.Mods.Count - 1); - Invoke(() => UpdateModList()); - Invoke(() => UpdateLabel(success)); + catch (Exception exc) + { + MsgBox.Get("failed").FormatText(exc.Message).Show(MessageBoxIcon.Error); + UpdateProgress(Progress.Aborted("Failed", exc)); + return false; } - ); + return true; + }, (success) => { + EnableUI(); + if (success) + { + selectedIndex = Mods.Count - 1; + selectedIndices.Clear(); + selectedIndices.Add(selectedIndex); + } + UpdateModList(); + UpdateStatusStrip(); + }); } - private void InstallBulk(String[] files) + private void InstallModFolderThreaded(string path) { - foreach (string filePath in files) - { - bool unpackBA2ByDefault = IniFiles.Instance.GetBool(IniFile.Config, "Mods", "bUnpackBA2ByDefault", false); - String fullFilePath = Path.GetFullPath(filePath); - if (fullFilePath.Length > 259 && Directory.Exists(@"\\?\" + fullFilePath)) - fullFilePath = @"\\?\" + fullFilePath; + RunThreaded(() => { + DisableUI(); + CloseSidePanel(); + }, () => { try { - if (Directory.Exists(fullFilePath)) - InstallModFolder(fullFilePath); - else if ((new String[] { ".zip", ".rar", ".7z", ".tar", ".tar.gz", ".gz" }).Contains(Path.GetExtension(fullFilePath))) - InstallModArchive(fullFilePath); - else if (Path.GetExtension(fullFilePath).ToLower() == ".ba2") - { - if (unpackBA2ByDefault) - InstallModArchive(fullFilePath); - else - InstallModArchiveFrozen(fullFilePath); - } - else - MsgBox.Get("modsArchiveTypeNotSupported").FormatText(Path.GetExtension(fullFilePath)).Show(MessageBoxIcon.Error); + ModInstallations.InstallFolder(Mods, path, UpdateProgress); + } + catch (Archive2RequirementsException exc) + { + MsgBox.ShowID("archive2InstallRequirements", MessageBoxIcon.Error); + UpdateProgress(Progress.Aborted("Archive2 installation requirements not met.", exc)); + return false; + } + catch (Archive2Exception exc) + { + MsgBox.ShowID("archive2Error", MessageBoxIcon.Error); + UpdateProgress(Progress.Aborted("Archive2 error", exc)); + return false; + } + catch (Exception exc) + { + MsgBox.Get("failed").FormatText(exc.Message).Show(MessageBoxIcon.Error); + UpdateProgress(Progress.Aborted("Failed", exc)); + return false; + } + return true; + }, (success) => { + EnableUI(); + if (success) + { + selectedIndex = Mods.Count - 1; + selectedIndices.Clear(); + selectedIndices.Add(selectedIndex); } - catch (FileNotFoundException exc) + UpdateModList(); + UpdateStatusStrip(); + }); + } + + private void InstallBulkThreaded(string[] files) + { + RunThreaded(() => { + DisableUI(); + CloseSidePanel(); + }, () => { + try + { + InstallBulk(files); + } + catch (Archive2RequirementsException exc) { - Console.WriteLine($"File not found: ({fullFilePath.Length}) {exc.Message}"); + MsgBox.ShowID("archive2InstallRequirements", MessageBoxIcon.Error); + UpdateProgress(Progress.Aborted("Archive2 installation requirements not met.", exc)); + return false; } + catch (Archive2Exception exc) + { + MsgBox.ShowID("archive2Error", MessageBoxIcon.Error); + UpdateProgress(Progress.Aborted("Archive2 error", exc)); + return false; + } + catch (NotSupportedException exc) + { + MsgBox.ShowID("modsArchiveTypeNotSupported", MessageBoxIcon.Error); + UpdateProgress(Progress.Aborted("Failed", exc)); + return false; + } + catch (Exception exc) + { + MsgBox.Get("failed").FormatText(exc.Message).Show(MessageBoxIcon.Error); + UpdateProgress(Progress.Aborted("Failed", exc)); + return false; + } + return true; + }, (success) => { + EnableUI(); + if (success) + { + selectedIndex = -1; + selectedIndices.Clear(); + UpdateProgress(Progress.Done("Mods imported.")); + } + UpdateModList(); + UpdateStatusStrip(); + }); + } + + private void InstallBulk(string[] files) + { + bool unpackBA2ByDefault = IniFiles.Config.GetBool("Mods", "bUnpackBA2ByDefault", false); + int i = 0; + foreach (string filePath in files) + { + UpdateProgress(Progress.Ongoing($"Importing {++i} of {files.Length} files/folders...", (float)i / (float)files.Length)); + string longFilePath = ModInstallations.EnsureLongPathSupport(filePath); + if (Directory.Exists(longFilePath)) + ModInstallations.InstallFolder(Mods, filePath); + else + ModInstallations.InstallArchive(Mods, filePath, !unpackBA2ByDefault); } } - private void UnfreezeBulkMods(List indices) + private void DeleteModThreaded(int index) { - Invoke(DisableUI); - ManagedMods.Instance.UnfreezeMods(indices, - (text, percent) => { - Invoke(() => Display(text)); - Invoke(() => { if (percent >= 0) { ProgressBarContinuous(percent); } else { ProgressBarMarquee(); } }); - }, - () => { - Invoke(() => EnableUI()); - Invoke(() => UpdateModList()); - Invoke(() => UpdateLabel()); + RunThreaded(() => { + CloseSidePanel(); + DisableUI(); + }, () => { + ModActions.DeleteMod(Mods, index, UpdateProgress); + return true; + }, (success) => { + EnableUI(); + if (success) + { + selectedIndex = -1; + selectedIndices.Clear(); } - ); + UpdateModList(); + UpdateStatusStrip(); + }); } - private void DeleteMod(int index) + private void DeleteModsBulkThreaded(List indices) { - Invoke(() => DisableUI()); - Invoke(() => ProgressBarMarquee()); - ManagedMods.Instance.DeleteMod(index, () => { - Invoke(() => ProgressBarContinuous(100)); - Invoke(() => EnableUI()); - Invoke(() => selectedIndex = -1); - Invoke(() => UpdateModList()); - Invoke(() => UpdateLabel()); + RunThreaded(() => { + CloseSidePanel(); + DisableUI(); + }, () => { + ModActions.DeleteMods(Mods, indices, UpdateProgress); + return true; + }, (success) => { + EnableUI(); + if (success) + { + selectedIndex = -1; + selectedIndices.Clear(); + } + UpdateModList(); + UpdateStatusStrip(); }); } - private void DeleteModsBulk(List indices) + private bool DeployMods() { - Invoke(() => DisableUI()); - Invoke(() => ProgressBarMarquee()); - ManagedMods.Instance.DeleteMods(indices, () => { - Invoke(() => ProgressBarContinuous(100)); - Invoke(() => EnableUI()); - Invoke(() => selectedIndex = -1); - Invoke(() => UpdateModList()); - Invoke(() => UpdateLabel()); + try + { + bool invalidateBundledFrozenArchives = true; + if (IniFiles.Config.GetBool("Mods", "bFreezeBundledArchives", false)) + invalidateBundledFrozenArchives = MsgBox.Get("modsRepackFrozenBundledArchives").Show(MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes; + ModDeployment.Deploy(Mods, UpdateProgress, invalidateBundledFrozenArchives); + } + catch (Archive2RequirementsException exc) + { + MsgBox.ShowID("archive2InstallRequirements", MessageBoxIcon.Error); + UpdateProgress(Progress.Aborted("Archive2 installation requirements not met.", exc)); + return false; + } + catch (Archive2Exception exc) + { + MsgBox.ShowID("archive2Error", MessageBoxIcon.Error); + UpdateProgress(Progress.Aborted("Archive2 error", exc)); + return false; + } + catch (Exception exc) + { + MsgBox.Get("failed").FormatText(exc.Message).Show(MessageBoxIcon.Error); + UpdateProgress(Progress.Aborted("Failed", exc)); + return false; + } + return true; + } + + private void DeployModsThreaded() + { + RunThreaded(() => { + CloseSidePanel(); + ShowLoadingUI(); + }, () => { + return DeployMods(); + }, (success) => { + if (success) + { + if (Mods.ModsDisabled) + MsgBox.Get("modsDisabledDone").Popup(MessageBoxIcon.Information); + else + MsgBox.Get("modsDeployedDone").Popup(MessageBoxIcon.Information); + } + else + { + MsgBox.Get("modsDeploymentFailed").Popup(MessageBoxIcon.Information); + } + UpdateUI(); + EnableUI(); }); } - public void Deploy() - { - Invoke(() => this.pictureBoxModsLoadingGIF.Visible = true); - Invoke(() => ShowLoadingUI()); - Invoke(() => ProgressBarContinuous(0)); - Invoke(() => Display("Deploying...")); - ManagedMods.Instance.Deploy( - (text, percent) => { - Invoke(() => Display(text)); - Invoke(() => { if (percent >= 0) { ProgressBarContinuous(percent); } else { ProgressBarMarquee(); } }); - }, - (success) => { - Invoke(() => { - UpdateUI(); - ProgressBarContinuous(100); - EnableUI(); - this.pictureBoxModsLoadingGIF.Visible = false; - - if (success) - { - DisplayAllDone(); + private void UpdateRemoteModInfoThreaded() + { + if (!NexusMods.User.IsLoggedIn) + { + MsgBox.ShowID("nexusModsNotLoggedIn", MessageBoxIcon.Information); + return; + } + RunThreaded(() => { + CloseSidePanel(); + ShowLoadingUI(); + }, () => { + UpdateRemoteModInfo(UpdateProgress); + return true; + }, (success) => { + EnableUI(); + UpdateUI(); + }); + } - if (ManagedMods.Instance.ModsDisabled) - MsgBox.Get("modsDisabledDone").Popup(MessageBoxIcon.Information); - else - MsgBox.Get("modsDeployedDone").Popup(MessageBoxIcon.Information); - } - else - { - DisplayFailState(); - MsgBox.Get("modsDeploymentFailed").Popup(MessageBoxIcon.Information); - } - }); + private void CheckForUpdatesThreaded() + { + if (!NexusMods.User.IsLoggedIn) + { + MsgBox.ShowID("nexusModsNotLoggedIn", MessageBoxIcon.Information); + return; + } + RunThreaded(() => { + CloseSidePanel(); + ShowLoadingUI(); + }, () => { + UpdateRemoteModInfo(UpdateProgress); + return true; + }, (success) => { + EnableUI(); + UpdateModList(); + UpdateStatusStrip(); + + // TODO: Check for updates could be so much better. + List modsWithUpdates = new List(); + foreach (ManagedMod mod in Mods) + if (mod.RemoteInfo != null && Utils.CompareVersions(mod.Version, mod.RemoteInfo.LatestVersion) < 0) + modsWithUpdates.Add($"{mod.Title} (updated from {mod.Version} to {mod.RemoteInfo.LatestVersion})"); + + if (modsWithUpdates.Count() > 0) + { + MsgBox.Show("Updates available", $"{modsWithUpdates.Count()} updates found:\n\n{String.Join("\n", modsWithUpdates)}", MessageBoxIcon.Information); + } + else + { + MsgBox.Show("Up to date", "No updates found.", MessageBoxIcon.Information); } - ); + }); + } + + private void EndorseModsThreaded() + { + if (!NexusMods.User.IsLoggedIn) + { + MsgBox.ShowID("nexusModsNotLoggedIn", MessageBoxIcon.Information); + return; + } + RunThreaded(() => { + CloseSidePanel(); + DisableUI(); + }, () => { + EndorseMods(UpdateProgress); + return true; + }, (success) => { + EnableUI(); + }); } - private void Invoke(Action func) + private void EndorseMods(Action ProgressChanged = null) { - this.progressBarMods.Invoke(func); + int i = 0; + foreach (ManagedMod mod in Mods) + { + i++; + if (mod.RemoteInfo != null && mod.Version != null && mod.Version != "" && mod.RemoteInfo.Endorsement != NMMod.EndorseStatus.Endorsed) + { + mod.RemoteInfo.Endorse(mod.Version); + ProgressChanged?.Invoke(Progress.Ongoing($"Endorsing \"{mod.Title}\"", (float)i / (float)Mods.Count())); + } + } + ProgressChanged?.Invoke(Progress.Done("All mods endorsed.")); } - private void ProgressBarMarquee() + private void UpdateRemoteModInfo(Action ProgressChanged = null) { - this.progressBarMods.Style = ProgressBarStyle.Marquee; - //this.progressBarMods.MarqueeAnimationSpeed = 15; + int i = 0; + int len = Mods.Count(); + List updatedIDs = new List(); + foreach (ManagedMod mod in Mods) + { + i++; + if (mod.URL != "") + { + // Don't update mods twice: + if (updatedIDs.Contains(mod.ID)) + continue; + updatedIDs.Add(mod.ID); + + // Don't update mods in quick succession (1 minute): + if (mod.RemoteInfo != null) + { + long lastUpdated = Utils.GetUnixTimeStamp() - mod.RemoteInfo.LastAccessTimestamp; + if (lastUpdated < 60) + continue; + } + + ProgressChanged?.Invoke(Progress.Ongoing($"[{i}/{len}] Requesting info for \"{mod.Title}\"", (float)i / (float)len)); + NexusMods.RequestModInformation(mod.URL); + } + } + ProgressChanged?.Invoke(Progress.Done("Mod information updated.")); + NexusMods.Save(); } - private void ProgressBarContinuous(int value) + private void ImportInstalledModsThreaded(Action ProgressChanged = null) { - this.progressBarMods.Style = ProgressBarStyle.Continuous; - this.progressBarMods.Value = Utils.Clamp(value, 0, 100); + RunThreaded(() => { + ShowLoadingUI(); + CloseSidePanel(); + }, () => { + ModInstallations.ImportInstalledMods(Mods, ProgressChanged); + return true; + }, (success) => { + EnableUI(); + }); } - private void HideLabel() + #endregion + + + /* + ********************************************************************************** + * Utility methods + ********************************************************************************** + */ + #region Utility methods + + private void RunThreaded(Action prepareWork, Func doWork, Action finishWork) { - this.labelModsDeploy.Visible = false; + Thread thread = new Thread(() => + { + this.Invoke(prepareWork); + bool result = doWork(); + this.Invoke(new Action(() => finishWork(result))); + }); + thread.IsBackground = true; + thread.Start(); } - private void Display(String text) + private void UpdateProgress(Progress progress) { - this.labelModsDeploy.ForeColor = Color.Black; - this.labelModsDeploy.Text = text; - this.labelModsDeploy.Visible = true; + this.progressBarMods.Invoke(new Action(() => { + this.labelModsDeploy.Visible = true; + progress.Update(labelModsDeploy, progressBarMods); + })); } private void DisplayDeploymentNecessary() { - this.labelModsDeploy.Visible = true; - this.labelModsDeploy.ForeColor = Color.Crimson; - this.labelModsDeploy.Text = Localization.GetString("modsDeploymentNecessary"); + this.toolStripStatusLabelDeploymentStatus.Visible = true; + this.toolStripStatusLabelDeploymentStatus.ForeColor = Color.Crimson; + this.toolStripStatusLabelDeploymentStatus.Text = Localization.GetString("modsDeploymentNecessary"); } private void DisplayAllDone() { - this.labelModsDeploy.Visible = true; - this.labelModsDeploy.ForeColor = Color.DarkGreen; - this.labelModsDeploy.Text = Localization.GetString("modsAllDone"); + this.toolStripStatusLabelDeploymentStatus.Visible = false; } - private void DisplayFailState() + private void UpdateStatusStrip() { - this.labelModsDeploy.Visible = true; - this.labelModsDeploy.ForeColor = Color.Red; - this.labelModsDeploy.Text = Localization.GetString("modsFailed"); + if (Mods.isDeploymentNecessary()) + this.DisplayDeploymentNecessary(); + else + this.DisplayAllDone(); + + this.toolStripStatusLabelModCount.Text = Mods.Count().ToString(); + + int enabledCount = 0; + foreach (ManagedMod mod in Mods) + if (mod.Enabled) + enabledCount++; + this.toolStripStatusLabelEnabledCount.Text = enabledCount.ToString(); } + + #endregion + } + + + public delegate void NuclearWinterEventHandler(object sender, NuclearWinterEventArgs e); + + public class NuclearWinterEventArgs : EventArgs + { + public bool NuclearWinterModeEnabled; } } diff --git a/Fo76ini/Forms/FormMods/FormMods.resx b/Fo76ini/Forms/FormMods/FormMods.resx index 75fb895..33151f7 100644 --- a/Fo76ini/Forms/FormMods/FormMods.resx +++ b/Fo76ini/Forms/FormMods/FormMods.resx @@ -118,7 +118,7 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - 17, 17 + 6, 11 @@ -138,48 +138,48 @@
- 132, 17 + 5, 63 - 222, 17 + 5, 37 iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 - YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAHDSURBVEhL5ZbNK0RhFMZPkoUkabKU5SRZSJIkTZLkL5lk - IQsrO02SJEmykpW1LCwkyUIpG1/jo0mThZWFhSSN33MdGePmmmsz5dTTec/X87zzvrd7x6LszKzjwmz3 - 3OwB/yhoTX4fdHtbPIOoBZL8ntkr/h7yO0HrolzS28s3hidBAaE1fOLIrFY4MWskXvFaxtujjR3pOFJF - 2BQJmCrKBYB4Al9gZqck3+l0X03HcWz2pKE/4hnRNqd9t0uzegRmQprjYkHH6PRmBM26tJDG2GDTrU4f - CNSRTPMrllTE74GxcsDcts+uckSjObMGp/80iv1qAoue+rUxM61ZyEc89d1KBfBpPSWgQ48nfh1s6M6o - JVXDj3tvtEDWrM/vIhBAcF5DIOWkVxDkdYH0dqmmI/HejOJ/IkDzkuI4AuSHFYdapQsEb4LKEKBxWXFF - CbCeVfyjAA29LrCiOI4AGFIcahQDgY8hSFshHCGf2DWrxqcgHkCgRi8zr7Wrl5k51j8L0NTjAlsi9HSk - FcyqENuQAH7Q099NuzpFx4/plvUN/sqRLUGQ954ceJG/NmtyunBjB/ouH4DgL8pvwdyhTsBp3MzeANnF - IIOkd+qKAAAAAElFTkSuQmCC + YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAHCSURBVEhL5ZbNK0RhFMZPkoUkSZaylGQhSZI0SZK/ZJKF + LKzsJEmSJk1Wspq1LCwkyUIpG1/jo0mThZWFhSSN33MdGTO3GXNtppx6Ou/5ep533vd271g5uzDruTLb + vzR7wj8LWpM/BP3eFs0gaocku2/2jn+E/EHQOi/X4e2VG8OzIIfQJr7lxKxeODNrJk56bcHbyxs70nHE + 8rAtEjCXlwsA8Qw+x8xeQb7X6X6ajuPU7EVDf8Qrol1O+2nXZo0ILIY0R8WqjtHpzQjadGkhjZHBpjud + PhBoIBnnVyRUxB+AqUrA3K7PbnBEkxmzJqf/NorDagJrnvq1MTOvWcgnPFVshQL4uJ4S0KPHE78FUroz + ah2q4ae9t7xA2mzI7yIQQHBFQyDmpDcQZHWB9PappiPx3gXF/0SA5oTiKALkxxWHWrULBG+C6hCgcV1x + VQmwXlJcUoCGQRdIKo4iAMYUhxrFQOBrCNJOCCfIt5CvxccgHkGgTi8zr3Wrl5ll1qUFaBpwgR0Rerqs + 5cxqEEtJAD/q6WLTrs7R8WO6Z32Hv3GkCxDkvScD3uRvzVqdLtzYgb7LRyD4i/JbMHesE3AaN7MPXQUg + Yy7JZ6QAAAAASUVORK5CYII= + + 5, 63 + - 327, 17 + 137, 46 - 486, 17 + 136, 119 - 674, 17 + 136, 77 - 864, 17 + 137, 16 - 17, 56 - - - 243, 56 + 136, 149 - - 491, 56 + + 6, 95 - 151 + 346 diff --git a/Fo76ini/Forms/FormSettings/FormSettings.Designer.cs b/Fo76ini/Forms/FormSettings/FormSettings.Designer.cs new file mode 100644 index 0000000..402daf6 --- /dev/null +++ b/Fo76ini/Forms/FormSettings/FormSettings.Designer.cs @@ -0,0 +1,1511 @@ +namespace Fo76ini.Forms.FormSettings +{ + partial class FormSettings + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + System.Windows.Forms.ListViewItem listViewItem6 = new System.Windows.Forms.ListViewItem("Default", 0); + System.Windows.Forms.ListViewItem listViewItem7 = new System.Windows.Forms.ListViewItem(new string[] { + "Steam"}, 2, System.Drawing.Color.Empty, System.Drawing.SystemColors.Window, null); + System.Windows.Forms.ListViewItem listViewItem8 = new System.Windows.Forms.ListViewItem("Bethesda.net", 1); + System.Windows.Forms.ListViewItem listViewItem9 = new System.Windows.Forms.ListViewItem("Bethesda.net PTS", 1); + System.Windows.Forms.ListViewItem listViewItem10 = new System.Windows.Forms.ListViewItem("Microsoft Store", 3); + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(FormSettings)); + this.tabControl1 = new System.Windows.Forms.TabControl(); + this.tabPageGeneral = new System.Windows.Forms.TabPage(); + this.groupBoxActions = new System.Windows.Forms.GroupBox(); + this.linkLabelEnableDangerZone = new System.Windows.Forms.LinkLabel(); + this.groupBoxOptions = new System.Windows.Forms.GroupBox(); + this.checkBoxReadOnly = new System.Windows.Forms.CheckBox(); + this.groupBoxNuclearWinterMode = new System.Windows.Forms.GroupBox(); + this.checkBoxNWAutoDeployMods = new System.Windows.Forms.CheckBox(); + this.labelNWmodoptions = new System.Windows.Forms.Label(); + this.labelNWdlloptions = new System.Windows.Forms.Label(); + this.checkBoxNWAutoDisableMods = new System.Windows.Forms.CheckBox(); + this.checkBoxNWRenameDLL = new System.Windows.Forms.CheckBox(); + this.groupBoxBehavior = new System.Windows.Forms.GroupBox(); + this.checkBoxPlayNotificationSound = new System.Windows.Forms.CheckBox(); + this.checkBoxIgnoreUpdates = new System.Windows.Forms.CheckBox(); + this.checkBoxQuitOnGameLaunch = new System.Windows.Forms.CheckBox(); + this.checkBoxAutoApply = new System.Windows.Forms.CheckBox(); + this.groupBoxLocalization = new System.Windows.Forms.GroupBox(); + this.buttonRefreshLanguage = new System.Windows.Forms.Button(); + this.pictureBoxSpinnerDownloadLanguages = new System.Windows.Forms.PictureBox(); + this.labelOutdatedLanguage = new System.Windows.Forms.Label(); + this.labelLanguage = new System.Windows.Forms.Label(); + this.buttonDownloadLanguages = new System.Windows.Forms.Button(); + this.comboBoxLanguage = new System.Windows.Forms.ComboBox(); + this.tabPageGameProfiles = new System.Windows.Forms.TabPage(); + this.panel1 = new System.Windows.Forms.Panel(); + this.groupBoxSettings = new System.Windows.Forms.GroupBox(); + this.panelSettings = new System.Windows.Forms.Panel(); + this.groupBox2 = new System.Windows.Forms.GroupBox(); + this.textBoxLaunchURL = new System.Windows.Forms.TextBox(); + this.labelLaunchURL = new System.Windows.Forms.Label(); + this.textBoxParameters = new System.Windows.Forms.TextBox(); + this.labelParameters = new System.Windows.Forms.Label(); + this.textBoxExecutable = new System.Windows.Forms.TextBox(); + this.labelExecutable = new System.Windows.Forms.Label(); + this.textBoxIniPrefix = new System.Windows.Forms.TextBox(); + this.labelIniPrefix = new System.Windows.Forms.Label(); + this.groupBoxLaunchOptions = new System.Windows.Forms.GroupBox(); + this.labelLaunchOptionMSStoreNotice = new System.Windows.Forms.Label(); + this.radioButtonLaunchViaExecutable = new System.Windows.Forms.RadioButton(); + this.radioButtonLaunchViaLink = new System.Windows.Forms.RadioButton(); + this.groupBoxGameLocation = new System.Windows.Forms.GroupBox(); + this.buttonAutoDetect = new System.Windows.Forms.Button(); + this.textBoxGamePath = new System.Windows.Forms.TextBox(); + this.buttonPickGamePath = new System.Windows.Forms.Button(); + this.groupBoxGameEdition = new System.Windows.Forms.GroupBox(); + this.radioButtonEditionUnknown = new System.Windows.Forms.RadioButton(); + this.pictureBoxUnknown = new System.Windows.Forms.PictureBox(); + this.pictureBoxMSStore = new System.Windows.Forms.PictureBox(); + this.pictureBoxSteam = new System.Windows.Forms.PictureBox(); + this.pictureBoxBethesdaNetPTS = new System.Windows.Forms.PictureBox(); + this.pictureBoxBethesdaNet = new System.Windows.Forms.PictureBox(); + this.radioButtonEditionMSStore = new System.Windows.Forms.RadioButton(); + this.radioButtonEditionBethesdaNetPTS = new System.Windows.Forms.RadioButton(); + this.radioButtonEditionSteam = new System.Windows.Forms.RadioButton(); + this.radioButtonEditionBethesdaNet = new System.Windows.Forms.RadioButton(); + this.groupBoxGame = new System.Windows.Forms.GroupBox(); + this.listViewGameInstances = new System.Windows.Forms.ListView(); + this.columnHeader1 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.contextMenuStripGame = new System.Windows.Forms.ContextMenuStrip(this.components); + this.gameToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.launchGameToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.toolStripSeparator2 = new System.Windows.Forms.ToolStripSeparator(); + this.renameGameToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.removeGameToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.imageList1 = new System.Windows.Forms.ImageList(this.components); + this.labelTip = new System.Windows.Forms.Label(); + this.toolStrip1 = new System.Windows.Forms.ToolStrip(); + this.toolStripButtonAddGame = new System.Windows.Forms.ToolStripButton(); + this.tabPageNexusMods = new System.Windows.Forms.TabPage(); + this.panel2 = new System.Windows.Forms.Panel(); + this.labelAPIKey = new System.Windows.Forms.Label(); + this.checkBoxShowAPIKey = new System.Windows.Forms.CheckBox(); + this.textBoxAPIKey = new System.Windows.Forms.TextBox(); + this.buttonNMLogin = new System.Windows.Forms.Button(); + this.buttonNWDeleteCache = new System.Windows.Forms.Button(); + this.buttonNWLogout = new System.Windows.Forms.Button(); + this.checkBoxNMDownloadThumbnails = new System.Windows.Forms.CheckBox(); + this.labelNMOptions = new System.Windows.Forms.Label(); + this.checkBoxNMUpdateProfile = new System.Windows.Forms.CheckBox(); + this.buttonNMUpdateProfile = new System.Windows.Forms.Button(); + this.panel3 = new System.Windows.Forms.Panel(); + this.labelNMNotLoggedIn = new System.Windows.Forms.Label(); + this.labelNMUserID = new System.Windows.Forms.Label(); + this.labelNMDescUserID = new System.Windows.Forms.Label(); + this.labelNMHourlyRateLimit = new System.Windows.Forms.Label(); + this.labelNMDescHourlyRateLimit = new System.Windows.Forms.Label(); + this.pictureBoxNMProfilePicture = new System.Windows.Forms.PictureBox(); + this.labelNMUserName = new System.Windows.Forms.Label(); + this.labelNMDescMembership = new System.Windows.Forms.Label(); + this.labelNMDailyRateLimitReset = new System.Windows.Forms.Label(); + this.labelNMMembership = new System.Windows.Forms.Label(); + this.labelNMDescLimitReset = new System.Windows.Forms.Label(); + this.labelNMDescDailyRateLimit = new System.Windows.Forms.Label(); + this.labelNMDailyRateLimit = new System.Windows.Forms.Label(); + this.toolTip = new System.Windows.Forms.ToolTip(this.components); + this.openFileDialogGamePath = new System.Windows.Forms.OpenFileDialog(); + this.backgroundWorkerDownloadLanguages = new System.ComponentModel.BackgroundWorker(); + this.backgroundWorkerRetrieveProfileInfo = new System.ComponentModel.BackgroundWorker(); + this.backgroundWorkerSSOLogin = new System.ComponentModel.BackgroundWorker(); + this.buttonNMLoginManually = new System.Windows.Forms.Button(); + this.linkLabelAPIKeyHelp = new System.Windows.Forms.LinkLabel(); + this.pictureBoxAPIKeyHelp = new System.Windows.Forms.PictureBox(); + this.label1 = new System.Windows.Forms.Label(); + this.tabControl1.SuspendLayout(); + this.tabPageGeneral.SuspendLayout(); + this.groupBoxActions.SuspendLayout(); + this.groupBoxOptions.SuspendLayout(); + this.groupBoxNuclearWinterMode.SuspendLayout(); + this.groupBoxBehavior.SuspendLayout(); + this.groupBoxLocalization.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBoxSpinnerDownloadLanguages)).BeginInit(); + this.tabPageGameProfiles.SuspendLayout(); + this.panel1.SuspendLayout(); + this.groupBoxSettings.SuspendLayout(); + this.panelSettings.SuspendLayout(); + this.groupBox2.SuspendLayout(); + this.groupBoxLaunchOptions.SuspendLayout(); + this.groupBoxGameLocation.SuspendLayout(); + this.groupBoxGameEdition.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBoxUnknown)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBoxMSStore)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBoxSteam)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBoxBethesdaNetPTS)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBoxBethesdaNet)).BeginInit(); + this.groupBoxGame.SuspendLayout(); + this.contextMenuStripGame.SuspendLayout(); + this.toolStrip1.SuspendLayout(); + this.tabPageNexusMods.SuspendLayout(); + this.panel2.SuspendLayout(); + this.panel3.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBoxNMProfilePicture)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBoxAPIKeyHelp)).BeginInit(); + this.SuspendLayout(); + // + // tabControl1 + // + this.tabControl1.Controls.Add(this.tabPageGeneral); + this.tabControl1.Controls.Add(this.tabPageGameProfiles); + this.tabControl1.Controls.Add(this.tabPageNexusMods); + this.tabControl1.Location = new System.Drawing.Point(12, 12); + this.tabControl1.Name = "tabControl1"; + this.tabControl1.SelectedIndex = 0; + this.tabControl1.Size = new System.Drawing.Size(774, 534); + this.tabControl1.TabIndex = 0; + // + // tabPageGeneral + // + this.tabPageGeneral.Controls.Add(this.groupBoxActions); + this.tabPageGeneral.Controls.Add(this.groupBoxOptions); + this.tabPageGeneral.Controls.Add(this.groupBoxNuclearWinterMode); + this.tabPageGeneral.Controls.Add(this.groupBoxBehavior); + this.tabPageGeneral.Controls.Add(this.groupBoxLocalization); + this.tabPageGeneral.Location = new System.Drawing.Point(4, 22); + this.tabPageGeneral.Name = "tabPageGeneral"; + this.tabPageGeneral.Padding = new System.Windows.Forms.Padding(3); + this.tabPageGeneral.Size = new System.Drawing.Size(766, 508); + this.tabPageGeneral.TabIndex = 0; + this.tabPageGeneral.Text = "General"; + this.tabPageGeneral.UseVisualStyleBackColor = true; + // + // groupBoxActions + // + this.groupBoxActions.Controls.Add(this.linkLabelEnableDangerZone); + this.groupBoxActions.Location = new System.Drawing.Point(6, 227); + this.groupBoxActions.Name = "groupBoxActions"; + this.groupBoxActions.Size = new System.Drawing.Size(390, 78); + this.groupBoxActions.TabIndex = 43; + this.groupBoxActions.TabStop = false; + this.groupBoxActions.Text = "Actions"; + // + // linkLabelEnableDangerZone + // + this.linkLabelEnableDangerZone.AutoSize = true; + this.linkLabelEnableDangerZone.LinkBehavior = System.Windows.Forms.LinkBehavior.HoverUnderline; + this.linkLabelEnableDangerZone.LinkColor = System.Drawing.Color.Red; + this.linkLabelEnableDangerZone.Location = new System.Drawing.Point(8, 18); + this.linkLabelEnableDangerZone.Name = "linkLabelEnableDangerZone"; + this.linkLabelEnableDangerZone.Size = new System.Drawing.Size(121, 13); + this.linkLabelEnableDangerZone.TabIndex = 44; + this.linkLabelEnableDangerZone.TabStop = true; + this.linkLabelEnableDangerZone.Text = "⚠️ Enable Danger Zone"; + this.linkLabelEnableDangerZone.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.linkLabelEnableDangerZone_LinkClicked); + // + // groupBoxOptions + // + this.groupBoxOptions.Controls.Add(this.checkBoxReadOnly); + this.groupBoxOptions.Location = new System.Drawing.Point(402, 6); + this.groupBoxOptions.Name = "groupBoxOptions"; + this.groupBoxOptions.Size = new System.Drawing.Size(358, 47); + this.groupBoxOptions.TabIndex = 42; + this.groupBoxOptions.TabStop = false; + this.groupBoxOptions.Text = "Options"; + // + // checkBoxReadOnly + // + this.checkBoxReadOnly.AutoSize = true; + this.checkBoxReadOnly.Location = new System.Drawing.Point(11, 19); + this.checkBoxReadOnly.Name = "checkBoxReadOnly"; + this.checkBoxReadOnly.Size = new System.Drawing.Size(140, 17); + this.checkBoxReadOnly.TabIndex = 4; + this.checkBoxReadOnly.Text = "Make *.ini files read-only"; + this.checkBoxReadOnly.UseVisualStyleBackColor = true; + // + // groupBoxNuclearWinterMode + // + this.groupBoxNuclearWinterMode.Controls.Add(this.checkBoxNWAutoDeployMods); + this.groupBoxNuclearWinterMode.Controls.Add(this.labelNWmodoptions); + this.groupBoxNuclearWinterMode.Controls.Add(this.labelNWdlloptions); + this.groupBoxNuclearWinterMode.Controls.Add(this.checkBoxNWAutoDisableMods); + this.groupBoxNuclearWinterMode.Controls.Add(this.checkBoxNWRenameDLL); + this.groupBoxNuclearWinterMode.Location = new System.Drawing.Point(402, 59); + this.groupBoxNuclearWinterMode.Name = "groupBoxNuclearWinterMode"; + this.groupBoxNuclearWinterMode.Size = new System.Drawing.Size(358, 162); + this.groupBoxNuclearWinterMode.TabIndex = 41; + this.groupBoxNuclearWinterMode.TabStop = false; + this.groupBoxNuclearWinterMode.Text = "Nuclear Winter options"; + // + // checkBoxNWAutoDeployMods + // + this.checkBoxNWAutoDeployMods.AutoSize = true; + this.checkBoxNWAutoDeployMods.Location = new System.Drawing.Point(10, 117); + this.checkBoxNWAutoDeployMods.Name = "checkBoxNWAutoDeployMods"; + this.checkBoxNWAutoDeployMods.Size = new System.Drawing.Size(221, 17); + this.checkBoxNWAutoDeployMods.TabIndex = 25; + this.checkBoxNWAutoDeployMods.Text = "Automatically deploy mods upon disabling"; + this.checkBoxNWAutoDeployMods.UseVisualStyleBackColor = true; + // + // labelNWmodoptions + // + this.labelNWmodoptions.AutoSize = true; + this.labelNWmodoptions.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.labelNWmodoptions.Location = new System.Drawing.Point(7, 76); + this.labelNWmodoptions.Name = "labelNWmodoptions"; + this.labelNWmodoptions.Size = new System.Drawing.Size(80, 13); + this.labelNWmodoptions.TabIndex = 24; + this.labelNWmodoptions.Text = "Mod options:"; + // + // labelNWdlloptions + // + this.labelNWdlloptions.AutoSize = true; + this.labelNWdlloptions.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.labelNWdlloptions.Location = new System.Drawing.Point(7, 23); + this.labelNWdlloptions.Name = "labelNWdlloptions"; + this.labelNWdlloptions.Size = new System.Drawing.Size(78, 13); + this.labelNWdlloptions.TabIndex = 23; + this.labelNWdlloptions.Text = "*.dll options:"; + // + // checkBoxNWAutoDisableMods + // + this.checkBoxNWAutoDisableMods.AutoSize = true; + this.checkBoxNWAutoDisableMods.Location = new System.Drawing.Point(10, 94); + this.checkBoxNWAutoDisableMods.Name = "checkBoxNWAutoDisableMods"; + this.checkBoxNWAutoDisableMods.Size = new System.Drawing.Size(224, 17); + this.checkBoxNWAutoDisableMods.TabIndex = 19; + this.checkBoxNWAutoDisableMods.Text = "Automatically remove mods upon enabling"; + this.checkBoxNWAutoDisableMods.UseVisualStyleBackColor = true; + // + // checkBoxNWRenameDLL + // + this.checkBoxNWRenameDLL.AutoSize = true; + this.checkBoxNWRenameDLL.Location = new System.Drawing.Point(10, 41); + this.checkBoxNWRenameDLL.Name = "checkBoxNWRenameDLL"; + this.checkBoxNWRenameDLL.Size = new System.Drawing.Size(140, 17); + this.checkBoxNWRenameDLL.TabIndex = 18; + this.checkBoxNWRenameDLL.Text = "Rename added *.dll files"; + this.checkBoxNWRenameDLL.UseVisualStyleBackColor = true; + // + // groupBoxBehavior + // + this.groupBoxBehavior.Controls.Add(this.checkBoxPlayNotificationSound); + this.groupBoxBehavior.Controls.Add(this.checkBoxIgnoreUpdates); + this.groupBoxBehavior.Controls.Add(this.checkBoxQuitOnGameLaunch); + this.groupBoxBehavior.Controls.Add(this.checkBoxAutoApply); + this.groupBoxBehavior.Location = new System.Drawing.Point(6, 103); + this.groupBoxBehavior.Name = "groupBoxBehavior"; + this.groupBoxBehavior.Size = new System.Drawing.Size(390, 118); + this.groupBoxBehavior.TabIndex = 32; + this.groupBoxBehavior.TabStop = false; + this.groupBoxBehavior.Text = "Behavior"; + // + // checkBoxPlayNotificationSound + // + this.checkBoxPlayNotificationSound.AutoSize = true; + this.checkBoxPlayNotificationSound.Location = new System.Drawing.Point(9, 89); + this.checkBoxPlayNotificationSound.Name = "checkBoxPlayNotificationSound"; + this.checkBoxPlayNotificationSound.Size = new System.Drawing.Size(132, 17); + this.checkBoxPlayNotificationSound.TabIndex = 25; + this.checkBoxPlayNotificationSound.Text = "Play notification sound"; + this.checkBoxPlayNotificationSound.UseVisualStyleBackColor = true; + // + // checkBoxIgnoreUpdates + // + this.checkBoxIgnoreUpdates.AutoSize = true; + this.checkBoxIgnoreUpdates.Location = new System.Drawing.Point(9, 66); + this.checkBoxIgnoreUpdates.Name = "checkBoxIgnoreUpdates"; + this.checkBoxIgnoreUpdates.Size = new System.Drawing.Size(143, 17); + this.checkBoxIgnoreUpdates.TabIndex = 24; + this.checkBoxIgnoreUpdates.Text = "Don\'t check for updates."; + this.checkBoxIgnoreUpdates.UseVisualStyleBackColor = true; + this.checkBoxIgnoreUpdates.CheckedChanged += new System.EventHandler(this.checkBoxIgnoreUpdates_CheckedChanged); + // + // checkBoxQuitOnGameLaunch + // + this.checkBoxQuitOnGameLaunch.AutoSize = true; + this.checkBoxQuitOnGameLaunch.Location = new System.Drawing.Point(9, 19); + this.checkBoxQuitOnGameLaunch.Name = "checkBoxQuitOnGameLaunch"; + this.checkBoxQuitOnGameLaunch.Size = new System.Drawing.Size(223, 17); + this.checkBoxQuitOnGameLaunch.TabIndex = 20; + this.checkBoxQuitOnGameLaunch.Text = "Close the tool when the game is launched"; + this.checkBoxQuitOnGameLaunch.UseVisualStyleBackColor = true; + // + // checkBoxAutoApply + // + this.checkBoxAutoApply.AutoSize = true; + this.checkBoxAutoApply.Location = new System.Drawing.Point(9, 42); + this.checkBoxAutoApply.Name = "checkBoxAutoApply"; + this.checkBoxAutoApply.Size = new System.Drawing.Size(354, 17); + this.checkBoxAutoApply.TabIndex = 21; + this.checkBoxAutoApply.Text = "Automatically apply changes when tool is closed or game is launched."; + this.checkBoxAutoApply.UseVisualStyleBackColor = true; + // + // groupBoxLocalization + // + this.groupBoxLocalization.Controls.Add(this.buttonRefreshLanguage); + this.groupBoxLocalization.Controls.Add(this.pictureBoxSpinnerDownloadLanguages); + this.groupBoxLocalization.Controls.Add(this.labelOutdatedLanguage); + this.groupBoxLocalization.Controls.Add(this.labelLanguage); + this.groupBoxLocalization.Controls.Add(this.buttonDownloadLanguages); + this.groupBoxLocalization.Controls.Add(this.comboBoxLanguage); + this.groupBoxLocalization.Location = new System.Drawing.Point(6, 6); + this.groupBoxLocalization.Name = "groupBoxLocalization"; + this.groupBoxLocalization.Size = new System.Drawing.Size(390, 91); + this.groupBoxLocalization.TabIndex = 31; + this.groupBoxLocalization.TabStop = false; + this.groupBoxLocalization.Text = "Localization"; + // + // buttonRefreshLanguage + // + this.buttonRefreshLanguage.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.buttonRefreshLanguage.BackColor = System.Drawing.Color.Transparent; + this.buttonRefreshLanguage.FlatAppearance.BorderColor = System.Drawing.Color.Gray; + this.buttonRefreshLanguage.FlatAppearance.BorderSize = 0; + this.buttonRefreshLanguage.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.buttonRefreshLanguage.Image = global::Fo76ini.Properties.Resources.available_updates; + this.buttonRefreshLanguage.Location = new System.Drawing.Point(351, 49); + this.buttonRefreshLanguage.Name = "buttonRefreshLanguage"; + this.buttonRefreshLanguage.Size = new System.Drawing.Size(32, 32); + this.buttonRefreshLanguage.TabIndex = 40; + this.toolTip.SetToolTip(this.buttonRefreshLanguage, "Refresh language list and reapply translation"); + this.buttonRefreshLanguage.UseVisualStyleBackColor = false; + this.buttonRefreshLanguage.Click += new System.EventHandler(this.buttonRefreshLanguage_Click); + // + // pictureBoxSpinnerDownloadLanguages + // + this.pictureBoxSpinnerDownloadLanguages.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.pictureBoxSpinnerDownloadLanguages.Image = global::Fo76ini.Properties.Resources.Spinner_24; + this.pictureBoxSpinnerDownloadLanguages.Location = new System.Drawing.Point(283, 53); + this.pictureBoxSpinnerDownloadLanguages.Name = "pictureBoxSpinnerDownloadLanguages"; + this.pictureBoxSpinnerDownloadLanguages.Size = new System.Drawing.Size(24, 24); + this.pictureBoxSpinnerDownloadLanguages.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom; + this.pictureBoxSpinnerDownloadLanguages.TabIndex = 40; + this.pictureBoxSpinnerDownloadLanguages.TabStop = false; + this.pictureBoxSpinnerDownloadLanguages.Visible = false; + // + // labelOutdatedLanguage + // + this.labelOutdatedLanguage.AutoSize = true; + this.labelOutdatedLanguage.ForeColor = System.Drawing.Color.Firebrick; + this.labelOutdatedLanguage.Location = new System.Drawing.Point(8, 53); + this.labelOutdatedLanguage.Name = "labelOutdatedLanguage"; + this.labelOutdatedLanguage.Size = new System.Drawing.Size(209, 26); + this.labelOutdatedLanguage.TabIndex = 21; + this.labelOutdatedLanguage.Text = "This translation is out-dated.\r\nSome elements might not be translated yet."; + // + // labelLanguage + // + this.labelLanguage.AutoSize = true; + this.labelLanguage.Location = new System.Drawing.Point(7, 25); + this.labelLanguage.Name = "labelLanguage"; + this.labelLanguage.Size = new System.Drawing.Size(58, 13); + this.labelLanguage.TabIndex = 16; + this.labelLanguage.Text = "Language:"; + // + // buttonDownloadLanguages + // + this.buttonDownloadLanguages.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.buttonDownloadLanguages.FlatAppearance.BorderColor = System.Drawing.Color.Gray; + this.buttonDownloadLanguages.FlatAppearance.BorderSize = 0; + this.buttonDownloadLanguages.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.buttonDownloadLanguages.Image = global::Fo76ini.Properties.Resources.download_2_24; + this.buttonDownloadLanguages.Location = new System.Drawing.Point(313, 49); + this.buttonDownloadLanguages.Name = "buttonDownloadLanguages"; + this.buttonDownloadLanguages.Size = new System.Drawing.Size(32, 32); + this.buttonDownloadLanguages.TabIndex = 20; + this.toolTip.SetToolTip(this.buttonDownloadLanguages, "Download / update language files"); + this.buttonDownloadLanguages.UseVisualStyleBackColor = true; + this.buttonDownloadLanguages.Click += new System.EventHandler(this.buttonDownloadLanguages_Click); + // + // comboBoxLanguage + // + this.comboBoxLanguage.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.comboBoxLanguage.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.comboBoxLanguage.FormattingEnabled = true; + this.comboBoxLanguage.Location = new System.Drawing.Point(117, 22); + this.comboBoxLanguage.Name = "comboBoxLanguage"; + this.comboBoxLanguage.Size = new System.Drawing.Size(266, 21); + this.comboBoxLanguage.TabIndex = 17; + // + // tabPageGameProfiles + // + this.tabPageGameProfiles.Controls.Add(this.panel1); + this.tabPageGameProfiles.Controls.Add(this.toolStrip1); + this.tabPageGameProfiles.Location = new System.Drawing.Point(4, 22); + this.tabPageGameProfiles.Name = "tabPageGameProfiles"; + this.tabPageGameProfiles.Padding = new System.Windows.Forms.Padding(3); + this.tabPageGameProfiles.Size = new System.Drawing.Size(766, 508); + this.tabPageGameProfiles.TabIndex = 1; + this.tabPageGameProfiles.Text = "Game profiles"; + this.tabPageGameProfiles.UseVisualStyleBackColor = true; + // + // panel1 + // + this.panel1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.panel1.Controls.Add(this.groupBoxSettings); + this.panel1.Controls.Add(this.groupBoxGame); + this.panel1.Controls.Add(this.labelTip); + this.panel1.Location = new System.Drawing.Point(3, 39); + this.panel1.Margin = new System.Windows.Forms.Padding(0); + this.panel1.Name = "panel1"; + this.panel1.Size = new System.Drawing.Size(760, 466); + this.panel1.TabIndex = 20; + // + // groupBoxSettings + // + this.groupBoxSettings.Controls.Add(this.panelSettings); + this.groupBoxSettings.Location = new System.Drawing.Point(348, 8); + this.groupBoxSettings.Name = "groupBoxSettings"; + this.groupBoxSettings.Size = new System.Drawing.Size(404, 419); + this.groupBoxSettings.TabIndex = 45; + this.groupBoxSettings.TabStop = false; + this.groupBoxSettings.Text = "Settings"; + // + // panelSettings + // + this.panelSettings.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.panelSettings.AutoScroll = true; + this.panelSettings.AutoScrollMargin = new System.Drawing.Size(0, 8); + this.panelSettings.BackColor = System.Drawing.SystemColors.Window; + this.panelSettings.Controls.Add(this.groupBox2); + this.panelSettings.Controls.Add(this.groupBoxLaunchOptions); + this.panelSettings.Controls.Add(this.groupBoxGameLocation); + this.panelSettings.Controls.Add(this.groupBoxGameEdition); + this.panelSettings.Location = new System.Drawing.Point(2, 14); + this.panelSettings.Name = "panelSettings"; + this.panelSettings.Size = new System.Drawing.Size(401, 402); + this.panelSettings.TabIndex = 39; + // + // groupBox2 + // + this.groupBox2.Controls.Add(this.textBoxLaunchURL); + this.groupBox2.Controls.Add(this.labelLaunchURL); + this.groupBox2.Controls.Add(this.textBoxParameters); + this.groupBox2.Controls.Add(this.labelParameters); + this.groupBox2.Controls.Add(this.textBoxExecutable); + this.groupBox2.Controls.Add(this.labelExecutable); + this.groupBox2.Controls.Add(this.textBoxIniPrefix); + this.groupBox2.Controls.Add(this.labelIniPrefix); + this.groupBox2.Location = new System.Drawing.Point(7, 397); + this.groupBox2.Name = "groupBox2"; + this.groupBox2.Size = new System.Drawing.Size(369, 128); + this.groupBox2.TabIndex = 38; + this.groupBox2.TabStop = false; + this.groupBox2.Text = "Advanced"; + // + // textBoxLaunchURL + // + this.textBoxLaunchURL.Location = new System.Drawing.Point(112, 95); + this.textBoxLaunchURL.Name = "textBoxLaunchURL"; + this.textBoxLaunchURL.Size = new System.Drawing.Size(251, 20); + this.textBoxLaunchURL.TabIndex = 7; + this.textBoxLaunchURL.TextChanged += new System.EventHandler(this.textBoxLaunchURL_TextChanged); + // + // labelLaunchURL + // + this.labelLaunchURL.AutoSize = true; + this.labelLaunchURL.Location = new System.Drawing.Point(8, 98); + this.labelLaunchURL.Name = "labelLaunchURL"; + this.labelLaunchURL.Size = new System.Drawing.Size(71, 13); + this.labelLaunchURL.TabIndex = 6; + this.labelLaunchURL.Text = "Launch URL:"; + // + // textBoxParameters + // + this.textBoxParameters.Location = new System.Drawing.Point(112, 69); + this.textBoxParameters.Name = "textBoxParameters"; + this.textBoxParameters.Size = new System.Drawing.Size(251, 20); + this.textBoxParameters.TabIndex = 5; + this.textBoxParameters.TextChanged += new System.EventHandler(this.textBoxParameters_TextChanged); + // + // labelParameters + // + this.labelParameters.AutoSize = true; + this.labelParameters.Location = new System.Drawing.Point(8, 72); + this.labelParameters.Name = "labelParameters"; + this.labelParameters.Size = new System.Drawing.Size(63, 13); + this.labelParameters.TabIndex = 4; + this.labelParameters.Text = "Parameters:"; + // + // textBoxExecutable + // + this.textBoxExecutable.Location = new System.Drawing.Point(112, 43); + this.textBoxExecutable.Name = "textBoxExecutable"; + this.textBoxExecutable.Size = new System.Drawing.Size(251, 20); + this.textBoxExecutable.TabIndex = 3; + this.textBoxExecutable.Text = "Fallout76.exe"; + this.textBoxExecutable.TextChanged += new System.EventHandler(this.textBoxExecutable_TextChanged); + // + // labelExecutable + // + this.labelExecutable.AutoSize = true; + this.labelExecutable.Location = new System.Drawing.Point(7, 46); + this.labelExecutable.Name = "labelExecutable"; + this.labelExecutable.Size = new System.Drawing.Size(63, 13); + this.labelExecutable.TabIndex = 2; + this.labelExecutable.Text = "Executable:"; + // + // textBoxIniPrefix + // + this.textBoxIniPrefix.Location = new System.Drawing.Point(112, 17); + this.textBoxIniPrefix.Name = "textBoxIniPrefix"; + this.textBoxIniPrefix.Size = new System.Drawing.Size(251, 20); + this.textBoxIniPrefix.TabIndex = 1; + this.textBoxIniPrefix.Text = "Fallout76"; + this.textBoxIniPrefix.TextChanged += new System.EventHandler(this.textBoxIniPrefix_TextChanged); + // + // labelIniPrefix + // + this.labelIniPrefix.AutoSize = true; + this.labelIniPrefix.Location = new System.Drawing.Point(7, 20); + this.labelIniPrefix.Name = "labelIniPrefix"; + this.labelIniPrefix.Size = new System.Drawing.Size(56, 13); + this.labelIniPrefix.TabIndex = 0; + this.labelIniPrefix.Text = "*.ini Prefix:"; + // + // groupBoxLaunchOptions + // + this.groupBoxLaunchOptions.Controls.Add(this.labelLaunchOptionMSStoreNotice); + this.groupBoxLaunchOptions.Controls.Add(this.radioButtonLaunchViaExecutable); + this.groupBoxLaunchOptions.Controls.Add(this.radioButtonLaunchViaLink); + this.groupBoxLaunchOptions.Location = new System.Drawing.Point(7, 283); + this.groupBoxLaunchOptions.Name = "groupBoxLaunchOptions"; + this.groupBoxLaunchOptions.Size = new System.Drawing.Size(369, 108); + this.groupBoxLaunchOptions.TabIndex = 36; + this.groupBoxLaunchOptions.TabStop = false; + this.groupBoxLaunchOptions.Text = "Launch options"; + // + // labelLaunchOptionMSStoreNotice + // + this.labelLaunchOptionMSStoreNotice.ForeColor = System.Drawing.Color.Red; + this.labelLaunchOptionMSStoreNotice.Location = new System.Drawing.Point(7, 68); + this.labelLaunchOptionMSStoreNotice.Name = "labelLaunchOptionMSStoreNotice"; + this.labelLaunchOptionMSStoreNotice.Size = new System.Drawing.Size(356, 29); + this.labelLaunchOptionMSStoreNotice.TabIndex = 4; + this.labelLaunchOptionMSStoreNotice.Text = "Fallout 76 cannot be run directly, if installed through the Microsoft Store."; + this.labelLaunchOptionMSStoreNotice.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + this.labelLaunchOptionMSStoreNotice.Visible = false; + // + // radioButtonLaunchViaExecutable + // + this.radioButtonLaunchViaExecutable.AutoSize = true; + this.radioButtonLaunchViaExecutable.Location = new System.Drawing.Point(10, 43); + this.radioButtonLaunchViaExecutable.Name = "radioButtonLaunchViaExecutable"; + this.radioButtonLaunchViaExecutable.Size = new System.Drawing.Size(157, 17); + this.radioButtonLaunchViaExecutable.TabIndex = 1; + this.radioButtonLaunchViaExecutable.TabStop = true; + this.radioButtonLaunchViaExecutable.Text = "Run \"Fallout76.exe\" directly"; + this.radioButtonLaunchViaExecutable.UseVisualStyleBackColor = true; + this.radioButtonLaunchViaExecutable.CheckedChanged += new System.EventHandler(this.radioButtonLaunchViaExecutable_CheckedChanged); + // + // radioButtonLaunchViaLink + // + this.radioButtonLaunchViaLink.AutoSize = true; + this.radioButtonLaunchViaLink.Location = new System.Drawing.Point(10, 20); + this.radioButtonLaunchViaLink.Name = "radioButtonLaunchViaLink"; + this.radioButtonLaunchViaLink.Size = new System.Drawing.Size(261, 17); + this.radioButtonLaunchViaLink.TabIndex = 0; + this.radioButtonLaunchViaLink.TabStop = true; + this.radioButtonLaunchViaLink.Text = "Launch via Steam / Bethesda.net (recommended)"; + this.radioButtonLaunchViaLink.UseVisualStyleBackColor = true; + this.radioButtonLaunchViaLink.CheckedChanged += new System.EventHandler(this.radioButtonLaunchViaLink_CheckedChanged); + // + // groupBoxGameLocation + // + this.groupBoxGameLocation.Controls.Add(this.buttonAutoDetect); + this.groupBoxGameLocation.Controls.Add(this.textBoxGamePath); + this.groupBoxGameLocation.Controls.Add(this.buttonPickGamePath); + this.groupBoxGameLocation.Location = new System.Drawing.Point(7, 190); + this.groupBoxGameLocation.Name = "groupBoxGameLocation"; + this.groupBoxGameLocation.Size = new System.Drawing.Size(369, 87); + this.groupBoxGameLocation.TabIndex = 37; + this.groupBoxGameLocation.TabStop = false; + this.groupBoxGameLocation.Text = "Game location"; + // + // buttonAutoDetect + // + this.buttonAutoDetect.Location = new System.Drawing.Point(6, 48); + this.buttonAutoDetect.Name = "buttonAutoDetect"; + this.buttonAutoDetect.Size = new System.Drawing.Size(357, 23); + this.buttonAutoDetect.TabIndex = 32; + this.buttonAutoDetect.Text = "Attempt auto-detect"; + this.buttonAutoDetect.UseVisualStyleBackColor = true; + this.buttonAutoDetect.Click += new System.EventHandler(this.buttonAutoDetect_Click); + // + // textBoxGamePath + // + this.textBoxGamePath.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.textBoxGamePath.Location = new System.Drawing.Point(6, 21); + this.textBoxGamePath.Name = "textBoxGamePath"; + this.textBoxGamePath.Size = new System.Drawing.Size(323, 20); + this.textBoxGamePath.TabIndex = 30; + this.textBoxGamePath.TextChanged += new System.EventHandler(this.textBoxGamePath_TextChanged); + // + // buttonPickGamePath + // + this.buttonPickGamePath.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.buttonPickGamePath.Location = new System.Drawing.Point(335, 19); + this.buttonPickGamePath.Name = "buttonPickGamePath"; + this.buttonPickGamePath.Size = new System.Drawing.Size(28, 23); + this.buttonPickGamePath.TabIndex = 31; + this.buttonPickGamePath.Text = "..."; + this.buttonPickGamePath.UseVisualStyleBackColor = true; + this.buttonPickGamePath.Click += new System.EventHandler(this.buttonPickGamePath_Click); + // + // groupBoxGameEdition + // + this.groupBoxGameEdition.Controls.Add(this.radioButtonEditionUnknown); + this.groupBoxGameEdition.Controls.Add(this.pictureBoxUnknown); + this.groupBoxGameEdition.Controls.Add(this.pictureBoxMSStore); + this.groupBoxGameEdition.Controls.Add(this.pictureBoxSteam); + this.groupBoxGameEdition.Controls.Add(this.pictureBoxBethesdaNetPTS); + this.groupBoxGameEdition.Controls.Add(this.pictureBoxBethesdaNet); + this.groupBoxGameEdition.Controls.Add(this.radioButtonEditionMSStore); + this.groupBoxGameEdition.Controls.Add(this.radioButtonEditionBethesdaNetPTS); + this.groupBoxGameEdition.Controls.Add(this.radioButtonEditionSteam); + this.groupBoxGameEdition.Controls.Add(this.radioButtonEditionBethesdaNet); + this.groupBoxGameEdition.Location = new System.Drawing.Point(7, 9); + this.groupBoxGameEdition.Name = "groupBoxGameEdition"; + this.groupBoxGameEdition.Size = new System.Drawing.Size(369, 175); + this.groupBoxGameEdition.TabIndex = 35; + this.groupBoxGameEdition.TabStop = false; + this.groupBoxGameEdition.Text = "Game edition"; + // + // radioButtonEditionUnknown + // + this.radioButtonEditionUnknown.AutoSize = true; + this.radioButtonEditionUnknown.Location = new System.Drawing.Point(43, 142); + this.radioButtonEditionUnknown.Name = "radioButtonEditionUnknown"; + this.radioButtonEditionUnknown.Size = new System.Drawing.Size(51, 17); + this.radioButtonEditionUnknown.TabIndex = 31; + this.radioButtonEditionUnknown.Text = "Other"; + this.radioButtonEditionUnknown.UseVisualStyleBackColor = true; + this.radioButtonEditionUnknown.CheckedChanged += new System.EventHandler(this.radioButtonEditionUnknown_CheckedChanged); + // + // pictureBoxUnknown + // + this.pictureBoxUnknown.BackColor = System.Drawing.Color.Transparent; + this.pictureBoxUnknown.Image = global::Fo76ini.Properties.Resources.help_24; + this.pictureBoxUnknown.Location = new System.Drawing.Point(11, 139); + this.pictureBoxUnknown.Name = "pictureBoxUnknown"; + this.pictureBoxUnknown.Size = new System.Drawing.Size(24, 24); + this.pictureBoxUnknown.TabIndex = 30; + this.pictureBoxUnknown.TabStop = false; + // + // pictureBoxMSStore + // + this.pictureBoxMSStore.BackColor = System.Drawing.Color.Transparent; + this.pictureBoxMSStore.Image = global::Fo76ini.Properties.Resources.msstore_24; + this.pictureBoxMSStore.Location = new System.Drawing.Point(11, 109); + this.pictureBoxMSStore.Name = "pictureBoxMSStore"; + this.pictureBoxMSStore.Size = new System.Drawing.Size(24, 24); + this.pictureBoxMSStore.TabIndex = 29; + this.pictureBoxMSStore.TabStop = false; + // + // pictureBoxSteam + // + this.pictureBoxSteam.BackColor = System.Drawing.Color.Transparent; + this.pictureBoxSteam.Image = global::Fo76ini.Properties.Resources.steam_24px; + this.pictureBoxSteam.Location = new System.Drawing.Point(11, 79); + this.pictureBoxSteam.Name = "pictureBoxSteam"; + this.pictureBoxSteam.Size = new System.Drawing.Size(24, 24); + this.pictureBoxSteam.TabIndex = 28; + this.pictureBoxSteam.TabStop = false; + // + // pictureBoxBethesdaNetPTS + // + this.pictureBoxBethesdaNetPTS.BackColor = System.Drawing.Color.Transparent; + this.pictureBoxBethesdaNetPTS.Image = global::Fo76ini.Properties.Resources.bethesda_24; + this.pictureBoxBethesdaNetPTS.Location = new System.Drawing.Point(11, 49); + this.pictureBoxBethesdaNetPTS.Name = "pictureBoxBethesdaNetPTS"; + this.pictureBoxBethesdaNetPTS.Size = new System.Drawing.Size(24, 24); + this.pictureBoxBethesdaNetPTS.TabIndex = 27; + this.pictureBoxBethesdaNetPTS.TabStop = false; + // + // pictureBoxBethesdaNet + // + this.pictureBoxBethesdaNet.BackColor = System.Drawing.Color.Transparent; + this.pictureBoxBethesdaNet.Image = global::Fo76ini.Properties.Resources.bethesda_24; + this.pictureBoxBethesdaNet.Location = new System.Drawing.Point(11, 19); + this.pictureBoxBethesdaNet.Name = "pictureBoxBethesdaNet"; + this.pictureBoxBethesdaNet.Size = new System.Drawing.Size(24, 24); + this.pictureBoxBethesdaNet.TabIndex = 26; + this.pictureBoxBethesdaNet.TabStop = false; + // + // radioButtonEditionMSStore + // + this.radioButtonEditionMSStore.AutoSize = true; + this.radioButtonEditionMSStore.Location = new System.Drawing.Point(43, 112); + this.radioButtonEditionMSStore.Name = "radioButtonEditionMSStore"; + this.radioButtonEditionMSStore.Size = new System.Drawing.Size(188, 17); + this.radioButtonEditionMSStore.TabIndex = 3; + this.radioButtonEditionMSStore.Text = "Microsoft Store / Xbox Game Pass"; + this.radioButtonEditionMSStore.UseVisualStyleBackColor = true; + this.radioButtonEditionMSStore.CheckedChanged += new System.EventHandler(this.radioButtonEditionMSStore_CheckedChanged); + // + // radioButtonEditionBethesdaNetPTS + // + this.radioButtonEditionBethesdaNetPTS.AutoSize = true; + this.radioButtonEditionBethesdaNetPTS.Location = new System.Drawing.Point(43, 52); + this.radioButtonEditionBethesdaNetPTS.Name = "radioButtonEditionBethesdaNetPTS"; + this.radioButtonEditionBethesdaNetPTS.Size = new System.Drawing.Size(118, 17); + this.radioButtonEditionBethesdaNetPTS.TabIndex = 2; + this.radioButtonEditionBethesdaNetPTS.Text = "Bethesda.net (PTS)"; + this.radioButtonEditionBethesdaNetPTS.UseVisualStyleBackColor = true; + this.radioButtonEditionBethesdaNetPTS.CheckedChanged += new System.EventHandler(this.radioButtonEditionBethesdaNetPTS_CheckedChanged); + // + // radioButtonEditionSteam + // + this.radioButtonEditionSteam.AutoSize = true; + this.radioButtonEditionSteam.Location = new System.Drawing.Point(43, 82); + this.radioButtonEditionSteam.Name = "radioButtonEditionSteam"; + this.radioButtonEditionSteam.Size = new System.Drawing.Size(55, 17); + this.radioButtonEditionSteam.TabIndex = 1; + this.radioButtonEditionSteam.Text = "Steam"; + this.radioButtonEditionSteam.UseVisualStyleBackColor = true; + this.radioButtonEditionSteam.CheckedChanged += new System.EventHandler(this.radioButtonEditionSteam_CheckedChanged); + // + // radioButtonEditionBethesdaNet + // + this.radioButtonEditionBethesdaNet.AutoSize = true; + this.radioButtonEditionBethesdaNet.Location = new System.Drawing.Point(43, 22); + this.radioButtonEditionBethesdaNet.Name = "radioButtonEditionBethesdaNet"; + this.radioButtonEditionBethesdaNet.Size = new System.Drawing.Size(88, 17); + this.radioButtonEditionBethesdaNet.TabIndex = 0; + this.radioButtonEditionBethesdaNet.Text = "Bethesda.net"; + this.radioButtonEditionBethesdaNet.UseVisualStyleBackColor = true; + this.radioButtonEditionBethesdaNet.CheckedChanged += new System.EventHandler(this.radioButtonEditionBethesdaNet_CheckedChanged); + // + // groupBoxGame + // + this.groupBoxGame.Controls.Add(this.listViewGameInstances); + this.groupBoxGame.Location = new System.Drawing.Point(3, 8); + this.groupBoxGame.Name = "groupBoxGame"; + this.groupBoxGame.Size = new System.Drawing.Size(339, 419); + this.groupBoxGame.TabIndex = 44; + this.groupBoxGame.TabStop = false; + this.groupBoxGame.Text = "Game"; + // + // listViewGameInstances + // + this.listViewGameInstances.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.listViewGameInstances.BorderStyle = System.Windows.Forms.BorderStyle.None; + this.listViewGameInstances.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.columnHeader1}); + this.listViewGameInstances.ContextMenuStrip = this.contextMenuStripGame; + this.listViewGameInstances.Font = new System.Drawing.Font("Microsoft Sans Serif", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.listViewGameInstances.FullRowSelect = true; + this.listViewGameInstances.HideSelection = false; + this.listViewGameInstances.Items.AddRange(new System.Windows.Forms.ListViewItem[] { + listViewItem6, + listViewItem7, + listViewItem8, + listViewItem9, + listViewItem10}); + this.listViewGameInstances.LabelWrap = false; + this.listViewGameInstances.LargeImageList = this.imageList1; + this.listViewGameInstances.Location = new System.Drawing.Point(3, 18); + this.listViewGameInstances.MultiSelect = false; + this.listViewGameInstances.Name = "listViewGameInstances"; + this.listViewGameInstances.Size = new System.Drawing.Size(333, 398); + this.listViewGameInstances.SmallImageList = this.imageList1; + this.listViewGameInstances.TabIndex = 21; + this.listViewGameInstances.UseCompatibleStateImageBehavior = false; + this.listViewGameInstances.View = System.Windows.Forms.View.Details; + this.listViewGameInstances.SelectedIndexChanged += new System.EventHandler(this.listViewGameInstances_SelectedIndexChanged); + // + // columnHeader1 + // + this.columnHeader1.Text = "Game"; + this.columnHeader1.Width = 312; + // + // contextMenuStripGame + // + this.contextMenuStripGame.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.gameToolStripMenuItem, + this.launchGameToolStripMenuItem, + this.toolStripSeparator2, + this.renameGameToolStripMenuItem, + this.removeGameToolStripMenuItem}); + this.contextMenuStripGame.Name = "contextMenuStripGame"; + this.contextMenuStripGame.Size = new System.Drawing.Size(118, 98); + this.contextMenuStripGame.Opening += new System.ComponentModel.CancelEventHandler(this.contextMenuStripGame_Opening); + // + // gameToolStripMenuItem + // + this.gameToolStripMenuItem.Enabled = false; + this.gameToolStripMenuItem.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Italic, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.gameToolStripMenuItem.Name = "gameToolStripMenuItem"; + this.gameToolStripMenuItem.Size = new System.Drawing.Size(117, 22); + this.gameToolStripMenuItem.Text = "Game"; + // + // launchGameToolStripMenuItem + // + this.launchGameToolStripMenuItem.Image = global::Fo76ini.Properties.Resources.play; + this.launchGameToolStripMenuItem.Name = "launchGameToolStripMenuItem"; + this.launchGameToolStripMenuItem.Size = new System.Drawing.Size(117, 22); + this.launchGameToolStripMenuItem.Text = "Launch"; + this.launchGameToolStripMenuItem.Click += new System.EventHandler(this.launchGameToolStripMenuItem_Click); + // + // toolStripSeparator2 + // + this.toolStripSeparator2.Name = "toolStripSeparator2"; + this.toolStripSeparator2.Size = new System.Drawing.Size(114, 6); + // + // renameGameToolStripMenuItem + // + this.renameGameToolStripMenuItem.Image = global::Fo76ini.Properties.Resources.text_24; + this.renameGameToolStripMenuItem.Name = "renameGameToolStripMenuItem"; + this.renameGameToolStripMenuItem.Size = new System.Drawing.Size(117, 22); + this.renameGameToolStripMenuItem.Text = "Rename"; + this.renameGameToolStripMenuItem.Click += new System.EventHandler(this.renameGameToolStripMenuItem_Click); + // + // removeGameToolStripMenuItem + // + this.removeGameToolStripMenuItem.Image = global::Fo76ini.Properties.Resources.delete_24; + this.removeGameToolStripMenuItem.Name = "removeGameToolStripMenuItem"; + this.removeGameToolStripMenuItem.Size = new System.Drawing.Size(117, 22); + this.removeGameToolStripMenuItem.Text = "Remove"; + this.removeGameToolStripMenuItem.Click += new System.EventHandler(this.removeGameToolStripMenuItem_Click); + // + // imageList1 + // + this.imageList1.ImageStream = ((System.Windows.Forms.ImageListStreamer)(resources.GetObject("imageList1.ImageStream"))); + this.imageList1.TransparentColor = System.Drawing.Color.Transparent; + this.imageList1.Images.SetKeyName(0, "help-24.png"); + this.imageList1.Images.SetKeyName(1, "bethesda_24px.png"); + this.imageList1.Images.SetKeyName(2, "steam_24px.png"); + this.imageList1.Images.SetKeyName(3, "msstore_24px.png"); + // + // labelTip + // + this.labelTip.AutoSize = true; + this.labelTip.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.labelTip.ForeColor = System.Drawing.Color.DimGray; + this.labelTip.Location = new System.Drawing.Point(8, 443); + this.labelTip.Name = "labelTip"; + this.labelTip.Size = new System.Drawing.Size(243, 13); + this.labelTip.TabIndex = 43; + this.labelTip.Text = "Tip: Right-click on a game profile for more options."; + // + // toolStrip1 + // + this.toolStrip1.BackColor = System.Drawing.Color.White; + this.toolStrip1.GripMargin = new System.Windows.Forms.Padding(0); + this.toolStrip1.GripStyle = System.Windows.Forms.ToolStripGripStyle.Hidden; + this.toolStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.toolStripButtonAddGame}); + this.toolStrip1.Location = new System.Drawing.Point(3, 3); + this.toolStrip1.Name = "toolStrip1"; + this.toolStrip1.Padding = new System.Windows.Forms.Padding(5); + this.toolStrip1.RenderMode = System.Windows.Forms.ToolStripRenderMode.System; + this.toolStrip1.Size = new System.Drawing.Size(760, 37); + this.toolStrip1.TabIndex = 19; + this.toolStrip1.Text = "toolStrip1"; + // + // toolStripButtonAddGame + // + this.toolStripButtonAddGame.BackColor = System.Drawing.Color.White; + this.toolStripButtonAddGame.Image = global::Fo76ini.Properties.Resources.plus_24; + this.toolStripButtonAddGame.ImageAlign = System.Drawing.ContentAlignment.MiddleLeft; + this.toolStripButtonAddGame.ImageTransparentColor = System.Drawing.Color.Magenta; + this.toolStripButtonAddGame.Name = "toolStripButtonAddGame"; + this.toolStripButtonAddGame.Padding = new System.Windows.Forms.Padding(4, 2, 4, 2); + this.toolStripButtonAddGame.Size = new System.Drawing.Size(90, 24); + this.toolStripButtonAddGame.Text = "Add game"; + this.toolStripButtonAddGame.Click += new System.EventHandler(this.toolStripButtonAddGame_Click); + // + // tabPageNexusMods + // + this.tabPageNexusMods.Controls.Add(this.panel2); + this.tabPageNexusMods.Controls.Add(this.panel3); + this.tabPageNexusMods.Location = new System.Drawing.Point(4, 22); + this.tabPageNexusMods.Name = "tabPageNexusMods"; + this.tabPageNexusMods.Padding = new System.Windows.Forms.Padding(3); + this.tabPageNexusMods.Size = new System.Drawing.Size(766, 508); + this.tabPageNexusMods.TabIndex = 2; + this.tabPageNexusMods.Text = "NexusMods"; + this.tabPageNexusMods.UseVisualStyleBackColor = true; + // + // panel2 + // + this.panel2.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.panel2.BackColor = System.Drawing.SystemColors.Window; + this.panel2.Controls.Add(this.pictureBoxAPIKeyHelp); + this.panel2.Controls.Add(this.linkLabelAPIKeyHelp); + this.panel2.Controls.Add(this.buttonNMLoginManually); + this.panel2.Controls.Add(this.labelAPIKey); + this.panel2.Controls.Add(this.checkBoxShowAPIKey); + this.panel2.Controls.Add(this.textBoxAPIKey); + this.panel2.Controls.Add(this.label1); + this.panel2.Controls.Add(this.buttonNMLogin); + this.panel2.Controls.Add(this.buttonNWDeleteCache); + this.panel2.Controls.Add(this.buttonNWLogout); + this.panel2.Controls.Add(this.checkBoxNMDownloadThumbnails); + this.panel2.Controls.Add(this.labelNMOptions); + this.panel2.Controls.Add(this.checkBoxNMUpdateProfile); + this.panel2.Controls.Add(this.buttonNMUpdateProfile); + this.panel2.Location = new System.Drawing.Point(0, 169); + this.panel2.Name = "panel2"; + this.panel2.Size = new System.Drawing.Size(766, 339); + this.panel2.TabIndex = 78; + // + // labelAPIKey + // + this.labelAPIKey.AutoSize = true; + this.labelAPIKey.Font = new System.Drawing.Font("Microsoft Sans Serif", 9.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.labelAPIKey.Location = new System.Drawing.Point(6, 239); + this.labelAPIKey.Name = "labelAPIKey"; + this.labelAPIKey.Size = new System.Drawing.Size(62, 16); + this.labelAPIKey.TabIndex = 109; + this.labelAPIKey.Text = "API Key"; + // + // checkBoxShowAPIKey + // + this.checkBoxShowAPIKey.AutoSize = true; + this.checkBoxShowAPIKey.Location = new System.Drawing.Point(20, 314); + this.checkBoxShowAPIKey.Name = "checkBoxShowAPIKey"; + this.checkBoxShowAPIKey.Size = new System.Drawing.Size(93, 17); + this.checkBoxShowAPIKey.TabIndex = 108; + this.checkBoxShowAPIKey.Text = "Show API key"; + this.checkBoxShowAPIKey.UseVisualStyleBackColor = true; + this.checkBoxShowAPIKey.CheckedChanged += new System.EventHandler(this.checkBoxShowAPIKey_CheckedChanged); + // + // textBoxAPIKey + // + this.textBoxAPIKey.Location = new System.Drawing.Point(20, 288); + this.textBoxAPIKey.Name = "textBoxAPIKey"; + this.textBoxAPIKey.Size = new System.Drawing.Size(726, 20); + this.textBoxAPIKey.TabIndex = 107; + this.textBoxAPIKey.UseSystemPasswordChar = true; + this.textBoxAPIKey.TextChanged += new System.EventHandler(this.textBoxAPIKey_TextChanged); + // + // buttonNMLogin + // + this.buttonNMLogin.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(218)))), ((int)(((byte)(142)))), ((int)(((byte)(53))))); + this.buttonNMLogin.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.buttonNMLogin.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.buttonNMLogin.ForeColor = System.Drawing.SystemColors.ControlLightLight; + this.buttonNMLogin.Image = global::Fo76ini.Properties.Resources.login_48; + this.buttonNMLogin.Location = new System.Drawing.Point(20, 23); + this.buttonNMLogin.Name = "buttonNMLogin"; + this.buttonNMLogin.Padding = new System.Windows.Forms.Padding(4); + this.buttonNMLogin.Size = new System.Drawing.Size(120, 120); + this.buttonNMLogin.TabIndex = 105; + this.buttonNMLogin.Text = "Log in"; + this.buttonNMLogin.TextAlign = System.Drawing.ContentAlignment.BottomCenter; + this.buttonNMLogin.UseVisualStyleBackColor = false; + this.buttonNMLogin.Click += new System.EventHandler(this.buttonNMLogin_Click); + // + // buttonNWDeleteCache + // + this.buttonNWDeleteCache.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(160)))), ((int)(((byte)(34)))), ((int)(((byte)(34))))); + this.buttonNWDeleteCache.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.buttonNWDeleteCache.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.buttonNWDeleteCache.ForeColor = System.Drawing.SystemColors.ControlLightLight; + this.buttonNWDeleteCache.Image = global::Fo76ini.Properties.Resources.delete_48; + this.buttonNWDeleteCache.Location = new System.Drawing.Point(524, 23); + this.buttonNWDeleteCache.Name = "buttonNWDeleteCache"; + this.buttonNWDeleteCache.Padding = new System.Windows.Forms.Padding(4); + this.buttonNWDeleteCache.Size = new System.Drawing.Size(120, 120); + this.buttonNWDeleteCache.TabIndex = 104; + this.buttonNWDeleteCache.Text = "Delete cache"; + this.buttonNWDeleteCache.TextAlign = System.Drawing.ContentAlignment.BottomCenter; + this.buttonNWDeleteCache.UseVisualStyleBackColor = false; + this.buttonNWDeleteCache.Click += new System.EventHandler(this.buttonNWDeleteCache_Click); + // + // buttonNWLogout + // + this.buttonNWLogout.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(62)))), ((int)(((byte)(128)))), ((int)(((byte)(62))))); + this.buttonNWLogout.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.buttonNWLogout.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.buttonNWLogout.ForeColor = System.Drawing.SystemColors.ControlLightLight; + this.buttonNWLogout.Image = global::Fo76ini.Properties.Resources.exit_48; + this.buttonNWLogout.Location = new System.Drawing.Point(272, 23); + this.buttonNWLogout.Name = "buttonNWLogout"; + this.buttonNWLogout.Padding = new System.Windows.Forms.Padding(4); + this.buttonNWLogout.Size = new System.Drawing.Size(120, 120); + this.buttonNWLogout.TabIndex = 103; + this.buttonNWLogout.Text = "Logout"; + this.buttonNWLogout.TextAlign = System.Drawing.ContentAlignment.BottomCenter; + this.buttonNWLogout.UseVisualStyleBackColor = false; + this.buttonNWLogout.Click += new System.EventHandler(this.buttonNWLogout_Click); + // + // checkBoxNMDownloadThumbnails + // + this.checkBoxNMDownloadThumbnails.AutoSize = true; + this.checkBoxNMDownloadThumbnails.Checked = true; + this.checkBoxNMDownloadThumbnails.CheckState = System.Windows.Forms.CheckState.Checked; + this.checkBoxNMDownloadThumbnails.Location = new System.Drawing.Point(20, 200); + this.checkBoxNMDownloadThumbnails.Name = "checkBoxNMDownloadThumbnails"; + this.checkBoxNMDownloadThumbnails.Size = new System.Drawing.Size(127, 17); + this.checkBoxNMDownloadThumbnails.TabIndex = 102; + this.checkBoxNMDownloadThumbnails.Text = "Download thumbnails"; + this.checkBoxNMDownloadThumbnails.UseVisualStyleBackColor = true; + this.checkBoxNMDownloadThumbnails.CheckedChanged += new System.EventHandler(this.checkBoxNMDownloadThumbnails_CheckedChanged); + // + // labelNMOptions + // + this.labelNMOptions.AutoSize = true; + this.labelNMOptions.Font = new System.Drawing.Font("Microsoft Sans Serif", 9.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.labelNMOptions.Location = new System.Drawing.Point(6, 155); + this.labelNMOptions.Name = "labelNMOptions"; + this.labelNMOptions.Size = new System.Drawing.Size(61, 16); + this.labelNMOptions.TabIndex = 101; + this.labelNMOptions.Text = "Options"; + // + // checkBoxNMUpdateProfile + // + this.checkBoxNMUpdateProfile.AutoSize = true; + this.checkBoxNMUpdateProfile.Checked = true; + this.checkBoxNMUpdateProfile.CheckState = System.Windows.Forms.CheckState.Checked; + this.checkBoxNMUpdateProfile.Location = new System.Drawing.Point(20, 177); + this.checkBoxNMUpdateProfile.Name = "checkBoxNMUpdateProfile"; + this.checkBoxNMUpdateProfile.Size = new System.Drawing.Size(156, 17); + this.checkBoxNMUpdateProfile.TabIndex = 100; + this.checkBoxNMUpdateProfile.Text = "Update profile automatically"; + this.checkBoxNMUpdateProfile.UseVisualStyleBackColor = true; + this.checkBoxNMUpdateProfile.CheckedChanged += new System.EventHandler(this.checkBoxNMUpdateProfile_CheckedChanged); + // + // buttonNMUpdateProfile + // + this.buttonNMUpdateProfile.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(218)))), ((int)(((byte)(142)))), ((int)(((byte)(53))))); + this.buttonNMUpdateProfile.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.buttonNMUpdateProfile.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.buttonNMUpdateProfile.ForeColor = System.Drawing.SystemColors.ControlLightLight; + this.buttonNMUpdateProfile.Image = global::Fo76ini.Properties.Resources.available_updates_48; + this.buttonNMUpdateProfile.Location = new System.Drawing.Point(398, 23); + this.buttonNMUpdateProfile.Name = "buttonNMUpdateProfile"; + this.buttonNMUpdateProfile.Padding = new System.Windows.Forms.Padding(4); + this.buttonNMUpdateProfile.Size = new System.Drawing.Size(120, 120); + this.buttonNMUpdateProfile.TabIndex = 94; + this.buttonNMUpdateProfile.Text = "Update profile"; + this.buttonNMUpdateProfile.TextAlign = System.Drawing.ContentAlignment.BottomCenter; + this.buttonNMUpdateProfile.UseVisualStyleBackColor = false; + this.buttonNMUpdateProfile.Click += new System.EventHandler(this.buttonNMUpdateProfile_Click); + // + // panel3 + // + this.panel3.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.panel3.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(24)))), ((int)(((byte)(24)))), ((int)(((byte)(24))))); + this.panel3.Controls.Add(this.labelNMNotLoggedIn); + this.panel3.Controls.Add(this.labelNMUserID); + this.panel3.Controls.Add(this.labelNMDescUserID); + this.panel3.Controls.Add(this.labelNMHourlyRateLimit); + this.panel3.Controls.Add(this.labelNMDescHourlyRateLimit); + this.panel3.Controls.Add(this.pictureBoxNMProfilePicture); + this.panel3.Controls.Add(this.labelNMUserName); + this.panel3.Controls.Add(this.labelNMDescMembership); + this.panel3.Controls.Add(this.labelNMDailyRateLimitReset); + this.panel3.Controls.Add(this.labelNMMembership); + this.panel3.Controls.Add(this.labelNMDescLimitReset); + this.panel3.Controls.Add(this.labelNMDescDailyRateLimit); + this.panel3.Controls.Add(this.labelNMDailyRateLimit); + this.panel3.Location = new System.Drawing.Point(0, 0); + this.panel3.Name = "panel3"; + this.panel3.Size = new System.Drawing.Size(766, 170); + this.panel3.TabIndex = 77; + // + // labelNMNotLoggedIn + // + this.labelNMNotLoggedIn.AutoSize = true; + this.labelNMNotLoggedIn.ForeColor = System.Drawing.SystemColors.ControlLightLight; + this.labelNMNotLoggedIn.Location = new System.Drawing.Point(173, 57); + this.labelNMNotLoggedIn.Name = "labelNMNotLoggedIn"; + this.labelNMNotLoggedIn.Size = new System.Drawing.Size(73, 13); + this.labelNMNotLoggedIn.TabIndex = 80; + this.labelNMNotLoggedIn.Text = "Not logged in."; + // + // labelNMUserID + // + this.labelNMUserID.AutoSize = true; + this.labelNMUserID.ForeColor = System.Drawing.SystemColors.ControlLightLight; + this.labelNMUserID.Location = new System.Drawing.Point(296, 85); + this.labelNMUserID.Name = "labelNMUserID"; + this.labelNMUserID.Size = new System.Drawing.Size(16, 13); + this.labelNMUserID.TabIndex = 79; + this.labelNMUserID.Text = "-1"; + // + // labelNMDescUserID + // + this.labelNMDescUserID.AutoSize = true; + this.labelNMDescUserID.ForeColor = System.Drawing.SystemColors.ControlLightLight; + this.labelNMDescUserID.Location = new System.Drawing.Point(173, 85); + this.labelNMDescUserID.Name = "labelNMDescUserID"; + this.labelNMDescUserID.Size = new System.Drawing.Size(46, 13); + this.labelNMDescUserID.TabIndex = 78; + this.labelNMDescUserID.Text = "User-ID:"; + // + // labelNMHourlyRateLimit + // + this.labelNMHourlyRateLimit.AutoSize = true; + this.labelNMHourlyRateLimit.ForeColor = System.Drawing.SystemColors.ControlLightLight; + this.labelNMHourlyRateLimit.Location = new System.Drawing.Point(585, 85); + this.labelNMHourlyRateLimit.Name = "labelNMHourlyRateLimit"; + this.labelNMHourlyRateLimit.Size = new System.Drawing.Size(30, 13); + this.labelNMHourlyRateLimit.TabIndex = 77; + this.labelNMHourlyRateLimit.Text = "0 left"; + // + // labelNMDescHourlyRateLimit + // + this.labelNMDescHourlyRateLimit.AutoSize = true; + this.labelNMDescHourlyRateLimit.ForeColor = System.Drawing.SystemColors.ControlLightLight; + this.labelNMDescHourlyRateLimit.Location = new System.Drawing.Point(457, 85); + this.labelNMDescHourlyRateLimit.Name = "labelNMDescHourlyRateLimit"; + this.labelNMDescHourlyRateLimit.Size = new System.Drawing.Size(81, 13); + this.labelNMDescHourlyRateLimit.TabIndex = 76; + this.labelNMDescHourlyRateLimit.Text = "Hourly rate limit:"; + // + // pictureBoxNMProfilePicture + // + this.pictureBoxNMProfilePicture.Cursor = System.Windows.Forms.Cursors.Hand; + this.pictureBoxNMProfilePicture.Image = ((System.Drawing.Image)(resources.GetObject("pictureBoxNMProfilePicture.Image"))); + this.pictureBoxNMProfilePicture.Location = new System.Drawing.Point(20, 20); + this.pictureBoxNMProfilePicture.Name = "pictureBoxNMProfilePicture"; + this.pictureBoxNMProfilePicture.Size = new System.Drawing.Size(128, 128); + this.pictureBoxNMProfilePicture.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage; + this.pictureBoxNMProfilePicture.TabIndex = 65; + this.pictureBoxNMProfilePicture.TabStop = false; + this.pictureBoxNMProfilePicture.Click += new System.EventHandler(this.pictureBoxNMProfilePicture_Click); + // + // labelNMUserName + // + this.labelNMUserName.AutoSize = true; + this.labelNMUserName.Font = new System.Drawing.Font("Microsoft Sans Serif", 21.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.labelNMUserName.ForeColor = System.Drawing.SystemColors.ControlLightLight; + this.labelNMUserName.Location = new System.Drawing.Point(170, 20); + this.labelNMUserName.Name = "labelNMUserName"; + this.labelNMUserName.Size = new System.Drawing.Size(169, 33); + this.labelNMUserName.TabIndex = 66; + this.labelNMUserName.Text = "Anonymous"; + // + // labelNMDescMembership + // + this.labelNMDescMembership.AutoSize = true; + this.labelNMDescMembership.ForeColor = System.Drawing.SystemColors.ControlLightLight; + this.labelNMDescMembership.Location = new System.Drawing.Point(173, 64); + this.labelNMDescMembership.Name = "labelNMDescMembership"; + this.labelNMDescMembership.Size = new System.Drawing.Size(67, 13); + this.labelNMDescMembership.TabIndex = 67; + this.labelNMDescMembership.Text = "Membership:"; + // + // labelNMDailyRateLimitReset + // + this.labelNMDailyRateLimitReset.AutoSize = true; + this.labelNMDailyRateLimitReset.ForeColor = System.Drawing.SystemColors.ControlLightLight; + this.labelNMDailyRateLimitReset.Location = new System.Drawing.Point(585, 107); + this.labelNMDailyRateLimitReset.Name = "labelNMDailyRateLimitReset"; + this.labelNMDailyRateLimitReset.Size = new System.Drawing.Size(36, 13); + this.labelNMDailyRateLimitReset.TabIndex = 72; + this.labelNMDailyRateLimitReset.Text = "Never"; + // + // labelNMMembership + // + this.labelNMMembership.AutoSize = true; + this.labelNMMembership.ForeColor = System.Drawing.SystemColors.ControlLightLight; + this.labelNMMembership.Location = new System.Drawing.Point(296, 64); + this.labelNMMembership.Name = "labelNMMembership"; + this.labelNMMembership.Size = new System.Drawing.Size(33, 13); + this.labelNMMembership.TabIndex = 68; + this.labelNMMembership.Text = "Basic"; + // + // labelNMDescLimitReset + // + this.labelNMDescLimitReset.AutoSize = true; + this.labelNMDescLimitReset.ForeColor = System.Drawing.SystemColors.ControlLightLight; + this.labelNMDescLimitReset.Location = new System.Drawing.Point(457, 107); + this.labelNMDescLimitReset.Name = "labelNMDescLimitReset"; + this.labelNMDescLimitReset.Size = new System.Drawing.Size(57, 13); + this.labelNMDescLimitReset.TabIndex = 71; + this.labelNMDescLimitReset.Text = "Limit reset:"; + // + // labelNMDescDailyRateLimit + // + this.labelNMDescDailyRateLimit.AutoSize = true; + this.labelNMDescDailyRateLimit.ForeColor = System.Drawing.SystemColors.ControlLightLight; + this.labelNMDescDailyRateLimit.Location = new System.Drawing.Point(457, 64); + this.labelNMDescDailyRateLimit.Name = "labelNMDescDailyRateLimit"; + this.labelNMDescDailyRateLimit.Size = new System.Drawing.Size(74, 13); + this.labelNMDescDailyRateLimit.TabIndex = 69; + this.labelNMDescDailyRateLimit.Text = "Daily rate limit:"; + // + // labelNMDailyRateLimit + // + this.labelNMDailyRateLimit.AutoSize = true; + this.labelNMDailyRateLimit.ForeColor = System.Drawing.SystemColors.ControlLightLight; + this.labelNMDailyRateLimit.Location = new System.Drawing.Point(585, 64); + this.labelNMDailyRateLimit.Name = "labelNMDailyRateLimit"; + this.labelNMDailyRateLimit.Size = new System.Drawing.Size(30, 13); + this.labelNMDailyRateLimit.TabIndex = 70; + this.labelNMDailyRateLimit.Text = "0 left"; + // + // toolTip + // + this.toolTip.AutoPopDelay = 20000; + this.toolTip.InitialDelay = 500; + this.toolTip.IsBalloon = true; + this.toolTip.ReshowDelay = 100; + // + // openFileDialogGamePath + // + this.openFileDialogGamePath.FileName = "Fallout76.exe"; + this.openFileDialogGamePath.Filter = "Executable|*.exe"; + this.openFileDialogGamePath.FilterIndex = 2; + // + // backgroundWorkerDownloadLanguages + // + this.backgroundWorkerDownloadLanguages.DoWork += new System.ComponentModel.DoWorkEventHandler(this.backgroundWorkerDownloadLanguages_DoWork); + // + // backgroundWorkerRetrieveProfileInfo + // + this.backgroundWorkerRetrieveProfileInfo.DoWork += new System.ComponentModel.DoWorkEventHandler(this.backgroundWorkerRetrieveProfileInfo_DoWork); + // + // backgroundWorkerSSOLogin + // + this.backgroundWorkerSSOLogin.DoWork += new System.ComponentModel.DoWorkEventHandler(this.backgroundWorkerSSOLogin_DoWork); + // + // buttonNMLoginManually + // + this.buttonNMLoginManually.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(218)))), ((int)(((byte)(142)))), ((int)(((byte)(53))))); + this.buttonNMLoginManually.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.buttonNMLoginManually.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.buttonNMLoginManually.ForeColor = System.Drawing.SystemColors.ControlLightLight; + this.buttonNMLoginManually.Image = global::Fo76ini.Properties.Resources.login_48; + this.buttonNMLoginManually.Location = new System.Drawing.Point(146, 23); + this.buttonNMLoginManually.Name = "buttonNMLoginManually"; + this.buttonNMLoginManually.Padding = new System.Windows.Forms.Padding(4); + this.buttonNMLoginManually.Size = new System.Drawing.Size(120, 120); + this.buttonNMLoginManually.TabIndex = 110; + this.buttonNMLoginManually.Text = "Log in with key"; + this.buttonNMLoginManually.TextAlign = System.Drawing.ContentAlignment.BottomCenter; + this.buttonNMLoginManually.UseVisualStyleBackColor = false; + this.buttonNMLoginManually.Click += new System.EventHandler(this.buttonNMLoginManually_Click); + // + // linkLabelAPIKeyHelp + // + this.linkLabelAPIKeyHelp.AutoSize = true; + this.linkLabelAPIKeyHelp.Location = new System.Drawing.Point(51, 264); + this.linkLabelAPIKeyHelp.Name = "linkLabelAPIKeyHelp"; + this.linkLabelAPIKeyHelp.Size = new System.Drawing.Size(158, 13); + this.linkLabelAPIKeyHelp.TabIndex = 111; + this.linkLabelAPIKeyHelp.TabStop = true; + this.linkLabelAPIKeyHelp.Text = "How do I login with an API key?"; + this.linkLabelAPIKeyHelp.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.linkLabelAPIKeyHelp_LinkClicked); + // + // pictureBoxAPIKeyHelp + // + this.pictureBoxAPIKeyHelp.Image = global::Fo76ini.Properties.Resources.help_24; + this.pictureBoxAPIKeyHelp.Location = new System.Drawing.Point(20, 258); + this.pictureBoxAPIKeyHelp.Name = "pictureBoxAPIKeyHelp"; + this.pictureBoxAPIKeyHelp.Size = new System.Drawing.Size(24, 24); + this.pictureBoxAPIKeyHelp.TabIndex = 112; + this.pictureBoxAPIKeyHelp.TabStop = false; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Font = new System.Drawing.Font("Microsoft Sans Serif", 9.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label1.Location = new System.Drawing.Point(6, 4); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(59, 16); + this.label1.TabIndex = 106; + this.label1.Text = "Actions"; + // + // FormSettings + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(796, 561); + this.Controls.Add(this.tabControl1); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; + this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "FormSettings"; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.Text = "Settings"; + this.Load += new System.EventHandler(this.FormSettings_Load); + this.tabControl1.ResumeLayout(false); + this.tabPageGeneral.ResumeLayout(false); + this.groupBoxActions.ResumeLayout(false); + this.groupBoxActions.PerformLayout(); + this.groupBoxOptions.ResumeLayout(false); + this.groupBoxOptions.PerformLayout(); + this.groupBoxNuclearWinterMode.ResumeLayout(false); + this.groupBoxNuclearWinterMode.PerformLayout(); + this.groupBoxBehavior.ResumeLayout(false); + this.groupBoxBehavior.PerformLayout(); + this.groupBoxLocalization.ResumeLayout(false); + this.groupBoxLocalization.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBoxSpinnerDownloadLanguages)).EndInit(); + this.tabPageGameProfiles.ResumeLayout(false); + this.tabPageGameProfiles.PerformLayout(); + this.panel1.ResumeLayout(false); + this.panel1.PerformLayout(); + this.groupBoxSettings.ResumeLayout(false); + this.panelSettings.ResumeLayout(false); + this.groupBox2.ResumeLayout(false); + this.groupBox2.PerformLayout(); + this.groupBoxLaunchOptions.ResumeLayout(false); + this.groupBoxLaunchOptions.PerformLayout(); + this.groupBoxGameLocation.ResumeLayout(false); + this.groupBoxGameLocation.PerformLayout(); + this.groupBoxGameEdition.ResumeLayout(false); + this.groupBoxGameEdition.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBoxUnknown)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBoxMSStore)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBoxSteam)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBoxBethesdaNetPTS)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBoxBethesdaNet)).EndInit(); + this.groupBoxGame.ResumeLayout(false); + this.contextMenuStripGame.ResumeLayout(false); + this.toolStrip1.ResumeLayout(false); + this.toolStrip1.PerformLayout(); + this.tabPageNexusMods.ResumeLayout(false); + this.panel2.ResumeLayout(false); + this.panel2.PerformLayout(); + this.panel3.ResumeLayout(false); + this.panel3.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBoxNMProfilePicture)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBoxAPIKeyHelp)).EndInit(); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.TabControl tabControl1; + private System.Windows.Forms.TabPage tabPageGeneral; + private System.Windows.Forms.TabPage tabPageGameProfiles; + private System.Windows.Forms.TabPage tabPageNexusMods; + private System.Windows.Forms.GroupBox groupBoxLocalization; + private System.Windows.Forms.Button buttonRefreshLanguage; + private System.Windows.Forms.PictureBox pictureBoxSpinnerDownloadLanguages; + public System.Windows.Forms.Label labelOutdatedLanguage; + private System.Windows.Forms.Label labelLanguage; + private System.Windows.Forms.Button buttonDownloadLanguages; + private System.Windows.Forms.ComboBox comboBoxLanguage; + private System.Windows.Forms.GroupBox groupBoxBehavior; + private System.Windows.Forms.CheckBox checkBoxPlayNotificationSound; + private System.Windows.Forms.CheckBox checkBoxIgnoreUpdates; + private System.Windows.Forms.CheckBox checkBoxQuitOnGameLaunch; + private System.Windows.Forms.CheckBox checkBoxAutoApply; + private System.Windows.Forms.GroupBox groupBoxNuclearWinterMode; + private System.Windows.Forms.CheckBox checkBoxNWAutoDeployMods; + private System.Windows.Forms.Label labelNWmodoptions; + private System.Windows.Forms.Label labelNWdlloptions; + private System.Windows.Forms.CheckBox checkBoxNWAutoDisableMods; + private System.Windows.Forms.CheckBox checkBoxNWRenameDLL; + private System.Windows.Forms.Panel panel1; + private System.Windows.Forms.Label labelTip; + private System.Windows.Forms.Panel panelSettings; + private System.Windows.Forms.GroupBox groupBox2; + private System.Windows.Forms.TextBox textBoxLaunchURL; + private System.Windows.Forms.Label labelLaunchURL; + private System.Windows.Forms.TextBox textBoxParameters; + private System.Windows.Forms.Label labelParameters; + private System.Windows.Forms.TextBox textBoxExecutable; + private System.Windows.Forms.Label labelExecutable; + private System.Windows.Forms.TextBox textBoxIniPrefix; + private System.Windows.Forms.Label labelIniPrefix; + private System.Windows.Forms.GroupBox groupBoxLaunchOptions; + private System.Windows.Forms.Label labelLaunchOptionMSStoreNotice; + private System.Windows.Forms.RadioButton radioButtonLaunchViaExecutable; + private System.Windows.Forms.RadioButton radioButtonLaunchViaLink; + private System.Windows.Forms.GroupBox groupBoxGameLocation; + private System.Windows.Forms.Button buttonAutoDetect; + private System.Windows.Forms.TextBox textBoxGamePath; + private System.Windows.Forms.Button buttonPickGamePath; + private System.Windows.Forms.GroupBox groupBoxGameEdition; + private System.Windows.Forms.PictureBox pictureBoxMSStore; + private System.Windows.Forms.PictureBox pictureBoxSteam; + private System.Windows.Forms.PictureBox pictureBoxBethesdaNetPTS; + private System.Windows.Forms.PictureBox pictureBoxBethesdaNet; + private System.Windows.Forms.RadioButton radioButtonEditionMSStore; + private System.Windows.Forms.RadioButton radioButtonEditionBethesdaNetPTS; + private System.Windows.Forms.RadioButton radioButtonEditionSteam; + private System.Windows.Forms.RadioButton radioButtonEditionBethesdaNet; + private System.Windows.Forms.ListView listViewGameInstances; + private System.Windows.Forms.ColumnHeader columnHeader1; + private System.Windows.Forms.ToolStrip toolStrip1; + private System.Windows.Forms.ToolStripButton toolStripButtonAddGame; + private System.Windows.Forms.Panel panel3; + private System.Windows.Forms.Label labelNMNotLoggedIn; + private System.Windows.Forms.Label labelNMUserID; + private System.Windows.Forms.Label labelNMDescUserID; + private System.Windows.Forms.Label labelNMHourlyRateLimit; + private System.Windows.Forms.Label labelNMDescHourlyRateLimit; + private System.Windows.Forms.PictureBox pictureBoxNMProfilePicture; + private System.Windows.Forms.Label labelNMUserName; + private System.Windows.Forms.Label labelNMDescMembership; + private System.Windows.Forms.Label labelNMDailyRateLimitReset; + private System.Windows.Forms.Label labelNMMembership; + private System.Windows.Forms.Label labelNMDescLimitReset; + private System.Windows.Forms.Label labelNMDescDailyRateLimit; + private System.Windows.Forms.Label labelNMDailyRateLimit; + private System.Windows.Forms.Panel panel2; + private System.Windows.Forms.Button buttonNWDeleteCache; + private System.Windows.Forms.Button buttonNWLogout; + private System.Windows.Forms.CheckBox checkBoxNMDownloadThumbnails; + private System.Windows.Forms.Label labelNMOptions; + private System.Windows.Forms.CheckBox checkBoxNMUpdateProfile; + private System.Windows.Forms.Button buttonNMUpdateProfile; + public System.Windows.Forms.ToolTip toolTip; + private System.Windows.Forms.ImageList imageList1; + private System.Windows.Forms.OpenFileDialog openFileDialogGamePath; + private System.Windows.Forms.ContextMenuStrip contextMenuStripGame; + private System.Windows.Forms.ToolStripMenuItem gameToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem launchGameToolStripMenuItem; + private System.Windows.Forms.ToolStripSeparator toolStripSeparator2; + private System.Windows.Forms.ToolStripMenuItem renameGameToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem removeGameToolStripMenuItem; + private System.ComponentModel.BackgroundWorker backgroundWorkerDownloadLanguages; + private System.Windows.Forms.GroupBox groupBoxSettings; + private System.Windows.Forms.GroupBox groupBoxGame; + private System.Windows.Forms.GroupBox groupBoxOptions; + private System.Windows.Forms.CheckBox checkBoxReadOnly; + private System.ComponentModel.BackgroundWorker backgroundWorkerRetrieveProfileInfo; + private System.Windows.Forms.RadioButton radioButtonEditionUnknown; + private System.Windows.Forms.PictureBox pictureBoxUnknown; + private System.Windows.Forms.GroupBox groupBoxActions; + private System.Windows.Forms.LinkLabel linkLabelEnableDangerZone; + private System.Windows.Forms.Button buttonNMLogin; + private System.ComponentModel.BackgroundWorker backgroundWorkerSSOLogin; + private System.Windows.Forms.Label labelAPIKey; + private System.Windows.Forms.CheckBox checkBoxShowAPIKey; + private System.Windows.Forms.TextBox textBoxAPIKey; + private System.Windows.Forms.Button buttonNMLoginManually; + private System.Windows.Forms.PictureBox pictureBoxAPIKeyHelp; + private System.Windows.Forms.LinkLabel linkLabelAPIKeyHelp; + private System.Windows.Forms.Label label1; + } +} \ No newline at end of file diff --git a/Fo76ini/Forms/FormSettings/FormSettings.cs b/Fo76ini/Forms/FormSettings/FormSettings.cs new file mode 100644 index 0000000..d4d83c4 --- /dev/null +++ b/Fo76ini/Forms/FormSettings/FormSettings.cs @@ -0,0 +1,843 @@ +using Fo76ini.Forms.FormTextPrompt; +using Fo76ini.Interface; +using Fo76ini.NexusAPI; +using Fo76ini.Profiles; +using Fo76ini.Properties; +using Fo76ini.Tweaks; +using Fo76ini.Tweaks.Config; +using Fo76ini.Tweaks.Inis; +using Fo76ini.Tweaks.NuclearWinterMode; +using Fo76ini.Utilities; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.IO; +using System.Linq; +using System.Net; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace Fo76ini.Forms.FormSettings +{ + public partial class FormSettings : Form + { + private bool UpdatingUI = false; + + public static event EventHandler SettingsClosing; + + public static bool DangerZoneEnabled = false; + + public FormSettings() + { + InitializeComponent(); + + // Make this form translatable: + Localization.LocalizedForms.Add(new LocalizedForm(this, toolTip)); + + // Handle translations: + Translation.LanguageChanged += OnLanguageChanged; + + // Assign a dropdown menu to hold languages: + Localization.AssignDropDown(this.comboBoxLanguage); + + Translation.BlackList.AddRange(new string[] { + "buttonDownloadLanguages", + "buttonRefreshLanguage", + "labelNMUserID", + "labelNMHourlyRateLimit", + "labelNMAPIKeyStatus", + "labelNMUserName", + "labelNMDailyRateLimitReset", + "labelNMMembership", + "labelNMDailyRateLimit" + }); + + // Link tweaks + LinkInfo(); + LinkControlsToTweaks(); + + // Load NexusMods + NexusMods.Load(); + + + // Init components / assign event handler: + this.listViewGameInstances.HeaderStyle = ColumnHeaderStyle.None; + + this.backgroundWorkerDownloadLanguages.RunWorkerCompleted += backgroundWorkerDownloadLanguages_RunWorkerCompleted; + this.backgroundWorkerRetrieveProfileInfo.RunWorkerCompleted += backgroundWorkerRetrieveProfileInfo_RunWorkerCompleted; + this.FormClosing += FormSettings_FormClosing; + + SingleSignOn.SSOFinished += SingleSignOn_SSOFinished; + } + + private void FormSettings_Load(object sender, EventArgs e) + { + LinkedTweaks.LoadValues(); + UpdateGamesTab(); + RefreshNMUI(); + if (IniFiles.Config.GetBool("NexusMods", "bAutoUpdateProfile", true)) + UpdateNMProfile(); + } + + private void FormSettings_FormClosing(object sender, FormClosingEventArgs e) + { + if (e.CloseReason == CloseReason.UserClosing) + { + e.Cancel = true; + ProfileManager.Save(); + ProfileManager.Feedback(); + if (SettingsClosing != null) + SettingsClosing(this, null); + this.Hide(); + } + } + + /// + /// Opens the "General" tab and shows the form as a modal dialog box (ShowDialog). + /// + public void ShowSettings() + { + this.tabControl1.SelectedTab = this.tabPageGeneral; + this.ShowDialog(); + } + + /// + /// Opens the "Game profiles" tab and shows the form as a modal dialog box (ShowDialog). + /// + public void ShowProfiles() + { + this.tabControl1.SelectedTab = this.tabPageGameProfiles; + this.ShowDialog(); + } + + #region General + + public void LinkInfo() + { + LinkedTweaks.LinkInfo(checkBoxReadOnly, toolTip, iniReadOnlyTweak); + LinkedTweaks.LinkInfo(checkBoxAutoApply, toolTip, autoApplyTweak); + LinkedTweaks.LinkInfo(checkBoxIgnoreUpdates, toolTip, ignoreUpdatesTweak); + LinkedTweaks.LinkInfo(checkBoxPlayNotificationSound, toolTip, playNotificationSoundsTweak); + LinkedTweaks.LinkInfo(checkBoxQuitOnGameLaunch, toolTip, toolQuitOnLaunchTweak); + LinkedTweaks.LinkInfo(checkBoxNWRenameDLL, toolTip, renameDLLsTweak); + LinkedTweaks.LinkInfo(checkBoxNWAutoDeployMods, toolTip, deployModsOnNWModeTweak); + LinkedTweaks.LinkInfo(checkBoxNWAutoDisableMods, toolTip, removeModsOnNWModeTweak); + } + + public void LinkControlsToTweaks() + { + // Make *.ini files read-only + LinkedTweaks.LinkTweak(checkBoxReadOnly, iniReadOnlyTweak); + + // Automatically apply changes when tool is closed or game is launched + LinkedTweaks.LinkTweak(checkBoxAutoApply, autoApplyTweak); + + // Don't check for updates on startup. + LinkedTweaks.LinkTweak(checkBoxIgnoreUpdates, ignoreUpdatesTweak); + + // Play notification sounds + LinkedTweaks.LinkTweak(checkBoxPlayNotificationSound, playNotificationSoundsTweak); + + // Close the tool when the game is launched. + LinkedTweaks.LinkTweak(checkBoxQuitOnGameLaunch, toolQuitOnLaunchTweak); + + + /* + * Nuclear Winter options + */ + + // Rename added *.dll files + LinkedTweaks.LinkTweak(checkBoxNWRenameDLL, renameDLLsTweak); + + // Automatically deploy mods + LinkedTweaks.LinkTweak(checkBoxNWAutoDeployMods, deployModsOnNWModeTweak); + + // Automatically remove mods + LinkedTweaks.LinkTweak(checkBoxNWAutoDisableMods, removeModsOnNWModeTweak); + } + + private void linkLabelEnableDangerZone_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) + { + if (MsgBox.Show("Warning", "Tweaks in the danger zone might introduce graphical glitches or make the game crash.\nAre you sure you want to enable it?", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) + == DialogResult.Yes) + { + DangerZoneEnabled = true; + this.linkLabelEnableDangerZone.Enabled = false; + } + } + + private void checkBoxIgnoreUpdates_CheckedChanged(object sender, EventArgs e) + { + // TODO: When checkBoxIgnoreUpdates gets checked, call Form1.CheckVersion + } + + #endregion + + #region Profiles + + private void UpdateGamesTab() + { + UpdatingUI = true; + + // For each managed game instance... + this.listViewGameInstances.Items.Clear(); + foreach (GameInstance game in ProfileManager.Games) + { + // ... add it to the list. + ListViewItem gameItem = new ListViewItem(game.Title, GetImageIndex(game.Edition)); + this.listViewGameInstances.Items.Add(gameItem); + + // If it is the currently selected game, then... + if (ProfileManager.IsSelected(game)) + { + // ... select it in the list ... + gameItem.Selected = true; + + // ... set the title of the window ... + //this.Text = $"Profiles ({game.Title})"; + + // ... fill the list of profiles: + /*this.listBoxProfile.Items.Clear(); + int i = 0; + foreach (Profile profile in game.Profiles) + { + this.listBoxProfile.Items.Add(profile.Name); + if (game.SelectedProfile.guid == profile.guid) + this.listBoxProfile.SelectedIndex = i; + i++; + }*/ + + // ... and update the settings: + switch (game.Edition) + { + case GameEdition.BethesdaNet: + this.radioButtonEditionBethesdaNet.Checked = true; + break; + case GameEdition.BethesdaNetPTS: + this.radioButtonEditionBethesdaNetPTS.Checked = true; + break; + case GameEdition.Steam: + this.radioButtonEditionSteam.Checked = true; + break; + case GameEdition.MSStore: + this.radioButtonEditionMSStore.Checked = true; + break; + default: + this.radioButtonEditionUnknown.Checked = true; + break; + } + + this.radioButtonLaunchViaLink.Checked = game.PreferredLaunchOption == LaunchOption.OpenURL; + this.radioButtonLaunchViaExecutable.Checked = game.PreferredLaunchOption == LaunchOption.RunExec; + + this.textBoxGamePath.Text = game.GamePath; + this.textBoxExecutable.Text = game.ExecutableName; + this.textBoxIniPrefix.Text = game.IniPrefix; + this.textBoxParameters.Text = game.ExecParameters; + this.textBoxLaunchURL.Text = game.LauncherURL; + + this.labelLaunchOptionMSStoreNotice.Visible = game.Edition == GameEdition.MSStore; + } + } + + UpdatingUI = false; + } + + private int GetImageIndex(GameEdition edition) + { + switch (edition) + { + case GameEdition.BethesdaNet: + case GameEdition.BethesdaNetPTS: + return 1; + case GameEdition.Steam: + return 2; + case GameEdition.MSStore: + return 3; + default: + return 0; + } + } + + + private void listViewGameInstances_SelectedIndexChanged(object sender, EventArgs e) + { + if (UpdatingUI) + return; + if (this.listViewGameInstances.SelectedItems != null && this.listViewGameInstances.SelectedItems.Count > 0) + { + int index = this.listViewGameInstances.SelectedItems[0].Index; + if (ProfileManager.SelectedGameIndex != index) + { + ProfileManager.SelectedGameIndex = index; + UpdateGamesTab(); + } + } + } + + private void radioButtonEditionBethesdaNet_CheckedChanged(object sender, EventArgs e) + { + if (UpdatingUI) + return; + ProfileManager.SelectedGame.Edition = GameEdition.BethesdaNet; + ProfileManager.SelectedGame.SetDefaultSettings(GameEdition.BethesdaNet); + UpdateGamesTab(); + } + + private void radioButtonEditionBethesdaNetPTS_CheckedChanged(object sender, EventArgs e) + { + if (UpdatingUI) + return; + ProfileManager.SelectedGame.Edition = GameEdition.BethesdaNetPTS; + ProfileManager.SelectedGame.SetDefaultSettings(GameEdition.BethesdaNetPTS); + UpdateGamesTab(); + } + + private void radioButtonEditionSteam_CheckedChanged(object sender, EventArgs e) + { + if (UpdatingUI) + return; + ProfileManager.SelectedGame.Edition = GameEdition.Steam; + ProfileManager.SelectedGame.SetDefaultSettings(GameEdition.Steam); + UpdateGamesTab(); + } + + private void radioButtonEditionMSStore_CheckedChanged(object sender, EventArgs e) + { + if (UpdatingUI) + return; + ProfileManager.SelectedGame.Edition = GameEdition.MSStore; + ProfileManager.SelectedGame.SetDefaultSettings(GameEdition.MSStore); + UpdateGamesTab(); + } + + private void radioButtonEditionUnknown_CheckedChanged(object sender, EventArgs e) + { + if (UpdatingUI) + return; + ProfileManager.SelectedGame.Edition = GameEdition.Unknown; + UpdateGamesTab(); + } + + private void textBoxGamePath_TextChanged(object sender, EventArgs e) + { + if (UpdatingUI) + return; + ProfileManager.SelectedGame.GamePath = this.textBoxGamePath.Text; + this.textBoxGamePath.ForeColor = ProfileManager.SelectedGame.ValidateGamePath() ? Color.Black : Color.Maroon; + } + + private void buttonPickGamePath_Click(object sender, EventArgs e) + { + if (UpdatingUI) + return; + this.openFileDialogGamePath.FileName = ProfileManager.SelectedGame.ExecutableName; + if (this.openFileDialogGamePath.ShowDialog() == DialogResult.OK) + { + string path = Path.GetDirectoryName(this.openFileDialogGamePath.FileName); // We want the path where Fallout76.exe resides. + if (GameInstance.ValidateGamePath(path)) + { + this.textBoxGamePath.Text = path; + ProfileManager.SelectedGame.GamePath = path; + UpdateGamesTab(); + } + else + MsgBox.ShowID("modsGamePathInvalid"); + } + } + + public static string AutoDetectGamePath () + { + // Search most common installation directories (probably good enough for now): + string foundPath = null; + string steamPath = @"C:\Program Files(x86)\Steam\steamapps\common\Fallout76"; + string bethNetPath = @"C:\Program Files (x86)\Bethesda.net Launcher\games\Fallout76"; + string xboxPathC = @"C:\Program Files\ModifiableWindowsApps\Fallout76"; + string xboxPathD = @"D:\Program Files\ModifiableWindowsApps\Fallout76"; + + GameEdition edition = ProfileManager.SelectedGame.Edition; + + if (edition == GameEdition.Steam && GameInstance.ValidateGamePath(steamPath)) + foundPath = steamPath; + + if ((edition == GameEdition.BethesdaNet || edition == GameEdition.BethesdaNetPTS) && GameInstance.ValidateGamePath(bethNetPath)) + foundPath = bethNetPath; + + if (edition == GameEdition.MSStore && GameInstance.ValidateGamePath(xboxPathC)) + foundPath = xboxPathC; + + if (edition == GameEdition.MSStore && GameInstance.ValidateGamePath(xboxPathD)) + foundPath = xboxPathD; + + /* + Registry? I only found this: + Path: Computer\HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\Fallout 76 + Name: Path + Type: REG_SZ + Data: "D:\Bethesda.net\Fallout76" + */ + + return foundPath; + } + + private void buttonAutoDetect_Click(object sender, EventArgs e) + { + string foundPath = AutoDetectGamePath(); + if (foundPath != null) + TextPrompt.Prompt("Found a path. Proceed?", foundPath, (newPath) => this.textBoxGamePath.Text = newPath); + else + MsgBox.ShowID("gamePathAutoDetectFailed", MessageBoxIcon.Information); + } + + private void radioButtonLaunchViaLink_CheckedChanged(object sender, EventArgs e) + { + if (UpdatingUI) + return; + ProfileManager.SelectedGame.PreferredLaunchOption = LaunchOption.OpenURL; + } + + private void radioButtonLaunchViaExecutable_CheckedChanged(object sender, EventArgs e) + { + if (UpdatingUI) + return; + ProfileManager.SelectedGame.PreferredLaunchOption = LaunchOption.RunExec; + } + + private void textBoxIniPrefix_TextChanged(object sender, EventArgs e) + { + if (UpdatingUI) + return; + ProfileManager.SelectedGame.IniPrefix = this.textBoxIniPrefix.Text; + } + + private void textBoxExecutable_TextChanged(object sender, EventArgs e) + { + if (UpdatingUI) + return; + ProfileManager.SelectedGame.ExecutableName = this.textBoxExecutable.Text; + } + + private void textBoxParameters_TextChanged(object sender, EventArgs e) + { + if (UpdatingUI) + return; + ProfileManager.SelectedGame.ExecParameters = this.textBoxParameters.Text; + } + + private void textBoxLaunchURL_TextChanged(object sender, EventArgs e) + { + if (UpdatingUI) + return; + ProfileManager.SelectedGame.LauncherURL = this.textBoxLaunchURL.Text; + } + + private void toolStripButtonAddGame_Click(object sender, EventArgs e) + { + GameInstance game = new GameInstance(); + ProfileManager.AddGame(game); + ProfileManager.SelectGame(game); + UpdateGamesTab(); + } + private void launchGameToolStripMenuItem_Click(object sender, EventArgs e) + { + ProfileManager.SelectedGame.LaunchGame(); + } + + private void renameGameToolStripMenuItem_Click(object sender, EventArgs e) + { + String oldName = ProfileManager.SelectedGame.Title; + TextPrompt.Prompt($"Edit title of game {oldName}", oldName, (newName) => { + if (newName.Trim() != "") + { + ProfileManager.SelectedGame.Title = newName; + UpdateGamesTab(); + } + }); + } + + private void removeGameToolStripMenuItem_Click(object sender, EventArgs e) + { + if (ProfileManager.Count == 1) + { + MsgBox.Get("errorAtLeastOneGameOrProfile").Show(MessageBoxIcon.Error); + return; + } + + if (MsgBox.Get("deleteQuestion") + .FormatTitle(ProfileManager.SelectedGame.Title) + .FormatText(ProfileManager.SelectedGame.Title) + .Show(MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes) + { + ProfileManager.RemoveGame(ProfileManager.SelectedGame); + ProfileManager.SelectedGameIndex -= 1; + UpdateGamesTab(); + } + } + + private void contextMenuStripGame_Opening(object sender, CancelEventArgs e) + { + this.gameToolStripMenuItem.Text = ProfileManager.SelectedGame.Title; + } + + #endregion + + #region Translations + + public void OnLanguageChanged(object sender, TranslationEventArgs e) + { + Translation translation = (Translation)sender; + this.labelOutdatedLanguage.Visible = translation.IsOutdated(); + } + + private void buttonDownloadLanguages_Click(object sender, EventArgs e) + { + if (this.backgroundWorkerDownloadLanguages.IsBusy) + return; + this.groupBoxLocalization.Focus(); + this.buttonDownloadLanguages.Enabled = false; + this.pictureBoxSpinnerDownloadLanguages.Visible = true; + this.backgroundWorkerDownloadLanguages.RunWorkerAsync(); + } + + private void buttonRefreshLanguage_Click(object sender, EventArgs e) + { + Localization.LookupLanguages(); + } + + private string errorMessageDownloadLanguages = null; + private string messageDownloadLanguages = null; + private void backgroundWorkerDownloadLanguages_DoWork(object sender, DoWorkEventArgs e) + { + // Download / update languages: + try + { + WebClient wc = new WebClient(); + wc.CachePolicy = new System.Net.Cache.RequestCachePolicy(System.Net.Cache.RequestCacheLevel.BypassCache); + + byte[] raw = wc.DownloadData("https://raw.githubusercontent.com/FelisDiligens/Fallout76-QuickConfiguration/master/Fo76ini/languages/list.txt"); + string encoded = Encoding.UTF8.GetString(raw).Trim(); + + string[] list = encoded.Split('\n', ','); + + foreach (string file in list) + { + wc.DownloadFile("https://raw.githubusercontent.com/FelisDiligens/Fallout76-QuickConfiguration/master/Fo76ini/languages/" + file, Path.Combine(Localization.LanguageFolder, file)); + } + + errorMessageDownloadLanguages = null; + messageDownloadLanguages = string.Join(", ", list); + } + catch (WebException ex) + { + errorMessageDownloadLanguages = ex.ToString(); + messageDownloadLanguages = null; + } + catch + { + errorMessageDownloadLanguages = "Unknown error"; + messageDownloadLanguages = null; + } + } + + private void backgroundWorkerDownloadLanguages_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) + { + if (errorMessageDownloadLanguages != null) + MsgBox.Get("failed").FormatText("Downloading language files failed.\n" + errorMessageDownloadLanguages).Popup(MessageBoxIcon.Error); + else + MsgBox.Get("downloadLanguagesFinished").FormatText(messageDownloadLanguages).Popup(MessageBoxIcon.Information); + this.buttonDownloadLanguages.Enabled = true; + this.pictureBoxSpinnerDownloadLanguages.Visible = false; + Localization.LookupLanguages(); + } + + #endregion + + #region NexusAPI + + /* + * Interface: + */ + + /// + /// As a last resort, if the SSO fails, the user can enter their API key manually. + /// + private bool APIKeyTextboxEnabled = false; + + public void RefreshNMUI() + { + /* + * Visiblility of labels: + */ + + bool loggedIn = NexusMods.User.IsLoggedIn; + + // Labels: + this.labelNMNotLoggedIn.Visible = !loggedIn; + this.labelNMDailyRateLimit.Visible = loggedIn; + this.labelNMHourlyRateLimit.Visible = loggedIn; + this.labelNMDailyRateLimitReset.Visible = loggedIn; + this.labelNMDescDailyRateLimit.Visible = loggedIn; + this.labelNMDescHourlyRateLimit.Visible = loggedIn; + this.labelNMDescLimitReset.Visible = loggedIn; + this.labelNMDescMembership.Visible = loggedIn; + this.labelNMDescUserID.Visible = loggedIn; + this.labelNMMembership.Visible = loggedIn; + this.labelNMUserID.Visible = loggedIn; + + + /* + * Position and visiblility of buttons: + */ + + int buttonMargin = 6; // px + int buttonOffset = 25; // px + + Button[] buttons = new Button[] { buttonNMLogin, buttonNMLoginManually, buttonNWLogout, buttonNMUpdateProfile, buttonNWDeleteCache }; + bool[] visiblity = new bool[] { !loggedIn, !loggedIn && APIKeyTextboxEnabled, loggedIn, loggedIn, true }; + + for (int i = 0; i < buttons.Length; i++) + { + int left = buttonOffset; + for (int j = 0; j < i; j++) + { + if (j >= 0 && visiblity[j]) + left += buttons[j].Width + buttonMargin; + } + buttons[i].Left = left; + buttons[i].Visible = visiblity[i]; + } + + + /* + * API Key textbox: + */ + + this.textBoxAPIKey.Visible = APIKeyTextboxEnabled; + this.checkBoxShowAPIKey.Visible = APIKeyTextboxEnabled; + this.labelAPIKey.Visible = APIKeyTextboxEnabled; + this.linkLabelAPIKeyHelp.Visible = APIKeyTextboxEnabled; + this.pictureBoxAPIKeyHelp.Visible = APIKeyTextboxEnabled; + + if (APIKeyTextboxEnabled) + { + this.textBoxAPIKey.Text = NexusMods.User.APIKey; + } + + + /* + * Fill in information: + */ + + this.labelNMUserName.Text = NexusMods.User.UserName; + this.labelNMUserID.Text = NexusMods.User.UserID.ToString(); + + switch (NexusMods.User.Status) + { + case NMUserProfile.Membership.Premium: + this.labelNMMembership.Text = Localization.GetString("nmPremiumAccount"); + this.labelNMMembership.ForeColor = Color.PaleGreen; + break; + case NMUserProfile.Membership.Supporter: + this.labelNMMembership.Text = Localization.GetString("nmSupporterAccount"); + this.labelNMMembership.ForeColor = Color.Orange; + break; + case NMUserProfile.Membership.Basic: + default: + this.labelNMMembership.Text = Localization.GetString("nmBasicAccount"); + this.labelNMMembership.ForeColor = Color.White; + break; + } + + this.labelNMDailyRateLimit.Text = string.Format(Localization.GetString("nmRateLimitLeft"), NexusMods.User.DailyRateLimit); + this.labelNMHourlyRateLimit.Text = string.Format(Localization.GetString("nmRateLimitLeft"), NexusMods.User.HourlyRateLimit); + DateTime dailyRateLimitReset; + if (NexusMods.User.DailyRateLimitResetString != "" && + NexusMods.User.TryParseDailyRateLimitReset(out dailyRateLimitReset)) + { + TimeSpan diff = dailyRateLimitReset - DateTime.Now; + this.labelNMDailyRateLimitReset.Text = string.Format(Localization.GetString("nmResetTime"), diff.Hours, diff.Minutes); + } + else + { + this.labelNMDailyRateLimitReset.Text = Localization.GetString("unknown"); + } + + this.pictureBoxNMProfilePicture.Image = Resources.user_white; + if (NexusMods.User.ProfilePictureFileName != null && + File.Exists(NexusMods.User.ProfilePictureFilePath)) + { + Bitmap bitmap; + using (Image img = Image.FromFile(NexusMods.User.ProfilePictureFilePath)) + { + bitmap = new Bitmap(img); + this.pictureBoxNMProfilePicture.Image = bitmap; + //this.pictureBoxNMProfilePicture.Image = Image.FromFile(NexusMods.User.ProfilePictureFilePath); + } + } + + this.checkBoxNMUpdateProfile.Checked = IniFiles.Config.GetBool("NexusMods", "bAutoUpdateProfile", true); + //this.checkBoxNMUpdateModInfo.Checked = IniFiles.Instance.GetBool(IniFile.Config, "NexusMods", "bAutoUpdateModInfo", false); + this.checkBoxNMDownloadThumbnails.Checked = IniFiles.Config.GetBool("NexusMods", "bDownloadThumbnailsOnUpdate", true); + } + + /* + * Event handler: + */ + + private void UpdateNMProfile() + { + if (this.backgroundWorkerRetrieveProfileInfo.IsBusy) + return; + if (NexusMods.User.APIKey == "") + return; + this.pictureBoxNMProfilePicture.Image = Resources.Spinner_200; + this.backgroundWorkerRetrieveProfileInfo.RunWorkerAsync(); + } + + private void buttonNMLogin_Click(object sender, EventArgs e) + { + MsgBox.Show("Login to NexusMods", "When the web browser opens, please click on 'Authorize' to login in.\nClick 'OK' to continue.", MessageBoxIcon.Information); + backgroundWorkerSSOLogin.RunWorkerAsync(); + } + + private void SingleSignOn_SSOFinished(object sender, SSOEventArgs e) + { + // The SSOFinished event handler is called from another thread, therefore Invoke is required: + this.tabPageNexusMods.Invoke(new Action(() => { + if (e.success) + { + NexusMods.User.APIKey = e.APIKey; + MsgBox.Popup("Success", "You are now logged in with your NexusMods account.", MessageBoxIcon.Information); + UpdateNMProfile(); + } + else + { + if (e.Exception != null) + { + if (e.Exception is PlatformNotSupportedException) + { + MsgBox.Show("Failed", "** WebSockets are not supported on Windows 7 and older. **\nBut you can still enter the API key manually to login. Please follow the instructions on the GitHub wiki.", MessageBoxIcon.Error); + } + else + { + MsgBox.Show("Failed", $"{e.Exception.GetType()}: {e.Exception.Message}", MessageBoxIcon.Error); + } + } + else + { + MsgBox.Popup("Failed", "Something went wrong.", MessageBoxIcon.Error); + } + + APIKeyTextboxEnabled = true; + RefreshNMUI(); + } + })); + } + + private void buttonNMLoginManually_Click(object sender, EventArgs e) + { + UpdateNMProfile(); + } + + private void buttonNMUpdateProfile_Click(object sender, EventArgs e) + { + UpdateNMProfile(); + } + + private void buttonNWLogout_Click(object sender, EventArgs e) + { + if (MsgBox.Get("areYouSure").FormatText("Do you really want to log out?").Show(MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes) + { + this.pictureBoxNMProfilePicture.Image = Resources.user_white; + NexusMods.User.Remove(); + RefreshNMUI(); + MsgBox.Get("done").FormatText("Logged out").Popup(MessageBoxIcon.Information); + } + } + + private void buttonNWDeleteCache_Click(object sender, EventArgs e) + { + if (MsgBox.Get("areYouSure").FormatText("Do you really want to delete all remote information?").Show(MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes) + { + // TODO: Call FormMods.UpdateModList after deleting remote info + NexusMods.DeleteCache(); + MsgBox.Get("done").FormatText("Removed remote information").Popup(MessageBoxIcon.Information); + } + } + + private void pictureBoxNMProfilePicture_Click(object sender, EventArgs e) + { + if (NexusMods.User.UserID >= 0) + Utils.OpenURL("https://www.nexusmods.com/users/"+ NexusMods.User.UserID); + } + + private void checkBoxShowAPIKey_CheckedChanged(object sender, EventArgs e) + { + this.textBoxAPIKey.UseSystemPasswordChar = !this.checkBoxShowAPIKey.Checked; + this.textBoxAPIKey.PasswordChar = !this.checkBoxShowAPIKey.Checked ? '\u2022' : '\0'; + } + + private void textBoxAPIKey_TextChanged(object sender, EventArgs e) + { + NexusMods.User.APIKey = this.textBoxAPIKey.Text; + } + + private void linkLabelAPIKeyHelp_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) + { + Utils.OpenURL("https://github.com/FelisDiligens/Fallout76-QuickConfiguration/wiki/Troubleshooting:-Login-with-NexusMods-failed"); + } + + + // Options: + + private void checkBoxNMUpdateProfile_CheckedChanged(object sender, EventArgs e) + { + IniFiles.Config.Set("NexusMods", "bAutoUpdateProfile", this.checkBoxNMUpdateProfile.Checked); + IniFiles.Config.Save(); + } + + private void checkBoxNMDownloadThumbnails_CheckedChanged(object sender, EventArgs e) + { + IniFiles.Config.Set("NexusMods", "bDownloadThumbnailsOnUpdate", this.checkBoxNMDownloadThumbnails.Checked); + IniFiles.Config.Save(); + } + + + /* + * Background worker: + */ + + // Retrieve profile info: + + private void backgroundWorkerRetrieveProfileInfo_DoWork(object sender, DoWorkEventArgs e) + { + NexusMods.User.Update(); + NexusMods.User.Save(); + } + + private void backgroundWorkerRetrieveProfileInfo_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) + { + RefreshNMUI(); + } + + private void backgroundWorkerSSOLogin_DoWork(object sender, DoWorkEventArgs e) + { + SingleSignOn.Connect(); + } + + #endregion + + private INIReadOnlyTweak iniReadOnlyTweak = new INIReadOnlyTweak(); + private AutoApplyTweak autoApplyTweak = new AutoApplyTweak(); + private IgnoreUpdatesTweak ignoreUpdatesTweak = new IgnoreUpdatesTweak(); + private PlayNotificationSoundsTweak playNotificationSoundsTweak = new PlayNotificationSoundsTweak(); + private ToolQuitOnLaunchTweak toolQuitOnLaunchTweak = new ToolQuitOnLaunchTweak(); + + private DeployModsOnNWModeTweak deployModsOnNWModeTweak = new DeployModsOnNWModeTweak(); + private RemoveModsOnNWModeTweak removeModsOnNWModeTweak = new RemoveModsOnNWModeTweak(); + private RenameDLLsTweak renameDLLsTweak = new RenameDLLsTweak(); + } +} diff --git a/Fo76ini/Forms/FormSettings/FormSettings.resx b/Fo76ini/Forms/FormSettings/FormSettings.resx new file mode 100644 index 0000000..e97704e --- /dev/null +++ b/Fo76ini/Forms/FormSettings/FormSettings.resx @@ -0,0 +1,306 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + + 107, 17 + + + 207, 60 + + + 388, 60 + + + + AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4w + LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0 + ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAADI + DAAAAk1TRnQBSQFMAgEBBAEAAegBAAHoAQABGAEAARgBAAT/AQkBAAj/AUIBTQE2AQQGAAE2AQQCAAEo + AwABYAMAATADAAEBAQABCAYAARIYAAGAAgABgAMAAoABAAGAAwABgAEAAYABAAKAAgADwAEAAcAB3AHA + AQAB8AHKAaYBAAEzBQABMwEAATMBAAEzAQACMwIAAxYBAAMcAQADIgEAAykBAANVAQADTQEAA0IBAAM5 + AQABgAF8Af8BAAJQAf8BAAGTAQAB1gEAAf8B7AHMAQABxgHWAe8BAAHWAucBAAGQAakBrQIAAf8BMwMA + AWYDAAGZAwABzAIAATMDAAIzAgABMwFmAgABMwGZAgABMwHMAgABMwH/AgABZgMAAWYBMwIAAmYCAAFm + AZkCAAFmAcwCAAFmAf8CAAGZAwABmQEzAgABmQFmAgACmQIAAZkBzAIAAZkB/wIAAcwDAAHMATMCAAHM + AWYCAAHMAZkCAALMAgABzAH/AgAB/wFmAgAB/wGZAgAB/wHMAQABMwH/AgAB/wEAATMBAAEzAQABZgEA + ATMBAAGZAQABMwEAAcwBAAEzAQAB/wEAAf8BMwIAAzMBAAIzAWYBAAIzAZkBAAIzAcwBAAIzAf8BAAEz + AWYCAAEzAWYBMwEAATMCZgEAATMBZgGZAQABMwFmAcwBAAEzAWYB/wEAATMBmQIAATMBmQEzAQABMwGZ + AWYBAAEzApkBAAEzAZkBzAEAATMBmQH/AQABMwHMAgABMwHMATMBAAEzAcwBZgEAATMBzAGZAQABMwLM + AQABMwHMAf8BAAEzAf8BMwEAATMB/wFmAQABMwH/AZkBAAEzAf8BzAEAATMC/wEAAWYDAAFmAQABMwEA + AWYBAAFmAQABZgEAAZkBAAFmAQABzAEAAWYBAAH/AQABZgEzAgABZgIzAQABZgEzAWYBAAFmATMBmQEA + AWYBMwHMAQABZgEzAf8BAAJmAgACZgEzAQADZgEAAmYBmQEAAmYBzAEAAWYBmQIAAWYBmQEzAQABZgGZ + AWYBAAFmApkBAAFmAZkBzAEAAWYBmQH/AQABZgHMAgABZgHMATMBAAFmAcwBmQEAAWYCzAEAAWYBzAH/ + AQABZgH/AgABZgH/ATMBAAFmAf8BmQEAAWYB/wHMAQABzAEAAf8BAAH/AQABzAEAApkCAAGZATMBmQEA + AZkBAAGZAQABmQEAAcwBAAGZAwABmQIzAQABmQEAAWYBAAGZATMBzAEAAZkBAAH/AQABmQFmAgABmQFm + ATMBAAGZATMBZgEAAZkBZgGZAQABmQFmAcwBAAGZATMB/wEAApkBMwEAApkBZgEAA5kBAAKZAcwBAAKZ + Af8BAAGZAcwCAAGZAcwBMwEAAWYBzAFmAQABmQHMAZkBAAGZAswBAAGZAcwB/wEAAZkB/wIAAZkB/wEz + AQABmQHMAWYBAAGZAf8BmQEAAZkB/wHMAQABmQL/AQABzAMAAZkBAAEzAQABzAEAAWYBAAHMAQABmQEA + AcwBAAHMAQABmQEzAgABzAIzAQABzAEzAWYBAAHMATMBmQEAAcwBMwHMAQABzAEzAf8BAAHMAWYCAAHM + AWYBMwEAAZkCZgEAAcwBZgGZAQABzAFmAcwBAAGZAWYB/wEAAcwBmQIAAcwBmQEzAQABzAGZAWYBAAHM + ApkBAAHMAZkBzAEAAcwBmQH/AQACzAIAAswBMwEAAswBZgEAAswBmQEAA8wBAALMAf8BAAHMAf8CAAHM + Af8BMwEAAZkB/wFmAQABzAH/AZkBAAHMAf8BzAEAAcwC/wEAAcwBAAEzAQAB/wEAAWYBAAH/AQABmQEA + AcwBMwIAAf8CMwEAAf8BMwFmAQAB/wEzAZkBAAH/ATMBzAEAAf8BMwH/AQAB/wFmAgAB/wFmATMBAAHM + AmYBAAH/AWYBmQEAAf8BZgHMAQABzAFmAf8BAAH/AZkCAAH/AZkBMwEAAf8BmQFmAQAB/wKZAQAB/wGZ + AcwBAAH/AZkB/wEAAf8BzAIAAf8BzAEzAQAB/wHMAWYBAAH/AcwBmQEAAf8CzAEAAf8BzAH/AQAC/wEz + AQABzAH/AWYBAAL/AZkBAAL/AcwBAAJmAf8BAAFmAf8BZgEAAWYC/wEAAf8CZgEAAf8BZgH/AQAC/wFm + AQABIQEAAaUBAANfAQADdwEAA4YBAAOWAQADywEAA7IBAAPXAQAD3QEAA+MBAAPqAQAD8QEAA/gBAAHw + AfsB/wEAAaQCoAEAA4ADAAH/AgAB/wMAAv8BAAH/AwAB/wEAAf8BAAL/AgAD//8A/wD/AP8A/wD/AP8A + /wD/ABEAAf8B3QG1AbQCzwG0AbUB3QH/JgAB/wHwAbsDswG0AboB8AH/BwAB9BbzAfQFAAH/AQkBzwit + Ac8BCQH/IgAB/wG7AYsIigGLAbsB/wUAGPMEAAHzAc8MrQHPAfMgAAHyAYsMigGLAfMEABjzAwAB3RCt + Ad0eAAG8EIoB8AMAB/ME8gLzBBsH8wIAAfMIrQK1CK0B8xwAAfIDigG0AvABCQGLCooB8wIAB/ME0wHb + AXoEOAfzAQAB/wHPB60BCQL/AQkHrQHPAf8GAA7/BgAB/wGLAooBtAG7ArQBiwHwAYsJigGLAf8BAAfz + BNMB2wF6BDgH8wEAAQkIrQHzAgABGQitAQkGAA7/BgABtQJlAYsB8wP/AfEBkQG1CmUB7wEAB/ME0wHb + AXoEOAfzAf8BzwitAbUC/wG1CK0BzwH/BQAO/wUAAf8BZgGuAbwG/wGLAfABZgllAWYB/wfzBNMB2wF6 + BDgH8wHxCq0CzwqtAd0FAA7/BQAB8AHzB/8BBwG0Af8B8wGLCWUB8AfzBNsBCQGaBHoH8wG1Cq0BzwG0 + Cq0BtQUADv8FAAHzBv8B8wKRBP8B9whlAZEH8wR1AZQBmQR4AfIG8wG0Cq0B3QHzCq0BtAUABf8EAAX/ + BQAE/wH0AfcBiwG1AfEG/wHwAZIBiwVlAa4H8wRNAXUBeAQ1AfIG8wHPCq0BCQH/AQkJrQHPBQAF/wQA + Bf8FAAL/AbwBrgRlAWYB9Aj/AbwBZgNlAWYH8wRNAXUBeAQ1AfIG8wHPC60B9AH/AfEIrQHPBQAF/wQA + Bf8FAAHvAWYHZQGuA/8B9AGuAmwBkQH/AQcDZQFmB/METQF1AXgENQHyBvMBtAutAbUC/wEJB60BtAUA + Bf8EAAX/BQABbAkNAe8C/wGuAe8C/wH3Ae0B/wFmAg0B6gfzBE0BdQF4BDUB8gbzAQkMrQH0AQAB/wHP + Bq0BtQUADv8FAAHsCQ0BZQHzAf8B6gT/AWwB/wGRAg0B7AzzBfIH8wEZCK0B3QG1Aq0B3QIAAbUGrQHx + BQAO/wUAAbwKDQH3Af8B6gT/AWwB/wHsAg0BvBjzAf8BzwatAbQBAAH0Aq0B3QEAAf8BtAWtAc8B/wUA + Dv8FAAH/Cg0BrgH/Aa4BBwL/AfcB7AH/AWYCDQH/GPMBAAEJBq0BzwL/ArQB9AEAAfQGrQEJBgAO/wYA + Ae0KDQHwAfQB6wJsAewB/wEHAg0B9wEAB/MB8gjzAfIH8wEAAf8BtAatAbUB9AP/AfMBzwWtAbQB/wYA + Dv8GAAH/AUMJDQFmAfAE/wEHAg0BQwH/CAAB8wH0AfMB9AQAAfQD8wcAAfMIrQK0Ac8HrQHzHAAB8QsN + AW0C7QESAw0B8gkAAfMB9ALzBAAB9ALzAfQIAAEZEK0B8R4AAbwQDQG8CgAB9AHzAf8B8wH/AwAB8wH0 + AfMB/wkAAfMBtAytAbQB8yAAAfEBQwwNAUMB8gsAAf8B8wH/AfQB8wH0Af8B9AHzAf8B9AsAAf8BCQHP + CK0BzwEJAf8iAAH0AfcBEAgNARAB9wH/DQAB9AHzAfQB/wH0AvMB9AH/DgAB/wEZAQkBtALPAbQBCQEZ + Af8mAAH0AbwB7AESAkMBEgHsAbwB/xAAAf8E8wH/CQABQgFNAT4HAAE+AwABKAMAAWADAAEwAwABAQEA + AQEFAAFAAQIWAAP//wAiAAH+AQABfwMAAf4BAAF/AwAB+AEAAR8DAAH4AQABHwMAAfABAAEPAwAB8AEA + AQ8DAAHgAQABBwMAAeABAAEHAwABwAEAAQMDAAHAAQABAwMAAYABAAEBAwABgAEAAQEDAAGAARgBAQMA + AYABAAEBWAABAgsAAQMLAAFCCgABgAECAQEDAAGAAQABAQMAAYABAAEBAwABgAEAAQEB/gEeAR8BwAEA + AQMDAAHAAQABAwH+AR4BHwHgAQABBwMAAeABAAEHAf4BDgEfAfABAAEPAwAB8AEAAQ8B/gEAAT8B+AEA + AR8DAAH4AQABHwH/AQABfwH+AQABfwMAAf4BAAF/Af8BgQH/Cw== + + + + 17, 17 + + + + + iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAADDPmHLAAABg2lDQ1BJQ0MgcHJvZmlsZQAAKM+VkTlI + A0EYhT+jkiCKhSlEBLdQGxVERSwlikFQkBjBq3B3Y6KQ3YTdBBtLwTZg4dF4FTbW2lrYCoLgAWJlaaVo + I7L+sxEShAgODPPxZt5j5g0EDtKm5db0gmXnnFg0os3OzWvBZ4K0EaKTLt10s5PTY3Eqjo9bqtR606Oy + +N9oSCy7JlRpwsNm1skJLwkPruWyineEw+aKnhA+Fe525ILC90o3ivyiOOVzQGWGnXhsRDgsrKXK2Chj + c8WxhAeE2xOWLfmB2SInFK8rttJ58+ee6oX1y/bMtNJlthJlnEmm0DDIs0qaHD2y2qK4xGQ/UsHf4vun + xGWIaxVTHKNksNB9P+oPfnfrJvv7ikn1Eah98ry3DghuwVfB8z4PPe/rCKof4cIu+TMHMPQueqGkte9D + 4wacXZY0YxvON6H5Ias7ui9Vywwkk/B6It80B03XULdQ7O1nn+M7iEtXE1ewuwedKclerPDuUHlvf57x + +yPyDceRcsnv+nvUAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH5AcfCjsw7KcyrwAAB1JJREFU + eF7tnWmsXWMUhotSrWoaYyRFiKJmIu2PRqi2plDhj3kOEZWI8KONag0RQ9BIighijHkMNQcxhsQcQxAR + hDZinsd63r2XH6LnnnPvPfvb3959n+RNbnp2z1rr/c45e/zWN8IYY4wxxhhjjDHGmFawbNmyldBEdBi6 + AN2BnkVvofdD+vsZdDs6Hx2KNkMrxduYJsHArYx2R1ehz9BQ+RRdiXZF/jDkDoM0Bp2CPkT95gN0Mhod + 4UwuMCiroBPQElQ1n6Nj0coR3tQJAzEJvYRS8zzaPNIwdcAAHId+0WjUxE/oyEjHpALTR6LLNQKZsBCt + EumZKsHoUeheuZ4ZOr1cLdI0VSCD0YNyO1PuQ6tGuqafYKzO7W+Ry5lzI/I1g36DqWcX9jaDeZG26QcY + uk/pa2P4G82M9M1wwMh10FK52jC+QGtFGWaoYOINhZ3N5JoowwwFDJxc+thYtCvYKcoxgwXzHitsbDaL + oxwzGDBup9K/VrBtlGV6BdOuKb1rBVdGWaYXMGw0+qGwrh18g3yZuFcwa1ZhW7vYK8oz3cCsRaVnreLS + KM90A7NeLz1rFS9FeWYgMEq3e/8sLGsXv6GRUabpBCZtXdjVTiZGmaYTmLR36VUrmR5lmk5g0pGlV63k + oCjTdAKTZpdetZLjo0zTCUzSxI62MjvKNJ3AJM2+aSsnRJmmE5h0TOlVKzk0yjSdwKT9Sq9ayR5RpukE + Jm1fetVKJkWZphOYpBm+epKmbejqpu8I9gJGvVtY1i7eiPJMNzCrTQ+D/MsVUZ7pBmYdVHrWKg6I8kw3 + MGsc+rWwrR1oGvkaUZ7pBQy7rbCuHdwUZZlewTQ1ZmoLU6Ms0yuYpvZuLxf2NRu1kvFs4aGAcXsUFjab + aVGOGQoY+EDpYyO5J8owQwUTN0JNnCPwHZoQZZjhgJFHFJY2i0MifdMPMFRtX5vCokjb9AtMVYOoJwp7 + 8+YR5EZRVYCxukKY86nhC2hspGuqAIPHh9G5oXbz4yJNUyUYvQa6X65nwl3IXcRTguHqG6jWcXU+PPIX + mofcOXw4YOB6aCY6CZ2LLkMXox1jk46wzW7oI5QarUmwS6TREbbZGV2CVNM5SDWq1nVjkxUTDNgWXYS6 + Pf1zPRrQLF7XLkEfnBSdw3VrdwEa8Cef1/WhvhkNxDvoQrR1/Ld2Q6G6wbMn0gHTYPgSaR2fAW+q8PoG + SN+271G/0ZU9fWDXj3DLhddV4+HoKzQYnkLtnTtIcZsgnSMPB90X2DDesiNsMxZpfsGj6Hc0VDSl+2F0 + FOr6QAfb6LL1YjQc1Ax743jLdkBBesSrX9fz9e3WfrSnAy+20+5BdxXPRFoVTNcRtJCUfsp1ECfpb/2b + Vh7Rgyg6sJuBxsTbDAjb6YBUM5r6VaN+bQ6Mt282FDK3KKn/PIdqb79GDprHoHv+VXB6hGkmFHBGWUdl + 6Nt7Ldo0QiaDmFpX8DpU9WloMz8EJJ5ynr8+CHeiaaiyc3K9N9Ku4W6kmKk4OFJoBiS8I6rrqV5dE9Ap + 4XZo2I9i6T2QfubPQx+jOvgZNaPbKImqyWMuM3s0YFcjHcWr91DXu3TaBm2DjkaaoPIJyoE30ahIM19I + Ut+UXPkD6RdCB2063dJuQ9Lf+je9lnOHsgVhc56Q4KZI586mGrRbzfcaAcndWqRpquSGsDsvSEz7TVM9 + OvvYImzPB5K6qUjPpODasD0PSEg3YXSAZdKg46x8bieTTNVX/Mz/yeMKIYnoQsn7RUomJW/FENQLibS5 + qVPubBXDUB8kMb/MxdTAnBiG+iCJF8tcTA08HcNQDySgiRop74qZ/6KnnXp6aKUSCN7m3v5NYUYMR3oI + nvONnxWF+TEc6SH442UOpkYejOFIC4F1/j/YR59N/1kSQ5IWAk8o45sMGHCuQiUQdK8ytsmA3WNY0kHQ + U8vYJgNOimFJB0GvKGObDFgYw5IOgj5UxjYZcF8MSzoI+nYZ22TAqzEs6SCo1sQ3ebA0hiUNBNSz8yYf + dD8mXZcSgqn5gcmL8TE81UMwTYw0ebFRDE/1EExz/0xepHs6iGBTy5gmIybH8FQPwaaXMU1GdO1Y1jcI + 5gdB8iNdgymC7VvGNBmRbl1igvkDkB97xvBUD8HasJZP29gthqd6CDaljGkyYocYnuohmJ8Gyo90k0UJ + pm5ZPxZhTQ58jdKuTUjAwfb7NdXxWAxLOgh6VhnbZMDcGJZ0ENSzgvNhyxiWdBBU8wJeKcKbOnkhhiQ9 + BFcXcFMv+8dwpIfgOhtQi3VTDzoQr3dlchJQe7i6+gKvyKh/cPp9//IgEfXVNWnJa21iEppT5mUScFrY + nhckdiLKudly01FHkOPC7jwhQT0upjX1TH9RK74pYXPekKjWDFDzyG+RGR66zq/d6+phb3Mg6TWRVvhS + L/46l3htGprooUWxtEttx2rkFLI2moV0D0Eraj6JXkNaXeS9FVSqXR7ICzXbVs9FPW21VthmjDHGGGOM + McYYY0w/GDHiH4RSOYX/ZZhxAAAAAElFTkSuQmCC + + + + 107, 17 + + + 17, 60 + + + 498, 60 + + + 17, 99 + + + 269, 101 + + + 346 + + + + AAABAAEAGBgAAAEAIACICQAAFgAAACgAAAAYAAAAMAAAAAEAIAAAAAAAAAkAAMMOAADDDgAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADhaUEA4GhAq+FpQfPgaUDz4GlBq+Fp + QQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAADgaEEq4WlB8eBpQf/haUH/4WlB8eBoQSoAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA4GhASOBpQCoAAAAAAAAAAAAAAADhaUGF4WlA/+Fp + Qf/haUD/4WlB/+FpQIUAAAAAAAAAAAAAAADhaUEq4WlBSAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AADgaEFq4WlB+eBoQf/haUG54GhAUuFpQTrhaUHr4WlB/+FpQf/haUD/4WlB/+FoQOvgaEE64WlAUuFp + QbnhaUD/4GhB+eBpQWoAAAAAAAAAAAAAAAAAAAAAAAAAAOFpQUjgaED54WlB/+FpQf/haEH/4GlB/eFp + QfnhaEH/4GlB/+BpQf/haUH/4WlB/+FpQf/gaUH54WhB/eFpQf/haUH/4WlB/+BoQfnhaUFIAAAAAAAA + AAAAAAAAAAAAAOFpQCrhaUH/4WlA/+FpQf/haUH/4WlA/+FpQf/haUH/4WlA/+FpQf/haUD/4WlB/+Fp + QP/haUD/4WlB/+FpQP/haUD/4WlB/+FpQP/haUEqAAAAAAAAAAAAAAAAAAAAAAAAAADgaEG54WlB/+Bo + Qf/haUH/4WlB/+FpQf/haUH/4WlB/+FpQf/haUD/4WlB/+FoQP/haUD/4WlB/+FoQP/haUD/4WlB/+Fp + QLkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADhaUFS4WlB/eFpQf/haEH/4GlB/+BpQf/gaEH74GhA0eFo + QZvhaUGb4WlB0eFoQfvhaUH/4WlB/+FpQf/haUH/4WlB/eFoQVIAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AADhaUE64WlB+eFpQf/haUH/4WlA/+FpQfXhaUFa4WhBBgAAAAAAAAAA4GhBBuFpQFrhaUD14WlB/+Fp + QP/haUD/4WhA+eBoQTgAAAAAAAAAAAAAAADhaEEA4WlBKuFpQYXhaEHr4WlB/+BoQf/haUH/4WlB++Fo + QVgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADgaEFY4WlB++FoQP/haUD/4WlB/+FoQOvhaUGF4GlBKuFp + QQDgaEGr4WlB8eFpQf/haUH/4WlB/+FpQf/haEH/4GhAzeFpQQYAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AADhaUEG4WlBzeFpQf/haUH/4WlB/+FpQf/haUH/4WlB8eBoQKvhaUDz4WlB/+FpQf/haUH/4WlA/+Fp + Qf/haUH/4WlBlQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA4WlBleFpQP/haUD/4WlB/+Fp + QP/haUD/4WlB/+FpQPPhaUDz4WlB/+FpQf/haEH/4WlB/+FpQf/gaEH/4WlBkwAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAA4WlBk+FpQf/haUH/4WlB/+FpQf/haUH/4WlB/+FpQfPhaUGr4WlB8eFp + Qf/haUH/4WhB/+FpQf/haUD/4WlByeFpQQQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADhaUEE4GlByeFp + Qf/haUH/4WlB/+FpQf/haUH/4WlB8eBpQavgaEAA4WhAKOBoQYXhaUHr4WlB/+FpQf/gaEH/4WhA+eBo + QVAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADhaEBQ4GhA+eBoQP/gaED/4GhA/+BoQOvhaUGF4WlBKOFp + QQAAAAAAAAAAAAAAAADgaEE64WlB+eFpQf/gaEH/4WlB/+FoQfHgaUFO4WlBBAAAAAAAAAAA4WlBBOFp + QU7haUHx4WlB/+FpQf/haUH/4GhB+eFoQTwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADhaEFS4WhA/eFp + Qf/haUD/4WlB/+FpQf/gaED54WlBw+FpQYvhaUGL4WhBw+FpQPnhaUH/4WlB/+FpQf/haUH/4WlB/eBo + QFIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADhaUG54WlB/+FpQf/gaEH/4WlA/+BoQf/gaEH/4WlA/+Bo + Qf/gaED/4GhA/+BoQP/gaED/4GhA/+BoQP/gaED/4GhA/+FpQLkAAAAAAAAAAAAAAAAAAAAAAAAAAOFp + QSrhaEH/4WlB/+FoQf/haUH/4WlB/+FpQf/haUH/4WlB/+FpQf/haUH/4WlB/+FoQf/haUH/4WlB/+Fo + Qf/haUH/4WlB/+FoQf/gaUAqAAAAAAAAAAAAAAAAAAAAAOFpQUjhaUH54WhB/+FpQf/haUH/4WlB/eFo + QfnhaUH/4WhB/+FpQf/haUH/4WlB/+FpQf/haUH54WlB/eFpQf/haUH/4WlB/+FpQfngaEBIAAAAAAAA + AAAAAAAAAAAAAAAAAADgaEFq4GhA+eBoQf/haUG54WhBUuFpQTzgaEHr4WhB/+BoQf/gaED/4GhA/+Bo + QOvhaUE44WhBUuBoQbngaED/4GlA+eBoQWoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA4WhBSOFo + QCoAAAAAAAAAAAAAAADgaECF4WlB/+FpQf/haUH/4WlB/+BpQIUAAAAAAAAAAAAAAADhaUAq4WlBSAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADgaUEq4WlA8eFp + Qf/haUH/4WlB8eFpQSoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADgaEAA4GhBq+FpQPPhaUDz4GhBq+FoQQAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/w/8A/4H/APOBzwDgAAcAwAADAMAAAwDgAAcA4AAHAOAY + BwCAfgEAAH4AAAD/AAAA/wAAAH4AAIB+AQDgGAcA4AAHAOAABwDAAAMAwAADAOAABwDzgc8A/4H/AP/D + /wA= + + + \ No newline at end of file diff --git a/Fo76ini/Forms/FormSplash/FormSplash.Designer.cs b/Fo76ini/Forms/FormSplash/FormSplash.Designer.cs new file mode 100644 index 0000000..c8d56a7 --- /dev/null +++ b/Fo76ini/Forms/FormSplash/FormSplash.Designer.cs @@ -0,0 +1,117 @@ +namespace Fo76ini.Forms.FormSplash +{ + partial class FormSplash + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(FormSplash)); + this.pictureBox1 = new System.Windows.Forms.PictureBox(); + this.labelVersion = new System.Windows.Forms.Label(); + this.progressBar1 = new System.Windows.Forms.ProgressBar(); + this.labelLoading = new System.Windows.Forms.Label(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit(); + this.SuspendLayout(); + // + // pictureBox1 + // + this.pictureBox1.BackColor = System.Drawing.Color.Transparent; + this.pictureBox1.Image = global::Fo76ini.Properties.Resources.banner; + this.pictureBox1.Location = new System.Drawing.Point(0, 0); + this.pictureBox1.Name = "pictureBox1"; + this.pictureBox1.Size = new System.Drawing.Size(500, 223); + this.pictureBox1.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom; + this.pictureBox1.TabIndex = 0; + this.pictureBox1.TabStop = false; + // + // labelVersion + // + this.labelVersion.AutoSize = true; + this.labelVersion.BackColor = System.Drawing.Color.Black; + this.labelVersion.Font = new System.Drawing.Font("Microsoft Sans Serif", 12F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.labelVersion.ForeColor = System.Drawing.Color.White; + this.labelVersion.Location = new System.Drawing.Point(295, 186); + this.labelVersion.Name = "labelVersion"; + this.labelVersion.Size = new System.Drawing.Size(57, 20); + this.labelVersion.TabIndex = 1; + this.labelVersion.Text = "v2.0.0"; + // + // progressBar1 + // + this.progressBar1.BackColor = System.Drawing.Color.Black; + this.progressBar1.Location = new System.Drawing.Point(8, 220); + this.progressBar1.MarqueeAnimationSpeed = 10; + this.progressBar1.Name = "progressBar1"; + this.progressBar1.Size = new System.Drawing.Size(484, 20); + this.progressBar1.Style = System.Windows.Forms.ProgressBarStyle.Marquee; + this.progressBar1.TabIndex = 2; + // + // labelLoading + // + this.labelLoading.AutoSize = true; + this.labelLoading.BackColor = System.Drawing.Color.Black; + this.labelLoading.Font = new System.Drawing.Font("Microsoft Sans Serif", 11.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.labelLoading.ForeColor = System.Drawing.Color.White; + this.labelLoading.Location = new System.Drawing.Point(5, 198); + this.labelLoading.Name = "labelLoading"; + this.labelLoading.Size = new System.Drawing.Size(72, 18); + this.labelLoading.TabIndex = 3; + this.labelLoading.Text = "Loading..."; + // + // FormSplash + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.BackColor = System.Drawing.Color.Black; + this.ClientSize = new System.Drawing.Size(500, 250); + this.ControlBox = false; + this.Controls.Add(this.labelLoading); + this.Controls.Add(this.progressBar1); + this.Controls.Add(this.labelVersion); + this.Controls.Add(this.pictureBox1); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None; + this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); + this.MaximizeBox = false; + this.MaximumSize = new System.Drawing.Size(500, 250); + this.MinimizeBox = false; + this.MinimumSize = new System.Drawing.Size(500, 250); + this.Name = "FormSplash"; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; + this.Text = "Fallout 76 Quick Configuration"; + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.PictureBox pictureBox1; + private System.Windows.Forms.Label labelVersion; + private System.Windows.Forms.ProgressBar progressBar1; + private System.Windows.Forms.Label labelLoading; + } +} \ No newline at end of file diff --git a/Fo76ini/Forms/FormSplash/FormSplash.cs b/Fo76ini/Forms/FormSplash/FormSplash.cs new file mode 100644 index 0000000..98dffee --- /dev/null +++ b/Fo76ini/Forms/FormSplash/FormSplash.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace Fo76ini.Forms.FormSplash +{ + // https://stackoverflow.com/questions/15836027/c-sharp-winform-loading-screen/15836105#15836105 + public partial class FormSplash : Form + { + // Delegate for cross thread call to close + private delegate void CloseDelegate(); + + // The type of form to be displayed as the splash screen. + private static FormSplash splashForm; + + public FormSplash() + { + InitializeComponent(); + } + + public static void ShowSplashScreen() + { + // Make sure it is only launched once. + if (splashForm != null) return; + splashForm = new FormSplash(); + Thread thread = new Thread(new ThreadStart(FormSplash.ShowForm)); + thread.IsBackground = true; + thread.SetApartmentState(ApartmentState.STA); + thread.Start(); + } + + private static void ShowForm() + { + if (splashForm != null) Application.Run(splashForm); + } + + public static void CloseForm() + { + splashForm?.Invoke(new CloseDelegate(FormSplash.CloseFormInternal)); + } + + private static void CloseFormInternal() + { + if (splashForm != null) + { + splashForm.Close(); + splashForm = null; + }; + } + } +} diff --git a/Fo76ini/Forms/FormSplash/FormSplash.resx b/Fo76ini/Forms/FormSplash/FormSplash.resx new file mode 100644 index 0000000..fed7c34 --- /dev/null +++ b/Fo76ini/Forms/FormSplash/FormSplash.resx @@ -0,0 +1,825 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + + 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 + w/4VRWD/GyEk/xwbGv8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cGxv/HB8h/xY+Vf8Mern/B5jq6weU + 5e0Khs7+Dmyi/w1yrP8Hl+rXCZDeJQmR4QAAAAAADoPLAAC//wAHl+pzCYzW/Rg0RP8cGxv/Gicv/xc9 + VP8US2v/Gis1/xwaGf8cHBv/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBoZ/xon + Lv8VSWj/FkBZ/xopMv8cHB3/Gis1/wqEyv8HmOyMFG+rAgyI0wAIkuIACZDfKAeY7NsRW4b/HBwc/xwc + HP8cGxv/HBoZ/xwaGf8cGxv/HBwc/xwcHP8cHBz/HBwc/xwbGv8cGhn/HBoZ/xwaGf8cHBv/HBwc/xwc + HP8cHBz/HBsb/xwaGf8cGhn/HBsb/xwcHP8cGxr/FE9x/weX6ekIk+M6B5boABF4ugQHmOyQC4LG/xoq + M/8cGxr/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwbGv8cHh//GS46/xY+Vf8WQVv/GDZI/xsk + Kf8cGxr/HBwb/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwbG/8bJCn/DHi2/weZ7akMiNILCZHhRAeX + 6usUT3L/HBoY/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cGxr/GDNC/w9roP8JitT/CYzX/wmL + 1f8Jjdj/C36//xRLa/8bICL/HBsb/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwaGP8WQl3/B5Xl9AiT + 5F4JkuFBB5jr4A9roP8bJSv/HBsa/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBsa/xc9VP8Kh8//C37A/xRM + bP8YMkL/GS88/xc9U/8PZ5r/CI/c/xBikP8bIST/HBwb/xwcHP8cHBz/HBwc/xwcHP8cGxv/GyEk/xBg + j/8Hl+nrCJPkWQD//wAJkuFMB5jq4Q5to/8aJi3/HBsb/xwcHP8cHBz/HBwc/xwbGv8ZLjr/CoXL/w5v + p/8aJy//HBoY/xwbGv8cGxr/HBoZ/xwdHf8VSWj/CI/c/xNTeP8cGxv/HBwc/xwcHP8cHBz/HBsb/xsi + Jv8QY5L/B5bo7AiT42ASeboCEXq8AAD//wAIlORFBpru2w9qnv8bICP/HBwb/xwcHP8cHBz/HBsb/xFf + jP8Khcv/Gis1/xwaGf8cHBz/HBwc/xwcHP8cHBz/HBwb/xwbG/8RXYj/CobO/xorNf8cGxr/HBwc/xwc + HP8cHR7/EV6L/weY6+YIledYGF+SAg6AxQAAAAAADIvYAAOj/AAHl+pyCofP/xooMf8cGxv/HBwc/xwb + G/8bJCr/C4HE/xFch/8cGhn/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBsa/xkwPv8Ji9b/FUdj/xwa + Gf8cHBz/HBwb/xsiJv8Lfr//B5ntjQD//wALjNkAAAAAAAAAAAAAAAAABpvwAAeZ7GwLgsb/GyUr/xwb + G/8cHBz/HBsa/xktOf8JitT/FURf/xwaGP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBv/GyIn/wt/ + wv8SWYL/HBoZ/xwcHP8cHBz/HB8i/w13tP8Hmu6IAaj/ABF8vwAAAAAAAAAAAAAAAAAGm/AAB5nsbAuC + xv8bJSv/HBsb/xwcHP8cGxr/GS05/wmK1P8VRF//HBoY/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwc + G/8bIif/C3/C/xJZgv8cGhn/HBwc/xwcHP8cHyL/DXe0/wea7ogBqP8AEXy/AAAAAAAAAAAADIvYAAOj + /AAHl+pyCofP/xooMf8cGxv/HBwc/xwbG/8bJCr/C4HE/xFch/8cGhn/HBwc/xwcHP8cHBz/HBwc/xwc + HP8cHBz/HBsa/xkwPv8Ji9b/FUdj/xwaGf8cHBz/HBwb/xsiJv8Lfr//B5ntjQD//wALjNkAAAAAABF6 + vAAA//8ACJTkRQaa7tsPap7/GyAj/xwcG/8cHBz/HBwc/xwbG/8RX4z/CoXL/xorNf8cGhn/HBwc/xwc + HP8cHBz/HBwc/xwcG/8cGxv/EV2I/wqGzv8aKzX/HBsa/xwcHP8cHBz/HB0e/xFei/8HmOvmCJXnWBhf + kgIOgMUAAP//AAmS4UwHmOrhDm2j/xomLf8cGxv/HBwc/xwcHP8cHBz/HBsa/xkuOv8Khcv/Dm+n/xon + L/8cGhj/HBsa/xwbGv8cGhn/HB0d/xVJaP8Ij9z/E1N4/xwbG/8cHBz/HBwc/xwcHP8cGxv/GyIm/xBj + kv8HlujsCJPjYBJ5ugIJkuFBB5jr4A9roP8bJSv/HBsa/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBsa/xc9 + VP8Kh8//C37A/xRMbP8YMkL/GS88/xc9U/8PZ5r/CI/c/xBhkP8bIST/HBwb/xwcHP8cHBz/HBwc/xwc + HP8cGxv/GyEk/xBgj/8Hl+nrCJPkWQmR4UQHl+rrFE9y/xwaGP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwc + HP8cHBz/HBsa/xgzQv8Pa6D/CYrU/wmM1/8Ji9X/CY3Y/wt+v/8US2v/GyAi/xwbG/8cHBz/HBwc/xwc + HP8cHBz/HBwc/xwcHP8cGhj/FkJd/weV5fQIk+ReEXi6BAeY7JALgsb/Gioz/xwbGv8cHBz/HBwc/xwc + HP8cHBz/HBwc/xwcHP8cHBz/HBsa/xweH/8ZLjr/Fj5V/xZBW/8YNkj/GyQp/xwbGv8cHBv/HBwc/xwc + HP8cHBz/HBwc/xwcHP8cHBz/HBsb/xskKf8MeLb/B5ntqQyI0gsIkuIACZDfKAeY7NsRW4b/HBwc/xwc + HP8cGxv/HBoZ/xwaGf8cGxv/HBwc/xwcHP8cHBz/HBwc/xwbGv8cGhn/HBoZ/xwaGf8cHBv/HBwc/xwc + HP8cHBz/HBsb/xwaGf8cGhn/HBsb/xwcHP8cGxr/FE9x/weX6ekIk+M6B5boAA6DywAAv/8AB5fqcwmM + 1v0YNET/HBsb/xonL/8XPVT/FEtr/xorNf8cGhn/HBwb/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwc + HP8cHBz/HBwc/xwaGf8aJy7/FElo/xZAWf8aKTL/HBwd/xorNf8KhMr/B5jsjBRvqwIMiNMAAAAAAAmP + 3AAKjdkWB5jrxQx4tv8PaZ3/CoTJ/giT4/AHmOvoC4DD/hVFYP8bIST/HBsa/xwcHP8cHBz/HBwc/xwc + HP8cHBz/HBwc/xwbG/8cHyH/Fj5V/wx6uf8HmOrrB5Tl7QqGzv4ObKL/DXKs/weX6tcJkN4lCZHhAAAA + AAAAAAAAD3y/AAWe9AAIk+NSB5js1geZ7bMHmOt0CJPkOQmQ3zAHmeyfB5Tk8g11sP8YNUf/HBsa/xwc + HP8cHBz/HBwc/xwcHP8cGxr/GS47/w5upv8IkuH2B5ntrgmS4TkJkuIyB5jqbAeZ7awHmezYCJTlaAC9 + /wANgsgAAAAAAAAAAAAAAAAADIjSAAyG0AULitYZDYTMBwDU/wAeSXIACo7cAAuJ1AgIlOVHBpzxzA5s + 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 + 7/8RYI7/HCAk/xktOf8VRmP/EGWW/wuBxP8IkN3/DH2+/xc/V/8cHR3/HBsa/xwcHP8cHBz/HBwc/xwc + HP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBsb/xwbG/8YNUb/DXOu/wiQ + 3f8Khcv/D2qf/xRMbP8ZMUD/HCAj/xRNb/8HmOr/B5fpzAuJ1BwKjNkAAAAAAAAAAAAAAAAAE3GuAAWf + 9gAJkeBXBpru9gqFzP8aLTj/HBsa/xwbGv8cGhn/HBwc/xslLP8ZMUD/GyYt/xwbGv8cHBz/HBwc/xwc + HP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwc + HP8cGxr/GyMn/xkxQP8aKDH/HB0e/xwaGf8cGxr/HBsa/xsjKP8NdrP/Bpvw/giT433UAAAAD33CAAAA + AAAAAAAAC4rVAAyI0hgHlunGBpjr/xRQdP8cGxr/HBwc/xwcHP8cHBz/HBwc/xwbG/8cGxr/HBsb/xwc + HP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwc + HP8cHBz/HBwc/xwcHP8cHBz/HBwb/xwbGv8cGxv/HBwc/xwcHP8cHBz/HBwc/xwaGf8XPlb/CJPi/weY + 6+EKjNkwCZDfAAAAAAAOgccAAO3/AAiS4nYGm/D9DHm5/xslK/8cGxv/HBwc/xwcHP8cHBz/HBwc/xwc + HP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cGxr/HBoZ/xwaGf8cGhn/HBoZ/xwa + Gf8cGxv/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwc + HP8cHiD/D2ic/wab8P8IlOWbEHu+Bg2FzgAJkN8ACo3aKgeY69wHlOT/FkJc/xwaGf8cHBz/HBwc/xwc + HP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBsa/xwdHf8aKzX/Fz9W/xRM + bf8UTnH/FUlo/xg4S/8bJSv/HBsa/xwbG/8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwc + HP8cHBz/HBwc/xwcHP8cGxr/GTJC/wmL1f8Gme3vCZDeRweY6wATcK0GCJTklAab7/8Pap//HB8h/xwc + G/8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcG/8cHBz/GDRE/xBl + lv8KiNH/B5jq/wac8f8GnPL/Bpvw/weU5P8Lf8H/E1R6/xonL/8cGxr/HBwc/xwcHP8cHBz/HBwc/xwc + HP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwb/xJYgP8Gme3/B5bntw2DyxMMiNIjB5bp3AaZ + 7f8TVHv/HBsa/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwb/xwf + If8UT3P/CYzX/wad8v8IkN7/DXe1/xBll/8RYZD/D2qf/wuAw/8Hl+n/Bpvw/wx8vP8XOU3/HBsb/xwc + HP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBoZ/xZCXP8HlOX/B5jr8QqM + 2UUPgMYICJPkhAaZ7fkIj9v/FUlo/xwcHP8cHBv/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwc + HP8cHBz/HB4f/xJYgP8Hl+n/B5Xm/xBmmP8YNUb/GyAk/xwcG/8cGxv/HBwd/xslK/8WQl3/DHq5/wab + 8P8JidL/FzxS/xwbGv8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cGxr/FztQ/wqG + zf8Gmu7+CJXmpAyI0xUMh9EADoHHCgmR4IcGme35CJHf/xRLbP8cHB3/HBwb/xwcHP8cHBz/HBwc/xwc + HP8cHBz/HBwc/xwcHP8cGxr/FUhm/weV5v8Ikd//FExt/xweH/8cGhn/HBwb/xwcHP8cHBz/HBwc/xwb + G/8cGhn/GyYu/xBnmv8Gm+//C4PI/xkuOv8cGxr/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwb + Gv8XPVT/CojR/waa7/4Ik+OmDIbQFgqN2gAAAAAADn/EABB3uAoJkN+BBpru9QiS4f8UTnD/HB0e/xwc + HP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwbGv8aKjT/C4PI/waY6/8TUXb/HBwb/xwcG/8cHBz/HBwc/xwc + HP8cHBz/HBwc/xwcHP8cHBz/HBsa/xskKf8Ocar/Bpzy/xBklf8cHR7/HBwc/xwcHP8cHBz/HBwc/xwc + HP8cHBz/HBwb/xY/V/8JitP/Bpvw/AiS4p8Of8QWDIfRAAAAAAAAAAAAAAAAAAyH0QAPfMAHCJXmdAaa + 7vMIkeD/Fz5V/xwaGf8cHBz/HBwc/xwcHP8cHBz/HBwc/xwaGf8TUXT/Bpvw/w10sP8bIib/HBsb/xwc + HP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwaGf8YNUb/CI7b/wmN2v8ZMUD/HBsa/xwc + HP8cHBz/HBwc/xwcHP8cGxr/GS89/wqHz/8Gm/D7B5bokwyI0hAJkuIAOQAAAAAAAAAAAAAAAAAAAAAA + AAAMitYAEH3BBQiV5pwGm/D/E1Z9/xwaGf8cHBz/HBwc/xwcHP8cHBz/HBwc/xwfIv8NdLD/Bpnt/xVH + ZP8cGhn/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHR7/D2ug/wac + 8f8UUHP/HBoZ/xwcHP8cHBz/HBwc/xwcHP8cGhn/FkJc/weY6v8HlunADInTEguL1wAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAVaaIAAP//AAiS4pcGmu7/FE1u/xwaGf8cHBz/HBwc/xwcHP8cHBz/HBsb/xop + Mv8KiND/CY3Z/xkuOv8cGxr/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwc + HP8cGhn/FE1u/wac8f8PZ5r/HBwc/xwcHP8cHBz/HBwc/xwcHP8cGhn/FzpP/weU5f8Ilea9EXW1ChB5 + uwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPhMsA/wAAAAiW6JsGmOz/FUdk/xwaGf8cHBz/HBwc/xwc + HP8cHBz/HBsa/xkwPv8IkN3/CoPI/xslK/8cGxv/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwc + HP8cHBz/HBwc/xwcHP8cGhn/Fj5V/weY6/8Nc67/HB8g/xwcHP8cHBz/HBwc/xwcHP8cGhn/GDVH/wiS + 4f8HmOvBDYrUCwyL1gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPhMsA/wAAAAiW6JsGmOz/FUdk/xwa + Gf8cHBz/HBwc/xwcHP8cHBz/HBsa/xkwPv8IkN3/CoPI/xslK/8cGxv/HBwc/xwcHP8cHBz/HBwc/xwc + HP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cGhn/Fj5V/weY6/8Nc67/HB8g/xwcHP8cHBz/HBwc/xwc + HP8cGhn/GDVH/wiS4f8HmOvBDYrUCwyL1gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAVaaIAAP//AAiS + 4pcGmu7/FE1u/xwaGf8cHBz/HBwc/xwcHP8cHBz/HBsb/xopMv8KiND/CY3Z/xkuOv8cGxr/HBwc/xwc + HP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cGhn/FE1u/wac8f8PZ5r/HBwc/xwc + HP8cHBz/HBwc/xwcHP8cGhn/FzpP/weU5f8Ilea9EXW1ChB5uwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAMitYAEH3BBQiV5pwGm/D/E1Z9/xwaGf8cHBz/HBwc/xwcHP8cHBz/HBwc/xwfIv8NdLD/Bpnt/xVH + ZP8cGhn/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHR7/D2ug/wac + 8f8UUHP/HBoZ/xwcHP8cHBz/HBwc/xwcHP8cGhn/FkJc/weY6v8HlunADInTEguL1wAAAAAAAAAAAAAA + AAAAAAAAAAAAAAyH0QAPfMAHCJXmdAaa7vMIkeD/Fz5V/xwaGf8cHBz/HBwc/xwcHP8cHBz/HBwc/xwa + Gf8TUXT/Bpvw/w10sP8bIib/HBsb/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwa + Gf8YNUb/CI7b/wmN2v8ZMUD/HBsa/xwcHP8cHBz/HBwc/xwcHP8cGxr/GS89/wqHz/8Gm/D7B5bokwyI + 0hAJkuIAOQAAAAAAAAAAAAAADn/EABB3uAoJkN+BBpru9QiS4P8UTm//HB0e/xwcHP8cHBz/HBwc/xwc + HP8cHBz/HBwc/xwbGv8aKjT/C4PI/waY6/8TUXb/HBwb/xwcG/8cHBz/HBwc/xwcHP8cHBz/HBwc/xwc + HP8cHBz/HBsa/xskKf8Ocar/Bpzy/xBklf8cHR7/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwb/xY/ + V/8JitP/Bpvw/AiS4p8Of8QWDIfRAAAAAAAMh9EADoHHCgmR4IcGme35CJHf/xRLbP8cHB3/HBwb/xwc + HP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cGxr/FUhm/weV5v8Ikd//FExt/xweH/8cGhn/HBwb/xwc + HP8cHBz/HBwc/xwbG/8cGhn/GyYu/xBnmv8Gm+//C4PI/xkuOv8cGxr/HBwc/xwcHP8cHBz/HBwc/xwc + HP8cHBz/HBwc/xwbGv8XPVT/CojR/waa7/4Ik+OmDIbQFgqN2gAPgMYICJPkhAaZ7fkIj9v/FUlo/xwc + HP8cHBv/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HB4f/xJYgP8Hl+n/B5Xm/xBm + mP8YNUb/GyAk/xwcG/8cGxv/HBwd/xslK/8WQl3/DHq5/wab8P8JidL/FzxS/xwbGv8cHBz/HBwc/xwc + HP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cGxr/FztQ/wqGzf8Gmu7+CJXmpAyI0xUMiNIjB5bp3AaZ + 7f8TVHv/HBsa/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwb/xwf + If8UT3P/CYzX/wad8v8IkN7/DXe1/xBll/8RYZD/D2qf/wuAw/8Hl+n/Bpvw/wx8vP8XOU3/HBsb/xwc + HP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBoZ/xZCXP8HlOX/B5jr8QqM + 2UUTcK0GCJTklAab7/8Pap//HB8h/xwcG/8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwc + HP8cHBz/HBwc/xwcG/8cHBz/GDRE/xBllv8KiNH/B5jq/wac8f8GnPL/Bpvw/weU5P8Lf8H/E1R6/xon + L/8cGxr/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwb/xJY + gP8Gme3/B5bntw2DyxMJkN8ACo3aKgeY69wHlOT/FkJc/xwaGf8cHBz/HBwc/xwcHP8cHBz/HBwc/xwc + HP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBsa/xwdHf8aKzX/Fz9W/xRMbf8UTnH/FUlo/xg4 + S/8bJSv/HBsa/xwbG/8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwc + HP8cGxr/GTJC/wmL1f8Gme3vCZDeRweY6wAOgccAAO3/AAiS4nYGm/D9DHm5/xslK/8cGxv/HBwc/xwc + HP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cGxr/HBoZ/xwa + Gf8cGhn/HBoZ/xwaGf8cGxv/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwc + HP8cHBz/HBwc/xwcHP8cHiD/D2ic/wab8P8IlOWbEHu+Bg2FzgAAAAAAC4rVAAyI0hgHlunGBpjr/xRQ + dP8cGxr/HBwc/xwcHP8cHBz/HBwc/xwbG/8cGxr/HBsb/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwc + HP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwb/xwb + Gv8cGxv/HBwc/xwcHP8cHBz/HBwc/xwaGf8XPlb/CJPi/weY6+EKjNkwCZDfAAAAAAAAAAAAE3GuAAWf + 9gAJkeBXBpru9gqFzP8aLTj/HBsa/xwbGv8cGhn/HBwc/xslLP8ZMUD/GyYt/xwbGv8cHBz/HBwc/xwc + HP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwc + HP8cGxr/GyMn/xkxQP8aKDH/HB0e/xwaGf8cGxr/HBsa/xsjKP8NdrP/Bpvw/giT433SAAAAD33CAAAA + AAAAAAAAAAAAAAyH0AAOgccLCJXmrAab7/8RYI7/HCAk/xktOf8VRmP/EGWW/wuBxP8IkN3/DH2+/xc/ + V/8cHR3/HBsa/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwc + HP8cHBz/HBsb/xwbG/8YNUb/DXOu/wiQ3f8Khcv/D2qf/xRMbP8ZMUD/HCAj/xRNb/8HmOr/B5fpzAuJ + 1BwKjNkAAAAAAAAAAAAAAAAAAAAAABddjwAIlOUACo3bPgeY7OoIkd//DXi2/wmL1f8HmOv/Bpvw/waa + 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 + wv8Hc8xO37nEVU8AAAAASUVORK5CYII= + + + \ No newline at end of file diff --git a/Fo76ini/Forms/FormTextPrompt/TextPrompt.Designer.cs b/Fo76ini/Forms/FormTextPrompt/TextPrompt.Designer.cs new file mode 100644 index 0000000..509e227 --- /dev/null +++ b/Fo76ini/Forms/FormTextPrompt/TextPrompt.Designer.cs @@ -0,0 +1,103 @@ +namespace Fo76ini.Forms.FormTextPrompt +{ + partial class TextPrompt + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.textBox = new System.Windows.Forms.TextBox(); + this.label = new System.Windows.Forms.Label(); + this.buttonCancel = new System.Windows.Forms.Button(); + this.buttonOK = new System.Windows.Forms.Button(); + this.SuspendLayout(); + // + // textBox + // + this.textBox.Location = new System.Drawing.Point(12, 58); + this.textBox.Name = "textBox"; + this.textBox.Size = new System.Drawing.Size(321, 20); + this.textBox.TabIndex = 0; + // + // label + // + this.label.Font = new System.Drawing.Font("Microsoft Sans Serif", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label.Location = new System.Drawing.Point(12, 13); + this.label.Name = "label"; + this.label.Size = new System.Drawing.Size(321, 42); + this.label.TabIndex = 1; + this.label.Text = "Text"; + this.label.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + // + // buttonCancel + // + this.buttonCancel.Location = new System.Drawing.Point(258, 97); + this.buttonCancel.Name = "buttonCancel"; + this.buttonCancel.Size = new System.Drawing.Size(75, 23); + this.buttonCancel.TabIndex = 2; + this.buttonCancel.Text = "Cancel"; + this.buttonCancel.UseVisualStyleBackColor = true; + this.buttonCancel.Click += new System.EventHandler(this.buttonCancel_Click); + // + // buttonOK + // + this.buttonOK.Location = new System.Drawing.Point(177, 97); + this.buttonOK.Name = "buttonOK"; + this.buttonOK.Size = new System.Drawing.Size(75, 23); + this.buttonOK.TabIndex = 3; + this.buttonOK.Text = "OK"; + this.buttonOK.UseVisualStyleBackColor = true; + this.buttonOK.Click += new System.EventHandler(this.buttonOK_Click); + // + // TextPrompt + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(345, 129); + this.ControlBox = false; + this.Controls.Add(this.buttonOK); + this.Controls.Add(this.buttonCancel); + this.Controls.Add(this.label); + this.Controls.Add(this.textBox); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "TextPrompt"; + this.ShowIcon = false; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.Text = "Text prompt"; + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.TextBox textBox; + private System.Windows.Forms.Label label; + private System.Windows.Forms.Button buttonCancel; + private System.Windows.Forms.Button buttonOK; + } +} \ No newline at end of file diff --git a/Fo76ini/Forms/FormTextPrompt/TextPrompt.cs b/Fo76ini/Forms/FormTextPrompt/TextPrompt.cs new file mode 100644 index 0000000..eb80ee9 --- /dev/null +++ b/Fo76ini/Forms/FormTextPrompt/TextPrompt.cs @@ -0,0 +1,68 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace Fo76ini.Forms.FormTextPrompt +{ + public partial class TextPrompt : Form + { + Action CallbackOK = null; + Action CallbackCancel = null; + + public TextPrompt() + { + InitializeComponent(); + this.textBox.KeyDown += textBox_KeyDown; + } + + public static void Prompt(String text, Action callbackOk, Action callbackCancel = null) + { + Prompt(text, "", callbackOk, callbackCancel); + } + + public static void Prompt(String text, String value, Action callbackOk, Action callbackCancel = null) + { + TextPrompt prompt = new TextPrompt(); + prompt.CallbackOK = callbackOk; + prompt.CallbackCancel = callbackCancel; + prompt.Text = text; + prompt.label.Text = text; + prompt.textBox.Text = value; + prompt.ShowDialog(); + prompt.Focus(); + } + + private void buttonOK_Click(object sender, EventArgs e) + { + CallbackOK?.Invoke(this.textBox.Text); + this.Close(); + this.Dispose(); + } + + private void buttonCancel_Click(object sender, EventArgs e) + { + CallbackCancel?.Invoke(); + this.Close(); + this.Dispose(); + } + + private void textBox_KeyDown(object sender, KeyEventArgs e) + { + switch (e.KeyCode) + { + case Keys.Enter: + buttonOK_Click(sender, e); + break; + case Keys.Escape: + buttonCancel_Click(sender, e); + break; + } + } + } +} diff --git a/Fo76ini/Forms/FormTextPrompt/TextPrompt.resx b/Fo76ini/Forms/FormTextPrompt/TextPrompt.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/Fo76ini/Forms/FormTextPrompt/TextPrompt.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/Fo76ini/Forms/FormWelcome/FormWelcome.Designer.cs b/Fo76ini/Forms/FormWelcome/FormWelcome.Designer.cs new file mode 100644 index 0000000..5db5a25 --- /dev/null +++ b/Fo76ini/Forms/FormWelcome/FormWelcome.Designer.cs @@ -0,0 +1,371 @@ + +namespace Fo76ini.Forms.FormWelcome +{ + partial class FormWelcome + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(FormWelcome)); + this.label1 = new System.Windows.Forms.Label(); + this.labelTitle = new System.Windows.Forms.Label(); + this.panel1 = new System.Windows.Forms.Panel(); + this.groupBoxGameLocation = new System.Windows.Forms.GroupBox(); + this.label3 = new System.Windows.Forms.Label(); + this.label2 = new System.Windows.Forms.Label(); + this.buttonAutoDetect = new System.Windows.Forms.Button(); + this.textBoxGamePath = new System.Windows.Forms.TextBox(); + this.buttonPickGamePath = new System.Windows.Forms.Button(); + this.groupBoxGameEdition = new System.Windows.Forms.GroupBox(); + this.radioButtonEditionUnknown = new System.Windows.Forms.RadioButton(); + this.pictureBoxUnknown = new System.Windows.Forms.PictureBox(); + this.pictureBoxMSStore = new System.Windows.Forms.PictureBox(); + this.pictureBoxSteam = new System.Windows.Forms.PictureBox(); + this.pictureBoxBethesdaNetPTS = new System.Windows.Forms.PictureBox(); + this.pictureBoxBethesdaNet = new System.Windows.Forms.PictureBox(); + this.radioButtonEditionMSStore = new System.Windows.Forms.RadioButton(); + this.radioButtonEditionBethesdaNetPTS = new System.Windows.Forms.RadioButton(); + this.radioButtonEditionSteam = new System.Windows.Forms.RadioButton(); + this.radioButtonEditionBethesdaNet = new System.Windows.Forms.RadioButton(); + this.buttonOK = new System.Windows.Forms.Button(); + this.openFileDialogGamePath = new System.Windows.Forms.OpenFileDialog(); + this.label4 = new System.Windows.Forms.Label(); + this.panel1.SuspendLayout(); + this.groupBoxGameLocation.SuspendLayout(); + this.groupBoxGameEdition.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBoxUnknown)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBoxMSStore)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBoxSteam)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBoxBethesdaNetPTS)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBoxBethesdaNet)).BeginInit(); + this.SuspendLayout(); + // + // label1 + // + this.label1.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label1.Location = new System.Drawing.Point(12, 43); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(422, 28); + this.label1.TabIndex = 8; + this.label1.Text = "Hi, it seems like you started the tool for the first time!\r\n"; + // + // labelTitle + // + this.labelTitle.Font = new System.Drawing.Font("Microsoft Sans Serif", 14.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.labelTitle.Location = new System.Drawing.Point(12, 9); + this.labelTitle.Name = "labelTitle"; + this.labelTitle.Size = new System.Drawing.Size(291, 24); + this.labelTitle.TabIndex = 7; + this.labelTitle.Text = "Welcome"; + // + // panel1 + // + this.panel1.BackColor = System.Drawing.Color.White; + this.panel1.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + this.panel1.Controls.Add(this.groupBoxGameLocation); + this.panel1.Controls.Add(this.groupBoxGameEdition); + this.panel1.Location = new System.Drawing.Point(12, 114); + this.panel1.Name = "panel1"; + this.panel1.Size = new System.Drawing.Size(422, 424); + this.panel1.TabIndex = 40; + // + // groupBoxGameLocation + // + this.groupBoxGameLocation.Controls.Add(this.label3); + this.groupBoxGameLocation.Controls.Add(this.label2); + this.groupBoxGameLocation.Controls.Add(this.buttonAutoDetect); + this.groupBoxGameLocation.Controls.Add(this.textBoxGamePath); + this.groupBoxGameLocation.Controls.Add(this.buttonPickGamePath); + this.groupBoxGameLocation.Location = new System.Drawing.Point(11, 190); + this.groupBoxGameLocation.Name = "groupBoxGameLocation"; + this.groupBoxGameLocation.Size = new System.Drawing.Size(400, 224); + this.groupBoxGameLocation.TabIndex = 41; + this.groupBoxGameLocation.TabStop = false; + this.groupBoxGameLocation.Text = "Game location"; + // + // label3 + // + this.label3.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.label3.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label3.Location = new System.Drawing.Point(8, 84); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(386, 34); + this.label3.TabIndex = 34; + this.label3.Text = "You can skip the game location, if you don\'t want to install mods."; + // + // label2 + // + this.label2.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.label2.Location = new System.Drawing.Point(8, 127); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(386, 88); + this.label2.TabIndex = 33; + this.label2.Text = resources.GetString("label2.Text"); + // + // buttonAutoDetect + // + this.buttonAutoDetect.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.buttonAutoDetect.Location = new System.Drawing.Point(6, 48); + this.buttonAutoDetect.Name = "buttonAutoDetect"; + this.buttonAutoDetect.Size = new System.Drawing.Size(388, 23); + this.buttonAutoDetect.TabIndex = 32; + this.buttonAutoDetect.Text = "Attempt auto-detect"; + this.buttonAutoDetect.UseVisualStyleBackColor = true; + this.buttonAutoDetect.Click += new System.EventHandler(this.buttonAutoDetect_Click); + // + // textBoxGamePath + // + this.textBoxGamePath.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.textBoxGamePath.Location = new System.Drawing.Point(6, 21); + this.textBoxGamePath.Name = "textBoxGamePath"; + this.textBoxGamePath.Size = new System.Drawing.Size(354, 20); + this.textBoxGamePath.TabIndex = 30; + this.textBoxGamePath.TextChanged += new System.EventHandler(this.textBoxGamePath_TextChanged); + // + // buttonPickGamePath + // + this.buttonPickGamePath.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.buttonPickGamePath.Location = new System.Drawing.Point(366, 19); + this.buttonPickGamePath.Name = "buttonPickGamePath"; + this.buttonPickGamePath.Size = new System.Drawing.Size(28, 23); + this.buttonPickGamePath.TabIndex = 31; + this.buttonPickGamePath.Text = "..."; + this.buttonPickGamePath.UseVisualStyleBackColor = true; + this.buttonPickGamePath.Click += new System.EventHandler(this.buttonPickGamePath_Click); + // + // groupBoxGameEdition + // + this.groupBoxGameEdition.Controls.Add(this.radioButtonEditionUnknown); + this.groupBoxGameEdition.Controls.Add(this.pictureBoxUnknown); + this.groupBoxGameEdition.Controls.Add(this.pictureBoxMSStore); + this.groupBoxGameEdition.Controls.Add(this.pictureBoxSteam); + this.groupBoxGameEdition.Controls.Add(this.pictureBoxBethesdaNetPTS); + this.groupBoxGameEdition.Controls.Add(this.pictureBoxBethesdaNet); + this.groupBoxGameEdition.Controls.Add(this.radioButtonEditionMSStore); + this.groupBoxGameEdition.Controls.Add(this.radioButtonEditionBethesdaNetPTS); + this.groupBoxGameEdition.Controls.Add(this.radioButtonEditionSteam); + this.groupBoxGameEdition.Controls.Add(this.radioButtonEditionBethesdaNet); + this.groupBoxGameEdition.Location = new System.Drawing.Point(11, 9); + this.groupBoxGameEdition.Name = "groupBoxGameEdition"; + this.groupBoxGameEdition.Size = new System.Drawing.Size(400, 175); + this.groupBoxGameEdition.TabIndex = 40; + this.groupBoxGameEdition.TabStop = false; + this.groupBoxGameEdition.Text = "Game edition"; + // + // radioButtonEditionUnknown + // + this.radioButtonEditionUnknown.AutoSize = true; + this.radioButtonEditionUnknown.Location = new System.Drawing.Point(43, 142); + this.radioButtonEditionUnknown.Name = "radioButtonEditionUnknown"; + this.radioButtonEditionUnknown.Size = new System.Drawing.Size(51, 17); + this.radioButtonEditionUnknown.TabIndex = 31; + this.radioButtonEditionUnknown.Text = "Other"; + this.radioButtonEditionUnknown.UseVisualStyleBackColor = true; + this.radioButtonEditionUnknown.CheckedChanged += new System.EventHandler(this.radioButtonEditionUnknown_CheckedChanged); + // + // pictureBoxUnknown + // + this.pictureBoxUnknown.BackColor = System.Drawing.Color.Transparent; + this.pictureBoxUnknown.Image = global::Fo76ini.Properties.Resources.help_24; + this.pictureBoxUnknown.Location = new System.Drawing.Point(11, 139); + this.pictureBoxUnknown.Name = "pictureBoxUnknown"; + this.pictureBoxUnknown.Size = new System.Drawing.Size(24, 24); + this.pictureBoxUnknown.TabIndex = 30; + this.pictureBoxUnknown.TabStop = false; + // + // pictureBoxMSStore + // + this.pictureBoxMSStore.BackColor = System.Drawing.Color.Transparent; + this.pictureBoxMSStore.Image = global::Fo76ini.Properties.Resources.msstore_24; + this.pictureBoxMSStore.Location = new System.Drawing.Point(11, 109); + this.pictureBoxMSStore.Name = "pictureBoxMSStore"; + this.pictureBoxMSStore.Size = new System.Drawing.Size(24, 24); + this.pictureBoxMSStore.TabIndex = 29; + this.pictureBoxMSStore.TabStop = false; + // + // pictureBoxSteam + // + this.pictureBoxSteam.BackColor = System.Drawing.Color.Transparent; + this.pictureBoxSteam.Image = global::Fo76ini.Properties.Resources.steam_24px; + this.pictureBoxSteam.Location = new System.Drawing.Point(11, 79); + this.pictureBoxSteam.Name = "pictureBoxSteam"; + this.pictureBoxSteam.Size = new System.Drawing.Size(24, 24); + this.pictureBoxSteam.TabIndex = 28; + this.pictureBoxSteam.TabStop = false; + // + // pictureBoxBethesdaNetPTS + // + this.pictureBoxBethesdaNetPTS.BackColor = System.Drawing.Color.Transparent; + this.pictureBoxBethesdaNetPTS.Image = global::Fo76ini.Properties.Resources.bethesda_24; + this.pictureBoxBethesdaNetPTS.Location = new System.Drawing.Point(11, 49); + this.pictureBoxBethesdaNetPTS.Name = "pictureBoxBethesdaNetPTS"; + this.pictureBoxBethesdaNetPTS.Size = new System.Drawing.Size(24, 24); + this.pictureBoxBethesdaNetPTS.TabIndex = 27; + this.pictureBoxBethesdaNetPTS.TabStop = false; + // + // pictureBoxBethesdaNet + // + this.pictureBoxBethesdaNet.BackColor = System.Drawing.Color.Transparent; + this.pictureBoxBethesdaNet.Image = global::Fo76ini.Properties.Resources.bethesda_24; + this.pictureBoxBethesdaNet.Location = new System.Drawing.Point(11, 19); + this.pictureBoxBethesdaNet.Name = "pictureBoxBethesdaNet"; + this.pictureBoxBethesdaNet.Size = new System.Drawing.Size(24, 24); + this.pictureBoxBethesdaNet.TabIndex = 26; + this.pictureBoxBethesdaNet.TabStop = false; + // + // radioButtonEditionMSStore + // + this.radioButtonEditionMSStore.AutoSize = true; + this.radioButtonEditionMSStore.Location = new System.Drawing.Point(43, 112); + this.radioButtonEditionMSStore.Name = "radioButtonEditionMSStore"; + this.radioButtonEditionMSStore.Size = new System.Drawing.Size(188, 17); + this.radioButtonEditionMSStore.TabIndex = 3; + this.radioButtonEditionMSStore.Text = "Microsoft Store / Xbox Game Pass"; + this.radioButtonEditionMSStore.UseVisualStyleBackColor = true; + this.radioButtonEditionMSStore.CheckedChanged += new System.EventHandler(this.radioButtonEditionMSStore_CheckedChanged); + // + // radioButtonEditionBethesdaNetPTS + // + this.radioButtonEditionBethesdaNetPTS.AutoSize = true; + this.radioButtonEditionBethesdaNetPTS.Location = new System.Drawing.Point(43, 52); + this.radioButtonEditionBethesdaNetPTS.Name = "radioButtonEditionBethesdaNetPTS"; + this.radioButtonEditionBethesdaNetPTS.Size = new System.Drawing.Size(118, 17); + this.radioButtonEditionBethesdaNetPTS.TabIndex = 2; + this.radioButtonEditionBethesdaNetPTS.Text = "Bethesda.net (PTS)"; + this.radioButtonEditionBethesdaNetPTS.UseVisualStyleBackColor = true; + this.radioButtonEditionBethesdaNetPTS.CheckedChanged += new System.EventHandler(this.radioButtonEditionBethesdaNetPTS_CheckedChanged); + // + // radioButtonEditionSteam + // + this.radioButtonEditionSteam.AutoSize = true; + this.radioButtonEditionSteam.Location = new System.Drawing.Point(43, 82); + this.radioButtonEditionSteam.Name = "radioButtonEditionSteam"; + this.radioButtonEditionSteam.Size = new System.Drawing.Size(55, 17); + this.radioButtonEditionSteam.TabIndex = 1; + this.radioButtonEditionSteam.Text = "Steam"; + this.radioButtonEditionSteam.UseVisualStyleBackColor = true; + this.radioButtonEditionSteam.CheckedChanged += new System.EventHandler(this.radioButtonEditionSteam_CheckedChanged); + // + // radioButtonEditionBethesdaNet + // + this.radioButtonEditionBethesdaNet.AutoSize = true; + this.radioButtonEditionBethesdaNet.Location = new System.Drawing.Point(43, 22); + this.radioButtonEditionBethesdaNet.Name = "radioButtonEditionBethesdaNet"; + this.radioButtonEditionBethesdaNet.Size = new System.Drawing.Size(88, 17); + this.radioButtonEditionBethesdaNet.TabIndex = 0; + this.radioButtonEditionBethesdaNet.Text = "Bethesda.net"; + this.radioButtonEditionBethesdaNet.UseVisualStyleBackColor = true; + this.radioButtonEditionBethesdaNet.CheckedChanged += new System.EventHandler(this.radioButtonEditionBethesdaNet_CheckedChanged); + // + // buttonOK + // + this.buttonOK.Location = new System.Drawing.Point(300, 547); + this.buttonOK.Name = "buttonOK"; + this.buttonOK.Size = new System.Drawing.Size(134, 27); + this.buttonOK.TabIndex = 41; + this.buttonOK.Text = "OK"; + this.buttonOK.UseVisualStyleBackColor = true; + this.buttonOK.Click += new System.EventHandler(this.buttonOK_Click); + // + // openFileDialogGamePath + // + this.openFileDialogGamePath.FileName = "Fallout76.exe"; + this.openFileDialogGamePath.Filter = "Executable|*.exe"; + this.openFileDialogGamePath.FilterIndex = 2; + // + // label4 + // + this.label4.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(112)))), ((int)(((byte)(112)))), ((int)(((byte)(112))))); + this.label4.Location = new System.Drawing.Point(12, 63); + this.label4.Name = "label4"; + this.label4.Size = new System.Drawing.Size(422, 46); + this.label4.TabIndex = 42; + this.label4.Text = "» Now, I know you\'re a busy fellow, so I won\'t take up much of your time.\r\n I j" + + "ust need to verify some information, that\'s all! «\r\n – Vault-Tec rep, Oct." + + " 2077"; + // + // FormWelcome + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(446, 581); + this.Controls.Add(this.label4); + this.Controls.Add(this.buttonOK); + this.Controls.Add(this.panel1); + this.Controls.Add(this.label1); + this.Controls.Add(this.labelTitle); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; + this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "FormWelcome"; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; + this.Text = "Welcome"; + this.panel1.ResumeLayout(false); + this.groupBoxGameLocation.ResumeLayout(false); + this.groupBoxGameLocation.PerformLayout(); + this.groupBoxGameEdition.ResumeLayout(false); + this.groupBoxGameEdition.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBoxUnknown)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBoxMSStore)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBoxSteam)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBoxBethesdaNetPTS)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBoxBethesdaNet)).EndInit(); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.Label label1; + private System.Windows.Forms.Label labelTitle; + private System.Windows.Forms.Panel panel1; + private System.Windows.Forms.GroupBox groupBoxGameLocation; + private System.Windows.Forms.Button buttonAutoDetect; + private System.Windows.Forms.TextBox textBoxGamePath; + private System.Windows.Forms.Button buttonPickGamePath; + private System.Windows.Forms.GroupBox groupBoxGameEdition; + private System.Windows.Forms.RadioButton radioButtonEditionUnknown; + private System.Windows.Forms.PictureBox pictureBoxUnknown; + private System.Windows.Forms.PictureBox pictureBoxMSStore; + private System.Windows.Forms.PictureBox pictureBoxSteam; + private System.Windows.Forms.PictureBox pictureBoxBethesdaNetPTS; + private System.Windows.Forms.PictureBox pictureBoxBethesdaNet; + private System.Windows.Forms.RadioButton radioButtonEditionMSStore; + private System.Windows.Forms.RadioButton radioButtonEditionBethesdaNetPTS; + private System.Windows.Forms.RadioButton radioButtonEditionSteam; + private System.Windows.Forms.RadioButton radioButtonEditionBethesdaNet; + private System.Windows.Forms.Button buttonOK; + private System.Windows.Forms.Label label2; + private System.Windows.Forms.Label label3; + private System.Windows.Forms.OpenFileDialog openFileDialogGamePath; + private System.Windows.Forms.Label label4; + } +} \ No newline at end of file diff --git a/Fo76ini/Forms/FormWelcome/FormWelcome.cs b/Fo76ini/Forms/FormWelcome/FormWelcome.cs new file mode 100644 index 0000000..5aa96f7 --- /dev/null +++ b/Fo76ini/Forms/FormWelcome/FormWelcome.cs @@ -0,0 +1,149 @@ +using Fo76ini.Forms.FormTextPrompt; +using Fo76ini.Interface; +using Fo76ini.Profiles; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace Fo76ini.Forms.FormWelcome +{ + public partial class FormWelcome : Form + { + private bool UpdatingUI = false; + + public FormWelcome() + { + InitializeComponent(); + this.FormClosing += FormWelcome_FormClosing; + } + + public static DialogResult OpenDialog() + { + FormWelcome form = new FormWelcome(); + form.UpdatingUI = true; + + switch (ProfileManager.SelectedGame.Edition) + { + case GameEdition.BethesdaNet: + form.radioButtonEditionBethesdaNet.Checked = true; + break; + case GameEdition.BethesdaNetPTS: + form.radioButtonEditionBethesdaNetPTS.Checked = true; + break; + case GameEdition.Steam: + form.radioButtonEditionSteam.Checked = true; + break; + case GameEdition.MSStore: + form.radioButtonEditionMSStore.Checked = true; + break; + default: + form.radioButtonEditionUnknown.Checked = true; + break; + } + + form.textBoxGamePath.Text = ProfileManager.SelectedGame.GamePath; + + form.UpdatingUI = false; + return form.ShowDialog(); + } + + private void FormWelcome_FormClosing(object sender, FormClosingEventArgs e) + { + if (e.CloseReason == CloseReason.UserClosing) + { + ProfileManager.Save(); + ProfileManager.Feedback(); + } + } + + private void buttonOK_Click(object sender, EventArgs e) + { + ProfileManager.Save(); + ProfileManager.Feedback(); + this.DialogResult = DialogResult.OK; + } + + private void radioButtonEditionBethesdaNet_CheckedChanged(object sender, EventArgs e) + { + if (UpdatingUI) + return; + ProfileManager.SelectedGame.Edition = GameEdition.BethesdaNet; + ProfileManager.SelectedGame.SetDefaultSettings(GameEdition.BethesdaNet); + ProfileManager.SelectedGame.Title = "Bethesda.net"; + } + + private void radioButtonEditionBethesdaNetPTS_CheckedChanged(object sender, EventArgs e) + { + if (UpdatingUI) + return; + ProfileManager.SelectedGame.Edition = GameEdition.BethesdaNetPTS; + ProfileManager.SelectedGame.SetDefaultSettings(GameEdition.BethesdaNetPTS); + ProfileManager.SelectedGame.Title = "Bethesda.net (PTS)"; + } + + private void radioButtonEditionSteam_CheckedChanged(object sender, EventArgs e) + { + if (UpdatingUI) + return; + ProfileManager.SelectedGame.Edition = GameEdition.Steam; + ProfileManager.SelectedGame.SetDefaultSettings(GameEdition.Steam); + ProfileManager.SelectedGame.Title = "Steam"; + } + + private void radioButtonEditionMSStore_CheckedChanged(object sender, EventArgs e) + { + if (UpdatingUI) + return; + ProfileManager.SelectedGame.Edition = GameEdition.MSStore; + ProfileManager.SelectedGame.SetDefaultSettings(GameEdition.MSStore); + ProfileManager.SelectedGame.Title = "Microsoft Store"; + } + + private void radioButtonEditionUnknown_CheckedChanged(object sender, EventArgs e) + { + if (UpdatingUI) + return; + ProfileManager.SelectedGame.Edition = GameEdition.Unknown; + ProfileManager.SelectedGame.Title = "Unknown"; + } + + private void textBoxGamePath_TextChanged(object sender, EventArgs e) + { + if (UpdatingUI) + return; + ProfileManager.SelectedGame.GamePath = this.textBoxGamePath.Text; + this.textBoxGamePath.ForeColor = ProfileManager.SelectedGame.ValidateGamePath() ? Color.Black : Color.Maroon; + } + + private void buttonPickGamePath_Click(object sender, EventArgs e) + { + if (UpdatingUI) + return; + this.openFileDialogGamePath.FileName = ProfileManager.SelectedGame.ExecutableName; + if (this.openFileDialogGamePath.ShowDialog() == DialogResult.OK) + { + string path = Path.GetDirectoryName(this.openFileDialogGamePath.FileName); // We want the path where Fallout76.exe resides. + if (GameInstance.ValidateGamePath(path)) + this.textBoxGamePath.Text = path; + else + MsgBox.ShowID("modsGamePathInvalid"); + } + } + + private void buttonAutoDetect_Click(object sender, EventArgs e) + { + string foundPath = FormSettings.FormSettings.AutoDetectGamePath(); + if (foundPath != null) + TextPrompt.Prompt("Found a path. Proceed?", foundPath, (newPath) => this.textBoxGamePath.Text = newPath); + else + MsgBox.ShowID("gamePathAutoDetectFailed", MessageBoxIcon.Information); + } + } +} diff --git a/Fo76ini/Forms/FormWelcome/FormWelcome.resx b/Fo76ini/Forms/FormWelcome/FormWelcome.resx new file mode 100644 index 0000000..6189415 --- /dev/null +++ b/Fo76ini/Forms/FormWelcome/FormWelcome.resx @@ -0,0 +1,835 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + If you have trouble finding the game location: + +Steam: C:\Program Files (x86)\Steam\steamapps\common\Fallout76\ +Bethesda.net: C:\Program Files (x86)\Bethesda.net Launcher\games\Fallout76\ +Microsoft Store: C:\Program Files\ModifiableWindowsApps\Fallout76\ + + + 17, 17 + + + + + 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 + w/4VRWD/GyEk/xwbGv8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cGxv/HB8h/xY+Vf8Mern/B5jq6weU + 5e0Khs7+Dmyi/w1yrP8Hl+rXCZDeJQmR4QAAAAAADoPLAAC//wAHl+pzCYzW/Rg0RP8cGxv/Gicv/xc9 + VP8US2v/Gis1/xwaGf8cHBv/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBoZ/xon + Lv8VSWj/FkBZ/xopMv8cHB3/Gis1/wqEyv8HmOyMFG+rAgyI0wAIkuIACZDfKAeY7NsRW4b/HBwc/xwc + HP8cGxv/HBoZ/xwaGf8cGxv/HBwc/xwcHP8cHBz/HBwc/xwbGv8cGhn/HBoZ/xwaGf8cHBv/HBwc/xwc + HP8cHBz/HBsb/xwaGf8cGhn/HBsb/xwcHP8cGxr/FE9x/weX6ekIk+M6B5boABF4ugQHmOyQC4LG/xoq + M/8cGxr/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwbGv8cHh//GS46/xY+Vf8WQVv/GDZI/xsk + Kf8cGxr/HBwb/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwbG/8bJCn/DHi2/weZ7akMiNILCZHhRAeX + 6usUT3L/HBoY/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cGxr/GDNC/w9roP8JitT/CYzX/wmL + 1f8Jjdj/C36//xRLa/8bICL/HBsb/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwaGP8WQl3/B5Xl9AiT + 5F4JkuFBB5jr4A9roP8bJSv/HBsa/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBsa/xc9VP8Kh8//C37A/xRM + bP8YMkL/GS88/xc9U/8PZ5r/CI/c/xBikP8bIST/HBwb/xwcHP8cHBz/HBwc/xwcHP8cGxv/GyEk/xBg + j/8Hl+nrCJPkWQD//wAJkuFMB5jq4Q5to/8aJi3/HBsb/xwcHP8cHBz/HBwc/xwbGv8ZLjr/CoXL/w5v + p/8aJy//HBoY/xwbGv8cGxr/HBoZ/xwdHf8VSWj/CI/c/xNTeP8cGxv/HBwc/xwcHP8cHBz/HBsb/xsi + Jv8QY5L/B5bo7AiT42ASeboCEXq8AAD//wAIlORFBpru2w9qnv8bICP/HBwb/xwcHP8cHBz/HBsb/xFf + jP8Khcv/Gis1/xwaGf8cHBz/HBwc/xwcHP8cHBz/HBwb/xwbG/8RXYj/CobO/xorNf8cGxr/HBwc/xwc + HP8cHR7/EV6L/weY6+YIledYGF+SAg6AxQAAAAAADIvYAAOj/AAHl+pyCofP/xooMf8cGxv/HBwc/xwb + G/8bJCr/C4HE/xFch/8cGhn/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBsa/xkwPv8Ji9b/FUdj/xwa + Gf8cHBz/HBwb/xsiJv8Lfr//B5ntjQD//wALjNkAAAAAAAAAAAAAAAAABpvwAAeZ7GwLgsb/GyUr/xwb + G/8cHBz/HBsa/xktOf8JitT/FURf/xwaGP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBv/GyIn/wt/ + wv8SWYL/HBoZ/xwcHP8cHBz/HB8i/w13tP8Hmu6IAaj/ABF8vwAAAAAAAAAAAAAAAAAGm/AAB5nsbAuC + xv8bJSv/HBsb/xwcHP8cGxr/GS05/wmK1P8VRF//HBoY/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwc + G/8bIif/C3/C/xJZgv8cGhn/HBwc/xwcHP8cHyL/DXe0/wea7ogBqP8AEXy/AAAAAAAAAAAADIvYAAOj + /AAHl+pyCofP/xooMf8cGxv/HBwc/xwbG/8bJCr/C4HE/xFch/8cGhn/HBwc/xwcHP8cHBz/HBwc/xwc + HP8cHBz/HBsa/xkwPv8Ji9b/FUdj/xwaGf8cHBz/HBwb/xsiJv8Lfr//B5ntjQD//wALjNkAAAAAABF6 + vAAA//8ACJTkRQaa7tsPap7/GyAj/xwcG/8cHBz/HBwc/xwbG/8RX4z/CoXL/xorNf8cGhn/HBwc/xwc + HP8cHBz/HBwc/xwcG/8cGxv/EV2I/wqGzv8aKzX/HBsa/xwcHP8cHBz/HB0e/xFei/8HmOvmCJXnWBhf + kgIOgMUAAP//AAmS4UwHmOrhDm2j/xomLf8cGxv/HBwc/xwcHP8cHBz/HBsa/xkuOv8Khcv/Dm+n/xon + L/8cGhj/HBsa/xwbGv8cGhn/HB0d/xVJaP8Ij9z/E1N4/xwbG/8cHBz/HBwc/xwcHP8cGxv/GyIm/xBj + kv8HlujsCJPjYBJ5ugIJkuFBB5jr4A9roP8bJSv/HBsa/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBsa/xc9 + VP8Kh8//C37A/xRMbP8YMkL/GS88/xc9U/8PZ5r/CI/c/xBhkP8bIST/HBwb/xwcHP8cHBz/HBwc/xwc + HP8cGxv/GyEk/xBgj/8Hl+nrCJPkWQmR4UQHl+rrFE9y/xwaGP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwc + HP8cHBz/HBsa/xgzQv8Pa6D/CYrU/wmM1/8Ji9X/CY3Y/wt+v/8US2v/GyAi/xwbG/8cHBz/HBwc/xwc + HP8cHBz/HBwc/xwcHP8cGhj/FkJd/weV5fQIk+ReEXi6BAeY7JALgsb/Gioz/xwbGv8cHBz/HBwc/xwc + HP8cHBz/HBwc/xwcHP8cHBz/HBsa/xweH/8ZLjr/Fj5V/xZBW/8YNkj/GyQp/xwbGv8cHBv/HBwc/xwc + HP8cHBz/HBwc/xwcHP8cHBz/HBsb/xskKf8MeLb/B5ntqQyI0gsIkuIACZDfKAeY7NsRW4b/HBwc/xwc + HP8cGxv/HBoZ/xwaGf8cGxv/HBwc/xwcHP8cHBz/HBwc/xwbGv8cGhn/HBoZ/xwaGf8cHBv/HBwc/xwc + HP8cHBz/HBsb/xwaGf8cGhn/HBsb/xwcHP8cGxr/FE9x/weX6ekIk+M6B5boAA6DywAAv/8AB5fqcwmM + 1v0YNET/HBsb/xonL/8XPVT/FEtr/xorNf8cGhn/HBwb/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwc + HP8cHBz/HBwc/xwaGf8aJy7/FElo/xZAWf8aKTL/HBwd/xorNf8KhMr/B5jsjBRvqwIMiNMAAAAAAAmP + 3AAKjdkWB5jrxQx4tv8PaZ3/CoTJ/giT4/AHmOvoC4DD/hVFYP8bIST/HBsa/xwcHP8cHBz/HBwc/xwc + HP8cHBz/HBwc/xwbG/8cHyH/Fj5V/wx6uf8HmOrrB5Tl7QqGzv4ObKL/DXKs/weX6tcJkN4lCZHhAAAA + AAAAAAAAD3y/AAWe9AAIk+NSB5js1geZ7bMHmOt0CJPkOQmQ3zAHmeyfB5Tk8g11sP8YNUf/HBsa/xwc + HP8cHBz/HBwc/xwcHP8cGxr/GS47/w5upv8IkuH2B5ntrgmS4TkJkuIyB5jqbAeZ7awHmezYCJTlaAC9 + /wANgsgAAAAAAAAAAAAAAAAADIjSAAyG0AULitYZDYTMBwDU/wAeSXIACo7cAAuJ1AgIlOVHBpzxzA5s + ov8cHR7/HBwc/xwcHP8cHBz/HBwc/xwbGv8RX4v/Bpvw2giV5lQLjNgMCJLiACJCaAAEofkADoHIBQuK + 1hkMiNEHC4rWAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGWGVAASg + 9wAHmOtxCoTJ/xonLv8cGxv/HBwc/xwcHP8cHBv/GyEk/wx5uP8Hme2NAMr/ABF4ugAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAACJTlAAiU5T4IkuHzFzhL/x0YFv8cGhj/HBoY/x0ZFv8ZLTn/CYzW/AiW6FcHmOoAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAKjtsACo7cGAeY6tUPaZ3/FUpp/xRLa/8US2v/FUpp/xFhkP8HlufnCZHgKgmR + 4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA2CyQARd7gEB5XnoQaZ7fgGmOz1Bpns9QaZ7PUGmOz1Bpnt+AeW + 6LgMhtAMDIjSAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/4Af//+AH///g + B///4Af/44ABx+AAAAfAAAADwAAAAYAAAAEAAAAAAAAAAAAAAACAAAAAwAAAAeAAAAfgAAAH4AAAB+AA + AAfAAAABgAAAAAAAAAAAAAAAAAAAAIAAAAHAAAABwAAAA+AAAAfjgAHH/+AH///gB///4Af//+AH/ygA + AAAwAAAAYAAAAAEAIAAAAAAAACQAANgOAADYDgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGViIAAKq/wAJkN5pB5jr7Qaa + 7u8Gmu7vBpru7waa7u8Gmu7vBpru7waa7u8Gmu7vBpjs8QiS4Y4bUX4CEXa2AAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEHq9ABNw + rgYIlOavBpnt/wmO2v8JitP/CYrU/wmK1P8JitT/CYrU/wmK0/8JjNf/Bpjr/weW6NENhM0WDYTNAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAC4rVAAuJ1B0HmOvaCI7a/xc7Uf8aKjT/Gis1/xorNf8aKzX/Gis1/xorNf8ZMkH/C4LG/waa + 7vAKjts6CZHgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAACZLhAAqO20UGmu/1DHq6/xshJf8cGxr/HBsa/xwbGv8cGxr/HBsa/xwb + Gv8cGxv/D2ea/wab8P8JkeBsBZ70ACM2VAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWYJUAAar/AAiS4ngGm/D/EGGR/xwbG/8cHBz/HBwc/xwc + HP8cHBz/HBwc/xwcHP8cGhn/FE1u/waZ7f8IleahHFB8AhB3uAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOf8UAEnOyBQiV5q4HmOv/FUdk/xwa + Gf8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cGhn/GDVH/wiR4P8Hl+rQDIfQFQyH0QAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAF2WbAAqN2gANhc4ICo3bTQeY + 7OMIjtv/GTA//xwbGv8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cGxv/GyUr/wuBxP8Gmu/zCZDeaAyH + 0Q0HmOwAFmefAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAACY/dAAuK1RwJkN94CZDfWguJ1CYPe74IAP//ACQ6WAANg8sAEHq8AwqP + 3TwHleepBprt8Qac8f8Ob6f/GyAj/xwcG/8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xFc + iP8Gmu7/Bprv9weW6LsJkN9PDoPKCAuL1wAwERkABJ/2ABF1tQUMh9EfCZDfTwmQ330KjNkuB5ntABxU + gQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPfsIAFmWbAwiT448Gmu7/Bpvw+weY6+MHluezCJLidwqN + 2zwLiNMiCJPjgQeZ7OkGmu//CojQ/xFdif8aKzX/HBsb/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwc + HP8cHBz/HBsb/xskK/8TU3j/C4HF/waZ7f8Gmu7zCJTlmguK1SkKjdkyCZHgawiV5qgHmOrcBpvv+Aaa + 7v8IleazDYHIDgyGzgAAAAAAAAAAAAAAAAAAAAAAAAAAABddjwAIlOUACo3bPgeY7OoIkd//DXi2/wmL + 1f8HmOv/Bpvw/waa7vAHmOvfBpvw+wiR3/8RYI3/GS05/xwbG/8cGxr/HBwc/xwcHP8cHBz/HBwc/xwc + HP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwbG/8cGxr/Gigw/xNUe/8JitT/Bpvw/QeY6+IGme3rBpvw/gaZ + 7f8Ijtv/DHm4/wmL1f8Gmu74CZDfYAKm/wATb6sAAAAAAAAAAAAAAAAAAAAAAAyH0AAOgccLCJXmrAab + 7/8RYI7/HCAk/xktOf8VRmP/EGWW/wuBxP8IkN3/DH2+/xc/V/8cHR3/HBsa/xwcHP8cHBz/HBwc/xwc + HP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBsb/xwbG/8YNUb/DXOu/wiQ + 3f8Khcv/D2qf/xRMbP8ZMUD/HCAj/xRNb/8HmOr/B5fpzAuJ1BwKjNkAAAAAAAAAAAAAAAAAE3GuAAWf + 9gAJkeBXBpru9gqFzP8aLTj/HBsa/xwbGv8cGhn/HBwc/xslLP8ZMUD/GyYt/xwbGv8cHBz/HBwc/xwc + HP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwc + HP8cGxr/GyMn/xkxQP8aKDH/HB0e/xwaGf8cGxr/HBsa/xsjKP8NdrP/Bpvw/giT433UAAAAD33CAAAA + AAAAAAAAC4rVAAyI0hgHlunGBpjr/xRQdP8cGxr/HBwc/xwcHP8cHBz/HBwc/xwbG/8cGxr/HBsb/xwc + HP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwc + HP8cHBz/HBwc/xwcHP8cHBz/HBwb/xwbGv8cGxv/HBwc/xwcHP8cHBz/HBwc/xwaGf8XPlb/CJPi/weY + 6+EKjNkwCZDfAAAAAAAOgccAAO3/AAiS4nYGm/D9DHm5/xslK/8cGxv/HBwc/xwcHP8cHBz/HBwc/xwc + HP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cGxr/HBoZ/xwaGf8cGhn/HBoZ/xwa + Gf8cGxv/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwc + HP8cHiD/D2ic/wab8P8IlOWbEHu+Bg2FzgAJkN8ACo3aKgeY69wHlOT/FkJc/xwaGf8cHBz/HBwc/xwc + HP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBsa/xwdHf8aKzX/Fz9W/xRM + bf8UTnH/FUlo/xg4S/8bJSv/HBsa/xwbG/8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwc + HP8cHBz/HBwc/xwcHP8cGxr/GTJC/wmL1f8Gme3vCZDeRweY6wATcK0GCJTklAab7/8Pap//HB8h/xwc + G/8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcG/8cHBz/GDRE/xBl + lv8KiNH/B5jq/wac8f8GnPL/Bpvw/weU5P8Lf8H/E1R6/xonL/8cGxr/HBwc/xwcHP8cHBz/HBwc/xwc + HP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwb/xJYgP8Gme3/B5bntw2DyxMMiNIjB5bp3AaZ + 7f8TVHv/HBsa/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwb/xwf + If8UT3P/CYzX/wad8v8IkN7/DXe1/xBll/8RYZD/D2qf/wuAw/8Hl+n/Bpvw/wx8vP8XOU3/HBsb/xwc + HP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBoZ/xZCXP8HlOX/B5jr8QqM + 2UUPgMYICJPkhAaZ7fkIj9v/FUlo/xwcHP8cHBv/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwc + HP8cHBz/HB4f/xJYgP8Hl+n/B5Xm/xBmmP8YNUb/GyAk/xwcG/8cGxv/HBwd/xslK/8WQl3/DHq5/wab + 8P8JidL/FzxS/xwbGv8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cGxr/FztQ/wqG + zf8Gmu7+CJXmpAyI0xUMh9EADoHHCgmR4IcGme35CJHf/xRLbP8cHB3/HBwb/xwcHP8cHBz/HBwc/xwc + HP8cHBz/HBwc/xwcHP8cGxr/FUhm/weV5v8Ikd//FExt/xweH/8cGhn/HBwb/xwcHP8cHBz/HBwc/xwb + G/8cGhn/GyYu/xBnmv8Gm+//C4PI/xkuOv8cGxr/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwb + Gv8XPVT/CojR/waa7/4Ik+OmDIbQFgqN2gAAAAAADn/EABB3uAoJkN+BBpru9QiS4f8UTnD/HB0e/xwc + HP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwbGv8aKjT/C4PI/waY6/8TUXb/HBwb/xwcG/8cHBz/HBwc/xwc + HP8cHBz/HBwc/xwcHP8cHBz/HBsa/xskKf8Ocar/Bpzy/xBklf8cHR7/HBwc/xwcHP8cHBz/HBwc/xwc + HP8cHBz/HBwb/xY/V/8JitP/Bpvw/AiS4p8Of8QWDIfRAAAAAAAAAAAAAAAAAAyH0QAPfMAHCJXmdAaa + 7vMIkeD/Fz5V/xwaGf8cHBz/HBwc/xwcHP8cHBz/HBwc/xwaGf8TUXT/Bpvw/w10sP8bIib/HBsb/xwc + HP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwaGf8YNUb/CI7b/wmN2v8ZMUD/HBsa/xwc + HP8cHBz/HBwc/xwcHP8cGxr/GS89/wqHz/8Gm/D7B5bokwyI0hAJkuIAOQAAAAAAAAAAAAAAAAAAAAAA + AAAMitYAEH3BBQiV5pwGm/D/E1Z9/xwaGf8cHBz/HBwc/xwcHP8cHBz/HBwc/xwfIv8NdLD/Bpnt/xVH + ZP8cGhn/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHR7/D2ug/wac + 8f8UUHP/HBoZ/xwcHP8cHBz/HBwc/xwcHP8cGhn/FkJc/weY6v8HlunADInTEguL1wAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAVaaIAAP//AAiS4pcGmu7/FE1u/xwaGf8cHBz/HBwc/xwcHP8cHBz/HBsb/xop + Mv8KiND/CY3Z/xkuOv8cGxr/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwc + HP8cGhn/FE1u/wac8f8PZ5r/HBwc/xwcHP8cHBz/HBwc/xwcHP8cGhn/FzpP/weU5f8Ilea9EXW1ChB5 + uwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPhMsA/wAAAAiW6JsGmOz/FUdk/xwaGf8cHBz/HBwc/xwc + HP8cHBz/HBsa/xkwPv8IkN3/CoPI/xslK/8cGxv/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwc + HP8cHBz/HBwc/xwcHP8cGhn/Fj5V/weY6/8Nc67/HB8g/xwcHP8cHBz/HBwc/xwcHP8cGhn/GDVH/wiS + 4f8HmOvBDYrUCwyL1gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPhMsA/wAAAAiW6JsGmOz/FUdk/xwa + Gf8cHBz/HBwc/xwcHP8cHBz/HBsa/xkwPv8IkN3/CoPI/xslK/8cGxv/HBwc/xwcHP8cHBz/HBwc/xwc + HP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cGhn/Fj5V/weY6/8Nc67/HB8g/xwcHP8cHBz/HBwc/xwc + HP8cGhn/GDVH/wiS4f8HmOvBDYrUCwyL1gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAVaaIAAP//AAiS + 4pcGmu7/FE1u/xwaGf8cHBz/HBwc/xwcHP8cHBz/HBsb/xopMv8KiND/CY3Z/xkuOv8cGxr/HBwc/xwc + HP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cGhn/FE1u/wac8f8PZ5r/HBwc/xwc + HP8cHBz/HBwc/xwcHP8cGhn/FzpP/weU5f8Ilea9EXW1ChB5uwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAMitYAEH3BBQiV5pwGm/D/E1Z9/xwaGf8cHBz/HBwc/xwcHP8cHBz/HBwc/xwfIv8NdLD/Bpnt/xVH + ZP8cGhn/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHR7/D2ug/wac + 8f8UUHP/HBoZ/xwcHP8cHBz/HBwc/xwcHP8cGhn/FkJc/weY6v8HlunADInTEguL1wAAAAAAAAAAAAAA + AAAAAAAAAAAAAAyH0QAPfMAHCJXmdAaa7vMIkeD/Fz5V/xwaGf8cHBz/HBwc/xwcHP8cHBz/HBwc/xwa + Gf8TUXT/Bpvw/w10sP8bIib/HBsb/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwa + Gf8YNUb/CI7b/wmN2v8ZMUD/HBsa/xwcHP8cHBz/HBwc/xwcHP8cGxr/GS89/wqHz/8Gm/D7B5bokwyI + 0hAJkuIAOQAAAAAAAAAAAAAADn/EABB3uAoJkN+BBpru9QiS4P8UTm//HB0e/xwcHP8cHBz/HBwc/xwc + HP8cHBz/HBwc/xwbGv8aKjT/C4PI/waY6/8TUXb/HBwb/xwcG/8cHBz/HBwc/xwcHP8cHBz/HBwc/xwc + HP8cHBz/HBsa/xskKf8Ocar/Bpzy/xBklf8cHR7/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwb/xY/ + V/8JitP/Bpvw/AiS4p8Of8QWDIfRAAAAAAAMh9EADoHHCgmR4IcGme35CJHf/xRLbP8cHB3/HBwb/xwc + HP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cGxr/FUhm/weV5v8Ikd//FExt/xweH/8cGhn/HBwb/xwc + HP8cHBz/HBwc/xwbG/8cGhn/GyYu/xBnmv8Gm+//C4PI/xkuOv8cGxr/HBwc/xwcHP8cHBz/HBwc/xwc + HP8cHBz/HBwc/xwbGv8XPVT/CojR/waa7/4Ik+OmDIbQFgqN2gAPgMYICJPkhAaZ7fkIj9v/FUlo/xwc + HP8cHBv/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HB4f/xJYgP8Hl+n/B5Xm/xBm + mP8YNUb/GyAk/xwcG/8cGxv/HBwd/xslK/8WQl3/DHq5/wab8P8JidL/FzxS/xwbGv8cHBz/HBwc/xwc + HP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cGxr/FztQ/wqGzf8Gmu7+CJXmpAyI0xUMiNIjB5bp3AaZ + 7f8TVHv/HBsa/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwb/xwf + If8UT3P/CYzX/wad8v8IkN7/DXe1/xBll/8RYZD/D2qf/wuAw/8Hl+n/Bpvw/wx8vP8XOU3/HBsb/xwc + HP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBoZ/xZCXP8HlOX/B5jr8QqM + 2UUTcK0GCJTklAab7/8Pap//HB8h/xwcG/8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwc + HP8cHBz/HBwc/xwcG/8cHBz/GDRE/xBllv8KiNH/B5jq/wac8f8GnPL/Bpvw/weU5P8Lf8H/E1R6/xon + L/8cGxr/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwb/xJY + gP8Gme3/B5bntw2DyxMJkN8ACo3aKgeY69wHlOT/FkJc/xwaGf8cHBz/HBwc/xwcHP8cHBz/HBwc/xwc + HP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBsa/xwdHf8aKzX/Fz9W/xRMbf8UTnH/FUlo/xg4 + S/8bJSv/HBsa/xwbG/8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwc + HP8cGxr/GTJC/wmL1f8Gme3vCZDeRweY6wAOgccAAO3/AAiS4nYGm/D9DHm5/xslK/8cGxv/HBwc/xwc + HP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cGxr/HBoZ/xwa + Gf8cGhn/HBoZ/xwaGf8cGxv/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwc + HP8cHBz/HBwc/xwcHP8cHiD/D2ic/wab8P8IlOWbEHu+Bg2FzgAAAAAAC4rVAAyI0hgHlunGBpjr/xRQ + dP8cGxr/HBwc/xwcHP8cHBz/HBwc/xwbG/8cGxr/HBsb/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwc + HP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwb/xwb + Gv8cGxv/HBwc/xwcHP8cHBz/HBwc/xwaGf8XPlb/CJPi/weY6+EKjNkwCZDfAAAAAAAAAAAAE3GuAAWf + 9gAJkeBXBpru9gqFzP8aLTj/HBsa/xwbGv8cGhn/HBwc/xslLP8ZMUD/GyYt/xwbGv8cHBz/HBwc/xwc + HP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwc + HP8cGxr/GyMn/xkxQP8aKDH/HB0e/xwaGf8cGxr/HBsa/xsjKP8NdrP/Bpvw/giT433SAAAAD33CAAAA + AAAAAAAAAAAAAAyH0AAOgccLCJXmrAab7/8RYI7/HCAk/xktOf8VRmP/EGWW/wuBxP8IkN3/DH2+/xc/ + V/8cHR3/HBsa/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwcHP8cHBz/HBwc/xwc + HP8cHBz/HBsb/xwbG/8YNUb/DXOu/wiQ3f8Khcv/D2qf/xRMbP8ZMUD/HCAj/xRNb/8HmOr/B5fpzAuJ + 1BwKjNkAAAAAAAAAAAAAAAAAAAAAABddjwAIlOUACo3bPgeY7OoIkd//DXi2/wmL1f8HmOv/Bpvw/waa + 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 + wv8Hc8xO37nEVU8AAAAASUVORK5CYII= + + + \ No newline at end of file diff --git a/Fo76ini/Forms/FormWhatsNew/FormWhatsNew.Designer.cs b/Fo76ini/Forms/FormWhatsNew/FormWhatsNew.Designer.cs index 3cd0dee..de1b1c8 100644 --- a/Fo76ini/Forms/FormWhatsNew/FormWhatsNew.Designer.cs +++ b/Fo76ini/Forms/FormWhatsNew/FormWhatsNew.Designer.cs @@ -120,7 +120,7 @@ private void InitializeComponent() this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); this.MaximizeBox = false; this.MinimizeBox = false; - this.MinimumSize = new System.Drawing.Size(350, 250); + this.MinimumSize = new System.Drawing.Size(520, 500); this.Name = "FormWhatsNew"; this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; this.Text = "What\'s new?"; diff --git a/Fo76ini/Forms/FormWhatsNew/FormWhatsNew.cs b/Fo76ini/Forms/FormWhatsNew/FormWhatsNew.cs index b150c5e..bcaa20e 100644 --- a/Fo76ini/Forms/FormWhatsNew/FormWhatsNew.cs +++ b/Fo76ini/Forms/FormWhatsNew/FormWhatsNew.cs @@ -1,10 +1,5 @@ using System; -using System.Collections.Generic; using System.ComponentModel; -using System.Data; -using System.Drawing; -using System.IO; -using System.Linq; using System.Net; using System.Text; using System.Windows.Forms; @@ -17,6 +12,13 @@ public FormWhatsNew() { InitializeComponent(); + // Make this form translatable: + Localization.LocalizedForms.Add(new LocalizedForm(this, null)); + + Translation.BlackList.AddRange(new string[] { + "richTextBox" + }); + this.FormClosing += this.Form1_FormClosing; this.backgroundWorkerDownloadRTF.RunWorkerCompleted += backgroundWorkerDownloadRTF_RunWorkerCompleted; } @@ -29,8 +31,8 @@ private void Form1_FormClosing(object sender, FormClosingEventArgs e) private void FormWhatsNew_Load(object sender, EventArgs e) { - if (IniFiles.Instance.Exists(IniFile.Config, "Debug", "sWhatsNewFilePath")) - richTextBox.LoadFile(IniFiles.Instance.GetString(IniFile.Config, "Debug", "sWhatsNewFilePath")); + if (IniFiles.Config.Exists("Debug", "sWhatsNewFilePath")) + richTextBox.LoadFile(IniFiles.Config.GetString("Debug", "sWhatsNewFilePath")); else this.backgroundWorkerDownloadRTF.RunWorkerAsync(); } @@ -51,7 +53,7 @@ private void backgroundWorkerDownloadRTF_DoWork(object sender, DoWorkEventArgs e private void backgroundWorkerDownloadRTF_RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e) { - richTextBox.Rtf = (String)e.Result; + richTextBox.Rtf = (string)e.Result; } private void buttonClose_Click(object sender, EventArgs e) @@ -61,8 +63,8 @@ private void buttonClose_Click(object sender, EventArgs e) private void checkBoxDontShowAgain_CheckedChanged(object sender, EventArgs e) { - IniFiles.Instance.Set(IniFile.Config, "Preferences", "bDisableWhatsNew", this.checkBoxDontShowAgain.Checked); - IniFiles.Instance.SaveConfig(); + IniFiles.Config.Set("Preferences", "bDisableWhatsNew", this.checkBoxDontShowAgain.Checked); + IniFiles.Config.Save(); } } } diff --git a/Fo76ini/Ini/IniFile.cs b/Fo76ini/Ini/IniFile.cs new file mode 100644 index 0000000..603684a --- /dev/null +++ b/Fo76ini/Ini/IniFile.cs @@ -0,0 +1,314 @@ +using Fo76ini.Ini; +using Fo76ini.Utilities; +using IniParser; +using IniParser.Model; +using IniParser.Model.Configuration; +using IniParser.Parser; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; + +namespace Fo76ini +{ + public class IniFile + { + public readonly string FilePath; + public readonly string FileName; + public string DefaultPath; // Fallback to this path, if the actual path doesn't exist. (To load defaults) + + public bool IsReadOnly + { + get + { + if (File.Exists(FilePath)) + return new FileInfo(FilePath).IsReadOnly; + else + return false; + } + set + { + SetFileReadOnlyAttribute(value); + } + } + + private FileIniDataParser iniParser; + private IniData data; + + private DateTime lastModified; + private Encoding encoding = new UTF8Encoding(false); // UTF-8 without BOM + //private static readonly System.Globalization.CultureInfo en_US = System.Globalization.CultureInfo.CreateSpecificCulture("en-US"); + + public IniFile(String path, String defaultPath = null) + { + this.FilePath = path; + this.FileName = Path.GetFileName(path); + this.DefaultPath = defaultPath; + + // Configuring INI parser + IniParserConfiguration iniParserConfig = new IniParserConfiguration(); + iniParserConfig.AllowCreateSectionsOnFly = true; + iniParserConfig.AssigmentSpacer = ""; + iniParserConfig.CaseInsensitive = true; + iniParserConfig.CommentRegex = new System.Text.RegularExpressions.Regex(@"^;.*"); + + // Be very generous, allow everything: + iniParserConfig.AllowDuplicateKeys = true; + iniParserConfig.AllowDuplicateSections = true; + iniParserConfig.AllowKeysWithoutSection = true; + iniParserConfig.OverrideDuplicateKeys = true; + + // Initialize INI parser + this.iniParser = new FileIniDataParser(new IniDataParser(iniParserConfig)); + } + + public void Save() + { + if (data == null) + return; + + RemoveEmptySections(); + bool readOnly = this.IsReadOnly; + SetFileReadOnlyAttribute(false); + this.iniParser.WriteFile(FilePath, data, encoding); + SetFileReadOnlyAttribute(readOnly); + UpdateLastModifiedDate(); + } + + public void Load() + { + try + { + if (File.Exists(FilePath)) + data = this.iniParser.ReadFile(FilePath, encoding); + else if (DefaultPath != null && File.Exists(DefaultPath)) + data = this.iniParser.ReadFile(DefaultPath, encoding); + else + data = new IniData(); + } + catch (IniParser.Exceptions.ParsingException exc) + { + // Add the path to the exception (since IniParser doesn't do this) and throw again: + // throw new IniParser.Exceptions.ParsingException($"{Path} couldn't be parsed: {e.Message}", e); + throw IniParsingException.CreateException(exc, FilePath); + } + UpdateLastModifiedDate(); + } + + public void LoadDefault() + { + try + { + if (DefaultPath != null && File.Exists(DefaultPath)) + data = this.iniParser.ReadFile(DefaultPath, encoding); + else + data = new IniData(); + } + catch + { + data = new IniData(); + } + UpdateLastModifiedDate(); + } + + public bool IsLoaded() + { + return data != null; + } + + public void Merge(IniFile f) + { + this.data.Merge(f.data); + } + + public void Merge(IniData d) + { + this.data.Merge(d); + } + + public bool FileHasBeenModified() + { + return this.lastModified != File.GetLastWriteTime(FilePath); + } + + public void UpdateLastModifiedDate() + { + this.lastModified = File.GetLastWriteTime(FilePath); + } + + protected void RemoveEmptySections() + { + List sectionNames = new List(); + foreach (SectionData section in data.Sections) + if (section.Keys.Count == 0) + sectionNames.Add(section.SectionName); + foreach (string sectionName in sectionNames) + data.Sections.RemoveSection(sectionName); + } + + protected void SetFileReadOnlyAttribute(bool readOnly) + { + // https://stackoverflow.com/questions/8081242/c-sharp-make-file-read-write-from-readonly + if (File.Exists(FilePath)) + { + var attr = File.GetAttributes(FilePath); + + if (readOnly) + attr = attr | FileAttributes.ReadOnly; + else + attr = attr & ~FileAttributes.ReadOnly; + + File.SetAttributes(FilePath, attr); + } + } + + /* + ********************************************************************************************************************************************* + * GETTER AND SETTER + ******************************************************************************************************************************************** + */ + + public bool Exists(string section, string key) + { + return data != null && data[section][key] != null; + } + + public string GetString(string section, string key, string defaultValue) + { + return Exists(section, key) ? data[section][key] : defaultValue; + } + + public string GetString(string section, string key) + { + if (!Exists(section, key)) + throw new KeyNotFoundException($"Couldn't find [{section}] {key} in any *.ini file."); + return data[section][key]; + } + + public static readonly string[] ValidBoolValues = new string[] { "1", "0", "" }; + + public bool GetBool(string section, string key) + { + return GetString(section, key) == "1"; + } + + public bool GetBool(string section, string key, bool defaultValue) + { + string value = GetString(section, key, defaultValue ? "1" : "0"); + if (ValidBoolValues.Contains(value)) + return value == "1"; + else + return defaultValue; + } + + public float GetFloat(string section, string key) + { + return Utils.ToFloat(GetString(section, key)); + } + + public float GetFloat(string section, string key, float defaultValue) + { + try + { + return Utils.ToFloat(GetString(section, key, defaultValue.ToString(Shared.en_US))); + } + catch + { + return defaultValue; + } + } + + public uint GetUInt(string section, string key) + { + return Utils.ToUInt(GetString(section, key)); + } + + public uint GetUInt(string section, string key, uint defaultValue) + { + try + { + return Utils.ToUInt(GetString(section, key, defaultValue.ToString(Shared.en_US))); + } + catch + { + return defaultValue; + } + } + + public int GetInt(string section, string key) + { + return Utils.ToInt(GetString(section, key)); + } + + public int GetInt(string section, string key, int defaultValue) + { + try + { + return Utils.ToInt(GetString(section, key, defaultValue.ToString(Shared.en_US))); + } + catch + { + return defaultValue; + } + } + + public long GetLong(string section, string key) + { + return Utils.ToLong(GetString(section, key)); + } + + public long GetLong(string section, string key, int defaultValue) + { + try + { + return Utils.ToLong(GetString(section, key, defaultValue.ToString(Shared.en_US))); + } + catch + { + return defaultValue; + } + } + + public void Set(string section, string key, string value) + { + data[section][key] = value; + } + + public void Set(string section, string key, int value) + { + Set(section, key, Utils.ToString(value)); + } + + public void Set(string section, string key, uint value) + { + Set(section, key, Utils.ToString(value)); + } + + public void Set(string section, string key, long value) + { + Set(section, key, Utils.ToString(value)); + } + + public void Set(string section, string key, float value) + { + Set(section, key, Utils.ToString(value)); + } + + public void Set(string section, string key, double value) + { + Set(section, key, Utils.ToString(value)); + } + + public void Set(string section, string key, bool value) + { + Set(section, key, value ? "1" : "0"); + } + + public void Remove(string section, string key) + { + if (Exists(section, key)) + data[section].RemoveKey(key); + } + } +} diff --git a/Fo76ini/Ini/IniFiles.cs b/Fo76ini/Ini/IniFiles.cs new file mode 100644 index 0000000..0ce82e0 --- /dev/null +++ b/Fo76ini/Ini/IniFiles.cs @@ -0,0 +1,338 @@ +using Fo76ini.Profiles; +using Fo76ini.Utilities; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Security.AccessControl; +using System.Security.Principal; + +namespace Fo76ini +{ + public static class IniFiles + { + public static IniFile F76; + public static IniFile F76Prefs; + public static IniFile F76Custom; + public static IniFile Config; + + public static readonly string ParentPath; + public static readonly string ConfigPath; + public static readonly string DefaultsPath; + + public static readonly string DefaultF76Path; + public static readonly string DefaultF76PrefsPath; + + static IniFiles() + { + ParentPath = Path.Combine( + Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), + @"My Games\Fallout 76\" + ); + + ConfigPath = Path.Combine(Shared.AppConfigFolder, "config.ini"); + + DefaultsPath = Path.Combine(Shared.AppInstallationFolder, "DefaultINI"); + DefaultF76Path = Path.Combine(DefaultsPath, "Fallout76.ini"); + DefaultF76PrefsPath = Path.Combine(DefaultsPath, "Medium.ini"); + } + + public static void LoadConfig() + { + Config = new IniFile(ConfigPath); + Config.Load(); + } + + public static void Load(GameInstance game) + { + F76 = new IniFile( + Path.Combine(ParentPath, $"{game.IniPrefix}.ini"), + DefaultF76Path + ); + F76Prefs = new IniFile( + Path.Combine(ParentPath, $"{game.IniPrefix}Prefs.ini"), + DefaultF76PrefsPath + ); + F76Custom = new IniFile( + Path.Combine(ParentPath, $"{game.IniPrefix}Custom.ini") + ); + + F76.Load(); + F76Prefs.Load(); + F76Custom.Load(); + + FixDuplicateResourceLists(); + } + + public static bool IsLoaded() + { + return + F76 != null && + F76Prefs != null && + F76Custom != null && + F76.IsLoaded() && + F76Prefs.IsLoaded() && + F76Custom.IsLoaded(); + } + + public static void SetINIsReadOnly(bool readOnly) + { + F76.IsReadOnly = readOnly; + F76Prefs.IsReadOnly = readOnly; + F76Custom.IsReadOnly = readOnly; + } + + public static bool AreINIsReadOnly() + { + return F76.IsReadOnly && F76Prefs.IsReadOnly; + } + + public static void Save() + { + Backup(); + F76.Save(); + F76Prefs.Save(); + F76Custom.Save(); + Config.Save(); + } + + public static void Backup() + { + string backupDir = Path.Combine(ParentPath, "Backups", DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss")); + Directory.CreateDirectory(backupDir); + if (File.Exists(F76.FilePath)) + File.Copy(F76.FilePath, Path.Combine(backupDir, F76.FileName), true); + if (File.Exists(F76Prefs.FilePath)) + File.Copy(F76Prefs.FilePath, Path.Combine(backupDir, F76Prefs.FileName), true); + if (File.Exists(F76Custom.FilePath)) + File.Copy(F76Custom.FilePath, Path.Combine(backupDir, F76Custom.FileName), true); + } + + public static bool FilesHaveBeenModified() + { + return F76.FileHasBeenModified() || F76Prefs.FileHasBeenModified() || F76Custom.FileHasBeenModified(); + } + + public static void UpdateLastModifiedDates() + { + F76.UpdateLastModifiedDate(); + F76Prefs.UpdateLastModifiedDate(); + F76Custom.UpdateLastModifiedDate(); + } + + + /* + ********************************************************************************************************************************************* + * GETTER AND SETTER + ******************************************************************************************************************************************** + */ + + public static bool Exists(string section, string key) + { + foreach (IniFile ini in new IniFile[] { F76, F76Prefs, F76Custom }) + if (ini.Exists(section, key)) + return true; + return false; + } + + public static string GetString(string section, string key, string defaultValue) + { + string value = defaultValue; + foreach (IniFile ini in new IniFile[] { F76, F76Prefs, F76Custom }) + if (ini.Exists(section, key)) + value = ini.GetString(section, key); + return value; + } + + public static string GetString(string section, string key) + { + string value = GetString(section, key, null); + if (value == null) + throw new KeyNotFoundException($"Couldn't find [{section}] {key} in any *.ini file."); + return value; + } + + public static bool GetBool(string section, string key) + { + return GetString(section, key) == "1"; + } + + public static bool GetBool(string section, string key, bool defaultValue) + { + string value = GetString(section, key, defaultValue ? "1" : "0"); + if (IniFile.ValidBoolValues.Contains(value)) + return value == "1"; + else + return defaultValue; + } + + public static float GetFloat(string section, string key) + { + return Utils.ToFloat(GetString(section, key)); + } + + public static float GetFloat(string section, string key, float defaultValue) + { + try + { + return Utils.ToFloat(GetString(section, key, defaultValue.ToString(Shared.en_US))); + } + catch + { + return defaultValue; + } + } + + public static uint GetUInt(string section, string key) + { + return Utils.ToUInt(GetString(section, key)); + } + + public static uint GetUInt(string section, string key, uint defaultValue) + { + try + { + return Utils.ToUInt(GetString(section, key, defaultValue.ToString(Shared.en_US))); + } + catch + { + return defaultValue; + } + } + + public static int GetInt(string section, string key) + { + return Utils.ToInt(GetString(section, key)); + } + + public static int GetInt(string section, string key, int defaultValue) + { + try + { + return Utils.ToInt(GetString(section, key, defaultValue.ToString(Shared.en_US))); + } + catch + { + return defaultValue; + } + } + + public static long GetLong(string section, string key) + { + return Utils.ToLong(GetString(section, key)); + } + + public static long GetLong(string section, string key, int defaultValue) + { + try + { + return Utils.ToLong(GetString(section, key, defaultValue.ToString(Shared.en_US))); + } + catch + { + return defaultValue; + } + } + + /* + ********************************************************************************************************************************************* + * Fixes for invalid *.ini files: + ******************************************************************************************************************************************** + */ + + private static void MergeLists(IniFile ini, string section, string key) + { + string list = ""; + bool found = false; + int i = -1; + IEnumerable lines = File.ReadLines(ini.FilePath); + foreach (string line in lines) + { + if (line.TrimStart().ToLower().StartsWith(key.ToLower())) + { + i = line.IndexOf("="); + if (i > -1) + { + found = true; + list += ", " + line.Substring(i + 1); + } + } + } + list = string.Join(",", + list.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries) + .Select(s => s.Trim()).Distinct().ToArray() + ).Trim(',').Replace(",,", ","); + if (found) + ini.Set(section, key, list); + } + + private static void FixDuplicateResourceLists() + { + // People seem to have duplicate key=value pairs of sResourceIndexFileList and sResourceArchive2List + // Merge them. Default behaviour of the Parser is overriding and this is probably not what the user wants. + // sResourceDataDirsFinal added in v.1.3.1 + // Case insensitive, and whitespace around '=' ignored as of v1.4 + + if (!File.Exists(F76Custom.FilePath)) + return; + + MergeLists(F76Custom, "Archive", "sResourceIndexFileList"); + MergeLists(F76Custom, "Archive", "sResourceArchive2List"); + MergeLists(F76Custom, "Archive", "sResourceDataDirsFinal"); + } + + /* + ********************************************************************************************************************************************* + * Backwards-compatibility: + ******************************************************************************************************************************************** + */ + + /// + /// Allows or denies write permission to the *.ini parent path (%USERPROFILE%\Documents\My Games\Fallout 76). + /// + /// true to allow, false to deny + /// true if successful, false otherwise + public static bool SetNTFSWritePermission(bool writePermission) + { + try + { + // https://stackoverflow.com/questions/7451861/setting-ntfs-permissions-in-c-net + // https://stackoverflow.com/questions/11478917/programmatically-adding-permissions-to-a-folder/11479031 + + // 'Allow' AND 'Deny' are ticked, wtf? + // Explanation: https://answers.microsoft.com/en-us/windows/forum/all/permission-entry-neither-allow-nor-deny-is-checked/5d210777-b466-49e6-855a-6dc1e85563df + + DirectoryInfo dInfo = new DirectoryInfo(ParentPath); + DirectorySecurity dSecurity = dInfo.GetAccessControl(); + + FileSystemRights rights = FileSystemRights.Write; + + // SID: https://support.microsoft.com/en-in/help/243330/well-known-security-identifiers-in-windows-operating-systems + // String account = System.Security.Principal.WindowsIdentity.GetCurrent().Name; + // SecurityIdentifier sidAll = new SecurityIdentifier("S-1-1-0"); + // SecurityIdentifier sidAdmins = new SecurityIdentifier("S-1-5-32-544"); + SecurityIdentifier sidUsers = new SecurityIdentifier("S-1-5-32-545"); + + AccessControlType access = writePermission ? AccessControlType.Allow : AccessControlType.Deny; + + if (writePermission) + { + dSecurity.RemoveAccessRule(new FileSystemAccessRule(sidUsers, rights, InheritanceFlags.ContainerInherit | InheritanceFlags.ObjectInherit, PropagationFlags.None, AccessControlType.Deny)); + dSecurity.AddAccessRule(new FileSystemAccessRule(sidUsers, rights, InheritanceFlags.ContainerInherit | InheritanceFlags.ObjectInherit, PropagationFlags.None, AccessControlType.Allow)); + } + else + { + dSecurity.AddAccessRule(new FileSystemAccessRule(sidUsers, rights, InheritanceFlags.ContainerInherit | InheritanceFlags.ObjectInherit, PropagationFlags.None, AccessControlType.Deny)); + dSecurity.RemoveAccessRule(new FileSystemAccessRule(sidUsers, rights, InheritanceFlags.ContainerInherit | InheritanceFlags.ObjectInherit, PropagationFlags.None, AccessControlType.Allow)); + } + dInfo.SetAccessControl(dSecurity); + } + catch + { + return false; + } + + return true; + } + } +} diff --git a/Fo76ini/Ini/IniParsingException.cs b/Fo76ini/Ini/IniParsingException.cs new file mode 100644 index 0000000..171aa13 --- /dev/null +++ b/Fo76ini/Ini/IniParsingException.cs @@ -0,0 +1,70 @@ +using IniParser.Exceptions; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Fo76ini.Ini +{ + public class IniParsingException : Exception + { + public int LineNumber; + public string LineValue; + public Version LibVersion; + public string FilePath; + public string FileName; + + public static IniParsingException CreateException(ParsingException originalException, string filePath) + { + // IniParser.Exceptions.ParsingException makes no sense (to me at least) because it displays stuff like this: + // "Unknown file format. Couldn't parse the line: 'bMBEnable1'. while parsing line number 0 with value '' - IniParser version: 2.5.2.0 while parsing line number 31 with value 'bMBEnable1' - IniParser version: 2.5.2.0 while parsing line number 0 with value '' - IniParser version: 2.5.2.0" + // Line Number 0, with value '', huh? + // So let's just extract actually usable information from it and create a new exception: + + string fileName = Path.GetFileName(filePath); + + int LineNumber = -1; + string LineValue = ""; + Version LibVersion = null; + + ParsingException innerExc = originalException; + while (innerExc != null) + { + if (innerExc.LineNumber > 0 && innerExc.LineValue != "") + { + LineNumber = innerExc.LineNumber; + LineValue = innerExc.LineValue; + LibVersion = innerExc.LibVersion; + } + try + { + innerExc = (ParsingException)innerExc.InnerException; + } + catch + { + break; + } + } + + string message = $"Couldn't parse line number {LineNumber}: '{LineValue}' in file '{fileName}'"; + + + IniParsingException newExc = new IniParsingException(message, originalException); + + newExc.LineNumber = LineNumber; + newExc.LineValue = LineValue; + newExc.LibVersion = LibVersion; + + newExc.FilePath = filePath; + newExc.FileName = fileName; + + return newExc; + } + + public IniParsingException() { } + public IniParsingException(string message) : base(message) { } + public IniParsingException(string message, Exception inner) : base(message, inner) { } + } +} diff --git a/Fo76ini/Interface/DropDown.cs b/Fo76ini/Interface/DropDown.cs index f69798d..06e5c4f 100644 --- a/Fo76ini/Interface/DropDown.cs +++ b/Fo76ini/Interface/DropDown.cs @@ -1,31 +1,29 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Text; -using System.Threading.Tasks; using System.Windows.Forms; using System.Xml.Linq; -namespace Fo76ini +namespace Fo76ini.Interface { public struct DropDown { public ComboBox comboBox; - private List items; + private List items; - public static Dictionary Dict = new Dictionary(); + public static Dictionary Dict = new Dictionary(); - public static void Add(String key, DropDown comboBox) + public static void Add(string key, DropDown comboBox) { Dict.Add(key, comboBox); } - public static DropDown Get(String key) + public static DropDown Get(string key) { return Dict[key]; } - public static bool ContainsKey(String key) + public static bool ContainsKey(string key) { return Dict.ContainsKey(key); } @@ -33,12 +31,12 @@ public static bool ContainsKey(String key) public DropDown(ComboBox comboBox) { this.comboBox = comboBox; - this.items = new List(); + this.items = new List(); foreach (object item in comboBox.Items) - this.items.Add((String)item); + this.items.Add((string)item); } - public DropDown(ComboBox comboBox, List items) + public DropDown(ComboBox comboBox, List items) { this.comboBox = comboBox; this.items = items; @@ -46,35 +44,35 @@ public DropDown(ComboBox comboBox, List items) this.comboBox.Items.AddRange(this.items.ToArray()); } - public DropDown(ComboBox comboBox, String[] items) + public DropDown(ComboBox comboBox, string[] items) { this.comboBox = comboBox; - this.items = new List(); - foreach (String item in items) + this.items = new List(); + foreach (string item in items) this.items.Add(item); this.comboBox.Items.Clear(); this.comboBox.Items.AddRange(this.items.ToArray()); } - public void Add(String item) + public void Add(string item) { this.comboBox.Items.Add(item); this.items.Add(item); } - public void AddRange(String[] items) + public void AddRange(string[] items) { this.comboBox.Items.AddRange(items); - foreach (String item in items) + foreach (string item in items) this.items.Add(item); } - public bool Contains(String item) + public bool Contains(string item) { return this.items.Contains(item); } - public int FindIndex(String match) + public int FindIndex(string match) { return this.items.FindIndex(x => x == match); } @@ -90,15 +88,15 @@ public void Clear() this.items.Clear(); } - public void SetRange(String[] items) + public void SetRange(string[] items) { this.Clear(); this.comboBox.Items.AddRange(items); - foreach (String item in items) + foreach (string item in items) this.items.Add(item); } - public void ReplaceRange(String[] items) + public void ReplaceRange(string[] items) { int selectedIndex = this.comboBox.SelectedIndex; this.SetRange(items); @@ -108,16 +106,16 @@ public void ReplaceRange(String[] items) public static XElement SerializeAll() { XElement xmlDropDowns = new XElement("Dropdowns"); - foreach (KeyValuePair pair in DropDown.Dict) + foreach (KeyValuePair pair in DropDown.Dict) xmlDropDowns.Add(pair.Value.Serialize(pair.Key)); return xmlDropDowns; } - public XElement Serialize(String id) + public XElement Serialize(string id) { XElement xmlDropDown = new XElement("Dropdown"); xmlDropDown.Add(new XAttribute("id", id)); - foreach (String option in this.Items) + foreach (string option in this.Items) xmlDropDown.Add(new XElement("Option", option)); return xmlDropDown; } @@ -134,7 +132,7 @@ public static void DeserializeAll(XElement xmlDropDowns) foreach (XElement xmlDropDown in xmlDropDowns.Descendants("Dropdown")) { // Get id: - String id = xmlDropDown.Attribute("id").Value; + string id = xmlDropDown.Attribute("id").Value; // If such a combobox exists, deserialize: if (DropDown.ContainsKey(id)) @@ -152,7 +150,7 @@ public void Deserialize(XElement xmlDropDown) ... */ - List options = new List(); + List options = new List(); foreach (XElement element in xmlDropDown.Descendants("Option")) options.Add(element.Value); @@ -162,10 +160,10 @@ public void Deserialize(XElement xmlDropDown) return; } - this.ReplaceRange(options.ToArray()); + this.ReplaceRange(options.ToArray()); } - public List Items + public List Items { get { return this.items; } set @@ -182,7 +180,7 @@ public int SelectedIndex set { this.comboBox.SelectedIndex = value; } } - public String SelectedItem + public string SelectedItem { get { return this.items[this.comboBox.SelectedIndex]; } } diff --git a/Fo76ini/Interface/InvalidXmlException.cs b/Fo76ini/Interface/InvalidXmlException.cs index e5f01c9..3315332 100644 --- a/Fo76ini/Interface/InvalidXmlException.cs +++ b/Fo76ini/Interface/InvalidXmlException.cs @@ -1,7 +1,7 @@ using System; using System.Runtime.Serialization; -namespace Fo76ini +namespace Fo76ini.Interface { [Serializable] internal class InvalidXmlException : Exception diff --git a/Fo76ini/Interface/MsgBox.cs b/Fo76ini/Interface/MsgBox.cs index b54777f..53b5cff 100644 --- a/Fo76ini/Interface/MsgBox.cs +++ b/Fo76ini/Interface/MsgBox.cs @@ -3,71 +3,87 @@ using System.IO; using System.Linq; using System.Media; -using System.Text; -using System.Threading.Tasks; using System.Windows.Forms; using System.Xml.Linq; +using Fo76ini.Utilities; -namespace Fo76ini +namespace Fo76ini.Interface { public class MsgBox { - public String Title; - public String Text; - private String id; + public string Title; + public string Text; + private string id; - public const String NotificationSoundFile = @"notify.wav"; - private static SoundPlayer SoundPlayer = new SoundPlayer(NotificationSoundFile); + public const string NotificationSoundFile = @"notify.wav"; + public const string ErrorSoundFile = @"error.wav"; + private static SoundPlayer NotifySoundPlayer = new SoundPlayer(NotificationSoundFile); + private static SoundPlayer ErrorSoundPlayer = new SoundPlayer(ErrorSoundFile); public static void PlayNotificationSound() { // Don't play sound, if disabled: - if (!IniFiles.Instance.GetBool(IniFile.Config, "Preferences", "bPlayNotificationSound", true)) + if (!IniFiles.Config.GetBool("Preferences", "bPlayNotificationSound", true)) return; // Play alert.wav if available: if (File.Exists(NotificationSoundFile)) - SoundPlayer.Play(); + NotifySoundPlayer.Play(); // Fallback to system sound if alert.wav is not available: else SystemSounds.Asterisk.Play(); } - public String ID + public static void PlayErrorNotificationSound() + { + // Don't play sound, if disabled: + if (!IniFiles.Config.GetBool("Preferences", "bPlayNotificationSound", true)) + return; + + // Play alert.wav if available: + if (File.Exists(ErrorSoundFile)) + ErrorSoundPlayer.Play(); + + // Fallback to system sound if alert.wav is not available: + else + SystemSounds.Hand.Play(); + } + + public string ID { get { return id; } } - public MsgBox (String id, String title, String text) + public MsgBox(string id, string title, string text) { this.Title = title; this.Text = text; this.id = id; } - - private static Dictionary msgBoxes = new Dictionary(); + + private static Dictionary msgBoxes = new Dictionary(); public static void Add(MsgBox msgBox) { MsgBox.msgBoxes[msgBox.id] = msgBox; } - public static void Add(String id, String title, String text) + public static void Add(string id, string title, string text) { MsgBox.msgBoxes[id] = new MsgBox(id, title, text); } - public static MsgBox Get(String key) + public static MsgBox Get(string key) { if (MsgBox.msgBoxes.ContainsKey(key)) return MsgBox.msgBoxes[key]; else - return new MsgBox("notfound", $"-- Messagebox \"{key}\" not found --", $"If you read this, the programmer screwed up, lol.\nAvailable messageboxes:\n{String.Join("\n", MsgBox.msgBoxes.Keys.ToArray())}"); + return new MsgBox("notfound", $"-- Messagebox \"{key}\" not found --", "If you read this, the programmer screwed up, lol."); // $"\nAvailable messageboxes:\n{string.Join("\n", MsgBox.msgBoxes.Keys.ToArray())}" } - public MsgBox FormatTitle(params String[] values) + public MsgBox FormatTitle(params string[] values) { try { - return new MsgBox(this.ID, String.Format(this.Title, values), this.Text); + return new MsgBox(this.ID, string.Format(this.Title, values), this.Text); } catch (FormatException ex) { @@ -75,11 +91,11 @@ public MsgBox FormatTitle(params String[] values) } } - public MsgBox FormatText(params String[] values) + public MsgBox FormatText(params string[] values) { try { - return new MsgBox(this.ID, this.Title, String.Format(this.Text, values)); + return new MsgBox(this.ID, this.Title, string.Format(this.Text, values)); } catch (FormatException ex) { @@ -89,66 +105,99 @@ public MsgBox FormatText(params String[] values) - public static DialogResult ShowID(String id) + public static DialogResult ShowID(string id) { return MsgBox.Get(id).Show(); } - public static DialogResult ShowID(String id, MessageBoxButtons buttons, MessageBoxIcon icon) + public static DialogResult ShowID(string id, MessageBoxButtons buttons, MessageBoxIcon icon) { return MsgBox.Get(id).Show(buttons, icon); } - public static DialogResult ShowID(String id, MessageBoxButtons buttons) + public static DialogResult ShowID(string id, MessageBoxButtons buttons) { return MsgBox.Get(id).Show(buttons); } - public static DialogResult ShowID(String id, MessageBoxIcon icon) + public static DialogResult ShowID(string id, MessageBoxIcon icon) { return MsgBox.Get(id).Show(icon); } public DialogResult Show() { - SystemSounds.Asterisk.Play(); + //SystemSounds.Asterisk.Play(); return MessageBox.Show(this.Text, this.Title); } public DialogResult Show(MessageBoxButtons buttons, MessageBoxIcon icon) { - SystemSounds.Asterisk.Play(); + //SystemSounds.Asterisk.Play(); return MessageBox.Show(this.Text, this.Title, buttons, icon); } public DialogResult Show(MessageBoxButtons buttons) { - SystemSounds.Asterisk.Play(); + //SystemSounds.Asterisk.Play(); return MessageBox.Show(this.Text, this.Title, buttons); } public DialogResult Show(MessageBoxIcon icon) { - SystemSounds.Asterisk.Play(); + //SystemSounds.Asterisk.Play(); return MessageBox.Show(this.Text, this.Title, MessageBoxButtons.OK, icon); } - public void Popup() + public static DialogResult Show(string title, string text, MessageBoxButtons buttons, MessageBoxIcon icon) + { + return MessageBox.Show(text, title, buttons, icon); + } + + public static DialogResult Show(string title, string text, MessageBoxButtons buttons) { - Utils.CreatePopup(this.Title, this.Text).Popup(); + return MessageBox.Show(text, title, buttons); + } + + public static DialogResult Show(string title, string text, MessageBoxIcon icon) + { + return MessageBox.Show(text, title, MessageBoxButtons.OK, icon); + } + + public static DialogResult Show(string title, string text) + { + return MessageBox.Show(text, title); + } + + public static void Popup(string title, string text) + { + Utils.CreatePopup(title, text).Popup(); PlayNotificationSound(); } + public static void Popup(string title, string text, MessageBoxIcon icon) + { + Utils.CreatePopup(title, text, icon).Popup(); + if (icon == MessageBoxIcon.Warning || icon == MessageBoxIcon.Error) + PlayErrorNotificationSound(); + else + PlayNotificationSound(); + } + + public void Popup() + { + MsgBox.Popup(this.Title, this.Text); + } + public void Popup(MessageBoxIcon icon) { - Utils.CreatePopup(this.Title, this.Text, icon).Popup(); - PlayNotificationSound(); + MsgBox.Popup(this.Title, this.Text, icon); } public static XElement SerializeAll() { XElement xmlMessageBoxes = new XElement("Messageboxes"); - foreach (KeyValuePair entry in MsgBox.msgBoxes) + foreach (KeyValuePair entry in MsgBox.msgBoxes) xmlMessageBoxes.Add(entry.Value.Serialize()); return xmlMessageBoxes; } diff --git a/Fo76ini/Interface/Translation.Shared.cs b/Fo76ini/Interface/Translation.Shared.cs index 8c3b4f9..a5a8922 100644 --- a/Fo76ini/Interface/Translation.Shared.cs +++ b/Fo76ini/Interface/Translation.Shared.cs @@ -1,8 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using Fo76ini.Interface; namespace Fo76ini { @@ -12,8 +8,9 @@ private static void AddSharedStrings() { localizedStrings["newVersionAvailable"] = "There is a newer version available: {0}"; localizedStrings["updateNowButton"] = "Update now!"; + localizedStrings["unknown"] = "Unknown"; localizedStrings["modsDeploymentNecessary"] = "Deployment necessary"; - localizedStrings["modsAllDone"] = "All set"; + //localizedStrings["modsAllDone"] = "All set"; localizedStrings["modsFailed"] = "Something went wrong, see log files for details."; localizedStrings["modsTableFormatGeneral"] = "General"; localizedStrings["modsTableFormatTextures"] = "Textures"; @@ -23,11 +20,13 @@ private static void AddSharedStrings() localizedStrings["modsTableTypeSeparateFrozen"] = "Separate (Frozen)"; localizedStrings["modsTableTypeLoose"] = "Loose"; localizedStrings["modTableFrozenPending"] = "Pending"; + localizedStrings["modTableFrozen"] = "Frozen"; + //localizedStrings["modTableThawed"] = "Thawed"; //localizedStrings["modDetailsTitle"] = "Edit {0}"; //localizedStrings["modDetailsTitleBulk"] = "Edit {0} mods"; localizedStrings["modDetailsTitleBulkSelected"] = "{0} mods selected"; localizedStrings["nmResetTime"] = "in {0} hour(s) and {1} minute(s)"; - localizedStrings["nmResetTimeNever"] = "Never"; + //localizedStrings["nmResetTimeNever"] = "Never"; localizedStrings["nmRateLimitLeft"] = "{0} left"; localizedStrings["nmBasicAccount"] = "Basic"; localizedStrings["nmSupporterAccount"] = "Supporter"; @@ -39,22 +38,28 @@ private static void AddSharedStrings() localizedStrings["invalid"] = "Invalid"; localizedStrings["nuclearwintermode"] = "Nuclear Winter"; localizedStrings["adventuremode"] = "Adventure"; + localizedStrings["affectedValues"] = "Affected values"; + localizedStrings["affectedFiles"] = "Affected files"; + localizedStrings["endorsedText"] = "You have endorsed this mod."; + localizedStrings["notEndorsedText"] = "You have not endorsed this mod yet."; + localizedStrings["abstainedText"] = "You have abstained from endorsing this mod."; } public static void AddSharedMessageBoxes() { // Form1: + MsgBox.Add("iniParsingError", "Couldn't parse *.ini files", - "At least one of the game's *.ini files is corrupted or contains a syntax error.\n\nYou might:\n -> read the error message and fix the error or\n -> delete the invalid *.ini file and start Fallout 76 to create a new, valid *.ini file\n -> and then try again.\n\nERROR MESSAGE:\n{0}" - ); - - MsgBox.Add("backupAndSave", - "Backup and save", - "Do you want to create a backup before applying all changes?\n\n" + - " Press \"Yes\" to create a backup and save.\n" + - " Press \"No\" to save without backup.\n" + - " Press \"Cancel\" to abort." + "At least one of the game's *.ini files is corrupted or contains a syntax error.\n" + + "\n" + + "You might:\n" + + " -> read the error message and fix the error or\n" + + " -> delete the invalid *.ini file and start Fallout 76 to create a new, valid *.ini file\n" + + " -> and then try again.\n" + + "\n" + + "ERROR MESSAGE:\n" + + "{0}" ); MsgBox.Add("changesApplied", @@ -62,22 +67,9 @@ public static void AddSharedMessageBoxes() "Changes have been applied. You may start the game now." ); - MsgBox.Add("chooseGameEdition", - "Choose Game Edition", - "Please pick your game edition under the Settings tab." - ); - - MsgBox.Add("runGameToGenerateINI", - "{0} and {1} not found", - "Please run the game first before using this tool.\n" + - "The game will generate those files on first start-up." - ); - - MsgBox.Add("oldValuesResetToDefault", + MsgBox.Add("downloadLanguagesFinished", "Done", - "Some values have been reset to default.\n" + - "Only unstable values from previous versions are affected.\n" + - "Don't forget to click 'Apply'." + "Downloaded language files: {0}" ); MsgBox.Add("iniFilesModified", @@ -87,68 +79,9 @@ public static void AddSharedMessageBoxes() "Please restart the tool to work with the new values." ); - MsgBox.Add("onLoadFuncException", - "Error while loading UI", - "{0} exception(s) occured while the UI was loaded.\n" + - "This might be caused by corrupted ini files.\n" + - "Some UI elements might not be functioning correctly.\n\n" + - "{1}" - ); - - MsgBox.Add("iniValuesInvalid", - "Invalid *.ini values found", - "{0} *.ini value(s) are invalid:\n\n" + - "{1}" - ); - - MsgBox.Add("downloadLanguagesFinished", - "Done", - "Downloaded language files: {0}" - ); - - MsgBox.Add("downloadLanguagesFailed", - "Failed", - "Downloading languages failed.\n{0}" - ); - - MsgBox.Add("msstoreRestartRequired", - "Do you want to switch?", - "Switching to or from the Microsoft Store edition requires a restart of the tool." - ); - - MsgBox.Add("msstoreRunExecutableFailed", - "Couldn't launch game: {0}", - "Unfortunately, it's not possible to launch the executable directly due to \"security\" restrictions. Thanks Microsoft, we hate it. :(" - ); - - MsgBox.Add("customIniFilesParsingError", - "Couldn't add your custom *.ini tweaks", - "At least one of your custom *.ini files contains an error.\n{0}" - ); - - MsgBox.Add("displayResolutionTooLow", - "Display resolution might be too low", - "Your display resolution is not supported.\nThe windows might be to big to fit on screen.\nYour display size: {0}\nMinimum display size: {1}\nRecommended display size: 1920 x 1080" - ); - - MsgBox.Add("restartRequired", - "Restart required.", - "A restart of the tool is required for changes to take effect.\nAre you sure, you want to change this option now?" - ); - // Gallery: - MsgBox.Add("galleryDeleteScreenshot", - "Delete {0}?", - "You are about to delete '{0}'. Are you sure?" - ); - - MsgBox.Add("galleryDeleteScreenshots", - "Delete {0} files?", - "You are about to delete {0} files. Are you sure?" - ); - MsgBox.Add("galleryDeleteThumbnails", "Are you sure?", "Are you sure you want to delete the gallery's thumbnails?\nThe next time you click on 'Refresh gallery', it will take significantly longer as it recreates all thumbnails." @@ -158,12 +91,12 @@ public static void AddSharedMessageBoxes() // Nuclear Winter: MsgBox.Add("nwModeDisabled", - "NW mode disabled", + "Nuclear Winter mode disabled", "You can now launch into Adventure mode." ); MsgBox.Add("nwModeEnabled", - "NW mode enabled", + "Nuclear Winter mode enabled", "You can now launch into Nuclear Winter mode." ); @@ -187,60 +120,18 @@ public static void AddSharedMessageBoxes() MsgBox.Add("modsArchive2Missing", "Archive2 is missing", - ".\\Archive2\\Archive2.exe is missing.\nPlease download this tool again, or install Archive2 manually." + ".\\Archive2\\Archive2.exe is missing.\nTry to reinstall this tool, or install Archive2 manually." ); MsgBox.Add("modsGamePathNotSet", - "Game path not set", - "Please set the path to the game (where Fallout76.exe resides)." - ); - - MsgBox.Add("modsGamePathInvalid", - "Wrong path", - "Wrong game folder path." - ); - - MsgBox.Add("modsDeployErrorModDirNotFound", - "Mod {0} couldn't be deployed.", - "Directory {0} does not exist.\n" + - "Please restart the mod manager and add the mod again." - ); - - MsgBox.Add("modsDeployErrorBA2RootIsNotData", - "Mod {0} couldn't be deployed.", - "The root folder has to be set to \".\\Data\" for mods, that are to be installed as a *.ba2 archive.\n" + - "Please fix the \"Install into\" setting and try again." + "Game path not specified or invalid", + "Please make sure you have set the correct path to the game.\n" + + "You can do this in the settings." ); - MsgBox.Add("modsDeleteBtn", - "Are you sure?", - "Are you sure you want to delete the mod {0}?" - ); - - MsgBox.Add("modsDeleteBulkBtn", - "Are you sure?", - "Are you sure you want to delete {0} mods?" - ); - - MsgBox.Add("modsExtractUnknownError", - "Archive couldn't be uncompressed", - "{0}" - ); - - MsgBox.Add("modsExtractUnknownErrorText", - "Archive couldn't be uncompressed", - "Please uncompress the archive and add the mod as a folder." - ); - - MsgBox.Add("modsExtractUnknownError7zip", - "7-Zip archive couldn't be uncompressed", - "{0}" - ); - - MsgBox.Add("modsArchiveTypeNotSupported", - "Unsupported file format", - "{0} files are not supported.\n" + - "Please uncompress the archive and add the mod as a folder." + MsgBox.Add("7ZipMissing", + "7-Zip is missing", + ".\\7z\\7z.exe is missing.\nTry to reinstall this tool, or copy 7-Zip manually." ); MsgBox.Add("modsNoConflictingFiles", @@ -248,62 +139,11 @@ public static void AddSharedMessageBoxes() "No conflicting files found." ); - MsgBox.Add("modsDeploymentNecessary", - "Deployment necessary", - "For this action, you have to deploy all mods first." - ); - - MsgBox.Add("modsOnCloseDeploymentNecessary", - "Are you sure?", - "You haven't deployed the changes you made.\n" + - "Are you sure you want to close the mod manager?" - ); - - MsgBox.Add("modDirNotExist", - "Mod folder does not exist.", - "The path {0} does not exist.\nThe mod folder was removed without removing the entry in the manifest." - ); - - MsgBox.Add("modsInvalidManifestEntry", - "Invalid manifest.xml entry", - "A mod entry is invalid and was ignored.\nError: {0}" - ); - - MsgBox.Add("modsInvalidManifestRoot", - "Invalid manifest.xml entry", - "The tag has invalid attributes.\nError: {0}" - ); - MsgBox.Add("modsImportQuestion", "Import manually installed mods?", "Are you sure you want to add mods installed outside of the mod manager?" ); - MsgBox.Add("modsSameArchiveName", - "Conflicting mods", - "Some mods have the same archive name: \"{0}\".\nConflicting mod name: {1}" - ); - - MsgBox.Add("modDetailsMoveManagedFolderFailed", - "Failed to rename folder", - "Managed mod folder couldn't be renamed.\nError message: \"{0}\"." - ); - - MsgBox.Add("modsRepairDDSQuestion", - "Are you sure?", - "This will attempt to repair all *.dds files.\nIt can take a long time, depending on file size and number of files.\nAre you sure you want to continue?" - ); - - MsgBox.Add("modsRepairDDSDone", - "Done", - "*.dds files have been repaired." - ); - - MsgBox.Add("modsAccessDenied", - "Access denied", - "{0}\nPlease start the tool as admin and try again." - ); - MsgBox.Add("modsRepackFrozenBundledArchives", "Would you like to repack bundled archives?", "There are frozen bundled archives available. Would you like to repack bundled archives again?\n\n" + @@ -311,70 +151,95 @@ public static void AddSharedMessageBoxes() " No - I didn't make changes, please deploy my frozen bundled archives. (quick)" ); + MsgBox.Add("archive2Error", + "Archive2 failed to pack/extract an archive", + "Archive2 failed for an unknown reason.\nPlease check the log files for details." + ); + MsgBox.Add("archive2InstallRequirements", "Archive2 failed to pack/extract an archive", "Please make sure you've installed 'Visual C++ Redistributable for Visual Studio 2012 Update 4'.\n" + "You can find a link on the NexusMods page." ); - MsgBox.Add("nwModeEnabledButModsAreDeployed", - "Mods are still deployed", - "You've enabled the Nuclear Winter mode, but your mods are still deployed.\n" + - "Do you want to disable them now?" + MsgBox.Add("modsArchiveTypeNotSupported", + "Unsupported file format", + "{0} files are not supported.\n" + + "Please uncompress the archive and add the mod as a folder." + ); + + MsgBox.Add("modsLegacyFormatDetected", + "Legacy version found", + "It seems like you've managed mods before, but with a version prior to v1.9.0.\n" + + "How mods are managed and stored has changed significantly.\n" + + "As a result, they must be converted to the new format.\n\n" + + "NOTE: This will rename folders and unfreeze archives. After they're converted, they may take up more space, depending on how many mods were frozen. Downgrading will still be possible, but some mods might load incorrectly.\n\n" + + "Would you like to convert them now? It won't take long." ); - MsgBox.Add("nwModeDisabledAndModsAreStillDisabled", - "Do you want to re-enable your mods again?", - "You've disabled the Nuclear Winter mode, but your mods are still disabled.\n" + - "Do you want to deploy them now?" + MsgBox.Add("modsInvalidManifestEntry", + "Invalid manifest.xml entry", + "A mod entry is invalid and was ignored.\nError: {0}" ); - // NexusMods + // NexusMods: MsgBox.Add("nexusModsRemoteInfoRefreshedSuccess", "Mod information updated", "Mod information updated and thumbnails downloaded." ); - MsgBox.Add("nexusModsProfileRefreshFailed", - "Failed", - "Couldn't update your profile:\n{0}" + MsgBox.Add("nexusModsEndorseAllQuestion", + "Endorse all mods?", + "This will endorse all your installed mods. Are you sure?" ); - MsgBox.Add("nexusModsDeleteThumbnails", - "Are you sure?", - "Do you really want to delete all thumbnails?" + MsgBox.Add("nexusModsNotLoggedIn", + "Not logged in", + "Please log in to NexusMods first and try again" ); - MsgBox.Add("nexusModsDeleteThumbnailsSuccess", - "Done", - "Thumbnails deleted." + + // TODO: Replace a lot of the message boxes with generic ones for easier translation. + // Generic questions: + + MsgBox.Add("deleteQuestion", + "Delete {0}?", + "You are about to delete '{0}'. Are you sure?" ); - MsgBox.Add("nexusModsDeleteThumbnailsFailed", - "Something went wrong", - "Thumbnails couldn't be deleted.\nTry again later." + MsgBox.Add("deleteMultipleQuestion", + "Delete {0} files?", + "You are about to delete {0} files. Are you sure?" ); - MsgBox.Add("nexusModsRemoveProfile", - "Are you sure?", - "Do you really want to remove your profile from the mod manager?" + MsgBox.Add("failed", + "Failed", + "{0}" ); - MsgBox.Add("nexusModsRemoveProfileSuccess", + MsgBox.Add("done", "Done", - "Profile removed." + "{0}" ); - MsgBox.Add("nexusModsRemoveRemoteInfo", + MsgBox.Add("areYouSure", "Are you sure?", - "Do you really want to remove mod information?" + "{0}" ); - MsgBox.Add("nexusModsRemoveRemoteInfoSuccess", - "Done", - "Mod information removed." + + // Profile manager: + + MsgBox.Add("errorAtLeastOneGameOrProfile", + "Cannot delete last game profile", + "At least one game profile is required." + ); + + MsgBox.Add("gamePathAutoDetectFailed", + "Auto-detect failed", + "Couldn't find any common game path. Please select the path manually." ); } } diff --git a/Fo76ini/Interface/Translation.cs b/Fo76ini/Interface/Translation.cs index 047fed9..6fadd08 100644 --- a/Fo76ini/Interface/Translation.cs +++ b/Fo76ini/Interface/Translation.cs @@ -4,26 +4,33 @@ using System.Globalization; using System.IO; using System.Linq; -using System.Net.Security; using System.Reflection; -using System.Text; using System.Text.RegularExpressions; -using System.Threading.Tasks; using System.Windows.Forms; using System.Xml.Linq; +using Fo76ini.Interface; +using Fo76ini.Tweaks; +using Fo76ini.Utilities; namespace Fo76ini { public partial class Localization { - public static Dictionary localizedStrings = new Dictionary(); - public static String languageFolder = Path.Combine(Shared.AppConfigFolder, "languages"); - private static List translations = new List(); - private static DropDown comboBoxTranslations; + public static Dictionary localizedStrings = new Dictionary(); + public static readonly string LanguageFolder = Path.Combine(Shared.AppConfigFolder, "languages"); + + /// + /// Current locale + /// + public static string Locale = "en-US"; + /// + /// Add your form to this list if you want it to get translated. + /// public static List LocalizedForms = new List(); - public static String locale = "en-US"; + private static List translations = new List(); + private static DropDown comboBoxTranslations; static Localization() { @@ -31,43 +38,73 @@ static Localization() AddSharedMessageBoxes(); } - public static String GetString(String str) + /// + /// Returns a localized string identified by 'str'. + /// + /// String identifier + /// Localized string + public static string GetString(string str) { - return Localization.localizedStrings[str]; + if (Localization.localizedStrings.ContainsKey(str)) + return Localization.localizedStrings[str]; + else + return $"\"{str}\" NOT FOUND"; } - public static void AssignDropBox(ComboBox comboBoxLanguage) + /// + /// Assigns a dropdown menu to hold all languages. + /// Also assigns an event handler 'SelectedIndexChanged' to automatically translate forms. + /// + /// + public static void AssignDropDown(ComboBox comboBoxLanguage) { Localization.comboBoxTranslations = new DropDown(comboBoxLanguage); + comboBoxLanguage.SelectedIndexChanged += (object sender, EventArgs e) => + { + Translation translation = Localization.GetTranslation(); + translation.Apply(); + + IniFiles.Config.Set("Preferences", "sLanguage", translation.ISO); + Localization.Locale = translation.ISO; + + if (translation.ISO != "en-US") + Localization.GenerateTemplate(translation); + }; } public static void LookupLanguages() { - // Create 'languages' folder: - if (!Directory.Exists(languageFolder)) - Directory.CreateDirectory(languageFolder); + // Create 'languages' folder if not existing: + Directory.CreateDirectory(LanguageFolder); // Look into the folder and add all language files to the dropdown menu: Localization.translations.Clear(); Localization.comboBoxTranslations.Clear(); - foreach (string filePath in Directory.GetFiles(languageFolder)) + foreach (string filePath in Directory.GetFiles(LanguageFolder)) { - if (filePath.EndsWith(".xml") && !filePath.EndsWith(".template.xml")) + try { - Translation translation = new Translation(); - translation.Load(filePath); - Localization.translations.Add(translation); - Localization.comboBoxTranslations.Add(translation.Name); - //Localization.comboBoxTranslations.Add($"{translation.Name} [{translation.Version}]"); + if (filePath.EndsWith(".xml") && !filePath.EndsWith(".template.xml")) + { + Translation translation = new Translation(); + translation.Load(filePath); + Localization.translations.Add(translation); + Localization.comboBoxTranslations.Add(translation.Name); + //Localization.comboBoxTranslations.Add($"{translation.Name} [{translation.Version}]"); + } + } + catch (Exception exc) + { + MsgBox.Popup("Loading translation failed", $"The translation '{Path.GetFileNameWithoutExtension(filePath)}' couldn't be loaded.\n{exc.GetType()}: {exc.Message}", MessageBoxIcon.Warning); } } // Set language: - String selectedLanguageISO = IniFiles.Instance.GetString(IniFile.Config, "Preferences", "sLanguage", CultureInfo.CurrentUICulture.Name); + string selectedLanguageISO = IniFiles.Config.GetString("Preferences", "sLanguage", CultureInfo.CurrentUICulture.Name); int languageIndex = GetTranslationIndex(selectedLanguageISO); int enUSIndex = GetTranslationIndex("en-US"); Localization.comboBoxTranslations.SelectedIndex = languageIndex > -1 ? languageIndex : enUSIndex; - Localization.locale = selectedLanguageISO; + Localization.Locale = selectedLanguageISO; } public static void GenerateTemplate(Translation translation) @@ -75,7 +112,7 @@ public static void GenerateTemplate(Translation translation) translation.Save(translation.ISO + ".template.xml", Shared.VERSION); } - public static void GenerateTemplate() + public static void GenerateDefaultTemplate() { Translation english = new Translation(); english.Name = "English (USA)"; @@ -90,7 +127,7 @@ public static Translation GetTranslation() return translations[comboBoxTranslations.SelectedIndex]; } - public static Translation GetTranslation(String iso) + public static Translation GetTranslation(string iso) { foreach (Translation translation in Localization.translations) if (translation.ISO == iso) @@ -98,7 +135,7 @@ public static Translation GetTranslation(String iso) return null; } - public static int GetTranslationIndex(String iso) + public static int GetTranslationIndex(string iso) { int index = 0; foreach (Translation translation in Localization.translations) @@ -113,7 +150,7 @@ public static int GetTranslationIndex(String iso) public static XElement SerializeStrings() { XElement xmlStrings = new XElement("Strings"); - foreach (KeyValuePair pair in Localization.localizedStrings) + foreach (KeyValuePair pair in Localization.localizedStrings) xmlStrings.Add(new XElement("String", new XAttribute("text", pair.Value), new XAttribute("id", pair.Key))); @@ -132,26 +169,30 @@ public static void DeserializeStrings(XElement strings) public class Translation { - public String Name; - public String ISO; - public String Version; - public String Author; - private String fileName; - private String filePath; - - private Dictionary dictText = new Dictionary(); - private Dictionary dictTooltip = new Dictionary(); - - private static List blackList = new List - { - "labelConfigVersion", - "labelAuthorName", - "labelTranslationAuthor", - "groupBoxWIP", - "labelNewVersion", - "labelModsDeploy", - "labelGameEdition" - }; + public string Name; + public string ISO; + public string Version; + public string Author; + private string fileName; + private string filePath; + + /// + /// Add event handler to reload UI elements after the program has been translated to another language. + /// + public static event TranslationEventHandler LanguageChanged; + + /// + /// Add control elements to this list if you want them to not be translated. + /// + public static List BlackList = new List{}; + + private Dictionary dictText = new Dictionary(); + private Dictionary dictTooltip = new Dictionary(); + + /// + /// Names of controls to ignore when setting tooltips + /// + private List ignoreTooltipsOfTheseControls = new List(); public Translation() { @@ -161,10 +202,10 @@ public Translation() * Public stuff: */ - public void Load(String fileName) + public void Load(string fileName) { this.fileName = fileName; - this.filePath = Path.Combine(Localization.languageFolder, this.fileName); + this.filePath = Path.Combine(Localization.LanguageFolder, this.fileName); /* * Read *.xml file: @@ -206,54 +247,88 @@ public bool IsOutdated() public void Apply() { - // Read *.xml file: - XDocument xmlDoc = XDocument.Load(this.filePath); - XElement xmlRoot = xmlDoc.Element("Language"); + try + { + // Read *.xml file: + XDocument xmlDoc = XDocument.Load(this.filePath); + XElement xmlRoot = xmlDoc.Element("Language"); - foreach (LocalizedForm form in Localization.LocalizedForms) + ignoreTooltipsOfTheseControls = LinkedTweaks.GetListOfLinkedControlNames(); + + // Translate each form individually: + foreach (LocalizedForm form in Localization.LocalizedForms) + { + XElement xmlForm = xmlRoot.Element(form.Form.Name); + + // Ignore non-existing forms + if (xmlForm == null) + continue; // throw new InvalidXmlException($"Couldn't find <{form.Form.Name}>"); + + // Set title, if it exists: + if (xmlForm.Attribute("title") != null) + form.Form.Text = xmlForm.Attribute("title").Value; + + // Forms: + DeserializeDictionaries(xmlForm); // TODO: xmlRoot replaced with xmlForm. Good idea? + DeserializeControls(xmlForm, form.Form, form.ToolTip); + foreach (Control subControl in form.SpecialControls) + DeserializeControl(xmlForm, subControl, form.ToolTip); + + // Message boxes: + XElement xmlMsgBox = xmlRoot.Element("Messageboxes"); + if (xmlMsgBox != null) + MsgBox.Deserialize(xmlMsgBox); + + // Strings: + XElement xmlStrings = xmlRoot.Element("Strings"); + if (xmlStrings != null) + Localization.DeserializeStrings(xmlStrings); + + // TODO: Generalize this. No outside references, plz: + + // TODO: Doesn't make sense to deserialize them multiple times: + + // Drop downs: + XElement xmlDropDowns = xmlRoot.Element("Dropdowns"); + if (xmlDropDowns != null) + DropDown.DeserializeAll(xmlDropDowns); + + // Tweak descriptions: + XElement xmlTweakDescriptions = xmlRoot.Element("TweakDescriptions"); + if (xmlTweakDescriptions != null) + LinkedTweaks.DeserializeTweakDescriptionList(xmlTweakDescriptions); + if (form.ToolTip != null) + LinkedTweaks.SetToolTips(); // TODO: No need to call it per form anymore + } + + // Call event handler: + if (LanguageChanged != null) + { + TranslationEventArgs e = new TranslationEventArgs(); + e.HasAuthor = this.Author != ""; + //e.ActiveTranslation = this; + LanguageChanged(this, e); + } + } + catch (Exception exc) { - XElement xmlForm = xmlRoot.Element(form.Form.Name); - if (xmlForm == null) - throw new InvalidXmlException($"Couldn't find <{form.Form.Name}>"); - - // Set title, if it exists: - if (xmlForm.Attribute("title") != null) - form.Form.Text = xmlForm.Attribute("title").Value; - - // Forms: - DeserializeDictionaries(xmlRoot); - DeserializeControls(xmlForm, form.Form, form.ToolTip); - foreach (Control subControl in form.SpecialControls) - DeserializeControl(xmlForm, subControl, form.ToolTip); - - // Message boxes: - XElement xmlMsgBox = xmlRoot.Element("Messageboxes"); - if (xmlMsgBox != null) - MsgBox.Deserialize(xmlMsgBox); - - // Strings: - XElement xmlStrings = xmlRoot.Element("Strings"); - if (xmlStrings != null) - Localization.DeserializeStrings(xmlStrings); - - // Drop downs: - XElement xmlDropDowns = xmlRoot.Element("Dropdowns"); - if (xmlDropDowns != null) - DropDown.DeserializeAll(xmlDropDowns); + MsgBox.Show("Loading translation failed", $"The translation '{Path.GetFileNameWithoutExtension(filePath)}' couldn't be loaded.\n{exc.GetType()}: {exc.Message}", MessageBoxIcon.Error); } } private void DeserializeControl(XElement xmlRoot, Control subControl, ToolTip toolTip) { if (subControl.Name != null && - subControl.Name.Length > 0) + subControl.Name.Length > 0 && + !BlackList.Contains(subControl.Name)) { // Set text: if (dictText.ContainsKey(subControl.Name)) subControl.Text = FromSafeString(dictText[subControl.Name]); // Set tooltip: - if (dictTooltip.ContainsKey(subControl.Name)) + if (dictTooltip.ContainsKey(subControl.Name) && + !ignoreTooltipsOfTheseControls.Contains(subControl.Name)) toolTip.SetToolTip(subControl, dictTooltip[subControl.Name]); @@ -291,7 +366,7 @@ private void DeserializeControls(XElement xmlRoot, Control control, ToolTip tool } } - private void DeserializeStrip(Component item, Dictionary dict) + private void DeserializeStrip(Component item, Dictionary dict) { if (item is MenuStrip) DeserializeStripItems(((MenuStrip)item).Items, dict); @@ -305,7 +380,7 @@ private void DeserializeStrip(Component item, Dictionary dict) DeserializeStripItems(((ToolStripDropDownButton)item).DropDownItems, dict); } - private void DeserializeStripItems(ToolStripItemCollection items, Dictionary dict) + private void DeserializeStripItems(ToolStripItemCollection items, Dictionary dict) { foreach (ToolStripItem item in items) { @@ -369,10 +444,10 @@ private void DeserializeDictionaries(XElement xmlRoot) * Serialization: */ - public void Save(String fileName, String version) + public void Save(string fileName, string version) { - String newFileName = fileName; - String newFilePath = Path.Combine(Localization.languageFolder, newFileName); + string newFileName = fileName; + string newFilePath = Path.Combine(Localization.LanguageFolder, newFileName); // Create document and root: XDocument xmlDoc = new XDocument(); @@ -381,20 +456,51 @@ public void Save(String fileName, String version) xmlRoot.Add(new XAttribute("iso", this.ISO)); if (this.ISO != "en-US" && this.Author.Length > 0) xmlRoot.Add(new XAttribute("author", this.Author)); + if (this.ISO == "en-US") - xmlDoc.AddFirst(new XComment("\n This file is auto-generated on program start.\n Therefore any changes made to this file will be overriden.\n You can use this as a template for your own translation, though.\n")); + xmlDoc.AddFirst( + new XComment("\n" + + " This file is auto-generated on program start.\n" + + " Therefore any changes made to this file will be overwritten.\n" + + " You can use this as a template for your own translation, though.\n" + + "\n" + + " If you need help with translating, you can find a guide here:\n" + + " https://github.com/FelisDiligens/Fallout76-QuickConfiguration/wiki/Translations\n")); + else + xmlDoc.AddFirst( + new XComment("\n" + + " This is a template that contains some of the already translated elements.\n" + + " You can rename it from \"*.template.xml\" to \"*.xml\" and translate the added elements.\n" + + "\n" + + " If you need help with translating, you can find a guide here:\n" + + " https://github.com/FelisDiligens/Fallout76-QuickConfiguration/wiki/Translations\n")); + xmlRoot.Add(new XAttribute("version", version)); xmlDoc.Add(xmlRoot); // Serialize external stuff: - xmlRoot.Add(Localization.SerializeStrings()); - xmlRoot.Add(DropDown.SerializeAll()); - xmlRoot.Add(MsgBox.SerializeAll()); + // TODO: Find a way to remove the references, plz: + XElement xmlStrings = Localization.SerializeStrings(); + XElement xmlDropDowns = DropDown.SerializeAll(); + XElement xmlMsgBoxes = MsgBox.SerializeAll(); + XElement xmlDescriptions = LinkedTweaks.SerializeTweakDescriptionList(); + string separator = "".PadLeft(150, '*'); + xmlStrings.AddFirst(new XComment($"\n Strings\n {separator}\n Basically little text snippets that can be used everywhere.\n ")); + xmlDropDowns.AddFirst(new XComment($"\n Dropdowns\n {separator}\n Make sure that the amount of options stays the same.\n ")); + xmlMsgBoxes.AddFirst(new XComment($"\n Message boxes\n {separator}\n The {"{0}"} is a placeholder, btw.\n ")); + xmlDescriptions.AddFirst(new XComment($"\n Descriptions\n {separator}\n These are the descriptions of almost all tweaks.\n They appear in tool tips, when the user hovers over a tweak with the mouse cursor.\n ")); + xmlRoot.Add(xmlStrings); + xmlRoot.Add(xmlDropDowns); + xmlRoot.Add(xmlMsgBoxes); + xmlRoot.Add(xmlDescriptions); + + ignoreTooltipsOfTheseControls = LinkedTweaks.GetListOfLinkedControlNames(); // Serialize all control elements: foreach (LocalizedForm form in Localization.LocalizedForms) { XElement xmlForm = new XElement(form.Form.Name, new XAttribute("title", form.Form.Text)); + xmlForm.AddFirst(new XComment($"\n {form.Form.Name}\n {separator}\n {form.Form.Text}\n ")); SerializeControls(xmlForm, form.Form, form.ToolTip); foreach (Control control in form.SpecialControls) SerializeControl(xmlForm, control, form.ToolTip); @@ -402,9 +508,7 @@ public void Save(String fileName, String version) } // Save it: - if (!Directory.Exists(Localization.languageFolder)) - Directory.CreateDirectory(Localization.languageFolder); - + Directory.CreateDirectory(Localization.LanguageFolder); xmlDoc.Save(newFilePath); } @@ -413,12 +517,20 @@ private int SerializeControl(XElement xmlElement, Control subControl, ToolTip to int count = 0; if (subControl.Name != null && subControl.Name.Length > 0 && - !blackList.Contains(subControl.Name) && + !BlackList.Contains(subControl.Name) && !subControl.Name.ToLower().Contains("separator")) { XElement subElement = new XElement(subControl.GetType().Name); bool addSubElement = false; + // Add (hopefully) helpful comment? + if (subControl is TabPage) + subElement.Add(new XComment($" ********** Tab \"{subControl.Text}\" ********** ")); + else if (subControl is GroupBox) + subElement.Add(new XComment($" Group \"{subControl.Text}\" ")); + else if (subControl is MenuStrip) + subElement.Add(new XComment($" Menu ")); + // Add text: if (subControl.Text != null && subControl.Text.Length > 0 && @@ -439,8 +551,10 @@ private int SerializeControl(XElement xmlElement, Control subControl, ToolTip to } // Add tooltip text: - if (toolTip.GetToolTip(subControl) != null && - toolTip.GetToolTip(subControl).Length > 0) + if (toolTip != null && + toolTip.GetToolTip(subControl) != null && + toolTip.GetToolTip(subControl).Length > 0 && + !ignoreTooltipsOfTheseControls.Contains(subControl.Name)) { subElement.Add(new XElement("Tooltip", toolTip.GetToolTip(subControl))); addSubElement = true; @@ -514,7 +628,7 @@ private int SerializeStripItems(XElement parent, Component stripItem) XElement xmlToolStripItem = new XElement(item.GetType().Name, new XAttribute("text", item.Text), new XAttribute("id", item.Name)); - + count += SerializeStripItems(xmlToolStripItem, item); count++; parent.Add(xmlToolStripItem); @@ -528,19 +642,19 @@ private int SerializeStripItems(XElement parent, Component stripItem) * Other stuff: */ - private String ToSafeString(String s) + private string ToSafeString(string s) { return Regex.Replace(s, @"\r\n?|\n", "\\n").Replace("\t", "\\t").Replace("\\", "\\\\").Replace("\\\\n", "\\n").Replace("\\\\t", "\\t"); } - private String FromSafeString(String s) + private string FromSafeString(string s) { return s.Replace("\\n", "\n").Replace("\\t", "\t").Replace("\\\\", "\\"); } - private Dictionary GetXMLDescendantsDict(XElement xmlItems) + private Dictionary GetXMLDescendantsDict(XElement xmlItems) { - Dictionary dict = new Dictionary(); + Dictionary dict = new Dictionary(); foreach (XElement item in xmlItems.Descendants()) { dict[item.Attribute("id").Value] = item.Attribute("text").Value; @@ -559,6 +673,14 @@ where typeof(Component).IsAssignableFrom(field.FieldType) } } + public delegate void TranslationEventHandler(object sender, TranslationEventArgs e); + + public class TranslationEventArgs : EventArgs + { + //public Translation ActiveTranslation; + public bool HasAuthor; + } + public class LocalizedForm { public Form Form; diff --git a/Fo76ini/Interface/UILoader.cs b/Fo76ini/Interface/UILoader.cs deleted file mode 100644 index 2b7e096..0000000 --- a/Fo76ini/Interface/UILoader.cs +++ /dev/null @@ -1,234 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows.Forms; - -namespace Fo76ini -{ - public class UILoader - { - public delegate void OnLoadUIFunction(); - private List OnLoadUI = new List(); - - public void Update() - { - List exceptions = new List(); - foreach (OnLoadUIFunction func in OnLoadUI) - { - try - { - func(); - } - catch (Exception ex) - { - exceptions.Add(ex); - } - } - if (exceptions.Count > 0) - MsgBox.Get("onLoadFuncException").FormatText(exceptions.Count.ToString(), exceptions[0].ToString()).Show(MessageBoxIcon.Error); - } - - public void Add(OnLoadUIFunction func) - { - OnLoadUI.Add(func); - } - - - /* - ************************************************************** - * Link control elements together - ************************************************************** - */ - - // Link slider to num and vice-versa - - public static void LinkSlider(TrackBar slider, NumericUpDown num, double numToSliderRatio) - { - LinkSlider(slider, num, numToSliderRatio, false); - } - - public static void LinkSlider(TrackBar slider, NumericUpDown num, double numToSliderRatio, bool reversed) - { - if (!reversed) - { - slider.ValueChanged += (object sender, EventArgs e) => num.Value = Convert.ToDecimal(slider.Value / numToSliderRatio); - num.ValueChanged += (object sender, EventArgs e) => slider.Value = Utils.Clamp(Convert.ToInt32(Convert.ToDouble(num.Value) * numToSliderRatio), slider.Minimum, slider.Maximum); - } - else - { - slider.ValueChanged += (object sender, EventArgs e) => num.Value = Convert.ToDecimal((slider.Maximum - slider.Value) / numToSliderRatio); - num.ValueChanged += (object sender, EventArgs e) => slider.Value = Utils.Clamp(Convert.ToInt32(slider.Maximum - Convert.ToDouble(num.Value) * numToSliderRatio), slider.Minimum, slider.Maximum); - } - } - - - - /* - ************************************************************** - * Link *.ini states to control elements - ************************************************************** - */ - - // comboBox.SelectedIndexChanged => comboBox.SelectionChangeCommitted - // checkBox.CheckedChanged => checkBox.MouseClick - // radioButton.CheckedChanged => radioButton.MouseClick - - public void LinkCustom(CheckBox checkBox, Func getState, Action setState) - { - this.Add(() => checkBox.Checked = getState()); - checkBox.MouseClick += (object sender, MouseEventArgs e) => setState(checkBox.Checked); - } - - public void LinkCustom(ComboBox comboBox, Func getState, Action setState) - { - this.Add(() => comboBox.SelectedIndex = getState()); - comboBox.SelectionChangeCommitted += (object sender, EventArgs e) => setState(comboBox.SelectedIndex); - } - - public void LinkCustom(NumericUpDown num, Func getState, Action setState) - { - this.Add(() => num.Value = Utils.Clamp(getState(), Convert.ToInt32(num.Minimum), Convert.ToInt32(num.Maximum))); - num.ValueChanged += (object sender, EventArgs e) => setState(Convert.ToInt32(num.Value)); - } - - public void LinkCustom(NumericUpDown num, Func getState, Action setState) - { - this.Add(() => num.Value = Convert.ToDecimal(Utils.Clamp(getState(), Convert.ToSingle(num.Minimum), Convert.ToSingle(num.Maximum)))); - num.ValueChanged += (object sender, EventArgs e) => setState(Convert.ToSingle(num.Value)); - } - - public void LinkBoolNegated(CheckBox checkBox, IniFile f, String section, String key, bool defaultValue) - { - LinkBool(checkBox, f, section, key, defaultValue, true); - } - - public void LinkBool(CheckBox checkBox, IniFile f, String section, String key, bool defaultValue, bool negated = false) - { - this.Add(() => { - bool val = IniFiles.Instance.GetBool(f, section, key, defaultValue); - checkBox.Checked = negated ? !val : val; - }); - checkBox.MouseClick += (object sender, MouseEventArgs e) => { - if (f == IniFile.F76Custom && (negated ? !checkBox.Checked : checkBox.Checked) == defaultValue) - IniFiles.Instance.Remove(f, section, key); - else - IniFiles.Instance.Set(f, section, key, negated ? !checkBox.Checked : checkBox.Checked); - }; - } - - public void LinkBool(RadioButton radioButtonTrue, RadioButton radioButtonFalse, IniFile f, String section, String key, bool defaultValue) - { - this.Add(() => { - bool val = IniFiles.Instance.GetBool(f, section, key, defaultValue); - if (val) - radioButtonTrue.Checked = true; - else - radioButtonFalse.Checked = true; - }); - radioButtonTrue.MouseClick += (object sender, MouseEventArgs e) => { - if (radioButtonTrue.Checked) - IniFiles.Instance.Set(f, section, key, true); - }; - radioButtonFalse.MouseClick += (object sender, MouseEventArgs e) => { - if (radioButtonFalse.Checked) - IniFiles.Instance.Set(f, section, key, false); - }; - } - - public void LinkInt(NumericUpDown num, IniFile f, String section, String key, int defaultValue) - { - this.Add(() => { - num.Value = Utils.Clamp(IniFiles.Instance.GetInt(f, section, key, defaultValue), Convert.ToInt32(num.Minimum), Convert.ToInt32(num.Maximum)); - }); - num.ValueChanged += (object sender, EventArgs e) => { - if (f == IniFile.F76Custom && num.Value == defaultValue) - IniFiles.Instance.Remove(f, section, key); - else - IniFiles.Instance.Set(f, section, key, Convert.ToInt32(num.Value)); - }; - } - - public void LinkInt(TrackBar slider, IniFile f, String section, String key, int defaultValue) - { - this.Add(() => { - slider.Value = Utils.Clamp(IniFiles.Instance.GetInt(f, section, key, defaultValue), Convert.ToInt32(slider.Minimum), Convert.ToInt32(slider.Maximum)); - }); - slider.ValueChanged += (object sender, EventArgs e) => { - if (f == IniFile.F76Custom && slider.Value == defaultValue) - IniFiles.Instance.Remove(f, section, key); - else - IniFiles.Instance.Set(f, section, key, Convert.ToInt32(slider.Value)); - }; - } - - public void LinkFloat(NumericUpDown num, IniFile f, String section, String key, float defaultValue) - { - this.Add(() => { - num.Value = Convert.ToDecimal(Utils.Clamp(IniFiles.Instance.GetFloat(f, section, key, defaultValue), Convert.ToSingle(num.Minimum), Convert.ToSingle(num.Maximum))); - }); - num.ValueChanged += (object sender, EventArgs e) => { - if (f == IniFile.F76Custom && Convert.ToSingle(num.Value) == defaultValue) - IniFiles.Instance.Remove(f, section, key); - else - IniFiles.Instance.Set(f, section, key, Convert.ToSingle(num.Value)); - }; - } - - public void LinkString(TextBox textBox, IniFile f, String section, String key, String defaultValue) - { - this.Add(() => textBox.Text = IniFiles.Instance.GetString(section, key, defaultValue)); - textBox.TextChanged += (object sender, EventArgs e) => { - if (f == IniFile.F76Custom && textBox.Text == defaultValue) - IniFiles.Instance.Remove(f, section, key); - else - IniFiles.Instance.Set(f, section, key, textBox.Text); - }; - } - - public void LinkList(RadioButton[] radioButtons, String[] associatedValues, IniFile f, String section, String key, String defaultValue) - { - if (radioButtons.Length != associatedValues.Length) - throw new ArgumentException("LinkList: radioButtons and associatedValues have to have the same length!"); - - this.Add(() => { - String value = IniFiles.Instance.GetString(f, section, key, defaultValue); - int index = Array.IndexOf(associatedValues, value); - if (index > -1) - { - radioButtons[index].Checked = true; - } - }); - - // I have a really bad feeling about this: - for (int i = 0; i < radioButtons.Length; i++) - { - RadioButton radioButton = radioButtons[i]; - String associatedValue = associatedValues[i]; - radioButton.MouseClick += (object sender, MouseEventArgs e) => { - if (radioButton.Checked) - IniFiles.Instance.Set(f, section, key, associatedValue); - }; - } - } - - public void LinkList(ComboBox comboBox, String[] associatedValues, IniFile f, String section, String key, String defaultValue, int defaultComboBoxIndex) - { - if (comboBox.Items.Count != associatedValues.Length) - throw new ArgumentException("LinkList: comboBox has to have as many items as associatedValues has!"); - - this.Add(() => { - String value = IniFiles.Instance.GetString(f, section, key, defaultValue); - int index = Array.IndexOf(associatedValues, value); - if (index > -1) - comboBox.SelectedIndex = index; - else - comboBox.SelectedIndex = defaultComboBoxIndex; - }); - comboBox.SelectionChangeCommitted += (object sender, EventArgs e) => { - IniFiles.Instance.Set(f, section, key, associatedValues[comboBox.SelectedIndex]); - }; - } - } -} diff --git a/Fo76ini/Interface/Versioning.cs b/Fo76ini/Interface/Versioning.cs new file mode 100644 index 0000000..7b53dc5 --- /dev/null +++ b/Fo76ini/Interface/Versioning.cs @@ -0,0 +1,37 @@ +using Fo76ini.Utilities; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Text; +using System.Threading.Tasks; + +namespace Fo76ini.Interface +{ + public static class Versioning + { + public static void GetLatestVersion () + { + try + { + WebClient wc = new WebClient(); + byte[] raw = wc.DownloadData("https://raw.githubusercontent.com/FelisDiligens/Fallout76-QuickConfiguration/master/VERSION"); + Shared.LatestVersion = Encoding.UTF8.GetString(raw).Trim(); + } + catch (WebException exc) + { + return; + } + } + + public static bool UpdateAvailable + { + get { return Shared.LatestVersion != null && Utils.CompareVersions(Shared.LatestVersion, Shared.VERSION) > 0; } + } + + /*public static bool PrereleaseUsed + { + get { return Shared.LatestVersion != null && Utils.CompareVersions(Shared.LatestVersion, Shared.VERSION) < 0; } + }*/ + } +} diff --git a/Fo76ini/IniFiles.cs b/Fo76ini/LegacyIniFiles.cs similarity index 64% rename from Fo76ini/IniFiles.cs rename to Fo76ini/LegacyIniFiles.cs index 0a3359a..44f529e 100644 --- a/Fo76ini/IniFiles.cs +++ b/Fo76ini/LegacyIniFiles.cs @@ -14,7 +14,7 @@ namespace Fo76ini { - public enum IniFile + public enum LegacyIniFile { F76, F76Prefs, @@ -22,7 +22,7 @@ public enum IniFile Config } - public class IniFiles + public class LegacyIniFiles { protected FileIniDataParser iniParser = null; @@ -34,7 +34,7 @@ public class IniFiles /*protected String fo76Path; protected String fo76PrefsPath; protected String fo76CustomPath;*/ - protected String configPath; + protected string configPath; protected DateTime fo76ModTime; protected DateTime fo76PrefsModTime; @@ -42,22 +42,22 @@ public class IniFiles protected Encoding iniEncoding = new UTF8Encoding(false); // UTF-8 without BOM - public String iniParentPath; + public string iniParentPath; protected System.Globalization.CultureInfo enUS = System.Globalization.CultureInfo.CreateSpecificCulture("en-US"); //public bool nuclearWinterMode = false; public bool renameF76Custom = false; - public const String nwF76CustomEnding = ".nwmodebak"; + public const string nwF76CustomEnding = ".nwmodebak"; public bool fixCustomIniDuplicateValues = true; //public GameEdition GameEdition; - private static IniFiles instance = null; + private static LegacyIniFiles instance = null; private static readonly object padlock = new object(); - public static IniFiles Instance + public static LegacyIniFiles Instance { get { @@ -65,77 +65,76 @@ public static IniFiles Instance { if (instance == null) { - instance = new IniFiles(); + instance = new LegacyIniFiles(); } return instance; } } } - public String GetIniName(IniFile iniFile, GameEdition edition = GameEdition.Unknown) + public string GetIniName(LegacyIniFile iniFile, GameEdition edition = GameEdition.Unknown) { if (edition == GameEdition.Unknown) edition = Shared.GameEdition; bool msstore = edition == GameEdition.MSStore; switch (iniFile) { - case IniFile.F76: + case LegacyIniFile.F76: return msstore ? "Project76.ini" : "Fallout76.ini"; - case IniFile.F76Prefs: + case LegacyIniFile.F76Prefs: return msstore ? "Project76Prefs.ini" : "Fallout76Prefs.ini"; - case IniFile.F76Custom: + case LegacyIniFile.F76Custom: return msstore ? "Project76Custom.ini" : "Fallout76Custom.ini"; - case IniFile.Config: - return "QuickConfiguration.ini"; + default: + throw new NotSupportedException("Ini name unknown"); } - return null; } - public String GetIniPath(IniFile iniFile, GameEdition edition) + public string GetIniPath(LegacyIniFile iniFile, GameEdition edition) { switch (iniFile) { - case IniFile.F76: - case IniFile.F76Prefs: - case IniFile.F76Custom: + case LegacyIniFile.F76: + case LegacyIniFile.F76Prefs: + case LegacyIniFile.F76Custom: return Path.Combine(this.iniParentPath, GetIniName(iniFile, edition)); - case IniFile.Config: + case LegacyIniFile.Config: return this.configPath; } return null; } - public String GetIniPath(IniFile iniFile) + public string GetIniPath(LegacyIniFile iniFile) { switch (iniFile) { - case IniFile.F76: - case IniFile.F76Prefs: - case IniFile.F76Custom: + case LegacyIniFile.F76: + case LegacyIniFile.F76Prefs: + case LegacyIniFile.F76Custom: return Path.Combine(this.iniParentPath, GetIniName(iniFile)); - case IniFile.Config: + case LegacyIniFile.Config: return this.configPath; } return null; } - protected IniData GetIniData(IniFile iniFile) + protected IniData GetIniData(LegacyIniFile iniFile) { switch (iniFile) { - case IniFile.F76: + case LegacyIniFile.F76: return this.fo76Data; - case IniFile.F76Prefs: + case LegacyIniFile.F76Prefs: return this.fo76PrefsData; - case IniFile.F76Custom: + case LegacyIniFile.F76Custom: return this.fo76CustomData; - case IniFile.Config: + case LegacyIniFile.Config: return this.configData; } return null; } - private IniFiles() + private LegacyIniFiles() { // Get the paths: this.iniParentPath = Path.Combine( @@ -143,31 +142,8 @@ private IniFiles() @"My Games\Fallout 76\" ); - /*this.GetIniName(IniFile.F76) = Path.Combine(this.iniParentPath, "Fallout76.ini"); - this.GetIniName(IniFile.F76Prefs) = Path.Combine(this.iniParentPath, "Fallout76Prefs.ini"); - this.GetIniName(IniFile.F76Custom) = Path.Combine(this.iniParentPath, "Fallout76Custom.ini");*/ - String pre1point6ConfigPath = Path.Combine(this.iniParentPath, "QuickConfiguration.ini"); - String oldConfigPath = Path.Combine(Shared.OldAppConfigFolder, "config.ini"); this.configPath = Path.Combine(Shared.AppConfigFolder, "config.ini"); - // Backwards-compatibility: Move config file to new location: - - // Pre v1.6 location: - if (File.Exists(pre1point6ConfigPath) && !File.Exists(this.configPath)) - { - if (!Directory.Exists(Path.GetDirectoryName(this.configPath))) - Directory.CreateDirectory(Path.GetDirectoryName(this.configPath)); - File.Move(pre1point6ConfigPath, this.configPath); - } - - // Pre v1.7.1 location: - if (File.Exists(oldConfigPath) && !File.Exists(this.configPath)) - { - if (!Directory.Exists(Path.GetDirectoryName(this.configPath))) - Directory.CreateDirectory(Path.GetDirectoryName(this.configPath)); - File.Copy(oldConfigPath, this.configPath); - } - // Configuring INI parser IniParserConfiguration iniParserConfig = new IniParserConfiguration(); iniParserConfig.AllowCreateSectionsOnFly = true; @@ -190,25 +166,25 @@ public void LoadGameInis() // Parse all INI files, if existing: // Do Fallout76.ini and Fallout76Prefs.ini exist? - if (!File.Exists(GetIniPath(IniFile.F76)) || !File.Exists(GetIniPath(IniFile.F76Prefs))) + if (!File.Exists(GetIniPath(LegacyIniFile.F76)) || !File.Exists(GetIniPath(LegacyIniFile.F76Prefs))) { if (Shared.GameEdition == GameEdition.MSStore) { // Do Fallout76.ini and Fallout76Prefs.ini exist? - if (File.Exists(GetIniPath(IniFile.F76, GameEdition.Steam)) && File.Exists(GetIniPath(IniFile.F76Prefs, GameEdition.Steam))) + if (File.Exists(GetIniPath(LegacyIniFile.F76, GameEdition.Steam)) && File.Exists(GetIniPath(LegacyIniFile.F76Prefs, GameEdition.Steam))) //Shared.ChangeGameEdition(GameEdition.Steam); Shared.GameEdition = GameEdition.Steam; else - throw new FileNotFoundException($"{GetIniName(IniFile.F76)} and {GetIniName(IniFile.F76Prefs)} not found"); + throw new FileNotFoundException($"{GetIniName(LegacyIniFile.F76)} and {GetIniName(LegacyIniFile.F76Prefs)} not found"); } else { // Do Project76.ini and Project76Prefs.ini exist? - if (File.Exists(GetIniPath(IniFile.F76, GameEdition.MSStore)) && File.Exists(GetIniPath(IniFile.F76Prefs, GameEdition.MSStore))) + if (File.Exists(GetIniPath(LegacyIniFile.F76, GameEdition.MSStore)) && File.Exists(GetIniPath(LegacyIniFile.F76Prefs, GameEdition.MSStore))) //Shared.ChangeGameEdition(GameEdition.MSStore); Shared.GameEdition = GameEdition.MSStore; else - throw new FileNotFoundException($"{GetIniName(IniFile.F76)} and {GetIniName(IniFile.F76Prefs)} not found"); + throw new FileNotFoundException($"{GetIniName(LegacyIniFile.F76)} and {GetIniName(LegacyIniFile.F76Prefs)} not found"); } } @@ -217,14 +193,14 @@ public void LoadGameInis() File.CreateText(this.GetIniPath(IniFile.F76Custom)).Close();*/ // Parse *.ini files: - this.fo76Data = LoadIni(GetIniPath(IniFile.F76), false); - this.fo76ModTime = File.GetLastWriteTime(GetIniPath(IniFile.F76)); - this.fo76PrefsData = LoadIni(GetIniPath(IniFile.F76Prefs), false); - this.fo76PrefsModTime = File.GetLastWriteTime(GetIniPath(IniFile.F76Prefs)); - if (File.Exists(GetIniPath(IniFile.F76Custom))) - this.fo76CustomData = LoadIni(GetIniPath(IniFile.F76Custom), false); - else if (File.Exists(GetIniPath(IniFile.F76Custom) + ".nwmodebak")) - this.fo76CustomData = LoadIni(GetIniPath(IniFile.F76Custom) + ".nwmodebak", false); + this.fo76Data = LoadIni(GetIniPath(LegacyIniFile.F76), false); + this.fo76ModTime = File.GetLastWriteTime(GetIniPath(LegacyIniFile.F76)); + this.fo76PrefsData = LoadIni(GetIniPath(LegacyIniFile.F76Prefs), false); + this.fo76PrefsModTime = File.GetLastWriteTime(GetIniPath(LegacyIniFile.F76Prefs)); + if (File.Exists(GetIniPath(LegacyIniFile.F76Custom))) + this.fo76CustomData = LoadIni(GetIniPath(LegacyIniFile.F76Custom), false); + else if (File.Exists(GetIniPath(LegacyIniFile.F76Custom) + ".nwmodebak")) + this.fo76CustomData = LoadIni(GetIniPath(LegacyIniFile.F76Custom) + ".nwmodebak", false); else this.fo76CustomData = new IniData(); @@ -248,19 +224,19 @@ public void ChangeGameEdition(GameEdition edition) //this.GameEdition = edition; /*if (reloadRequired) LoadGameInis();*/ - IniFiles.Instance.Set(IniFile.Config, "Preferences", "uGameEdition", (int)edition); + LegacyIniFiles.Instance.Set(LegacyIniFile.Config, "Preferences", "uGameEdition", (int)edition); UpdateLastModifiedDates(); } public void SaveGameInis(bool readOnly = false) { - SaveIni(this.GetIniPath(IniFile.F76), this.fo76Data, readOnly); - SaveIni(this.GetIniPath(IniFile.F76Prefs), this.fo76PrefsData, readOnly); + SaveIni(this.GetIniPath(LegacyIniFile.F76), this.fo76Data, readOnly); + SaveIni(this.GetIniPath(LegacyIniFile.F76Prefs), this.fo76PrefsData, readOnly); if (this.renameF76Custom) - SaveIni(this.GetIniPath(IniFile.F76Custom) + nwF76CustomEnding, this.fo76CustomData, readOnly); + SaveIni(this.GetIniPath(LegacyIniFile.F76Custom) + nwF76CustomEnding, this.fo76CustomData, readOnly); else - SaveIni(this.GetIniPath(IniFile.F76Custom), this.fo76CustomData, readOnly); + SaveIni(this.GetIniPath(LegacyIniFile.F76Custom), this.fo76CustomData, readOnly); UpdateLastModifiedDates(); } @@ -271,45 +247,45 @@ public void ResolveNWMode() { foreach (GameEdition edition in Enum.GetValues(typeof(GameEdition))) { - if (!File.Exists(this.GetIniPath(IniFile.F76Custom, edition))) + if (!File.Exists(this.GetIniPath(LegacyIniFile.F76Custom, edition))) return; - if (!File.Exists(this.GetIniPath(IniFile.F76Custom, edition) + nwF76CustomEnding)) - File.Copy(this.GetIniPath(IniFile.F76Custom, edition), this.GetIniPath(IniFile.F76Custom, edition) + nwF76CustomEnding); - Utils.DeleteFile(this.GetIniPath(IniFile.F76Custom, edition)); + if (!File.Exists(this.GetIniPath(LegacyIniFile.F76Custom, edition) + nwF76CustomEnding)) + File.Copy(this.GetIniPath(LegacyIniFile.F76Custom, edition), this.GetIniPath(LegacyIniFile.F76Custom, edition) + nwF76CustomEnding); + Utils.DeleteFile(this.GetIniPath(LegacyIniFile.F76Custom, edition)); } } else { foreach (GameEdition edition in Enum.GetValues(typeof(GameEdition))) { - if (!File.Exists(this.GetIniPath(IniFile.F76Custom, edition) + nwF76CustomEnding)) + if (!File.Exists(this.GetIniPath(LegacyIniFile.F76Custom, edition) + nwF76CustomEnding)) return; - if (!File.Exists(this.GetIniPath(IniFile.F76Custom, edition))) - File.Copy(this.GetIniPath(IniFile.F76Custom, edition) + nwF76CustomEnding, this.GetIniPath(IniFile.F76Custom, edition)); - Utils.DeleteFile(this.GetIniPath(IniFile.F76Custom, edition) + nwF76CustomEnding); + if (!File.Exists(this.GetIniPath(LegacyIniFile.F76Custom, edition))) + File.Copy(this.GetIniPath(LegacyIniFile.F76Custom, edition) + nwF76CustomEnding, this.GetIniPath(LegacyIniFile.F76Custom, edition)); + Utils.DeleteFile(this.GetIniPath(LegacyIniFile.F76Custom, edition) + nwF76CustomEnding); } } UpdateLastModifiedDates(); - if (this.GetBool(IniFile.Config, "Preferences", "bDenyNTFSWritePermission", false)) + if (this.GetBool(LegacyIniFile.Config, "Preferences", "bDenyNTFSWritePermission", false)) SetNTFSWritePermission(false); } public bool FilesHaveBeenModified() { - if (this.fo76ModTime != File.GetLastWriteTime(this.GetIniPath(IniFile.F76))) + if (this.fo76ModTime != File.GetLastWriteTime(this.GetIniPath(LegacyIniFile.F76))) return true; - if (this.fo76PrefsModTime != File.GetLastWriteTime(this.GetIniPath(IniFile.F76Prefs))) + if (this.fo76PrefsModTime != File.GetLastWriteTime(this.GetIniPath(LegacyIniFile.F76Prefs))) return true; - if (File.Exists(this.GetIniPath(IniFile.F76Custom))) + if (File.Exists(this.GetIniPath(LegacyIniFile.F76Custom))) { - if (this.fo76CustomModTime != File.GetLastWriteTime(this.GetIniPath(IniFile.F76Custom))) + if (this.fo76CustomModTime != File.GetLastWriteTime(this.GetIniPath(LegacyIniFile.F76Custom))) return true; } - else if (File.Exists(this.GetIniPath(IniFile.F76Custom) + ".nwmodebak")) + else if (File.Exists(this.GetIniPath(LegacyIniFile.F76Custom) + ".nwmodebak")) { - if (this.fo76CustomModTime != File.GetLastWriteTime(this.GetIniPath(IniFile.F76Custom) + ".nwmodebak")) + if (this.fo76CustomModTime != File.GetLastWriteTime(this.GetIniPath(LegacyIniFile.F76Custom) + ".nwmodebak")) return true; } return false; @@ -317,13 +293,13 @@ public bool FilesHaveBeenModified() public void UpdateLastModifiedDates() { - this.fo76ModTime = File.GetLastWriteTime(this.GetIniPath(IniFile.F76)); - this.fo76PrefsModTime = File.GetLastWriteTime(this.GetIniPath(IniFile.F76Prefs)); + this.fo76ModTime = File.GetLastWriteTime(this.GetIniPath(LegacyIniFile.F76)); + this.fo76PrefsModTime = File.GetLastWriteTime(this.GetIniPath(LegacyIniFile.F76Prefs)); - if (File.Exists(this.GetIniPath(IniFile.F76Custom))) - this.fo76CustomModTime = File.GetLastWriteTime(this.GetIniPath(IniFile.F76Custom)); - else if (File.Exists(this.GetIniPath(IniFile.F76Custom) + ".nwmodebak")) - this.fo76CustomModTime = File.GetLastWriteTime(this.GetIniPath(IniFile.F76Custom) + ".nwmodebak"); + if (File.Exists(this.GetIniPath(LegacyIniFile.F76Custom))) + this.fo76CustomModTime = File.GetLastWriteTime(this.GetIniPath(LegacyIniFile.F76Custom)); + else if (File.Exists(this.GetIniPath(LegacyIniFile.F76Custom) + ".nwmodebak")) + this.fo76CustomModTime = File.GetLastWriteTime(this.GetIniPath(LegacyIniFile.F76Custom) + ".nwmodebak"); } public void LoadConfig() @@ -351,54 +327,54 @@ public void SaveAll(bool readOnly = false) /// /// Create a backup folder and copy all *.ini files into it. /// - public void BackupAll(String backupFolder = null) + public void BackupAll(string backupFolder = null) { if (backupFolder == null) backupFolder = DateTime.Now.ToString("Backup_yyyy-MM-dd_HH-mm-ss"); - String backupPath = Path.Combine(this.iniParentPath, backupFolder); - String tempPath; + string backupPath = Path.Combine(this.iniParentPath, backupFolder); + string tempPath; if (Directory.Exists(backupPath)) Utils.DeleteDirectory(backupPath); Directory.CreateDirectory(backupPath); - if (File.Exists(this.GetIniPath(IniFile.F76))) + if (File.Exists(this.GetIniPath(LegacyIniFile.F76))) { tempPath = Path.Combine(backupPath, "Fallout76.ini"); - File.Copy(this.GetIniPath(IniFile.F76), tempPath); + File.Copy(this.GetIniPath(LegacyIniFile.F76), tempPath); SetFileReadOnlyAttribute(tempPath, false); } - if (File.Exists(this.GetIniPath(IniFile.F76Prefs))) + if (File.Exists(this.GetIniPath(LegacyIniFile.F76Prefs))) { tempPath = Path.Combine(backupPath, "Fallout76Prefs.ini"); - File.Copy(this.GetIniPath(IniFile.F76Prefs), tempPath); + File.Copy(this.GetIniPath(LegacyIniFile.F76Prefs), tempPath); SetFileReadOnlyAttribute(tempPath, false); } - if (File.Exists(this.GetIniPath(IniFile.F76Custom))) + if (File.Exists(this.GetIniPath(LegacyIniFile.F76Custom))) { tempPath = Path.Combine(backupPath, "Fallout76Custom.ini"); - File.Copy(this.GetIniPath(IniFile.F76Custom), tempPath); + File.Copy(this.GetIniPath(LegacyIniFile.F76Custom), tempPath); SetFileReadOnlyAttribute(tempPath, false); } - if (File.Exists(this.GetIniPath(IniFile.F76Custom) + ".nwmodebak")) + if (File.Exists(this.GetIniPath(LegacyIniFile.F76Custom) + ".nwmodebak")) { tempPath = Path.Combine(backupPath, "Fallout76Custom.ini.nwmodebak"); - File.Copy(this.GetIniPath(IniFile.F76Custom) + ".nwmodebak", tempPath); + File.Copy(this.GetIniPath(LegacyIniFile.F76Custom) + ".nwmodebak", tempPath); SetFileReadOnlyAttribute(tempPath, false); } } protected void RemoveEmptySections(IniData data) { - List sectionNames = new List(); + List sectionNames = new List(); foreach (SectionData section in data.Sections) if (section.Keys.Count == 0) sectionNames.Add(section.SectionName); - foreach (String sectionName in sectionNames) + foreach (string sectionName in sectionNames) data.Sections.RemoveSection(sectionName); } @@ -409,7 +385,7 @@ protected void RemoveEmptySections(IniData data) ******************************************************************************************************************************************** */ - public IniData LoadIni(String path, bool ignoreErrors) + public IniData LoadIni(string path, bool ignoreErrors) { if (!File.Exists(path)) return new IniData(); @@ -425,12 +401,12 @@ public IniData LoadIni(String path, bool ignoreErrors) } } - public IniData LoadIni(String path) + public IniData LoadIni(string path) { return LoadIni(path, true); } - public void SaveIni(String path, IniData data, bool readOnly = false) + public void SaveIni(string path, IniData data, bool readOnly = false) { if (data == null) return; @@ -446,7 +422,7 @@ public void SaveIni(String path, IniData data, bool readOnly = false) if (readOnly) SetFileReadOnlyAttribute(path, readOnly); - if (this.GetBool(IniFile.Config, "Preferences", "bDenyNTFSWritePermission", false)) + if (this.GetBool(LegacyIniFile.Config, "Preferences", "bDenyNTFSWritePermission", false)) SetNTFSWritePermission(false); } @@ -457,7 +433,7 @@ public void SaveIni(String path, IniData data, bool readOnly = false) ******************************************************************************************************************************************** */ - protected void SetFileReadOnlyAttribute(String path, bool readOnly) + protected void SetFileReadOnlyAttribute(string path, bool readOnly) { SetNTFSWritePermission(true); @@ -477,17 +453,17 @@ protected void SetFileReadOnlyAttribute(String path, bool readOnly) public void SetINIsReadOnly(bool readOnly) { - SetFileReadOnlyAttribute(this.GetIniPath(IniFile.F76), readOnly); - SetFileReadOnlyAttribute(this.GetIniPath(IniFile.F76Prefs), readOnly); - SetFileReadOnlyAttribute(this.GetIniPath(IniFile.F76Custom), readOnly); + SetFileReadOnlyAttribute(this.GetIniPath(LegacyIniFile.F76), readOnly); + SetFileReadOnlyAttribute(this.GetIniPath(LegacyIniFile.F76Prefs), readOnly); + SetFileReadOnlyAttribute(this.GetIniPath(LegacyIniFile.F76Custom), readOnly); } public bool AreINIsReadOnly() { - if (File.Exists(this.GetIniPath(IniFile.F76)) && File.Exists(this.GetIniPath(IniFile.F76Prefs))) + if (File.Exists(this.GetIniPath(LegacyIniFile.F76)) && File.Exists(this.GetIniPath(LegacyIniFile.F76Prefs))) { - FileInfo fo76fi = new FileInfo(this.GetIniPath(IniFile.F76)); - FileInfo fo76Prefsfi = new FileInfo(this.GetIniPath(IniFile.F76Prefs)); + FileInfo fo76fi = new FileInfo(this.GetIniPath(LegacyIniFile.F76)); + FileInfo fo76Prefsfi = new FileInfo(this.GetIniPath(LegacyIniFile.F76Prefs)); return fo76fi.IsReadOnly && fo76Prefsfi.IsReadOnly; } return false; @@ -535,7 +511,7 @@ public void SetNTFSWritePermission(bool writePermission) ******************************************************************************************************************************************** */ - public bool Exists(String section, String key) + public bool Exists(string section, string key) { foreach (IniData data in new IniData[] { this.configData, this.fo76Data, this.fo76PrefsData, this.fo76CustomData }) { @@ -548,7 +524,7 @@ public bool Exists(String section, String key) return false; } - public bool Exists(IniFile f, String section, String key) + public bool Exists(LegacyIniFile f, string section, string key) { return GetIniData(f)[section][key] != null; } @@ -561,9 +537,9 @@ public bool Exists(IniFile f, String section, String key) /// /// /// - public String GetString(String section, String key, String defaultValue) + public string GetString(string section, string key, string defaultValue) { - String value = defaultValue; + string value = defaultValue; foreach (IniData data in new IniData[] { this.configData, this.fo76Data, this.fo76PrefsData, this.fo76CustomData }) { if (data != null) @@ -575,9 +551,9 @@ public String GetString(String section, String key, String defaultValue) return value; } - public String GetString(String section, String key) + public string GetString(string section, string key) { - String value = GetString(section, key, null); + string value = GetString(section, key, null); if (value == null) throw new KeyNotFoundException($"Couldn't find [{section}] {key} in any *.ini file."); return value; @@ -595,9 +571,9 @@ public String GetString(String section, String key) /// /// /// - public String[] GetString(String[][] sectionKeyDefaultPairs) + public string[] GetString(string[][] sectionKeyDefaultPairs) { - String[] values = new String[sectionKeyDefaultPairs.Length]; + string[] values = new string[sectionKeyDefaultPairs.Length]; for (int i = 0; i < sectionKeyDefaultPairs.Length; i++) { if (sectionKeyDefaultPairs[i].Length > 2) @@ -612,8 +588,8 @@ public String[] GetString(String[][] sectionKeyDefaultPairs) { if (data != null) { - String section = sectionKeyDefaultPairs[i][0]; - String key = sectionKeyDefaultPairs[i][1]; + string section = sectionKeyDefaultPairs[i][0]; + string key = sectionKeyDefaultPairs[i][1]; if (data[section][key] != null) values[i] = data[section][key]; } @@ -622,101 +598,121 @@ public String[] GetString(String[][] sectionKeyDefaultPairs) return values; } - public String GetString(IniFile f, String section, String key) + public string GetString(LegacyIniFile f, string section, string key) { - String value = GetIniData(f)[section][key]; + string value = GetIniData(f)[section][key]; if (value == null) throw new KeyNotFoundException($"Couldn't find [{section}] {key} in {GetIniName(f)}"); return value; } - public String GetString(IniFile f, String section, String key, String defaultValue) + public string GetString(LegacyIniFile f, string section, string key, string defaultValue) { - String value = GetIniData(f)[section][key]; + string value = GetIniData(f)[section][key]; return value != null ? value : defaultValue; } - public bool GetBool(IniFile f, String section, String key) + public bool GetBool(LegacyIniFile f, string section, string key) { return GetString(f, section, key) == "1"; } - public bool GetBool(IniFile f, String section, String key, bool defaultValue) + public bool GetBool(LegacyIniFile f, string section, string key, bool defaultValue) { return GetString(f, section, key, defaultValue ? "1" : "0") == "1"; } - public bool GetBool(String section, String key) + public bool GetBool(string section, string key) { return GetString(section, key) == "1"; } - public bool GetBool(String section, String key, bool defaultValue) + public bool GetBool(string section, string key, bool defaultValue) { return GetString(section, key, defaultValue ? "1" : "0") == "1"; } - public float GetFloat(IniFile f, String section, String key) + public float GetFloat(LegacyIniFile f, string section, string key) { return Utils.ToFloat(GetString(f, section, key)); } - public float GetFloat(IniFile f, String section, String key, float defaultValue) + public float GetFloat(LegacyIniFile f, string section, string key, float defaultValue) { return Utils.ToFloat(GetString(f, section, key, defaultValue.ToString(enUS))); } - public float GetFloat(String section, String key) + public float GetFloat(string section, string key) { return Utils.ToFloat(GetString(section, key)); } - public float GetFloat(String section, String key, float defaultValue) + public float GetFloat(string section, string key, float defaultValue) { return Utils.ToFloat(GetString(section, key, defaultValue.ToString(enUS))); } - public uint GetUInt(IniFile f, String section, String key) + public uint GetUInt(LegacyIniFile f, string section, string key) { return Utils.ToUInt(GetString(f, section, key)); } - public uint GetUInt(IniFile f, String section, String key, uint defaultValue) + public uint GetUInt(LegacyIniFile f, string section, string key, uint defaultValue) { return Utils.ToUInt(GetString(f, section, key, defaultValue.ToString(enUS))); } - public uint GetUInt(String section, String key) + public uint GetUInt(string section, string key) { return Utils.ToUInt(GetString(section, key)); } - public uint GetUInt(String section, String key, uint defaultValue) + public uint GetUInt(string section, string key, uint defaultValue) { return Utils.ToUInt(GetString(section, key, defaultValue.ToString(enUS))); } - public int GetInt(IniFile f, String section, String key) + public int GetInt(LegacyIniFile f, string section, string key) { return Utils.ToInt(GetString(f, section, key)); } - public int GetInt(IniFile f, String section, String key, int defaultValue) + public int GetInt(LegacyIniFile f, string section, string key, int defaultValue) { return Utils.ToInt(GetString(f, section, key, defaultValue.ToString(enUS))); } - public int GetInt(String section, String key) + public int GetInt(string section, string key) { return Utils.ToInt(GetString(section, key)); } - public int GetInt(String section, String key, int defaultValue) + public int GetInt(string section, string key, int defaultValue) { return Utils.ToInt(GetString(section, key, defaultValue.ToString(enUS))); } - public void Set(IniFile f, String section, String key, String value) + public long GetLong(LegacyIniFile f, string section, string key) + { + return Utils.ToLong(GetString(f, section, key)); + } + + public long GetLong(LegacyIniFile f, string section, string key, int defaultValue) + { + return Utils.ToLong(GetString(f, section, key, defaultValue.ToString(enUS))); + } + + public long GetLong(string section, string key) + { + return Utils.ToLong(GetString(section, key)); + } + + public long GetLong(string section, string key, int defaultValue) + { + return Utils.ToLong(GetString(section, key, defaultValue.ToString(enUS))); + } + + public void Set(LegacyIniFile f, string section, string key, string value) { GetIniData(f)[section][key] = value; @@ -725,73 +721,78 @@ public void Set(IniFile f, String section, String key, String value) // then the value in Custom will overshadow Prefs, when GetString is called. // Of course people start to report that their values are reset. Who can blame them? // Soooo, we are going to set the same value in Custom if IniFile f is something else but Custom. Great? Great. - if (fixCustomIniDuplicateValues && (f == IniFile.F76 || f == IniFile.F76Prefs) && Exists(IniFile.F76Custom, section, key)) + if (fixCustomIniDuplicateValues && (f == LegacyIniFile.F76 || f == LegacyIniFile.F76Prefs) && Exists(LegacyIniFile.F76Custom, section, key)) this.fo76CustomData[section][key] = value; } - public void Set(IniFile f, String section, String key, int value) + public void Set(LegacyIniFile f, string section, string key, int value) + { + Set(f, section, key, Utils.ToString(value)); + } + + public void Set(LegacyIniFile f, string section, string key, uint value) { Set(f, section, key, Utils.ToString(value)); } - public void Set(IniFile f, String section, String key, float value) + public void Set(LegacyIniFile f, string section, string key, long value) { Set(f, section, key, Utils.ToString(value)); } - public void Set(IniFile f, String section, String key, double value) + public void Set(LegacyIniFile f, string section, string key, float value) { Set(f, section, key, Utils.ToString(value)); } - public void Set(IniFile f, String section, String key, uint value) + public void Set(LegacyIniFile f, string section, string key, double value) { Set(f, section, key, Utils.ToString(value)); } - public void Set(IniFile f, String section, String key, bool value) + public void Set(LegacyIniFile f, string section, string key, bool value) { Set(f, section, key, value ? "1" : "0"); } - public void Remove(IniFile f, String section, String key) + public void Remove(LegacyIniFile f, string section, string key) { if (Exists(f, section, key)) GetIniData(f)[section].RemoveKey(key); } - public void RemoveAll(String section, String key) + public void RemoveAll(string section, string key) { - Remove(IniFile.F76, section, key); - Remove(IniFile.F76Prefs, section, key); - Remove(IniFile.F76Custom, section, key); + Remove(LegacyIniFile.F76, section, key); + Remove(LegacyIniFile.F76Prefs, section, key); + Remove(LegacyIniFile.F76Custom, section, key); } - public bool ExpectBool(String section, String key) + public bool ExpectBool(string section, string key) { - String value = this.GetString(section, key).Trim(); + string value = this.GetString(section, key).Trim(); return value == "1" || value == "0"; } - public bool ExpectInt(String section, String key) + public bool ExpectInt(string section, string key) { - String value = this.GetString(section, key).Trim(); + string value = this.GetString(section, key).Trim(); return Regex.IsMatch(value, @"^-?\d+$"); } - public bool ExpectUInt(String section, String key) + public bool ExpectUInt(string section, string key) { - String value = this.GetString(section, key).Trim(); + string value = this.GetString(section, key).Trim(); return Regex.IsMatch(value, @"^\d+$"); } - public bool ExpectFloat(String section, String key) + public bool ExpectFloat(string section, string key) { - String value = this.GetString(section, key).Trim(); + string value = this.GetString(section, key).Trim(); return Regex.IsMatch(value, @"-?[0-9\.]+"); } @@ -803,13 +804,13 @@ public bool ExpectFloat(String section, String key) ******************************************************************************************************************************************** */ - protected void MergeLists(IniFile f, String section, String key) + protected void MergeLists(LegacyIniFile f, string section, string key) { - String list = ""; + string list = ""; bool found = false; int i = -1; - IEnumerable lines = File.ReadLines(GetIniPath(f)); - foreach (String line in lines) + IEnumerable lines = File.ReadLines(GetIniPath(f)); + foreach (string line in lines) { if (line.TrimStart().ToLower().StartsWith(key.ToLower())) { @@ -821,7 +822,7 @@ protected void MergeLists(IniFile f, String section, String key) } } } - list = String.Join(",", + list = string.Join(",", list.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries) .Select(s => s.Trim()).Distinct().ToArray() ).Trim(',').Replace(",,", ","); @@ -835,13 +836,13 @@ protected void FixDuplicateResourceLists() // Merge them. Default behaviour of the Parser is overriding and this is probably not what the user wants. // sResourceDataDirsFinal added in v.1.3.1 // Case insensitive, and whitespace around '=' ignored as of v1.4 - if (!File.Exists(GetIniPath(IniFile.F76Custom))) + if (!File.Exists(GetIniPath(LegacyIniFile.F76Custom))) return; - MergeLists(IniFile.F76Custom, "Archive", "sResourceIndexFileList"); - MergeLists(IniFile.F76Custom, "Archive", "sResourceArchive2List"); - MergeLists(IniFile.F76Custom, "Archive", "sResourceDataDirsFinal"); + MergeLists(LegacyIniFile.F76Custom, "Archive", "sResourceIndexFileList"); + MergeLists(LegacyIniFile.F76Custom, "Archive", "sResourceArchive2List"); + MergeLists(LegacyIniFile.F76Custom, "Archive", "sResourceDataDirsFinal"); - this.fo76CustomModTime = File.GetLastWriteTime(this.GetIniPath(IniFile.F76Custom)); + this.fo76CustomModTime = File.GetLastWriteTime(this.GetIniPath(LegacyIniFile.F76Custom)); } @@ -856,64 +857,64 @@ protected void FixDuplicateResourceLists() ******************************************************************************************************************************************** */ - public void Merge(IniFile f, IniData d) + public void Merge(LegacyIniFile f, IniData d) { this.GetIniData(f).Merge(d); } // https://stackoverflow.com/questions/1873658/net-windows-forms-remember-windows-size-and-location - public void SaveWindowState(String formName, Form form) + public void SaveWindowState(string formName, Form form) { if (form.WindowState == FormWindowState.Maximized) { - this.Set(IniFile.Config, formName, "iLocationX", form.RestoreBounds.Location.X); - this.Set(IniFile.Config, formName, "iLocationY", form.RestoreBounds.Location.Y); - this.Set(IniFile.Config, formName, "iWidth", form.RestoreBounds.Size.Width); - this.Set(IniFile.Config, formName, "iHeight", form.RestoreBounds.Size.Height); - this.Set(IniFile.Config, formName, "bMaximised", true); + this.Set(LegacyIniFile.Config, formName, "iLocationX", form.RestoreBounds.Location.X); + this.Set(LegacyIniFile.Config, formName, "iLocationY", form.RestoreBounds.Location.Y); + this.Set(LegacyIniFile.Config, formName, "iWidth", form.RestoreBounds.Size.Width); + this.Set(LegacyIniFile.Config, formName, "iHeight", form.RestoreBounds.Size.Height); + this.Set(LegacyIniFile.Config, formName, "bMaximised", true); } else { - this.Set(IniFile.Config, formName, "iLocationX", form.Location.X); - this.Set(IniFile.Config, formName, "iLocationY", form.Location.Y); - this.Set(IniFile.Config, formName, "iWidth", form.Size.Width); - this.Set(IniFile.Config, formName, "iHeight", form.Size.Height); - this.Set(IniFile.Config, formName, "bMaximised", false); + this.Set(LegacyIniFile.Config, formName, "iLocationX", form.Location.X); + this.Set(LegacyIniFile.Config, formName, "iLocationY", form.Location.Y); + this.Set(LegacyIniFile.Config, formName, "iWidth", form.Size.Width); + this.Set(LegacyIniFile.Config, formName, "iHeight", form.Size.Height); + this.Set(LegacyIniFile.Config, formName, "bMaximised", false); } this.SaveConfig(); } - public void LoadWindowState(String formName, Form form) + public void LoadWindowState(string formName, Form form) { - int locX = this.GetInt(IniFile.Config, formName, "iLocationX", -1); - int locY = this.GetInt(IniFile.Config, formName, "iLocationY", -1); + int locX = this.GetInt(LegacyIniFile.Config, formName, "iLocationX", -1); + int locY = this.GetInt(LegacyIniFile.Config, formName, "iLocationY", -1); if (locX >= 0 && locY >= 0) form.Location = new System.Drawing.Point(locX, locY); - int width = this.GetInt(IniFile.Config, formName, "iWidth", form.Size.Width); - int height = this.GetInt(IniFile.Config, formName, "iHeight", form.Size.Height); + int width = this.GetInt(LegacyIniFile.Config, formName, "iWidth", form.Size.Width); + int height = this.GetInt(LegacyIniFile.Config, formName, "iHeight", form.Size.Height); if (width >= form.MinimumSize.Width && height >= form.MinimumSize.Height) form.Size = new System.Drawing.Size(width, height); - if (this.GetBool(IniFile.Config, formName, "bMaximised", false)) + if (this.GetBool(LegacyIniFile.Config, formName, "bMaximised", false)) form.WindowState = FormWindowState.Maximized; } - public void SaveListViewState(String formName, ListView listView) + public void SaveListViewState(string formName, ListView listView) { List widths = new List(); foreach (ColumnHeader column in listView.Columns) { widths.Add(column.Width); } - this.Set(IniFile.Config, formName, "sColumnWidths", String.Join(",", widths)); + this.Set(LegacyIniFile.Config, formName, "sColumnWidths", string.Join(",", widths)); } - public void LoadListViewState(String formName, ListView listView) + public void LoadListViewState(string formName, ListView listView) { List lWidths = new List(); - String[] sWidths = this.GetString(IniFile.Config, formName, "sColumnWidths", "").Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); - foreach (String sWidth in sWidths) + string[] sWidths = this.GetString(LegacyIniFile.Config, formName, "sColumnWidths", "").Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); + foreach (string sWidth in sWidths) lWidths.Add(Convert.ToInt32(sWidth)); int i = 0; diff --git a/Fo76ini/Mods/LegacyManagedMods.cs b/Fo76ini/Mods/LegacyManagedMods.cs new file mode 100644 index 0000000..93fd26b --- /dev/null +++ b/Fo76ini/Mods/LegacyManagedMods.cs @@ -0,0 +1,355 @@ +using Fo76ini.Profiles; +using Fo76ini.Utilities; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Xml; +using System.Xml.Linq; + +namespace Fo76ini.Mods +{ + public static class LegacyManagedMods + { + /// + /// Checks whether there are mods have been managed by a version prior to v1.9.0. + /// + public static bool CheckLegacy(string gamePath) + { + try + { + return Directory.Exists(Path.Combine(gamePath, "Mods")) && + File.Exists(Path.Combine(gamePath, "Mods", "manifest.xml")) && + XDocument.Load(Path.Combine(gamePath, "Mods", "manifest.xml")).Root.Attribute("doNotImport") == null; + } + catch + { + return false; + } + } + + /// + /// Loads and converts legacy managed mods to the new format. + /// It adds them to an already existing ManagedMods object. + /// + public static void ConvertLegacy(ManagedMods mods, GameEdition edition, Action ProgressChanged = null) + { + Directory.CreateDirectory(Path.Combine(mods.GamePath, "FrozenData")); + + XDocument xmlDoc = XDocument.Load(Path.Combine(mods.ModsPath, "manifest.xml")); + + // I added a doNotImport="true" attribute, so I can check, whether the manifest.xml has only been generated for backwards-compatibility. + // If it exists, we can just skip the import: + if (xmlDoc.Root.Attribute("doNotImport") != null) + { + ProgressChanged?.Invoke(Progress.Aborted("Import skipped.")); + return; + } + + // Make backups: + File.Copy(Path.Combine(mods.ModsPath, "manifest.xml"), Path.Combine(mods.ModsPath, "manifest.old.xml"), true); + if (File.Exists(Path.Combine(mods.ModsPath, "managed.xml"))) + File.Copy(Path.Combine(mods.ModsPath, "managed.xml"), Path.Combine(mods.ModsPath, "managed.old.xml"), true); + + // Converting the legacy list will completely erase the current mod list: + mods.Mods.Clear(); + + /* + * Converting: + */ + int modCount = xmlDoc.Descendants("Mod").Count(); + int modIndex = 0; + foreach (XElement xmlMod in xmlDoc.Descendants("Mod")) + { + modIndex++; + + if (xmlMod.Attribute("modFolder") == null) + continue; + + ManagedMod mod = new ManagedMod(mods.GamePath); + + string managedFolderName = xmlMod.Attribute("modFolder").Value; + string managedFolderPath = Path.Combine(mods.ModsPath, managedFolderName); + string frozenArchivePath = Path.Combine(mods.ModsPath, managedFolderName, "frozen.ba2"); + bool isFrozen = File.Exists(frozenArchivePath); + + if (xmlMod.Attribute("title") != null) + mod.Title = xmlMod.Attribute("title").Value; + + string progressTitle = $"Converting \"{mod.Title}\" ({modIndex} of {modCount})"; + float progressPercentage = (float)modIndex / (float)modCount; + + // In case the mod was "frozen" before, + // we'll need to move the *.ba2 archive into the FrozenData folder and then extract it. + if (isFrozen) + { + ProgressChanged?.Invoke(Progress.Ongoing($"{progressTitle}: Extracting *.ba2 archive...", progressPercentage)); + File.Move(frozenArchivePath, mod.FrozenArchivePath); + Archive2.Extract(mod.FrozenArchivePath, managedFolderPath); + mod.Frozen = true; + mod.Freeze = true; + } + + // We need to rename the old folder to fit with the new format. + if (Directory.Exists(managedFolderPath)) + { + ProgressChanged?.Invoke(Progress.Ongoing($"{progressTitle}: Moving managed folder...", progressPercentage)); + if (Directory.Exists(mod.ManagedFolderPath)) + Directory.Delete(mod.ManagedFolderPath, true); + Directory.Move(managedFolderPath, mod.ManagedFolderPath); + } + + ProgressChanged?.Invoke(Progress.Ongoing($"{progressTitle}: Parsing XML...", progressPercentage)); + + if (xmlMod.Attribute("url") != null) + mod.URL = xmlMod.Attribute("url").Value; + + if (xmlMod.Attribute("version") != null) + mod.Version = xmlMod.Attribute("version").Value; + + if (xmlMod.Attribute("enabled") != null) + { + try + { + mod.Deployed = XmlConvert.ToBoolean(xmlMod.Attribute("enabled").Value); + } + catch + { + mod.Deployed = false; + } + mod.Enabled = mod.Deployed; + } + + if (xmlMod.Attribute("installType") != null) + { + switch (xmlMod.Attribute("installType").Value) + { + case "Loose": + mod.PreviousMethod = ManagedMod.DeploymentMethod.LooseFiles; + break; + case "SeparateBA2": + mod.PreviousMethod = ManagedMod.DeploymentMethod.SeparateBA2; + break; + case "BA2Archive": // Backward compatibility + case "BundledBA2": + case "BundledBA2Textures": // Backward compatibility + default: + mod.PreviousMethod = ManagedMod.DeploymentMethod.BundledBA2; + break; + } + mod.Method = mod.PreviousMethod; + } + + if (xmlMod.Attribute("format") != null) + { + switch (xmlMod.Attribute("format").Value) + { + case "General": + mod.CurrentFormat = ManagedMod.ArchiveFormat.General; + break; + case "DDS": // Backward compatibility + case "Textures": + mod.CurrentFormat = ManagedMod.ArchiveFormat.Textures; + break; + case "Auto": + default: + mod.CurrentFormat = ManagedMod.ArchiveFormat.Auto; + break; + } + mod.Format = mod.CurrentFormat; + } + + if (xmlMod.Attribute("compression") != null) + { + switch (xmlMod.Attribute("compression").Value) + { + case "Default": // Backward compatibility + case "Compressed": + mod.CurrentCompression = ManagedMod.ArchiveCompression.Compressed; + break; + case "None": // Backward compatibility + case "Uncompressed": + mod.CurrentCompression = ManagedMod.ArchiveCompression.Uncompressed; + break; + case "Auto": + default: + mod.CurrentCompression = ManagedMod.ArchiveCompression.Auto; + break; + } + mod.Compression = mod.CurrentCompression; + } + + if (xmlMod.Attribute("archiveName") != null) + { + mod.CurrentArchiveName = xmlMod.Attribute("archiveName").Value; + mod.ArchiveName = mod.CurrentArchiveName; + } + + if (xmlMod.Attribute("root") != null) + { + mod.CurrentRootFolder = xmlMod.Attribute("root").Value; + mod.RootFolder = mod.CurrentRootFolder; + foreach (XElement xmlFile in xmlMod.Descendants("File")) + if (xmlFile.Attribute("path") != null) + mod.LooseFiles.Add(xmlFile.Attribute("path").Value); + } + + /*if (xmlMod.Attribute("frozen") != null) + { + frozen = XmlConvert.ToBoolean(xmlMod.Attribute("frozen").Value); + }*/ + + mods.Add(mod); + } + + // Legacy resource list: + if (IniFiles.Config.GetBool("Preferences", "bMultipleGameEditionsUsed", false)) + { + string backedUpList = IniFiles.Config.GetString("Mods", $"sResourceIndexFileList{edition}", ""); + string actualList = IniFiles.F76Custom.GetString("Archive", "sResourceIndexFileList", ""); + if (backedUpList != "") + mods.Resources.ReplaceRange(ResourceList.FromString(backedUpList)); + else if (actualList != "") + mods.Resources.ReplaceRange(ResourceList.FromString(actualList)); + } + + ProgressChanged?.Invoke(Progress.Ongoing("Saving XML...", 1f)); + mods.Save(); + + ProgressChanged?.Invoke(Progress.Done("Legacy mods imported.")); + } + + /// + /// Generates and saves a legacy "manifest.xml" for backwards-compatibility. + /// + /// Generate a legacy xml for these mods. + public static void GenerateLegacyXML(ManagedMods mods) + { + // I ported the old Serialize methods of the old Mod and old ManagedMods classes. + // It now uses the new format, but generates an *.xml that is compatible with older versions. + // Since there is now way more information saved: It uses the current disk state, not the pending one. (PreviousMethod, CurrentArchiveName, etc.) + // In case the user wants to downgrade, they can. + + XDocument xmlDoc = new XDocument(); + XElement xmlRoot = new XElement("Mods"); + xmlRoot.Add(new XAttribute("doNotImport", true)); + xmlDoc.Add(xmlRoot); + + xmlDoc.AddFirst(new XComment($"\n This file has been generated by v{Shared.VERSION} for backwards-compatibility.\n It not actually being used anymore.\n")); + + foreach (ManagedMod mod in mods) + { + XElement xmlMod = new XElement("Mod", + new XAttribute("title", mod.Title), + new XAttribute("enabled", mod.Deployed), + new XAttribute("modFolder", mod.ManagedFolderName), + new XAttribute("installType", GetLegacyInstallMethodName(mod))); + + if (mod.URL != "") + xmlMod.Add(new XAttribute("url", mod.URL)); + + if (mod.Version != "") + xmlMod.Add(new XAttribute("version", mod.Version)); + + if (mod.PreviousMethod == ManagedMod.DeploymentMethod.SeparateBA2 && mod.CurrentArchiveName != null) + { + xmlMod.Add(new XAttribute("archiveName", mod.CurrentArchiveName)); + xmlMod.Add(new XAttribute("compression", GetLegacyArchiveCompressionName(mod))); + xmlMod.Add(new XAttribute("format", GetLegacyArchiveFormatName(mod))); + + // We can't set the frozen flag anymore, because we store frozen archives differently now: + //if (mod.Frozen) + //xmlMod.Add(new XAttribute("frozen", mod.Frozen)); + } + + if (mod.PreviousMethod == ManagedMod.DeploymentMethod.LooseFiles && mod.CurrentRootFolder != "") + xmlMod.Add(new XAttribute("root", mod.CurrentRootFolder)); + + if (mod.PreviousMethod == ManagedMod.DeploymentMethod.LooseFiles && mod.Deployed) + foreach (String filePath in mod.LooseFiles) + xmlMod.Add(new XElement("File", new XAttribute("path", filePath))); + + xmlRoot.Add(xmlMod); + } + + xmlDoc.Save(Path.Combine(mods.ModsPath, "manifest.xml")); + } + + /// + /// Returns the legacy string of the install method: + /// + /// public enum FileType + /// { + /// Loose, + /// BundledBA2, + /// SeparateBA2 + /// } + /// + /// "Loose", "SeparateBA2", or "BundledBA2" + private static string GetLegacyInstallMethodName(ManagedMod mod) + { + switch (mod.PreviousMethod) + { + case ManagedMod.DeploymentMethod.LooseFiles: + return "Loose"; + case ManagedMod.DeploymentMethod.SeparateBA2: + return "SeparateBA2"; + case ManagedMod.DeploymentMethod.BundledBA2: + default: + return "BundledBA2"; + } + } + + /// + /// Returns the legacy string of ArchiveCompression. + /// + /// public enum ArchiveCompression + /// { + /// Auto, + /// Compressed, + /// Uncompressed + /// } + /// + /// "Auto", "Compressed", or "Uncompressed" + private static string GetLegacyArchiveCompressionName(ManagedMod mod) + { + switch (mod.CurrentCompression) + { + case ManagedMod.ArchiveCompression.Compressed: + return "Compressed"; + case ManagedMod.ArchiveCompression.Uncompressed: + return "Uncompressed"; + case ManagedMod.ArchiveCompression.Auto: + default: + return "Auto"; + } + } + + /// + /// Returns the legacy string of ArchiveFormat. + /// + /// public enum ArchiveFormat + /// { + /// Auto, + /// General, + /// Textures + /// } + /// + /// "Auto", "General", or "Textures" + private static string GetLegacyArchiveFormatName(ManagedMod mod) + { + switch (mod.CurrentFormat) + { + case ManagedMod.ArchiveFormat.General: + return "General"; + case ManagedMod.ArchiveFormat.Textures: + return "Textures"; + case ManagedMod.ArchiveFormat.Auto: + default: + return "Auto"; + } + } + } +} diff --git a/Fo76ini/Mods/ManagedMod.cs b/Fo76ini/Mods/ManagedMod.cs new file mode 100644 index 0000000..79af80a --- /dev/null +++ b/Fo76ini/Mods/ManagedMod.cs @@ -0,0 +1,585 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Xml.Linq; +using Fo76ini.NexusAPI; +using Fo76ini.Utilities; + +namespace Fo76ini.Mods +{ + /// + /// Represents a managed mod. Stores information about the mod and how it's installed. + /// + public class ManagedMod + { + /// + /// How a mod should be deployed. + /// Loose - Copy files over without packing + /// BundledBA2 - Bundle it with other mods in one package + /// SeparateBA2 - Pack it as a separate *.ba2 archive + /// + public enum DeploymentMethod + { + LooseFiles, + BundledBA2, + SeparateBA2 + } + + /// + /// Archive format + /// Auto - Automatically detect + /// General - Use "Archive2.Format.General" + /// Textures - Use "Archive2.Format.DDS" + /// + /// (Does only apply to DeploymentMethod.SeparateBA2) + /// + public enum ArchiveFormat + { + Auto, + General, + Textures + } + + /// + /// Archive compression + /// Auto - Automatically detect + /// Compressed - Use "Archive2.Compression.Default" + /// Uncompressed - Use "Archive2.Compression.None" + /// + /// (Does only apply to DeploymentMethod.SeparateBA2) + /// + public enum ArchiveCompression + { + Auto, + Compressed, + Uncompressed + } + + /// + /// Convert DeploymentMethod enum to string. + /// + private static string GetMethodName(DeploymentMethod method) + { + return Enum.GetName(typeof(DeploymentMethod), (int)method); + } + + /// + /// Convert string to DeploymentMethod enum. + /// + private static DeploymentMethod GetMethod(String method) + { + switch (method) + { + case "Loose": + case "LooseFiles": + return DeploymentMethod.LooseFiles; + case "BundledBA2": + return DeploymentMethod.BundledBA2; + case "SeparateBA2": + return DeploymentMethod.SeparateBA2; + default: + throw new InvalidDataException($"Invalid mod deployment method: {method}"); + } + } + + /// + /// Convert ArchiveFormat enum to string. + /// + private static string GetFormatName(ArchiveFormat format) + { + return Enum.GetName(typeof(ArchiveFormat), (int)format); + } + + /// + /// Convert string to ArchiveFormat enum. + /// + private static ArchiveFormat GetFormat(String format) + { + switch (format) + { + case "General": + return ArchiveFormat.General; + case "Textures": + return ArchiveFormat.Textures; + case "Auto": + return ArchiveFormat.Auto; + default: + throw new InvalidDataException($"Invalid mod archive format: {format}"); + } + } + + /// + /// Convert ArchiveCompression enum to string. + /// + private static string GetCompressionName(ArchiveCompression compression) + { + return Enum.GetName(typeof(ArchiveCompression), (int)compression); + } + + /// + /// Convert string to ArchiveCompression enum. + /// + private static ArchiveCompression GetCompression(String compression) + { + switch (compression) + { + case "Compressed": + return ArchiveCompression.Compressed; + case "Uncompressed": + return ArchiveCompression.Uncompressed; + case "Auto": + return ArchiveCompression.Auto; + default: + throw new InvalidDataException($"Invalid mod archive compression: {compression}"); + } + } + + /// + /// Enabled for deployment: Whether we want to have this mod deployed or not. + /// + public bool Enabled = false; + + /// + /// Has it been deployed? Is it on disk? + /// + public bool Deployed = false; + + /// + /// Do we have a frozen archive for deployment? (SeparateBA2) + /// + public bool Frozen = false; + + /// + /// Do we want to freeze this archive? Do we want to use a frozen archive if available? (SeparateBA2) + /// + public bool Freeze = false; + + /// + /// How the mod got installed. (Current disk state) + /// + public DeploymentMethod PreviousMethod; + + /// + /// How the mod should get installed. (Pending disk state) + /// + public DeploymentMethod Method = DeploymentMethod.BundledBA2; + + /// + /// How it should get compressed on deployment. + /// + public ArchiveCompression Compression = ArchiveCompression.Auto; + + /// + /// How it should get formatted on deployment. + /// + public ArchiveFormat Format = ArchiveFormat.Auto; + + /// + /// How the archive in Data is compressed. + /// + public ArchiveCompression CurrentCompression = ArchiveCompression.Auto; + + /// + /// How the archive in Data is formatted. + /// + public ArchiveFormat CurrentFormat = ArchiveFormat.Auto; + + /// + /// How the archive in FrozenData is compressed. + /// + public ArchiveCompression FrozenCompression = ArchiveCompression.Auto; + + /// + /// How the archive in FrozenData is formatted. + /// + public ArchiveFormat FrozenFormat = ArchiveFormat.Auto; + + /// + /// Relative paths of the mod files that are currently deployed. + /// + public List LooseFiles = new List(); + + /// + /// The folder where loose files are currently copied to. + /// + public string CurrentRootFolder = "."; + + /// + /// The folder where to copy loose files to on deployment. + /// + public string RootFolder = "."; + + /// + /// If deployed as SeparateBA2, what is the archive in Data called? (SeparateBA2) + /// + public string CurrentArchiveName; + + /// + /// Get the path to the currently deployed archive. + /// Example: @"C:\Program Files (x86)\Steam\steamapps\common\Fallout 76\Data\Foobar.ba2" + /// + public string CurrentArchivePath + { + get { return Path.Combine(GamePath, "Data", this.ArchiveName); } + } + + private string archiveName; + + /// + /// How is the archive going to be called after deployment? (SeparateBA2) + /// + public string ArchiveName + { + get { return this.archiveName; } + set + { + if (value.Trim().Length < 0) + return; + this.archiveName = Utils.GetValidFileName(value, ".ba2"); + } + } + + /// + /// Get the path to where the archive should get deployed. + /// Example: @"C:\Program Files (x86)\Steam\steamapps\common\Fallout 76\Data\Foobar.ba2" + /// + public string ArchivePath + { + get { return Path.Combine(GamePath, "Data", this.ArchiveName); } + } + + /// + /// Get the folder name (not path). This folder stores the mod's files. + /// Example: @"{2f2d3b3b-b21b-4ec2-b555-c8806a801b16}" + /// + public string ManagedFolderName + { + get { return "{" + guid.ToString() + "}"; } + } + + /// + /// Get the path to where the mod's files are stored. + /// Example: @"C:\Program Files (x86)\Steam\steamapps\common\Fallout 76\Mods\{2f2d3b3b-b21b-4ec2-b555-c8806a801b16}" + /// + public string ManagedFolderPath + { + get { return Path.Combine(GamePath, "Mods", ManagedFolderName); } + } + + /// + /// Path where frozen archives are stored. + /// Example: @"C:\Program Files (x86)\Steam\steamapps\common\Fallout 76\FrozenData" + /// + public string FrozenDataPath + { + get { return Path.Combine(GamePath, "FrozenData"); } + } + + /// + /// Name of the frozen archive. + /// Example: @"{2f2d3b3b-b21b-4ec2-b555-c8806a801b16}.ba2" + /// + public string FrozenArchiveName + { + get { return "{" + this.guid.ToString() + "}.ba2"; } + } + + /// + /// Path to the mod's frozen archive. + /// Example: @"C:\Program Files (x86)\Steam\steamapps\common\Fallout 76\FrozenData\{2f2d3b3b-b21b-4ec2-b555-c8806a801b16}.ba2" + /// + public string FrozenArchivePath + { + get { return Path.Combine(FrozenDataPath, FrozenArchiveName); } + } + + public readonly Guid guid; + + private string title = "Untitled"; + public string Version = "1.0"; + private string url = ""; + public int ID = -1; + public readonly string GamePath; + + public ManagedMod(string gamePath, Guid uuid) + { + this.GamePath = gamePath; + this.guid = uuid; + } + + public ManagedMod(string gamePath) + { + this.GamePath = gamePath; + this.guid = Guid.NewGuid(); + } + + /// + /// Creates a deep copy of 'mod'. + /// + /// The object it makes a copy of. + public ManagedMod(ManagedMod mod) + { + /* + * Info + */ + + this.title = mod.title; + this.ID = mod.ID; + this.URL = mod.URL; + this.Version = mod.Version; + this.guid = mod.guid; + this.GamePath = mod.GamePath; + + + /* + * General + */ + this.Enabled = mod.Enabled; + this.Deployed = mod.Deployed; + this.Method = mod.Method; + this.PreviousMethod = mod.PreviousMethod; + + + /* + * SeparateBA2 + */ + + this.archiveName = mod.archiveName; + this.CurrentArchiveName = mod.CurrentArchiveName; + this.Compression = mod.Compression; + this.CurrentCompression = mod.CurrentCompression; + this.Format = mod.Format; + this.CurrentFormat = mod.CurrentFormat; + + + /* + * SeparateBA2 Frozen + */ + this.Freeze = mod.Freeze; + this.Frozen = mod.Frozen; + this.FrozenCompression = mod.FrozenCompression; + this.FrozenFormat = mod.FrozenFormat; + + + /* + * Loose + */ + this.LooseFiles = new List(mod.LooseFiles); + this.RootFolder = mod.RootFolder; + this.CurrentRootFolder = mod.CurrentRootFolder; + } + + /// + /// URL to the NexusMods page of the mod. + /// + public string URL + { + get + { + return this.url; + } + set + { + this.url = value; + this.ID = NexusMods.GetIDFromURL(value); + } + } + + /// + /// Returns remote info from NexusMods if available. + /// Returns null if not available. + /// + public NMMod RemoteInfo + { + get + { + if (this.ID >= 0 && NexusMods.Mods.ContainsKey(this.ID)) + return NexusMods.Mods[this.ID]; + else + return null; + } + } + + public string Title + { + get { return this.title; } + set { this.title = value.Trim().Length > 0 ? value.Trim() : "Untitled"; } + } + + public ManagedMod CreateDeepCopy() + { + return new ManagedMod(this); + } + + public XElement Serialize() + { + XElement xmlMod = new XElement("Mod", + new XAttribute("guid", this.guid.ToString()), + new XElement("Title", this.Title), + new XElement("Version", this.Version), + new XElement("NexusMods", + new XAttribute("id", this.ID), + new XElement("URL", this.URL) + ) + ); + + XElement xmlLooseFiles = new XElement("InstalledLooseFiles"); + if (this.PreviousMethod == DeploymentMethod.LooseFiles && this.Deployed) + foreach (string filePath in this.LooseFiles) + xmlLooseFiles.Add(new XElement("File", new XAttribute("path", filePath))); + + XElement xmlDiskState = new XElement("DiskState", + new XElement("Current", + new XAttribute("isDeployed", this.Deployed), + new XElement("InstallationMethod", GetMethodName(this.PreviousMethod)), + new XElement("ArchiveName", this.CurrentArchiveName), + new XElement("ArchiveFormat", GetFormatName(this.CurrentFormat)), + new XElement("ArchiveCompression", GetCompressionName(this.CurrentCompression)), + new XElement("RootFolder", this.CurrentRootFolder), + xmlLooseFiles + ), + new XElement("Pending", + new XAttribute("isEnabled", this.Enabled), + new XElement("InstallationMethod", GetMethodName(this.Method)), + new XElement("ArchiveName", this.ArchiveName), + new XElement("ArchiveFormat", GetFormatName(this.Format)), + new XElement("ArchiveCompression", GetCompressionName(this.Compression)), + new XElement("RootFolder", this.RootFolder) + ), + new XElement("FrozenData", + new XAttribute("isFrozen", this.Frozen), + new XAttribute("freeze", this.Freeze), + new XElement("ArchiveFormat", GetFormatName(this.FrozenFormat)), + new XElement("ArchiveCompression", GetCompressionName(this.FrozenCompression)) + ) + ); + + xmlMod.Add(xmlDiskState); + + return xmlMod; + } + + public static ManagedMod Deserialize(XElement xmlMod, string GamePath) + { + if (xmlMod.Attribute("guid") == null) + throw new Exception("Invalid *.xml entry for mod."); + + ManagedMod mod = new ManagedMod(GamePath, new Guid(xmlMod.Attribute("guid").Value)); + + if (xmlMod.Element("Title") == null) + throw new Exception("Invalid *.xml entry for mod."); + else + mod.Title = xmlMod.Element("Title").Value; + + if (xmlMod.Element("Version") != null) + mod.Version = xmlMod.Element("Version").Value; + + XElement xmlNexusMods = xmlMod.Element("NexusMods"); + int modId; + if (xmlNexusMods != null && xmlNexusMods.Attribute("id") != null && xmlNexusMods.Element("URL") != null) + { + if (xmlNexusMods.Attribute("id").TryParseInt(out modId)) + mod.ID = modId; + mod.URL = xmlNexusMods.Element("URL").Value; + } + + XElement xmlDiskState = xmlMod.Element("DiskState"); + if (xmlDiskState == null) + throw new Exception("Invalid *.xml entry for mod."); + + XElement xmlCurrentDiskState = xmlDiskState.Element("Current"); + if (xmlCurrentDiskState == null) + throw new Exception("Invalid *.xml entry for mod."); + if (xmlCurrentDiskState.Attribute("isDeployed") != null && + xmlCurrentDiskState.Attribute("isDeployed").TryParseBool(out bool deployed)) + mod.Deployed = deployed; + if (xmlCurrentDiskState.Element("InstallationMethod") != null) + mod.PreviousMethod = GetMethod(xmlCurrentDiskState.Element("InstallationMethod").Value); + if (xmlCurrentDiskState.Element("ArchiveFormat") != null) + mod.CurrentFormat = GetFormat(xmlCurrentDiskState.Element("ArchiveFormat").Value); + if (xmlCurrentDiskState.Element("ArchiveCompression") != null) + mod.CurrentCompression = GetCompression(xmlCurrentDiskState.Element("ArchiveCompression").Value); + if (xmlCurrentDiskState.Element("ArchiveName") != null) + mod.CurrentArchiveName = xmlCurrentDiskState.Element("ArchiveName").Value; + if (xmlCurrentDiskState.Element("RootFolder") != null) + mod.CurrentRootFolder = xmlCurrentDiskState.Element("RootFolder").Value; + + XElement xmlInstalledLooseFiles = xmlCurrentDiskState.Element("InstalledLooseFiles"); + if (xmlInstalledLooseFiles != null) + foreach (XElement xmlFile in xmlInstalledLooseFiles.Descendants("File")) + if (xmlFile.Attribute("path") != null) + mod.LooseFiles.Add(xmlFile.Attribute("path").Value); + + XElement xmlPendingDiskState = xmlDiskState.Element("Pending"); + if (xmlPendingDiskState == null) + throw new Exception("Invalid *.xml entry for mod."); + if (xmlPendingDiskState.Attribute("isEnabled") != null && + xmlPendingDiskState.Attribute("isEnabled").TryParseBool(out bool enabled)) + mod.Enabled = enabled; + if (xmlPendingDiskState.Element("InstallationMethod") != null) + mod.Method = GetMethod(xmlPendingDiskState.Element("InstallationMethod").Value); + if (xmlPendingDiskState.Element("ArchiveName") != null) + mod.ArchiveName = xmlPendingDiskState.Element("ArchiveName").Value; + if (xmlPendingDiskState.Element("ArchiveFormat") != null) + mod.Format = GetFormat(xmlPendingDiskState.Element("ArchiveFormat").Value); + if (xmlPendingDiskState.Element("ArchiveCompression") != null) + mod.Compression = GetCompression(xmlPendingDiskState.Element("ArchiveCompression").Value); + if (xmlPendingDiskState.Element("RootFolder") != null) + mod.RootFolder = xmlPendingDiskState.Element("RootFolder").Value; + + XElement xmlFrozenDiskState = xmlDiskState.Element("FrozenData"); + if (xmlFrozenDiskState == null) + throw new Exception("Invalid *.xml entry for mod."); + if (xmlFrozenDiskState.Attribute("isFrozen") != null && + xmlFrozenDiskState.Attribute("isFrozen").TryParseBool(out bool frozen)) + mod.Frozen = frozen; + if (xmlFrozenDiskState.Attribute("freeze") != null && + xmlFrozenDiskState.Attribute("freeze").TryParseBool(out bool freeze)) + mod.Freeze = freeze; + if (xmlFrozenDiskState.Element("ArchiveFormat") != null) + mod.FrozenFormat = GetFormat(xmlFrozenDiskState.Element("ArchiveFormat").Value); + if (xmlFrozenDiskState.Element("ArchiveCompression") != null) + mod.FrozenCompression = GetCompression(xmlFrozenDiskState.Element("ArchiveCompression").Value); + + return mod; + } + + /// + /// Compares current disk state with pending disk state and returns true, if they're different. + /// + /// + public bool isDeploymentNecessary() + { + if (Deployed != Enabled) + return true; + + if (!Enabled && !Deployed) + return false; + + if (PreviousMethod != Method) + return true; + + if (Method == DeploymentMethod.SeparateBA2) + { + if (CurrentArchiveName != ArchiveName) + return true; + + if (CurrentFormat != Format) + return true; + + if (CurrentCompression != Compression) + return true; + + if (Freeze && !Frozen) + return true; + } + else if (Method == DeploymentMethod.LooseFiles) + { + if (CurrentRootFolder != RootFolder) + return true; + } + + return false; + } + } +} diff --git a/Fo76ini/Mods/ManagedMods.cs b/Fo76ini/Mods/ManagedMods.cs new file mode 100644 index 0000000..12fc479 --- /dev/null +++ b/Fo76ini/Mods/ManagedMods.cs @@ -0,0 +1,298 @@ +using Fo76ini.Tweaks.ResourceLists; +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Windows.Forms; +using System.Xml.Linq; +using Fo76ini.Interface; +using Fo76ini.Profiles; + +namespace Fo76ini.Mods +{ + /// + /// This class is used to load, store, and save all data about installed mods and their current state. + /// Pass an instance of this class to a method which works with the data. + /// + public class ManagedMods : ICollection + { + public ManagedMods(string gamePath) + { + this.GamePath = gamePath; + } + + public List Mods = new List(); + public ResourceList Resources = ResourceList.GetDefaultList(); + public readonly string GamePath = ""; + public bool ModsDisabled = false; + public bool NuclearWinterModeEnabled = false; + + /// + /// Path where mods get stored. ("Fallout76\Mods") + /// + public string ModsPath + { + get { return Path.Combine(GamePath, "Mods"); } + } + + /// + /// Path to the "Fallout76\Mods\managed.xml" + /// + public string XMLPath + { + get { return Path.Combine(ModsPath, "managed.xml"); } + } + + /// + /// Path to the "Fallout76\Mods\resources.txt" + /// + public string ResourcesPath + { + get { return Path.Combine(ModsPath, "resources.txt"); } + } + + public int Count => this.Mods.Count(); + + public bool IsReadOnly => false; + + public void EnableMod(int index) + { + this.Mods[index].Enabled = true; + } + + public void DisableMod(int index) + { + this.Mods[index].Enabled = false; + } + + public bool isModEnabled(int index) + { + return this.Mods[index].Enabled; + } + + /// + /// Move a mod from one index to another. + /// + /// + private int MoveMod(int oldIndex, int newIndex) + { + if (oldIndex >= this.Mods.Count || + oldIndex < 0 || + newIndex >= this.Mods.Count || + newIndex < 0) + return oldIndex; + + // https://stackoverflow.com/questions/450233/generic-list-moving-an-item-within-the-list + ManagedMod mod = this.Mods[oldIndex]; + + this.Mods.RemoveAt(oldIndex); + + // TODO: Do we need to change the index? (MoveMod) + // the actual index could have shifted due to the removal + // if (newIndex > oldIndex) newIndex--; + + this.Mods.Insert(newIndex, mod); + + return newIndex; + } + + /// + /// Moves the mod one up in the list. + /// + /// Index of the mod that should be moved + /// New index of the mod after it got moved + public int MoveModUp(int index) + { + if (index > 0) + return MoveMod(index, index - 1); + return index; + } + + /// + /// Moves the mod one down in the list. + /// + /// Index of the mod that should be moved + /// New index of the mod after it got moved + public int MoveModDown(int index) + { + if (index < this.Mods.Count - 1) + return MoveMod(index, index + 1); + return index; + } + + /// + /// Compares current disk state and pending disk state and returns true, if they're different. + /// + /// + public bool isDeploymentNecessary() + { + foreach (ManagedMod mod in Mods) + { + if (mod.Deployed && this.ModsDisabled) + return true; + + if (mod.isDeploymentNecessary()) + return true; + } + return false; + } + + /// + /// Serializes a list of mods into a *.xml document. + /// + /// A list of mods + /// A *.xml document that can be saved to disk. + public XDocument Serialize(List mods) + { + /* + Fallout76\Mods\managed.xml + + + + + + */ + + XDocument xmlDoc = new XDocument(); + XElement xmlRoot = new XElement("ManagedMods", + new XAttribute("enabled", !this.ModsDisabled), + new XAttribute("nwmode", this.NuclearWinterModeEnabled) + ); + xmlDoc.Add(xmlRoot); + + foreach (ManagedMod mod in mods) + { + if (Directory.Exists(mod.ManagedFolderPath)) + xmlRoot.Add(mod.Serialize()); + } + + return xmlDoc; + } + + /// + /// Deserializes every mod and returns them as a list. + /// + /// The document that contains all Mod elements. + /// + public List Deserialize(XDocument xmlDoc) + { + List mods = new List(); + + if (xmlDoc.Root.Attribute("enabled") != null) + this.ModsDisabled = !Convert.ToBoolean(xmlDoc.Root.Attribute("enabled").Value); + + if (xmlDoc.Root.Attribute("nwmode") != null) + this.NuclearWinterModeEnabled = Convert.ToBoolean(xmlDoc.Root.Attribute("nwmode").Value); + + foreach (XElement xmlMod in xmlDoc.Descendants("Mod")) + { + try + { + ManagedMod mod = ManagedMod.Deserialize(xmlMod, GamePath); + /*if (!Directory.Exists(mod.GetManagedPath())) + continue;*/ + mods.Add(mod); + } + catch (Exception ex) + { + /* InvalidDataException, ArgumentException */ + MsgBox.Get("modsInvalidManifestEntry").FormatText(ex.Message).Show(MessageBoxIcon.Warning); + } + } + return mods; + } + + /// + /// Loads the XML file, deserializes every mod, and adds it to the list. + /// + public void Load() + { + this.Mods.Clear(); + this.Resources.Clear(); + + if (!GameInstance.ValidateGamePath(GamePath)) + return; + + if (!File.Exists(XMLPath)) + return; + + XDocument xmlDoc = XDocument.Load(XMLPath); + this.Mods = Deserialize(xmlDoc); + this.Resources = ResourceList.FromTXT(ResourcesPath); + this.Resources.AssociateTweak(ResourceListTweak.GetDefaultList()); + } + + /// + /// Serializes the list of mods and saves it to managed.xml. Also saves resource list. + /// + public void Save() + { + if (!Directory.Exists(Path.Combine(this.GamePath, "Mods"))) + Directory.CreateDirectory(Path.Combine(this.GamePath, "Mods")); + + this.Serialize(this.Mods).Save(XMLPath); + SaveResources(); + LegacyManagedMods.GenerateLegacyXML(this); + } + + /// + /// Saves the resource list + /// + public void SaveResources() + { + this.Resources.SaveTXT(ResourcesPath); + if (NuclearWinterModeEnabled) + IniFiles.F76Custom.Remove("Archive", "sResourceIndexFileList"); + else + this.Resources.CommitToINI(); // TODO: Where else do we have CommitToINI? + IniFiles.F76Custom.Save(); + } + + public void Add(ManagedMod item) + { + this.Mods.Add(item); + } + + public void Clear() + { + this.Mods.Clear(); + } + + public bool Contains(ManagedMod item) + { + return this.Mods.Contains(item); + } + + public void CopyTo(ManagedMod[] array, int arrayIndex) + { + this.Mods.CopyTo(array, arrayIndex); + } + + public bool Remove(ManagedMod item) + { + return this.Mods.Remove(item); + } + + public void RemoveAt(int index) + { + this.Mods.RemoveAt(index); + } + + public IEnumerator GetEnumerator() + { + return this.Mods.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + public ManagedMod this[int index] + { + get { return this.Mods[index]; } + set { this.Mods[index] = value; } + } + } +} diff --git a/Fo76ini/Mods/ModActions.cs b/Fo76ini/Mods/ModActions.cs new file mode 100644 index 0000000..0a39d13 --- /dev/null +++ b/Fo76ini/Mods/ModActions.cs @@ -0,0 +1,284 @@ +using Fo76ini.Utilities; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; + +namespace Fo76ini.Mods +{ + /// + /// Bundles functions that change the state or the files of a mod, but don't affect game files. + /// + public static class ModActions + { + /// + /// Deletes all files of 'mod'. + /// This includes the managed folder and frozen archive. + /// + private static void DeleteFiles(ManagedMod mod) + { + // Delete managed folder: + if (Directory.Exists(mod.ManagedFolderPath)) + Directory.Delete(mod.ManagedFolderPath, true); + + // Delete frozen archive: + if (/*mod.Frozen && + mod.PreviousMethod == ManagedMod.DeploymentMethod.SeparateBA2 &&*/ + File.Exists(mod.FrozenArchivePath)) + { + File.Delete(mod.FrozenArchivePath); + } + } + + /// + /// Deletes all files of the mod and removes it from the list. + /// Saves the xml file afterwards. + /// + public static void DeleteMod(ManagedMods mods, int index, Action ProgressChanged = null) + { + ModActions.DeleteFiles(mods[index]); + mods.RemoveAt(index); + mods.Save(); + ProgressChanged?.Invoke(Progress.Done("Mod deleted.")); + } + + /// + /// Deletes multiple mods and removes them from the list. + /// Saves the xml file afterwards. + /// + public static void DeleteMods(ManagedMods mods, List indices, Action ProgressChanged = null) + { + indices = indices.OrderByDescending(i => i).ToList(); + int fi = 0; + int count = indices.Count(); + foreach (int index in indices) + { + ProgressChanged?.Invoke(Progress.Ongoing($"Deleting mod {++fi} of {count}.", (float)(fi - 1) / (float)count)); + ModActions.DeleteFiles(mods[index]); + mods.RemoveAt(index); + mods.Save(); + } + ProgressChanged?.Invoke(Progress.Done($"{count} mods deleted.")); + } + + /// + /// Freezes the mod. + /// + public static void Freeze(ManagedMods mods, int index) + { + ModActions.Freeze(mods[index]); + mods.Save(); + } + + /// + /// Freezes the mods. + /// + public static void Freeze(ManagedMods mods, IEnumerable indices) + { + foreach (int index in indices) + ModActions.Freeze(mods[index]); + mods.Save(); + } + + public static void Freeze(ManagedMod mod) + { + // TODO: Remove connection to ManagedMods + // Only freeze if not already frozen: + if (mod.Frozen && File.Exists(mod.FrozenArchivePath)) + { + // TODO: ModActions.Freeze: Should the mod get "refrozen"? + //ManagedMods.Instance.logFile.WriteLine($"Cannot freeze a mod ('{mod.Title}') that is already frozen.\n"); + return; + } + + Directory.CreateDirectory(mod.FrozenDataPath); + + // Getting preset: + Archive2.Preset preset = ModHelpers.GetArchive2Preset(mod); + + ModDeployment.LogFile.WriteLine($" Freezing mod '{mod.Title}'..."); + ModDeployment.LogFile.WriteLine($" Format: {preset.format}"); + ModDeployment.LogFile.WriteLine($" Compression: {preset.compression}"); + ModDeployment.LogFile.WriteLine($" Destination: FrozenData\\{mod.FrozenArchiveName}"); + + // Create archive: + Archive2.Create(mod.FrozenArchivePath, mod.ManagedFolderPath, preset); + + // Change DiskState and save: + mod.Frozen = true; + mod.FrozenCompression = mod.Compression; + mod.FrozenFormat = mod.Format; + } + + /// + /// Unfreezes the mod. + /// + public static void Unfreeze(ManagedMods mods, int index, Action ProgressChanged = null) + { + ModActions.Unfreeze(mods[index]); + mods.Save(); + ProgressChanged?.Invoke(Progress.Done("Mod thawed.")); + } + + /// + /// Unfreezes the mods. + /// + public static void Unfreeze(ManagedMods mods, IEnumerable indices, Action ProgressChanged = null) + { + int count = indices.Count(); + int n = 1; + foreach (int index in indices) + { + ModActions.Unfreeze(mods[index]); + ProgressChanged?.Invoke(Progress.Ongoing($"Unfreezing {n} of {count} mod(s)...", (float)n++ / (float)count)); + } + mods.Save(); + ProgressChanged?.Invoke(Progress.Done($"{count} mod(s) thawed.")); + } + + public static void Unfreeze(ManagedMod mod) + { + // Delete *.ba2: + if (File.Exists(mod.FrozenArchivePath)) + File.Delete(mod.FrozenArchivePath); + + // Change DiskState and save: + mod.Frozen = false; + } + + public static void DetectOptimalModInstallationOptions(ManagedMod mod, Action ProgressChanged = null) + { + ProgressChanged?.Invoke(Progress.Indetermined("Detecting installation options.")); + + /* + * Searching through folder: + */ + + bool resourceFoldersFound = false; + bool generalFoldersFound = false; + bool texturesFolderFound = false; + bool soundFoldersFound = false; + bool stringsFolderFound = false; + bool dataFolderFound = false; + bool videoFolderFound = false; + bool dllFound = false; + + foreach (string folderPath in Directory.EnumerateDirectories(mod.ManagedFolderPath)) + { + string folderName = Path.GetFileName(folderPath).ToLower(); + + if (ModHelpers.ResourceFolders.Contains(folderName)) + resourceFoldersFound = true; + if (ModHelpers.GeneralFolders.Contains(folderName)) + generalFoldersFound = true; + if (ModHelpers.TextureFolders.Contains(folderName)) + texturesFolderFound = true; + if (ModHelpers.SoundFolders.Contains(folderName)) + soundFoldersFound = true; + if (folderName == "strings") + stringsFolderFound = true; + if (folderName == "data") + dataFolderFound = true; + if (folderName == "video") + videoFolderFound = true; + } + + foreach (string filePath in Directory.EnumerateFiles(mod.ManagedFolderPath)) + { + string fileExtension = Path.GetExtension(filePath).ToLower(); + + if (fileExtension == ".dll") + dllFound = true; + } + + + /* + * Detecting optimal installation options: + */ + + if (resourceFoldersFound) + { + mod.Method = ManagedMod.DeploymentMethod.SeparateBA2; + mod.Format = ManagedMod.ArchiveFormat.Auto; + mod.Compression = ManagedMod.ArchiveCompression.Auto; + mod.RootFolder = "Data"; + } + + if (stringsFolderFound || videoFolderFound) + { + mod.Method = ManagedMod.DeploymentMethod.LooseFiles; + mod.RootFolder = "Data"; + } + + if (dllFound || dataFolderFound) + { + mod.Method = ManagedMod.DeploymentMethod.LooseFiles; + mod.RootFolder = "."; + } + + if (generalFoldersFound) + { + mod.Method = ManagedMod.DeploymentMethod.SeparateBA2; + mod.Format = ManagedMod.ArchiveFormat.General; + mod.Compression = ManagedMod.ArchiveCompression.Compressed; + mod.RootFolder = "Data"; + } + + if (texturesFolderFound) + { + mod.Method = ManagedMod.DeploymentMethod.SeparateBA2; + mod.Format = ManagedMod.ArchiveFormat.Textures; + mod.Compression = ManagedMod.ArchiveCompression.Compressed; + mod.RootFolder = "Data"; + } + + if (soundFoldersFound) + { + mod.Method = ManagedMod.DeploymentMethod.SeparateBA2; + mod.Format = ManagedMod.ArchiveFormat.General; + mod.Compression = ManagedMod.ArchiveCompression.Uncompressed; + mod.RootFolder = "Data"; + } + + if (generalFoldersFound && texturesFolderFound || + generalFoldersFound && soundFoldersFound || + texturesFolderFound && soundFoldersFound) + { + mod.Method = ManagedMod.DeploymentMethod.BundledBA2; + mod.Format = ManagedMod.ArchiveFormat.Auto; + mod.Compression = ManagedMod.ArchiveCompression.Auto; + mod.RootFolder = "Data"; + } + } + + public static void CleanUpFolder(string folderPath, Action ProgressChanged = null) + { + ProgressChanged?.Invoke(Progress.Indetermined("Cleaning up mod folder.")); + + foreach (string subFolderPath in Directory.EnumerateDirectories(folderPath)) + { + string subFolderName = Path.GetFileName(subFolderPath).ToLower(); + + // Move data folder one up: + if (subFolderName == "data") + ModInstallations.MoveDirectory(subFolderPath, folderPath); + } + + foreach (String filePath in Directory.EnumerateFiles(folderPath)) + { + string fileExtension = Path.GetExtension(filePath).ToLower().Trim(); + + // Extract archives within folder: + if (fileExtension == ".ba2" || Utils.SevenZipSupportedFileTypes.Contains(fileExtension)) + { + ModInstallations.ExtractArchive(filePath, folderPath, ProgressChanged); + File.Delete(filePath); + } + + // Delete crap: + else if (fileExtension == ".txt") + File.Delete(filePath); + } + } + } +} diff --git a/Fo76ini/Mods/ModDeployment.cs b/Fo76ini/Mods/ModDeployment.cs new file mode 100644 index 0000000..0efc5ce --- /dev/null +++ b/Fo76ini/Mods/ModDeployment.cs @@ -0,0 +1,607 @@ +using Fo76ini.Utilities; +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading; + +namespace Fo76ini.Mods +{ + /// + /// Bundles functions that add, remove, or change game files. + /// Managed mods --> Game files + /// + public static class ModDeployment + { + // TODO: Clean FrozenData? + public static Log LogFile; + + static ModDeployment() + { + ModDeployment.LogFile = new Log(Log.GetFilePath("modmanager.log.txt")); + } + + public static void Deploy(ManagedMods mods, Action ProgressChanged, bool invalidateBundledFrozenArchives = true) + { + LogFile.WriteLine("\n\n"); + LogFile.WriteTimeStamp(); + LogFile.WriteLine($"Version {Shared.VERSION}, deploying..."); + + // TODO: More descriptive ProgressChanged + ProgressChanged?.Invoke(Progress.Indetermined("Deploying...")); + + // Check for conflicts: + LogFile.WriteLine("Checking for conflicting archive names..."); + List conflicts = ModHelpers.GetConflictingArchiveNames(mods.Mods); + if (conflicts.Count > 0) + { + LogFile.WriteLine("Conflicts found, abort."); + foreach (ModHelpers.Conflict conflict in conflicts) + LogFile.WriteLine($" Conflict: {conflict.conflictText}"); + throw new DeploymentFailedException("Conflicting archive names."); + } + + // Restore *.dll files: + RestoreAddedDLLs(mods.GamePath); + + // Remove all currently deployed mods: + ProgressChanged?.Invoke(Progress.Indetermined("Removing mods...")); + ModDeployment.RemoveAll(mods); + mods.Save(); + + // If mods are enabled: + if (!mods.ModsDisabled) + { + LogFile.WriteLine("Installing mods..."); + + // Deploy all SeparateBA2 and Loose mods: + foreach (ManagedMod mod in mods) + { + ProgressChanged?.Invoke(Progress.Indetermined($"Deploying {mod.Title}...")); + if (mod.Enabled && + Directory.Exists(mod.ManagedFolderPath) && + !Utils.IsDirectoryEmpty(mod.ManagedFolderPath)) + { + switch (mod.Method) + { + case ManagedMod.DeploymentMethod.SeparateBA2: + DeploySeparateArchive(mod, mods.Resources); + mods.Save(); + break; + case ManagedMod.DeploymentMethod.LooseFiles: + DeployLooseFiles(mods, mod, mods.GamePath); + mods.Save(); + break; + } + } + } + + // Deploy all BundledBA2 mods: + ProgressChanged?.Invoke(Progress.Indetermined($"Building bundled archives...")); + ModDeployment.DeployBundledArchives(mods, IniFiles.Config.GetBool("Mods", "bFreezeBundledArchives", false), invalidateBundledFrozenArchives); + + mods.Save(); + ProgressChanged?.Invoke(Progress.Done("Mods deployed.")); + } + else + ProgressChanged?.Invoke(Progress.Done("Mods removed.")); + + LogFile.WriteLine("Deployment finished."); + } + + /// + /// Used in the deployment chain to deploy a single mod with the Loose method. + /// + private static void DeployLooseFiles(ManagedMods mods, ManagedMod mod, String GamePath) + { + LogFile.WriteLine($" Installing mod '{mod.Title}' as LooseFiles"); + + mod.LooseFiles.Clear(); + + // Iterate over each file in the managed folder ... + foreach (string filePath in Directory.EnumerateFiles(mod.ManagedFolderPath, "*.*", SearchOption.AllDirectories)) + { + // ... extract the relative path ... + string relPath = Utils.MakeRelativePath(mod.ManagedFolderPath, filePath); + mod.LooseFiles.Add(relPath); + + // ... determine the full destination path ... + string destinationPath = Path.Combine(GamePath, mod.RootFolder, relPath); + FileInfo destInfo = new FileInfo(destinationPath); + Directory.CreateDirectory(destInfo.DirectoryName); + + // ... make a backup if the file already exists ... + if (File.Exists(destinationPath) && !DoesLooseFileBelongToMod(mods, destinationPath) && !File.Exists(destinationPath + ".old")) + File.Move(destinationPath, destinationPath + ".old"); + + // ... and copy the file (and replace it if necessary). + LogFile.WriteLine($" Copying: \"{relPath}\""); + if (Configuration.bUseHardlinks) + Utils.CreateHardLink(filePath, destinationPath, true); + else + File.Copy(filePath, destinationPath, true); + } + + mod.CurrentRootFolder = mod.RootFolder; + mod.Deployed = true; + mod.PreviousMethod = ManagedMod.DeploymentMethod.LooseFiles; + } + + /// + /// Used in the deployment chain to deploy a single mod with the SeparateBA2 method. + /// Freezes a mod if necessary. + /// + private static void DeploySeparateArchive(ManagedMod mod, ResourceList resources) + { + LogFile.WriteLine($" Installing mod '{mod.Title}' as SeparateBA2"); + + // If mod is supposed to be deployed frozen... + if (mod.Freeze) + { + // ... freeze if necessary ... + if (!mod.Frozen) + { + //LogFile.WriteLine($" Freezing mod..."); + ModActions.Freeze(mod); + } + + LogFile.WriteLine($" Copying frozen archive..."); + + // ... and copy it to the Data folder. + if (Configuration.bUseHardlinks) + Utils.CreateHardLink( + mod.FrozenArchivePath, + mod.ArchivePath, + true); + else + File.Copy( + mod.FrozenArchivePath, + mod.ArchivePath, + true); + } + + // If mod isn't supposed to be deployed frozen... + else + { + // ... unfreeze mod if needed ... + if (mod.Frozen) + { + LogFile.WriteLine($" Unfreezing mod..."); + ModActions.Unfreeze(mod); + } + + // Getting preset: + Archive2.Preset preset = ModHelpers.GetArchive2Preset(mod); + + LogFile.WriteLine($" Creating new archive..."); + LogFile.WriteLine($" Format: {preset.format}"); + LogFile.WriteLine($" Compression: {preset.compression}"); + + // ... and create a new archive. + Archive2.Create( + mod.ArchivePath, + mod.ManagedFolderPath, + preset); + } + + // Finally, update the disk state ... + mod.CurrentArchiveName = mod.ArchiveName; + mod.CurrentCompression = mod.Frozen ? mod.FrozenCompression : mod.Compression; + mod.CurrentFormat = mod.Frozen ? mod.FrozenFormat : mod.Format; + mod.Deployed = true; + mod.PreviousMethod = ManagedMod.DeploymentMethod.SeparateBA2; + + // ... and add the archive to the resource list. + resources.Add(mod.ArchiveName); + + LogFile.WriteLine($" Installed."); + } + + /// + /// Used in the deployment chain to deploy mods with the BundledBA2 method. + /// + private static void DeployBundledArchives(ManagedMods mods, bool freezeArchives = false, bool invalidateFrozenArchives = true) + { + LogFile.WriteLine($" Installing BundledBA2 mods..."); + DeployArchiveList archives = new DeployArchiveList(mods.GamePath); + + // We want to use frozen archives but haven't invalidated them... + // ... so just copy bundled archives if available: + if (freezeArchives && !invalidateFrozenArchives) + { + CopyFrozenBundledArchives(mods.Resources, archives); + return; + } + + // Otherwise iterate over each enabled mod... + foreach (ManagedMod mod in mods) + { + if (mod.Enabled && mod.Method == ManagedMod.DeploymentMethod.BundledBA2) + { + LogFile.WriteLine($" Copy files of mod '{mod.Title}' to temp folder..."); + + // ... copy it's files into temporary folders ... + CopyFilesToTempSorted(mod, archives); + mod.Deployed = true; + mod.PreviousMethod = ManagedMod.DeploymentMethod.BundledBA2; + } + } + + // ... and pack those folders to archives. + PackBundledArchives(mods.Resources, archives, freezeArchives); + } + + /// + /// Used in the deployment chain to copy frozen bundled archives from FrozenData to Data. + /// + private static void CopyFrozenBundledArchives(ResourceList resources, DeployArchiveList archives) + { + LogFile.WriteLine($" Copy frozen bundled archives..."); + + // For each archive... + foreach (DeployArchive archive in archives) + { + // ... if it had been frozen ... + if (File.Exists(archive.GetFrozenArchivePath())) + { + LogFile.WriteLine($" Copying {archive.ArchiveName}"); + + // ... copy it into the Data folder ... + if (Configuration.bUseHardlinks) + Utils.CreateHardLink(archive.GetFrozenArchivePath(), archive.GetArchivePath(), true); + else + File.Copy(archive.GetFrozenArchivePath(), archive.GetArchivePath(), true); + + // ... and add it to the resource list. + resources.Insert(0, archive.ArchiveName); + } + } + } + + /// + /// Used in the deployment chain to pack each bundled temporary folder to an archive. + /// + private static void PackBundledArchives(ResourceList resources, DeployArchiveList archives, bool freezeArchives) + { + // For each archive... + foreach (DeployArchive archive in archives.Reverse()) + { + // ... if needed ... + if (archive.Count > 0 && !Utils.IsDirectoryEmpty(archive.TempPath)) + { + // ... pack the temporary folder to an archive ... + if (freezeArchives) + { + LogFile.WriteLine($" Freezing archive '{archive.ArchiveName}'"); + + // either freeze to FrozenData and then copy to Data: + Archive2.Create(archive.GetFrozenArchivePath(), archive.TempPath, archive.Compression, archive.Format); + + if (Configuration.bUseHardlinks) + Utils.CreateHardLink(archive.GetFrozenArchivePath(), archive.GetArchivePath(), true); + else + File.Copy(archive.GetFrozenArchivePath(), archive.GetArchivePath(), true); + } + else + { + LogFile.WriteLine($" Creating archive '{archive.ArchiveName}'"); + + // or create directly in Data: + Archive2.Create(archive.GetArchivePath(), archive.TempPath, archive.Compression, archive.Format); + } + + // ... and add it to the resource list. + resources.Insert(0, archive.ArchiveName); + } + } + + // Clean up after we're finished. + LogFile.WriteLine($" Deleting temporary folder..."); + archives.DeleteTempFolder(); + } + + /// + /// Used in the deployment chain to copy individual files to a temporary folder. + /// It sorts files into different temporary folders. + /// Each temporary folder gets packed to a bundled *.ba2 archive. + /// + private static void CopyFilesToTempSorted(ManagedMod mod, DeployArchiveList archives) + { + // Iterate over each file in the managed folder: + IEnumerable files = Directory.EnumerateFiles(mod.ManagedFolderPath, "*.*", SearchOption.AllDirectories); + foreach (string filePath in files) + { + FileInfo info = new FileInfo(filePath); + string fileExtension = info.Extension.ToLower(); + + // Make a relative path: + string relativePath = Utils.MakeRelativePath(mod.ManagedFolderPath, filePath); + + // Determine the type of archive: + string destinationPath; + if (relativePath.Trim().ToLower().StartsWith("sound") || relativePath.Trim().ToLower().StartsWith("music") || + (new string[] { ".wav", ".xwm", ".fuz", ".lip" }).Contains(fileExtension)) + { + archives.SoundsArchive.Count++; + destinationPath = Path.Combine(archives.SoundsArchive.TempPath, relativePath); + } + else if (fileExtension == ".dds") + { + archives.TexturesArchive.Count++; + destinationPath = Path.Combine(archives.TexturesArchive.TempPath, relativePath); + } + else + { + archives.GeneralArchive.Count++; + destinationPath = Path.Combine(archives.GeneralArchive.TempPath, relativePath); + } + + // Copy the file to the correct temp folder: + Directory.CreateDirectory(Path.GetDirectoryName(destinationPath)); + + if (Configuration.bUseHardlinks) + Utils.CreateHardLink(filePath, destinationPath, true); + else + File.Copy(filePath, destinationPath, true); + } + } + + public static void RemoveAll(ManagedMods mods) + { + LogFile.WriteLine("Removing all installed mods"); + + // Delete bundled archives: + DeployArchiveList deployArchives = new DeployArchiveList(mods.GamePath); + foreach (DeployArchive deployArchive in deployArchives) + { + LogFile.WriteLine($" Removing {deployArchive.ArchiveName}"); + if (File.Exists(deployArchive.GetArchivePath())) + File.Delete(deployArchive.GetArchivePath()); + mods.Resources.Remove(deployArchive.ArchiveName); + } + LogFile.WriteLine($" Deleting temporary folders"); + deployArchives.DeleteTempFolder(); + + // Remove mods: + foreach (ManagedMod mod in mods) + { + LogFile.WriteLine($" Removing mod {mod.Title}"); + ModDeployment.Remove(mod, mods.Resources, mods.GamePath); + } + + mods.Save(); + } + + private static void Remove(ManagedMod mod, ResourceList resources, String GamePath) + { + if (mod.Deployed) + { + switch (mod.PreviousMethod) + { + case ManagedMod.DeploymentMethod.BundledBA2: + LogFile.WriteLine($" Skipped (mod is bundled)"); + break; + + case ManagedMod.DeploymentMethod.SeparateBA2: + LogFile.WriteLine($" Deleting {mod.CurrentArchiveName}"); + File.Delete(mod.CurrentArchivePath); + resources.Remove(mod.CurrentArchiveName); + break; + + case ManagedMod.DeploymentMethod.LooseFiles: + LogFile.WriteLine($" Deleting loose files"); + foreach (string relFilePath in mod.LooseFiles) + { + string installedFilePath = Path.GetFullPath(Path.Combine(GamePath, mod.CurrentRootFolder, relFilePath)); // .Replace("\\.\\", "\\") + + // Delete file, if existing: + if (File.Exists(installedFilePath)) + File.Delete(installedFilePath); + + // Rename backup, if there is one: + if (File.Exists(installedFilePath + ".old")) + File.Move(installedFilePath + ".old", installedFilePath); + + // Remove empty folders one by one, if existing: + else + RemoveEmptyFolders(Path.GetDirectoryName(installedFilePath)); + } + mod.LooseFiles.Clear(); + break; + } + + mod.Deployed = false; + } + } + + // Use lower-case, plz + private static List whitelistedDlls = new List() { + "bink2w64.dll", + "chrome_elf.dll", + "concrt140.dll", + "d3dcompiler_43.dll", + "libcef.dll", + "libegl.dll", // "libEGL.dll", + "libglesv2.dll", // "libGLESv2.dll", + "msvcp140.dll", + "ortp_x64.dll", + "steam_api64.dll", + "vccorlib140.dll", + "vcruntime140.dll", + "vivoxsdk_x64.dll", + "d3dcompiler_46.dll", + "d3dcompiler_47.dll" + // "x3daudio1_7.dll" ? + }; + + public static void RenameAddedDLLs(string GamePath) + { + LogFile.WriteLine("Renaming non-whitelisted *.dll to *.dll.nwmode"); + // Iterate through every *.dll file in game path: + IEnumerable files = Directory.EnumerateFiles(GamePath, "*.dll"); + foreach (string filePath in files) + { + // If not whitelisted... + string fileName = Path.GetFileName(filePath); + if (!whitelistedDlls.Contains(fileName.ToLower())) + { + // ... rename it: + if (!File.Exists(filePath + ".nwmode")) + { + File.Move(filePath, filePath + ".nwmode"); + LogFile.WriteLine($" Renamed {fileName}"); + } + + // ... or delete it: + else + { + File.Delete(filePath); + LogFile.WriteLine($" Deleted {fileName}"); + } + } + } + } + + public static void RestoreAddedDLLs(string GamePath) + { + LogFile.WriteLine("Renaming *.dll.nwmode to *.dll"); + // Iterate through every *.dll.nwmode file in game path: + IEnumerable files = Directory.EnumerateFiles(GamePath, "*.dll.nwmode"); + foreach (string filePath in files) + { + string fileName = Path.GetFileName(filePath); + string originalFilePath = Path.Combine(Path.GetDirectoryName(filePath), fileName.Replace(".dll.nwmode", ".dll")); + + // Rename or delete, if the original exists: + if (!File.Exists(originalFilePath)) + { + File.Move(filePath, originalFilePath); + LogFile.WriteLine($" Renamed {fileName}"); + } + else + { + // Assuming that the same *.dll file has been copied during deployment: + File.Delete(filePath); // we can just delete it. + LogFile.WriteLine($" Deleted {fileName}"); + } + } + } + + private static void RemoveEmptyFolders(string parent) + { + while (Directory.Exists(parent) && Utils.IsDirectoryEmpty(parent)) + { + Directory.Delete(parent); + parent = Path.GetDirectoryName(parent); + } + } + + /// + /// Searches through each mod.LooseFiles entry to find if the file belongs to a mod. + /// + /// + /// Has to be a full path, not a relative path + /// true, if a mod has installed this file. false otherwise. + private static bool DoesLooseFileBelongToMod(ManagedMods mods, string fullPath) + { + foreach (ManagedMod mod in mods) + { + if (mod.PreviousMethod == ManagedMod.DeploymentMethod.LooseFiles) + { + foreach (string relPath in mod.LooseFiles) + { + string installedPath = Path.Combine(mods.GamePath, mod.RootFolder, relPath); + if (installedPath == fullPath) + return true; + } + } + } + return false; + } + + private class DeployArchiveList : IEnumerable + { + public DeployArchive GeneralArchive; + public DeployArchive TexturesArchive; + public DeployArchive SoundsArchive; + + public string GamePath; + public string TempPath; + + public DeployArchiveList(String gamePath) + { + this.GamePath = gamePath; + this.TempPath = Path.Combine(GamePath, "tmp"); + + GeneralArchive = new DeployArchive("General", GamePath, TempPath); + TexturesArchive = new DeployArchive("Textures", GamePath, TempPath); + TexturesArchive.Format = Archive2.Format.DDS; + SoundsArchive = new DeployArchive("Sounds", GamePath, TempPath); + SoundsArchive.Compression = Archive2.Compression.None; + } + + public void DeleteTempFolder() + { + if (Directory.Exists(TempPath)) + Directory.Delete(TempPath, true); + } + + public List GetList() + { + return new List() { GeneralArchive, TexturesArchive, SoundsArchive }; + } + + public IEnumerator GetEnumerator() + { + return this.GetList().GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + } + + private class DeployArchive + { + public string GamePath; + public string TempPath; + public string ArchiveName; + public Archive2.Format Format = Archive2.Format.General; + public Archive2.Compression Compression = Archive2.Compression.Default; + public int Count = 0; + + public DeployArchive(string name, string gamePath, string tempFolderPath) + { + this.GamePath = gamePath; + this.TempPath = Path.Combine(tempFolderPath, name); + if (name == "General") + this.ArchiveName = "Bundled.ba2"; + else + this.ArchiveName = "Bundled - " + name + ".ba2"; + + /*if (Directory.Exists(this.tempPath)) + Directory.Delete(this.tempPath, true);*/ + Directory.CreateDirectory(this.TempPath); + } + + public string GetArchivePath() + { + return Path.Combine(GamePath, "Data", this.ArchiveName); + } + + public string GetFrozenArchivePath() + { + return Path.Combine(GamePath, "FrozenData", this.ArchiveName); + } + } + + public class DeploymentFailedException : Exception + { + public DeploymentFailedException() { } + public DeploymentFailedException(string message) : base(message) { } + public DeploymentFailedException(string message, Exception inner) : base(message, inner) { } + } + } +} diff --git a/Fo76ini/Mods/ModHelpers.cs b/Fo76ini/Mods/ModHelpers.cs new file mode 100644 index 0000000..cb27a4d --- /dev/null +++ b/Fo76ini/Mods/ModHelpers.cs @@ -0,0 +1,182 @@ +using Fo76ini.Utilities; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; + +namespace Fo76ini.Mods +{ + /// + /// Bundles functions that help with working with mods. + /// They don't affect any files and don't change any state. + /// + public static class ModHelpers + { + public static string[] ResourceFolders = new string[] { "meshes", "strings", "music", "sound", "textures", "materials", "interface", "geoexporter", "programs", "vis", "scripts", "misc", "shadersfx", "lodsettings", "video" }; + public static string[] GeneralFolders = new string[] { "meshes", "strings", "interface", "materials" }; + public static string[] TextureFolders = new string[] { "textures", "effects" }; + public static string[] SoundFolders = new string[] { "sound", "music" }; + + /// + /// Converts ManagedMod.ArchiveCompression and ManagedMod.ArchiveFormat to an Archive2.Preset. + /// Automatically determines appropriate compression and format if needed. + /// + public static Archive2.Preset GetArchive2Preset(ManagedMod mod) + { + return GetArchive2Preset(mod.ManagedFolderPath, mod.Format, mod.Compression); + } + + /// + /// Converts ManagedMod.ArchiveCompression and ManagedMod.ArchiveFormat to an Archive2.Preset. + /// Automatically determines appropriate compression and format if needed. + /// + public static Archive2.Preset GetArchive2Preset(String managedFolderPath, ManagedMod.ArchiveFormat format, ManagedMod.ArchiveCompression compression) + { + var preset = new Archive2.Preset(); + + // No detection needed, "convert" ArchiveCompression to Archive2.Compression and ArchiveFormat to Archive2.Format: + if (compression != ManagedMod.ArchiveCompression.Auto && format != ManagedMod.ArchiveFormat.Auto) + { + preset.compression = compression == ManagedMod.ArchiveCompression.Compressed ? Archive2.Compression.Default : Archive2.Compression.None; + preset.format = format == ManagedMod.ArchiveFormat.General ? Archive2.Format.General : Archive2.Format.DDS; + + return preset; + } + + // Detect mod type: + + int generalFoldersCount = 0; + int textureFoldersCount = 0; + int soundFoldersCount = 0; + + IEnumerable folders = Directory.EnumerateDirectories(managedFolderPath); + foreach (string path in folders) + { + string folderName = Path.GetFileName(path).ToLower(); + + if (GeneralFolders.Contains(folderName)) + generalFoldersCount++; + else if (TextureFolders.Contains(folderName)) + textureFoldersCount++; + else if (SoundFolders.Contains(folderName)) + soundFoldersCount++; + } + + if (soundFoldersCount > generalFoldersCount && soundFoldersCount > textureFoldersCount) + { + preset.compression = Archive2.Compression.None; + preset.format = Archive2.Format.General; + } + else if (textureFoldersCount > generalFoldersCount && textureFoldersCount > soundFoldersCount) + { + preset.compression = Archive2.Compression.Default; + preset.format = Archive2.Format.DDS; + } + else + { + preset.compression = Archive2.Compression.Default; + preset.format = Archive2.Format.General; + } + + return preset; + } + + /// + /// Represents a conflict between mods. Used as the return value of the GetConflictingFiles() and the GetConflictingArchiveNames() methods. + /// + public struct Conflict + { + public string conflictText; + public string conflictingArchiveName; + public List conflictingFiles; + } + + /// + /// Checks if enabled mods lower on the list overwrite files of enabled mods higher on the list. + /// + /// A list of conflicting mods. + public static List GetConflictingFiles(List mods) + { + List conflictingMods = new List(); + + // Mods higher in the list (upperMod) can get overwritten by mods lower in the list (lowerMod). + + // Iterate over all mods: + for (int i = 1; i < mods.Count; i++) + { + ManagedMod lowerMod = mods[i]; + string lowerPath = lowerMod.ManagedFolderPath; + + // If not enabled or non-existant, we don't need to check. + if (!lowerMod.Enabled || !Directory.Exists(lowerPath)) + continue; + + // Get a list of files with relative paths: + List lowerRelPaths = new List(); + foreach (string filePath in Directory.EnumerateFiles(lowerPath, "*.*", SearchOption.AllDirectories)) + lowerRelPaths.Add(Utils.MakeRelativePath(lowerPath, filePath)); + + // Iterate over all mods whose files could get overwritten: + for (int l = 0; l < i; l++) + { + ManagedMod upperMod = mods[l]; + string upperPath = upperMod.ManagedFolderPath; + + // If not enabled or non-existant, we don't need to check. + if (!upperMod.Enabled || !Directory.Exists(upperPath)) + continue; + + Conflict conflict = new Conflict(); + conflict.conflictingFiles = new List(); + conflict.conflictText = lowerMod.Title + " overrides " + upperMod.Title; + + // For each file... + foreach (string filePath in Directory.EnumerateFiles(upperPath, "*.*", SearchOption.AllDirectories)) + { + string relUpperPath = Utils.MakeRelativePath(upperPath, filePath); + + // ... check if it gets overwritten by the lower mod: + if (lowerRelPaths.Contains(relUpperPath)) + { + // If it does, add it to the list of conflicting files: + if (!conflict.conflictingFiles.Contains(relUpperPath)) + conflict.conflictingFiles.Add(relUpperPath); + } + } + + // Add the conflict to the conflictingMods list, if files get overwritten: + if (conflict.conflictingFiles.Count > 0) + conflictingMods.Add(conflict); + } + } + return conflictingMods; + } + + /// + /// Searches through the list of mods and returns a list of conflicting archive names. + /// + public static List GetConflictingArchiveNames(List mods) + { + List customArchiveNames = new List(); + List conflictingArchiveNames = new List(); + foreach (ManagedMod mod in mods) + { + if (mod.Method == ManagedMod.DeploymentMethod.SeparateBA2 && mod.Enabled) + { + if (customArchiveNames.Contains(mod.ArchiveName.ToLower())) + { + Conflict conflict = new Conflict(); + conflict.conflictText = $"{mod.Title} uses a taken archive name: {mod.ArchiveName}"; + conflict.conflictingArchiveName = mod.ArchiveName; + conflictingArchiveNames.Add(conflict); + } + else + { + customArchiveNames.Add(mod.ArchiveName.ToLower()); + } + } + } + return conflictingArchiveNames; + } + } +} diff --git a/Fo76ini/Mods/ModInstallations.cs b/Fo76ini/Mods/ModInstallations.cs new file mode 100644 index 0000000..0dddfb5 --- /dev/null +++ b/Fo76ini/Mods/ModInstallations.cs @@ -0,0 +1,342 @@ +using Fo76ini.Interface; +using Fo76ini.Utilities; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; + +namespace Fo76ini.Mods +{ + /// + /// Bundles methods that handle the installation and import of mods. + /// External files --> Managed mods + /// + public static class ModInstallations + { + /// + /// Adds a new blank mod. + /// + public static void InstallBlank(ManagedMods mods) + { + ManagedMod newMod = new ManagedMod(mods.GamePath); + newMod.Title = "Untitled"; + newMod.ArchiveName = "untitled.ba2"; + Directory.CreateDirectory(newMod.ManagedFolderPath); + mods.Add(newMod); + mods.Save(); + } + + /// + /// Extracts the archive and adds the mod to the list. + /// Saves the xml file afterwards. + /// + /// When false, creates a new "frozen" mod. + public static void InstallArchive(ManagedMods mods, string filePath, bool useSourceBA2Archive = false, Action ProgressChanged = null) + { + ManagedMod newMod = ModInstallations.FromArchive(mods.GamePath, filePath, useSourceBA2Archive, ProgressChanged); + mods.Add(newMod); + mods.Save(); + ProgressChanged?.Invoke(Progress.Done("Mod archive installed.")); + } + + /// + /// Creates a new mod from any supported archive. (zip, tar, rar, 7z, ba2) + /// BA2 files can be installed frozen if needed. + /// + /// Path to the game installation + /// Path to archive + /// When false, creates a new "frozen" mod. + /// + private static ManagedMod FromArchive(string gamePath, string filePath, bool useSourceBA2Archive = false, Action ProgressChanged = null) + { + // Get path information: + string longFilePath = EnsureLongPathSupport(filePath); + string fileNameWOEx = Path.GetFileNameWithoutExtension(longFilePath); + string fileExtension = Path.GetExtension(longFilePath); + + // Install mod: + ManagedMod newMod = new ManagedMod(gamePath); + newMod.Title = fileNameWOEx; + newMod.ArchiveName = fileNameWOEx + ".ba2"; + + // Extract mod: + ProgressChanged?.Invoke(Progress.Indetermined($"Extracting {Path.GetFileName(filePath)}")); + ModInstallations.ExtractArchive(longFilePath, newMod.ManagedFolderPath); + + // Freeze mod conditionally: + if (useSourceBA2Archive && fileExtension == ".ba2") + { + // Copy *.ba2 into FrozenData: + FileInfo frozenPath = new FileInfo(newMod.FrozenArchivePath); + ProgressChanged?.Invoke(Progress.Indetermined($"Copying {Path.GetFileName(filePath)} to {frozenPath.DirectoryName}")); + Directory.CreateDirectory(frozenPath.DirectoryName); + File.Copy(longFilePath, frozenPath.FullName, true); + + newMod.Frozen = true; + newMod.Freeze = true; + newMod.PreviousMethod = ManagedMod.DeploymentMethod.SeparateBA2; + newMod.Method = ManagedMod.DeploymentMethod.SeparateBA2; + } + else + { + ModActions.CleanUpFolder(newMod.ManagedFolderPath, ProgressChanged); + ModActions.DetectOptimalModInstallationOptions(newMod); + } + + return newMod; + } + + /// + /// Extracts the archive and then copy and replaces from the temp folder into the managed mod folder. + /// + public static void AddArchive(ManagedMod mod, string filePath, Action ProgressChanged = null) + { + string longFilePath = EnsureLongPathSupport(filePath); + string tempFolderPath = Path.Combine(Path.GetTempPath(), $"tmp_{mod.guid}"); + if (Directory.Exists(tempFolderPath)) + Directory.Delete(tempFolderPath, true); + Directory.CreateDirectory(tempFolderPath); + + ProgressChanged?.Invoke(Progress.Indetermined($"Extracting {Path.GetFileName(filePath)}")); + ModInstallations.ExtractArchive(longFilePath, tempFolderPath); + ModActions.CleanUpFolder(tempFolderPath, ProgressChanged); + CopyDirectory(tempFolderPath, mod.ManagedFolderPath, ProgressChanged); + + Directory.Delete(tempFolderPath, true); + + ProgressChanged?.Invoke(Progress.Done("Archive added to mod.")); + } + + /// + /// Copies the folder and adds the mod to the list. + /// Saves the xml file afterwards. + /// + public static void InstallFolder(ManagedMods mods, string folderPath, Action ProgressChanged = null) + { + ManagedMod newMod = ModInstallations.FromFolder(mods.GamePath, folderPath, ProgressChanged); + mods.Add(newMod); + mods.Save(); + ProgressChanged?.Invoke(Progress.Done("Mod folder installed.")); + } + + /// + /// Creates a new mod from a folder. + /// + /// Path to the game installation + /// Path to folder + /// + private static ManagedMod FromFolder(string gamePath, string folderPath, Action ProgressChanged = null) + { + // Get path information: + folderPath = EnsureLongPathSupport(folderPath); + string folderName = Path.GetFileName(folderPath); + + // Install mod: + ManagedMod newMod = new ManagedMod(gamePath); + newMod.Title = folderName; + newMod.ArchiveName = folderName + ".ba2"; + + // Copy folder: + CopyDirectory(folderPath, newMod.ManagedFolderPath, ProgressChanged); + + ModActions.CleanUpFolder(newMod.ManagedFolderPath, ProgressChanged); + ModActions.DetectOptimalModInstallationOptions(newMod); + + return newMod; + } + + /// + /// Copies and replaces from the external folder into the managed mod folder. + /// + /// If true, will copy the folder instead of it's contents. + public static void AddFolder(ManagedMod mod, string folderPath, bool copyFolder, Action ProgressChanged = null) + { + string longFolderPath = EnsureLongPathSupport(folderPath); + string folderName = Path.GetFileName(folderPath); + CopyDirectory(longFolderPath, + copyFolder ? Path.Combine(mod.ManagedFolderPath, folderName) : mod.ManagedFolderPath, + ProgressChanged); + // TODO: ModActions.CleanUpFolder(newMod.ManagedFolderPath, ProgressChanged); + ProgressChanged?.Invoke(Progress.Done("Folder added to mod.")); + } + + /// + /// Looks through the resource lists in the *.ini and imports *.ba2 archives. + /// + public static void ImportInstalledMods(ManagedMods mods, Action ProgressChanged = null) + { + // TODO: ProgressChanged for ImportInstalledMods + ProgressChanged?.Invoke(Progress.Indetermined("Importing already installed mods...")); + + // Get all archives: + ResourceList IndexFileList = ResourceList.GetResourceIndexFileList(); + ResourceList Archive2List = ResourceList.GetResourceArchive2List(); + + /* + * Prepare list: + */ + + // Add all archives: + List installedMods = new List(); + installedMods.AddRange(IndexFileList); + installedMods.AddRange(Archive2List); + installedMods.AddRange(mods.Resources); + + // Remove bundled archives: + installedMods = installedMods.FindAll(e => !e.ToLower().Contains("bundled")); + + // Remove currently managed archives: + foreach (ManagedMod mod in mods) + if (mod.PreviousMethod == ManagedMod.DeploymentMethod.SeparateBA2) + installedMods.Remove(mod.CurrentArchiveName); + + // Ignore any game files ("SeventySix - *.ba2"): + foreach (string archiveName in IndexFileList) + if (archiveName.StartsWith("SeventySix")) + installedMods.Remove(archiveName); + foreach (string archiveName in Archive2List) + if (archiveName.StartsWith("SeventySix")) + installedMods.Remove(archiveName); + foreach (string archiveName in mods.Resources) + if (archiveName.StartsWith("SeventySix")) + installedMods.Remove(archiveName); + + /* + * Import installed mods: + */ + + foreach (string archiveName in installedMods) + { + string path = Path.Combine(mods.GamePath, "Data", archiveName); + Console.WriteLine(path); + if (File.Exists(path)) + { + // Import archive: + ModInstallations.InstallArchive(mods, path, true); + File.Delete(path); + + // Remove from lists: + IndexFileList.Remove(archiveName); + Archive2List.Remove(archiveName); + } + } + + // Save *.ini files: + IndexFileList.CommitToINI(); + Archive2List.CommitToINI(); + //IniFiles.Instance.SaveAll(); + + mods.Save(); + } + + /// + /// Extracts an archive into the given folder. (Throws exceptions) + /// + /// + /// + /// + public static void ExtractArchive(string archivePath, string destinationPath, Action ProgressChanged = null) + { + // TODO: Make a ModUtilities.cs? + string filePath = Path.GetFullPath(archivePath); + string fileName = Path.GetFileName(filePath); + string fileExtension = Path.GetExtension(filePath); + + Directory.CreateDirectory(destinationPath); + + ProgressChanged?.Invoke(Progress.Indetermined($"Extracting {fileName} ...")); + + /* + * Depending on file extention: + */ + + // Use Archive2.exe to extract: + if (fileExtension.ToLower() == ".ba2") + Archive2.Extract(filePath, destinationPath); + + // Use 7-Zip (7za.exe) to extract: + else if (Utils.SevenZipSupportedFileTypes.Contains(fileExtension.ToLower())) + Utils.ExtractArchive(filePath, destinationPath); + + // Not supported: + else + throw new NotSupportedException($"File type not supported: {fileExtension}"); + + + ProgressChanged?.Invoke(Progress.Done("Extracting finished.")); + } + + /// + /// Recursively copy every file and subdirectory to a new destination. + /// + /// Path *from* where we copy files. + /// Path *to* where we copy files. + public static void CopyDirectory(string sourcePath, string destinationPath, Action ProgressChanged = null) + { + Directory.CreateDirectory(destinationPath); + + DirectoryInfo dir = new DirectoryInfo(sourcePath); + + foreach (FileInfo file in dir.EnumerateFiles("*.*", SearchOption.TopDirectoryOnly)) + { + file.CopyTo(Path.Combine(destinationPath, file.Name), true); + ProgressChanged?.Invoke(Progress.Indetermined($"Copying {file.Name} ({Utils.GetFormatedSize(file.Length)})")); + } + + foreach (DirectoryInfo subdir in dir.GetDirectories()) + CopyDirectory(subdir.FullName, Path.Combine(destinationPath, subdir.Name)); + } + + /// + /// Recursively move every file and subdirectory to a new destination. + /// + /// Path *from* where we move files. + /// Path *to* where we move files. + public static void MoveDirectory(string sourcePath, string destinationPath, Action ProgressChanged = null) + { + Directory.CreateDirectory(destinationPath); + + DirectoryInfo dir = new DirectoryInfo(sourcePath); + + foreach (FileInfo file in dir.EnumerateFiles("*.*", SearchOption.TopDirectoryOnly)) + { + // file.MoveTo has no "bool overwrite" for some reason: + file.CopyTo(Path.Combine(destinationPath, file.Name), true); + file.Delete(); + ProgressChanged?.Invoke(Progress.Indetermined($"Moving {file.Name} ({Utils.GetFormatedSize(file.Length)})")); + } + + foreach (DirectoryInfo subdir in dir.GetDirectories()) + MoveDirectory(subdir.FullName, Path.Combine(destinationPath, subdir.Name)); + + if (Directory.EnumerateFileSystemEntries(sourcePath).Count() == 0) + Directory.Delete(sourcePath); + } + + /// + /// If a path exceeds the 259 character limit, all io methods stop working. + /// Adding @"\\?\" to the beginning of a path works around this issue. + /// + /// + /// The file path with an added @"\\?\" at the beginning if needed. + public static string EnsureLongPathSupport(string filePath) + { + /* + string fullFilePath = Path.GetFullPath(filePath); + if (fullFilePath.Length > 259 && Directory.Exists(@"\\?\" + fullFilePath)) + fullFilePath = @"\\?\" + fullFilePath; + */ + if (!File.Exists(filePath)) + { + // Path too long? + // https://stackoverflow.com/questions/5188527/how-to-deal-with-files-with-a-name-longer-than-259-characters + // https://docs.microsoft.com/de-de/archive/blogs/jeremykuhne/more-on-new-net-path-handling + if (File.Exists(@"\\?\" + filePath)) + { + filePath = @"\\?\" + filePath; + } + } + return filePath; + } + } +} diff --git a/Fo76ini/Mods/Mods.cs b/Fo76ini/Mods/Mods.cs deleted file mode 100644 index 075ad95..0000000 --- a/Fo76ini/Mods/Mods.cs +++ /dev/null @@ -1,2320 +0,0 @@ -using Fo76ini.Mods; -using Newtonsoft.Json.Linq; -using SharpCompress.Common; -using SharpCompress.Readers; -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Drawing; -using System.IO; -using System.Linq; -using System.Net; -using System.Text; -using System.Threading; -using System.Threading.Tasks; -using System.Windows.Forms; -using System.Xml.Linq; - -namespace Fo76ini -{ - public class Mod - { - public enum FileType - { - Loose, - BundledBA2, - SeparateBA2 - } - - public enum ArchiveFormat - { - Auto, - General, - Textures - } - - public enum ArchiveCompression - { - Auto, - Compressed, - Uncompressed - } - - private String title; - private String managedFolderName; - public Mod.FileType Type; - private String root; - private bool enabled; - - public int ID = -1; - private String url = ""; - public String Version = ""; - /*public String LatestVersion = ""; - public String ThumbnailURL = ""; - public String Thumbnail = ""; - public String PublicName = "";*/ - - public String URL - { - get - { - return this.url; - } - set - { - this.url = value; - this.ID = -1; - } - } - - /* Does only apply for FileType.Loose */ - private List looseFiles = new List(); - - /* Does only apply for FileType.SeparateBA2 */ - public Mod.ArchiveCompression Compression = Mod.ArchiveCompression.Auto; - private String archiveName = "untitled.ba2"; - public Mod.ArchiveFormat Format = Mod.ArchiveFormat.Auto; - public bool freeze = false; - private bool frozen = false; - - public Mod() - { - this.title = "Untitled"; - this.managedFolderName = "Untitled"; - this.enabled = false; - this.Type = Mod.FileType.BundledBA2; - this.root = "Data"; - } - - // Deep copy: - public Mod(Mod mod) - { - this.title = mod.title; - this.managedFolderName = mod.managedFolderName; - this.enabled = mod.enabled; - this.Type = mod.Type; - this.root = mod.root; - this.looseFiles = new List(mod.looseFiles); - this.Compression = mod.Compression; - this.Format = mod.Format; - this.archiveName = mod.archiveName; - this.freeze = mod.freeze; - this.frozen = mod.frozen; - - this.ID = mod.ID; - this.URL = mod.URL; - this.Version = mod.Version; - /*this.LatestVersion = mod.LatestVersion; - this.ThumbnailURL = mod.ThumbnailURL; - this.Thumbnail = mod.Thumbnail; - this.PublicName = mod.PublicName;*/ - } - - public Mod CreateCopy() - { - return new Mod(this); - } - - public Mod(String title, String managedFolderName, Mod.FileType type, bool enabled) - { - this.Title = title; - this.ManagedFolder = managedFolderName; - this.isEnabled = enabled; - this.Type = type; - } - - public String Title - { - get { return this.title; } - set { this.title = value.Trim().Length > 0 ? value.Trim() : "Untitled"; } - } - - public String ArchiveName - { - get { return this.archiveName; } - set - { - if (value.Trim().Length < 0) - return; - this.archiveName = Utils.GetValidFileName(value, ".ba2"); - } - } - - public String GetTypeName() - { - return Enum.GetName(typeof(Mod.FileType), (int)this.Type); - } - - public String GetFormatName() - { - return Enum.GetName(typeof(Mod.ArchiveFormat), (int)this.Format); - } - - public String GetManagedPath() - { - return Path.Combine(Shared.GamePath, "Mods", this.ManagedFolder); - } - - public String RootFolder - { - get { return this.root; } - set { this.root = value; } - } - - public String ManagedFolder - { - get { return this.managedFolderName; } - set { this.managedFolderName = value; } - } - - public bool isEnabled - { - get { return this.enabled; } - set { this.enabled = value; } - } - - public bool isFrozen() - { - return this.frozen && File.Exists(GetFrozenArchivePath()); - } - - public void OverwriteFrozen(bool isFrozen) - { - ManagedMods.Instance.logFile.WriteLine($"Manually overwritten: (Mod){this.Title}.frozen = {isFrozen}"); - this.frozen = isFrozen; - } - - public void Freeze (Action updateProgress = null, Action done = null) - { - try - { - // Check if mod is not frozen: - if (this.isFrozen()) - return; - - if (updateProgress != null) - updateProgress($"Freezing {this.Title}", -1); - - // Create archive: - String tempPath = Path.Combine(Shared.GamePath, "Mods", "frozen.ba2"); - Archive2.Create(tempPath, GetManagedPath(), ManagedMods.Instance.GetArchive2Preset(this)); - - // Failed? - if (!File.Exists(tempPath)) - { - ManagedMods.Instance.logFile.WriteLine("Error while freezing mod: Couldn't create *.ba2 file. Please check archive2.log.txt.\n"); - if (done != null) - done(false); - return; - } - - this.frozen = true; - this.freeze = true; - - // Remove contents of managed folder: - if (Directory.Exists(GetManagedPath())) - Directory.Delete(GetManagedPath(), true); - Directory.CreateDirectory(GetManagedPath()); - - // Move frozen.ba2 into folder: - File.Move(tempPath, GetFrozenArchivePath()); - - if (done != null) - done(true); - - } - catch (Archive2Exception ex) - { - ManagedMods.Instance.logFile.WriteLine($"Archive2Exception occured while freezing mod '{this.Title}': {ex.Message}\n{ex.StackTrace}\n"); - MsgBox.Get("archive2InstallRequirements").Show(MessageBoxIcon.Error); - if (done != null) - done(false); - return; - } - catch (Exception ex) - { - ManagedMods.Instance.logFile.WriteLine($"Unhandled exception occured while freezing mod '{this.Title}': {ex.Message}\n{ex.StackTrace}\n"); - if (done != null) - done(false); - } - } - - public void Unfreeze(Action updateProgress = null, Action done = null) - { - try - { - // Check if mod is frozen: - if (!this.isFrozen()) - { - ManagedMods.Instance.logFile.WriteLine($"Cannot unfreeze a mod ('{this.Title}') which isn't frozen.\n"); - if (done != null) - done(false); - return; - } - - if (updateProgress != null) - updateProgress($"Unfreezing {this.Title}", -1); - - this.frozen = false; - this.freeze = false; - - // Move frozen.ba2 out of folder: - String tempPath = Path.Combine(Shared.GamePath, "Mods", "frozen.ba2"); - File.Move(GetFrozenArchivePath(), tempPath); - - // Remove contents of managed folder: - if (Directory.Exists(GetManagedPath())) - Directory.Delete(GetManagedPath(), true); - Directory.CreateDirectory(GetManagedPath()); - - // Extract frozen archive: - Archive2.Extract(tempPath, GetManagedPath()); - - // Remove frozen archive: - File.Delete(tempPath); - - if (done != null) - done(true); - } - catch (Archive2Exception ex) - { - ManagedMods.Instance.logFile.WriteLine($"Archive2Exception occured while unfreezing mod '{this.Title}': {ex.Message}\n{ex.StackTrace}\n"); - MsgBox.Get("archive2InstallRequirements").Show(MessageBoxIcon.Error); - if (done != null) - done(false); - return; - } - catch (Exception ex) - { - ManagedMods.Instance.logFile.WriteLine($"Unhandled exception occured while unfreezing mod '{this.Title}': {ex.Message}\n{ex.StackTrace}\n"); - if (done != null) - done(false); - return; - } - } - - public String GetFrozenArchivePath() - { - return Path.Combine(GetManagedPath(), "frozen.ba2"); - } - - public void AddFile(String path) - { - if (this.Type == Mod.FileType.Loose) - this.looseFiles.Add(path); - else - throw new InvalidOperationException($"Can't add loose files to a \"{this.GetTypeName()}\" type mod."); - } - - public void ClearFiles() - { - this.looseFiles.Clear(); - } - - public List LooseFiles - { - get { return this.looseFiles; } - set - { - if (this.Type == Mod.FileType.Loose) - this.looseFiles = value; - else - throw new InvalidOperationException($"Can't set loose files because mod is of \"{this.GetTypeName()}\" type."); - } - } - - override public String ToString() - { - return $"Mod \"{Title}\":\n Enabled: {isEnabled}\n Installation type: {this.GetTypeName()}\n Root folder: {RootFolder}\n File count: {this.looseFiles.Count}"; - } - - public XElement Serialize() - { - // - XElement xmlMod = new XElement("Mod", - new XAttribute("title", this.title), - new XAttribute("enabled", this.enabled), - new XAttribute("modFolder", this.managedFolderName), - new XAttribute("installType", this.GetTypeName())); - - if (this.URL != "") - xmlMod.Add(new XAttribute("url", this.URL)); - - if (this.Version != "") - xmlMod.Add(new XAttribute("version", this.Version)); - - /*if (this.LatestVersion != "") - xmlMod.Add(new XAttribute("latestVersion", this.LatestVersion)); - - if (this.ThumbnailURL != "") - xmlMod.Add(new XAttribute("thumbnailUrl", this.ThumbnailURL)); - - if (this.Thumbnail != "") - xmlMod.Add(new XAttribute("thumbnail", this.Thumbnail)); - - if (this.PublicName != "") - xmlMod.Add(new XAttribute("publicName", this.PublicName));*/ - - if (this.Type == Mod.FileType.Loose && this.enabled) - foreach (String filePath in this.looseFiles) - xmlMod.Add(new XElement("File", new XAttribute("path", filePath))); - - if (this.Type == Mod.FileType.SeparateBA2) - { - String compressionStr = Enum.GetName(typeof(Mod.ArchiveCompression), (int)Compression); - xmlMod.Add(new XAttribute("archiveName", archiveName)); - xmlMod.Add(new XAttribute("compression", compressionStr)); - xmlMod.Add(new XAttribute("format", this.GetFormatName())); - if (frozen) - xmlMod.Add(new XAttribute("frozen", frozen)); - } - - if (this.Type == Mod.FileType.Loose) - { - xmlMod.Add(new XAttribute("root", this.root)); - } - - return xmlMod; - } - - public static Mod Deserialize(XElement xmlMod) - { - if (xmlMod.Attribute("title") == null || - xmlMod.Attribute("modFolder") == null || - xmlMod.Attribute("enabled") == null || - xmlMod.Attribute("installType") == null) - throw new InvalidDataException("Some attributes are missing."); - Mod mod = new Mod(); - mod.Title = xmlMod.Attribute("title").Value; - mod.ManagedFolder = xmlMod.Attribute("modFolder").Value; - - if (xmlMod.Attribute("url") != null) - mod.URL = xmlMod.Attribute("url").Value; - - if (xmlMod.Attribute("version") != null) - mod.Version = xmlMod.Attribute("version").Value; - - /*if (xmlMod.Attribute("latestVersion") != null) - mod.LatestVersion = xmlMod.Attribute("latestVersion").Value; - - if (xmlMod.Attribute("thumbnailUrl") != null) - mod.ThumbnailURL = xmlMod.Attribute("thumbnailUrl").Value; - - if (xmlMod.Attribute("thumbnail") != null) - mod.Thumbnail = xmlMod.Attribute("thumbnail").Value; - - if (xmlMod.Attribute("publicName") != null) - mod.PublicName = xmlMod.Attribute("publicName").Value;*/ - - try - { - mod.isEnabled = Convert.ToBoolean(xmlMod.Attribute("enabled").Value); - } - catch (FormatException ex) - { - throw new InvalidDataException($"Invalid 'enabled' value: {xmlMod.Attribute("enabled").Value}"); - } - switch (xmlMod.Attribute("installType").Value) - { - case "Loose": - mod.Type = Mod.FileType.Loose; - break; - case "BA2Archive": // Backward compatibility - case "BundledBA2": - case "BundledBA2Textures": // Backward compatibility - mod.Type = Mod.FileType.BundledBA2; - break; - case "SeparateBA2": - mod.Type = Mod.FileType.SeparateBA2; - break; - default: - throw new InvalidDataException($"Invalid mod installation type: {xmlMod.Attribute("installType").Value}"); - } - if (xmlMod.Attribute("format") != null) - { - switch (xmlMod.Attribute("format").Value) - { - case "General": - mod.Format = Mod.ArchiveFormat.General; - break; - case "DDS": // Backward compatibility - case "Textures": - mod.Format = Mod.ArchiveFormat.Textures; - break; - case "Auto": - default: - mod.Format = Mod.ArchiveFormat.Auto; - break; - } - } - if (mod.Type == Mod.FileType.SeparateBA2 && - xmlMod.Attribute("compression") != null && - xmlMod.Attribute("archiveName") != null) - { - switch (xmlMod.Attribute("compression").Value) - { - case "Default": // Backward compatibility - case "Compressed": - mod.Compression = Mod.ArchiveCompression.Compressed; - break; - case "None": // Backward compatibility - case "Uncompressed": - mod.Compression = Mod.ArchiveCompression.Uncompressed; - break; - case "Auto": - default: - mod.Compression = Mod.ArchiveCompression.Auto; - break; - } - //mod.Compression = Archive2.GetCompression(xmlMod.Attribute("compression").Value); - mod.ArchiveName = xmlMod.Attribute("archiveName").Value; - if (xmlMod.Attribute("frozen") != null) - { - mod.frozen = Convert.ToBoolean(xmlMod.Attribute("frozen").Value); - mod.freeze = mod.frozen; - } - } - if (mod.Type == Mod.FileType.Loose && - xmlMod.Attribute("root") != null) - { - mod.RootFolder = xmlMod.Attribute("root").Value; - if (mod.isEnabled) - foreach (XElement xmlFile in xmlMod.Descendants("File")) - if (xmlFile.Attribute("path") != null) - mod.AddFile(xmlFile.Attribute("path").Value); - else - throw new InvalidDataException("path attribute is missing from tag"); - } - return mod; - } - } - - public class ManagedMods - { - private static ManagedMods instance = null; - private static readonly object padlock = new object(); - - public static ManagedMods Instance - { - get - { - lock (padlock) - { - if (instance == null) - { - instance = new ManagedMods(); - } - return instance; - } - } - } - - private ManagedMods() - { - Shared.LoadGameEdition(); - Shared.LoadGamePath(); - - bool nwMode = IniFiles.Instance.GetBool(IniFile.Config, "Mods", "bDisableMods", false); - this.ModsDisabled = nwMode; - this.WriteDataDirs = IniFiles.Instance.GetBool(IniFile.Config, "Mods", "bWriteSResourceDataDirsFinal", false); - this.logFile = new Log(Log.GetFilePath("modmanager.log.txt")); - } - - private List mods = new List(); - private List changedMods = new List(); - public bool ModsDisabled = false; - public bool WriteToF76Custom = true; - public bool WriteDataDirs = false; - public Log logFile; - - // Use lower-case, plz - private List whitelistedDlls = new List() { - "bink2w64.dll", - "chrome_elf.dll", - "concrt140.dll", - "d3dcompiler_43.dll", - "libcef.dll", - "libegl.dll", // "libEGL.dll", - "libglesv2.dll", // "libGLESv2.dll", - "msvcp140.dll", - "ortp_x64.dll", - "steam_api64.dll", - "vccorlib140.dll", - "vcruntime140.dll", - "vivoxsdk_x64.dll", - "d3dcompiler_46.dll", - "d3dcompiler_47.dll" - // "x3daudio1_7.dll" ? - }; - - public static String GetEditionSuffix(int gameEdition) - { - return ManagedMods.GetEditionSuffix((GameEdition)gameEdition); - } - - public static String GetGamePathKey(int gameEdition) - { - return ManagedMods.GetGamePathKey((GameEdition)gameEdition); - } - - public static String GetEditionSuffix(GameEdition gameEdition) - { - switch (gameEdition) - { - case GameEdition.Steam: - return "Steam"; - case GameEdition.BethesdaNet: - return "BethesdaNet"; - case GameEdition.BethesdaNetPTS: - return "BethesdaNetPTS"; - case GameEdition.MSStore: - return "MSStore"; - default: - return ""; - } - } - - public static String GetGamePathKey (GameEdition gameEdition) - { - return "sGamePath" + GetEditionSuffix(gameEdition); - } - - private List CreateDeepCopy(List original) - { - List copy = new List(); - foreach (Mod mod in original) - copy.Add(mod.CreateCopy()); - return copy; - } - - public List Mods - { - get { return this.changedMods; } - } - - private void DeleteAt(int index) - { - String managedFolderPath = Path.Combine(Shared.GamePath, "Mods", this.changedMods[index].ManagedFolder); - if (Directory.Exists(managedFolderPath)) - Directory.Delete(managedFolderPath, true); - this.changedMods.RemoveAt(index); - //this.mods.RemoveAt(index); - } - - /// - /// Delete all files of the mod and remove it from the list. - /// Saves the manifest afterwards. - /// - /// - /// - public void DeleteMod(int index, Action done = null) - { - DeleteAt(index); - this.Save(); - if (done != null) - done(); - } - - public void DeleteMods(List indices, Action done = null) - { - indices = indices.OrderByDescending(i => i).ToList(); - foreach (int index in indices) - DeleteAt(index); - this.Save(); - if (done != null) - done(); - } - - public void UnfreezeMods(List indices, Action updateProgress = null, Action done = null) - { - foreach (int index in indices) - { - Mod mod = this.Mods[index]; - if (updateProgress != null) - updateProgress($"Unfreezing {mod.Title}...", (index + 1) / indices.Count() * 100); - mod.Unfreeze(); - } - if (done != null) - done(); - } - - public bool ValidateGamePath(String path) - { - return path != null && path.Trim().Length > 0 && Directory.Exists(path) && Directory.Exists(Path.Combine(path, "Data")); - } - - public bool ValidateGamePath() - { - return this.ValidateGamePath(Shared.GamePath); - } - - public String RenameManagedFolder(String currentManagedFolderName, String newManagedFolderName) - { - newManagedFolderName = Utils.GetValidFileName(newManagedFolderName); - if (currentManagedFolderName == newManagedFolderName) - return currentManagedFolderName; - if (!Directory.Exists(Path.Combine(Shared.GamePath, "Mods", currentManagedFolderName))) - return currentManagedFolderName; - - Mod deployedMod = null; - Mod changedMod = null; - foreach (Mod mod in this.mods) - if (mod.ManagedFolder == currentManagedFolderName) - deployedMod = mod; - foreach (Mod mod in this.changedMods) - if (mod.ManagedFolder == currentManagedFolderName) - changedMod = mod; - if (deployedMod == null || changedMod == null) - { - MsgBox.Get("modDetailsMoveManagedFolderFailed").FormatText("Internal error").Show(MessageBoxIcon.Error); - return currentManagedFolderName; - } - - String currentManagedFolderPath = deployedMod.GetManagedPath(); - String newManagedFolderPath = Utils.GetUniquePath(Path.Combine(Shared.GamePath, "Mods", newManagedFolderName)); - newManagedFolderName = Path.GetFileName(newManagedFolderPath); - try - { - Directory.Move(currentManagedFolderPath, newManagedFolderPath); - deployedMod.ManagedFolder = newManagedFolderName; - changedMod.ManagedFolder = newManagedFolderName; - this.Save(); - return newManagedFolderName; - } - catch (Exception exc) - { - MsgBox.Get("modDetailsMoveManagedFolderFailed").FormatText(exc.Message).Show(MessageBoxIcon.Error); - } - return currentManagedFolderName; - } - - public Archive2.Preset GetArchive2Preset(Mod mod) - { - var preset = new Archive2.Preset(); - - // No detection needed, "convert" Mod.ArchiveCompression to Archive2.Compression and Mod.ArchiveFormat to Archive2.Format: - if (mod.Compression != Mod.ArchiveCompression.Auto && mod.Format != Mod.ArchiveFormat.Auto) - { - preset.compression = mod.Compression == Mod.ArchiveCompression.Compressed ? Archive2.Compression.Default : Archive2.Compression.None; - preset.format = mod.Format == Mod.ArchiveFormat.General ? Archive2.Format.General : Archive2.Format.DDS; - - return preset; - } - - // Detect mod type: - // String[] resourceFolders = new string[] { "meshes", "strings", "music", "sound", "textures", "materials", "interface", "geoexporter", "programs", "vis", "scripts", "misc", "shadersfx", "lodsettings" }; - String[] generalFolders = new string[] { "meshes", "strings", "interface", "materials" }; - String[] textureFolders = new string[] { "textures", "effects" }; - String[] soundFolders = new string[] { "sound", "music" }; - - int generalFoldersCount = 0; - int textureFoldersCount = 0; - int soundFoldersCount = 0; - - String managedFolderPath = mod.GetManagedPath(); - IEnumerable folders = Directory.EnumerateDirectories(managedFolderPath); - foreach (String path in folders) - { - String folderName = Path.GetFileName(path).ToLower(); - - if (generalFolders.Contains(folderName)) - generalFoldersCount++; - else if (textureFolders.Contains(folderName)) - textureFoldersCount++; - else if (soundFolders.Contains(folderName)) - soundFoldersCount++; - } - - //int fileCount = Directory.EnumerateFiles(managedFolderPath).Count(); - //if (fileCount == 0) - - if (soundFoldersCount > generalFoldersCount && soundFoldersCount > textureFoldersCount) - { - preset.compression = Archive2.Compression.None; - preset.format = Archive2.Format.General; - } else if (textureFoldersCount > generalFoldersCount && textureFoldersCount > soundFoldersCount) - { - preset.compression = Archive2.Compression.Default; - preset.format = Archive2.Format.DDS; - } else - { - preset.compression = Archive2.Compression.Default; - preset.format = Archive2.Format.General; - } - - return preset; - } - - private void ManipulateModFolder(Mod mod, String managedFolderPath, Action updateProgress = null) - { - foreach (String path in Directory.EnumerateFiles(managedFolderPath)) - { - // If a *.ba2 archive was found, extract it: - if (path.EndsWith(".ba2")) - { - if (ExtractBA2Archive(path, managedFolderPath, updateProgress)) - File.Delete(path); - } - - // Remove crap: - if (path.EndsWith(".txt")) - File.Delete(path); - } - - String[] typicalFolders = new string[] { "meshes", "strings", "music", "sound", "textures", "materials", "interface", "geoexporter", "programs", "vis", "scripts", "misc", "shadersfx" }; - // Do it two times, because it changes files, so we need to check again. - for (int i = 0; i < 2; i++) - { - // Search through all folders in the mod folder. - foreach (String path in Directory.GetDirectories(managedFolderPath)) - { - String name = Path.GetFileName(path).ToLower(); - - // If only a data folder is in the mod folder... - if (name == "data" && Directory.EnumerateFiles(managedFolderPath).Count() == 0) - { - // ... move all files in data on up: - Directory.Move(path, managedFolderPath); - // Delete the empty data folder afterwards: - // Directory.Delete(path); - break; - } - - // If the mod folder contains "textures"... - if (name == "textures" && Directory.EnumerateFiles(managedFolderPath).Count() == 0) - { - // ... set ba2 format type to DDS - if (mod.Format != Mod.ArchiveFormat.Auto) - { - mod.Format = Mod.ArchiveFormat.Textures; - mod.RootFolder = "Data"; - break; - } - } - } - } - - // Search through all files in the mod folder. - foreach (String path in Directory.EnumerateFiles(managedFolderPath)) - { - String name = Path.GetFileName(path).ToLower(); - String extension = Path.GetExtension(path).ToLower(); - - // If the mod contains *.dll files... - if (extension == ".dll") - { - // ... then it probably has to be installed as loose files into the root directory: - mod.Type = Mod.FileType.Loose; - mod.RootFolder = "."; - } - } - } - - private bool ExtractBA2Archive(String archivePath, String destinationPath, Action updateProgress = null) - { - String filePath = Path.GetFullPath(archivePath); - String fileName = Path.GetFileNameWithoutExtension(filePath); - String fileExtension = Path.GetExtension(filePath); - - // Rename *.ba2 file if necessary: - if (fileName.Contains(",") || fileName != Utils.GetValidFileName(fileName)) - { - String newFileName = Utils.GetValidFileName(fileName).Replace(",", "_") + fileExtension; - String newFilePath = Path.Combine(Path.GetDirectoryName(filePath), newFileName); - File.Move(filePath, newFilePath); - fileName = newFileName; - filePath = newFilePath; - } - - if (fileExtension.ToLower() == ".ba2") - { - // For *.ba2 archives, Archive2 has to be installed: - if (!Archive2.ValidatePath()) - { - MsgBox.ShowID("modsArchive2Missing", MessageBoxIcon.Error); - return false; - } - - if (updateProgress != null) - updateProgress($"Extracting {fileName}.ba2 ...", -1); - - Archive2.Extract(filePath, destinationPath); - - return true; - } - else - return false; - } - - private bool ExtractModArchive(String archivePath, String managedFolderPath, Action updateProgress = null) - { - String filePath = Path.GetFullPath(archivePath); - String fileName = Path.GetFileNameWithoutExtension(filePath); - String fileExtension = Path.GetExtension(filePath); - - if (fileExtension.ToLower() == ".ba2") - { - return ExtractBA2Archive(filePath, managedFolderPath); - } - else if ((new String[] { ".zip", ".rar", ".tar", ".tar.gz", ".gz", ".xz", ".lz", ".bz2" }).Contains(fileExtension.ToLower())) - { - try - { - using (Stream stream = File.OpenRead(filePath)) - using (var reader = ReaderFactory.Open(stream)) - { - while (reader.MoveToNextEntry()) - { - if (!reader.Entry.IsDirectory) - { - if (updateProgress != null) - updateProgress(reader.Entry.Key, -1); - reader.WriteEntryToDirectory(managedFolderPath, new ExtractionOptions() - { - ExtractFullPath = true, - Overwrite = true - }); - } - } - } - - return true; - } - catch (InvalidOperationException exc) - { - MsgBox.Get("modsExtractUnknownError").FormatText(exc.Message).Show(MessageBoxIcon.Error); - return false; - } - } - else if ((new String[] { ".7z" }).Contains(fileExtension.ToLower())) - { - try - { - Utils.ExtractArchive(filePath, managedFolderPath); - - if (Directory.Exists(managedFolderPath)) - { - return true; - } - else - { - MsgBox.ShowID("modsExtractUnknownErrorText", MessageBoxIcon.Error); - //MessageBox.Show($"Please uncompress the archive and add the mod as a folder.", "Archive couldn't be uncompressed.", MessageBoxButtons.OK, MessageBoxIcon.Error); - return false; - } - } - catch (Exception exc) - { - MsgBox.Get("modsExtractUnknownError7zip").FormatText(exc.Message).Show(MessageBoxIcon.Error); - return false; - } - } - else - { - //MessageBox.Show($"*{fileExtension} files are not supported.\nPlease uncompress the archive and add the mod as a folder.", "Unsupported file format", MessageBoxButtons.OK, MessageBoxIcon.Error); - MsgBox.Get("modsArchiveTypeNotSupported").FormatText(fileExtension).Show(MessageBoxIcon.Error); - return false; - } - } - - public void InstallModArchiveFrozen(String filePath, Action updateProgress = null, Action done = null) - { - // Some conditions have to be met: - if (Shared.GamePath == null) - { - this.logFile.WriteLine("Couldn't import *.ba2 file: No game path has been set."); - if (done != null) - done(false); - return; - } - - if (!File.Exists(filePath)) - { - // Path too long? - // https://stackoverflow.com/questions/5188527/how-to-deal-with-files-with-a-name-longer-than-259-characters - // https://docs.microsoft.com/de-de/archive/blogs/jeremykuhne/more-on-new-net-path-handling - if (File.Exists(@"\\?\" + filePath)) - { - filePath = @"\\?\" + filePath; - } - else - { - this.logFile.WriteLine($"Error while importing *.ba2 file: Couldn't locate file: {filePath}"); - if (done != null) - done(false); - throw new FileNotFoundException(filePath); - } - } - - try - { - // Create Mods folder: - if (!Directory.Exists(Path.Combine(Shared.GamePath, "Mods"))) - Directory.CreateDirectory(Path.Combine(Shared.GamePath, "Mods")); - - // Get paths: - filePath = Path.GetFullPath(filePath); - String fileName = Path.GetFileNameWithoutExtension(filePath); - String fileExtension = Path.GetExtension(filePath); - String managedFolderPath = Utils.GetUniquePath(Path.Combine(Shared.GamePath, "Mods", fileName)); - String managedFolder = Path.GetFileName(managedFolderPath); - - // Create a new mod: - Mod mod = new Mod(); - mod.Title = fileName; - mod.ManagedFolder = managedFolder; - mod.RootFolder = "Data"; - mod.ArchiveName = fileName; - mod.Type = Mod.FileType.SeparateBA2; - // TODO: Detect archive format: - // mod.Compression = Archive2.Compression.?? - // mod.Format = Mod.ArchiveFormat.?? - mod.freeze = true; - mod.OverwriteFrozen(true); - mod.isEnabled = false; - - // Copy the archive: - if (updateProgress != null) - updateProgress($"Copying {Path.GetFileName(filePath)}", -1); - - if (!Directory.Exists(managedFolderPath)) - Directory.CreateDirectory(managedFolderPath); - - File.Copy(filePath, Path.Combine(managedFolderPath, "frozen.ba2")); - this.AddInstalledMod(mod); - this.Save(); - - if (done != null) - done(true); - } - catch (UnauthorizedAccessException ex) - { - MsgBox.Get("modsAccessDenied").FormatText("UnauthorizedAccessException: " + ex.Message).Show(MessageBoxIcon.Error); - this.logFile.WriteLine($"UnauthorizedAccessException occured while importing a folder: {ex.Message}\n{ex.StackTrace}\n"); - if (done != null) - done(false); - return; - } - catch (Exception ex) - { - this.logFile.WriteLine($"Unhandled exception occured while importing a *.ba2 file: {ex.Message}\n{ex.StackTrace}\n"); - if (done != null) - done(false); - return; - } - } - - /// - /// Extracts the archive and adds the mod. - /// Saves the manifest afterwards. - /// - /// Path to archive - /// Callback: Progress has been made. - /// Callback: It's done. - public void InstallModArchive(String filePath, Action updateProgress = null, Action done = null) - { - // Some conditions have to be met: - if (Shared.GamePath == null) - { - this.logFile.WriteLine("Couldn't import *.ba2 file: No game path has been set."); - if (done != null) - done(false); - return; - } - - if (!File.Exists(filePath)) - { - // Path too long? - // https://stackoverflow.com/questions/5188527/how-to-deal-with-files-with-a-name-longer-than-259-characters - // https://docs.microsoft.com/de-de/archive/blogs/jeremykuhne/more-on-new-net-path-handling - if (File.Exists(@"\\?\" + filePath)) - { - filePath = @"\\?\" + filePath; - } - else - { - this.logFile.WriteLine($"Error while importing *.ba2 file: Couldn't locate file: {filePath}"); - if (done != null) - done(false); - throw new FileNotFoundException(filePath); - } - } - - - if (!Archive2.ValidatePath()) - { - MsgBox.ShowID("modsArchive2Missing", MessageBoxIcon.Error); - this.logFile.WriteLine("Archive2 is missing."); - if (done != null) - done(false); - return; - } - - try - { - // Create Mods folder: - if (!Directory.Exists(Path.Combine(Shared.GamePath, "Mods"))) - Directory.CreateDirectory(Path.Combine(Shared.GamePath, "Mods")); - - // Get paths: - filePath = Path.GetFullPath(filePath); - String fileName = Path.GetFileNameWithoutExtension(filePath); - String fileExtension = Path.GetExtension(filePath); - String managedFolderPath = Utils.GetUniquePath(Path.Combine(Shared.GamePath, "Mods", fileName)); - String managedFolder = Path.GetFileName(managedFolderPath); - /*if (Directory.Exists(managedFolderPath)) - { - managedFolder += DateTime.Now.ToString("(yyyy-MM-dd_HH-mm-ss)"); - managedFolderPath = Path.Combine(this.GamePath, "Mods", managedFolder); - }*/ - - // Create a new mod: - Mod mod = new Mod(); - mod.Title = fileName; - mod.ManagedFolder = managedFolder; - mod.RootFolder = "Data"; - mod.ArchiveName = fileName; - mod.Type = Mod.FileType.BundledBA2; - mod.isEnabled = false; - - // Extract the archive: - if (updateProgress != null) - updateProgress($"Extracting {Path.GetFileName(filePath)}", -1); - if (ExtractModArchive(filePath, managedFolderPath, updateProgress)) - { - ManipulateModFolder(mod, managedFolderPath, updateProgress); - this.AddInstalledMod(mod); - this.Save(); - } - - if (done != null) - done(true); - } - catch (Archive2Exception ex) - { - ManagedMods.Instance.logFile.WriteLine($"Archive2Exception occured while importing an archive: {ex.Message}\n{ex.StackTrace}\n"); - MsgBox.Get("archive2InstallRequirements").Show(MessageBoxIcon.Error); - if (done != null) - done(false); - return; - } - catch (UnauthorizedAccessException ex) - { - MsgBox.Get("modsAccessDenied").FormatText("UnauthorizedAccessException: " + ex.Message).Show(MessageBoxIcon.Error); - this.logFile.WriteLine($"UnauthorizedAccessException occured while importing an archive: {ex.Message}\n{ex.StackTrace}\n"); - if (done != null) - done(false); - return; - } - catch (Exception ex) - { - this.logFile.WriteLine($"Unhandled exception occured while importing an archive: {ex.Message}\n{ex.StackTrace}\n"); - if (done != null) - done(false); - return; - } - } - - /// - /// Copies the folder's contents and adds the mod. - /// Saves the manifest afterwards. - /// - /// Path to directory - /// Callback: "Copying file xyz" and percentage. - /// Callback: It's done. - public void InstallModFolder(String folderPath, Action updateProgress = null, Action done = null) - { - // Some conditions have to be met: - if (Shared.GamePath == null) - { - this.logFile.WriteLine("Couldn't import folder: No game path has been set."); - if (done != null) - done(false); - return; - } - - if (!Directory.Exists(folderPath)) - { - // Path too long? - // https://stackoverflow.com/questions/5188527/how-to-deal-with-files-with-a-name-longer-than-259-characters - // https://docs.microsoft.com/de-de/archive/blogs/jeremykuhne/more-on-new-net-path-handling - if (Directory.Exists(@"\\?\" + folderPath)) - { - folderPath = @"\\?\" + folderPath; - } - else - { - this.logFile.WriteLine($"Error while importing a folder: Couldn't locate folder: {folderPath}"); - if (done != null) - done(false); - throw new FileNotFoundException(folderPath); - } - } - - - if (!Archive2.ValidatePath()) - { - MsgBox.ShowID("modsArchive2Missing", MessageBoxIcon.Error); - this.logFile.WriteLine("Archive2 is missing."); - if (done != null) - done(false); - return; - } - - try - { - // Create Mods folder: - if (!Directory.Exists(Path.Combine(Shared.GamePath, "Mods"))) - Directory.CreateDirectory(Path.Combine(Shared.GamePath, "Mods")); - - // Get paths: - folderPath = Path.GetFullPath(folderPath); - String folderName = Path.GetFileName(folderPath); - String managedFolderPath = Utils.GetUniquePath(Path.Combine(Shared.GamePath, "Mods", folderName)); - String managedFolder = Path.GetFileName(managedFolderPath); - - // Create a new mod: - Mod mod = new Mod(); - mod.Title = folderName; - mod.ManagedFolder = managedFolder; - mod.RootFolder = "Data"; - mod.ArchiveName = folderName; - mod.Type = Mod.FileType.BundledBA2; - mod.isEnabled = false; - - // Copy every file found in the folder: - if (updateProgress != null) - updateProgress($"Indexing {folderName}...", -1); - IEnumerable files = Directory.EnumerateFiles(folderPath, "*.*", SearchOption.AllDirectories); - float count = (float)files.Count(); - if (count == 0) - { - this.logFile.WriteLine($"Imported folder is empty. Abort."); - if (done != null) - done(false); - return; - } - int i = 0; - foreach (String file in files) - { - if (updateProgress != null) - updateProgress($"Copying {Path.GetFileName(file)} ...", Convert.ToInt32((float)i++ / (float)count * 100)); - - // Make a relative path, create directories and copy file: - String destinationPath = Path.Combine(managedFolderPath, Utils.MakeRelativePath(folderPath, file)); - Directory.CreateDirectory(Path.GetDirectoryName(destinationPath)); - File.Copy(file, destinationPath); - } - - ManipulateModFolder(mod, managedFolderPath, updateProgress); - - // Add to mods: - AddInstalledMod(mod); - this.Save(); - - if (done != null) - done(true); - } - catch (Archive2Exception ex) - { - ManagedMods.Instance.logFile.WriteLine($"Archive2Exception occured while importing a folder: {ex.Message}\n{ex.StackTrace}\n"); - MsgBox.Get("archive2InstallRequirements").Show(MessageBoxIcon.Error); - if (done != null) - done(false); - return; - } - catch (UnauthorizedAccessException ex) - { - MsgBox.Get("modsAccessDenied").FormatText("UnauthorizedAccessException: " + ex.Message).Show(MessageBoxIcon.Error); - this.logFile.WriteLine($"UnauthorizedAccessException occured while importing a folder: {ex.Message}\n{ex.StackTrace}\n"); - if (done != null) - done(false); - return; - } - catch (Exception ex) - { - this.logFile.WriteLine($"Unhandled exception occured while importing a folder: {ex.Message}\n{ex.StackTrace}\n"); - if (done != null) - done(false); - return; - } - } - - private void AddInstalledMod(Mod mod) - { - mods.Add(mod.CreateCopy()); - AddMod(mod); - } - - public void AddMod(Mod mod) - { - changedMods.Add(mod); - } - - public void EnableMod(int index) - { - if (changedMods[index].isEnabled) - return; - changedMods[index].isEnabled = true; - } - - public void DisableMod(int index) - { - if (!changedMods[index].isEnabled) - return; - changedMods[index].isEnabled = false; - } - - public void ToggleMod(int index, bool enabled) - { - if (changedMods[index].isEnabled == enabled) - return; - changedMods[index].isEnabled = enabled; - } - - public bool isModEnabled(int index) - { - return changedMods[index].isEnabled; - } - - private int MoveMod(int oldIndex, int newIndex) - { - // https://stackoverflow.com/questions/450233/generic-list-moving-an-item-within-the-list - Mod mod = this.changedMods[oldIndex]; - - this.changedMods.RemoveAt(oldIndex); - - // the actual index could have shifted due to the removal - // if (newIndex > oldIndex) newIndex--; - - this.changedMods.Insert(newIndex, mod); - - return newIndex; - } - - - public int MoveModUp(int index) - { - if (index > 0) - return MoveMod(index, index - 1); - return index; - } - - public int MoveModDown(int index) - { - if (index < this.changedMods.Count - 1) - return MoveMod(index, index + 1); - return index; - } - - /// - /// Compares this.mods and this.changedMods. - /// Since this.mods represents the state on disk and this.changedMods represents changed that are due, - /// if both aren't equal then deployment is necessary. - /// - /// - public bool isDeploymentNecessary() - { - if (this.changedMods.Count() != this.mods.Count()) - return true; - for (int i = 0; i < this.changedMods.Count(); i++) - { - if (this.changedMods[i].isEnabled != this.mods[i].isEnabled || - this.changedMods[i].LooseFiles.Count() != this.mods[i].LooseFiles.Count() || - this.changedMods[i].RootFolder != this.mods[i].RootFolder || - this.changedMods[i].Type != this.mods[i].Type || - this.changedMods[i].ManagedFolder != this.mods[i].ManagedFolder || - this.changedMods[i].Compression != this.mods[i].Compression || - this.changedMods[i].Format != this.mods[i].Format || - this.changedMods[i].freeze != this.mods[i].freeze) - return true; - } - return false; - } - - /*public String GamePath - { - get { return this.gamePath; } - set - { - if (value != null && Directory.Exists(value)) - this.gamePath = Path.GetFullPath(value); - } - }*/ - - public String GetModPath(int index) - { - return Path.Combine(Shared.GamePath, "Mods", this.changedMods[index].ManagedFolder); - } - - public String GetInstalledModPath(int index) - { - return Path.Combine(Shared.GamePath, "Mods", this.mods[index].ManagedFolder); - } - - public struct Conflict - { - public String conflictText; - public List conflictingFiles; - } - - public List GetConflictingFiles() - { - //List conflictingFiles = new List(); - //List conflictingMods = new List(); - List conflictingMods = new List(); - for (int i = 1; i < this.changedMods.Count; i++) - { - Mod lowerMod = this.changedMods[i]; - String lowerPath = Path.Combine(Shared.GamePath, "Mods", lowerMod.ManagedFolder); - if (!lowerMod.isEnabled && Directory.Exists(lowerPath)) - continue; - List lowerRelPaths = new List(); - foreach (String filePath in Directory.EnumerateFiles(lowerPath, "*.*", SearchOption.AllDirectories)) - lowerRelPaths.Add(Utils.MakeRelativePath(lowerPath, filePath)); - - //for (int l = i - 1; l >= 0; l--) - for (int l = 0; l < i; l++) - { - Conflict conflict = new Conflict(); - conflict.conflictingFiles = new List(); - Mod upperMod = this.changedMods[l]; - String upperPath = Path.Combine(Shared.GamePath, "Mods", upperMod.ManagedFolder); - if (!upperMod.isEnabled && Directory.Exists(upperPath)) - continue; - IEnumerable upperFiles = Directory.EnumerateFiles(upperPath, "*.*", SearchOption.AllDirectories); - foreach (String filePath in upperFiles) - { - String relUpperPath = Utils.MakeRelativePath(upperPath, filePath); - if (!relUpperPath.Contains("frozen.ba2") && lowerRelPaths.Contains(relUpperPath)) - { - if (!conflict.conflictingFiles.Contains(relUpperPath)) - conflict.conflictingFiles.Add(relUpperPath); - conflict.conflictText = lowerMod.Title + " overrides " + upperMod.Title; - } - } - if (conflict.conflictingFiles.Count > 0) - conflictingMods.Add(conflict); - } - } - return conflictingMods; - } - - public void ImportInstalledMods() - { - // Get all archives: - List sResourceIndexFileList = (new List(IniFiles.Instance.GetString(IniFile.F76Custom, "Archive", "sResourceIndexFileList", "").Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))).Distinct().ToList(); - List sResourceArchive2List = (new List(IniFiles.Instance.GetString(IniFile.F76Custom, "Archive", "sResourceArchive2List", "").Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))).Distinct().ToList(); - - // Prepare list: - List installedMods = new List(); - installedMods.AddRange(sResourceIndexFileList); - installedMods.AddRange(sResourceArchive2List); - installedMods.Remove("bundled.ba2"); - installedMods.Remove("bundled_textures.ba2"); - foreach (Mod mod in this.mods) - if (mod.Type == Mod.FileType.SeparateBA2) - installedMods.Remove(mod.ArchiveName); - - // Ignore any game files ("SeventySix - *.ba2"): - foreach (String archiveName in sResourceIndexFileList) - if (archiveName.StartsWith("SeventySix")) - installedMods.Remove(archiveName); - foreach (String archiveName in sResourceArchive2List) - if (archiveName.StartsWith("SeventySix")) - installedMods.Remove(archiveName); - - // Import every archive: - foreach (String archiveName in installedMods) - { - String path = Path.Combine(Shared.GamePath, "Data", archiveName); - Console.WriteLine(path); - if (File.Exists(path)) - { - // Import archive: - this.InstallModArchiveFrozen(path); - File.Delete(path); - - // Remove from lists: - if (sResourceIndexFileList.Contains(archiveName)) - sResourceIndexFileList.Remove(archiveName); - if (sResourceArchive2List.Contains(archiveName)) - sResourceArchive2List.Remove(archiveName); - } - } - - // Save *.ini files: - sResourceIndexFileList = sResourceIndexFileList.Distinct().ToList(); - sResourceArchive2List = sResourceArchive2List.Distinct().ToList(); - if (sResourceIndexFileList.Count > 0) - IniFiles.Instance.Set(IniFile.F76Custom, "Archive", "sResourceIndexFileList", String.Join(",", sResourceIndexFileList.ToArray())); - else - IniFiles.Instance.Remove(IniFile.F76Custom, "Archive", "sResourceIndexFileList"); - if (sResourceArchive2List.Count > 0) - IniFiles.Instance.Set(IniFile.F76Custom, "Archive", "sResourceArchive2List", String.Join(",", sResourceArchive2List.ToArray())); - else - IniFiles.Instance.Remove(IniFile.F76Custom, "Archive", "sResourceArchive2List"); - IniFiles.Instance.SaveAll(); - } - - public XDocument Serialize() - { - /* - Fallout76\Mods\manifest.xml - - - - - - */ - - XDocument xmlDoc = new XDocument(); - XElement xmlRoot = new XElement("Mods"); - xmlDoc.Add(xmlRoot); - foreach (Mod mod in mods) - { - if (Directory.Exists(mod.GetManagedPath())) - xmlRoot.Add(mod.Serialize()); - } - return xmlDoc; - } - - public void Unload() - { - this.mods.Clear(); - this.changedMods.Clear(); - - Shared.ClearGamePath(); - } - - public void Load() - { - this.mods.Clear(); - this.changedMods.Clear(); - - if (Shared.GamePath == null) - return; - - if (!IniFiles.Instance.GetBool(IniFile.Config, "Preferences", "bMultipleGameEditionsUsed", false)) - this.LoadINILists(); - - String manifestPath = Path.Combine(Shared.GamePath, "Mods", "manifest.xml"); - - if (!File.Exists(manifestPath)) - return; - - XDocument xmlDoc = XDocument.Load(manifestPath); - - foreach (XElement xmlMod in xmlDoc.Descendants("Mod")) - { - try - { - Mod mod = Mod.Deserialize(xmlMod); - if (!Directory.Exists(Path.Combine(Shared.GamePath, "Mods", mod.ManagedFolder))) - continue; - this.AddInstalledMod(mod); - } - catch (Exception ex) - { - /* InvalidDataException, ArgumentException */ - MsgBox.Get("modsInvalidManifestEntry").FormatText(ex.Message).Show(MessageBoxIcon.Warning); - } - } - } - - public void Save() - { - if (Shared.GamePath == null) - { - MsgBox.ShowID("modsGamePathNotSet", MessageBoxIcon.Error); - return; - } - - if (!Directory.Exists(Path.Combine(Shared.GamePath, "Mods"))) - Directory.CreateDirectory(Path.Combine(Shared.GamePath, "Mods")); - - this.CopyINILists(); - this.Serialize().Save(Path.Combine(Shared.GamePath, "Mods", "manifest.xml")); - } - - private class DeployArchive - { - public String tempPath; - public String archiveName; - public Archive2.Format format = Archive2.Format.General; - public Archive2.Compression compression = Archive2.Compression.Default; - public int count = 0; - - public DeployArchive(String name, String tempFolderPath) - { - this.tempPath = Path.Combine(tempFolderPath, name); - if (name == "general") - this.archiveName = "bundled.ba2"; - else - this.archiveName = "bundled_" + name + ".ba2"; - - /*if (Directory.Exists(this.tempPath)) - Directory.Delete(this.tempPath, true);*/ - Directory.CreateDirectory(this.tempPath); - } - } - - public void Deploy(Action updateProgress = null, Action done = null) - { - try - { - this.logFile.WriteLine("\n\n"); - this.logFile.WriteTimeStamp(); - this.logFile.WriteLine($"Version {Shared.VERSION}, deploying..."); - - /* - * Check if everything is ready for deployment: - */ - - // Archive2 existing? - if (!Archive2.ValidatePath()) - { - MsgBox.ShowID("modsArchive2Missing", MessageBoxIcon.Error); - this.logFile.WriteLine("Failed: Couldn't find Archive2"); - if (done != null) - done(false); - return; - } - - // Game path existing? - if (Shared.GamePath == null) - { - if (done != null) - done(false); - return; - } - - // Game path valid? - if (!Directory.Exists(Path.Combine(Shared.GamePath, "Data"))) - { - MsgBox.ShowID("modsGamePathInvalid", MessageBoxIcon.Error); - this.logFile.WriteLine("Failed: Game path invalid"); - if (done != null) - done(false); - return; - } - - // Check if we don't have multiple mods with the same archive name: - List customArchiveNames = new List(); - foreach (Mod mod in this.changedMods) - { - if (mod.Type == Mod.FileType.SeparateBA2 && mod.isEnabled) - { - if (customArchiveNames.Contains(mod.ArchiveName.ToLower())) - { - MsgBox.Get("modsSameArchiveName").FormatText(mod.ArchiveName, mod.Title).Show(MessageBoxIcon.Error); - this.logFile.WriteLine($"Conflict: Multiple mods with the same archive name. (1st conflict: '{mod.ArchiveName}', '{mod.Title}')"); - if (done != null) - done(false); - return; - } - else - { - customArchiveNames.Add(mod.ArchiveName.ToLower()); - } - } - } - - - - /* - * Check / declare parameters - */ - - // NW Mode: - if (this.ModsDisabled) - { - this.logFile.WriteLine("NOTE: Nuclear Winter mode enabled. (Disable Mods checkbox checked)"); - IniFiles.Instance.Set(IniFile.Config, "Mods", "bDisableMods", this.ModsDisabled); - } - else - { - IniFiles.Instance.Set(IniFile.Config, "Mods", "bDisableMods", false); - } - - // Hard links: - bool useHardlinks = IniFiles.Instance.GetBool(IniFile.Config, "Mods", "bUseHardlinks", true); - this.logFile.WriteLine("Deployment method: " + (useHardlinks ? "Make hard links" : "Make copies (slow)")); - - // Create temp folder: - String tempPath = Path.Combine(Shared.GamePath, "temp"); - if (Directory.Exists(tempPath)) - Directory.Delete(tempPath, true); - Directory.CreateDirectory(tempPath); - - // Setup 'DeployArchives' for every bundled archive: - DeployArchive generalArchive = new DeployArchive("general", tempPath); - DeployArchive texturesArchive = new DeployArchive("textures", tempPath); - texturesArchive.format = Archive2.Format.DDS; - DeployArchive soundsArchive = new DeployArchive("sounds", tempPath); - soundsArchive.compression = Archive2.Compression.None; - var archives = new List() { generalArchive, texturesArchive, soundsArchive }; - - // Frozen bundled archives feature: - bool freezeBundledArchives = IniFiles.Instance.GetBool(IniFile.Config, "Mods", "bFreezeBundledArchives", false); - bool frozenBundledArchivesAvailable = false; - bool repackBundledArchives = true; - String frozenBundledFolder = Path.Combine(Shared.GamePath, "Mods", "_frozen"); - if (freezeBundledArchives) - { - this.logFile.WriteLine($"NOTE: Experimental feature 'Freeze bundled archives' enabled."); - - // Create folder: - if (!Directory.Exists(frozenBundledFolder)) - Directory.CreateDirectory(frozenBundledFolder); - - // Do we have frozen archives? - foreach (DeployArchive archive in archives) - frozenBundledArchivesAvailable = frozenBundledArchivesAvailable || File.Exists(Path.Combine(frozenBundledFolder, archive.archiveName)); - - // Don't repack archives when disabling mods: - if (this.ModsDisabled) - repackBundledArchives = false; - - // Ask user whether to deploy frozen archives or repack them: - else if (frozenBundledArchivesAvailable) - repackBundledArchives = MsgBox.Get("modsRepackFrozenBundledArchives").Show(MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes; - } - - // Parse lists: - // sResourceIndexFileList, sResourceArchive2List, sResourceDataDirsFinal - List sResourceIndexFileList = LoadResourceList("sResourceIndexFileList"); - List sResourceDataDirsFinal = new List(IniFiles.Instance.GetString(IniFile.F76Custom, "Archive", "sResourceDataDirsFinal", "").Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries)); - - - /* - ***************************************************** - * Beginning of deployment: - ***************************************************** - */ - - - /* - * Remove any leftover files from previous installations: - */ - - this.logFile.WriteLine($"\n\nREMOVING MODS\n"); - - // Remove all loose files: - int i = 0; - foreach (Mod mod in this.mods) - { - if (updateProgress != null) - updateProgress($"[1/4] Removing files of mod {mod.Title} ({i} of {this.mods.Count})", Convert.ToInt32((float)i / (float)this.mods.Count * 20)); - - if (!mod.isEnabled) - continue; - - if (mod.Type == Mod.FileType.Loose) - { - foreach (String relFilePath in mod.LooseFiles) - { - String installedFilePath = Path.Combine(Shared.GamePath, mod.RootFolder, relFilePath).Replace("\\.\\", "\\"); - - // Delete file, if existing: - if (File.Exists(installedFilePath)) - File.Delete(installedFilePath); - - // Use backups, if there are any: - if (File.Exists(installedFilePath + ".old")) - File.Move(installedFilePath + ".old", installedFilePath); - else - { - // Remove empty folders one by one, if existing: - String parent = Path.GetDirectoryName(installedFilePath); - while (Directory.Exists(parent) && Utils.IsDirectoryEmpty(parent)) - { - Directory.Delete(parent); - parent = Path.GetDirectoryName(parent); - } - } - } - this.logFile.WriteLine($"Loose files of mod {mod.Title} removed."); - } - else if (mod.Type == Mod.FileType.SeparateBA2) - { - String path = Path.Combine(Shared.GamePath, "Data", mod.ArchiveName); - if (File.Exists(path)) - File.Delete(path); - - if (sResourceIndexFileList.Contains(mod.ArchiveName)) - { - sResourceIndexFileList = sResourceIndexFileList.Distinct().ToList(); - sResourceIndexFileList.Remove(mod.ArchiveName); - } - this.logFile.WriteLine($"*.ba2 archive of mod {mod.Title} removed."); - } - - i++; - } - - - /* - * Copy all mods - */ - - this.logFile.WriteLine($"\n\nCOPYING MODS\n"); - - i = 0; - /*int enabledBA2GeneralMods = 0; - int enabledBA2TexturesMods = 0;*/ - int enabledLooseMods = 0; - List allModRelPaths = new List(); - int enabledModsCount = this.changedMods.Count(n => n.isEnabled); - float modPercent = 1f / (float)enabledModsCount * 0.8f; - foreach (Mod mod in this.changedMods) - { - /* - * Skip if nuclear winter mode is enabled. - * Skip if mod is disabled. - * Show error if mod folder wasn't found - */ - if (this.ModsDisabled) - break; - - if (!mod.isEnabled) - continue; - - String progressModName = $"{mod.Title} ({i + 1} of {enabledModsCount})"; - int progressPercent = Convert.ToInt32((float)i / (float)enabledModsCount * 80 + 20); - - if (updateProgress != null) - updateProgress($"[2/4] Deploying mod {progressModName}", progressPercent); - - String managedFolderPath = Path.Combine(Shared.GamePath, "Mods", mod.ManagedFolder); - if (!Directory.Exists(managedFolderPath)) - { - //MessageBox.Show($"Directory \"{managedFolderPath}\" does not exist.\nPlease restart the mod manager and add the mod again.", $"Mod {mod.Title} couldn't be deployed.", MessageBoxButtons.OK, MessageBoxIcon.Error); - MsgBox.Get("modsDeployErrorModDirNotFound") - .FormatTitle(mod.Title) - .FormatText(managedFolderPath) - .Show(MessageBoxIcon.Error); - continue; - } - - /* - * Copy files into temporary folder for bundled archives - */ - if (mod.Type == Mod.FileType.BundledBA2) - { - // Frozen bundled feature: - if (!repackBundledArchives) - { - this.logFile.WriteLine($"[Bundled] Skipping {mod.Title}"); - continue; - } - - // Check if root folder is data: - if (!mod.RootFolder.Contains("Data")) - { - MsgBox.Get("modsDeployErrorBA2RootIsNotData") - .FormatTitle(mod.Title) - .Show(MessageBoxIcon.Error); - //MessageBox.Show("The root folder has to be set to \".\\Data\" for mods, that are to be installed as a bundled *.ba2 archive.", $"Mod {mod.Title} couldn't be deployed.", MessageBoxButtons.OK, MessageBoxIcon.Error); - continue; - } - - this.logFile.WriteLine($"[Bundled] Copying files of {mod.Title} to temp folder."); - - int generalFiles = 0; - int DDSFiles = 0; - int soundFiles = 0; - - // Copy all files to temp data path: - // String[] files = Directory.GetFiles(managedFolderPath, "*.*", SearchOption.AllDirectories); - IEnumerable files = Directory.EnumerateFiles(managedFolderPath, "*.*", SearchOption.AllDirectories); - int count = files.Count(); - int f = 0; - foreach (String filePath in files) - { - if (updateProgress != null) - updateProgress($"[2/4] Copying file {f} of {count} (\"{Path.GetFileName(filePath)}\") of mod {progressModName}", progressPercent + (int)((float)f++ / (float)count * modPercent * 100)); - - // Make a relative path, create directories and copy file: - String relativePath = Utils.MakeRelativePath(managedFolderPath, filePath); - String destinationPath; - if (relativePath.Trim().ToLower().StartsWith("sound") || relativePath.Trim().ToLower().StartsWith("music") || - filePath.ToLower().EndsWith(".wav") || filePath.ToLower().EndsWith(".xwm") || filePath.ToLower().EndsWith(".fuz") || filePath.ToLower().EndsWith(".lip")) - { - soundFiles++; - destinationPath = Path.Combine(soundsArchive.tempPath, relativePath); - } - else if (filePath.ToLower().EndsWith(".dds")) - { - DDSFiles++; - destinationPath = Path.Combine(texturesArchive.tempPath, relativePath); - } - else - { - generalFiles++; - destinationPath = Path.Combine(generalArchive.tempPath, relativePath); - } - Directory.CreateDirectory(Path.GetDirectoryName(destinationPath)); - - if (useHardlinks) - Utils.CreateHardLink(filePath, destinationPath, true); - else - File.Copy(filePath, destinationPath, true); - } - - // Increment counter: - if (generalFiles > 0) - { - //enabledBA2GeneralMods++; - generalArchive.count++; - this.logFile.WriteLine($" General files copied: {generalFiles}"); - } - if (DDSFiles > 0) - { - //enabledBA2TexturesMods++; - texturesArchive.count++; - this.logFile.WriteLine($" *.dds files copied: {DDSFiles}"); - } - if (soundFiles > 0) - { - //enabledBA2TexturesMods++; - soundsArchive.count++; - this.logFile.WriteLine($" Sound files copied: {soundFiles}"); - } - } - /* - * Install separate archive: - */ - else if (mod.Type == Mod.FileType.SeparateBA2) - { - // Check if root folder is data: - if (!mod.RootFolder.Contains("Data")) - { - MsgBox.Get("modsDeployErrorBA2RootIsNotData") - .FormatTitle(mod.Title) - .Show(MessageBoxIcon.Error); - //MessageBox.Show("The root folder has to be set to \".\\Data\" for mods, that are to be installed as a bundled *.ba2 archive.", $"Mod {mod.Title} couldn't be deployed.", MessageBoxButtons.OK, MessageBoxIcon.Error); - continue; - } - - // Check if folder is empty: - if (!mod.isFrozen() && Utils.IsDirectoryEmpty(mod.GetManagedPath())) - { - this.logFile.WriteLine($"[Separate] Skipping {mod.Title} because it's folder is empty."); - continue; - } - - if (mod.freeze) - { - if (mod.isFrozen()) - { - this.logFile.WriteLine($"[Separate] Copying frozen archive of {mod.Title}."); - this.logFile.WriteLine($" Archive name: {mod.ArchiveName}"); - } - else - { - Archive2.Preset preset = GetArchive2Preset(mod); - - this.logFile.WriteLine($"[Separate] Freezing archive of {mod.Title}."); - this.logFile.WriteLine($" Archive name: {mod.ArchiveName}"); - this.logFile.WriteLine($" Format: {Enum.GetName(typeof(Archive2.Format), (int)preset.format)}"); - this.logFile.WriteLine($" Compression: {Enum.GetName(typeof(Archive2.Compression), (int)preset.compression)}"); - - if (updateProgress != null) - updateProgress($"[2/4] Creating a *ba2 archive of mod {progressModName}", progressPercent + (int)(modPercent * 100)); - mod.Freeze(); - } - - // Copy archive: - if (updateProgress != null) - updateProgress($"[2/4] Copying frozen *ba2 archive of mod {progressModName}", progressPercent + (int)(modPercent * 100)); - - string frozenPath = mod.GetFrozenArchivePath(); - string destPath = Path.Combine(Shared.GamePath, "Data", mod.ArchiveName); - if (useHardlinks) - Utils.CreateHardLink(frozenPath, destPath, true); - else - File.Copy(frozenPath, destPath, true); - } - else - { - if (mod.isFrozen()) - { - mod.Unfreeze(); - } - - Archive2.Preset preset = GetArchive2Preset(mod); - - this.logFile.WriteLine($"[Separate] Creating archive of {mod.Title}."); - this.logFile.WriteLine($" Archive name: {mod.ArchiveName}"); - this.logFile.WriteLine($" Format: {Enum.GetName(typeof(Archive2.Format), (int)preset.format)}"); - this.logFile.WriteLine($" Compression: {Enum.GetName(typeof(Archive2.Compression), (int)preset.compression)}"); - - // Create archive: - if (updateProgress != null) - updateProgress($"[2/4] Creating a *ba2 archive of mod {progressModName}", progressPercent + (int)(modPercent * 100)); - Archive2.Create(Path.Combine(Shared.GamePath, "Data", mod.ArchiveName), managedFolderPath, preset); - } - sResourceIndexFileList.Add(mod.ArchiveName); - } - /* - * Install loose files: - */ - else if (mod.Type == Mod.FileType.Loose) - { - // Loose files - List modRelPaths = new List(); - // String[] files = Directory.GetFiles(managedFolderPath, "*.*", SearchOption.AllDirectories); - IEnumerable files = Directory.GetFiles(managedFolderPath, "*.*", SearchOption.AllDirectories); - int count = files.Count(); - int f = 0; - foreach (String filePath in files) - { - if (updateProgress != null) - updateProgress($"[2/4] Copying file {f} of {count} (\"{Path.GetFileName(filePath)}\") of mod {progressModName}", progressPercent + (int)((float)f++ / (float)count * modPercent * 100)); - String relPath = Utils.MakeRelativePath(managedFolderPath, filePath); - modRelPaths.Add(relPath); - String destinationPath = Path.Combine(Shared.GamePath, mod.RootFolder, relPath); - Directory.CreateDirectory(Path.GetDirectoryName(destinationPath)); - if (!allModRelPaths.Contains(relPath) && File.Exists(destinationPath) && !File.Exists(destinationPath + ".old")) - File.Move(destinationPath, destinationPath + ".old"); - - if (useHardlinks) - Utils.CreateHardLink(filePath, destinationPath, true); - else - File.Copy(filePath, destinationPath, true); - } - mod.LooseFiles = modRelPaths; - allModRelPaths.AddRange(modRelPaths); - enabledLooseMods++; - - this.logFile.WriteLine($"[Loose] Files of {mod.Title} copied."); - } - - i++; - } - - - /* - * Create all bundled archives - */ - - this.logFile.WriteLine($"\n\nBUNDLED ARCHIVES\n"); - - sResourceIndexFileList = sResourceIndexFileList.Distinct().ToList(); - if (repackBundledArchives) - { - // Create / delete archives: - foreach (DeployArchive archive in archives) - { - String bundledFrozenArchivePath = Path.Combine(frozenBundledFolder, archive.archiveName); - String bundledLiveArchivePath = Path.Combine(Shared.GamePath, "Data", archive.archiveName); - - if (!this.ModsDisabled && archive.count > 0 && !Utils.IsDirectoryEmpty(archive.tempPath)) - { - // Deploy when files exist and NW mode is disabled: - if (updateProgress != null) - updateProgress($"[3/4] Creating {archive.archiveName}...", -1); - - if (freezeBundledArchives) - { - this.logFile.WriteLine($"Freezing {archive.archiveName}"); - Archive2.Create(bundledFrozenArchivePath, archive.tempPath, archive.compression, archive.format); - - if (updateProgress != null) - updateProgress($"[3/4] Copying {archive.archiveName}...", -1); - - if (useHardlinks) - Utils.CreateHardLink(bundledFrozenArchivePath, bundledLiveArchivePath, true); - else - File.Copy(bundledFrozenArchivePath, bundledLiveArchivePath, true); - } - else - { - this.logFile.WriteLine($"Creating {archive.archiveName}"); - Archive2.Create(bundledLiveArchivePath, archive.tempPath, archive.compression, archive.format); - - // Freeze feature disabled, let's clean up junk: - if (File.Exists(bundledFrozenArchivePath)) - { - this.logFile.WriteLine($"Removing frozen {archive.archiveName}"); - File.Delete(bundledFrozenArchivePath); - } - } - - // Insert entry into list: - sResourceIndexFileList.Insert(0, archive.archiveName); - } - else - { - // Remove archive when NW mode is active or mod is disabled: - - // Delete files: - if (!this.ModsDisabled && File.Exists(bundledFrozenArchivePath)) - { - this.logFile.WriteLine($"Removing frozen {archive.archiveName}"); - File.Delete(bundledFrozenArchivePath); - } - - if (File.Exists(bundledLiveArchivePath)) - { - this.logFile.WriteLine($"Removing {archive.archiveName}"); - File.Delete(bundledLiveArchivePath); - } - - // Remove entry from list: - sResourceIndexFileList.Remove(archive.archiveName); - } - } - } - else - { - // Deploy frozen archives: - foreach (DeployArchive archive in archives) - { - if (updateProgress != null) - updateProgress($"[3/4] Deploying {archive.archiveName}...", -1); - - String bundledFrozenArchivePath = Path.Combine(frozenBundledFolder, archive.archiveName); - String bundledLiveArchivePath = Path.Combine(Shared.GamePath, "Data", archive.archiveName); - - if (this.ModsDisabled) - { - this.logFile.WriteLine($"Removing {archive.archiveName}"); - File.Delete(bundledLiveArchivePath); - sResourceIndexFileList.Remove(archive.archiveName); - } - else if (File.Exists(bundledFrozenArchivePath) && !File.Exists(bundledLiveArchivePath)) - { - this.logFile.WriteLine($"Deploying frozen {archive.archiveName}"); - if (useHardlinks) - Utils.CreateHardLink(bundledFrozenArchivePath, bundledLiveArchivePath, true); - else - File.Copy(bundledFrozenArchivePath, bundledLiveArchivePath, true); - - sResourceIndexFileList.Insert(0, archive.archiveName); - } - else if (!File.Exists(bundledFrozenArchivePath) && File.Exists(bundledLiveArchivePath)) - { - this.logFile.WriteLine($"Removing {archive.archiveName}"); - File.Delete(bundledLiveArchivePath); - sResourceIndexFileList.Remove(archive.archiveName); - } - else if (File.Exists(bundledLiveArchivePath)) - { - this.logFile.WriteLine($"Skipping {archive.archiveName}"); - } - } - } - - /* - * Finishing up... - */ - - if (updateProgress != null) - updateProgress("[4/4] Finishing up...", -1); - this.logFile.WriteLine($"\n\nFINISHING UP"); - - - // Renaming *.dll files - if (!this.ModsDisabled) - RestoreAddedDLLs(); - - // Writing lists to *.ini files - this.logFile.WriteLine($" Changing values in *.ini files..."); - SaveResourceList("sResourceIndexFileList", sResourceIndexFileList); - - // sResourceDataDirsFinal - if (this.WriteDataDirs) - { - sResourceDataDirsFinal.Clear(); - String[] resourceFolders = new string[] { "meshes", "strings", "music", "sound", "textures", "materials", "interface", "geoexporter", "programs", "vis", "scripts", "misc", "shadersfx", "lodsettings" }; - foreach (String folder in Directory.GetDirectories(Path.Combine(Shared.GamePath, "Data"))) - { - String folderName = Path.GetFileName(folder); - if (resourceFolders.Contains(folderName.ToLower())) - sResourceDataDirsFinal.Add(folderName.ToUpper() + "\\"); - } - if (sResourceDataDirsFinal.Count() > 0) - { - IniFiles.Instance.Set(IniFile.F76Custom, "Archive", "sResourceDataDirsFinal", String.Join(",", sResourceDataDirsFinal.Distinct())); - IniFiles.Instance.Set(IniFile.F76Custom, "Archive", "bInvalidateOlderFiles", true); - } - else - { - IniFiles.Instance.Remove(IniFile.F76Custom, "Archive", "sResourceDataDirsFinal"); - IniFiles.Instance.Remove(IniFile.F76Custom, "Archive", "bInvalidateOlderFiles"); - } - } - else - { - IniFiles.Instance.Remove(IniFile.F76Custom, "Archive", "sResourceDataDirsFinal"); - IniFiles.Instance.Remove(IniFile.F76Custom, "Archive", "bInvalidateOlderFiles"); - } - - CopyINILists(); - - // Save *.ini files: - this.logFile.WriteLine($" Saving."); - IniFiles.Instance.SaveAll(); - - // Save manifest.xml: - this.mods = CreateDeepCopy(this.changedMods); - this.Save(); - - // Remove temp folder: - Directory.Delete(tempPath, true); - - this.logFile.WriteLine("Done.\n"); - - if (done != null) - done(true); - } - catch (Archive2Exception ex) - { - ManagedMods.Instance.logFile.WriteLine($"Archive2Exception occured while deploying: {ex.Message}\n{ex.StackTrace}\n"); - MsgBox.Get("archive2InstallRequirements").Show(MessageBoxIcon.Error); - if (done != null) - done(false); - return; - } - catch (UnauthorizedAccessException ex) - { - MsgBox.Get("modsAccessDenied").FormatText("UnauthorizedAccessException: " + ex.Message).Show(MessageBoxIcon.Error); - this.logFile.WriteLine($"UnauthorizedAccessException occured while deploying: {ex.Message}\n{ex.StackTrace}\n"); - if (done != null) - done(false); - } - catch (Exception ex) - { - this.logFile.WriteLine($"Unhandled exception occured: \"{ex.GetType().Name}: {ex.Message}\"\n{ex.StackTrace}"); - if (done != null) - done(false); - } - } - - public List LoadResourceList (String key) - { - List list = new List(IniFiles.Instance.GetString(IniFile.F76Custom, "Archive", key, "").Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries)); - list.AddRange(IniFiles.Instance.GetString(IniFile.Config, "Archive", key, "").Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries)); - return list; - } - - public void SaveResourceList (String key, List list) - { - list = list.Distinct().ToList(); - int count = list.Count(); - String value = String.Join(",", list); - - IniFile iniFile = WriteToF76Custom ? IniFile.F76Custom : IniFile.Config; - IniFile otherIniFile = !WriteToF76Custom ? IniFile.F76Custom : IniFile.Config; - - //this.logFile.WriteLine($" Changing values in *.ini files..."); - this.logFile.WriteLine($" writting to {IniFiles.Instance.GetIniName(iniFile)}"); - if (count > 0) - { - IniFiles.Instance.Set(iniFile, "Archive", key, value); - this.logFile.WriteLine($" {key}={value}"); - } - else - { - IniFiles.Instance.Remove(iniFile, "Archive", key); - this.logFile.WriteLine($" {key} removed."); - } - IniFiles.Instance.Remove(otherIniFile, "Archive", key); - } - - public void ResolveNWResourceLists() - { - SaveResourceList("sResourceIndexFileList", LoadResourceList("sResourceIndexFileList")); - SaveResourceList("sResourceArchive2List", LoadResourceList("sResourceArchive2List")); - CopyINILists(); - } - - public void RenameAddedDLLs() - { - // Iterate through every *.dll file in game path: - IEnumerable files = Directory.EnumerateFiles(Shared.GamePath, "*.dll"); - this.logFile.WriteLine($"Renaming \'*.dll\' files to \'*.dll.nwmode\'."); - foreach (String filePath in files) - { - // If not whitelisted... - String fileName = Path.GetFileName(filePath); - if (!this.whitelistedDlls.Contains(fileName.ToLower())) - { - // ... rename it: - if (!File.Exists(filePath + ".nwmode")) - { - File.Move(filePath, filePath + ".nwmode"); - this.logFile.WriteLine($" Renamed {fileName}"); - } - - // ... or delete it: - else - { - File.Delete(filePath); - this.logFile.WriteLine($" Deleted {fileName}"); - } - } - } - } - - public void RestoreAddedDLLs() - { - // Iterate through every *.dll.nwmode file in game path: - IEnumerable files = Directory.EnumerateFiles(Shared.GamePath, "*.dll.nwmode"); - this.logFile.WriteLine($"Restoring \'*.dll.nwmode\' files to \'*.dll\'."); - foreach (String filePath in files) - { - String fileName = Path.GetFileName(filePath); - String originalFilePath = Path.Combine(Path.GetDirectoryName(filePath), fileName.Replace(".dll.nwmode", ".dll")); - - // Rename or delete, if the original exists: - if (!File.Exists(originalFilePath)) - { - File.Move(filePath, originalFilePath); - this.logFile.WriteLine($" Renamed {fileName}"); - } - else - { - // Assuming that the same *.dll file has been copied during deployment: - File.Delete(filePath); // we can just delete it. - this.logFile.WriteLine($" Deleted {fileName}"); - } - } - } - - public void CopyINILists() - { - String suffix = ManagedMods.GetEditionSuffix(Shared.GameEdition); - IniFiles.Instance.Set(IniFile.Config, "Mods", "sResourceIndexFileList" + suffix, String.Join(",", LoadResourceList("sResourceIndexFileList"))); - IniFiles.Instance.Set(IniFile.Config, "Mods", "sResourceArchive2List" + suffix, String.Join(",", LoadResourceList("sResourceArchive2List"))); - IniFiles.Instance.Set(IniFile.Config, "Mods", "sResourceDataDirsFinal" + suffix, String.Join(",", IniFiles.Instance.GetString(IniFile.F76Custom, "Archive", "sResourceDataDirsFinal", ""))); - IniFiles.Instance.SaveConfig(); - } - - public void LoadINILists() - { - String suffix = ManagedMods.GetEditionSuffix(Shared.GameEdition); - List sResourceIndexFileList = IniFiles.Instance.GetString(IniFile.Config, "Mods", "sResourceIndexFileList" + suffix, "").Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList(); - List sResourceArchive2List = IniFiles.Instance.GetString(IniFile.Config, "Mods", "sResourceArchive2List" + suffix, "").Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList(); - String sResourceDataDirsFinal = IniFiles.Instance.GetString(IniFile.Config, "Mods", "sResourceDataDirsFinal" + suffix, ""); - - if (sResourceIndexFileList.Count > 0 || IniFiles.Instance.Exists(IniFile.F76Custom, "Mods", "sResourceIndexFileList")) - SaveResourceList("sResourceIndexFileList", sResourceIndexFileList); - //IniFiles.Instance.Set(IniFile.F76Custom, "Archive", "sResourceIndexFileList", sResourceIndexFileList); - if (sResourceArchive2List.Count > 0 || IniFiles.Instance.Exists(IniFile.F76Custom, "Mods", "sResourceArchive2List")) - SaveResourceList("sResourceArchive2List", sResourceArchive2List); - // IniFiles.Instance.Set(IniFile.F76Custom, "Archive", "sResourceArchive2List", sResourceArchive2List); - if (sResourceDataDirsFinal.Length > 0 && this.WriteDataDirs || IniFiles.Instance.Exists(IniFile.F76Custom, "Mods", "sResourceDataDirsFinal")) - IniFiles.Instance.Set(IniFile.F76Custom, "Archive", "sResourceDataDirsFinal", sResourceDataDirsFinal); - - /*if (IniFiles.Instance.GetString(IniFile.F76Custom, "Mods", "sResourceIndexFileList", "").Trim().Length == 0) - IniFiles.Instance.Remove(IniFile.F76Custom, "Mods", "sResourceIndexFileList"); - if (IniFiles.Instance.GetString(IniFile.F76Custom, "Mods", "sResourceArchive2List", "").Trim().Length == 0) - IniFiles.Instance.Remove(IniFile.F76Custom, "Mods", "sResourceArchive2List");*/ - if (IniFiles.Instance.GetString(IniFile.F76Custom, "Mods", "sResourceDataDirsFinal", "").Trim().Length == 0) - IniFiles.Instance.Remove(IniFile.F76Custom, "Mods", "sResourceDataDirsFinal"); - } - } -} diff --git a/Fo76ini/Mods/ResourceList.cs b/Fo76ini/Mods/ResourceList.cs new file mode 100644 index 0000000..3813c87 --- /dev/null +++ b/Fo76ini/Mods/ResourceList.cs @@ -0,0 +1,268 @@ +using Fo76ini.Tweaks; +using Fo76ini.Tweaks.ResourceLists; +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Linq; + +namespace Fo76ini.Mods +{ + /// + /// Wrapper around the resource lists to function as a regular List. + /// Implements ways to read and write to *.ini file. + /// + public class ResourceList : ICollection + { + public static List KnownLists = new List() { + "sResourceIndexFileList", + "sResourceArchive2List", + "sResourceStartUpArchiveList", + "SResourceArchiveList", + "SResourceArchiveList2" + }; + + private List resourceList = new List(); + + private ITweak tweak; + + public int Count => this.resourceList.Count; + + public bool IsReadOnly => false; + + + /* + * Constructor: + */ + + /// + /// Creates a new ResourceList from a string. + /// + /// Resources, separated by a ',' + public static ResourceList FromString(String s) + { + ResourceList list = new ResourceList(); + list.resourceList = ResourceList.ToList(s); + return list; + } + + /// + /// Reads the Mods\resources.txt file and loads it's contents. + /// + /// + public static ResourceList FromTXT(String path) + { + ResourceList list = new ResourceList(); + list.LoadTXT(path); + return list; + } + + /// + /// Loads the resource list from the *.ini file. + /// + /// + /// + /// + /// + public static ResourceList FromTweak(ITweak tweak) + { + return new ResourceList(tweak); + } + + public static ResourceList GetDefaultList() + { + return ResourceList.FromTweak( + ResourceListTweak.GetDefaultList() + ); + } + + public static ResourceList GetResourceArchive2List() + { + return ResourceList.FromTweak( + ResourceListTweak.GetSResourceArchive2List() + ); + } + + public static ResourceList GetResourceIndexFileList() + { + return ResourceList.FromTweak( + ResourceListTweak.GetSResourceIndexFileList() + ); + } + + /// + /// Creates an empty list. + /// + public ResourceList() { } + + /// + /// Associates the *.ini value and loads the resource list. + /// + /// + /// + /// + private ResourceList(ITweak tweak) + { + AssociateTweak(tweak); + LoadFromINI(); + } + + /* + * Converting from and to string: + */ + + private static List ToList(string sResourceList) + { + return (new List(sResourceList.Split(new char[] { ',', '\n' }, StringSplitOptions.RemoveEmptyEntries))).Distinct().Select(x => x.Trim()).ToList(); + } + + private static string ToString(List resourceList, string separator = ",") + { + return string.Join(separator, resourceList.Distinct()); + } + + public override string ToString() + { + return ResourceList.ToString(this.resourceList); + } + + public string ToString(string separator) + { + return ResourceList.ToString(this.resourceList, separator); + } + + /// + /// Loads the resource list from the associated *.ini file. + /// + public void LoadFromINI() + { + this.resourceList = ResourceList.ToList(tweak.GetValue()); + } + + /// + /// Commits changes to the resource list for the associated *.ini file. + /// Use IniFiles.Save() to write *.ini file to disk. + /// + public void CommitToINI() + { + if (this.resourceList.Count > 0) + tweak.SetValue(ToString()); + else + tweak.ResetValue(); + } + + /// + /// Associate a value in an *.ini file to save to and load from. + /// + /// + public void AssociateTweak(ITweak tweak) + { + this.tweak = tweak; + } + + + /* + * Writting to and reading from resources.txt: + */ + + /// + /// Writes list to the Mods\resources.txt file. + /// + public void SaveTXT(String path) + { + File.WriteAllText( + path, + this.ToString() + ); + } + + public void LoadTXT(String path) + { + if (File.Exists(path)) + { + string text = File.ReadAllText(path); + this.resourceList = ResourceList.ToList(text); + } + else + { + this.Clear(); + } + } + + + /* + * Implementing ICollection interface: + */ + + public IEnumerator GetEnumerator() + { + return this.resourceList.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + public void Add(string item) + { + this.resourceList.Add(item); + } + + public void Clear() + { + this.resourceList.Clear(); + } + + public bool Contains(string item) + { + return this.resourceList.Contains(item); + } + + public void CopyTo(string[] array, int arrayIndex) + { + this.resourceList.CopyTo(array, arrayIndex); + } + + public bool Remove(string item) + { + return this.resourceList.Remove(item); + } + + + /* + * Additional methods from List: + */ + + /// + /// Inserts an element into the list at the specified index. + /// + public void Insert(int index, string item) + { + this.resourceList.Insert(index, item); + } + + + /* + * Utility methods: + */ + + /// + /// Removes resources that aren't existing on disk. + /// + public void CleanUp(string gamePath) + { + string[] temp = new string[this.Count()]; + this.CopyTo(temp, 0); + foreach (string ba2file in temp) + if (!File.Exists(Path.Combine(gamePath, "Data", ba2file))) + this.Remove(ba2file); + } + + public void ReplaceRange(ResourceList other) + { + this.resourceList.Clear(); + this.resourceList.AddRange(other); + } + } +} diff --git a/Fo76ini/NexusAPI/APIRequest.cs b/Fo76ini/NexusAPI/APIRequest.cs new file mode 100644 index 0000000..7aa5756 --- /dev/null +++ b/Fo76ini/NexusAPI/APIRequest.cs @@ -0,0 +1,134 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Net; +using System.IO; +using Newtonsoft.Json.Linq; + +namespace Fo76ini.NexusAPI +{ + /// + /// Wrapper around the classes of System.Net. + /// Used to make HTTPS requests to the NexusMods' API. + /// + public class APIRequest + { + public string URL; + + private HttpWebRequest request; + private HttpWebResponse response; + + public WebException Exception = null; + + public string PostData = ""; + + public APIRequest(string url) + { + this.URL = url; + this.request = (HttpWebRequest)WebRequest.Create(this.URL); + + this.UserAgent = Shared.AppUserAgent; + this.Headers["Application-Version"] = Shared.VERSION; + this.Headers["Application-Name"] = NexusMods.ApplicationName; + } + + /// + /// Sends the request and reads the response. + /// + public void Execute() + { + this.Success = false; + try + { + // Send POST data, if needed: + if (Method.ToUpper() == "POST" && PostData.Trim() != "") + using (var streamWriter = new StreamWriter(request.GetRequestStream())) + streamWriter.Write(PostData); + + // Get response: + this.response = (HttpWebResponse)request.GetResponse(); + this.Success = true; + + // Read the response: + using (Stream stream = response.GetResponseStream()) + using (StreamReader reader = new StreamReader(stream)) + { + ResponseText = reader.ReadToEnd(); + } + + this.Exception = null; + } + catch (WebException ex) + { + // If the status code isn't 200 (or rather 2xx), it will throw an exception: + if (ex.Response != null) + { + // Get response: + this.response = (HttpWebResponse)ex.Response; + this.Success = true; + + // Read the response: + using (Stream stream = response.GetResponseStream()) + using (StreamReader reader = new StreamReader(stream)) + { + ResponseText = reader.ReadToEnd(); + } + } + + this.Exception = ex; + } + } + + public JObject GetJSON() + { + return JObject.Parse(ResponseText); + } + + public WebHeaderCollection ResponseHeaders + { + get => response.Headers; + } + + public WebHeaderCollection Headers + { + get => request.Headers; + } + + public HttpStatusCode StatusCode + { + get => response.StatusCode; + } + + /// + /// Whether the request was successful. + /// + public bool Success { get; private set; } + public string ResponseText { get; private set; } + + public string UserAgent + { + get => this.request.UserAgent; + set => this.request.UserAgent = value; + } + + public string Accept + { + get => this.request.Accept; + set => this.request.Accept = value; + } + + public string Method + { + get => this.request.Method; + set => this.request.Method = value; + } + + public string RequestContentType + { + get => this.request.ContentType; + set => this.request.ContentType = value; + } + } +} diff --git a/Fo76ini/NexusAPI/NMMod.cs b/Fo76ini/NexusAPI/NMMod.cs new file mode 100644 index 0000000..17f2ad4 --- /dev/null +++ b/Fo76ini/NexusAPI/NMMod.cs @@ -0,0 +1,350 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Newtonsoft.Json.Linq; +using System.Drawing; +using System.IO; +using System.Net; +using System.Windows.Forms; +using System.Xml.Linq; +using Fo76ini.Interface; +using Fo76ini.Utilities; + +namespace Fo76ini.NexusAPI +{ + public class NMMod + { + public int ID = -1; + public string URL = ""; + + public string Title = ""; + public string LatestVersion = ""; + public string Author = ""; + public string Uploader = ""; + public string Summary = ""; + public int EndorsementCount = 0; + public EndorseStatus Endorsement = EndorseStatus.Undecided; + public bool ContainsAdultContent = false; + + public string ThumbnailURL = ""; + public string ThumbnailFileName = ""; + + public string ThumbnailFilePath + { + get => Path.Combine(NexusMods.ThumbnailsPath, ThumbnailFileName); + } + + public long CreatedTimestamp = -1; + public long UpdatedTimestamp = -1; + public long LastAccessTimestamp = -1; + + public enum EndorseStatus + { + Undecided, + Endorsed, + Abstained + } + + /// + /// Creates a new mod from a URL. + /// + /// URL to the mod page. + public NMMod(string url) + { + this.URL = url; + this.ID = NexusMods.GetIDFromURL(url); + } + + /// + /// Creates a new mod from an ID. + /// + /// Mod ID + public NMMod(int id) + { + this.ID = id; + this.URL = $"https://www.nexusmods.com/fallout76/mods/{id}"; + } + + /// + /// Sends a request to the API and retrieves all mod information. + /// Will (optionally) download thumbnails. + /// + public void RequestInformation() + { + if (!NexusMods.User.IsLoggedIn) + { + MsgBox.ShowID("nexusModsNotLoggedIn", MessageBoxIcon.Information); + return; + } + + // Make API request: + APIRequest request = new APIRequest("https://api.nexusmods.com/v1/games/fallout76/mods/" + this.ID + ".json"); + request.Headers["apikey"] = NexusMods.User.APIKey; + request.Execute(); + if (request.Success && request.StatusCode == HttpStatusCode.OK) + { + /* + * Get data: + */ + + JObject json = request.GetJSON(); + this.Title = json["name"].ToString(); + this.Author = json["author"].ToString(); + this.Uploader = json["uploaded_by"].ToString(); + this.Summary = json["summary"].ToString(); + this.EndorsementCount = json["endorsement_count"].ToObject(); + this.CreatedTimestamp = json["created_timestamp"].ToObject(); + this.UpdatedTimestamp = json["updated_timestamp"].ToObject(); + this.ContainsAdultContent = json["contains_adult_content"].ToObject(); + this.ThumbnailURL = json["picture_url"].ToString(); + this.LatestVersion = json["version"].ToString(); + + JObject endorsement = (JObject)json["endorsement"]; + string endorseStatus = endorsement["endorse_status"].ToString(); + switch (endorseStatus) + { + case "Endorsed": + this.Endorsement = EndorseStatus.Endorsed; + break; + case "Abstained": + this.Endorsement = EndorseStatus.Abstained; + break; + case "Undecided": + default: + this.Endorsement = EndorseStatus.Undecided; + break; + } + + + /* + * Download thumbnail: + */ + + if (!Directory.Exists(NexusMods.ThumbnailsPath)) + Directory.CreateDirectory(NexusMods.ThumbnailsPath); + + // If user opted in: + if (IniFiles.Config.GetBool("NexusMods", "bDownloadThumbnailsOnUpdate", true)) + { + try + { + // Example: "https://staticdelivery.nexusmods.com/mods/2590/images/84/84-1542823522-262308780.png" + + // Download if non-existent: + ThumbnailFileName = $"thumb_{this.ID}.jpg"; // Path.GetExtension(Path.GetFileName(uri.LocalPath)); + if (!File.Exists(ThumbnailFilePath)) + { + var thumbRequest = WebRequest.Create(this.ThumbnailURL); + using (var thumbResponse = thumbRequest.GetResponse()) + using (var stream = thumbResponse.GetResponseStream()) + { + // Create a thumbnail (small *.jpg) from the downloaded image: + Image image = Image.FromStream(stream); + Utils.MakeThumbnail(image, ThumbnailFilePath, false, 400, 160, 90L); + } + } + } + catch (Exception ex) + { + // TODO: Handle: Thumbnail couldn't be downloaded. + Console.WriteLine($"Couldn't download thumbnail.\n{ex.GetType().Name}: {ex.Message}"); + } + } + } + else + { + // TODO: Handle: Couldn't retrieve info. + Console.WriteLine($"Couldn't retrieve info.\n{request.Exception.GetType().Name}: {request.Exception.Message}\n{request.ResponseText}"); + } + this.LastAccessTimestamp = Utils.GetUnixTimeStamp(); + } + + /// + /// Endorses this mod. + /// + /// Version that will be endorsed. + /// true if successful; false otherwise + public bool Endorse(string endorsedVersion) + { + APIRequest request = new APIRequest("https://api.nexusmods.com/v1/games/fallout76/mods/" + this.ID + "/endorse.json"); + request.Headers["apikey"] = NexusMods.User.APIKey; + request.Method = "POST"; + + // Without a version: {"code":400,"message":"You must provide a version"} + request.RequestContentType = "application/x-www-form-urlencoded"; + request.PostData = $"version={endorsedVersion}"; + + request.Execute(); + if (request.Success) + { + JObject json = request.GetJSON(); + if (json.ContainsKey("status") && json["status"].ToString() == "Endorsed") + { + this.Endorsement = EndorseStatus.Endorsed; + return true; + } + else + { + MsgBox.Get("failed").FormatText($"Couldn't endorse mod.\nServer message: {json["message"]}").Show(MessageBoxIcon.Error); + return false; + } + } + else + { + MsgBox.Get("failed").FormatText($"Couldn't endorse mod.\nError: {request.Exception.Message}").Show(MessageBoxIcon.Error); + return false; + } + } + + /// + /// Abstains from endorsing this mod. + /// + /// Version that will be abstained. + /// true if successful; false otherwise + public bool Abstain(string abstainedVersion) + { + APIRequest request = new APIRequest("https://api.nexusmods.com/v1/games/fallout76/mods/" + this.ID + "/abstain.json"); + request.Headers["apikey"] = NexusMods.User.APIKey; + request.Method = "POST"; + + // Without a version: {"code":400,"message":"You must provide a version"} + request.RequestContentType = "application/x-www-form-urlencoded"; + request.PostData = $"version={abstainedVersion}"; + + request.Execute(); + if (request.Success) + { + JObject json = request.GetJSON(); + if (json.ContainsKey("status") && json["status"].ToString() == "Abstained") + { + this.Endorsement = EndorseStatus.Abstained; + return true; + } + else + { + MsgBox.Get("failed").FormatText($"Couldn't abstain from endorsing mod.\nServer message: {json["message"]}").Show(MessageBoxIcon.Error); + return false; + } + } + else + { + MsgBox.Get("failed").FormatText($"Couldn't abstain from endorsing mod.\nError: {request.Exception.Message}").Show(MessageBoxIcon.Error); + return false; + } + } + + /// + /// Serializes this mod to an XML element. + /// + public XElement Serialize() + { + XElement xmlMod = new XElement("Mod", + new XAttribute("id", this.ID), + new XAttribute("nsfw", this.ContainsAdultContent)); + + if (this.Title != "") + xmlMod.Add(new XElement("Title", this.Title)); + + if (this.LatestVersion != "") + xmlMod.Add(new XElement("Version", this.LatestVersion)); + + if (this.Author != "") + xmlMod.Add(new XElement("CreatedBy", this.Author)); + + if (this.Uploader != "") + xmlMod.Add(new XElement("UploadedBy", this.Uploader)); + + xmlMod.Add(new XElement("EndorsementCount", this.EndorsementCount)); + xmlMod.Add(new XElement("CreatedTimestamp", this.CreatedTimestamp)); + xmlMod.Add(new XElement("UpdatedTimestamp", this.UpdatedTimestamp)); + + string endorseState = Enum.GetName(typeof(EndorseStatus), (int)this.Endorsement); + xmlMod.Add(new XElement("EndorseState", endorseState)); + + xmlMod.Add(new XElement("Summary", this.Summary)); + + if (this.ThumbnailFileName != "" && this.ThumbnailURL != "") + { + XElement thumbnail = new XElement("Thumbnail"); + thumbnail.Add(new XElement("URL", this.ThumbnailURL)); + thumbnail.Add(new XElement("File", this.ThumbnailFileName)); + xmlMod.Add(thumbnail); + } + + xmlMod.Add(new XElement("LastUpdated", this.LastAccessTimestamp)); + + return xmlMod; + } + + /// + /// Deserializes an XML element to a NMMod. + /// + /// + /// + public static NMMod Deserialize(XElement xmlMod) + { + if (xmlMod.Attribute("id") == null) + throw new InvalidDataException("'id' attribute wasn't provided."); + + NMMod mod = new NMMod(Convert.ToInt32(xmlMod.Attribute("id").Value)); + + if (xmlMod.Element("Title") != null) + mod.Title = xmlMod.Element("Title").Value; + + if (xmlMod.Element("Version") != null) + mod.LatestVersion = xmlMod.Element("Version").Value; + + if (xmlMod.Element("CreatedBy") != null) + mod.Author = xmlMod.Element("CreatedBy").Value; + + if (xmlMod.Element("UploadedBy") != null) + mod.Uploader = xmlMod.Element("UploadedBy").Value; + + if (xmlMod.Element("Summary") != null) + mod.Summary = xmlMod.Element("Summary").Value; + + if (xmlMod.Element("EndorsementCount") != null) + mod.EndorsementCount = Convert.ToInt32(xmlMod.Element("EndorsementCount").Value); + + if (xmlMod.Element("CreatedTimestamp") != null) + mod.CreatedTimestamp = Convert.ToInt64(xmlMod.Element("CreatedTimestamp").Value); + + if (xmlMod.Element("UpdatedTimestamp") != null) + mod.UpdatedTimestamp = Convert.ToInt64(xmlMod.Element("UpdatedTimestamp").Value); + + if (xmlMod.Attribute("nsfw") != null) + mod.ContainsAdultContent = Convert.ToBoolean(xmlMod.Attribute("nsfw").Value); + + XElement thumbnail = xmlMod.Element("Thumbnail"); + if (thumbnail != null) + { + mod.ThumbnailURL = thumbnail.Element("URL").Value; + mod.ThumbnailFileName = thumbnail.Element("File").Value; + } + + if (xmlMod.Element("EndorseState") != null) + { + switch (xmlMod.Element("EndorseState").Value) + { + case "Endorsed": + mod.Endorsement = EndorseStatus.Endorsed; + break; + case "Abstained": + mod.Endorsement = EndorseStatus.Abstained; + break; + case "Undecided": + default: + mod.Endorsement = EndorseStatus.Undecided; + break; + } + } + + if (xmlMod.Element("LastUpdated") != null) + mod.LastAccessTimestamp = Convert.ToInt64(xmlMod.Element("LastUpdated").Value); + + return mod; + } + } +} diff --git a/Fo76ini/NexusAPI/NMUserProfile.cs b/Fo76ini/NexusAPI/NMUserProfile.cs new file mode 100644 index 0000000..c5f2708 --- /dev/null +++ b/Fo76ini/NexusAPI/NMUserProfile.cs @@ -0,0 +1,329 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Newtonsoft.Json.Linq; +using System.Drawing; +using System.IO; +using System.Net; +using System.Windows.Forms; +using System.Xml.Linq; +using Fo76ini.Interface; +using Fo76ini.Utilities; + +namespace Fo76ini.NexusAPI +{ + public class NMUserProfile + { + public enum Membership + { + Basic, + Supporter, + Premium + } + + public string APIKey = ""; + + public string UserName = "Anonymous"; + public long UserID = -1; + public Membership Status = Membership.Basic; + + public string ProfilePictureURL = ""; + public string ProfilePictureFileName = ""; + + public string ProfilePictureFilePath + { + get => Path.Combine(NexusMods.FolderPath, ProfilePictureFileName); + } + + public int DailyRateLimit = 0; + public int HourlyRateLimit = 0; + public string DailyRateLimitResetString = ""; + + /// + /// Whether the user is currently logged in. + /// + public bool IsLoggedIn + { + get { return APIKey != null && APIKey != "" && UserID > 0; } + } + + public NMUserProfile() { } + + /// + /// Updates profile information. + /// + public void Update() + { + // Make API request: + APIRequest request = new APIRequest($"{NexusMods.APIDomain}/v1/users/validate.json"); + request.Headers["apikey"] = APIKey; + request.Execute(); + if (request.Success && request.StatusCode == HttpStatusCode.OK) + { + try + { + JObject json = request.GetJSON(); + + UserName = json["name"].ToString(); + ProfilePictureURL = json["profile_url"].ToString(); + UserID = Convert.ToInt64(json["user_id"].ToString()); + + if (json["is_premium"].Value() || json["is_premium?"].Value()) + Status = Membership.Premium; + else if (json["is_supporter"].Value() || json["is_supporter?"].Value()) + Status = Membership.Supporter; + else + Status = Membership.Basic; + + DailyRateLimit = Convert.ToInt32(request.ResponseHeaders["x-rl-daily-remaining"]); + DailyRateLimitResetString = request.ResponseHeaders["x-rl-daily-reset"]; + HourlyRateLimit = Convert.ToInt32(request.ResponseHeaders["X-RL-Hourly-Remaining"]); + + DownloadProfilePicture(); + + /* + Unused values: + - "key" + - "email" + */ + } + catch (Exception e) + { + MsgBox.Get("failed").FormatText($"Unexpected exception: {e.Message}\n{e.StackTrace}\n\n{e.InnerException}").Show(MessageBoxIcon.Error); + } + } + else + { + try + { + if (request.Success) + MsgBox.Get("failed").FormatText($"Server returned: HTTP {request.StatusCode}\n{request.GetJSON()["message"]}").Show(MessageBoxIcon.Error); + else + MsgBox.Get("failed").FormatText($"WebException: {request.Exception.Message}").Show(MessageBoxIcon.Error); + } + catch (Exception e) + { + MsgBox.Get("failed").FormatText($"Unexpected exception: {e.Message}").Show(MessageBoxIcon.Error); + } + } + } + + private void DownloadProfilePicture() + { + try + { + Uri uri = new Uri(ProfilePictureURL); + ProfilePictureFileName = "profile" + Path.GetExtension(Path.GetFileName(uri.LocalPath)); + + // Download if non-existent: + if (!File.Exists(ProfilePictureFilePath)) + { + Directory.CreateDirectory(NexusMods.FolderPath); + using (var client = new WebClient()) + client.DownloadFile(ProfilePictureURL, ProfilePictureFilePath); + } + } + catch (UriFormatException exc) + { + // TODO: Handle exception + Console.WriteLine($"Not a valid URL: '{ProfilePictureURL}'\nSystem.UriFormatException: {exc.Message}"); + ProfilePictureFileName = ""; + } + } + + /// + /// Saves user profile information to account.xml + /// + public void Save() + { + /* + + + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + + + datasnake01 + Premium + + + + 2020-12-07 00:00:00 +0010 + + + */ + + XDocument xmlDoc = new XDocument(); + XElement xmlRoot = new XElement("Account", new XAttribute("id", UserID)); + xmlDoc.Add(xmlRoot); + + /* + * Authentification + */ + + // Add apikey: + XElement xmlAuth = new XElement("Authentification"); + if (APIKey != null && APIKey != "") + xmlAuth.Add(new XElement("APIKey", APIKey)); + xmlRoot.Add(xmlAuth); + + + /* + * Profile + */ + + XElement xmlProfile = new XElement("Profile", + new XElement("Username", UserName), + new XElement("Membership", Status.ToString()) + ); + xmlRoot.Add(xmlProfile); + + if (ProfilePictureURL != "" && ProfilePictureFileName != "") + { + xmlProfile.Add(new XElement("Picture", + new XAttribute("url", ProfilePictureURL), + new XAttribute("file", ProfilePictureFileName) + )); + } + + + /* + * RateLimit + */ + + xmlRoot.Add(new XElement("RateLimit", + new XAttribute("daily", DailyRateLimit), + new XAttribute("hourly", HourlyRateLimit), + new XElement("DailyResetTime", DailyRateLimitResetString) + )); + + xmlDoc.Save(NexusMods.AccountXMLPath); + } + + /// + /// Loads user profile information from account.xml + /// + public bool Load() + { + if (!File.Exists(NexusMods.AccountXMLPath)) + return false; + + XDocument xmlDoc = XDocument.Load(NexusMods.AccountXMLPath); + XElement xmlRoot = xmlDoc.Root; + + if (xmlRoot.Attribute("id") != null) + if (!xmlRoot.Attribute("id").TryParseLong(out UserID)) + UserID = -1; + + /* + * Authentification + */ + + XElement xmlAuth = xmlRoot.Element("Authentification"); + if (xmlAuth != null && xmlAuth.Element("APIKey") != null) + APIKey = xmlAuth.Element("APIKey").Value; + + + /* + * Profile + */ + + XElement xmlProfile = xmlRoot.Element("Profile"); + if (xmlProfile != null) + { + if (xmlProfile.Element("Username") != null) + UserName = xmlProfile.Element("Username").Value; + if (xmlProfile.Element("Membership") != null) + Enum.TryParse(xmlProfile.Element("Membership").Value, out Status); + + // Profile picture + XElement xmlProfilePicture = xmlProfile.Element("Picture"); + if (xmlProfilePicture != null && xmlProfilePicture.Attribute("url") != null && xmlProfilePicture.Attribute("file") != null) + { + ProfilePictureURL = xmlProfilePicture.Attribute("url").Value; + ProfilePictureFileName = xmlProfilePicture.Attribute("file").Value; + } + } + + + /* + * RateLimit + */ + + XElement xmlRateLimit = xmlRoot.Element("RateLimit"); + if (xmlRateLimit != null) + { + if (xmlRateLimit.Attribute("daily") != null) + xmlRateLimit.Attribute("daily").TryParseInt(out DailyRateLimit); + + if (xmlRateLimit.Attribute("hourly") != null) + xmlRateLimit.Attribute("hourly").TryParseInt(out HourlyRateLimit); + + if (xmlRateLimit.Element("DailyResetTime") != null) + DailyRateLimitResetString = xmlRateLimit.Element("DailyResetTime").Value; + } + + return true; + } + + public bool TryParseDailyRateLimitReset(out DateTime result) + { + try + { + result = DateTime.ParseExact(DailyRateLimitResetString, "yyyy-MM-dd HH:mm:ss zzz", System.Globalization.CultureInfo.InvariantCulture); + return true; + } + catch + { + result = DateTime.Now; + return false; + } + } + + /// + /// Removes user profile information and thumbnail. + /// + public void Remove() + { + // Remove old values from config.ini: + IniFiles.Config.Remove("NexusMods", "sAPIKey"); + IniFiles.Config.Remove("NexusMods", "bAPIKeyValid"); + IniFiles.Config.Remove("NexusMods", "sUserName"); + IniFiles.Config.Remove("NexusMods", "iUserID"); + IniFiles.Config.Remove("NexusMods", "sProfileURL"); + IniFiles.Config.Remove("NexusMods", "sProfile"); + IniFiles.Config.Remove("NexusMods", "iDailyRateLimit"); + IniFiles.Config.Remove("NexusMods", "iHourlyRateLimit"); + IniFiles.Config.Remove("NexusMods", "sDailyRateLimitReset"); + IniFiles.Config.Remove("NexusMods", "sMembership"); + IniFiles.Config.Save(); + + // Remove accounts.xml: + if (File.Exists(NexusMods.AccountXMLPath)) + File.Delete(NexusMods.AccountXMLPath); + + // Remove profile picture: + try + { + if (File.Exists(ProfilePictureFilePath)) + File.Delete(ProfilePictureFilePath); + } + catch (Exception ex) + { + Console.WriteLine($"Couldn't remove profile picture: {ex.Message}"); + } + + // Reset values: + APIKey = ""; + UserName = "Anonymous"; + UserID = -1; + ProfilePictureFileName = ""; + ProfilePictureURL = ""; + Status = Membership.Basic; + DailyRateLimit = 0; + HourlyRateLimit = 0; + DailyRateLimitResetString = ""; + } + } +} diff --git a/Fo76ini/NexusAPI/NexusMods.cs b/Fo76ini/NexusAPI/NexusMods.cs new file mode 100644 index 0000000..0e2023c --- /dev/null +++ b/Fo76ini/NexusAPI/NexusMods.cs @@ -0,0 +1,174 @@ +using Newtonsoft.Json.Linq; +using System; +using System.Collections.Generic; +using System.Drawing; +using System.IO; +using System.Net; +using System.Windows.Forms; +using System.Xml.Linq; +using Fo76ini.Interface; +using Fo76ini.Utilities; + +namespace Fo76ini.NexusAPI +{ + public static class NexusMods + { + public const string APIDomain = "https://api.nexusmods.com"; + public const string SSODomain = "wss://sso.nexusmods.com"; + public const string ApplicationSlug = "fo76quickconfiguration"; + public const string ApplicationName = "Fallout 76 Quick Configuration"; + + public static string FolderPath = Path.Combine(Shared.AppConfigFolder, "nexusmods"); + public static string ThumbnailsPath = Path.Combine(Shared.AppConfigFolder, "thumbnails", "nexusmods"); + public static string RemoteXMLPath = Path.Combine(NexusMods.FolderPath, "mods.xml"); + public static string AccountXMLPath = Path.Combine(NexusMods.FolderPath, "account.xml"); + + public static Dictionary Mods = new Dictionary(); + + private static readonly object padlock = new object(); + private static NMUserProfile _nmprofile = null; + + static NexusMods () + { + SingleSignOn.SSOFinished += OnSSOLogin; + } + + public static NMUserProfile User + { + get + { + lock (padlock) + { + if (_nmprofile == null) + _nmprofile = new NMUserProfile(); + return _nmprofile; + } + } + } + + /// + /// Saves the user's profile and mods. + /// + public static void Save() + { + if (!Directory.Exists(NexusMods.FolderPath)) + Directory.CreateDirectory(NexusMods.FolderPath); + + Serialize().Save(NexusMods.RemoteXMLPath); + + NexusMods.User.Save(); + } + + /// + /// Serializes all mods to an *.xml document. + /// + public static XDocument Serialize() + { + /* + Fallout 76 Quick Configuration\nexusmods\remote.xml + + + + + + */ + + XDocument xmlDoc = new XDocument(); + XElement xmlRoot = new XElement("Mods"); + xmlDoc.Add(xmlRoot); + foreach (NMMod mod in Mods.Values) + xmlRoot.Add(mod.Serialize()); + return xmlDoc; + } + + /// + /// Loads the user's profile and mods. + /// + public static void Load() + { + Mods.Clear(); + + NexusMods.User.Load(); + + if (!File.Exists(NexusMods.RemoteXMLPath)) + return; + + XDocument xmlDoc = XDocument.Load(NexusMods.RemoteXMLPath); + foreach (XElement xmlMod in xmlDoc.Descendants("Mod")) + { + try + { + NMMod mod = NMMod.Deserialize(xmlMod); + Mods[mod.ID] = mod; + } + catch + { + // TODO: Handle invalid entries. + } + } + } + + private static void OnSSOLogin(object sender, SSOEventArgs e) + { + /*if (e.success) + { + User.APIKey = e.APIKey; + User.Save(); + }*/ + } + + /// + /// Requests remote information about a mod. + /// + /// The url to the mod page. Example: "https://www.nexusmods.com/fallout76/mods/419?tab=files" + public static void RequestModInformation(string url) + { + NMMod mod = new NMMod(url); + mod.RequestInformation(); + Mods[mod.ID] = mod; + } + + /// + /// Deletes any downloaded information about mods and it's thumbnails. + /// + public static void DeleteCache() + { + // Remove remote info: + Mods.Clear(); + + if (File.Exists(NexusMods.RemoteXMLPath)) + File.Delete(NexusMods.RemoteXMLPath); + + // Delete thumbnails + try + { + string path = Path.Combine(NexusMods.ThumbnailsPath); + if (Directory.Exists(path)) + Directory.Delete(path, true); + } + catch + { + // TODO: Handle exceptions. + } + } + + /// + /// Extracts the mod ID from a URL. + /// + /// The url to the mod page. Example: "https://www.nexusmods.com/fallout76/mods/419?tab=files" + /// The mod ID. Example: 419 + public static int GetIDFromURL(string url) + { + if (url == "" || !url.Contains("www.nexusmods.com/fallout76/mods")) + return -1; + + string modId = url.Substring(url.IndexOf("fallout76/mods/") + 15); + if (modId.Contains("?")) + modId = modId.Substring(0, modId.IndexOf("?")); + + if (Int32.TryParse(modId, out int result)) + return result; + return -1; + } + } +} diff --git a/Fo76ini/NexusAPI/SingleSignOn.cs b/Fo76ini/NexusAPI/SingleSignOn.cs new file mode 100644 index 0000000..b8351f2 --- /dev/null +++ b/Fo76ini/NexusAPI/SingleSignOn.cs @@ -0,0 +1,153 @@ +using Fo76ini.Utilities; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using Websocket.Client; +using Websocket.Client.Models; + +namespace Fo76ini.NexusAPI +{ + // TODO: Possible bug in SingleSignOn + // There might be a bug where if no message is received from the server within 30 seconds (see TimeSpan ReconnectTimeout), + // the client will try to reconnect and the login fails. + + public static class SingleSignOn + { + public static event SSOEventHandler SSOFinished; + + private static Guid uuidv4; + private static string connectionToken = null; + + private static readonly TimeSpan ReconnectTimeout = TimeSpan.FromSeconds(60); + + private static WebsocketClient client = null; + + private static bool success = false; + + public static void Connect () + { + if (client != null && client.IsRunning) + client.Stop(System.Net.WebSockets.WebSocketCloseStatus.NormalClosure, ""); + + success = false; + client = new WebsocketClient(new Uri(NexusMods.SSODomain)); + client.ReconnectTimeout = ReconnectTimeout; + client.ReconnectionHappened.Subscribe(OnReconnect); + client.MessageReceived.Subscribe(OnMessage); + client.DisconnectionHappened.Subscribe(OnDisconnect); + client.Start(); + + string data = BuildLoginData(); + + client.Send(data); // SendInstant + } + + private static void OnMessage(ResponseMessage msg) + { + if (msg.MessageType == System.Net.WebSockets.WebSocketMessageType.Text) + { + JObject response = JObject.Parse(msg.Text); + + if (response["success"].Value()) + { + JObject data = (JObject)response["data"]; + + if (data.ContainsKey("connection_token")) + { + connectionToken = data["connection_token"].ToString(); + + Utils.OpenURL("https://www.nexusmods.com/sso?id=" + uuidv4 + "&application=" + NexusMods.ApplicationSlug); + } + + if (data.ContainsKey("api_key")) + { + success = true; + + SSOEventArgs e = new SSOEventArgs(); + e.APIKey = data["api_key"].ToString(); + e.success = true; + + if (SSOFinished != null) + SSOFinished(null, e); + } + } + else + { + Console.WriteLine($"Something went wrong: {response["error"]}"); + } + } + else + { + Console.WriteLine($"Received message was not of type 'Text': {msg}"); + return; + } + } + + private static void OnReconnect(ReconnectionInfo info) + { + Console.WriteLine($"Reconnection happened, type: {info.Type}"); + } + + private static void OnDisconnect(DisconnectionInfo info) + { + Console.WriteLine( + $"---- Disconnection happened. ----\n" + + $"Reason: {info.CloseStatus}\n" + + $"Message: {info.CloseStatusDescription}\n" + + $"Subprotocol: {info.SubProtocol}\n" + + $"Exception: {info.Exception}\n" + + $"---------------------------------"); + + if (success) + { + info.CancelReconnection = true; + } + else if (info.Exception != null) + { + info.CancelReconnection = true; + + SSOEventArgs e = new SSOEventArgs(); + e.Exception = info.Exception; + e.success = false; + + if (SSOFinished != null) + SSOFinished(null, e); + } + } + + + private class LoginData + { + public string id; + public string token; + public int protocol; + } + + private static string BuildLoginData() + { + if (uuidv4 == Guid.Empty) + uuidv4 = Guid.NewGuid(); + + LoginData loginData = new LoginData(); + loginData.id = uuidv4.ToString(); + loginData.token = connectionToken; + loginData.protocol = 2; + + return JsonConvert.SerializeObject(loginData); + } + } + + public delegate void SSOEventHandler(object sender, SSOEventArgs e); + + public class SSOEventArgs : EventArgs + { + public bool success; + public string APIKey = ""; + public Exception Exception = null; + } +} diff --git a/Fo76ini/Profiles/GameInstance.cs b/Fo76ini/Profiles/GameInstance.cs new file mode 100644 index 0000000..52d956b --- /dev/null +++ b/Fo76ini/Profiles/GameInstance.cs @@ -0,0 +1,176 @@ +using Fo76ini.Interface; +using System; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.Diagnostics; +using System.IO; +using System.Xml.Linq; + +namespace Fo76ini.Profiles +{ + public enum GameEdition + { + Unknown = 0, + BethesdaNet = 1, + Steam = 2, + BethesdaNetPTS = 3, + MSStore = 4 + } + + public enum LaunchOption + { + OpenURL = 0, // Launch through Steam or Bethesda.net + RunExec = 1 // Run executable directly + } + + /// + /// Represents a game installation. Contains information such as path and executable name. + /// + public class GameInstance + { + public string Title = "Untitled"; + public GameEdition Edition = GameEdition.Unknown; + public string GamePath = ""; + public string ExecutableName = "Fallout76.exe"; + public string IniPrefix = "Fallout76"; + public string ExecParameters = ""; + public string LauncherURL; + public LaunchOption PreferredLaunchOption = LaunchOption.OpenURL; + + /// + /// Sets the default settings (such as executable name, ini prefix, and launcher url) for the game edition. + /// + public void SetDefaultSettings(GameEdition edition) + { + switch (edition) + { + case GameEdition.Steam: + this.ExecutableName = "Fallout76.exe"; + this.IniPrefix = "Fallout76"; + this.LauncherURL = "steam://run/1151340"; + this.PreferredLaunchOption = LaunchOption.OpenURL; + break; + case GameEdition.BethesdaNet: + this.ExecutableName = "Fallout76.exe"; + this.IniPrefix = "Fallout76"; + this.LauncherURL = "bethesdanet://run/20"; + this.PreferredLaunchOption = LaunchOption.OpenURL; + break; + case GameEdition.BethesdaNetPTS: + this.ExecutableName = "Fallout76.exe"; + this.IniPrefix = "Fallout76"; + this.LauncherURL = "bethesdanet://run/57"; + this.PreferredLaunchOption = LaunchOption.OpenURL; + break; + case GameEdition.MSStore: + this.ExecutableName = "Project76_GamePass.exe"; + this.IniPrefix = "Project76"; + this.LauncherURL = "ms-windows-store://pdp/?ProductId=9nkgnmnk3k3z"; + this.PreferredLaunchOption = LaunchOption.OpenURL; + break; + default: + this.ExecutableName = "Fallout76.exe"; + this.IniPrefix = "Fallout76"; + this.LauncherURL = ""; + this.PreferredLaunchOption = LaunchOption.RunExec; + break; + } + } + + public XElement Serialize () + { + XElement xmlGameInstance = new XElement("Game", + new XElement("Title", Title), + new XElement("InstallationPath", GamePath), + new XElement("ExecutableName", ExecutableName), + new XElement("ExecParameters", ExecParameters), + new XElement("LauncherURL", LauncherURL), + new XElement("IniPrefix", IniPrefix), + new XElement("GameEdition", Edition.ToString()), + new XElement("LaunchOption", PreferredLaunchOption.ToString()) + ); + + return xmlGameInstance; + } + + public static GameInstance Deserialize (XElement xmlGameInstance) + { + GameInstance game = new GameInstance(); + + game.Title = xmlGameInstance.Element("Title").Value; + game.GamePath = xmlGameInstance.Element("InstallationPath").Value; + game.ExecutableName = xmlGameInstance.Element("ExecutableName").Value; + game.ExecParameters = xmlGameInstance.Element("ExecParameters").Value; + game.LauncherURL = xmlGameInstance.Element("LauncherURL").Value; + game.IniPrefix = xmlGameInstance.Element("IniPrefix").Value; + + if (Enum.TryParse(xmlGameInstance.Element("GameEdition").Value, out GameEdition edition)) + game.Edition = edition; + + if (Enum.TryParse(xmlGameInstance.Element("LaunchOption").Value, out LaunchOption launchOption)) + game.PreferredLaunchOption = launchOption; + + return game; + } + + /// + /// Starts the game using the preferred launch option. + /// + public void LaunchGame() + { + LaunchGame(this.PreferredLaunchOption); + } + + /// + /// Starts the game using the passed on launch option. + /// + /// Whether to run the executable or open the launcher url. + public void LaunchGame(LaunchOption option) + { + switch (option) + { + case LaunchOption.OpenURL: + try + { + Process.Start(this.LauncherURL); + } + catch + { + MsgBox.Show("Couldn't start game", "Please make sure to provide a valid 'Launcher URL'.", System.Windows.Forms.MessageBoxIcon.Error); + } + break; + case LaunchOption.RunExec: + try + { + Process pr = new Process(); + pr.StartInfo.FileName = Path.Combine(this.GamePath, this.ExecutableName); + pr.StartInfo.WorkingDirectory = this.GamePath; + pr.StartInfo.Arguments = this.ExecParameters; + pr.StartInfo.UseShellExecute = false; + pr.Start(); + } + catch + { + MsgBox.Show("Couldn't start game", "Please make sure that the game path and executable name are correct.", System.Windows.Forms.MessageBoxIcon.Error); + } + break; + } + } + + /// + /// Checks whether the passed on game path is valid. + /// + public static bool ValidateGamePath(string path) + { + return path != null && path.Trim().Length > 0 && Directory.Exists(path) && Directory.Exists(Path.Combine(path, "Data")); + } + + /// + /// Checks whether the current game path is valid. + /// + public bool ValidateGamePath() + { + return ValidateGamePath(GamePath); + } + } +} diff --git a/Fo76ini/Profiles/ProfileManager.cs b/Fo76ini/Profiles/ProfileManager.cs new file mode 100644 index 0000000..edff060 --- /dev/null +++ b/Fo76ini/Profiles/ProfileManager.cs @@ -0,0 +1,253 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Xml.Linq; + +namespace Fo76ini.Profiles +{ + /// + /// Loads, saves, and manages game profiles. + /// + public static class ProfileManager + { + public static event ProfileEventHandler ProfileChanged; + private static List games = new List(); + private static int selectedGameIndex; + + public static IEnumerable Games + { + get { return games.Select(x => x); } + } + + public static int Count + { + get { return games.Count; } + } + + public static int SelectedGameIndex + { + get { return selectedGameIndex; } + set + { + selectedGameIndex = value; + Feedback(); + } + } + + public static void Feedback() + { + if (ProfileChanged != null) + ProfileChanged(null, BuildProfileEventArgs()); + + // Backwards-compatibility: + IniFiles.Config.Set("Preferences", "uGameEdition", (int)SelectedGame.Edition); + IniFiles.Config.Set("Preferences", "sGamePath", SelectedGame.GamePath); + IniFiles.Config.Set("Preferences", $"sGamePath{SelectedGame.Edition}", SelectedGame.GamePath); + } + + public static string XMLPath = Path.Combine(Shared.AppConfigFolder, "profiles.xml"); + + public static void AddGame(GameInstance game) + { + games.Add(game); + } + + public static void RemoveGame(GameInstance game) + { + games.Remove(game); + } + + public static int FindIndex(GameInstance game) + { + return games.FindIndex((GameInstance search) => search == game); + } + + public static void SelectGame(GameInstance game) + { + SelectedGameIndex = FindIndex(game); + } + + public static GameInstance SelectedGame + { + get + { + if (SelectedGameIndex < 0 || SelectedGameIndex >= games.Count) + return null; + return games[SelectedGameIndex]; + } + } + + public static bool IsSelected(GameInstance game) + { + return SelectedGameIndex >= 0 && SelectedGameIndex == FindIndex(game); + } + + /*public Profile SelectedProfile + { + get { return games[selectedGameGuid].SelectedProfile; } + }*/ + + public static void Save() + { + XDocument xmlDoc = new XDocument(); + XElement xmlRoot = new XElement("Games", + new XAttribute("selected", SelectedGameIndex) + ); + + foreach (GameInstance game in games) + xmlRoot.Add(game.Serialize()); + + xmlDoc.Add(xmlRoot); + xmlDoc.Save(XMLPath); + } + + public static void Load() + { + if (!File.Exists(XMLPath)) + { + Init(); + Feedback(); // This is important. + return; + } + + XDocument xmlDoc = XDocument.Load(XMLPath); + + games.Clear(); + foreach (XElement xmlGame in xmlDoc.Descendants("Game")) + AddGame(GameInstance.Deserialize(xmlGame)); + + SelectedGameIndex = Convert.ToInt32(xmlDoc.Root.Attribute("selected").Value); + + // Call event handler: + Feedback(); + } + + private static void Init() + { + // If tool has been started for the first time, no profiles are available. + // Create profiles and save the xml. + + // No games? + if (games.Count == 0) + { + // Do we have legacy profiles? + if (IniFiles.Config != null && IniFiles.Config.Exists("Preferences", "uGameEdition")) + { + // then convert them: + ConvertLegacyFormat(); + } + else + { + // else create a new game profile from scratch: + GameInstance defaultGame = new GameInstance(); + if (File.Exists(Path.Combine(IniFiles.ParentPath, "Project76.ini"))) + { + // "Project76.ini" exists, which means the user has it from the Microsoft Store + defaultGame.Edition = GameEdition.MSStore; + defaultGame.SetDefaultSettings(GameEdition.MSStore); + } + AddGame(defaultGame); + SelectGame(defaultGame); + } + } + + // No game selected? + if (SelectedGameIndex < 0) + { + // Select first game in list: + SelectedGameIndex = 0; + } + + Save(); + } + + /// + /// Converts legacy profiles from v1.8.4h1 and prior to new format. + /// + private static void ConvertLegacyFormat() + { + // Some people might have denied NTFS write permission. Give permission back: + IniFiles.SetNTFSWritePermission(true); + IniFiles.Config.Remove("Preferences", "bDenyNTFSWritePermission"); + + // If NWMode was active, then the Fallout76Custom.ini might have been renamed to Fallout76Custom.ini.nwmodebak + // Rename it back: + string f76C_NW = Path.Combine(IniFiles.ParentPath, "Fallout76Custom.ini.nwmodebak"); + string f76C = Path.Combine(IniFiles.ParentPath, "Fallout76Custom.ini"); + string p76C_NW = Path.Combine(IniFiles.ParentPath, "Project76Custom.ini.nwmodebak"); + string p76C = Path.Combine(IniFiles.ParentPath, "Project76Custom.ini"); + if (File.Exists(f76C_NW) && !File.Exists(f76C)) + File.Move(f76C_NW, f76C); + if (File.Exists(p76C_NW) && !File.Exists(p76C)) + File.Move(p76C_NW, p76C); + + // sGamePath [ + MSStore / BethesdaNet / BethesdaNetPTS / Steam ] + // uLaunchOption (1 = OpenURL) (2 = RunExec) + // uGameEdition + + // Iterate over each possible key: + List editions = new List { GameEdition.BethesdaNet, GameEdition.Steam, GameEdition.BethesdaNetPTS, GameEdition.MSStore }; + List gamePathKeys = new List() { "sGamePathBethesdaNet", "sGamePathSteam", "sGamePathBethesdaNetPTS", "sGamePathMSStore" }; + for (int i = 0; i < gamePathKeys.Count; i++) + { + // Get the game path. Skip if empty. + string gamePath = IniFiles.Config.GetString("Preferences", gamePathKeys[i], ""); + if (gamePath == "") + continue; + + GameInstance game = new GameInstance(); + game.GamePath = gamePath; + game.Edition = editions[i]; // (GameEdition)(i + 1) + game.SetDefaultSettings(game.Edition); + + // If the index matches uGameEdition, then this is the default game edition: + bool selected = IniFiles.Config.GetUInt("Preferences", "uGameEdition", 0) - 1 == i; + + if (selected) + { + uint uLaunchOption = IniFiles.Config.GetUInt("Preferences", "uLaunchOption", 1); + game.PreferredLaunchOption = uLaunchOption == 2 ? LaunchOption.RunExec : LaunchOption.OpenURL; + } + + switch (game.Edition) + { + case GameEdition.BethesdaNet: + game.Title = "Bethesda.net"; + break; + case GameEdition.BethesdaNetPTS: + game.Title = "Bethesda.net (PTS)"; + break; + case GameEdition.Steam: + game.Title = "Steam"; + break; + case GameEdition.MSStore: + game.Title = "Microsoft Store"; + break; + } + + AddGame(game); + if (selected) + SelectGame(game); + } + } + + private static ProfileEventArgs BuildProfileEventArgs() + { + ProfileEventArgs args = new ProfileEventArgs(); + args.ActiveGameInstance = SelectedGame; + args.GameIndex = SelectedGameIndex; + return args; + } + } + + public delegate void ProfileEventHandler(object sender, ProfileEventArgs e); + + public class ProfileEventArgs : EventArgs + { + public GameInstance ActiveGameInstance; + public int GameIndex; + } +} diff --git a/Fo76ini/Program.cs b/Fo76ini/Program.cs index 4f0a3e3..27f33aa 100644 --- a/Fo76ini/Program.cs +++ b/Fo76ini/Program.cs @@ -1,10 +1,7 @@ using Fo76ini.Forms.ExceptionDialog; using System; -using System.Collections.Generic; -using System.Linq; using System.Net; using System.Threading; -using System.Threading.Tasks; using System.Windows.Forms; namespace Fo76ini diff --git a/Fo76ini/Progress.cs b/Fo76ini/Progress.cs new file mode 100644 index 0000000..67c6fd0 --- /dev/null +++ b/Fo76ini/Progress.cs @@ -0,0 +1,162 @@ +using Fo76ini.Utilities; +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace Fo76ini +{ + /// + /// A simple class that holds a percentage, a progress text, and other information + some utility methods. + /// + public class Progress + { + /// + /// Percentage between 0.0f and 1.0f. + /// + public float Percentage = 0.0f; + public string Text = ""; + public Color? TextColor = null; + public bool IsDone = false; + public bool Success = true; + public Exception Exc = null; + + /// + /// Rounded percentage between 0 and 100. + /// + public int RoundedPercentage + { + get + { + return Utils.Clamp((int)Math.Round(Percentage * 100f, 0), 0, 100); + } + } + + /// + /// Progress is ongoing and we now the exact percentage. + /// + public static Progress Ongoing(string text, float percentage) + { + Progress progress = new Progress(); + progress.Percentage = percentage; + progress.Text = text; + return progress; + } + + /// + /// Progress is ongoing, but we don't know the exact percentage. + /// + public static Progress Indetermined(string text) + { + Progress progress = new Progress(); + progress.Percentage = -1; + progress.Text = text; + return progress; + } + + /// + /// The operation was successful. + /// + public static Progress Done(string text = null) + { + Progress progress = new Progress(); + progress.Text = text != null ? text : "Done"; + progress.IsDone = true; + progress.Success = true; + progress.Percentage = 100; + return progress; + } + + /// + /// The operation was aborted due to an error. + /// + public static Progress Aborted(string text, Exception exc = null) + { + Progress progress = new Progress(); + progress.IsDone = true; + progress.Success = false; + progress.Exc = exc; + progress.Text = text; + progress.Percentage = 0; + return progress; + } + + public void Update (Label label, ProgressBar progressbar) + { + /* + * Progress bar + */ + + if (Percentage < 0) + { + progressbar.Style = ProgressBarStyle.Marquee; + //this.progressBarMods.MarqueeAnimationSpeed = 15; + } + else + { + progressbar.Style = ProgressBarStyle.Continuous; + progressbar.Value = RoundedPercentage; + } + + + /* + * Label + */ + + if (TextColor != null) + label.ForeColor = (Color)TextColor; + else if (IsDone && Success) + label.ForeColor = Color.DarkGreen; + else if (IsDone && !Success) + label.ForeColor = Color.Red; + else + label.ForeColor = Color.Black; + + label.Text = Text; + if (Exc != null) + label.Text += " - " + Exc.Message; + } + + /// + /// Changes the progress object to be part of a "phase". + /// + /// Example: + /// "'some.jpg' - 58% copied" + /// [****** ] 58% + /// + /// turns into + /// + /// "Copying 5 of 39 files - 'some.jpg' - 58% copied" + /// [* ] 12% + /// + /// Example: "Copying {0} of {1} files - {2}" + /// + /// + /// + public Progress AsPhase(string formattedPhaseStr, int currentPhase, int phaseCount) + { + return this.AsPhase(formattedPhaseStr, currentPhase, phaseCount, (float)(currentPhase - 1) / (float)phaseCount, 1f / (float)phaseCount); + } + + public Progress AsPhase (string formattedPhaseStr, int currentPhase, int phaseCount, float progressSoFar, float phaseAmountsTo) + { + if (this.Percentage >= 0 && this.Percentage <= 100) + this.Percentage = progressSoFar + this.Percentage * phaseAmountsTo; + else + this.Percentage = progressSoFar; + this.Text = String.Format(formattedPhaseStr, currentPhase, phaseCount, this.Text); + this.IsDone = false; + return this; + } + + public static Action BuildPhasedProgressChanged(Action originalProgressChanged, string formattedPhaseStr, int currentPhase, int phaseCount) + { + return (progress) => { + originalProgressChanged(progress.AsPhase(formattedPhaseStr, currentPhase, phaseCount)); + }; + } + } +} diff --git a/Fo76ini/Properties/AssemblyInfo.cs b/Fo76ini/Properties/AssemblyInfo.cs index 4e9cfde..652f4c3 100644 --- a/Fo76ini/Properties/AssemblyInfo.cs +++ b/Fo76ini/Properties/AssemblyInfo.cs @@ -1,6 +1,5 @@ -using System.Resources; -using System.Reflection; -using System.Runtime.CompilerServices; +using System.Reflection; +using System.Resources; using System.Runtime.InteropServices; // Allgemeine Informationen über eine Assembly werden über die folgenden diff --git a/Fo76ini/Properties/Resources.Designer.cs b/Fo76ini/Properties/Resources.Designer.cs index 0abad49..17df2b7 100644 --- a/Fo76ini/Properties/Resources.Designer.cs +++ b/Fo76ini/Properties/Resources.Designer.cs @@ -60,6 +60,16 @@ internal Resources() { } } + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap add_archive_3_24 { + get { + object obj = ResourceManager.GetObject("add-archive-3-24", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// @@ -140,6 +150,26 @@ internal static System.Drawing.Bitmap available_updates { } } + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap available_updates_48 { + get { + object obj = ResourceManager.GetObject("available_updates_48", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap banner { + get { + object obj = ResourceManager.GetObject("banner", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// @@ -200,6 +230,16 @@ internal static System.Drawing.Bitmap button_hover { } } + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap checkbox_24 { + get { + object obj = ResourceManager.GetObject("checkbox-24", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// @@ -210,6 +250,16 @@ internal static System.Drawing.Bitmap checked_checkbox_24 { } } + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap cog_24 { + get { + object obj = ResourceManager.GetObject("cog-24", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// @@ -220,6 +270,46 @@ internal static System.Drawing.Bitmap delete_24 { } } + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap delete_48 { + get { + object obj = ResourceManager.GetObject("delete-48", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap dislike { + get { + object obj = ResourceManager.GetObject("dislike", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap download_2_24 { + get { + object obj = ResourceManager.GetObject("download-2-24", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap download_2_48 { + get { + object obj = ResourceManager.GetObject("download_2_48", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// @@ -240,6 +330,26 @@ internal static System.Drawing.Bitmap error_64 { } } + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap exit_48 { + get { + object obj = ResourceManager.GetObject("exit-48", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap external_link_16 { + get { + object obj = ResourceManager.GetObject("external-link-16", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// @@ -250,6 +360,16 @@ internal static System.Drawing.Bitmap fire { } } + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap Fo76ini_LDu4jzf2p3 { + get { + object obj = ResourceManager.GetObject("Fo76ini_LDu4jzf2p3", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// @@ -260,6 +380,36 @@ internal static System.Drawing.Bitmap folder_24 { } } + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap heart_24 { + get { + object obj = ResourceManager.GetObject("heart-24", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap heart_48 { + get { + object obj = ResourceManager.GetObject("heart-48", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap heart_broken_24 { + get { + object obj = ResourceManager.GetObject("heart_broken_24", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// @@ -310,6 +460,26 @@ internal static System.Drawing.Bitmap info_64 { } } + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap like { + get { + object obj = ResourceManager.GetObject("like", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap login_48 { + get { + object obj = ResourceManager.GetObject("login-48", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// @@ -340,6 +510,36 @@ internal static System.Drawing.Bitmap nexus_24 { } } + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap pipboy_preview_bg { + get { + object obj = ResourceManager.GetObject("pipboy_preview_bg", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap pipboy_preview_fg { + get { + object obj = ResourceManager.GetObject("pipboy_preview_fg", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap pipboy_preview_fg_masked { + get { + object obj = ResourceManager.GetObject("pipboy_preview_fg_masked", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// @@ -430,6 +630,16 @@ internal static System.Drawing.Bitmap steam_24px { } } + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap text_24 { + get { + object obj = ResourceManager.GetObject("text-24", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// diff --git a/Fo76ini/Properties/Resources.resx b/Fo76ini/Properties/Resources.resx index 70a237e..a109137 100644 --- a/Fo76ini/Properties/Resources.resx +++ b/Fo76ini/Properties/Resources.resx @@ -118,136 +118,199 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - ..\Resources\bethesda_24px.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Resources\bethesda-launcher.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\Gear-0.4s-200px.gif;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\info-2-64.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\..\Images\banner.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\external-link-16.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\checked-checkbox-24(1).png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\button.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\Spinner-1s-24px-white.gif;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\download-2-48.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\play-24.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\heart-48.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\delete-24.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\user-6-512.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a ..\Resources\steam.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Resources\pipboy_preview_fg_masked.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\plus-24.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\available-updates-48.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\like.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\icon-60.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + ..\Resources\xbox_24px.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - ..\Resources\bethesda-launcher-pts.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Resources\Fo76ini_LDu4jzf2p3.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a ..\Resources\available-updates-24.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - ..\Resources\save-24.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Resources\icon.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - ..\Resources\bethesda-launcher.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Resources\add-folder-24.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - ..\Resources\help-24.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Resources\arrow-down.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - ..\Resources\msstore_24px.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Resources\help-128.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - ..\Resources\save-32.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Resources\edit-2-24.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - ..\Resources\msstore.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Resources\thaw-24.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - ..\Resources\VaultBoyThumbsUp_200px.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Resources\snowflake-16-24.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - ..\Resources\steam_24px.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Resources\fire-2-24.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - ..\Resources\xbox.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Resources\arrow_left_black.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - ..\Resources\play-24.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Resources\add-snowflake-24.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - ..\Resources\nexus-24.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Resources\adventures-24.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - ..\Resources\Gear-0.4s-200px.gif;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Resources\delete-48.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - ..\Resources\button.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Resources\heart-24.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - ..\Resources\button_hover.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Resources\pipboy_preview_fg.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - ..\Resources\Spinner-1s-24px-white.gif;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Resources\warning-5-64.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - ..\Resources\arrow_left_black.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Resources\folder-3-24.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\checkbox-24.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\add-archive-3-24.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a ..\Resources\arrow_right_black.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - ..\Resources\bg.jpg;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Resources\help-24.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - ..\Resources\adventures-24.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Resources\nexus-24.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - ..\Resources\fire-2-24.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Resources\button_hover.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - ..\Resources\add-folder-24.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Resources\save-24.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - ..\Resources\add-snowflake-24.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Resources\bethesda_24px.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - ..\Resources\checked-checkbox-24(1).png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Resources\bethesda-launcher-pts.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - ..\Resources\delete-24.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Resources\save-32.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - ..\Resources\edit-2-24.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Resources\cog-24.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - ..\Resources\error-5-64.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Resources\download-2-24.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - ..\Resources\folder-3-24.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Resources\dislike.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - ..\Resources\help-128.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Resources\arrow-up.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - ..\Resources\icon.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Resources\exit-48.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - ..\Resources\icon-60.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Resources\msstore.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - ..\Resources\info-2-64.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Resources\heart-broken-24.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - ..\Resources\plus-24.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Resources\pipboy_preview_bg.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - ..\Resources\snowflake-16-24.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Resources\steam_24px.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - ..\Resources\thaw-24.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Resources\xbox.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - ..\Resources\user-6-512.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Resources\text-24.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\msstore_24px.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\error-5-64.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a ..\Resources\user-white.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - ..\Resources\warning-5-64.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Resources\VaultBoyThumbsUp_200px.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - ..\Resources\arrow-down.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Resources\bg.jpg;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - ..\Resources\arrow-up.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Resources\login-48.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a \ No newline at end of file diff --git a/Fo76ini/Resources/Fo76ini_LDu4jzf2p3.png b/Fo76ini/Resources/Fo76ini_LDu4jzf2p3.png new file mode 100644 index 0000000..4aa22d9 Binary files /dev/null and b/Fo76ini/Resources/Fo76ini_LDu4jzf2p3.png differ diff --git a/Fo76ini/Resources/Xbox-One-Controller-icon.png b/Fo76ini/Resources/Xbox-One-Controller-icon.png new file mode 100644 index 0000000..10167e8 Binary files /dev/null and b/Fo76ini/Resources/Xbox-One-Controller-icon.png differ diff --git a/Fo76ini/Resources/add-archive-3-24.png b/Fo76ini/Resources/add-archive-3-24.png new file mode 100644 index 0000000..c73ecaa Binary files /dev/null and b/Fo76ini/Resources/add-archive-3-24.png differ diff --git a/Fo76ini/Resources/add-folder-24.png b/Fo76ini/Resources/add-folder-24.png index d1eebd0..28e18db 100644 Binary files a/Fo76ini/Resources/add-folder-24.png and b/Fo76ini/Resources/add-folder-24.png differ diff --git a/Fo76ini/Resources/available-updates-48.png b/Fo76ini/Resources/available-updates-48.png new file mode 100644 index 0000000..7199928 Binary files /dev/null and b/Fo76ini/Resources/available-updates-48.png differ diff --git a/Fo76ini/Resources/bg.jpg b/Fo76ini/Resources/bg.jpg index cbc6d5f..9f30a3d 100644 Binary files a/Fo76ini/Resources/bg.jpg and b/Fo76ini/Resources/bg.jpg differ diff --git a/Fo76ini/Resources/checkbox-24.png b/Fo76ini/Resources/checkbox-24.png new file mode 100644 index 0000000..633a355 Binary files /dev/null and b/Fo76ini/Resources/checkbox-24.png differ diff --git a/Fo76ini/Resources/cog-24.png b/Fo76ini/Resources/cog-24.png new file mode 100644 index 0000000..f177407 Binary files /dev/null and b/Fo76ini/Resources/cog-24.png differ diff --git a/Fo76ini/Resources/delete-48.png b/Fo76ini/Resources/delete-48.png new file mode 100644 index 0000000..642c865 Binary files /dev/null and b/Fo76ini/Resources/delete-48.png differ diff --git a/Fo76ini/Resources/dislike.png b/Fo76ini/Resources/dislike.png new file mode 100644 index 0000000..663515b Binary files /dev/null and b/Fo76ini/Resources/dislike.png differ diff --git a/Fo76ini/Resources/download-2-24.png b/Fo76ini/Resources/download-2-24.png new file mode 100644 index 0000000..72ff05a Binary files /dev/null and b/Fo76ini/Resources/download-2-24.png differ diff --git a/Fo76ini/Resources/download-2-48.png b/Fo76ini/Resources/download-2-48.png new file mode 100644 index 0000000..7ca111b Binary files /dev/null and b/Fo76ini/Resources/download-2-48.png differ diff --git a/Fo76ini/Resources/exit-48.png b/Fo76ini/Resources/exit-48.png new file mode 100644 index 0000000..1f0a80a Binary files /dev/null and b/Fo76ini/Resources/exit-48.png differ diff --git a/Fo76ini/Resources/external-link-16.png b/Fo76ini/Resources/external-link-16.png new file mode 100644 index 0000000..b666da2 Binary files /dev/null and b/Fo76ini/Resources/external-link-16.png differ diff --git a/Fo76ini/Resources/heart-24.png b/Fo76ini/Resources/heart-24.png new file mode 100644 index 0000000..8094a3d Binary files /dev/null and b/Fo76ini/Resources/heart-24.png differ diff --git a/Fo76ini/Resources/heart-48.png b/Fo76ini/Resources/heart-48.png new file mode 100644 index 0000000..6cf1895 Binary files /dev/null and b/Fo76ini/Resources/heart-48.png differ diff --git a/Fo76ini/Resources/heart-broken-24.png b/Fo76ini/Resources/heart-broken-24.png new file mode 100644 index 0000000..3a3ae89 Binary files /dev/null and b/Fo76ini/Resources/heart-broken-24.png differ diff --git a/Fo76ini/Resources/like.png b/Fo76ini/Resources/like.png new file mode 100644 index 0000000..333c786 Binary files /dev/null and b/Fo76ini/Resources/like.png differ diff --git a/Fo76ini/Resources/login-48.png b/Fo76ini/Resources/login-48.png new file mode 100644 index 0000000..d955f5d Binary files /dev/null and b/Fo76ini/Resources/login-48.png differ diff --git a/Fo76ini/Resources/mouse-icon.png b/Fo76ini/Resources/mouse-icon.png new file mode 100644 index 0000000..94451d2 Binary files /dev/null and b/Fo76ini/Resources/mouse-icon.png differ diff --git a/Fo76ini/Resources/pipboy_preview_bg.png b/Fo76ini/Resources/pipboy_preview_bg.png new file mode 100644 index 0000000..ee34fb5 Binary files /dev/null and b/Fo76ini/Resources/pipboy_preview_bg.png differ diff --git a/Fo76ini/Resources/pipboy_preview_fg.png b/Fo76ini/Resources/pipboy_preview_fg.png new file mode 100644 index 0000000..a1a8ead Binary files /dev/null and b/Fo76ini/Resources/pipboy_preview_fg.png differ diff --git a/Fo76ini/Resources/pipboy_preview_fg_masked.png b/Fo76ini/Resources/pipboy_preview_fg_masked.png new file mode 100644 index 0000000..44dea3b Binary files /dev/null and b/Fo76ini/Resources/pipboy_preview_fg_masked.png differ diff --git a/Fo76ini/Resources/text-24.png b/Fo76ini/Resources/text-24.png new file mode 100644 index 0000000..62f9868 Binary files /dev/null and b/Fo76ini/Resources/text-24.png differ diff --git a/Fo76ini/Resources/thumb-down-24.png b/Fo76ini/Resources/thumb-down-24.png new file mode 100644 index 0000000..c9913da Binary files /dev/null and b/Fo76ini/Resources/thumb-down-24.png differ diff --git a/Fo76ini/Resources/thumb-up-24.png b/Fo76ini/Resources/thumb-up-24.png new file mode 100644 index 0000000..4f25d1b Binary files /dev/null and b/Fo76ini/Resources/thumb-up-24.png differ diff --git a/Fo76ini/Shared.cs b/Fo76ini/Shared.cs index 25ed08b..b9077b0 100644 --- a/Fo76ini/Shared.cs +++ b/Fo76ini/Shared.cs @@ -1,129 +1,51 @@ using System; -using System.Collections.Generic; using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using System.Windows.Forms; +using Fo76ini.Profiles; namespace Fo76ini { - public enum GameEdition - { - Unknown = 0, - BethesdaNet = 1, - Steam = 2, - BethesdaNetPTS = 3, - MSStore = 4 - } - public class Shared { - public const String VERSION = "1.8.4h2"; - - public static String OldAppConfigFolder = Path.Combine(System.Environment.GetFolderPath(System.Environment.SpecialFolder.MyDocuments), "Fallout 76 Quick Configuration"); - public static String AppConfigFolder = Path.Combine(System.Environment.GetFolderPath(System.Environment.SpecialFolder.LocalApplicationData), "Fallout 76 Quick Configuration"); - - public static System.Globalization.CultureInfo enUS = System.Globalization.CultureInfo.CreateSpecificCulture("en-US"); + public const string VERSION = "1.9.0"; + public static string LatestVersion = null; - private static String gamePath = null; + public static readonly string AppInstallationFolder = Directory.GetParent(Application.ExecutablePath).ToString(); + public static readonly string AppConfigFolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Fallout 76 Quick Configuration"); - public static GameEdition GameEdition = GameEdition.Unknown; + public static readonly System.Globalization.CultureInfo en_US = System.Globalization.CultureInfo.CreateSpecificCulture("en-US"); public static bool NuclearWinterMode = false; - public static void LoadGameEdition() - { - Shared.GameEdition = (GameEdition)(IniFiles.Instance.GetInt(IniFile.Config, "Preferences", "uGameEdition", 0)); - } + // https://stackoverflow.com/a/49754978 + public static readonly string DotNetFrameworkVersion; - public static void SaveGameEdition() - { - IniFiles.Instance.Set(IniFile.Config, "Preferences", "uGameEdition", (uint)Shared.GameEdition); - } + // Example: "Fo76QConf/1.9.0 (Windows NT 10.0.19042.0; x64) .NETFramework/4.7.2" + public static readonly string AppUserAgent; - public static void ChangeGameEdition(GameEdition gameEdition) + static Shared () { - Shared.GameEdition = gameEdition; - - // ManagedMods: - ManagedMods.Instance.CopyINILists(); - ManagedMods.Instance.Unload(); + // Find DotNetFrameworkVersion: + string DotNetTargetFrameworkName = AppDomain.CurrentDomain.SetupInformation.TargetFrameworkName; + int i = DotNetTargetFrameworkName.IndexOf("v"); + if (i >= 0) + DotNetFrameworkVersion = DotNetTargetFrameworkName.Substring(i + 1); + else + DotNetFrameworkVersion = DotNetTargetFrameworkName; - // IniFiles: - IniFiles.Instance.ChangeGameEdition(Shared.GameEdition); - SaveGameEdition(); + // Build user-agent: + string os = ""; + if (Environment.OSVersion.Platform == PlatformID.Win32NT) + os = $"Windows NT {Environment.OSVersion.Version}; "; + else + os = $"{Environment.OSVersion.Platform} {Environment.OSVersion.Version}; "; - // ManagedMods: - Shared.LoadGamePath(); - ManagedMods.Instance.Load(); + if (Environment.Is64BitOperatingSystem) + os += "x64"; + else + os += "x86"; - // FormMods: - // formMods.UpdateUI(); - } - - public static void LoadGamePath () - { - String gamePath = IniFiles.Instance.GetString(IniFile.Config, "Preferences", Shared.GamePathKey, ""); - if (gamePath.Length > 0) - Shared.GamePath = gamePath; - } - - public static void SaveGamePath () - { - IniFiles.Instance.Set(IniFile.Config, "Preferences", Shared.GamePathKey, Shared.GamePath); - IniFiles.Instance.SaveConfig(); - } - - public static void ClearGamePath() - { - Shared.gamePath = ""; - } - - public static String GamePath - { - get { return Shared.gamePath; } - set - { - if (value != null && Directory.Exists(value)) - Shared.gamePath = Path.GetFullPath(value); - } - } - - public static String GamePathKey - { - get { return Shared.GetGamePathKey(Shared.GameEdition); } - } - - public static String GetGamePathKey(int gameEdition) - { - return Shared.GetGamePathKey((GameEdition)gameEdition); - } - - public static String GetGamePathKey(GameEdition gameEdition) - { - return "sGamePath" + GetEditionSuffix(gameEdition); - } - - public static String GetEditionSuffix(int gameEdition) - { - return Shared.GetEditionSuffix((GameEdition)gameEdition); - } - - public static String GetEditionSuffix(GameEdition gameEdition) - { - switch (gameEdition) - { - case GameEdition.Steam: - return "Steam"; - case GameEdition.BethesdaNet: - return "BethesdaNet"; - case GameEdition.BethesdaNetPTS: - return "BethesdaNetPTS"; - case GameEdition.MSStore: - return "MSStore"; - default: - return ""; - } + AppUserAgent = $"Fo76QuickConfiguration/{Shared.VERSION} ({os}) .NETFramework/{Shared.DotNetFrameworkVersion}"; } } } diff --git a/Fo76ini/Tweaks/Audio/EnableAudioTweak.cs b/Fo76ini/Tweaks/Audio/EnableAudioTweak.cs new file mode 100644 index 0000000..a0e7bfb --- /dev/null +++ b/Fo76ini/Tweaks/Audio/EnableAudioTweak.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Fo76ini.Tweaks.Audio +{ + class EnableAudioTweak : ITweak, ITweakInfo + { + public string Description => "If disabled, the game will be completely silent."; + + public string AffectedFiles => "Fallout76Custom.ini"; + + public string AffectedValues => "[Audio]bEnableAudio"; + + public bool DefaultValue => true; + + public string Identifier => this.GetType().FullName; + + public bool GetValue() + { + return IniFiles.GetBool("Audio", "bEnableAudio", DefaultValue); + } + + public void SetValue(bool value) + { + IniFiles.F76Custom.Set("Audio", "bEnableAudio", value); + } + + public void ResetValue() + { + SetValue(DefaultValue); + } + } +} diff --git a/Fo76ini/Tweaks/Audio/PlayMainMenuMusicTweak.cs b/Fo76ini/Tweaks/Audio/PlayMainMenuMusicTweak.cs new file mode 100644 index 0000000..aaa2b13 --- /dev/null +++ b/Fo76ini/Tweaks/Audio/PlayMainMenuMusicTweak.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Fo76ini.Tweaks.Audio +{ + class PlayMainMenuMusicTweak : ITweak, ITweakInfo + { + public string Description => "If unchecked, the game won't play background music in the main menu."; + + public string AffectedFiles => "Fallout76Custom.ini"; + + public string AffectedValues => "[General]bPlayMainMenuMusic"; + + public bool DefaultValue => true; + + public string Identifier => this.GetType().FullName; + + public bool GetValue() + { + return IniFiles.GetBool("General", "bPlayMainMenuMusic", DefaultValue); + } + + public void SetValue(bool value) + { + IniFiles.F76Custom.Set("General", "bPlayMainMenuMusic", value); + } + + public void ResetValue() + { + SetValue(DefaultValue); + } + } +} diff --git a/Fo76ini/Tweaks/Audio/VoiceChatModeTweak.cs b/Fo76ini/Tweaks/Audio/VoiceChatModeTweak.cs new file mode 100644 index 0000000..979c187 --- /dev/null +++ b/Fo76ini/Tweaks/Audio/VoiceChatModeTweak.cs @@ -0,0 +1,57 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Fo76ini.Tweaks.Audio +{ + public enum VoiceChatMode + { + Auto = 0, + Area = 1, + Team = 2, + None = 3 + } + + class VoiceChatModeTweak : ITweak, ITweakInfo, IEnumTweak + { + public string Description => ""; + + public string AffectedFiles => "Fallout76Prefs.ini"; + + public string AffectedValues => "[Voice]uTransmitPreference"; + + public VoiceChatMode DefaultValue => VoiceChatMode.Auto; + + public string Identifier => this.GetType().FullName; + + // https://stackoverflow.com/a/16946496 + public int Count => Enum.GetNames(typeof(VoiceChatMode)).Length; + + public VoiceChatMode GetValue() + { + return (VoiceChatMode)IniFiles.GetInt("Voice", "uTransmitPreference", (int)DefaultValue); + } + + public void SetValue(VoiceChatMode value) + { + IniFiles.F76Prefs.Set("Voice", "uTransmitPreference", (int)value); + } + + public void ResetValue() + { + SetValue(DefaultValue); + } + + public int GetInt() + { + return (int)GetValue(); + } + + public void SetInt(int value) + { + SetValue((VoiceChatMode)value); + } + } +} diff --git a/Fo76ini/Tweaks/Audio/VoicePushToTalkEnabledTweak.cs b/Fo76ini/Tweaks/Audio/VoicePushToTalkEnabledTweak.cs new file mode 100644 index 0000000..db1cfe1 --- /dev/null +++ b/Fo76ini/Tweaks/Audio/VoicePushToTalkEnabledTweak.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Fo76ini.Tweaks.Audio +{ + class VoicePushToTalkEnabledTweak : ITweak, ITweakInfo + { + public string Description => ""; + + public string AffectedFiles => "Fallout76Prefs.ini"; + + public string AffectedValues => "[Voice]bVoicePushToTalkEnabled"; + + public bool DefaultValue => true; + + public string Identifier => this.GetType().FullName; + + public bool GetValue() + { + return IniFiles.GetBool("Voice", "bVoicePushToTalkEnabled", DefaultValue); + } + + public void SetValue(bool value) + { + IniFiles.F76Prefs.Set("Voice", "bVoicePushToTalkEnabled", value); + } + + public void ResetValue() + { + SetValue(DefaultValue); + } + } +} diff --git a/Fo76ini/Tweaks/Camera/ApplyCameraNodeAnimationsTweak.cs b/Fo76ini/Tweaks/Camera/ApplyCameraNodeAnimationsTweak.cs new file mode 100644 index 0000000..1c3b89d --- /dev/null +++ b/Fo76ini/Tweaks/Camera/ApplyCameraNodeAnimationsTweak.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Fo76ini.Tweaks.Camera +{ + class ApplyCameraNodeAnimationsTweak : ITweak, ITweakInfo + { + public string Description => String.Join( + Environment.NewLine, + "When disabled, sets the camera's position into the characters head.", + "You'll need to zoom out in third person.", + "If enabled, sets the camera's position behind the right shoulder.", + "", + "⚠️ Might cause issues if disabled."); + + public string AffectedFiles => "Fallout76Custom.ini"; + + public string AffectedValues => "[Camera]bApplyCameraNodeAnimations"; + + public bool DefaultValue => true; + + public string Identifier => this.GetType().FullName; + + public bool GetValue() + { + return IniFiles.GetBool("Camera", "bApplyCameraNodeAnimations", DefaultValue); + } + + public void SetValue(bool value) + { + IniFiles.F76Prefs.Set("Camera", "bApplyCameraNodeAnimations", value); + } + + public void ResetValue() + { + SetValue(DefaultValue); + } + } +} diff --git a/Fo76ini/Tweaks/Camera/CameraOverShoulderCombatAddYTweak.cs b/Fo76ini/Tweaks/Camera/CameraOverShoulderCombatAddYTweak.cs new file mode 100644 index 0000000..4c21e42 --- /dev/null +++ b/Fo76ini/Tweaks/Camera/CameraOverShoulderCombatAddYTweak.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Fo76ini.Tweaks.Camera +{ + class CameraOverShoulderCombatAddYTweak : ITweak, ITweakInfo + { + public string Description => ""; + + public string AffectedFiles => "Fallout76Custom.ini"; + + public string AffectedValues => "[Camera]fOverShoulderCombatAddY"; + + public float DefaultValue => 0; + + public string Identifier => this.GetType().FullName; + + public float GetValue() + { + return IniFiles.GetFloat("Camera", "fOverShoulderCombatAddY", DefaultValue); + } + + public void SetValue(float value) + { + IniFiles.F76Custom.Set("Camera", "fOverShoulderCombatAddY", value); + } + + public void ResetValue() + { + IniFiles.F76Custom.Remove("Camera", "fOverShoulderCombatAddY"); + //SetValue(DefaultValue); + } + } +} diff --git a/Fo76ini/Tweaks/Camera/CameraOverShoulderCombatPosXTweak.cs b/Fo76ini/Tweaks/Camera/CameraOverShoulderCombatPosXTweak.cs new file mode 100644 index 0000000..f19a8b4 --- /dev/null +++ b/Fo76ini/Tweaks/Camera/CameraOverShoulderCombatPosXTweak.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Fo76ini.Tweaks.Camera +{ + class CameraOverShoulderCombatPosXTweak : ITweak, ITweakInfo + { + public string Description => ""; + + public string AffectedFiles => "Fallout76Custom.ini"; + + public string AffectedValues => "[Camera]fOverShoulderCombatPosX"; + + public float DefaultValue => 0; + + public string Identifier => this.GetType().FullName; + + public float GetValue() + { + return IniFiles.GetFloat("Camera", "fOverShoulderCombatPosX", DefaultValue); + } + + public void SetValue(float value) + { + IniFiles.F76Custom.Set("Camera", "fOverShoulderCombatPosX", value); + } + + public void ResetValue() + { + IniFiles.F76Custom.Remove("Camera", "fOverShoulderCombatPosX"); + //SetValue(DefaultValue); + } + } +} diff --git a/Fo76ini/Tweaks/Camera/CameraOverShoulderCombatPosZTweak.cs b/Fo76ini/Tweaks/Camera/CameraOverShoulderCombatPosZTweak.cs new file mode 100644 index 0000000..44b0023 --- /dev/null +++ b/Fo76ini/Tweaks/Camera/CameraOverShoulderCombatPosZTweak.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Fo76ini.Tweaks.Camera +{ + class CameraOverShoulderCombatPosZTweak : ITweak, ITweakInfo + { + public string Description => ""; + + public string AffectedFiles => "Fallout76Custom.ini"; + + public string AffectedValues => "[Camera]fOverShoulderCombatPosZ"; + + public float DefaultValue => 0; + + public string Identifier => this.GetType().FullName; + + public float GetValue() + { + return IniFiles.GetFloat("Camera", "fOverShoulderCombatPosZ", DefaultValue); + } + + public void SetValue(float value) + { + IniFiles.F76Custom.Set("Camera", "fOverShoulderCombatPosZ", value); + } + + public void ResetValue() + { + IniFiles.F76Custom.Remove("Camera", "fOverShoulderCombatPosZ"); + //SetValue(DefaultValue); + } + } +} diff --git a/Fo76ini/Tweaks/Camera/CameraOverShoulderMeleeCombatAddYTweak.cs b/Fo76ini/Tweaks/Camera/CameraOverShoulderMeleeCombatAddYTweak.cs new file mode 100644 index 0000000..f63adbc --- /dev/null +++ b/Fo76ini/Tweaks/Camera/CameraOverShoulderMeleeCombatAddYTweak.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Fo76ini.Tweaks.Camera +{ + class CameraOverShoulderMeleeCombatAddYTweak : ITweak, ITweakInfo + { + public string Description => ""; + + public string AffectedFiles => "Fallout76Custom.ini"; + + public string AffectedValues => "[Camera]fOverShoulderMeleeCombatAddY"; + + public float DefaultValue => 0; + + public string Identifier => this.GetType().FullName; + + public float GetValue() + { + return IniFiles.GetFloat("Camera", "fOverShoulderMeleeCombatAddY", DefaultValue); + } + + public void SetValue(float value) + { + IniFiles.F76Custom.Set("Camera", "fOverShoulderMeleeCombatAddY", value); + } + + public void ResetValue() + { + IniFiles.F76Custom.Remove("Camera", "fOverShoulderMeleeCombatAddY"); + //SetValue(DefaultValue); + } + } +} diff --git a/Fo76ini/Tweaks/Camera/CameraOverShoulderMeleeCombatPosXTweak.cs b/Fo76ini/Tweaks/Camera/CameraOverShoulderMeleeCombatPosXTweak.cs new file mode 100644 index 0000000..12c2911 --- /dev/null +++ b/Fo76ini/Tweaks/Camera/CameraOverShoulderMeleeCombatPosXTweak.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Fo76ini.Tweaks.Camera +{ + class CameraOverShoulderMeleeCombatPosXTweak : ITweak, ITweakInfo + { + public string Description => ""; + + public string AffectedFiles => "Fallout76Custom.ini"; + + public string AffectedValues => "[Camera]fOverShoulderMeleeCombatPosX"; + + public float DefaultValue => 0; + + public string Identifier => this.GetType().FullName; + + public float GetValue() + { + return IniFiles.GetFloat("Camera", "fOverShoulderMeleeCombatPosX", DefaultValue); + } + + public void SetValue(float value) + { + IniFiles.F76Custom.Set("Camera", "fOverShoulderMeleeCombatPosX", value); + } + + public void ResetValue() + { + IniFiles.F76Custom.Remove("Camera", "fOverShoulderMeleeCombatPosX"); + //SetValue(DefaultValue); + } + } +} diff --git a/Fo76ini/Tweaks/Camera/CameraOverShoulderMeleeCombatPosZTweak.cs b/Fo76ini/Tweaks/Camera/CameraOverShoulderMeleeCombatPosZTweak.cs new file mode 100644 index 0000000..7f7193f --- /dev/null +++ b/Fo76ini/Tweaks/Camera/CameraOverShoulderMeleeCombatPosZTweak.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Fo76ini.Tweaks.Camera +{ + class CameraOverShoulderMeleeCombatPosZTweak : ITweak, ITweakInfo + { + public string Description => ""; + + public string AffectedFiles => "Fallout76Custom.ini"; + + public string AffectedValues => "[Camera]fOverShoulderMeleeCombatPosZ"; + + public float DefaultValue => 0; + + public string Identifier => this.GetType().FullName; + + public float GetValue() + { + return IniFiles.GetFloat("Camera", "fOverShoulderMeleeCombatPosZ", DefaultValue); + } + + public void SetValue(float value) + { + IniFiles.F76Custom.Set("Camera", "fOverShoulderMeleeCombatPosZ", value); + } + + public void ResetValue() + { + IniFiles.F76Custom.Remove("Camera", "fOverShoulderMeleeCombatPosZ"); + //SetValue(DefaultValue); + } + } +} diff --git a/Fo76ini/Tweaks/Camera/CameraOverShoulderPosXTweak.cs b/Fo76ini/Tweaks/Camera/CameraOverShoulderPosXTweak.cs new file mode 100644 index 0000000..e24b17c --- /dev/null +++ b/Fo76ini/Tweaks/Camera/CameraOverShoulderPosXTweak.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Fo76ini.Tweaks.Camera +{ + class CameraOverShoulderPosXTweak : ITweak, ITweakInfo + { + public string Description => ""; + + public string AffectedFiles => "Fallout76Custom.ini"; + + public string AffectedValues => "[Camera]fOverShoulderPosX"; + + public float DefaultValue => 0; + + public string Identifier => this.GetType().FullName; + + public float GetValue() + { + return IniFiles.GetFloat("Camera", "fOverShoulderPosX", DefaultValue); + } + + public void SetValue(float value) + { + IniFiles.F76Custom.Set("Camera", "fOverShoulderPosX", value); + } + + public void ResetValue() + { + IniFiles.F76Custom.Remove("Camera", "fOverShoulderPosX"); + //SetValue(DefaultValue); + } + } +} diff --git a/Fo76ini/Tweaks/Camera/CameraOverShoulderPosZTweak.cs b/Fo76ini/Tweaks/Camera/CameraOverShoulderPosZTweak.cs new file mode 100644 index 0000000..baf4d9b --- /dev/null +++ b/Fo76ini/Tweaks/Camera/CameraOverShoulderPosZTweak.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Fo76ini.Tweaks.Camera +{ + class CameraOverShoulderPosZTweak : ITweak, ITweakInfo + { + public string Description => ""; + + public string AffectedFiles => "Fallout76Custom.ini"; + + public string AffectedValues => "[Camera]fOverShoulderPosZ"; + + public float DefaultValue => 0; + + public string Identifier => this.GetType().FullName; + + public float GetValue() + { + return IniFiles.GetFloat("Camera", "fOverShoulderPosZ", DefaultValue); + } + + public void SetValue(float value) + { + IniFiles.F76Custom.Set("Camera", "fOverShoulderPosZ", value); + } + + public void ResetValue() + { + IniFiles.F76Custom.Remove("Camera", "fOverShoulderPosZ"); + //SetValue(DefaultValue); + } + } +} diff --git a/Fo76ini/Tweaks/Camera/DefaultFOVTweak.cs b/Fo76ini/Tweaks/Camera/DefaultFOVTweak.cs new file mode 100644 index 0000000..5085a9b --- /dev/null +++ b/Fo76ini/Tweaks/Camera/DefaultFOVTweak.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Fo76ini.Tweaks.Camera +{ + class DefaultFOVTweak : ITweak, ITweakInfo + { + public string Description => "⚠️ Causes issues with the GUI."; + + public string AffectedFiles => "Fallout76Custom.ini"; + + public string AffectedValues => "[Camera]fDefaultFOV"; + + public float DefaultValue => 80; + + public string Identifier => this.GetType().FullName; + + public float GetValue() + { + return IniFiles.GetFloat("Camera", "fDefaultFOV", DefaultValue); + } + + public void SetValue(float value) + { + IniFiles.F76Custom.Set("Camera", "fDefaultFOV", value); + } + + public void ResetValue() + { + IniFiles.F76Custom.Remove("Camera", "fDefaultFOV"); + //SetValue(DefaultValue); + } + } +} diff --git a/Fo76ini/Tweaks/Camera/DisableAutoVanityModeTweak.cs b/Fo76ini/Tweaks/Camera/DisableAutoVanityModeTweak.cs new file mode 100644 index 0000000..00ae745 --- /dev/null +++ b/Fo76ini/Tweaks/Camera/DisableAutoVanityModeTweak.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Fo76ini.Tweaks.Camera +{ + class DisableAutoVanityModeTweak : ITweak, ITweakInfo + { + public string Description => + "When enabled, the camera will spin around the character after no input was given for a certain amount of time.\n" + + "⚠️ Not sure if it does anything. I stood around for 5 minutes and the camera didn't spin. Needs more testing."; + + public string AffectedFiles => "Fallout76Custom.ini"; + + public string AffectedValues => "[Camera]bDisableAutoVanityMode"; + + public bool DefaultValue => false; + + public string Identifier => this.GetType().FullName; + + public bool GetValue() + { + return IniFiles.GetBool("Camera", "bDisableAutoVanityMode", DefaultValue); + } + + public void SetValue(bool value) + { + IniFiles.F76Custom.Set("Camera", "bDisableAutoVanityMode", value); + } + + public void ResetValue() + { + SetValue(DefaultValue); + } + } +} diff --git a/Fo76ini/Tweaks/Camera/FOV1stPersonTweak.cs b/Fo76ini/Tweaks/Camera/FOV1stPersonTweak.cs new file mode 100644 index 0000000..e636393 --- /dev/null +++ b/Fo76ini/Tweaks/Camera/FOV1stPersonTweak.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Fo76ini.Tweaks.Camera +{ + class FOV1stPersonTweak : ITweak, ITweakInfo + { + public string Description => ""; + + public string AffectedFiles => "Fallout76Prefs.ini"; + + public string AffectedValues => "fDefault1stPersonFOV"; + + public float DefaultValue => 80; + + public string Identifier => this.GetType().FullName; + + public float GetValue() + { + return IniFiles.GetFloat("Display", "fDefault1stPersonFOV", DefaultValue); + } + + public void SetValue(float value) + { + IniFiles.F76Prefs.Set("Display", "fDefault1stPersonFOV", value); + IniFiles.F76Prefs.Set("Interface", "fDefault1stPersonFOV", value); + } + + public void ResetValue() + { + SetValue(DefaultValue); + } + } +} diff --git a/Fo76ini/Tweaks/Camera/FOV3rdADSTweak.cs b/Fo76ini/Tweaks/Camera/FOV3rdADSTweak.cs new file mode 100644 index 0000000..c701457 --- /dev/null +++ b/Fo76ini/Tweaks/Camera/FOV3rdADSTweak.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Fo76ini.Tweaks.Camera +{ + class FOV3rdADSTweak : ITweak, ITweakInfo + { + public string Description => "Changes the field of view of the 3rd person perspective while aiming."; + + public string AffectedFiles => "Fallout76Custom.ini"; + + public string AffectedValues => "[Camera]f3rdPersonAimFOV"; + + public float DefaultValue => 50; + + public string Identifier => this.GetType().FullName; + + public float GetValue() + { + return IniFiles.GetFloat("Camera", "f3rdPersonAimFOV", DefaultValue); + } + + public void SetValue(float value) + { + IniFiles.F76Custom.Set("Camera", "f3rdPersonAimFOV", value); + } + + public void ResetValue() + { + IniFiles.F76Custom.Remove("Camera", "f3rdPersonAimFOV"); + //SetValue(DefaultValue); + } + } +} diff --git a/Fo76ini/Tweaks/Camera/FOV3rdPersonTweak.cs b/Fo76ini/Tweaks/Camera/FOV3rdPersonTweak.cs new file mode 100644 index 0000000..60ad1de --- /dev/null +++ b/Fo76ini/Tweaks/Camera/FOV3rdPersonTweak.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Fo76ini.Tweaks.Camera +{ + class FOV3rdPersonTweak : ITweak, ITweakInfo + { + public string Description => ""; + + public string AffectedFiles => "Fallout76Prefs.ini"; + + public string AffectedValues => "fDefaultWorldFOV"; + + public float DefaultValue => 80; + + public string Identifier => this.GetType().FullName; + + public float GetValue() + { + return IniFiles.GetFloat("Display", "fDefaultWorldFOV", DefaultValue); + } + + public void SetValue(float value) + { + IniFiles.F76Prefs.Set("Display", "fDefaultWorldFOV", value); + IniFiles.F76Prefs.Set("Interface", "fDefaultWorldFOV", value); + } + + public void ResetValue() + { + SetValue(DefaultValue); + } + } +} diff --git a/Fo76ini/Tweaks/Camera/FirstThirdPerspectiveSwitchDelayTweak.cs b/Fo76ini/Tweaks/Camera/FirstThirdPerspectiveSwitchDelayTweak.cs new file mode 100644 index 0000000..5a700c0 --- /dev/null +++ b/Fo76ini/Tweaks/Camera/FirstThirdPerspectiveSwitchDelayTweak.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Fo76ini.Tweaks.Camera +{ + class FirstThirdPerspectiveSwitchDelayTweak : ITweak, ITweakInfo + { + public string Description => ""; + + public string AffectedFiles => "Fallout76Custom.ini"; + + public string AffectedValues => "[Camera]f1st3rdSwitchDelay"; + + public float DefaultValue => 0.25f; + + public string Identifier => this.GetType().FullName; + + public float GetValue() + { + return IniFiles.GetFloat("Camera", "f1st3rdSwitchDelay", DefaultValue); + } + + public void SetValue(float value) + { + IniFiles.F76Custom.Set("Camera", "f1st3rdSwitchDelay", value); + } + + public void ResetValue() + { + IniFiles.F76Custom.Remove("Camera", "f1st3rdSwitchDelay"); + //SetValue(DefaultValue); + } + } +} diff --git a/Fo76ini/Tweaks/Camera/ForceAutoVanityModeTweak.cs b/Fo76ini/Tweaks/Camera/ForceAutoVanityModeTweak.cs new file mode 100644 index 0000000..dc796ba --- /dev/null +++ b/Fo76ini/Tweaks/Camera/ForceAutoVanityModeTweak.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Fo76ini.Tweaks.Camera +{ + class ForceAutoVanityModeTweak : ITweak, ITweakInfo + { + public string Description => ""; + + public string AffectedFiles => "Fallout76Custom.ini"; + + public string AffectedValues => "[Camera]bForceAutoVanityMode"; + + public bool DefaultValue => false; + + public string Identifier => this.GetType().FullName; + + public bool GetValue() + { + return IniFiles.GetBool("Camera", "bForceAutoVanityMode", DefaultValue); + } + + public void SetValue(bool value) + { + IniFiles.F76Custom.Set("Camera", "bForceAutoVanityMode", value); + } + + public void ResetValue() + { + SetValue(DefaultValue); + } + } +} diff --git a/Fo76ini/Tweaks/Camera/PitchZoomOutMaxDistTweak.cs b/Fo76ini/Tweaks/Camera/PitchZoomOutMaxDistTweak.cs new file mode 100644 index 0000000..a785f7f --- /dev/null +++ b/Fo76ini/Tweaks/Camera/PitchZoomOutMaxDistTweak.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Fo76ini.Tweaks.Camera +{ + class PitchZoomOutMaxDistTweak : ITweak, ITweakInfo + { + public string Description => "By how much the camera gets zoomed out when you look at the ground in 3rd person."; + + public string AffectedFiles => "Fallout76Custom.ini"; + + public string AffectedValues => "[Camera]fPitchZoomOutMaxDist"; + + public float DefaultValue => 100; + + public string Identifier => this.GetType().FullName; + + public float GetValue() + { + return IniFiles.GetFloat("Camera", "fPitchZoomOutMaxDist", DefaultValue); + } + + public void SetValue(float value) + { + IniFiles.F76Custom.Set("Camera", "fPitchZoomOutMaxDist", value); + } + + public void ResetValue() + { + IniFiles.F76Custom.Remove("Camera", "fPitchZoomOutMaxDist"); + //SetValue(DefaultValue); + } + } +} diff --git a/Fo76ini/Tweaks/Camera/SelfieCameraRotationSpeedTweak.cs b/Fo76ini/Tweaks/Camera/SelfieCameraRotationSpeedTweak.cs new file mode 100644 index 0000000..4d1608c --- /dev/null +++ b/Fo76ini/Tweaks/Camera/SelfieCameraRotationSpeedTweak.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Fo76ini.Tweaks.Camera +{ + class SelfieCameraRotationSpeedTweak : ITweak, ITweakInfo + { + public string Description => ""; + + public string AffectedFiles => "Fallout76Custom.ini"; + + public string AffectedValues => "[Camera]fSelfieCameraRotationSpeed"; + + public float DefaultValue => 1.5f; + + public string Identifier => this.GetType().FullName; + + public float GetValue() + { + return IniFiles.GetFloat("Camera", "fSelfieCameraRotationSpeed", DefaultValue); + } + + public void SetValue(float value) + { + IniFiles.F76Custom.Set("Camera", "fSelfieCameraRotationSpeed", value); + } + + public void ResetValue() + { + IniFiles.F76Custom.Remove("Camera", "fSelfieCameraRotationSpeed"); + //SetValue(DefaultValue); + } + } +} diff --git a/Fo76ini/Tweaks/Camera/SelfieCameraTranslationSpeedTweak.cs b/Fo76ini/Tweaks/Camera/SelfieCameraTranslationSpeedTweak.cs new file mode 100644 index 0000000..578d8ab --- /dev/null +++ b/Fo76ini/Tweaks/Camera/SelfieCameraTranslationSpeedTweak.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Fo76ini.Tweaks.Camera +{ + class SelfieCameraTranslationSpeedTweak : ITweak, ITweakInfo + { + public string Description => ""; + + public string AffectedFiles => "Fallout76Custom.ini"; + + public string AffectedValues => "[Camera]fSelfieCameraTranslationSpeed"; + + public float DefaultValue => 2.5f; + + public string Identifier => this.GetType().FullName; + + public float GetValue() + { + return IniFiles.GetFloat("Camera", "fSelfieCameraTranslationSpeed", DefaultValue); + } + + public void SetValue(float value) + { + IniFiles.F76Custom.Set("Camera", "fSelfieCameraTranslationSpeed", value); + } + + public void ResetValue() + { + IniFiles.F76Custom.Remove("Camera", "fSelfieCameraTranslationSpeed"); + //SetValue(DefaultValue); + } + } +} diff --git a/Fo76ini/Tweaks/Camera/SelfieModeRangeTweak.cs b/Fo76ini/Tweaks/Camera/SelfieModeRangeTweak.cs new file mode 100644 index 0000000..e6ba4ce --- /dev/null +++ b/Fo76ini/Tweaks/Camera/SelfieModeRangeTweak.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Fo76ini.Tweaks.Camera +{ + class SelfieModeRangeTweak : ITweak, ITweakInfo + { + public string Description => ""; + + public string AffectedFiles => "Fallout76Custom.ini"; + + public string AffectedValues => "[Camera]fSelfieModeRange"; + + public float DefaultValue => 500; + + public string Identifier => this.GetType().FullName; + + public float GetValue() + { + return IniFiles.GetFloat("Camera", "fSelfieModeRange", DefaultValue); + } + + public void SetValue(float value) + { + IniFiles.F76Custom.Set("Camera", "fSelfieModeRange", value); + } + + public void ResetValue() + { + IniFiles.F76Custom.Remove("Camera", "fSelfieModeRange"); + //SetValue(DefaultValue); + } + } +} diff --git a/Fo76ini/Tweaks/Camera/VanityModeMaxDistTweak.cs b/Fo76ini/Tweaks/Camera/VanityModeMaxDistTweak.cs new file mode 100644 index 0000000..78ff360 --- /dev/null +++ b/Fo76ini/Tweaks/Camera/VanityModeMaxDistTweak.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Fo76ini.Tweaks.Camera +{ + class VanityModeMaxDistTweak : ITweak, ITweakInfo + { + public string Description => ""; + + public string AffectedFiles => "Fallout76Custom.ini"; + + public string AffectedValues => "[Camera]fVanityModeMaxDist"; + + public float DefaultValue => 150; + + public string Identifier => this.GetType().FullName; + + public float GetValue() + { + return IniFiles.GetFloat("Camera", "fVanityModeMaxDist", DefaultValue); + } + + public void SetValue(float value) + { + IniFiles.F76Custom.Set("Camera", "fVanityModeMaxDist", value); + } + + public void ResetValue() + { + IniFiles.F76Custom.Remove("Camera", "fVanityModeMaxDist"); + //SetValue(DefaultValue); + } + } +} diff --git a/Fo76ini/Tweaks/Camera/VanityModeMinDistTweak.cs b/Fo76ini/Tweaks/Camera/VanityModeMinDistTweak.cs new file mode 100644 index 0000000..521616f --- /dev/null +++ b/Fo76ini/Tweaks/Camera/VanityModeMinDistTweak.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Fo76ini.Tweaks.Camera +{ + class VanityModeMinDistTweak : ITweak, ITweakInfo + { + public string Description => ""; + + public string AffectedFiles => "Fallout76Custom.ini"; + + public string AffectedValues => "[Camera]fVanityModeMinDist"; + + public float DefaultValue => 0; + + public string Identifier => this.GetType().FullName; + + public float GetValue() + { + return IniFiles.GetFloat("Camera", "fVanityModeMinDist", DefaultValue); + } + + public void SetValue(float value) + { + IniFiles.F76Custom.Set("Camera", "fVanityModeMinDist", value); + } + + public void ResetValue() + { + IniFiles.F76Custom.Remove("Camera", "fVanityModeMinDist"); + //SetValue(DefaultValue); + } + } +} diff --git a/Fo76ini/Tweaks/Colors/PipboyColorTweak.cs b/Fo76ini/Tweaks/Colors/PipboyColorTweak.cs new file mode 100644 index 0000000..3b70e99 --- /dev/null +++ b/Fo76ini/Tweaks/Colors/PipboyColorTweak.cs @@ -0,0 +1,52 @@ +using Fo76ini.Utilities; +using System; +using System.Drawing; + +namespace Fo76ini.Tweaks.Colors +{ + public class PipboyColorTweak : ITweak, ITweakInfo + { + public Color DefaultValue => Color.FromArgb(26, 255, 128); + + public string Identifier => this.GetType().FullName; + + public string Description => "Changes the color of the Pipboy"; + + public string AffectedFiles => "Fallout76Prefs.ini"; + + public string AffectedValues => String.Join( + Environment.NewLine, + "", + " [Pipboy]fPipboyEffectColorR", + " [Pipboy]fPipboyEffectColorG", + " [Pipboy]fPipboyEffectColorB", + ""); + + public Color GetValue() + { + float r = Utils.Clamp(IniFiles.GetFloat("Pipboy", "fPipboyEffectColorR", 0.1f), 0f, 1f); + float g = Utils.Clamp(IniFiles.GetFloat("Pipboy", "fPipboyEffectColorG", 1.0f), 0f, 1f); + float b = Utils.Clamp(IniFiles.GetFloat("Pipboy", "fPipboyEffectColorB", 0.5f), 0f, 1f); + return Color.FromArgb( + Convert.ToInt32(r * 255), + Convert.ToInt32(g * 255), + Convert.ToInt32(b * 255) + ); + } + + public void SetValue(Color value) + { + float r = Convert.ToSingle(value.R) / 255f; + float g = Convert.ToSingle(value.G) / 255f; + float b = Convert.ToSingle(value.B) / 255f; + IniFiles.F76Prefs.Set("Pipboy", "fPipboyEffectColorR", r); + IniFiles.F76Prefs.Set("Pipboy", "fPipboyEffectColorG", g); + IniFiles.F76Prefs.Set("Pipboy", "fPipboyEffectColorB", b); + } + + public void ResetValue() + { + SetValue(DefaultValue); + } + } +} diff --git a/Fo76ini/Tweaks/Colors/PowerArmorPipboyColorTweak.cs b/Fo76ini/Tweaks/Colors/PowerArmorPipboyColorTweak.cs new file mode 100644 index 0000000..a219e69 --- /dev/null +++ b/Fo76ini/Tweaks/Colors/PowerArmorPipboyColorTweak.cs @@ -0,0 +1,54 @@ +using Fo76ini.Utilities; +using System; +using System.Drawing; + +namespace Fo76ini.Tweaks.Colors +{ + public class PowerArmorPipboyColorTweak : ITweak, ITweakInfo + { + public Color DefaultValue => Color.FromArgb(255, 209, 105); + + public string Identifier => this.GetType().FullName; + + public string Description => "Changes the color of the Power Armor Quickboy"; + + public string AffectedFiles => "Fallout76Custom.ini"; + + public string AffectedValues => String.Join( + Environment.NewLine, + "", + " [Pipboy]fPAEffectColorR", + " [Pipboy]fPAEffectColorG", + " [Pipboy]fPAEffectColorB", + ""); + + public Color GetValue() + { + float r = Utils.Clamp(IniFiles.GetFloat("Pipboy", "fPAEffectColorR", 1.0f), 0f, 1f); + float g = Utils.Clamp(IniFiles.GetFloat("Pipboy", "fPAEffectColorG", 0.82f), 0f, 1f); + float b = Utils.Clamp(IniFiles.GetFloat("Pipboy", "fPAEffectColorB", 0.41f), 0f, 1f); + return Color.FromArgb( + Convert.ToInt32(r * 255), + Convert.ToInt32(g * 255), + Convert.ToInt32(b * 255) + ); + } + + public void SetValue(Color value) + { + float r = Convert.ToSingle(value.R) / 255f; + float g = Convert.ToSingle(value.G) / 255f; + float b = Convert.ToSingle(value.B) / 255f; + IniFiles.F76Custom.Set("Pipboy", "fPAEffectColorR", r); + IniFiles.F76Custom.Set("Pipboy", "fPAEffectColorG", g); + IniFiles.F76Custom.Set("Pipboy", "fPAEffectColorB", b); + } + + public void ResetValue() + { + IniFiles.F76Custom.Remove("Pipboy", "fPAEffectColorR"); + IniFiles.F76Custom.Remove("Pipboy", "fPAEffectColorG"); + IniFiles.F76Custom.Remove("Pipboy", "fPAEffectColorB"); + } + } +} diff --git a/Fo76ini/Tweaks/Colors/QuickboyColorTweak.cs b/Fo76ini/Tweaks/Colors/QuickboyColorTweak.cs new file mode 100644 index 0000000..94d5673 --- /dev/null +++ b/Fo76ini/Tweaks/Colors/QuickboyColorTweak.cs @@ -0,0 +1,54 @@ +using System; +using System.Drawing; +using Fo76ini.Utilities; + +namespace Fo76ini.Tweaks.Colors +{ + public class QuickboyColorTweak : ITweak, ITweakInfo + { + public Color DefaultValue => Color.FromArgb(247, 242, 184); + + public string Identifier => this.GetType().FullName; + + public string Description => "Changes the color of the Quickboy"; + + public string AffectedFiles => "Fallout76Custom.ini"; + + public string AffectedValues => String.Join( + Environment.NewLine, + "", + " [Pipboy]fQuickBoyEffectColorR", + " [Pipboy]fQuickBoyEffectColorG", + " [Pipboy]fQuickBoyEffectColorB", + ""); + + public Color GetValue() + { + float r = Utils.Clamp(IniFiles.GetFloat("Pipboy", "fQuickBoyEffectColorR", 0.97f), 0f, 1f); + float g = Utils.Clamp(IniFiles.GetFloat("Pipboy", "fQuickBoyEffectColorG", 0.95f), 0f, 1f); + float b = Utils.Clamp(IniFiles.GetFloat("Pipboy", "fQuickBoyEffectColorB", 0.72f), 0f, 1f); + return Color.FromArgb( + Convert.ToInt32(r * 255), + Convert.ToInt32(g * 255), + Convert.ToInt32(b * 255) + ); + } + + public void SetValue(Color value) + { + float r = Convert.ToSingle(value.R) / 255f; + float g = Convert.ToSingle(value.G) / 255f; + float b = Convert.ToSingle(value.B) / 255f; + IniFiles.F76Custom.Set("Pipboy", "fQuickBoyEffectColorR", r); + IniFiles.F76Custom.Set("Pipboy", "fQuickBoyEffectColorG", g); + IniFiles.F76Custom.Set("Pipboy", "fQuickBoyEffectColorB", b); + } + + public void ResetValue() + { + IniFiles.F76Custom.Remove("Pipboy", "fQuickBoyEffectColorR"); + IniFiles.F76Custom.Remove("Pipboy", "fQuickBoyEffectColorG"); + IniFiles.F76Custom.Remove("Pipboy", "fQuickBoyEffectColorB"); + } + } +} diff --git a/Fo76ini/Tweaks/Config/AutoApplyTweak.cs b/Fo76ini/Tweaks/Config/AutoApplyTweak.cs new file mode 100644 index 0000000..08d03f4 --- /dev/null +++ b/Fo76ini/Tweaks/Config/AutoApplyTweak.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Fo76ini.Tweaks.Config +{ + class AutoApplyTweak : ITweak, ITweakInfo + { + public string Description => "No need to press apply anymore."; + + public string AffectedFiles => "config.ini"; + + public string AffectedValues => "bAutoApply"; + + public bool DefaultValue => false; + + public string Identifier => this.GetType().FullName; + + public bool GetValue() + { + return IniFiles.Config.GetBool("Preferences", "bAutoApply", DefaultValue); + } + + public void SetValue(bool value) + { + IniFiles.Config.Set("Preferences", "bAutoApply", value); + } + + public void ResetValue() + { + SetValue(DefaultValue); + } + } +} diff --git a/Fo76ini/Tweaks/Config/IgnoreUpdatesTweak.cs b/Fo76ini/Tweaks/Config/IgnoreUpdatesTweak.cs new file mode 100644 index 0000000..2cb8033 --- /dev/null +++ b/Fo76ini/Tweaks/Config/IgnoreUpdatesTweak.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Fo76ini.Tweaks.Config +{ + class IgnoreUpdatesTweak : ITweak, ITweakInfo + { + public string Description => "Won't check for updates on startup and hides the big update button."; + + public string AffectedFiles => "config.ini"; + + public string AffectedValues => "bIgnoreUpdates"; + + public bool DefaultValue => false; + + public string Identifier => this.GetType().FullName; + + public bool GetValue() + { + return IniFiles.Config.GetBool("Preferences", "bIgnoreUpdates", DefaultValue); + } + + public void SetValue(bool value) + { + IniFiles.Config.Set("Preferences", "bIgnoreUpdates", value); + } + + public void ResetValue() + { + SetValue(DefaultValue); + } + } +} diff --git a/Fo76ini/Tweaks/Config/PlayNotificationSoundsTweak.cs b/Fo76ini/Tweaks/Config/PlayNotificationSoundsTweak.cs new file mode 100644 index 0000000..f275dee --- /dev/null +++ b/Fo76ini/Tweaks/Config/PlayNotificationSoundsTweak.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Fo76ini.Tweaks.Config +{ + class PlayNotificationSoundsTweak : ITweak, ITweakInfo + { + public string Description => "When enabled, the tool will play custom notification sounds."; + + public string AffectedFiles => "config.ini"; + + public string AffectedValues => "bPlayNotificationSound"; + + public bool DefaultValue => true; + + public string Identifier => this.GetType().FullName; + + public bool GetValue() + { + return IniFiles.Config.GetBool("Preferences", "bPlayNotificationSound", DefaultValue); + } + + public void SetValue(bool value) + { + IniFiles.Config.Set("Preferences", "bPlayNotificationSound", value); + } + + public void ResetValue() + { + SetValue(DefaultValue); + } + } +} diff --git a/Fo76ini/Tweaks/Config/ToolQuitOnLaunchTweak.cs b/Fo76ini/Tweaks/Config/ToolQuitOnLaunchTweak.cs new file mode 100644 index 0000000..5007be7 --- /dev/null +++ b/Fo76ini/Tweaks/Config/ToolQuitOnLaunchTweak.cs @@ -0,0 +1,30 @@ +namespace Fo76ini.Tweaks.Config +{ + class ToolQuitOnLaunchTweak : ITweak, ITweakInfo + { + public string Description => "When enabled, closes the tool when the game is launched.\nOnly works if launched through the tool."; + + public string AffectedFiles => "config.ini"; + + public string AffectedValues => "bQuitOnLaunch"; + + public bool DefaultValue => false; + + public string Identifier => this.GetType().FullName; + + public bool GetValue() + { + return IniFiles.Config.GetBool("Preferences", "bQuitOnLaunch", DefaultValue); + } + + public void SetValue(bool value) + { + IniFiles.Config.Set("Preferences", "bQuitOnLaunch", value); + } + + public void ResetValue() + { + SetValue(DefaultValue); + } + } +} diff --git a/Fo76ini/Tweaks/Controls/EnableGamepadRumbleTweak.cs b/Fo76ini/Tweaks/Controls/EnableGamepadRumbleTweak.cs new file mode 100644 index 0000000..71e7380 --- /dev/null +++ b/Fo76ini/Tweaks/Controls/EnableGamepadRumbleTweak.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Fo76ini.Tweaks.Controls +{ + class EnableGamepadRumbleTweak : ITweak, ITweakInfo + { + public string Description => ""; + + public string AffectedFiles => "Fallout76Custom.ini"; + + public string AffectedValues => "[Controls]bGamePadRumble"; + + public bool DefaultValue => true; + + public string Identifier => this.GetType().FullName; + + public bool GetValue() + { + return IniFiles.GetBool("Controls", "bGamePadRumble", DefaultValue); + } + + public void SetValue(bool value) + { + IniFiles.F76Custom.Set("Controls", "bGamePadRumble", value); + } + + public void ResetValue() + { + SetValue(DefaultValue); + } + } +} diff --git a/Fo76ini/Tweaks/Controls/FixAimSensitivityTweak.cs b/Fo76ini/Tweaks/Controls/FixAimSensitivityTweak.cs new file mode 100644 index 0000000..6a5e228 --- /dev/null +++ b/Fo76ini/Tweaks/Controls/FixAimSensitivityTweak.cs @@ -0,0 +1,51 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Fo76ini.Tweaks.Controls +{ + class FixAimSensitivityTweak : ITweak, ITweakInfo + { + public string Description => String.Join( + Environment.NewLine, + "If enabled, the sensitivity won't change when aiming.", + "If disabled (default), the sensitivity will be lowered when aiming down sights.", + "", + "⚠️ This might only work on 16:9 monitors.", + "⚠️ This might not work in-game while crouching."); + + public string AffectedFiles => "Fallout76Custom.ini"; + + public string AffectedValues => "fIronSightsFOVRotateMult"; + + public bool DefaultValue => false; + + public string Identifier => this.GetType().FullName; + + public bool GetValue() + { + return Math.Abs(IniFiles.GetFloat("Main", "fIronSightsFOVRotateMult", 0f) - 2.14f) < 0.1f; + } + + public void SetValue(bool value) + { + if (value) + { + IniFiles.F76Custom.Set("Controls", "fIronSightsFOVRotateMult", 2.136363636f); + IniFiles.F76Custom.Set("Main", "fIronSightsFOVRotateMult", 2.136363636f); + } + else + { + IniFiles.F76Custom.Remove("Controls", "fIronSightsFOVRotateMult"); + IniFiles.F76Custom.Remove("Main", "fIronSightsFOVRotateMult"); + } + } + + public void ResetValue() + { + SetValue(DefaultValue); + } + } +} diff --git a/Fo76ini/Tweaks/Controls/FixMouseSensitivityTweak.cs b/Fo76ini/Tweaks/Controls/FixMouseSensitivityTweak.cs new file mode 100644 index 0000000..fe9b0c1 --- /dev/null +++ b/Fo76ini/Tweaks/Controls/FixMouseSensitivityTweak.cs @@ -0,0 +1,97 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Fo76ini.Tweaks.Controls +{ + class FixMouseSensitivityTweak : ITweak, ITweakInfo + { + public string Description => String.Join( + Environment.NewLine, + "If enabled, the sensitivity for looking up/down and left/right will be equal.", + "If disabled (default), the sensitivity for looking left/right will likely be higher than up/down.", + "", + "• Enable this if you're using Mouse & Keyboard.", + "• Disable this if you're using a Gamepad.", + "", + "⚠️ When enabled, your mouse sensitivity might increase. Decrease your cursor speed or mouse DPI.", + "", + "ℹ️ The vertical sensitivity depends on your display's aspect ratio:", + " ⇨ For 4:3, the value of Y is 0.028", + " ⇨ For 16:9, the value of Y is 0.03738", + " ⇨ For 16:10, the value of Y is 0.0336", + " ⇨ For 21:9, the value of Y is 0.042", + " ⇨ For all other aspect ratios, the value of Y is equals to 0.021 times the aspect ratio. (YScale = 0.021 * Width / Height)"); + + public string AffectedFiles => "Fallout76Custom.ini"; + + public string AffectedValues => String.Join( + Environment.NewLine, + "", + " [Controls]fMouseHeadingXScale", + " [Controls]fMouseHeadingYScale", + " [Controls]fPitchSpeedRatio", + " [Controls]fIronSightsPitchSpeedRatio", + ""); + + public bool DefaultValue => false; + + public string Identifier => this.GetType().FullName; + + public bool GetValue() + { + return IniFiles.GetFloat("Controls", "fMouseHeadingXScale", 0.021f) != IniFiles.GetFloat("Controls", "fMouseHeadingYScale", 0.021f); + } + + public void SetValue(bool value) + { + if (value) + { + int width = IniFiles.GetInt("Display", "iSize W", 1920); + int height = IniFiles.GetInt("Display", "iSize H", 1080); + float aspectRatio = width / height; + float YScale; + + // 16:9 + if (Math.Abs(aspectRatio - 16 / 9) < 0.01) + YScale = 0.03738f; + + // 16:10 + else if (Math.Abs(aspectRatio - 16 / 10) < 0.01) + YScale = 0.0336f; + + // 21:9 + else if (Math.Abs(aspectRatio - 21 / 9) < 0.01) + YScale = 0.042f; + + // 4:3 + else if (Math.Abs(aspectRatio - 4 / 3) < 0.01) + YScale = 0.028f; + + // Unknown aspect ratio + else + YScale = aspectRatio * 0.021f; + + IniFiles.F76Custom.Set("Controls", "fMouseHeadingXScale", 0.021f); + IniFiles.F76Custom.Set("Controls", "fMouseHeadingYScale", YScale); + + IniFiles.F76Custom.Set("Controls", "fPitchSpeedRatio", 1.0f); + IniFiles.F76Custom.Set("Controls", "fIronSightsPitchSpeedRatio", 1.0f); + } + else + { + IniFiles.F76Custom.Remove("Controls", "fMouseHeadingXScale"); + IniFiles.F76Custom.Remove("Controls", "fMouseHeadingYScale"); + IniFiles.F76Custom.Remove("Controls", "fPitchSpeedRatio"); + IniFiles.F76Custom.Remove("Controls", "fIronSightsPitchSpeedRatio"); + } + } + + public void ResetValue() + { + SetValue(DefaultValue); + } + } +} diff --git a/Fo76ini/Tweaks/Controls/GamepadEnableTweak.cs b/Fo76ini/Tweaks/Controls/GamepadEnableTweak.cs new file mode 100644 index 0000000..073ec8a --- /dev/null +++ b/Fo76ini/Tweaks/Controls/GamepadEnableTweak.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Fo76ini.Tweaks.Controls +{ + class GamepadEnableTweak : ITweak, ITweakInfo + { + public string Description => "Disable this, if you have a gamepad plugged in, but want to use your keyboard and mouse instead."; + + public string AffectedFiles => "Fallout76Prefs.ini"; + + public string AffectedValues => "[General]bGamepadEnable"; + + public bool DefaultValue => true; + + public string Identifier => this.GetType().FullName; + + public bool GetValue() + { + return IniFiles.GetBool("General", "bGamepadEnable", DefaultValue); + } + + public void SetValue(bool value) + { + IniFiles.F76Prefs.Set("General", "bGamepadEnable", value); + } + + public void ResetValue() + { + SetValue(DefaultValue); + } + } +} diff --git a/Fo76ini/Tweaks/Controls/MouseAccelerationTweak.cs b/Fo76ini/Tweaks/Controls/MouseAccelerationTweak.cs new file mode 100644 index 0000000..ea5da6c --- /dev/null +++ b/Fo76ini/Tweaks/Controls/MouseAccelerationTweak.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Fo76ini.Tweaks.Controls +{ + class MouseAccelerationTweak : ITweak, ITweakInfo + { + public string Description => "ℹ️ This option might not have any effect."; + + public string AffectedFiles => "Fallout76Custom.ini"; + + public string AffectedValues => "[Controls]bMouseAcceleration"; + + public bool DefaultValue => false; + + public string Identifier => this.GetType().FullName; + + public bool GetValue() + { + return IniFiles.GetBool("Controls", "bMouseAcceleration", DefaultValue); + } + + public void SetValue(bool value) + { + IniFiles.F76Custom.Set("Controls", "bMouseAcceleration", value); + } + + public void ResetValue() + { + SetValue(DefaultValue); + } + } +} diff --git a/Fo76ini/Tweaks/Controls/MouseInvertXTweak.cs b/Fo76ini/Tweaks/Controls/MouseInvertXTweak.cs new file mode 100644 index 0000000..94f42f5 --- /dev/null +++ b/Fo76ini/Tweaks/Controls/MouseInvertXTweak.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Fo76ini.Tweaks.Controls +{ + class MouseInvertXTweak : ITweak, ITweakInfo + { + public string Description => ""; + + public string AffectedFiles => "Fallout76Prefs.ini"; + + public string AffectedValues => "[Controls]bInvertXValues"; + + public bool DefaultValue => false; + + public string Identifier => this.GetType().FullName; + + public bool GetValue() + { + return IniFiles.GetBool("Controls", "bInvertXValues", DefaultValue); + } + + public void SetValue(bool value) + { + IniFiles.F76Prefs.Set("Controls", "bInvertXValues", value); + } + + public void ResetValue() + { + SetValue(DefaultValue); + } + } +} diff --git a/Fo76ini/Tweaks/Controls/MouseInvertYTweak.cs b/Fo76ini/Tweaks/Controls/MouseInvertYTweak.cs new file mode 100644 index 0000000..ac19574 --- /dev/null +++ b/Fo76ini/Tweaks/Controls/MouseInvertYTweak.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Fo76ini.Tweaks.Controls +{ + class MouseInvertYTweak : ITweak, ITweakInfo + { + public string Description => ""; + + public string AffectedFiles => "Fallout76Prefs.ini"; + + public string AffectedValues => "[Controls]bInvertYValues"; + + public bool DefaultValue => false; + + public string Identifier => this.GetType().FullName; + + public bool GetValue() + { + return IniFiles.GetBool("Controls", "bInvertYValues", DefaultValue); + } + + public void SetValue(bool value) + { + IniFiles.F76Prefs.Set("Controls", "bInvertYValues", value); + } + + public void ResetValue() + { + SetValue(DefaultValue); + } + } +} diff --git a/Fo76ini/Tweaks/Controls/MouseSensitivityTweak.cs b/Fo76ini/Tweaks/Controls/MouseSensitivityTweak.cs new file mode 100644 index 0000000..431949e --- /dev/null +++ b/Fo76ini/Tweaks/Controls/MouseSensitivityTweak.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Fo76ini.Tweaks.Controls +{ + class MouseSensitivityTweak : ITweak, ITweakInfo + { + public string Description => ""; + + public string AffectedFiles => "Fallout76Prefs.ini"; + + public string AffectedValues => "[Controls]fMouseHeadingSensitivity(Y)"; + + public float DefaultValue => 0.03f; + + public string Identifier => this.GetType().FullName; + + public float GetValue() + { + return IniFiles.GetFloat("Controls", "fMouseHeadingSensitivity", DefaultValue); + } + + public void SetValue(float value) + { + // TODO: Fallout76Custom.ini had no effect. I hope Fallout76Prefs.ini will have an effect this time: + IniFiles.F76Prefs.Set("Controls", "fMouseHeadingSensitivity", value); + IniFiles.F76Prefs.Set("Controls", "fMouseHeadingSensitivityY", value); + } + + public void ResetValue() + { + SetValue(DefaultValue); + } + } +} diff --git a/Fo76ini/Tweaks/General/AutoSigninTweak.cs b/Fo76ini/Tweaks/General/AutoSigninTweak.cs new file mode 100644 index 0000000..523d418 --- /dev/null +++ b/Fo76ini/Tweaks/General/AutoSigninTweak.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Fo76ini.Tweaks.General +{ + class AutoSigninTweak : ITweak, ITweakInfo + { + public string Description => "Enabling this, will skip the login prompt if you provide your login credentials."; + + public string AffectedFiles => "Fallout76Custom.ini"; + + public string AffectedValues => "[Login]bAutoSignin"; + + public bool DefaultValue => false; + + public string Identifier => this.GetType().FullName; + + public bool GetValue() + { + return IniFiles.F76Custom.GetBool("Login", "bAutoSignin", DefaultValue); + } + + public void SetValue(bool value) + { + IniFiles.F76Custom.Set("Login", "bAutoSignin", value); + } + + public void ResetValue() + { + SetValue(DefaultValue); + } + } +} \ No newline at end of file diff --git a/Fo76ini/Tweaks/General/EnableSteamTweak.cs b/Fo76ini/Tweaks/General/EnableSteamTweak.cs new file mode 100644 index 0000000..3d1eb5f --- /dev/null +++ b/Fo76ini/Tweaks/General/EnableSteamTweak.cs @@ -0,0 +1,30 @@ +namespace Fo76ini.Tweaks.General +{ + class EnableSteamTweak : ITweak, ITweakInfo + { + public bool DefaultValue => true; + + public string Description => "Enables/Disables Steam integration. Disable it to use your Bethesda.net account."; + + public string AffectedFiles => "Fallout76Custom.ini"; + + public string AffectedValues => "[General]bSteamEnabled"; + + public string Identifier => this.GetType().FullName; + + public bool GetValue() + { + return IniFiles.F76Custom.GetBool("General", "bSteamEnabled", DefaultValue); + } + + public void SetValue(bool value) + { + IniFiles.F76Custom.Set("General", "bSteamEnabled", value); + } + + public void ResetValue() + { + SetValue(DefaultValue); + } + } +} diff --git a/Fo76ini/Tweaks/General/IntroVideoTweak.cs b/Fo76ini/Tweaks/General/IntroVideoTweak.cs new file mode 100644 index 0000000..b30ff76 --- /dev/null +++ b/Fo76ini/Tweaks/General/IntroVideoTweak.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Fo76ini.Tweaks.General +{ + class IntroVideoTweak : ITweak, ITweakInfo + { + public string Description => "When this option is disabled, the game will start without displaying the Bethesda logo video."; + + public string AffectedFiles => "Fallout76Custom.ini"; + + public string AffectedValues => "[General]sIntroSequence, [General]uMainMenuDelayBeforeAllowSkip"; + + public bool DefaultValue => true; + + public string Identifier => this.GetType().FullName; + + public bool GetValue() + { + string sIntroSequence = IniFiles.GetString("General", "sIntroSequence", "BGSLogo4k.bk2").Trim(); + return sIntroSequence.Length > 0 && sIntroSequence != "0"; + } + + public void SetValue(bool value) + { + if (value) + { + IniFiles.F76Custom.Remove("General", "sIntroSequence"); + IniFiles.F76Custom.Remove("General", "uMainMenuDelayBeforeAllowSkip"); + } + else + { + IniFiles.F76Custom.Set("General", "sIntroSequence", ""); + IniFiles.F76Custom.Set("General", "uMainMenuDelayBeforeAllowSkip", "0"); + } + } + + public void ResetValue() + { + SetValue(DefaultValue); + } + } +} diff --git a/Fo76ini/Tweaks/General/ScreenshotIndexTweak.cs b/Fo76ini/Tweaks/General/ScreenshotIndexTweak.cs new file mode 100644 index 0000000..c3953ae --- /dev/null +++ b/Fo76ini/Tweaks/General/ScreenshotIndexTweak.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Fo76ini.Tweaks.General +{ + class ScreenshotIndexTweak : ITweak, ITweakInfo + { + public string Description => + "When you take screenshots ingame with the print screen button,\n" + + "it saves them in the game directory as \"ScreenShotX.png\".\n" + + "The \"X\" being the screenshot index."; + + public string AffectedFiles => "Fallout76Prefs.ini"; + + public string AffectedValues => "[Display]iScreenShotIndex"; + + public int DefaultValue => 0; + + public string Identifier => this.GetType().FullName; + + public int GetValue() + { + return IniFiles.GetInt("Display", "iScreenShotIndex", DefaultValue); + } + + public void SetValue(int value) + { + IniFiles.F76Prefs.Set("Display", "iScreenShotIndex", value); + } + + public void ResetValue() + { + SetValue(DefaultValue); + } + } +} diff --git a/Fo76ini/Tweaks/General/SkipStartupSplash.cs b/Fo76ini/Tweaks/General/SkipStartupSplash.cs new file mode 100644 index 0000000..350a714 --- /dev/null +++ b/Fo76ini/Tweaks/General/SkipStartupSplash.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Fo76ini.Tweaks.General +{ + class SkipStartupSplash : ITweak, ITweakInfo + { + public string Description => "If enabled, the game won't bother you with news on startup."; + + public string AffectedFiles => "Fallout76Custom.ini"; + + public string AffectedValues => "[General]bSkipSplash"; + + public bool DefaultValue => false; + + public string Identifier => this.GetType().FullName; + + public bool GetValue() + { + return IniFiles.GetBool("General", "bSkipSplash", DefaultValue); + } + + public void SetValue(bool value) + { + IniFiles.F76Custom.Set("General", "bSkipSplash", value); + } + + public void ResetValue() + { + SetValue(DefaultValue); + } + } +} diff --git a/Fo76ini/Tweaks/Graphics/AmbientOcclusionTweak.cs b/Fo76ini/Tweaks/Graphics/AmbientOcclusionTweak.cs new file mode 100644 index 0000000..d09c500 --- /dev/null +++ b/Fo76ini/Tweaks/Graphics/AmbientOcclusionTweak.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Fo76ini.Tweaks.Graphics +{ + class AmbientOcclusionTweak : ITweak, ITweakInfo + { + public string Description => ""; + + public string AffectedFiles => "Fallout76Prefs.ini"; + + public string AffectedValues => "[Display]bSAOEnable"; + + public bool DefaultValue => true; + + public string Identifier => this.GetType().FullName; + + public bool GetValue() + { + return IniFiles.GetBool("Display", "bSAOEnable", DefaultValue); + } + + public void SetValue(bool value) + { + IniFiles.F76Prefs.Set("Display", "bSAOEnable", value); + } + + public void ResetValue() + { + SetValue(DefaultValue); + } + } +} diff --git a/Fo76ini/Tweaks/Graphics/AnisotropicFilteringTweak.cs b/Fo76ini/Tweaks/Graphics/AnisotropicFilteringTweak.cs new file mode 100644 index 0000000..ae8292c --- /dev/null +++ b/Fo76ini/Tweaks/Graphics/AnisotropicFilteringTweak.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Fo76ini.Tweaks.Graphics +{ + class AnisotropicFilteringTweak : ITweak, ITweakInfo + { + public string Description => "Reduces aliasing of textures when viewed from oblique angles."; + + public string AffectedFiles => "Fallout76Prefs.ini"; + + public string AffectedValues => "[Display]iMaxAnisotropy"; + + public int DefaultValue => 8; + + public string Identifier => this.GetType().FullName; + + public int GetValue() + { + return IniFiles.GetInt("Display", "iMaxAnisotropy", DefaultValue); + } + + public void SetValue(int value) + { + IniFiles.F76Prefs.Set("Display", "iMaxAnisotropy", value); + } + + public void ResetValue() + { + SetValue(DefaultValue); + } + } +} diff --git a/Fo76ini/Tweaks/Graphics/AntiAliasingTweak.cs b/Fo76ini/Tweaks/Graphics/AntiAliasingTweak.cs new file mode 100644 index 0000000..8b156a7 --- /dev/null +++ b/Fo76ini/Tweaks/Graphics/AntiAliasingTweak.cs @@ -0,0 +1,74 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Fo76ini.Tweaks.Graphics +{ + public enum AntiAliasing + { + TAA = 0, + FXAA = 1, + Disabled = 2 + } + + class AntiAliasingTweak : ITweak, ITweakInfo, IEnumTweak + { + public string Description => String.Join( + Environment.NewLine, + "Smoothes edges of objects.", + "", + "• TAA - Temporal Anti-Aliasing: Relatively expensive, can introduce artefacts, default", + "• FXAA - Fast Approximate Anti-Aliasing: Slightly improves performance", + "• Off - Improves performance, degrades visual quality", + "", + "⚠️ FXAA might not work. The game might just disable AA instead."); + + public string AffectedFiles => "Fallout76Prefs.ini"; + + public string AffectedValues => "[Display]sAntiAliasing"; + + public AntiAliasing DefaultValue => AntiAliasing.TAA; + + public string Identifier => this.GetType().FullName; + + // https://stackoverflow.com/a/16946496 + public int Count => Enum.GetNames(typeof(AntiAliasing)).Length; + + public AntiAliasing GetValue() + { + switch (IniFiles.GetString("Display", "sAntiAliasing", DefaultValue.ToString())) + { + case "TAA": + return AntiAliasing.TAA; + case "FXAA": + return AntiAliasing.FXAA; + case "": + return AntiAliasing.Disabled; + default: + return DefaultValue; + } + } + + public void SetValue(AntiAliasing value) + { + IniFiles.F76Prefs.Set("Display", "sAntiAliasing", value.ToString()); + } + + public void ResetValue() + { + SetValue(DefaultValue); + } + + public int GetInt() + { + return (int)GetValue(); + } + + public void SetInt(int value) + { + SetValue((AntiAliasing)value); + } + } +} diff --git a/Fo76ini/Tweaks/Graphics/BlendSplitDirShadowTweak.cs b/Fo76ini/Tweaks/Graphics/BlendSplitDirShadowTweak.cs new file mode 100644 index 0000000..d4e546e --- /dev/null +++ b/Fo76ini/Tweaks/Graphics/BlendSplitDirShadowTweak.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Fo76ini.Tweaks.Graphics +{ + class BlendSplitDirShadowTweak : ITweak, ITweakInfo + { + public string Description => + "Distance at which the game will transition to lower-res a shadow \"segment\".\n" + + "MUST be a multiple of 12."; + + public string AffectedFiles => "Fallout76Prefs.ini"; + + public string AffectedValues => "[Display]fBlendSplitDirShadow"; + + public int DefaultValue => 48; + + public string Identifier => this.GetType().FullName; + + public int GetValue() + { + return IniFiles.GetInt("Display", "fBlendSplitDirShadow", DefaultValue); + } + + public void SetValue(int value) + { + IniFiles.F76Prefs.Set("Display", "fBlendSplitDirShadow", value); + } + + public void ResetValue() + { + SetValue(DefaultValue); + } + } +} diff --git a/Fo76ini/Tweaks/Graphics/DirShadowSplitsTweak.cs b/Fo76ini/Tweaks/Graphics/DirShadowSplitsTweak.cs new file mode 100644 index 0000000..c445133 --- /dev/null +++ b/Fo76ini/Tweaks/Graphics/DirShadowSplitsTweak.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Fo76ini.Tweaks.Graphics +{ + class DirShadowSplitsTweak : ITweak, ITweakInfo + { + public string Description => + "Amount of \"segments\" of lower-res shadows at a distance.\n" + + "A value of 1 forces the game to render only the lowest resolution shadows."; + + public string AffectedFiles => "Fallout76Prefs.ini"; + + public string AffectedValues => "[Display]iDirShadowSplits"; + + public int DefaultValue => 3; + + public string Identifier => this.GetType().FullName; + + public int GetValue() + { + return IniFiles.GetInt("Display", "iDirShadowSplits", DefaultValue); + } + + public void SetValue(int value) + { + IniFiles.F76Prefs.Set("Display", "iDirShadowSplits", value); + } + + public void ResetValue() + { + SetValue(DefaultValue); + } + } +} diff --git a/Fo76ini/Tweaks/Graphics/DisableAllGoreTweak.cs b/Fo76ini/Tweaks/Graphics/DisableAllGoreTweak.cs new file mode 100644 index 0000000..52a5655 --- /dev/null +++ b/Fo76ini/Tweaks/Graphics/DisableAllGoreTweak.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Fo76ini.Tweaks.Graphics +{ + class DisableAllGoreTweak : ITweak, ITweakInfo + { + public string Description => ""; + + public string AffectedFiles => "Fallout76Custom.ini"; + + public string AffectedValues => "[General]bDisableAllGore, bBloodSpatterEnabled"; + + public bool DefaultValue => false; + + public string Identifier => this.GetType().FullName; + + public bool GetValue() + { + return IniFiles.GetBool("General", "bDisableAllGore", DefaultValue); + } + + public void SetValue(bool value) + { + if (value) + { + IniFiles.F76Custom.Set("General", "bDisableAllGore", true); + IniFiles.F76Custom.Set("General", "bBloodSpatterEnabled", false); + } + else + { + IniFiles.F76Custom.Remove("General", "bDisableAllGore"); + IniFiles.F76Custom.Remove("General", "bBloodSpatterEnabled"); + } + } + + public void ResetValue() + { + SetValue(DefaultValue); + } + } +} diff --git a/Fo76ini/Tweaks/Graphics/EnableDepthOfFieldTweak.cs b/Fo76ini/Tweaks/Graphics/EnableDepthOfFieldTweak.cs new file mode 100644 index 0000000..992cc8d --- /dev/null +++ b/Fo76ini/Tweaks/Graphics/EnableDepthOfFieldTweak.cs @@ -0,0 +1,74 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Fo76ini.Tweaks.Graphics +{ + // TODO: More DoF tweaks instead of just on/off. + class EnableDepthOfFieldTweak : ITweak, ITweakInfo + { + public string Description => "Disabling this will disable all Depth of Field effects."; + + public string AffectedFiles => "Fallout76Custom.ini"; + + public string AffectedValues => String.Join( + Environment.NewLine, + "", + " [ImageSpace]bDynamicDepthOfField", + " [Display]fDOFBlendRatio", + " [Display]fDOFMinFocalCoefDist", + " [Display]fDOFMaxFocalCoefDist", + " [Display]fDOFDynamicFarRange", + " [Display]fDOFCenterWeightInt", + " [Display]fDOFFarDistance", + ""); + + public bool DefaultValue => true; + + public string Identifier => this.GetType().FullName; + + public bool GetValue() + { + return IniFiles.GetBool("ImageSpace", "bDynamicDepthOfField", true); + } + + public void SetValue(bool value) + { + if (value) + { + IniFiles.F76Custom.Remove("ImageSpace", "bDynamicDepthOfField"); + IniFiles.F76Custom.Remove("Display", "fDOFBlendRatio"); + IniFiles.F76Custom.Remove("Display", "fDOFMinFocalCoefDist"); + IniFiles.F76Custom.Remove("Display", "fDOFMaxFocalCoefDist"); + IniFiles.F76Custom.Remove("Display", "fDOFDynamicFarRange"); + IniFiles.F76Custom.Remove("Display", "fDOFCenterWeightInt"); + IniFiles.F76Custom.Remove("Display", "fDOFFarDistance"); + } + else + { + IniFiles.F76Custom.Set("ImageSpace", "bDynamicDepthOfField", false); + IniFiles.F76Custom.Set("Display", "fDOFBlendRatio", 0); + IniFiles.F76Custom.Set("Display", "fDOFMinFocalCoefDist", 999999); + IniFiles.F76Custom.Set("Display", "fDOFMaxFocalCoefDist", 99999999); + IniFiles.F76Custom.Set("Display", "fDOFDynamicFarRange", 99999999); + IniFiles.F76Custom.Set("Display", "fDOFCenterWeightInt", 0); + IniFiles.F76Custom.Set("Display", "fDOFFarDistance", 99999999); + + /* + Things I wanted to add: + + bDoDepthOfField - DO NOT set this to 0. It will cause underwater effects to disappear. + bScreenSpaceBokeh - Apparently some blur effect. Is it related to DOF? + bUseBlurShader - ? + */ + } + } + + public void ResetValue() + { + SetValue(DefaultValue); + } + } +} diff --git a/Fo76ini/Tweaks/Graphics/EnableGrassTweak.cs b/Fo76ini/Tweaks/Graphics/EnableGrassTweak.cs new file mode 100644 index 0000000..869dff5 --- /dev/null +++ b/Fo76ini/Tweaks/Graphics/EnableGrassTweak.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Fo76ini.Tweaks.Graphics +{ + class EnableGrassTweak : ITweak, ITweakInfo + { + public string Description => ""; + + public string AffectedFiles => "Fallout76Custom.ini"; + + public string AffectedValues => "[Grass]bAllowCreateGrass"; + + public bool DefaultValue => true; + + public string Identifier => this.GetType().FullName; + + public bool GetValue() + { + return IniFiles.GetBool("Grass", "bAllowCreateGrass", DefaultValue); + } + + public void SetValue(bool value) + { + IniFiles.F76Custom.Set("Grass", "bAllowCreateGrass", value); + } + + public void ResetValue() + { + SetValue(DefaultValue); + } + } +} diff --git a/Fo76ini/Tweaks/Graphics/FogTweak.cs b/Fo76ini/Tweaks/Graphics/FogTweak.cs new file mode 100644 index 0000000..063b135 --- /dev/null +++ b/Fo76ini/Tweaks/Graphics/FogTweak.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Fo76ini.Tweaks.Graphics +{ + class FogTweak : ITweak, ITweakInfo + { + public string Description => ""; + + public string AffectedFiles => "Fallout76Prefs.ini"; + + public string AffectedValues => "[Weather]bFogEnabled"; + + public bool DefaultValue => true; + + public string Identifier => this.GetType().FullName; + + public bool GetValue() + { + return IniFiles.GetBool("Weather", "bFogEnabled", DefaultValue); + } + + public void SetValue(bool value) + { + IniFiles.F76Prefs.Set("Weather", "bFogEnabled", value); + } + + public void ResetValue() + { + SetValue(DefaultValue); + } + } +} diff --git a/Fo76ini/Tweaks/Graphics/GrassFadeDistanceTweak.cs b/Fo76ini/Tweaks/Graphics/GrassFadeDistanceTweak.cs new file mode 100644 index 0000000..43fed35 --- /dev/null +++ b/Fo76ini/Tweaks/Graphics/GrassFadeDistanceTweak.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Fo76ini.Tweaks.Graphics +{ + class GrassFadeDistanceTweak : ITweak, ITweakInfo + { + public string Description => String.Join( + Environment.NewLine, + "Sets the distance grass will begin to fade.", + " ⇨ Ultra is 7000", + " ⇨ High is 5500", + " ⇨ Medium is 4500"); + + public string AffectedFiles => "Fallout76Prefs.ini"; + + public string AffectedValues => "[Grass]fGrassStartFadeDistance, fGrassMinStartFadeDistance, fGrassMaxStartFadeDistance"; + + public float DefaultValue => 3000f; + + public string Identifier => this.GetType().FullName; + + public float GetValue() + { + return IniFiles.GetFloat("Grass", "fGrassStartFadeDistance", DefaultValue); + } + + public void SetValue(float value) + { + IniFiles.F76Prefs.Set("Grass", "fGrassStartFadeDistance", value); + IniFiles.F76Prefs.Set("Grass", "fGrassMinStartFadeDistance", 0); + IniFiles.F76Prefs.Set("Grass", "fGrassMaxStartFadeDistance", value); + } + + public void ResetValue() + { + SetValue(DefaultValue); + } + } +} diff --git a/Fo76ini/Tweaks/Graphics/LODFadeOutMultActorsTweak.cs b/Fo76ini/Tweaks/Graphics/LODFadeOutMultActorsTweak.cs new file mode 100644 index 0000000..4dc881e --- /dev/null +++ b/Fo76ini/Tweaks/Graphics/LODFadeOutMultActorsTweak.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Fo76ini.Tweaks.Graphics +{ + class LODFadeOutMultActorsTweak : ITweak, ITweakInfo + { + public string Description => ""; + + public string AffectedFiles => "Fallout76Prefs.ini"; + + public string AffectedValues => "[LOD]fLODFadeOutMultActors"; + + public float DefaultValue => 4.5f; + + public string Identifier => this.GetType().FullName; + + public float GetValue() + { + return IniFiles.GetFloat("LOD", "fLODFadeOutMultActors", DefaultValue); + } + + public void SetValue(float value) + { + IniFiles.F76Prefs.Set("LOD", "fLODFadeOutMultActors", value); + } + + public void ResetValue() + { + SetValue(DefaultValue); + } + } +} diff --git a/Fo76ini/Tweaks/Graphics/LODFadeOutMultItemsTweak.cs b/Fo76ini/Tweaks/Graphics/LODFadeOutMultItemsTweak.cs new file mode 100644 index 0000000..b44c67b --- /dev/null +++ b/Fo76ini/Tweaks/Graphics/LODFadeOutMultItemsTweak.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Fo76ini.Tweaks.Graphics +{ + class LODFadeOutMultItemsTweak : ITweak, ITweakInfo + { + public string Description => ""; + + public string AffectedFiles => "Fallout76Prefs.ini"; + + public string AffectedValues => "[LOD]fLODFadeOutMultItems"; + + public float DefaultValue => 2.5f; + + public string Identifier => this.GetType().FullName; + + public float GetValue() + { + return IniFiles.GetFloat("LOD", "fLODFadeOutMultItems", DefaultValue); + } + + public void SetValue(float value) + { + IniFiles.F76Prefs.Set("LOD", "fLODFadeOutMultItems", value); + } + + public void ResetValue() + { + SetValue(DefaultValue); + } + } +} diff --git a/Fo76ini/Tweaks/Graphics/LODFadeOutMultObjectsTweak.cs b/Fo76ini/Tweaks/Graphics/LODFadeOutMultObjectsTweak.cs new file mode 100644 index 0000000..64fb1d5 --- /dev/null +++ b/Fo76ini/Tweaks/Graphics/LODFadeOutMultObjectsTweak.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Fo76ini.Tweaks.Graphics +{ + class LODFadeOutMultObjectsTweak : ITweak, ITweakInfo + { + public string Description => ""; + + public string AffectedFiles => "Fallout76Prefs.ini"; + + public string AffectedValues => "[LOD]fLODFadeOutMultObjects"; + + public float DefaultValue => 6.0f; + + public string Identifier => this.GetType().FullName; + + public float GetValue() + { + return IniFiles.GetFloat("LOD", "fLODFadeOutMultObjects", DefaultValue); + } + + public void SetValue(float value) + { + IniFiles.F76Prefs.Set("LOD", "fLODFadeOutMultObjects", value); + } + + public void ResetValue() + { + SetValue(DefaultValue); + } + } +} diff --git a/Fo76ini/Tweaks/Graphics/LensFlareTweak.cs b/Fo76ini/Tweaks/Graphics/LensFlareTweak.cs new file mode 100644 index 0000000..6963247 --- /dev/null +++ b/Fo76ini/Tweaks/Graphics/LensFlareTweak.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Fo76ini.Tweaks.Graphics +{ + class LensFlareTweak : ITweak, ITweakInfo + { + public string Description => ""; + + public string AffectedFiles => "Fallout76Prefs.ini"; + + public string AffectedValues => "[ImageSpace]bLensFlare"; + + public bool DefaultValue => true; + + public string Identifier => this.GetType().FullName; + + public bool GetValue() + { + return IniFiles.GetBool("ImageSpace", "bLensFlare", DefaultValue); + } + + public void SetValue(bool value) + { + IniFiles.F76Prefs.Set("ImageSpace", "bLensFlare", value); + } + + public void ResetValue() + { + SetValue(DefaultValue); + } + } +} diff --git a/Fo76ini/Tweaks/Graphics/MotionBlurTweak.cs b/Fo76ini/Tweaks/Graphics/MotionBlurTweak.cs new file mode 100644 index 0000000..15c025a --- /dev/null +++ b/Fo76ini/Tweaks/Graphics/MotionBlurTweak.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Fo76ini.Tweaks.Graphics +{ + class MotionBlurTweak : ITweak, ITweakInfo + { + public string Description => ""; + + public string AffectedFiles => "Fallout76Custom.ini"; + + public string AffectedValues => "[ImageSpace]bMBEnable"; + + public bool DefaultValue => true; + + public string Identifier => this.GetType().FullName; + + public bool GetValue() + { + return IniFiles.GetBool("ImageSpace", "bMBEnable", DefaultValue); + } + + public void SetValue(bool value) + { + IniFiles.F76Custom.Set("ImageSpace", "bMBEnable", value); + } + + public void ResetValue() + { + SetValue(DefaultValue); + } + } +} diff --git a/Fo76ini/Tweaks/Graphics/RadialBlurTweak.cs b/Fo76ini/Tweaks/Graphics/RadialBlurTweak.cs new file mode 100644 index 0000000..6add78a --- /dev/null +++ b/Fo76ini/Tweaks/Graphics/RadialBlurTweak.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Fo76ini.Tweaks.Graphics +{ + class RadialBlurTweak : ITweak, ITweakInfo + { + public string Description => + "Blurs the screen when the player is hurt (e.g. hit by bullets) or under water.\n" + + "⚠️ Disabling this might result in a clear view underwater."; + + public string AffectedFiles => "Fallout76Custom.ini"; + + public string AffectedValues => "[ImageSpace]bDoRadialBlur"; + + public bool DefaultValue => true; + + public string Identifier => this.GetType().FullName; + + public bool GetValue() + { + return IniFiles.GetBool("ImageSpace", "bDoRadialBlur", DefaultValue); + } + + public void SetValue(bool value) + { + IniFiles.F76Custom.Set("ImageSpace", "bDoRadialBlur", value); + } + + public void ResetValue() + { + SetValue(DefaultValue); + } + } +} diff --git a/Fo76ini/Tweaks/Graphics/RainOcclusionTweak.cs b/Fo76ini/Tweaks/Graphics/RainOcclusionTweak.cs new file mode 100644 index 0000000..0673ee3 --- /dev/null +++ b/Fo76ini/Tweaks/Graphics/RainOcclusionTweak.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Fo76ini.Tweaks.Graphics +{ + class RainOcclusionTweak : ITweak, ITweakInfo + { + public string Description => ""; + + public string AffectedFiles => "Fallout76.ini"; + + public string AffectedValues => "[Weather]bRainOcclusion"; + + public bool DefaultValue => true; + + public string Identifier => this.GetType().FullName; + + public bool GetValue() + { + return IniFiles.GetBool("Weather", "bRainOcclusion", DefaultValue); + } + + public void SetValue(bool value) + { + IniFiles.F76.Set("Weather", "bRainOcclusion", value); + } + + public void ResetValue() + { + SetValue(DefaultValue); + } + } +} diff --git a/Fo76ini/Tweaks/Graphics/ScreenSpaceReflectionsTweak.cs b/Fo76ini/Tweaks/Graphics/ScreenSpaceReflectionsTweak.cs new file mode 100644 index 0000000..5675f91 --- /dev/null +++ b/Fo76ini/Tweaks/Graphics/ScreenSpaceReflectionsTweak.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Fo76ini.Tweaks.Graphics +{ + class ScreenSpaceReflectionsTweak : ITweak, ITweakInfo + { + public string Description => "Enables/disables screen space reflections.\nWill make water disappear or become pitch black!"; + + public string AffectedFiles => "Fallout76Prefs.ini"; + + public string AffectedValues => "[LightingShader]bScreenSpaceReflections"; + + public bool DefaultValue => true; + + public string Identifier => this.GetType().FullName; + + public bool GetValue() + { + return IniFiles.GetBool("LightingShader", "bScreenSpaceReflections", DefaultValue); + } + + public void SetValue(bool value) + { + IniFiles.F76Prefs.Set("LightingShader", "bScreenSpaceReflections", value); + } + + public void ResetValue() + { + SetValue(DefaultValue); + } + } +} diff --git a/Fo76ini/Tweaks/Graphics/ShadowBlurrinessTweak.cs b/Fo76ini/Tweaks/Graphics/ShadowBlurrinessTweak.cs new file mode 100644 index 0000000..7bd9e4d --- /dev/null +++ b/Fo76ini/Tweaks/Graphics/ShadowBlurrinessTweak.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Fo76ini.Tweaks.Graphics +{ + class ShadowBlurrinessTweak : ITweak, ITweakInfo + { + public string Description => "Blurs shadows. Especially useful, if you set a lower shadow resolution."; + + public string AffectedFiles => "Fallout76Prefs.ini"; + + public string AffectedValues => "[Display]uiOrthoShadowFilter"; + + public int DefaultValue => 3; + + public string Identifier => this.GetType().FullName; + + public int GetValue() + { + return IniFiles.GetInt("Display", "uiOrthoShadowFilter", DefaultValue); + } + + public void SetValue(int value) + { + IniFiles.F76Prefs.Set("Display", "uiOrthoShadowFilter", value); + } + + public void ResetValue() + { + SetValue(DefaultValue); + } + } +} diff --git a/Fo76ini/Tweaks/Graphics/ShadowDistanceTweak.cs b/Fo76ini/Tweaks/Graphics/ShadowDistanceTweak.cs new file mode 100644 index 0000000..5328298 --- /dev/null +++ b/Fo76ini/Tweaks/Graphics/ShadowDistanceTweak.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Fo76ini.Tweaks.Graphics +{ + // fShadowDistance was replaced by fDirShadowDistance in Fallout 4 + class ShadowDistanceTweak : ITweak, ITweakInfo + { + public string Description => String.Join( + Environment.NewLine, + "Sets the distance that shadows are rendered.", + " ⇨ Ultra is 150000", + " ⇨ High is 120000", + " ⇨ Medium is 90000", + " ⇨ Low is 60000"); + + public string AffectedFiles => "Fallout76Prefs.ini"; + + public string AffectedValues => "[Display]fDirShadowDistance"; + + public float DefaultValue => 90000f; + + public string Identifier => this.GetType().FullName; + + public float GetValue() + { + return IniFiles.GetFloat("Display", "fDirShadowDistance", DefaultValue); + } + + public void SetValue(float value) + { + IniFiles.F76Prefs.Set("Display", "fDirShadowDistance", value); + } + + public void ResetValue() + { + SetValue(DefaultValue); + } + } +} diff --git a/Fo76ini/Tweaks/Graphics/ShadowMapResolutionTweak.cs b/Fo76ini/Tweaks/Graphics/ShadowMapResolutionTweak.cs new file mode 100644 index 0000000..042d7b1 --- /dev/null +++ b/Fo76ini/Tweaks/Graphics/ShadowMapResolutionTweak.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Fo76ini.Tweaks.Graphics +{ + class ShadowMapResolutionTweak : ITweak, ITweakInfo + { + public string Description => "Resolution of shadows. Higher settings will make shadows more detailed."; + + public string AffectedFiles => "Fallout76Prefs.ini"; + + public string AffectedValues => "[Display]iShadowMapResolution"; + + public int DefaultValue => 2048; + + public string Identifier => this.GetType().FullName; + + public int GetValue() + { + return IniFiles.GetInt("Display", "iShadowMapResolution", DefaultValue); + } + + public void SetValue(int value) + { + IniFiles.F76Prefs.Set("Display", "iShadowMapResolution", value); + } + + public void ResetValue() + { + SetValue(DefaultValue); + } + } +} diff --git a/Fo76ini/Tweaks/Graphics/TAAPostOverlayTweak.cs b/Fo76ini/Tweaks/Graphics/TAAPostOverlayTweak.cs new file mode 100644 index 0000000..a5c61f6 --- /dev/null +++ b/Fo76ini/Tweaks/Graphics/TAAPostOverlayTweak.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Fo76ini.Tweaks.Graphics +{ + class TAAPostOverlayTweak : ITweak, ITweakInfo + { + public string Description => String.Join( + Environment.NewLine, + "Sharpens the image.", + "Default: 0.21"); + + public string AffectedFiles => "Fallout76Custom.ini"; + + public string AffectedValues => "[Display]fTAAPostOverlay"; + + public float DefaultValue => 0.21f; + + public string Identifier => this.GetType().FullName; + + public float GetValue() + { + return IniFiles.GetFloat("Display", "fTAAPostOverlay", DefaultValue); + } + + public void SetValue(float value) + { + IniFiles.F76Custom.Set("Display", "fTAAPostOverlay", value); + } + + public void ResetValue() + { + SetValue(DefaultValue); + } + } +} diff --git a/Fo76ini/Tweaks/Graphics/TAAPostSharpenTweak.cs b/Fo76ini/Tweaks/Graphics/TAAPostSharpenTweak.cs new file mode 100644 index 0000000..7476fae --- /dev/null +++ b/Fo76ini/Tweaks/Graphics/TAAPostSharpenTweak.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Fo76ini.Tweaks.Graphics +{ + class TAAPostSharpenTweak : ITweak, ITweakInfo + { + public string Description => String.Join( + Environment.NewLine, + "Sharpens the image.", + "Default: 0.21", + "Recommended: 0.4"); + + public string AffectedFiles => "Fallout76Custom.ini"; + + public string AffectedValues => "[Display]fTAAPostSharpen"; + + public float DefaultValue => 0.21f; + + public string Identifier => this.GetType().FullName; + + public float GetValue() + { + return IniFiles.GetFloat("Display", "fTAAPostSharpen", DefaultValue); + } + + public void SetValue(float value) + { + IniFiles.F76Custom.Set("Display", "fTAAPostSharpen", value); + } + + public void ResetValue() + { + SetValue(DefaultValue); + } + } +} diff --git a/Fo76ini/Tweaks/Graphics/VolumetricLightingTweak.cs b/Fo76ini/Tweaks/Graphics/VolumetricLightingTweak.cs new file mode 100644 index 0000000..25357c7 --- /dev/null +++ b/Fo76ini/Tweaks/Graphics/VolumetricLightingTweak.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Fo76ini.Tweaks.Graphics +{ + class VolumetricLightingTweak : ITweak, ITweakInfo + { + public string Description => ""; + + public string AffectedFiles => "Fallout76Prefs.ini"; + + public string AffectedValues => "[Display]bVolumetricLightingEnable"; + + public bool DefaultValue => true; + + public string Identifier => this.GetType().FullName; + + public bool GetValue() + { + return IniFiles.GetBool("Display", "bVolumetricLightingEnable", DefaultValue); + } + + public void SetValue(bool value) + { + IniFiles.F76Prefs.Set("Display", "bVolumetricLightingEnable", value); + } + + public void ResetValue() + { + SetValue(DefaultValue); + } + } +} diff --git a/Fo76ini/Tweaks/Graphics/WaterDisplacementsTweak.cs b/Fo76ini/Tweaks/Graphics/WaterDisplacementsTweak.cs new file mode 100644 index 0000000..4eb177d --- /dev/null +++ b/Fo76ini/Tweaks/Graphics/WaterDisplacementsTweak.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Fo76ini.Tweaks.Graphics +{ + class WaterDisplacementsTweak : ITweak, ITweakInfo + { + public string Description => "Enables/disables water displacement (ripples, waves)."; + + public string AffectedFiles => "Fallout76Prefs.ini"; + + public string AffectedValues => "[Water]bUseWaterDisplacements"; + + public bool DefaultValue => true; + + public string Identifier => this.GetType().FullName; + + public bool GetValue() + { + return IniFiles.GetBool("Water", "bUseWaterDisplacements", DefaultValue); + } + + public void SetValue(bool value) + { + IniFiles.F76Prefs.Set("Water", "bUseWaterDisplacements", value); + } + + public void ResetValue() + { + SetValue(DefaultValue); + } + } +} diff --git a/Fo76ini/Tweaks/Graphics/WetnessOcclusionTweak.cs b/Fo76ini/Tweaks/Graphics/WetnessOcclusionTweak.cs new file mode 100644 index 0000000..4a4230a --- /dev/null +++ b/Fo76ini/Tweaks/Graphics/WetnessOcclusionTweak.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Fo76ini.Tweaks.Graphics +{ + class WetnessOcclusionTweak : ITweak, ITweakInfo + { + public string Description => ""; + + public string AffectedFiles => "Fallout76.ini"; + + public string AffectedValues => "[Weather]bWetnessOcclusion"; + + public bool DefaultValue => true; + + public string Identifier => this.GetType().FullName; + + public bool GetValue() + { + return IniFiles.GetBool("Weather", "bWetnessOcclusion", DefaultValue); + } + + public void SetValue(bool value) + { + IniFiles.F76.Set("Weather", "bWetnessOcclusion", value); + } + + public void ResetValue() + { + SetValue(DefaultValue); + } + } +} diff --git a/Fo76ini/Tweaks/ITweak.cs b/Fo76ini/Tweaks/ITweak.cs new file mode 100644 index 0000000..ecb013c --- /dev/null +++ b/Fo76ini/Tweaks/ITweak.cs @@ -0,0 +1,48 @@ +namespace Fo76ini.Tweaks +{ + /// + /// Represents an *.ini tweak. May change more than one value in more than one file. + /// + public interface ITweak + { + T GetValue(); + + void SetValue(T value); + + /// + /// Reset the tweak to default values. + /// + void ResetValue(); + + T DefaultValue { get; } + } + + /// + /// Stores info about an *.ini tweak. + /// + public interface ITweakInfo + { + string Identifier { get; } + + string Description { get; } + + string AffectedFiles { get; } + + string AffectedValues { get; } + } + + /// + /// Makes it possible to interface with an ITweak using integer. + /// + public interface IEnumTweak + { + int GetInt(); + + void SetInt(int value); + + /// + /// Get the amount of names in an enum. + /// + int Count { get; } + } +} diff --git a/Fo76ini/Tweaks/IniFiles/INIReadOnlyTweak.cs b/Fo76ini/Tweaks/IniFiles/INIReadOnlyTweak.cs new file mode 100644 index 0000000..f044a94 --- /dev/null +++ b/Fo76ini/Tweaks/IniFiles/INIReadOnlyTweak.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Fo76ini; + +namespace Fo76ini.Tweaks.Inis +{ + public class INIReadOnlyTweak : ITweak, ITweakInfo + { + public string Description => "This option will make all *.ini files read-only immediately.\nEnable this if your settings get reverted."; + + public string AffectedFiles => @"%UserProfile%\Documents\My Games\Fallout 76\*.ini"; + + public string AffectedValues => ""; + + public bool DefaultValue => false; + + public string Identifier => this.GetType().FullName; + + public bool GetValue() + { + return IniFiles.AreINIsReadOnly(); + } + + public void SetValue(bool value) + { + IniFiles.SetINIsReadOnly(value); + } + + public void ResetValue() + { + SetValue(DefaultValue); + } + } +} diff --git a/Fo76ini/Tweaks/Interface/ActiveEffectsOnHUDTweak.cs b/Fo76ini/Tweaks/Interface/ActiveEffectsOnHUDTweak.cs new file mode 100644 index 0000000..7409ce4 --- /dev/null +++ b/Fo76ini/Tweaks/Interface/ActiveEffectsOnHUDTweak.cs @@ -0,0 +1,58 @@ +using Fo76ini.Utilities; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Fo76ini.Tweaks.Interface +{ + public enum ActiveEffectsOnHUD + { + Disabled = 0, + Detrimental = 1, + All = 2 + } + + class ActiveEffectsOnHUDTweak : ITweak, ITweakInfo, IEnumTweak + { + public string Description => ""; + + public string AffectedFiles => "Fallout76Prefs.ini"; + + public string AffectedValues => "[Interface]uHUDActiveEffectWidget"; + + public ActiveEffectsOnHUD DefaultValue => ActiveEffectsOnHUD.All; + + public string Identifier => this.GetType().FullName; + + // https://stackoverflow.com/a/16946496 + public int Count => Enum.GetNames(typeof(ActiveEffectsOnHUD)).Length; + + public ActiveEffectsOnHUD GetValue() + { + int val = IniFiles.GetInt("Interface", "uHUDActiveEffectWidget", (int)DefaultValue); + return (ActiveEffectsOnHUD)(Utils.Clamp(val, 0, 2)); + } + + public void SetValue(ActiveEffectsOnHUD value) + { + IniFiles.F76Prefs.Set("Interface", "uHUDActiveEffectWidget", (int)value); + } + + public void ResetValue() + { + SetValue(DefaultValue); + } + + public int GetInt() + { + return (int)GetValue(); + } + + public void SetInt(int value) + { + SetValue((ActiveEffectsOnHUD)value); + } + } +} diff --git a/Fo76ini/Tweaks/Interface/AutoTrackQuestWhenStartedTweak.cs b/Fo76ini/Tweaks/Interface/AutoTrackQuestWhenStartedTweak.cs new file mode 100644 index 0000000..9851841 --- /dev/null +++ b/Fo76ini/Tweaks/Interface/AutoTrackQuestWhenStartedTweak.cs @@ -0,0 +1,60 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Fo76ini.Tweaks.Interface +{ + class AutoTrackQuestWhenStartedTweak : ITweak, ITweakInfo + { + public AutoTrackQuestWhenStartedTweak(string keyPrefix, string questType) + { + this.KeyPrefix = keyPrefix; + this.QuestType = questType; + + // Determine default value: + switch (this.KeyPrefix) + { + case "Main": + case "Side": + case "Misc": + case "Event": + this.DefaultValue = true; + break; + case "Other": + default: + this.DefaultValue = false; + break; + } + } + + private string KeyPrefix; + private string QuestType; + + public string Description => $"If enabled, automatically tracks newly added '{this.QuestType}' quests."; + + public string AffectedFiles => "Fallout76Prefs.ini"; + + public string AffectedValues => $"[MAIN]bEnableQuestAutoTrack{this.KeyPrefix}"; + + public bool DefaultValue { get; } + + public string Identifier => this.GetType().FullName + "+" + this.KeyPrefix; + + public bool GetValue() + { + return IniFiles.GetBool("MAIN", $"bEnableQuestAutoTrack{this.KeyPrefix}", DefaultValue); + } + + public void SetValue(bool value) + { + IniFiles.F76Prefs.Set("MAIN", $"bEnableQuestAutoTrack{this.KeyPrefix}", value); + } + + public void ResetValue() + { + SetValue(DefaultValue); + } + } +} diff --git a/Fo76ini/Tweaks/Interface/ConversationHistorySizeTweak.cs b/Fo76ini/Tweaks/Interface/ConversationHistorySizeTweak.cs new file mode 100644 index 0000000..99148df --- /dev/null +++ b/Fo76ini/Tweaks/Interface/ConversationHistorySizeTweak.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Fo76ini.Tweaks.Interface +{ + class ConversationHistorySizeTweak : ITweak, ITweakInfo + { + public string Description => ""; + + public string AffectedFiles => "Fallout76Prefs.ini"; + + public string AffectedValues => "[Display]fConversationHistorySize"; + + public float DefaultValue => 4.0f; + + public string Identifier => this.GetType().FullName; + + public float GetValue() + { + return IniFiles.GetFloat("Display", "fConversationHistorySize", DefaultValue); + } + + public void SetValue(float value) + { + IniFiles.F76Prefs.Set("Display", "fConversationHistorySize", value); + } + + public void ResetValue() + { + SetValue(DefaultValue); + } + } +} diff --git a/Fo76ini/Tweaks/Interface/DialogueSubtitlesTweak.cs b/Fo76ini/Tweaks/Interface/DialogueSubtitlesTweak.cs new file mode 100644 index 0000000..e96a552 --- /dev/null +++ b/Fo76ini/Tweaks/Interface/DialogueSubtitlesTweak.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Fo76ini.Tweaks.Interface +{ + class DialogueSubtitlesTweak : ITweak, ITweakInfo + { + public string Description => ""; + + public string AffectedFiles => "Fallout76Prefs.ini"; + + public string AffectedValues => "[Interface]bDialogueSubtitles"; + + public bool DefaultValue => false; + + public string Identifier => this.GetType().FullName; + + public bool GetValue() + { + return IniFiles.GetBool("Interface", "bDialogueSubtitles", DefaultValue); + } + + public void SetValue(bool value) + { + IniFiles.F76Prefs.Set("Interface", "bDialogueSubtitles", value); + } + + public void ResetValue() + { + SetValue(DefaultValue); + } + } +} \ No newline at end of file diff --git a/Fo76ini/Tweaks/Interface/EnableItemRarityColorsTweak.cs b/Fo76ini/Tweaks/Interface/EnableItemRarityColorsTweak.cs new file mode 100644 index 0000000..0146976 --- /dev/null +++ b/Fo76ini/Tweaks/Interface/EnableItemRarityColorsTweak.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Fo76ini.Tweaks.Interface +{ + class EnableItemRarityColorsTweak : ITweak, ITweakInfo + { + public string Description => ""; + + public string AffectedFiles => "Fallout76Prefs.ini"; + + public string AffectedValues => "[NuclearWinter]bEnableItemRarityColors"; + + public bool DefaultValue => true; + + public string Identifier => this.GetType().FullName; + + public bool GetValue() + { + return IniFiles.GetBool("NuclearWinter", "bEnableItemRarityColors", DefaultValue); + } + + public void SetValue(bool value) + { + IniFiles.F76Prefs.Set("NuclearWinter", "bEnableItemRarityColors", value); + } + + public void ResetValue() + { + SetValue(DefaultValue); + } + } +} diff --git a/Fo76ini/Tweaks/Interface/EnablePowerArmorHUDTweak.cs b/Fo76ini/Tweaks/Interface/EnablePowerArmorHUDTweak.cs new file mode 100644 index 0000000..ed2f5c4 --- /dev/null +++ b/Fo76ini/Tweaks/Interface/EnablePowerArmorHUDTweak.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Fo76ini.Tweaks.Interface +{ + class EnablePowerArmorHUDTweak : ITweak, ITweakInfo + { + public string Description => ""; + + public string AffectedFiles => "Fallout76Prefs.ini"; + + public string AffectedValues => "[MAIN]bEnablePowerArmorHUD"; + + public bool DefaultValue => true; + + public string Identifier => this.GetType().FullName; + + public bool GetValue() + { + return IniFiles.GetBool("MAIN", "bEnablePowerArmorHUD", DefaultValue); + } + + public void SetValue(bool value) + { + IniFiles.F76Prefs.Set("MAIN", "bEnablePowerArmorHUD", value); + } + + public void ResetValue() + { + SetValue(DefaultValue); + } + } +} diff --git a/Fo76ini/Tweaks/Interface/FixHUD4to3RatioTweak.cs b/Fo76ini/Tweaks/Interface/FixHUD4to3RatioTweak.cs new file mode 100644 index 0000000..a18a3f5 --- /dev/null +++ b/Fo76ini/Tweaks/Interface/FixHUD4to3RatioTweak.cs @@ -0,0 +1,63 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Fo76ini.Tweaks.Interface +{ + class FixHUD4to3RatioTweak : ITweak, ITweakInfo + { + public string Description => String.Join( + Environment.NewLine, + "Fixes hidden / borked", + " • lock picking screen and", + " • Power Armor HUD", + "for 5:4 and 4:3 screens.", + "", + "⚠️ Mostly untested."); + + public string AffectedFiles => "Fallout76Custom.ini"; + + public string AffectedValues => String.Join( + Environment.NewLine, + "", + " [Interface]fLockPositionY", + " [Interface]fUIPowerArmorGeometry_TranslateZ", + " [Interface]fUIPowerArmorGeometry_TranslateY", + ""); + + public bool DefaultValue => false; + + public string Identifier => this.GetType().FullName; + + public bool GetValue() + { + return + Math.Abs(IniFiles.GetFloat("Interface", "fLockPositionY", 0f) - 100f) < 0.1 && + Math.Abs(IniFiles.GetFloat("Interface", "fUIPowerArmorGeometry_TranslateZ", 0f) - -18.5f) < 0.1 && + Math.Abs(IniFiles.GetFloat("Interface", "fUIPowerArmorGeometry_TranslateY", 0f) - 460f) < 0.1; + } + + public void SetValue(bool value) + { + if (value) + { + IniFiles.F76Custom.Set("Interface", "fLockPositionY", 100f); + IniFiles.F76Custom.Set("Interface", "fUIPowerArmorGeometry_TranslateZ", -18.5f); + IniFiles.F76Custom.Set("Interface", "fUIPowerArmorGeometry_TranslateY", 460f); + } + else + { + IniFiles.F76Custom.Remove("Interface", "fLockPositionY"); + IniFiles.F76Custom.Remove("Interface", "fUIPowerArmorGeometry_TranslateZ"); + IniFiles.F76Custom.Remove("Interface", "fUIPowerArmorGeometry_TranslateY"); + } + } + + public void ResetValue() + { + SetValue(DefaultValue); + } + } +} diff --git a/Fo76ini/Tweaks/Interface/FloatingQuestMarkersDistanceTweak.cs b/Fo76ini/Tweaks/Interface/FloatingQuestMarkersDistanceTweak.cs new file mode 100644 index 0000000..4466713 --- /dev/null +++ b/Fo76ini/Tweaks/Interface/FloatingQuestMarkersDistanceTweak.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Fo76ini.Tweaks.Interface +{ + class FloatingQuestMarkersDistanceTweak : ITweak, ITweakInfo + { + public string Description => ""; + + public string AffectedFiles => "Fallout76Prefs.ini"; + + public string AffectedValues => "[GamePlay]fFloatingQuestMarkersDistance"; + + public float DefaultValue => 100.0f; + + public string Identifier => this.GetType().FullName; + + public float GetValue() + { + return IniFiles.GetFloat("GamePlay", "fFloatingQuestMarkersDistance", DefaultValue); + } + + public void SetValue(float value) + { + IniFiles.F76Prefs.Set("GamePlay", "fFloatingQuestMarkersDistance", value); + } + + public void ResetValue() + { + SetValue(DefaultValue); + } + } +} diff --git a/Fo76ini/Tweaks/Interface/GeneralSubtitlesTweak.cs b/Fo76ini/Tweaks/Interface/GeneralSubtitlesTweak.cs new file mode 100644 index 0000000..20f531d --- /dev/null +++ b/Fo76ini/Tweaks/Interface/GeneralSubtitlesTweak.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Fo76ini.Tweaks.Interface +{ + class GeneralSubtitlesTweak : ITweak, ITweakInfo + { + public string Description => ""; + + public string AffectedFiles => "Fallout76Prefs.ini"; + + public string AffectedValues => "[Interface]bGeneralSubtitles"; + + public bool DefaultValue => false; + + public string Identifier => this.GetType().FullName; + + public bool GetValue() + { + return IniFiles.GetBool("Interface", "bGeneralSubtitles", DefaultValue); + } + + public void SetValue(bool value) + { + IniFiles.F76Prefs.Set("Interface", "bGeneralSubtitles", value); + } + + public void ResetValue() + { + SetValue(DefaultValue); + } + } +} diff --git a/Fo76ini/Tweaks/Interface/HUDOpacityTweak.cs b/Fo76ini/Tweaks/Interface/HUDOpacityTweak.cs new file mode 100644 index 0000000..5b268f9 --- /dev/null +++ b/Fo76ini/Tweaks/Interface/HUDOpacityTweak.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Fo76ini.Tweaks.Interface +{ + class HUDOpacityTweak : ITweak, ITweakInfo + { + public string Description => ""; + + public string AffectedFiles => "Fallout76Prefs.ini"; + + public string AffectedValues => "[MAIN]fHUDOpacity"; + + public float DefaultValue => 1.0f; + + public string Identifier => this.GetType().FullName; + + public float GetValue() + { + return IniFiles.GetFloat("MAIN", "fHUDOpacity", DefaultValue); + } + + public void SetValue(float value) + { + IniFiles.F76Prefs.Set("MAIN", "fHUDOpacity", value); + } + + public void ResetValue() + { + SetValue(DefaultValue); + } + } +} diff --git a/Fo76ini/Tweaks/Interface/ShowCompassTweak.cs b/Fo76ini/Tweaks/Interface/ShowCompassTweak.cs new file mode 100644 index 0000000..3fb5b48 --- /dev/null +++ b/Fo76ini/Tweaks/Interface/ShowCompassTweak.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Fo76ini.Tweaks.Interface +{ + class ShowCompassTweak : ITweak, ITweakInfo + { + public string Description => ""; + + public string AffectedFiles => "Fallout76Prefs.ini"; + + public string AffectedValues => "[Interface]bShowCompass"; + + public bool DefaultValue => true; + + public string Identifier => this.GetType().FullName; + + public bool GetValue() + { + return IniFiles.GetBool("Interface", "bShowCompass", DefaultValue); + } + + public void SetValue(bool value) + { + IniFiles.F76Prefs.Set("Interface", "bShowCompass", value); + } + + public void ResetValue() + { + SetValue(DefaultValue); + } + } +} diff --git a/Fo76ini/Tweaks/Interface/ShowCrosshairTweak.cs b/Fo76ini/Tweaks/Interface/ShowCrosshairTweak.cs new file mode 100644 index 0000000..f93a177 --- /dev/null +++ b/Fo76ini/Tweaks/Interface/ShowCrosshairTweak.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Fo76ini.Tweaks.Interface +{ + class ShowCrosshairTweak : ITweak, ITweakInfo + { + public string Description => ""; + + public string AffectedFiles => "Fallout76Prefs.ini"; + + public string AffectedValues => "[MAIN]bCrosshairEnabled"; + + public bool DefaultValue => true; + + public string Identifier => this.GetType().FullName; + + public bool GetValue() + { + return IniFiles.GetBool("MAIN", "bCrosshairEnabled", DefaultValue); + } + + public void SetValue(bool value) + { + IniFiles.F76Prefs.Set("MAIN", "bCrosshairEnabled", value); + } + + public void ResetValue() + { + SetValue(DefaultValue); + } + } +} diff --git a/Fo76ini/Tweaks/Interface/ShowDamageNumbersAdventureTweak.cs b/Fo76ini/Tweaks/Interface/ShowDamageNumbersAdventureTweak.cs new file mode 100644 index 0000000..2e15521 --- /dev/null +++ b/Fo76ini/Tweaks/Interface/ShowDamageNumbersAdventureTweak.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Fo76ini.Tweaks.Interface +{ + class ShowDamageNumbersAdventureTweak : ITweak, ITweakInfo + { + public string Description => ""; + + public string AffectedFiles => "Fallout76Prefs.ini"; + + public string AffectedValues => "[Adventure]bShowDamageNumbers"; + + public bool DefaultValue => false; + + public string Identifier => this.GetType().FullName; + + public bool GetValue() + { + return IniFiles.GetBool("Adventure", "bShowDamageNumbers", DefaultValue); + } + + public void SetValue(bool value) + { + IniFiles.F76Prefs.Set("Adventure", "bShowDamageNumbers", value); + } + + public void ResetValue() + { + SetValue(DefaultValue); + } + } +} diff --git a/Fo76ini/Tweaks/Interface/ShowDamageNumbersNuclearWinterTweak.cs b/Fo76ini/Tweaks/Interface/ShowDamageNumbersNuclearWinterTweak.cs new file mode 100644 index 0000000..48d1616 --- /dev/null +++ b/Fo76ini/Tweaks/Interface/ShowDamageNumbersNuclearWinterTweak.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Fo76ini.Tweaks.Interface +{ + class ShowDamageNumbersNuclearWinterTweak : ITweak, ITweakInfo + { + public string Description => ""; + + public string AffectedFiles => "Fallout76Prefs.ini"; + + public string AffectedValues => "[NuclearWinter]bShowDamageNumbers"; + + public bool DefaultValue => true; + + public string Identifier => this.GetType().FullName; + + public bool GetValue() + { + return IniFiles.GetBool("NuclearWinter", "bShowDamageNumbers", DefaultValue); + } + + public void SetValue(bool value) + { + IniFiles.F76Prefs.Set("NuclearWinter", "bShowDamageNumbers", value); + } + + public void ResetValue() + { + SetValue(DefaultValue); + } + } +} diff --git a/Fo76ini/Tweaks/Interface/ShowDialogueHistoryTweak.cs b/Fo76ini/Tweaks/Interface/ShowDialogueHistoryTweak.cs new file mode 100644 index 0000000..b0e730b --- /dev/null +++ b/Fo76ini/Tweaks/Interface/ShowDialogueHistoryTweak.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Fo76ini.Tweaks.Interface +{ + class ShowDialogueHistoryTweak : ITweak, ITweakInfo + { + public string Description => ""; + + public string AffectedFiles => "Fallout76Prefs.ini"; + + public string AffectedValues => "[MAIN]bShowDialogueHistory"; + + public bool DefaultValue => false; + + public string Identifier => this.GetType().FullName; + + public bool GetValue() + { + return IniFiles.GetBool("MAIN", "bShowDialogueHistory", DefaultValue); + } + + public void SetValue(bool value) + { + IniFiles.F76Prefs.Set("MAIN", "bShowDialogueHistory", value); + } + + public void ResetValue() + { + SetValue(DefaultValue); + } + } +} \ No newline at end of file diff --git a/Fo76ini/Tweaks/Interface/ShowFloatingQuestMarkersTweak.cs b/Fo76ini/Tweaks/Interface/ShowFloatingQuestMarkersTweak.cs new file mode 100644 index 0000000..6e2acc1 --- /dev/null +++ b/Fo76ini/Tweaks/Interface/ShowFloatingQuestMarkersTweak.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Fo76ini.Tweaks.Interface +{ + class ShowFloatingQuestMarkersTweak : ITweak, ITweakInfo + { + public string Description => ""; + + public string AffectedFiles => "Fallout76Prefs.ini"; + + public string AffectedValues => "[GamePlay]bShowFloatingQuestMarkers"; + + public bool DefaultValue => true; + + public string Identifier => this.GetType().FullName; + + public bool GetValue() + { + return IniFiles.GetBool("GamePlay", "bShowFloatingQuestMarkers", DefaultValue); + } + + public void SetValue(bool value) + { + IniFiles.F76Prefs.Set("GamePlay", "bShowFloatingQuestMarkers", value); + } + + public void ResetValue() + { + SetValue(DefaultValue); + } + } +} diff --git a/Fo76ini/Tweaks/Interface/ShowFloatingQuestTextTweak.cs b/Fo76ini/Tweaks/Interface/ShowFloatingQuestTextTweak.cs new file mode 100644 index 0000000..df9a95f --- /dev/null +++ b/Fo76ini/Tweaks/Interface/ShowFloatingQuestTextTweak.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Fo76ini.Tweaks.Interface +{ + class ShowFloatingQuestTextTweak : ITweak, ITweakInfo + { + public string Description => ""; + + public string AffectedFiles => "Fallout76Prefs.ini"; + + public string AffectedValues => "[GamePlay]bShowFloatingQuestText"; + + public bool DefaultValue => true; + + public string Identifier => this.GetType().FullName; + + public bool GetValue() + { + return IniFiles.GetBool("GamePlay", "bShowFloatingQuestText", DefaultValue); + } + + public void SetValue(bool value) + { + IniFiles.F76Prefs.Set("GamePlay", "bShowFloatingQuestText", value); + } + + public void ResetValue() + { + SetValue(DefaultValue); + } + } +} diff --git a/Fo76ini/Tweaks/Interface/ShowOtherPlayersNamesTweak.cs b/Fo76ini/Tweaks/Interface/ShowOtherPlayersNamesTweak.cs new file mode 100644 index 0000000..bf1e3b9 --- /dev/null +++ b/Fo76ini/Tweaks/Interface/ShowOtherPlayersNamesTweak.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Fo76ini.Tweaks.Interface +{ + class ShowOtherPlayersNamesTweak : ITweak, ITweakInfo + { + public string Description => ""; + + public string AffectedFiles => "Fallout76Prefs.ini"; + + public string AffectedValues => "[Display]bShowOtherPlayersNames"; + + public bool DefaultValue => true; + + public string Identifier => this.GetType().FullName; + + public bool GetValue() + { + return IniFiles.GetBool("Display", "bShowOtherPlayersNames", DefaultValue); + } + + public void SetValue(bool value) + { + IniFiles.F76Prefs.Set("Display", "bShowOtherPlayersNames", value); + } + + public void ResetValue() + { + SetValue(DefaultValue); + } + } +} diff --git a/Fo76ini/Tweaks/Interface/ShowPublicTeamNotificationsTweak.cs b/Fo76ini/Tweaks/Interface/ShowPublicTeamNotificationsTweak.cs new file mode 100644 index 0000000..d2849ba --- /dev/null +++ b/Fo76ini/Tweaks/Interface/ShowPublicTeamNotificationsTweak.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Fo76ini.Tweaks.Interface +{ + class ShowPublicTeamNotificationsTweak : ITweak, ITweakInfo + { + public string Description => ""; + + public string AffectedFiles => "Fallout76Prefs.ini"; + + public string AffectedValues => "[GamePlay]bShowPublicTeamNotifications"; + + public bool DefaultValue => true; + + public string Identifier => this.GetType().FullName; + + public bool GetValue() + { + return IniFiles.GetBool("GamePlay", "bShowPublicTeamNotifications", DefaultValue); + } + + public void SetValue(bool value) + { + IniFiles.F76Prefs.Set("GamePlay", "bShowPublicTeamNotifications", value); + } + + public void ResetValue() + { + SetValue(DefaultValue); + } + } +} diff --git a/Fo76ini/Tweaks/LinkedTweaks.cs b/Fo76ini/Tweaks/LinkedTweaks.cs new file mode 100644 index 0000000..689a64c --- /dev/null +++ b/Fo76ini/Tweaks/LinkedTweaks.cs @@ -0,0 +1,329 @@ +using Fo76ini.Forms.Form1; +using Fo76ini.Tweaks.Video; +using Fo76ini.Utilities; +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Windows.Forms; +using System.Xml.Linq; + +namespace Fo76ini.Tweaks +{ + /// + /// Links tweaks to control elements. Initializes them. + /// + public static class LinkedTweaks + { + private struct LinkedControl + { + public Control Control; + public ToolTip Tip; + } + + private static Dictionary LinkedTweakInfos = new Dictionary(); + public static Dictionary TranslatedDescriptions = new Dictionary(); + private static List SetValueActions = new List(); + + /// + /// Gets a list of names of control elements that have been linked to a tweak info. + /// + public static List GetListOfLinkedControlNames() + { + return LinkedTweakInfos.Keys + .Select(x => x.Control.Name) + .Where(x => x != "") + .ToList(); + } + + /// + /// (Re)sets all control values. + /// + public static void LoadValues() + { + foreach (Action action in SetValueActions) + action(); + } + + public static string BuildToolTipText(string description, string affectedFiles, string affectedValues) + { + string toolTipText = ""; + + if (description != null && description != "") + toolTipText += description; + + if ((description != null && description != "") && (affectedFiles != null && affectedFiles != "")) + toolTipText += "\n\n"; + + if (affectedValues != null && affectedValues != "") + toolTipText += Localization.GetString("affectedValues") + ": " + affectedValues; + + if ((affectedValues != null && affectedValues != "") && (affectedFiles != null && affectedFiles != "")) + toolTipText += "\n"; + + if (affectedFiles != null && affectedFiles != "") + toolTipText += Localization.GetString("affectedFiles") + ": " + affectedFiles; + + return toolTipText; + } + + private static void SetToolTip(ITweakInfo info, LinkedControl linkedControl) + { + string description = info.Description; + TranslatedDescriptions.TryGetValue(info.Identifier, out description); + linkedControl.Tip.SetToolTip(linkedControl.Control, BuildToolTipText(description, info.AffectedFiles, info.AffectedValues)); + } + + public static void SetToolTips() + { + foreach (var pair in LinkedTweakInfos) + SetToolTip(pair.Value, pair.Key); + } + + /// + /// Link a tweak to a control's tooltip. + /// + /// + /// + public static void LinkInfo(Control control, ToolTip tip, ITweakInfo tweakInfo) + { + LinkedControl linkedControl = new LinkedControl(); + linkedControl.Control = control; + linkedControl.Tip = tip; + LinkedTweakInfos.Add(linkedControl, tweakInfo); + + if (!TranslatedDescriptions.ContainsKey(tweakInfo.Identifier)) + TranslatedDescriptions[tweakInfo.Identifier] = tweakInfo.Description; + } + + public static XElement SerializeTweakDescriptionList() + { + XElement parent = new XElement("TweakDescriptions"); + foreach (var pair in TranslatedDescriptions) + if (pair.Value != "") + parent.Add(new XElement("Description", new XAttribute("id", pair.Key), pair.Value)); + return parent; + } + + public static void DeserializeTweakDescriptionList(XElement xmlDescriptionList) + { + foreach (XElement xmlDescription in xmlDescriptionList.Descendants("Description")) + { + string id = xmlDescription.Attribute("id").Value; + string desc = xmlDescription.Value; + TranslatedDescriptions[id] = desc; + } + } + + + /* + ************************************************************** + * Link control elements together + ************************************************************** + */ + + // Link slider to num and vice-versa + + public static void LinkSlider(TrackBar slider, NumericUpDown num, double numToSliderRatio) + { + LinkSlider(slider, num, numToSliderRatio, false); + } + + /// + /// Links the value of a TrackBar to a value of NumericUpDown and vice-versa. + /// Whenever the value of one changes, the other gets changed too. + /// + /// + /// + /// Because Trackbar can only have integers, you can use numToSliderRatio to work around it. slider.Value gets multiplied by numToSliderRatio and num.Value gets divided by numToSliderRatio. + /// Whether slider.Maximum should correlate with the minimum and vice-versa. + public static void LinkSlider(TrackBar slider, NumericUpDown num, double numToSliderRatio, bool reversed) + { + if (!reversed) + { + slider.ValueChanged += (object sender, EventArgs e) => num.Value = Convert.ToDecimal(slider.Value / numToSliderRatio); + num.ValueChanged += (object sender, EventArgs e) => slider.Value = Utils.Clamp(Convert.ToInt32(Convert.ToDouble(num.Value) * numToSliderRatio), slider.Minimum, slider.Maximum); + } + else + { + slider.ValueChanged += (object sender, EventArgs e) => num.Value = Convert.ToDecimal((slider.Maximum - slider.Value) / numToSliderRatio); + num.ValueChanged += (object sender, EventArgs e) => slider.Value = Utils.Clamp(Convert.ToInt32(slider.Maximum - Convert.ToDouble(num.Value) * numToSliderRatio), slider.Minimum, slider.Maximum); + } + } + + + /* + ************************************************************** + * Link *.ini tweaks to control elements + ************************************************************** + */ + + public static void LinkTweak(CheckBox checkBox, ITweak tweak) + { + SetValueActions.Add(() => checkBox.Checked = tweak.GetValue()); + checkBox.MouseClick += (object sender, MouseEventArgs e) => tweak.SetValue(checkBox.Checked); + } + + public static void LinkTweakNegated(CheckBox checkBox, ITweak tweak) + { + SetValueActions.Add(() => checkBox.Checked = !tweak.GetValue()); + checkBox.MouseClick += (object sender, MouseEventArgs e) => tweak.SetValue(!checkBox.Checked); + } + + public static void LinkTweak(RadioButton radioButtonTrue, RadioButton radioButtonFalse, ITweak tweak) + { + SetValueActions.Add(() => + { + if (tweak.GetValue()) + radioButtonTrue.Checked = true; + else + radioButtonFalse.Checked = true; + }); + radioButtonTrue.MouseClick += (object sender, MouseEventArgs e) => + { + if (radioButtonTrue.Checked) + tweak.SetValue(true); + }; + radioButtonFalse.MouseClick += (object sender, MouseEventArgs e) => + { + if (radioButtonFalse.Checked) + tweak.SetValue(false); + }; + } + + // TODO: This needs to be refined: + public static void LinkTweak(Dictionary radioButtons, ITweak tweak) + { + SetValueActions.Add(() => + { + RadioButton radioButton; + if (radioButtons.TryGetValue(tweak.GetValue(), out radioButton)) + radioButton.Checked = true; + }); + + // I have a really bad feeling about this: + foreach (var pair in radioButtons) + { + pair.Value.MouseClick += (object sender, MouseEventArgs e) => + { + if (pair.Value.Checked) + tweak.SetValue(pair.Key); + }; + } + } + + // TODO: This needs to be refined: + public static void LinkTweak(ComboBox comboBox, T[] associatedValues, ITweak tweak) + { + // TODO: This could potentially crash the tool on load: + if (comboBox.Items.Count != associatedValues.Length) + throw new ArgumentException("LinkTweak: comboBox has to have as many items as associatedValues has!"); + + SetValueActions.Add(() => + { + int index = Array.IndexOf(associatedValues, tweak.GetValue()); + int defaultIndex = Array.IndexOf(associatedValues, tweak.DefaultValue); + if (index > -1) + comboBox.SelectedIndex = index; + else if (defaultIndex > -1) + comboBox.SelectedIndex = defaultIndex; + else + throw new ArgumentException("LinkTweak: Couldn't assign a value to comboBox."); + }); + + comboBox.SelectionChangeCommitted += (object sender, EventArgs e) => + { + tweak.SetValue(associatedValues[comboBox.SelectedIndex]); + }; + } + + public static void LinkTweak(ComboBox comboBox, ITweak tweak) + { + SetValueActions.Add(() => comboBox.SelectedIndex = tweak.GetValue()); + comboBox.SelectionChangeCommitted += (object sender, EventArgs e) => tweak.SetValue(comboBox.SelectedIndex); + } + + public static void LinkTweak(ComboBox comboBox, IEnumTweak tweak) + { + SetValueActions.Add(() => comboBox.SelectedIndex = tweak.GetInt()); + comboBox.SelectionChangeCommitted += (object sender, EventArgs e) => tweak.SetInt(comboBox.SelectedIndex); + } + + public static void LinkTweak(NumericUpDown num, ITweak tweak) + { + SetValueActions.Add(() => num.Value = Utils.Clamp(tweak.GetValue(), Convert.ToInt32(num.Minimum), Convert.ToInt32(num.Maximum))); + num.ValueChanged += (object sender, EventArgs e) => tweak.SetValue(Convert.ToInt32(num.Value)); + } + + public static void LinkTweak(NumericUpDown num, ITweak tweak) + { + SetValueActions.Add(() => num.Value = Convert.ToDecimal(Utils.Clamp(tweak.GetValue(), Convert.ToSingle(num.Minimum), Convert.ToSingle(num.Maximum)))); + num.ValueChanged += (object sender, EventArgs e) => tweak.SetValue(Convert.ToSingle(num.Value)); + } + + public static void LinkTweak(TrackBar slider, ITweak tweak) + { + SetValueActions.Add(() => slider.Value = Utils.Clamp(tweak.GetValue(), Convert.ToInt32(slider.Minimum), Convert.ToInt32(slider.Maximum))); + slider.ValueChanged += (object sender, EventArgs e) => tweak.SetValue(slider.Value); + } + + public static void LinkTweak(TextBox textBox, ITweak tweak) + { + SetValueActions.Add(() => textBox.Text = tweak.GetValue()); + textBox.TextChanged += (object sender, EventArgs e) => tweak.SetValue(textBox.Text); + } + + /// + /// This is specific code for the Pipboy/Quickboy/Power armor color picker. + /// + /// This dialog opens when "Pick color" button has been clicked. + /// A picture box whose BackColor property gets set. + public static void LinkColor(Button pickColor, Button resetColor, ColorDialog colorDialog, ColorPreview preview, ITweak tweak) + { + SetValueActions.Add(() => preview.BackColor = tweak.GetValue()); + + preview.BackColorChanged += (object sender, EventArgs e) => + { + tweak.SetValue(preview.BackColor); + }; + + pickColor.Click += (object sender, EventArgs e) => + { + colorDialog.Color = tweak.GetValue(); + if (colorDialog.ShowDialog() == DialogResult.OK) + { + preview.BackColor = colorDialog.Color; + tweak.SetValue(colorDialog.Color); + } + }; + + resetColor.Click += (object sender, EventArgs e) => + { + tweak.ResetValue(); + preview.BackColor = tweak.GetValue(); + }; + } + + public static void LinkSize(NumericUpDown width, NumericUpDown height, ITweak tweak) + { + SetValueActions.Add(() => + { + Size size = tweak.GetValue(); + width.Value = size.Width; + height.Value = size.Height; + }); + + EventHandler sizeChanged = (object sender, EventArgs e) => + { + Size newSize = new Size( + Convert.ToInt32(width.Value), + Convert.ToInt32(height.Value) + ); + tweak.SetValue(newSize); + }; + + width.ValueChanged += sizeChanged; + height.ValueChanged += sizeChanged; + } + } +} diff --git a/Fo76ini/Tweaks/NuclearWinterMode/DeployModsOnNWModeTweak.cs b/Fo76ini/Tweaks/NuclearWinterMode/DeployModsOnNWModeTweak.cs new file mode 100644 index 0000000..fb49958 --- /dev/null +++ b/Fo76ini/Tweaks/NuclearWinterMode/DeployModsOnNWModeTweak.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Fo76ini.Tweaks.NuclearWinterMode +{ + class DeployModsOnNWModeTweak : ITweak, ITweakInfo + { + public string Identifier => this.GetType().FullName; + + public string Description => "If checked, mods will be deployed when the Nuclear Winter mode is disabled."; + + public string AffectedFiles => "config.ini"; + + public string AffectedValues => "[NuclearWinter]bAutoDeployMods"; + + public bool DefaultValue => true; + + public bool GetValue() + { + return IniFiles.Config.GetBool("NuclearWinter", "bAutoDeployMods", DefaultValue); + } + + public void SetValue(bool value) + { + IniFiles.Config.Set("NuclearWinter", "bAutoDeployMods", value); + } + + public void ResetValue() + { + IniFiles.Config.Set("NuclearWinter", "bAutoDeployMods", DefaultValue); + } + } +} diff --git a/Fo76ini/Tweaks/NuclearWinterMode/RemoveModsOnNWModeTweak.cs b/Fo76ini/Tweaks/NuclearWinterMode/RemoveModsOnNWModeTweak.cs new file mode 100644 index 0000000..264475c --- /dev/null +++ b/Fo76ini/Tweaks/NuclearWinterMode/RemoveModsOnNWModeTweak.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Fo76ini.Tweaks.NuclearWinterMode +{ + class RemoveModsOnNWModeTweak : ITweak, ITweakInfo + { + public string Identifier => this.GetType().FullName; + + public string Description => "If checked, mods will be removed when the Nuclear Winter mode is enabled."; + + public string AffectedFiles => "config.ini"; + + public string AffectedValues => "[NuclearWinter]bAutoDisableMods"; + + public bool DefaultValue => true; + + public bool GetValue() + { + return IniFiles.Config.GetBool("NuclearWinter", "bAutoDisableMods", DefaultValue); + } + + public void SetValue(bool value) + { + IniFiles.Config.Set("NuclearWinter", "bAutoDisableMods", value); + } + + public void ResetValue() + { + IniFiles.Config.Set("NuclearWinter", "bAutoDisableMods", DefaultValue); + } + } +} diff --git a/Fo76ini/Tweaks/NuclearWinterMode/RenameDLLsTweak.cs b/Fo76ini/Tweaks/NuclearWinterMode/RenameDLLsTweak.cs new file mode 100644 index 0000000..4840f7a --- /dev/null +++ b/Fo76ini/Tweaks/NuclearWinterMode/RenameDLLsTweak.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Fo76ini.Tweaks.NuclearWinterMode +{ + class RenameDLLsTweak : ITweak, ITweakInfo + { + public string Identifier => this.GetType().FullName; + + public string Description => "If checked, any *.dll files that don't belong to the game will be renamed."; + + public string AffectedFiles => "config.ini"; + + public string AffectedValues => "[NuclearWinter]bRenameDLLs"; + + public bool DefaultValue => true; + + public bool GetValue() + { + return IniFiles.Config.GetBool("NuclearWinter", "bRenameDLLs", DefaultValue); + } + + public void SetValue(bool value) + { + IniFiles.Config.Set("NuclearWinter", "bRenameDLLs", value); + } + + public void ResetValue() + { + IniFiles.Config.Set("NuclearWinter", "bRenameDLLs", DefaultValue); + } + } +} diff --git a/Fo76ini/Tweaks/Pipboy/PipboyTargetResolution.cs b/Fo76ini/Tweaks/Pipboy/PipboyTargetResolution.cs new file mode 100644 index 0000000..6d58e4a --- /dev/null +++ b/Fo76ini/Tweaks/Pipboy/PipboyTargetResolution.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Fo76ini.Tweaks.Pipboy +{ + class PipboyTargetResolutionTweak : ITweak, ITweakInfo + { + public string Description => ""; + + public string AffectedFiles => "Fallout76Prefs.ini"; + + public string AffectedValues => "[Display]uPipboyTargetWidth, uPipboyTargetHeight"; + + public Size DefaultValue => new Size(876, 700); + + public string Identifier => this.GetType().FullName; + + public Size GetValue() + { + int width = IniFiles.GetInt("Display", "uPipboyTargetWidth", DefaultValue.Width); + int height = IniFiles.GetInt("Display", "uPipboyTargetHeight", DefaultValue.Height); + return new Size(width, height); + } + + public void SetValue(Size value) + { + IniFiles.F76Prefs.Set("Display", "uPipboyTargetWidth", value.Width); + IniFiles.F76Prefs.Set("Display", "uPipboyTargetHeight", value.Height); + } + + public void ResetValue() + { + SetValue(DefaultValue); + } + } +} diff --git a/Fo76ini/Tweaks/Pipboy/QuickboyModeEnabledTweak.cs b/Fo76ini/Tweaks/Pipboy/QuickboyModeEnabledTweak.cs new file mode 100644 index 0000000..4083603 --- /dev/null +++ b/Fo76ini/Tweaks/Pipboy/QuickboyModeEnabledTweak.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Fo76ini.Tweaks.Pipboy +{ + class QuickboyModeEnabledTweak : ITweak, ITweakInfo + { + public string Description => ""; + + public string AffectedFiles => "Fallout76Prefs.ini"; + + public string AffectedValues => "[Pipboy]bQuickboyMode"; + + public bool DefaultValue => false; + + public string Identifier => this.GetType().FullName; + + public bool GetValue() + { + return IniFiles.GetBool("Pipboy", "bQuickboyMode", DefaultValue); + } + + public void SetValue(bool value) + { + IniFiles.F76Prefs.Set("Pipboy", "bQuickboyMode", value); + } + + public void ResetValue() + { + SetValue(DefaultValue); + } + } +} diff --git a/Fo76ini/Tweaks/ResourceLists/ResourceListTweak.cs b/Fo76ini/Tweaks/ResourceLists/ResourceListTweak.cs new file mode 100644 index 0000000..894c9c5 --- /dev/null +++ b/Fo76ini/Tweaks/ResourceLists/ResourceListTweak.cs @@ -0,0 +1,52 @@ +namespace Fo76ini.Tweaks.ResourceLists +{ + public class ResourceListTweak : ITweak, ITweakInfo + { + private string key; + + public ResourceListTweak(string key) + { + this.key = key; + } + + public static ResourceListTweak GetDefaultList() + { + return new ResourceListTweak("sResourceIndexFileList"); + } + + public static ResourceListTweak GetSResourceIndexFileList() + { + return new ResourceListTweak("sResourceIndexFileList"); + } + + public static ResourceListTweak GetSResourceArchive2List() + { + return new ResourceListTweak("sResourceArchive2List"); + } + + public string DefaultValue => ""; + + public string Description => "A string that contains resources, delimited by commas."; + + public string AffectedFiles => "Fallout76Custom.ini"; + + public string AffectedValues => key; + + public string Identifier => this.GetType().FullName; + + public string GetValue() + { + return IniFiles.F76Custom.GetString("Archive", key, DefaultValue); + } + + public void SetValue(string value) + { + IniFiles.F76Custom.Set("Archive", key, value); + } + + public void ResetValue() + { + IniFiles.F76Custom.Remove("Archive", key); + } + } +} diff --git a/Fo76ini/Tweaks/Video/DisplayModeTweak.cs b/Fo76ini/Tweaks/Video/DisplayModeTweak.cs new file mode 100644 index 0000000..6918357 --- /dev/null +++ b/Fo76ini/Tweaks/Video/DisplayModeTweak.cs @@ -0,0 +1,103 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Fo76ini.Tweaks.Video +{ + public enum DisplayMode + { + Fullscreen = 0, + Windowed = 1, + BorderlessWindowed = 2, + BorderlessFullscreen = 3 + } + + class DisplayModeTweak : ITweak, ITweakInfo, IEnumTweak + { + public string Description => String.Join( + Environment.NewLine, + "Changes the display mode.", + "", + "• Fullscreen: Real fullscreen mode (Best Performance)", + "• Windowed: Starts the game in a window with border (aka. window decoration).", + "• Borderless windowed: Allows you to painlessly Alt+Tab, but make sure the resolution matches your display's resolution. (Default)", + "• Borderless windowed (Fullscreen): Same as \"Borderless windowed\", but window will be maximized to fit your screen.", + "This will look pixelated, if the resolution is lower than your display, as it uses Nearest Neighbor to upscale it."); + + public string AffectedFiles => "Fallout76Prefs.ini"; + + public string AffectedValues => "[Display]bFull Screen, [Display]bBorderless, [Display]bMaximizeWindow"; + + public DisplayMode DefaultValue => DisplayMode.BorderlessWindowed; + + public string Identifier => this.GetType().FullName; + + // https://stackoverflow.com/a/16946496 + public int Count => Enum.GetNames(typeof(DisplayMode)).Length; + + public DisplayMode GetValue() + { + bool bFullScreen = IniFiles.GetBool("Display", "bFull Screen", false); + bool bBorderless = IniFiles.GetBool("Display", "bBorderless", true); + bool bMaximizeWindow = IniFiles.GetBool("Display", "bMaximizeWindow", false); + + if (bFullScreen) + return DisplayMode.Fullscreen; + else if (!bBorderless) + return DisplayMode.Windowed; + else if (bBorderless && !bMaximizeWindow) + return DisplayMode.BorderlessWindowed; + else + return DisplayMode.BorderlessFullscreen; + } + + public void SetValue(DisplayMode value) + { + bool bFullScreen, bBorderless, bMaximizeWindow; + switch (value) + { + case DisplayMode.Fullscreen: + bBorderless = true; + bFullScreen = true; + bMaximizeWindow = false; + break; + case DisplayMode.Windowed: + bBorderless = false; + bFullScreen = false; + bMaximizeWindow = false; + break; + case DisplayMode.BorderlessFullscreen: + bBorderless = true; + bFullScreen = false; + bMaximizeWindow = true; + break; + case DisplayMode.BorderlessWindowed: + default: + bBorderless = true; + bFullScreen = false; + bMaximizeWindow = false; + break; + } + IniFiles.F76Prefs.Set("Display", "bFull Screen", bFullScreen); + IniFiles.F76Prefs.Set("Display", "bBorderless", bBorderless); + IniFiles.F76Prefs.Set("Display", "bMaximizeWindow", bMaximizeWindow); + } + + public void ResetValue() + { + SetValue(DefaultValue); + } + + public int GetInt() + { + return (int)GetValue(); + } + + public void SetInt(int value) + { + SetValue((DisplayMode)value); + } + } +} diff --git a/Fo76ini/Tweaks/Video/DisplaySizeTweak.cs b/Fo76ini/Tweaks/Video/DisplaySizeTweak.cs new file mode 100644 index 0000000..c7517f9 --- /dev/null +++ b/Fo76ini/Tweaks/Video/DisplaySizeTweak.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Fo76ini.Tweaks.Video +{ + class DisplaySizeTweak : ITweak, ITweakInfo + { + public string Description => "Display resolution"; + + public string AffectedFiles => "Fallout76Prefs.ini"; + + public string AffectedValues => "[Display]iSize W, [Display]iSize H"; + + public Size DefaultValue => new Size(1920, 1080); + + public string Identifier => this.GetType().FullName; + + public Size GetValue() + { + int w = IniFiles.GetInt("Display", "iSize W", DefaultValue.Width); + int h = IniFiles.GetInt("Display", "iSize H", DefaultValue.Height); + return new Size(w, h); + } + + public void SetValue(Size value) + { + // TODO: Put iSizeW and iSizeH into Fallout76Custom.ini instead of Prefs.ini: https://www.reddit.com/r/fo76/comments/9z6jan/if_you_change_your_resolution_in/ + IniFiles.F76Prefs.Set("Display", "iSize W", value.Width); + IniFiles.F76Prefs.Set("Display", "iSize H", value.Height); + } + + public void ResetValue() + { + SetValue(DefaultValue); + } + } +} diff --git a/Fo76ini/Tweaks/Video/PresentIntervalTweak.cs b/Fo76ini/Tweaks/Video/PresentIntervalTweak.cs new file mode 100644 index 0000000..629f3f2 --- /dev/null +++ b/Fo76ini/Tweaks/Video/PresentIntervalTweak.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Fo76ini.Tweaks.Video +{ + // From what I've read on the interwebzz, this might not actually be VSync but a fps cap, which is determined this way: Monitor refresh rate divided by iPresentInterval + // A 120 Hz monitor and iPresentInterval set to 2 will result in a 60fps cap: 120Hz / 2 = 60 fps + // + // For some reason though, setting it to 2 or 3 causes a black screen or the game just flat out crashes to desktop. + // The majority links iPresentInterval directly to vertical synchronization. + // + // My question is this: If VSync is more like an on/off setting (like a boolean), why is iPresentInterval a signed integer then? Wouldn't "bPresentInterval" or "bVSync" be more reasonable? + // Just my two cents... + + class PresentIntervalTweak : ITweak, ITweakInfo + { + public string Description => String.Join( + Environment.NewLine, + "Disabling this will uncap the frame rate.", + "", + "• Enable this if you experience screen tearing.", + "• Disable this if you experience input lag.", + "", + "⚠️ Enabling this might NOT get rid of screen tearing.", + "⚠️ If you disable this, it is recommended to cap the game to 60 FPS manually. (e.g. using NVIDIA's Control Panel)", + "", + "ℹ️ Uncapped frame rate shouldn't make the physics go haywire like in older titles,", + "as this has been fixed by Bethesda quite a while ago (in 2018).", + "Capping it to 60 is recommended nonetheless."); + + public string AffectedFiles => "Fallout76Prefs.ini"; + + public string AffectedValues => "[Display]iPresentInterval"; + + public bool DefaultValue => true; + + public string Identifier => this.GetType().FullName; + + public bool GetValue() + { + int val = IniFiles.GetInt("Display", "iPresentInterval", DefaultValue ? 1 : 0); + return val > 0; + } + + public void SetValue(bool value) + { + IniFiles.F76Prefs.Set("Display", "iPresentInterval", value ? 1 : 0); + // TODO: IniFiles.F76Custom.Remove("Display", "iPresentInterval"); + } + + public void ResetValue() + { + SetValue(DefaultValue); + } + } +} diff --git a/Fo76ini/Tweaks/Video/TopMostWindowTweak.cs b/Fo76ini/Tweaks/Video/TopMostWindowTweak.cs new file mode 100644 index 0000000..7738f41 --- /dev/null +++ b/Fo76ini/Tweaks/Video/TopMostWindowTweak.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Fo76ini.Tweaks.Video +{ + class TopMostWindowTweak : ITweak, ITweakInfo + { + public string Description => + "Enabling this, will keep the game's window in the foreground.\n" + + "⚠️ This will prevent you from being able to Alt+Tab on single monitors."; + + public string AffectedFiles => "Fallout76Prefs.ini"; + + public string AffectedValues => "[Display]bTopMostWindow"; + + public bool DefaultValue => false; + + public string Identifier => this.GetType().FullName; + + public bool GetValue() + { + return IniFiles.GetBool("Display", "bTopMostWindow", DefaultValue); + } + + public void SetValue(bool value) + { + IniFiles.F76Prefs.Set("Display", "bTopMostWindow", value); + } + + public void ResetValue() + { + SetValue(DefaultValue); + } + } +} diff --git a/Fo76ini/Tweaks/Video/WindowAlwaysActiveTweak.cs b/Fo76ini/Tweaks/Video/WindowAlwaysActiveTweak.cs new file mode 100644 index 0000000..0e51ec1 --- /dev/null +++ b/Fo76ini/Tweaks/Video/WindowAlwaysActiveTweak.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Fo76ini.Tweaks.Video +{ + class WindowAlwaysActiveTweak : ITweak, ITweakInfo + { + public string Description => "Disable this, if you want the game to pause if another window is in front."; + + public string AffectedFiles => "Fallout76Custom.ini"; + + public string AffectedValues => "[Interface]bAlwaysActive"; + + public bool DefaultValue => true; + + public string Identifier => this.GetType().FullName; + + public bool GetValue() + { + return IniFiles.GetBool("Interface", "bAlwaysActive", DefaultValue); + } + + public void SetValue(bool value) + { + IniFiles.F76Custom.Set("Interface", "bAlwaysActive", value); + } + + public void ResetValue() + { + SetValue(DefaultValue); + } + } +} diff --git a/Fo76ini/Tweaks/Volume/AudioMenuValTweak.cs b/Fo76ini/Tweaks/Volume/AudioMenuValTweak.cs new file mode 100644 index 0000000..31929a7 --- /dev/null +++ b/Fo76ini/Tweaks/Volume/AudioMenuValTweak.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Fo76ini.Tweaks.Volume +{ + class AudioMenuValTweak : ITweak, ITweakInfo + { + public AudioMenuValTweak(string keySuffix, string soundFxName) + { + Suffix = keySuffix; + SoundFX = soundFxName; + } + + private string Suffix; + private string SoundFX; + + public string Description => $"Changes the volume of '{SoundFX}'"; + + public string AffectedFiles => "Fallout76Prefs.ini"; + + public string AffectedValues => $"[AudioMenu]fVal{Suffix}"; + + public float DefaultValue => 1.0f; + + public string Identifier => this.GetType().FullName + $"+fVal{Suffix}"; + + public float GetValue() + { + return IniFiles.GetFloat("AudioMenu", $"fVal{Suffix}", DefaultValue); + } + + public void SetValue(float value) + { + IniFiles.F76Prefs.Set("AudioMenu", $"fVal{Suffix}", value); + } + + public void ResetValue() + { + SetValue(DefaultValue); + } + } +} diff --git a/Fo76ini/Tweaks/Volume/MasterVolumeTweak.cs b/Fo76ini/Tweaks/Volume/MasterVolumeTweak.cs new file mode 100644 index 0000000..17a794f --- /dev/null +++ b/Fo76ini/Tweaks/Volume/MasterVolumeTweak.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Fo76ini.Tweaks.Volume +{ + class MasterVolumeTweak : ITweak, ITweakInfo + { + public string Description => ""; + + public string AffectedFiles => "Fallout76Prefs.ini"; + + public string AffectedValues => "[AudioMenu]fAudioMasterVolume"; + + public float DefaultValue => 1.0f; + + public string Identifier => this.GetType().FullName; + + public float GetValue() + { + return IniFiles.GetFloat("AudioMenu", "fAudioMasterVolume", DefaultValue); + } + + public void SetValue(float value) + { + IniFiles.F76Prefs.Set("AudioMenu", "fAudioMasterVolume", value); + } + + public void ResetValue() + { + SetValue(DefaultValue); + } + } +} diff --git a/Fo76ini/Tweaks/Volume/VivoxVoiceVolumeTweak.cs b/Fo76ini/Tweaks/Volume/VivoxVoiceVolumeTweak.cs new file mode 100644 index 0000000..685d2c4 --- /dev/null +++ b/Fo76ini/Tweaks/Volume/VivoxVoiceVolumeTweak.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Fo76ini.Tweaks.Volume +{ + class VivoxVoiceVolumeTweak : ITweak, ITweakInfo + { + public string Description => ""; + + public string AffectedFiles => "Fallout76Prefs.ini"; + + public string AffectedValues => "[Voice]uVivoxVoiceVolume"; + + public int DefaultValue => 100; + + public string Identifier => this.GetType().FullName; + + public int GetValue() + { + return IniFiles.GetInt("Voice", "uVivoxVoiceVolume", DefaultValue); + } + + public void SetValue(int value) + { + IniFiles.F76Prefs.Set("Voice", "uVivoxVoiceVolume", value); + } + + public void ResetValue() + { + SetValue(DefaultValue); + } + } +} diff --git a/Fo76ini/Mods/Archive2.cs b/Fo76ini/Utilities/Archive2.cs similarity index 70% rename from Fo76ini/Mods/Archive2.cs rename to Fo76ini/Utilities/Archive2.cs index 01230a5..d08673b 100644 --- a/Fo76ini/Mods/Archive2.cs +++ b/Fo76ini/Utilities/Archive2.cs @@ -1,26 +1,22 @@ using System; -using System.Collections.Generic; using System.Diagnostics; using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -namespace Fo76ini.Mods +namespace Fo76ini.Utilities { public class Archive2 { - public static Log logFile; - private static String archive2Path = ".\\Archive2\\Archive2.exe"; + public static Log LogFile; + private static string archive2Path = ".\\Archive2\\Archive2.exe"; - public static String Archive2Path + public static string Archive2Path { get { return Archive2.archive2Path; } } static Archive2() { - logFile = new Log(Log.GetFilePath("archive2.log.txt")); + LogFile = new Log(Log.GetFilePath("archive2.log.txt")); } public enum Compression @@ -44,7 +40,7 @@ public struct Preset public Archive2.Format format; } - public static Archive2.Compression GetCompression(String compressionStr) + public static Archive2.Compression GetCompression(string compressionStr) { switch (compressionStr) { @@ -59,7 +55,7 @@ public static Archive2.Compression GetCompression(String compressionStr) } } - public static Archive2.Format GetFormat(String formatStr) + public static Archive2.Format GetFormat(string formatStr) { switch (formatStr) { @@ -76,15 +72,15 @@ public static Archive2.Format GetFormat(String formatStr) } } - private static void Call(String arguments) + private static void Call(string arguments) { if (!Archive2.ValidatePath()) throw new Archive2Exception("Path to Archive2.exe not specified or Archive2.exe not found."); using (Process proc = new Process()) { - logFile.WriteTimeStamp(); - logFile.WriteLine($">> Archive2.exe {arguments}"); + LogFile.WriteTimeStamp(); + LogFile.WriteLine($">> Archive2.exe {arguments}"); proc.StartInfo.UseShellExecute = false; // = true proc.StartInfo.RedirectStandardOutput = true; // // ... proc.StartInfo.RedirectStandardError = true; // // ... @@ -94,13 +90,20 @@ private static void Call(String arguments) proc.Start(); //MessageBox.Show(/*proc.StandardOutput.ReadToEnd(), */$"Archive2.exe {arguments}"); - logFile.WriteLine(proc.StandardOutput.ReadToEnd()); - logFile.WriteLine(proc.StandardError.ReadToEnd()); + /*logFile.WriteLine(proc.StandardOutput.ReadToEnd()); + logFile.WriteLine(proc.StandardError.ReadToEnd());*/ + + string output = proc.StandardOutput.ReadToEnd() + "\n" + proc.StandardError.ReadToEnd(); + LogFile.WriteLine(output); proc.WaitForExit(); + + // System.IO.FileNotFoundException: Could not load file or assembly 'Archive2Interop.dll' + if (output.Contains("System.IO.FileNotFoundException:") && output.Contains("'Archive2Interop.dll'")) + throw new Archive2RequirementsException("System.IO.FileNotFoundException: Could not load file or assembly 'Archive2Interop.dll'. 'Visual C++ Redistributable for Visual Studio 2012 Update 4' is likely not installed."); } } - private static void CallParallel(String arguments) + private static void CallParallel(string arguments) { if (!Archive2.ValidatePath()) throw new Archive2Exception("Path to Archive2.exe not specified or Archive2.exe not found."); @@ -115,7 +118,7 @@ private static void CallParallel(String arguments) } } - public static void Extract(String ba2Archive, String outputFolder) + public static void Extract(string ba2Archive, string outputFolder) { Archive2.Call($"\"{ba2Archive}\" -extract=\"{outputFolder}\" -quiet"); @@ -125,7 +128,7 @@ public static void Extract(String ba2Archive, String outputFolder) throw new Archive2Exception("Extraction failed, folder is empty."); } - public static void Explore(String ba2Archive) + public static void Explore(string ba2Archive) { Archive2.CallParallel($"\"{ba2Archive}\""); } @@ -135,23 +138,23 @@ public static void Explore() Archive2.CallParallel(""); } - public static void Create(String ba2Archive, String folder) + public static void Create(string ba2Archive, string folder) { Archive2.Create(ba2Archive, folder, Archive2.Compression.Default, Archive2.Format.General); } - public static void Create(String ba2Archive, String folder, Archive2.Preset preset) + public static void Create(string ba2Archive, string folder, Archive2.Preset preset) { Archive2.Create(ba2Archive, folder, preset.compression, preset.format); } - public static void Create(String ba2Archive, String folder, Archive2.Compression compression, Archive2.Format format) + public static void Create(string ba2Archive, string folder, Archive2.Compression compression, Archive2.Format format) { if (!Directory.Exists(folder) || Utils.IsDirectoryEmpty(folder)) throw new DirectoryNotFoundException($"The specified folder \"{folder}\" does not exist or is empty."); - String compressionStr = Enum.GetName(typeof(Archive2.Compression), (int)compression); - String formatStr = Enum.GetName(typeof(Archive2.Format), (int)format); + string compressionStr = Enum.GetName(typeof(Archive2.Compression), (int)compression); + string formatStr = Enum.GetName(typeof(Archive2.Format), (int)format); folder = Path.GetFullPath(folder); Archive2.Call($"\"{folder}\" -create=\"{ba2Archive}\" -compression={compressionStr} -format={formatStr} -root=\"{folder}\" -tempFiles -quiet"); @@ -159,7 +162,7 @@ public static void Create(String ba2Archive, String folder, Archive2.Compression throw new Archive2Exception("Packing failed, archive has not been created."); } - public static bool ValidatePath(String path) + public static bool ValidatePath(string path) { return path != null && File.Exists(path) && path.EndsWith(".exe"); } @@ -176,4 +179,11 @@ public Archive2Exception() { } public Archive2Exception(string message) : base(message) { } public Archive2Exception(string message, Exception inner) : base(message, inner) { } } + + public class Archive2RequirementsException : Archive2Exception + { + public Archive2RequirementsException() { } + public Archive2RequirementsException(string message) : base(message) { } + public Archive2RequirementsException(string message, Exception inner) : base(message, inner) { } + } } diff --git a/Fo76ini/ClipboardUtils.cs b/Fo76ini/Utilities/ClipboardUtils.cs similarity index 87% rename from Fo76ini/ClipboardUtils.cs rename to Fo76ini/Utilities/ClipboardUtils.cs index c37eb56..c8e4fcb 100644 --- a/Fo76ini/ClipboardUtils.cs +++ b/Fo76ini/Utilities/ClipboardUtils.cs @@ -5,12 +5,12 @@ using System.Linq; using System.Windows.Forms; -namespace Fo76ini +namespace Fo76ini.Utilities { // https://stackoverflow.com/questions/2077981/cut-files-to-clipboard-in-c-sharp public class ClipboardUtils { - public static void CopyFile(String file) + public static void CopyFile(string file) { FileSystemInfo fsinfo = null; if (File.Exists(file)) @@ -23,7 +23,7 @@ public static void CopyFile(String file) DragDropEffects.Copy); } - public static void CutFile(String file) + public static void CutFile(string file) { FileSystemInfo fsinfo = null; if (File.Exists(file)) @@ -36,24 +36,24 @@ public static void CutFile(String file) DragDropEffects.Move); } - public static void CopyFiles(IEnumerable filesAndFolders) + public static void CopyFiles(IEnumerable filesAndFolders) { ClipboardUtils.PutFilesOnClipboard( ClipboardUtils.GetFileSystemInfoList(filesAndFolders), DragDropEffects.Copy); } - public static void CutFiles(IEnumerable filesAndFolders) + public static void CutFiles(IEnumerable filesAndFolders) { ClipboardUtils.PutFilesOnClipboard( ClipboardUtils.GetFileSystemInfoList(filesAndFolders), DragDropEffects.Move); } - private static List GetFileSystemInfoList (IEnumerable filesAndFolders) + private static List GetFileSystemInfoList(IEnumerable filesAndFolders) { List fileSystemInfos = new List(); - foreach (String fileOrFolder in filesAndFolders) + foreach (string fileOrFolder in filesAndFolders) { FileSystemInfo fsinfo = null; diff --git a/Fo76ini/Log.cs b/Fo76ini/Utilities/Log.cs similarity index 68% rename from Fo76ini/Log.cs rename to Fo76ini/Utilities/Log.cs index 94d3a75..80c3738 100644 --- a/Fo76ini/Log.cs +++ b/Fo76ini/Utilities/Log.cs @@ -1,17 +1,13 @@ using System; -using System.Collections.Generic; using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -namespace Fo76ini +namespace Fo76ini.Utilities { public class Log { - private String path; + private string path; - public Log(String path) + public Log(string path) { this.path = Path.GetFullPath(path); } @@ -36,30 +32,30 @@ public void WriteLine(T line) sw.WriteLine(line); } - public void WriteFormat(String line, params String[] values) + public void WriteFormat(string line, params string[] values) { using (StreamWriter sw = Open()) - sw.Write(String.Format(line, values)); + sw.Write(string.Format(line, values)); } - public void WriteLineFormat(String line, params String[] values) + public void WriteLineFormat(string line, params string[] values) { using (StreamWriter sw = Open()) - sw.WriteLine(String.Format(line, values)); + sw.WriteLine(string.Format(line, values)); } - public void WriteTimeStamp(String suffix = "") + public void WriteTimeStamp(string suffix = "") { using (StreamWriter sw = Open()) sw.WriteLine($"{ DateTime.Now.ToLongDateString()}, { DateTime.Now.ToLongTimeString()} {suffix}"); } - public String GetFilePath() + public string GetFilePath() { return path; } - public static String GetFilePath(String fileName) + public static string GetFilePath(string fileName) { // return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "Fallout 76 Quick Configuration", fileName); return Path.Combine(Shared.AppConfigFolder, fileName); diff --git a/Fo76ini/Utilities/RichTextBoxExtensions.cs b/Fo76ini/Utilities/RichTextBoxExtensions.cs new file mode 100644 index 0000000..7095ad0 --- /dev/null +++ b/Fo76ini/Utilities/RichTextBoxExtensions.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace Fo76ini.Utilities +{ + public static class RichTextBoxExtensions + { + public static void AppendRichText(this RichTextBox box, string text, bool appendNewLine = false, Color? foreColor = null, Color? backColor = null, Font font = null) + { + box.SelectionStart = box.TextLength; + box.SelectionLength = 0; + + Font originalFont = box.SelectionFont; + if (foreColor != null) + box.SelectionColor = (Color)foreColor; + if (backColor != null) + box.SelectionBackColor = (Color)backColor; + if (font != null) + box.SelectionFont = font; + box.AppendText( + appendNewLine + ? $"{text}{Environment.NewLine}" + : text); + box.SelectionColor = box.ForeColor; + box.SelectionBackColor = box.BackColor; + box.SelectionFont = originalFont; + } + } +} diff --git a/Fo76ini/Utils.cs b/Fo76ini/Utilities/Utils.cs similarity index 74% rename from Fo76ini/Utils.cs rename to Fo76ini/Utilities/Utils.cs index 667880e..1a71617 100644 --- a/Fo76ini/Utils.cs +++ b/Fo76ini/Utilities/Utils.cs @@ -1,28 +1,33 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Drawing.Imaging; +using System.Globalization; using System.IO; using System.Linq; -using System.Text; -using System.Threading.Tasks; - - using System.Runtime.InteropServices; -using System.Windows.Forms; using System.Threading; -using System.Globalization; -using System.Drawing; -using System.Drawing.Imaging; +using System.Windows.Forms; using Tulpep.NotificationWindow; -using System.Drawing.Drawing2D; -namespace Fo76ini +namespace Fo76ini.Utilities { - class Utils + public static class Utils { public static CultureInfo enUS = CultureInfo.CreateSpecificCulture("en-US"); - public static String SevenZipPath = Path.GetFullPath(".\\7z\\7za.exe"); + public static string SevenZipPath = Path.GetFullPath(".\\7z\\7z.exe"); + public static readonly string[] SevenZipSupportedFileTypes = new string[] { + ".7z", + ".zip", + ".rar", + ".tar", + ".xz", + ".gz", + ".bz2" + }; /// /// Returns a path relative to "workingDirectory". @@ -67,7 +72,7 @@ public static string MakeRelativePath(string workingDirectory, string fullPath) // we go a few levels back: if (workingDirectory.StartsWith(fullPath)) { - return String.Concat(Enumerable.Repeat("..\\", baseDirs.Length - fileDirs.Length)); + return string.Concat(Enumerable.Repeat("..\\", baseDirs.Length - fileDirs.Length)); } // skip all leading directories that match @@ -102,7 +107,6 @@ public static string MakeRelativePath(string workingDirectory, string fullPath) public static void DeleteDirectory(string targetDir) { // https://stackoverflow.com/questions/1157246/unauthorizedaccessexception-trying-to-delete-a-file-in-a-folder-where-i-can-dele - IniFiles.Instance.SetNTFSWritePermission(true); File.SetAttributes(targetDir, FileAttributes.Normal); string[] files = Directory.GetFiles(targetDir); @@ -128,9 +132,9 @@ public static void DeleteFile(string targetFile) File.Delete(targetFile); } - public static String GetValidFileName(string value, string extension = "") + public static string GetValidFileName(string value, string extension = "") { - String newName = ""; + string newName = ""; if (value.Trim().Length < 0) { newName = "untitled"; @@ -155,7 +159,7 @@ public static String GetValidFileName(string value, string extension = "") /// /// /// - public static String GetUniquePath(string fullPath) + public static string GetUniquePath(string fullPath) { // https://stackoverflow.com/a/13049909 int count = 1; @@ -187,15 +191,15 @@ public static long GetSizeInBytes(string path) long totalFolderSize = 0; - IEnumerable files = Directory.GetFiles(path); - foreach (String filePath in files) + IEnumerable files = Directory.GetFiles(path); + foreach (string filePath in files) { FileInfo info = new FileInfo(filePath); totalFolderSize += info.Length; } - IEnumerable folders = Directory.GetDirectories(path); - foreach (String folderPath in folders) + IEnumerable folders = Directory.GetDirectories(path); + foreach (string folderPath in folders) { totalFolderSize += GetSizeInBytes(folderPath); } @@ -205,7 +209,10 @@ public static long GetSizeInBytes(string path) // https://stackoverflow.com/questions/281640/how-do-i-get-a-human-readable-file-size-in-bytes-abbreviation-using-net // Copy-paste because, I'm lazy. Don't jugde me! :P - public static String GetFormatedSize(long size) + /// + /// Formats size in bytes into a string. + /// + public static string GetFormatedSize(long size) { string[] sizes = { "B", "KB", "MB", "GB", "TB" }; double len = (double)size; @@ -216,7 +223,7 @@ public static String GetFormatedSize(long size) len = len / 1024; } - return String.Format("{0:0.#} {1}", len, sizes[order]); + return string.Format("{0:0.#} {1}", len, sizes[order]); } /// @@ -236,7 +243,7 @@ public static T Clamp(T val, T min, T max) where T : IComparable else return val; } - public static void OpenExplorer(String path) + public static void OpenExplorer(string path) { // https://www.codeproject.com/Questions/852563/How-to-open-file-explorer-at-given-location-in-csh @@ -256,7 +263,7 @@ public static void OpenExplorer(String path) } } - public static void OpenNotepad(String path) + public static void OpenNotepad(string path) { if (File.Exists(path)) { @@ -273,10 +280,34 @@ public static void OpenNotepad(String path) } } + public static void OpenFile(string path) + { + if (File.Exists(path)) + { + ProcessStartInfo startInfo = new ProcessStartInfo(path) + { + UseShellExecute = true + }; + Process.Start(startInfo); + } + else + { + throw new FileNotFoundException($"File \"{path}\" does not exist!"); + } + } + + public static void OpenURL(string url) + { + Process.Start(url); + } + public static void ExtractArchive(string sourceArchive, string destination) { if (!File.Exists(Utils.SevenZipPath)) - throw new FileNotFoundException("7z\\7za.exe could not be found."); + throw new FileNotFoundException("7z\\7z.exe could not be found."); + + if (!Utils.SevenZipSupportedFileTypes.Contains(Path.GetExtension(sourceArchive).ToLower())) + throw new NotSupportedException($"{Path.GetExtension(sourceArchive)} archives are not supported."); ProcessStartInfo proc = new ProcessStartInfo(); proc.WindowStyle = ProcessWindowStyle.Hidden; @@ -284,6 +315,9 @@ public static void ExtractArchive(string sourceArchive, string destination) proc.Arguments = string.Format("x \"{0}\" -y -o\"{1}\"", sourceArchive, destination); Process x = Process.Start(proc); x.WaitForExit(); + + if (!Directory.Exists(destination) || Directory.EnumerateFileSystemEntries(destination).Count() == 0) + throw new FileNotFoundException($"Something went wrong:\n{x.StandardOutput.ReadToEnd()}"); } public static bool IsDirectoryEmpty(string path) @@ -300,7 +334,7 @@ public static bool IsDirectoryEmpty(string path) * https://docs.microsoft.com/de-de/windows/win32/api/winuser/nf-winuser-enumdisplaysettingsa?redirectedfrom=MSDN */ - [DllImport("user32.dll")] + [DllImport("user32.dll")] private static extern bool EnumDisplaySettings( string deviceName, int modeNum, ref DEVMODE devMode); private const int ENUM_CURRENT_SETTINGS = -1; @@ -361,10 +395,10 @@ public static int GetDisplayRefreshRate() return vDevMode.dmDisplayFrequency; } - public static int[] GetDisplayResolution() + public static Size GetDisplayResolution() { DEVMODE vDevMode = Utils.GetDisplayInfo(); - return new int[] { vDevMode.dmPelsWidth, vDevMode.dmPelsHeight }; + return new Size(vDevMode.dmPelsWidth, vDevMode.dmPelsHeight); } @@ -385,25 +419,36 @@ public static int ToInt(string num) return Convert.ToInt32(Convert.ToDecimal(num, enUS)); // "0.0" => (int)0 } - public static String ToString(float num) + public static long ToLong(string num) + { + return Convert.ToInt64(Convert.ToDecimal(num, enUS)); // "0.0" => (int)0 + } + + public static string ToString(float num) { Thread.CurrentThread.CurrentCulture = enUS; return num.ToString("F99").TrimEnd('0').TrimEnd('.'); } - public static String ToString(double num) + public static string ToString(double num) { Thread.CurrentThread.CurrentCulture = enUS; return num.ToString("F99").TrimEnd('0').TrimEnd('.'); } - public static String ToString(int num) + public static string ToString(long num) + { + Thread.CurrentThread.CurrentCulture = enUS; + return num.ToString("D"); + } + + public static string ToString(int num) { Thread.CurrentThread.CurrentCulture = enUS; return num.ToString("D"); } - public static String ToString(uint num) + public static string ToString(uint num) { Thread.CurrentThread.CurrentCulture = enUS; return num.ToString("D"); @@ -420,10 +465,10 @@ public static void SetFormPosition(Form form, int x, int y) form.Location = new Point(x, y); } - public static List ParseVersion(String versionString) + public static List ParseVersion(string versionString) { List version = new List(); - foreach (String chunk in versionString.Trim().Split(new char[] { 'v', '.', 'h', ' ' }, StringSplitOptions.RemoveEmptyEntries)) + foreach (string chunk in versionString.Trim().Split(new char[] { 'v', '.', 'h', ' ' }, StringSplitOptions.RemoveEmptyEntries)) { bool isNumeric = int.TryParse(chunk.Trim(), out int n); if (isNumeric) @@ -436,7 +481,7 @@ public static List ParseVersion(String versionString) return version; // "1.3.1h2" => { 1, 3, 1, 2 } } - public static int CompareVersions(String ver1Str, String ver2Str) + public static int CompareVersions(string ver1Str, string ver2Str) { var ver1 = ParseVersion(ver1Str); var ver2 = ParseVersion(ver2Str); @@ -450,7 +495,7 @@ public static int CompareVersions(String ver1Str, String ver2Str) } - public static PopupNotifier CreatePopup (String title, String text) + public static PopupNotifier CreatePopup(string title, string text) { // https://www.c-sharpcorner.com/article/working-with-popup-notification-in-windows-forms/ // https://github.com/Tulpep/Notification-Popup-Window @@ -483,7 +528,7 @@ public static PopupNotifier CreatePopup (String title, String text) return popup; } - public static PopupNotifier CreatePopup(String title, String text, MessageBoxIcon icon) + public static PopupNotifier CreatePopup(string title, string text, MessageBoxIcon icon) { var popup = Utils.CreatePopup(title, text); switch (icon) @@ -524,12 +569,12 @@ private static extern bool CreateHardLink( IntPtr lpSecurityAttributes ); - public static bool CreateHardLink(String originalFilePath, String newLinkPath) + public static bool CreateHardLink(string originalFilePath, string newLinkPath) { return Utils.CreateHardLink(newLinkPath, originalFilePath, IntPtr.Zero); } - public static bool CreateHardLink(String originalFilePath, String newLinkPath, bool overwrite) + public static bool CreateHardLink(string originalFilePath, string newLinkPath, bool overwrite) { if (File.Exists(newLinkPath)) { @@ -557,21 +602,20 @@ public static ImageCodecInfo GetImageEncoder(ImageFormat format) // https://stackoverflow.com/questions/2808887/create-thumbnail-image // https://stackoverflow.com/questions/1940581/c-sharp-image-resizing-to-different-size-while-preserving-aspect-ratio // https://stackoverflow.com/questions/1484759/quality-of-a-saved-jpg-in-c-sharp - /* - * Creates an thumbnail as *.jpg with a given width and height. - * Instead of stretching the image, it'll resize it while maintaining the aspect ratio. - * A black padding will be drawn if the aspect ratios don't match. - */ - public static Image MakeThumbnail(Image image, string thumbnailPath, int canvasWidth = 160, int canvasHeight = 90, long quality = 70L) + /// + /// Creates an thumbnail as *.jpg with a given width and height. + /// Instead of stretching the image, it'll resize it while maintaining the aspect ratio. + /// A black padding can be drawn if the aspect ratios don't match. + /// + /// Input image + /// Path to *.jpg thumbnail (output) + /// Whether or not to draw a black border if the aspect ratios don't match + /// Max thumbnail width + /// Max thumbnail height + /// JPG Quality (percentage) between 0 and 100 + /// The thumbnail as Image object + public static Image MakeThumbnail(Image image, string thumbnailPath, bool drawBorders = false, int canvasWidth = 160, int canvasHeight = 90, long quality = 70L) { - Image thumbnail = new Bitmap(canvasWidth, canvasHeight); - Graphics graphic = Graphics.FromImage(thumbnail); - - graphic.InterpolationMode = InterpolationMode.HighQualityBicubic; - graphic.SmoothingMode = SmoothingMode.HighQuality; - graphic.PixelOffsetMode = PixelOffsetMode.HighQuality; - graphic.CompositingQuality = CompositingQuality.HighQuality; - // Figure out the ratio double ratioX = (double)canvasWidth / (double)image.Width; double ratioY = (double)canvasHeight / (double)image.Height; @@ -582,33 +626,65 @@ public static Image MakeThumbnail(Image image, string thumbnailPath, int canvasW int newHeight = Convert.ToInt32(image.Height * ratio); int newWidth = Convert.ToInt32(image.Width * ratio); - // Now calculate the X,Y position of the upper-left corner - // (one of these will always be zero) - int posX = Convert.ToInt32((canvasWidth - (image.Width * ratio)) / 2); - int posY = Convert.ToInt32((canvasHeight - (image.Height * ratio)) / 2); + // Create new image: + Image thumbnail; + if (drawBorders) + thumbnail = new Bitmap(canvasWidth, canvasHeight); + else + thumbnail = new Bitmap(newWidth, newHeight); + Graphics graphic = Graphics.FromImage(thumbnail); + + graphic.InterpolationMode = InterpolationMode.HighQualityBicubic; + graphic.SmoothingMode = SmoothingMode.HighQuality; + graphic.PixelOffsetMode = PixelOffsetMode.HighQuality; + graphic.CompositingQuality = CompositingQuality.HighQuality; - graphic.Clear(Color.Black); // background color, padding - graphic.DrawImage(image, posX, posY, newWidth, newHeight); + if (drawBorders) + { + // Now calculate the X,Y position of the upper-left corner + // (one of these will always be zero) + int posX = Convert.ToInt32((canvasWidth - (image.Width * ratio)) / 2); + int posY = Convert.ToInt32((canvasHeight - (image.Height * ratio)) / 2); + + graphic.Clear(Color.Black); // background color, padding + graphic.DrawImage(image, posX, posY, newWidth, newHeight); + } + else + { + graphic.DrawImage(image, 0, 0, newWidth, newHeight); + } // Save the thumbnails as JPEG: ImageCodecInfo jgpEncoder = Utils.GetImageEncoder(ImageFormat.Jpeg); EncoderParameters encoderParameters = new EncoderParameters(1); - encoderParameters.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, quality); + encoderParameters.Param[0] = new EncoderParameter(Encoder.Quality, quality); thumbnail.Save(thumbnailPath, jgpEncoder, encoderParameters); return thumbnail; } - public static Image MakeThumbnail(string filePath, string thumbnailPath, int canvasWidth = 160, int canvasHeight = 90, long quality = 70L) + /// + /// Creates an thumbnail as *.jpg with a given width and height. + /// Instead of stretching the image, it'll resize it while maintaining the aspect ratio. + /// A black padding can be drawn if the aspect ratios don't match. + /// + /// Path to image (input) + /// Path to *.jpg thumbnail (output) + /// Whether or not to draw a black border if the aspect ratios don't match + /// Max thumbnail width + /// Max thumbnail height + /// JPG Quality (percentage) between 0 and 100 + /// The thumbnail as Image object + public static Image MakeThumbnail(string filePath, string thumbnailPath, bool drawBorders = false, int canvasWidth = 160, int canvasHeight = 90, long quality = 70L) { Image image = Image.FromFile(filePath); - return Utils.MakeThumbnail(image, thumbnailPath, canvasWidth, canvasHeight, quality); + return Utils.MakeThumbnail(image, thumbnailPath, drawBorders, canvasWidth, canvasHeight, quality); } // https://stackoverflow.com/questions/3639129/c-sharp-how-do-you-get-the-operating-system-architecture-x86-or-x64 - public static String GetOSArchitecture() + public static string GetOSArchitecture() { - if (!String.IsNullOrEmpty(Environment.GetEnvironmentVariable("PROCESSOR_ARCHITEW6432"))) + if (!string.IsNullOrEmpty(Environment.GetEnvironmentVariable("PROCESSOR_ARCHITEW6432"))) return "64-bit"; return "32-bit"; } @@ -617,7 +693,7 @@ public static String GetOSArchitecture() // https://andrewensley.com/2009/06/c-detect-windows-os-part-1/ // https://docs.microsoft.com/en-us/windows/win32/sysinfo/operating-system-version // https://www.prugg.at/2019/09/09/properly-detect-windows-version-in-c-net-even-windows-10/ - public static String GetOSName() + public static string GetOSName() { // Get Operating system information. OperatingSystem os = Environment.OSVersion; @@ -710,5 +786,38 @@ public static String GetOSName() // Return the information we've gathered. return operatingSystem; } + + public static long GetUnixTimeStamp() + { + return DateTimeOffset.UtcNow.ToUnixTimeSeconds(); + } + + // https://stackoverflow.com/a/250400 + public static DateTime UnixTimeStampToDateTime(double unixTimeStamp) + { + // Unix timestamp is seconds past epoch + System.DateTime dtDateTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, System.DateTimeKind.Utc); + dtDateTime = dtDateTime.AddSeconds(unixTimeStamp).ToLocalTime(); + return dtDateTime; + } + + + + /// + /// Disable scroll wheel on UI elements (NumericUpDown and ComboBox) to prevent the user from accidentally changing values + /// + public static void PreventChangeOnMouseWheelForAllElements(Control control) + { + foreach (Control subControl in control.Controls) + { + // NumericUpDown and ComboBox: + if (subControl.Name.StartsWith("num") || subControl.Name.StartsWith("comboBox") || subControl.Name.StartsWith("slider")) + subControl.MouseWheel += (object sender, MouseEventArgs e) => ((HandledMouseEventArgs)e).Handled = true; + + // TabControl, TabPage, and GroupBox: + if (subControl.Name.StartsWith("tab") || subControl.Name.StartsWith("groupBox") || subControl.Name.StartsWith("panel")) + PreventChangeOnMouseWheelForAllElements(subControl); + } + } } } diff --git a/Fo76ini/Volume.cs b/Fo76ini/Utilities/Volume.cs similarity index 85% rename from Fo76ini/Volume.cs rename to Fo76ini/Utilities/Volume.cs index 4b602a0..92f25ce 100644 --- a/Fo76ini/Volume.cs +++ b/Fo76ini/Utilities/Volume.cs @@ -1,11 +1,8 @@ using System; -using System.Collections.Generic; -using System.Linq; using System.Runtime.InteropServices; -using System.Text; -using System.Threading.Tasks; -namespace Fo76ini +// Doesn't work +namespace Fo76ini.Utilities { // https://stackoverflow.com/questions/1738980/how-do-i-disable-the-c-sharp-message-box-beep // https://stackoverflow.com/a/26700191 @@ -18,7 +15,7 @@ public static class Volume public static extern int waveOutSetVolume(IntPtr h, uint dwVolume); private static uint _savedVolumeLevel; - private static Boolean VolumeLevelSaved = false; + private static bool VolumeLevelSaved = false; // ---------------------------------------------------------------------------- public static void On() diff --git a/Fo76ini/Utilities/XMLExtensions.cs b/Fo76ini/Utilities/XMLExtensions.cs new file mode 100644 index 0000000..1a5f098 --- /dev/null +++ b/Fo76ini/Utilities/XMLExtensions.cs @@ -0,0 +1,97 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Xml; +using System.Xml.Linq; + +namespace Fo76ini.Utilities +{ + public static class XMLExtensions + { + public static bool TryParseBool(this XElement element, out bool result) + { + try + { + result = XmlConvert.ToBoolean(element.Value); + return true; + } + catch + { + result = false; + return false; + } + } + + public static bool TryParseBool(this XAttribute element, out bool result) + { + try + { + result = XmlConvert.ToBoolean(element.Value); + return true; + } + catch + { + result = false; + return false; + } + } + + public static bool TryParseInt(this XAttribute element, out int result) + { + try + { + result = XmlConvert.ToInt32(element.Value); + return true; + } + catch + { + result = 0; + return false; + } + } + + public static bool TryParseInt(this XElement element, out int result) + { + try + { + result = XmlConvert.ToInt32(element.Value); + return true; + } + catch + { + result = 0; + return false; + } + } + + public static bool TryParseLong(this XAttribute element, out long result) + { + try + { + result = XmlConvert.ToInt64(element.Value); + return true; + } + catch + { + result = 0; + return false; + } + } + + public static bool TryParseLong(this XElement element, out long result) + { + try + { + result = XmlConvert.ToInt64(element.Value); + return true; + } + catch + { + result = 0; + return false; + } + } + } +} diff --git a/Fo76ini/cog.ico b/Fo76ini/cog.ico new file mode 100644 index 0000000..09a0714 Binary files /dev/null and b/Fo76ini/cog.ico differ diff --git a/Fo76ini/languages/ja-JP.xml b/Fo76ini/languages/ja-JP.xml index 5ad511f..67d5737 100644 --- a/Fo76ini/languages/ja-JP.xml +++ b/Fo76ini/languages/ja-JP.xml @@ -1,1232 +1,1232 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ゲームの*.iniファイルの少なくとも1つが壊れているか、構文エラーが含まれています。 - -次のような場合があります。 - ->エラーメッセージを読み、エラーを修正するか、 - ->無効な*.iniファイルを削除し、Fallout 76を起動して新しい有効な*.iniファイルを作成します。 - ->再度実行してください。 - -ERROR MESSAGE: -{0} - すべての変更を適用する前にバックアップを作成しますか? - - 「はい」を押してバックアップを作成し、保存します。 - バックアップしないで保存するときは「いいえ」を押します。 - 中止するときは「キャンセル」を押します。 - 変更が適用されました。今からゲームを始めてもよろしい。 - 設定タブでゲームエディションを選択してください。 - このツールを使用する前に、まずゲームを実行してください。 -ゲームは最初の起動時にこれらのファイルを生成します。 - 一部の値がデフォルトにリセットされました。 -以前のバージョンの不安定な値のみが影響を受けます。 -必ず [適用] をクリックしてください。 - *.iniファイルは、実行中にツールの外部で変更されています。 -NOTE:「[適用]」をクリックするか、変更が管理されている場合、変更は上書きされます。 -新しい値を使用するには、ツールを再起動してください。 - UIのロード中に {0} 例外が発生しました。 -これは、破損したiniファイルが原因である可能性があります。 -一部のUI要素が正しく機能していない可能性があります。 - -{1} - {0} *.ini値が無効です: - -{1} - ダウンロードした言語ファイル: {0} - 言語のダウンロードに失敗しました。 -{0} - Microsoft Storeエディションに切り替えるには、ツールを再起動する必要があります。 - 残念ながら、「セキュリティ」の制限により、実行可能ファイルを直接起動することはできません。 マイクロソフトに感謝します、私たちはそれを嫌います。 :( - カスタム* .iniファイルの少なくとも1つにエラーが含まれています。 -{0} - お使いのディスプレイの解像度はサポートされていません。 -ウィンドウは画面に収まるほど大きい場合があります。 -あなたのディスプレイサイズ: {0} -最小表示サイズ: {1} -推奨表示サイズ: 1920 x 1080 - 変更を有効にするには、ツールを再起動する必要があります。 -よろしいですか、今すぐこのオプションを変更しますか? - '{0}'を削除しようとしています。 よろしいですか? - {0}ファイルを削除しようとしています。よろしいですか? - ギャラリーのサムネイルを削除してもよろしいですか? -次に[ギャラリーの更新]をクリックすると、すべてのサムネイルが再作成されるため、かなり時間がかかります。 - これで、アドベンチャーモードで起動できます。 - これでNuclear Winterが起動できます。 - Modは無効になり、ゲームから削除されました。 - Modがデプロイされます。 - Modがデプロイされていない可能性があります。 -ログファイルを確認してください。 - .\ Archive2 \ Archive2.exeがありません。 -このツールを再度ダウンロードするか、Archive2を手動でインストールしてください。 - ゲームへのパス(Fallout76.exeが存在する場所)を設定してください。 - ゲームフォルダのパスが間違っています。 - ディレクトリ{0}は存在しません。 -Mod Managerを再起動して、Modを再度追加してください。 - * .ba2アーカイブとしてインストールされるmodの場合、ルートフォルダを「。\ Data」に設定する必要があります。 -「インストール先」設定を修正して、再試行してください。 - mod {0}を削除してもよろしいですか? - {0} modsを削除してもよろしいですか? - {0} - アーカイブを解凍し、modをフォルダとして追加してください。 - {0} - {0}ファイルはサポートされていません。 -アーカイブを解凍し、modをフォルダとして追加してください。 - 競合するファイルは見つかりませんでした。 - このアクションでは、最初にすべてのmodをデプロイする必要があります。 - 行った変更を展開していません。 -Mod Managerを閉じてもよろしいですか? - パス{0}は存在しません。 -マニフェストのエントリを削除せずに、modフォルダが削除されました。 - modエントリは無効であり、無視されました。 -エラー:{0} - <Mods>タグに無効な属性があります。 -エラー:{0} - Mod Managerの外部にインストールされたModを追加してもよろしいですか? - 一部のmodのアーカイブ名は同じです: "{0}"。 -競合するmod名:{1} - 管理対象のmodフォルダーの名前を変更できませんでした。 -エラーメッセージ: "{0}"。 - これにより、すべての* .ddsファイルが修復されます。 -ファイルサイズやファイル数によっては、時間がかかる場合があります。 -続行してもよろしいですか? - * .ddsファイルが修復されました。 - {0} -管理者としてツールを起動して、再試行してください。 - 利用可能な凍結されたバンドルアーカイブがあります。 バンドルされたアーカイブを再度パックしますか? - - はい-modリストに変更を加えましたが、バンドルされたアーカイブを再度パックしたいと思います。 (スロー) - - いいえ-変更はしていません。凍結されたバンドルアーカイブをデプロイしてください。 (クイック) - 「VisualStudio2012 Update4用のVisualC ++再頒布可能パッケージ」がインストールされていることを確認してください。 -NexusModsページにリンクがあります。 - Nuclear Winterモードを有効にしましたが、Modはまだデプロイされています。 -今すぐ無効にしますか? - Nuclear Winterモードを無効にしましたが、MODはまだ無効になっています。 -今すぐ展開しますか? - Mod情報が更新され、サムネイルがダウンロードされました。 - プロファイルを更新できませんでした: -{0} - 本当にすべてのサムネイルを削除しますか? - サムネイルが削除されました。 - サムネイルを削除できませんでした。 -あとでもう一度試してみてください。 - あなたは本当にあなたのプロフィールをmodマネージャーから削除したいですか? - プロファイルが削除されました。 - 本当にmod情報を削除しますか? - Mod情報が削除されました。 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -