├── .gitignore ├── CHANGELOG.txt ├── LICENSE ├── README.md ├── Touhou Launcher.sln └── Touhou Launcher ├── ConfigForm.Designer.cs ├── ConfigForm.cs ├── ConfigForm.resx ├── MainForm.Designer.cs ├── MainForm.cs ├── MainForm.resx ├── Program.cs ├── Properties ├── AssemblyInfo.cs ├── Resources.Designer.cs ├── Resources.resx ├── Settings.Designer.cs └── Settings.settings ├── Resources_en.Designer.cs ├── Resources_en.resx ├── Resources_jp.Designer.cs ├── Resources_jp.resx ├── Resources_ru.Designer.cs ├── Resources_ru.resx ├── Touhou Launcher.csproj ├── app.config ├── jsonnet ├── LICENSE.md ├── Newtonsoft.Json.dll └── Newtonsoft.Json.xml ├── thcrap.Designer.cs ├── thcrap.cs ├── thcrap.resx └── thicon.ico /.gitignore: -------------------------------------------------------------------------------- 1 | Touhou Launcher.v11.suo 2 | bin/ 3 | obj/ 4 | /.vs/ 5 | -------------------------------------------------------------------------------- /CHANGELOG.txt: -------------------------------------------------------------------------------- 1 | 1.03 (03/09/2023) 2 | Added: Touhou 19 support. 3 | 4 | 1.02 (14/09/2022) 5 | Added: Touhou 18.5 support. 6 | Added: Complete Japanese translation. (Courtesy of HoengSaan) 7 | Added: Error when adding custom game without a category. 8 | Added: Queue for fetching repos so servers aren't overloaded. Lowers refresh speed. 9 | Changed: Rearranged the game categories: Separated the PC-98 games into their own category and renamed the fighting category to games by Twilight Frontier. 10 | Changed: Moved Gouyoku Ibun to the Twilight Frontier category. 11 | Changed: Made instructions more clear when launching a game that isn't set up. (Russian translation pending) 12 | Changed: Updated .Net Framework target to 4.8 13 | Changed: Simplified repo search to use tasks. 14 | Changed: Changed default repo to the official server on the Touhou Patch Center. 15 | Removed: Upwards repository crawl. 16 | 17 | 1.01 (02/02/2022) 18 | Changed: Removed Royalflare's link in the replays tab in light of its approaching shutdown. 19 | Changed: Maribel Hearn's replay link now points to the site's top page. 20 | Changed: Switched to TLS 1.2 to fix thcrap/replay links that don't support older TLS versions. 21 | Changed: Added a check for repo crawling to prevent repeated requests. 22 | Fixed: The launcher creating another directory for thcrap sometimes. 23 | 24 | 1.0 (02/11/2021) 25 | Added: Touhou 17.5 support. 26 | 27 | 1.0-pre5 (04/06/2021) 28 | Added: Touhou 18 support. 29 | 30 | 1.0-pre4 (06/12/2019) 31 | Added: Tray icon for Touhou 17. 32 | Changed: The backwards compatibility code has been rewritten. Unfortunately this breaks compatibility with older versions. An intermediary version called pre3.5 is provided for conversion of settings.json to the new format. 33 | Changed: The browser will no longer start on a webpage. 34 | Changed: replays.gensokyo.org was changed to maribelhearn.com/gensokyo as the former is no longer accessible. 35 | Changed: Updated thcrap interaction to be compatible with the 2019-10-05 update. You may need to set your thcrap_loader path again. 36 | Changed: The profile editor will now fill in missing game profiles with paths that you have already filled automatically when launching it. 37 | Changed: You can now set arbitrary names for game profile IDs as long as they don't start with "th". 38 | Changed: Enlarged the custom games list. 39 | Changed: Upgraded to Visual Studio 2017 from 2012. Hopefully shouldn't change anything. 40 | Changed: Dependencies will now appear only above the patches that depend on them. 41 | Changed: Required thcrap directories will now be created automatically if they do not exist. 42 | Changed: Repository descriptor json files will now be saved upon visiting the patch menu. 43 | Changed: Patch descriptor json files will now be updated whenever they're fetched from the repositories. 44 | Changed: The patch list will no longer lose focus on every repository check. 45 | Fixed: The tray icon's Main Games menu not working (no idea when that broke). 46 | Fixed: thcrap's encoding for patches not using UTF-8. 47 | Fixed: Error if patch directory does not exist. 48 | Fixed: Error when games.js does not exist. 49 | 50 | 1.0-pre3 (13/08/2019) 51 | Added: Selected patches list to show the order of installed patches. 52 | Added: Touhou 17 support. 53 | Added: Dependency search for patches. 54 | Changed: You can now resize the window to smaller size than default. (buggy at the moment) 55 | Changed: Updates to the patch repositories are shown in real time. 56 | Fixed: Appdata/Replay folder being undetectable. 57 | Fixed: Infinite loop when searching for thcrap repositories. 58 | Fixed: local repositories having higher priority than thcrap. 59 | Fixed: thcrap complaining about patch.js not existing. 60 | 61 | 1.0-pre2 (17/04/2019) 62 | Added: thcrap Profile Editor. Lets you select patches from a list and configure the game list manually. The repository search starts at a configurable Url. Offline-only builds will also be released without this feature from now on. 63 | Added: Customizable text color for buttons + the ability to disable the text or banner entirely. 64 | Added: Saved states for the random games list. 65 | Changed: Custom game categories no longer save their key name in the config (hopefully since they are no longer needed). 66 | Changed: The File Select Dialog will now start from the last place a file was selected. 67 | Changed: Custom banners now stretch to fit the button. 68 | Changed: The settings in the settings tab will now only save when switching tabs or closing the program. 69 | Fixed: Background pictures for games being one pixel off. 70 | Fixed: Double Dealing Character typo. 71 | Fixed: Custom banner checkbox not saving. 72 | Fixed: Tab order for the controls. 73 | Fixed: Tray icon's custom games list adding games to their parent category. 74 | Fixed: Not changing the name while renaming custom games/categories would result in an error. 75 | Fixed: Adding the same custom game multiple times. (As long as the path is the exact same) 76 | Fixed: Expanding/Collapsing a custom game category deselecting it. 77 | Fixed: thcrap's files appearing in the launcher's directory. 78 | Fixed: Hisoutensoku and Double Spoiler having the wrong numbers. 79 | Fixed: The banner size label not showing up on the configuration form. 80 | Fixed: Smaller buttons will now show a tooltip with the full text when translated text does not fit in them. 81 | Optimized code 82 | Optimized resources. Should reduce file size by 1.40MBs 83 | Updated localization files. 84 | 85 | 1.0-pre (06/03/2019) 86 | Added: Replay downloader. Includes 3 websites + manual link input. 87 | Added: Tray icon including minimization to tray and always-on tray settings. Can be used to launch any game set up in the program. 88 | Added: thcrap directory setting. 89 | Added: Confirmation dialog when removing custom categories/games. 90 | Added: Drag/drop support to Neko Project II and thcrap's directory settings. 91 | Added: Support for IaMP's Config.exe 92 | Added: Complete localization support. 93 | Added: Russian language support. (courtesy of Lensrub) 94 | Changed: Game configuration dialog shows which game you're configuring. 95 | Changed: Normal buttons no longer use the hand cursor. 96 | Changed: The configuration form always shows at the center of the main window. 97 | Changed: Switched to the DD/MM/YYYY format. 98 | Changed: Custom banner group box now shows the supported dimensions. 99 | Changed: thcrap support is now handled through dropboxes with the name of the game and the configuration files. 100 | Fixed: Unformatted localization strings. 101 | Fixed: PC-98 games giving two messageboxes per error. 102 | Fixed: Possibility of Neko Project II's directory not being saved. 103 | Fixed: Colored banner throwing an exception when editing it manually. 104 | Fixed: Custom banner checkbox and text box not saving when the latter is edited manually. 105 | Fixed: Previously filled textboxes being re-filled. 106 | Fixed: Randomizer select buttons are symmetrical and fit more text. 107 | Fixed: The random button stretching by resizing the window. 108 | Fixed: IaMP's text color being black for some reason. 109 | Updated localization files. 110 | Code reorganization 111 | 112 | 0.8 (11/02/2019) 113 | Added: Actual launch code for PC-98 games (How did I forget that). 114 | Added: Drag/Drop support for game configuration. 115 | Changed: Launching PC-98 games now simply replaces the hdi directory instead of the entire ini file. 116 | Changed: Invalid textboxes turn red instead of giving you a message box/not doing anything. 117 | Fixed: PC-98 games not saving their status immediately. 118 | Fixed: Manually adding banners now checks if the image is valid/openable. 119 | 120 | 0.5 (10/02/2019) 121 | Initial Release 122 | 123 | 07/02/2019 (DD/MM/YYYY) 124 | Project Start 125 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 2-Clause License 2 | 3 | Copyright (c) 2019, David_JonesDVN 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 20 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Touhou-Launcher 2 | A rewrite of the Touhou Launcher created by Widdiful and an alternative to the thcrap configurator.\ 3 | I tried making it more user friendly and added options wherever it was needed. 4 | 5 | The Touhou Launcher a program you can use and set up to launch any Touhou game (and even others if you're using the custom games tab) from the UI or the tray icon. It supports Neko Project II for PC-98 games, game exe files (the game itself, custom.exe or vpatch.exe), and thcrap.\ 6 | In addition, it supports the addition and removal of patches from the thcrap patch repository using a checkbox and list format, with dependencies being added automatically.\ 7 | There is also a "Replays" tab you can use to either navigate popular Touhou replay websites (Don't, actually. The .NET web browser is worse than Internet Explorer 8) or enter your own links to let the launcher automatically download and put them in the correct folder.\ 8 | Finally, each game has a background picture that you can change to whatever you want. 9 | 10 | # Features 11 | Dynamic tray icon menu for custom games.\ 12 | Proper thcrap support, including patch and game profile configuration. (The offline version ships without the configurator.)\ 13 | No auto-updater. I know some of you probably hate things like that.\ 14 | Customizability for how the games launch.\ 15 | Russian language support (Thanks Lensrub).\ 16 | Work-in-progress Japanese language support.\ 17 | Custom language support for testing purposes if you're interested in translating it.\ 18 | Almost all of the features from the original Touhou Launcher. 19 | 20 | # How To Use 21 | First of all, fill in Neko Project II/thcrap_loader's paths in the settings tab.\ 22 | You can then fill in the games' paths by right-clicking on their buttons.\ 23 | If you're not using the offline build, you can choose the "Custom" option from the thcrap dropdown menu on a game's configuration screen to configure patches for that game. 24 | 25 | This is a nonprofit project developed independently by a fan.\ 26 | Touhou belongs to Team Shanghai Alice.\ 27 | \ 28 | Thank you for using this program.\ 29 | I hope you'll enjoy it as much as I enjoyed making it.\ 30 | Feel free to report any bugs, problems or feature requests on the Issues page.\ 31 | \ 32 | Json.NET used under the MIT license. -------------------------------------------------------------------------------- /Touhou Launcher.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2012 4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Touhou Launcher", "Touhou Launcher\Touhou Launcher.csproj", "{DC2E240A-725B-4A6C-83B0-73DBAAB13D1D}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|Any CPU = Debug|Any CPU 9 | Release|Any CPU = Release|Any CPU 10 | EndGlobalSection 11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 12 | {DC2E240A-725B-4A6C-83B0-73DBAAB13D1D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 13 | {DC2E240A-725B-4A6C-83B0-73DBAAB13D1D}.Debug|Any CPU.Build.0 = Debug|Any CPU 14 | {DC2E240A-725B-4A6C-83B0-73DBAAB13D1D}.Release|Any CPU.ActiveCfg = Release|Any CPU 15 | {DC2E240A-725B-4A6C-83B0-73DBAAB13D1D}.Release|Any CPU.Build.0 = Release|Any CPU 16 | EndGlobalSection 17 | GlobalSection(SolutionProperties) = preSolution 18 | HideSolutionNode = FALSE 19 | EndGlobalSection 20 | EndGlobal 21 | -------------------------------------------------------------------------------- /Touhou Launcher/ConfigForm.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace Touhou_Launcher 2 | { 3 | partial class ConfigForm 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Windows Form Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ConfigForm)); 32 | this.openFolder = new System.Windows.Forms.Button(); 33 | this.openvpatch = new System.Windows.Forms.Button(); 34 | this.jpDir = new System.Windows.Forms.TextBox(); 35 | this.enDir = new System.Windows.Forms.TextBox(); 36 | this.customDir = new System.Windows.Forms.TextBox(); 37 | this.browseJP = new System.Windows.Forms.Button(); 38 | this.jpLabel = new System.Windows.Forms.Label(); 39 | this.enLabel = new System.Windows.Forms.Label(); 40 | this.customLabel = new System.Windows.Forms.Label(); 41 | this.openReplays = new System.Windows.Forms.Button(); 42 | this.browseEN = new System.Windows.Forms.Button(); 43 | this.browseCustom = new System.Windows.Forms.Button(); 44 | this.jpApplocale = new System.Windows.Forms.CheckBox(); 45 | this.defaultExec = new System.Windows.Forms.ComboBox(); 46 | this.defaultLabel = new System.Windows.Forms.Label(); 47 | this.launchCustom = new System.Windows.Forms.Button(); 48 | this.launchEN = new System.Windows.Forms.Button(); 49 | this.launchJP = new System.Windows.Forms.Button(); 50 | this.launchcrap = new System.Windows.Forms.Button(); 51 | this.crapLabel = new System.Windows.Forms.Label(); 52 | this.customApplocale = new System.Windows.Forms.CheckBox(); 53 | this.defaultApplocale = new System.Windows.Forms.CheckBox(); 54 | this.crapApplocale = new System.Windows.Forms.CheckBox(); 55 | this.enApplocale = new System.Windows.Forms.CheckBox(); 56 | this.chkCustomBanner = new System.Windows.Forms.CheckBox(); 57 | this.bannerOnLabel = new System.Windows.Forms.Label(); 58 | this.browseBannerOn = new System.Windows.Forms.Button(); 59 | this.bannerOnDir = new System.Windows.Forms.TextBox(); 60 | this.bannerOffLabel = new System.Windows.Forms.Label(); 61 | this.browseBannerOff = new System.Windows.Forms.Button(); 62 | this.bannerOffDir = new System.Windows.Forms.TextBox(); 63 | this.pc98Settings = new System.Windows.Forms.GroupBox(); 64 | this.openNP2Folder = new System.Windows.Forms.Button(); 65 | this.launchHDI = new System.Windows.Forms.Button(); 66 | this.hdiLabel = new System.Windows.Forms.Label(); 67 | this.browseHDI = new System.Windows.Forms.Button(); 68 | this.hdiDir = new System.Windows.Forms.TextBox(); 69 | this.bannerSettings = new System.Windows.Forms.GroupBox(); 70 | this.chkCustomText = new System.Windows.Forms.CheckBox(); 71 | this.btnCustomText = new System.Windows.Forms.Button(); 72 | this.bannerSize = new System.Windows.Forms.Label(); 73 | this.windowsSettings = new System.Windows.Forms.GroupBox(); 74 | this.crapCfg = new System.Windows.Forms.ComboBox(); 75 | this.crapGame = new System.Windows.Forms.ComboBox(); 76 | this.openAppdata = new System.Windows.Forms.Button(); 77 | this.pc98Settings.SuspendLayout(); 78 | this.bannerSettings.SuspendLayout(); 79 | this.windowsSettings.SuspendLayout(); 80 | this.SuspendLayout(); 81 | // 82 | // openFolder 83 | // 84 | this.openFolder.Location = new System.Drawing.Point(337, 235); 85 | this.openFolder.Name = "openFolder"; 86 | this.openFolder.Size = new System.Drawing.Size(242, 23); 87 | this.openFolder.TabIndex = 3; 88 | this.openFolder.Text = "Open Folder"; 89 | this.openFolder.UseVisualStyleBackColor = true; 90 | this.openFolder.Click += new System.EventHandler(this.openFolder_Click); 91 | // 92 | // openvpatch 93 | // 94 | this.openvpatch.AutoEllipsis = true; 95 | this.openvpatch.Location = new System.Drawing.Point(231, 227); 96 | this.openvpatch.Name = "openvpatch"; 97 | this.openvpatch.Size = new System.Drawing.Size(91, 23); 98 | this.openvpatch.TabIndex = 21; 99 | this.openvpatch.Text = "Edit vpatch.ini"; 100 | this.openvpatch.UseVisualStyleBackColor = true; 101 | this.openvpatch.Click += new System.EventHandler(this.openvpatch_Click); 102 | // 103 | // jpDir 104 | // 105 | this.jpDir.AllowDrop = true; 106 | this.jpDir.Location = new System.Drawing.Point(9, 32); 107 | this.jpDir.Name = "jpDir"; 108 | this.jpDir.Size = new System.Drawing.Size(181, 20); 109 | this.jpDir.TabIndex = 1; 110 | this.jpDir.DragDrop += new System.Windows.Forms.DragEventHandler(this.Dir_DragDrop); 111 | this.jpDir.DragEnter += new System.Windows.Forms.DragEventHandler(this.Dir_DragEnter); 112 | this.jpDir.LostFocus += new System.EventHandler(this.Dir_LostFocus); 113 | // 114 | // enDir 115 | // 116 | this.enDir.AllowDrop = true; 117 | this.enDir.Location = new System.Drawing.Point(9, 80); 118 | this.enDir.Name = "enDir"; 119 | this.enDir.Size = new System.Drawing.Size(181, 20); 120 | this.enDir.TabIndex = 5; 121 | this.enDir.DragDrop += new System.Windows.Forms.DragEventHandler(this.Dir_DragDrop); 122 | this.enDir.DragEnter += new System.Windows.Forms.DragEventHandler(this.Dir_DragEnter); 123 | this.enDir.LostFocus += new System.EventHandler(this.Dir_LostFocus); 124 | // 125 | // customDir 126 | // 127 | this.customDir.AllowDrop = true; 128 | this.customDir.Location = new System.Drawing.Point(9, 128); 129 | this.customDir.Name = "customDir"; 130 | this.customDir.Size = new System.Drawing.Size(181, 20); 131 | this.customDir.TabIndex = 10; 132 | this.customDir.DragDrop += new System.Windows.Forms.DragEventHandler(this.Dir_DragDrop); 133 | this.customDir.DragEnter += new System.Windows.Forms.DragEventHandler(this.Dir_DragEnter); 134 | this.customDir.LostFocus += new System.EventHandler(this.Dir_LostFocus); 135 | // 136 | // browseJP 137 | // 138 | this.browseJP.Location = new System.Drawing.Point(196, 30); 139 | this.browseJP.Name = "browseJP"; 140 | this.browseJP.Size = new System.Drawing.Size(62, 22); 141 | this.browseJP.TabIndex = 2; 142 | this.browseJP.Text = "Browse"; 143 | this.browseJP.UseVisualStyleBackColor = true; 144 | this.browseJP.Click += new System.EventHandler(this.browse_Click); 145 | // 146 | // jpLabel 147 | // 148 | this.jpLabel.AutoSize = true; 149 | this.jpLabel.Location = new System.Drawing.Point(6, 16); 150 | this.jpLabel.Name = "jpLabel"; 151 | this.jpLabel.Size = new System.Drawing.Size(150, 13); 152 | this.jpLabel.TabIndex = 6; 153 | this.jpLabel.Text = "Japanese/vpatch Executable:"; 154 | // 155 | // enLabel 156 | // 157 | this.enLabel.AutoSize = true; 158 | this.enLabel.Location = new System.Drawing.Point(6, 64); 159 | this.enLabel.Name = "enLabel"; 160 | this.enLabel.Size = new System.Drawing.Size(100, 13); 161 | this.enLabel.TabIndex = 7; 162 | this.enLabel.Text = "English Executable:"; 163 | // 164 | // customLabel 165 | // 166 | this.customLabel.AutoSize = true; 167 | this.customLabel.Location = new System.Drawing.Point(6, 112); 168 | this.customLabel.Name = "customLabel"; 169 | this.customLabel.Size = new System.Drawing.Size(65, 13); 170 | this.customLabel.TabIndex = 8; 171 | this.customLabel.Text = "Custom.exe:"; 172 | // 173 | // openReplays 174 | // 175 | this.openReplays.AutoEllipsis = true; 176 | this.openReplays.Location = new System.Drawing.Point(106, 227); 177 | this.openReplays.Name = "openReplays"; 178 | this.openReplays.Size = new System.Drawing.Size(119, 23); 179 | this.openReplays.TabIndex = 20; 180 | this.openReplays.Text = "Open Replays Folder"; 181 | this.openReplays.UseVisualStyleBackColor = true; 182 | this.openReplays.Click += new System.EventHandler(this.openReplays_Click); 183 | // 184 | // browseEN 185 | // 186 | this.browseEN.Location = new System.Drawing.Point(196, 78); 187 | this.browseEN.Name = "browseEN"; 188 | this.browseEN.Size = new System.Drawing.Size(62, 22); 189 | this.browseEN.TabIndex = 6; 190 | this.browseEN.Text = "Browse"; 191 | this.browseEN.UseVisualStyleBackColor = true; 192 | this.browseEN.Click += new System.EventHandler(this.browse_Click); 193 | // 194 | // browseCustom 195 | // 196 | this.browseCustom.Location = new System.Drawing.Point(196, 126); 197 | this.browseCustom.Name = "browseCustom"; 198 | this.browseCustom.Size = new System.Drawing.Size(62, 22); 199 | this.browseCustom.TabIndex = 11; 200 | this.browseCustom.Text = "Browse"; 201 | this.browseCustom.UseVisualStyleBackColor = true; 202 | this.browseCustom.Click += new System.EventHandler(this.browse_Click); 203 | // 204 | // jpApplocale 205 | // 206 | this.jpApplocale.AutoSize = true; 207 | this.jpApplocale.Location = new System.Drawing.Point(221, 12); 208 | this.jpApplocale.Name = "jpApplocale"; 209 | this.jpApplocale.Size = new System.Drawing.Size(98, 17); 210 | this.jpApplocale.TabIndex = 0; 211 | this.jpApplocale.Text = "With Applocale"; 212 | this.jpApplocale.UseVisualStyleBackColor = true; 213 | this.jpApplocale.CheckedChanged += new System.EventHandler(this.Applocale_CheckedChanged); 214 | // 215 | // defaultExec 216 | // 217 | this.defaultExec.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; 218 | this.defaultExec.FormattingEnabled = true; 219 | this.defaultExec.Items.AddRange(new object[] { 220 | "Japanese/vpatch.ini", 221 | "English (non-THCRAP)", 222 | "Custom.exe", 223 | "thcrap"}); 224 | this.defaultExec.Location = new System.Drawing.Point(109, 198); 225 | this.defaultExec.Name = "defaultExec"; 226 | this.defaultExec.Size = new System.Drawing.Size(113, 21); 227 | this.defaultExec.TabIndex = 17; 228 | this.defaultExec.SelectedIndexChanged += new System.EventHandler(this.defaultExec_SelectedIndexChanged); 229 | // 230 | // defaultLabel 231 | // 232 | this.defaultLabel.AutoSize = true; 233 | this.defaultLabel.Location = new System.Drawing.Point(6, 198); 234 | this.defaultLabel.Name = "defaultLabel"; 235 | this.defaultLabel.Size = new System.Drawing.Size(100, 13); 236 | this.defaultLabel.TabIndex = 16; 237 | this.defaultLabel.Text = "Default Executable:"; 238 | // 239 | // launchCustom 240 | // 241 | this.launchCustom.AutoEllipsis = true; 242 | this.launchCustom.Location = new System.Drawing.Point(264, 126); 243 | this.launchCustom.Name = "launchCustom"; 244 | this.launchCustom.Size = new System.Drawing.Size(55, 22); 245 | this.launchCustom.TabIndex = 12; 246 | this.launchCustom.Text = "Launch"; 247 | this.launchCustom.UseVisualStyleBackColor = true; 248 | this.launchCustom.Click += new System.EventHandler(this.launch_Click); 249 | // 250 | // launchEN 251 | // 252 | this.launchEN.AutoEllipsis = true; 253 | this.launchEN.Location = new System.Drawing.Point(264, 78); 254 | this.launchEN.Name = "launchEN"; 255 | this.launchEN.Size = new System.Drawing.Size(55, 22); 256 | this.launchEN.TabIndex = 7; 257 | this.launchEN.Text = "Launch"; 258 | this.launchEN.UseVisualStyleBackColor = true; 259 | this.launchEN.Click += new System.EventHandler(this.launch_Click); 260 | // 261 | // launchJP 262 | // 263 | this.launchJP.AutoEllipsis = true; 264 | this.launchJP.Location = new System.Drawing.Point(264, 30); 265 | this.launchJP.Name = "launchJP"; 266 | this.launchJP.Size = new System.Drawing.Size(55, 22); 267 | this.launchJP.TabIndex = 3; 268 | this.launchJP.Text = "Launch"; 269 | this.launchJP.UseVisualStyleBackColor = true; 270 | this.launchJP.Click += new System.EventHandler(this.launch_Click); 271 | // 272 | // launchcrap 273 | // 274 | this.launchcrap.AutoEllipsis = true; 275 | this.launchcrap.Location = new System.Drawing.Point(264, 171); 276 | this.launchcrap.Name = "launchcrap"; 277 | this.launchcrap.Size = new System.Drawing.Size(55, 22); 278 | this.launchcrap.TabIndex = 16; 279 | this.launchcrap.Text = "Launch"; 280 | this.launchcrap.UseVisualStyleBackColor = true; 281 | this.launchcrap.Click += new System.EventHandler(this.launchcrap_Click); 282 | // 283 | // crapLabel 284 | // 285 | this.crapLabel.AutoSize = true; 286 | this.crapLabel.Location = new System.Drawing.Point(6, 155); 287 | this.crapLabel.Name = "crapLabel"; 288 | this.crapLabel.Size = new System.Drawing.Size(72, 13); 289 | this.crapLabel.TabIndex = 21; 290 | this.crapLabel.Text = "thcrap Profile:"; 291 | // 292 | // customApplocale 293 | // 294 | this.customApplocale.AutoSize = true; 295 | this.customApplocale.Location = new System.Drawing.Point(221, 108); 296 | this.customApplocale.Name = "customApplocale"; 297 | this.customApplocale.Size = new System.Drawing.Size(98, 17); 298 | this.customApplocale.TabIndex = 9; 299 | this.customApplocale.Text = "With Applocale"; 300 | this.customApplocale.UseVisualStyleBackColor = true; 301 | this.customApplocale.CheckedChanged += new System.EventHandler(this.Applocale_CheckedChanged); 302 | // 303 | // defaultApplocale 304 | // 305 | this.defaultApplocale.AutoSize = true; 306 | this.defaultApplocale.Location = new System.Drawing.Point(228, 202); 307 | this.defaultApplocale.Name = "defaultApplocale"; 308 | this.defaultApplocale.Size = new System.Drawing.Size(98, 17); 309 | this.defaultApplocale.TabIndex = 18; 310 | this.defaultApplocale.Text = "With Applocale"; 311 | this.defaultApplocale.UseVisualStyleBackColor = true; 312 | this.defaultApplocale.CheckedChanged += new System.EventHandler(this.defaultApplocale_CheckedChanged); 313 | // 314 | // crapApplocale 315 | // 316 | this.crapApplocale.AutoSize = true; 317 | this.crapApplocale.Location = new System.Drawing.Point(221, 152); 318 | this.crapApplocale.Name = "crapApplocale"; 319 | this.crapApplocale.Size = new System.Drawing.Size(98, 17); 320 | this.crapApplocale.TabIndex = 13; 321 | this.crapApplocale.Text = "With Applocale"; 322 | this.crapApplocale.UseVisualStyleBackColor = true; 323 | this.crapApplocale.CheckedChanged += new System.EventHandler(this.Applocale_CheckedChanged); 324 | // 325 | // enApplocale 326 | // 327 | this.enApplocale.AutoSize = true; 328 | this.enApplocale.Location = new System.Drawing.Point(221, 60); 329 | this.enApplocale.Name = "enApplocale"; 330 | this.enApplocale.Size = new System.Drawing.Size(98, 17); 331 | this.enApplocale.TabIndex = 4; 332 | this.enApplocale.Text = "With Applocale"; 333 | this.enApplocale.UseVisualStyleBackColor = true; 334 | this.enApplocale.CheckedChanged += new System.EventHandler(this.Applocale_CheckedChanged); 335 | // 336 | // chkCustomBanner 337 | // 338 | this.chkCustomBanner.AutoSize = true; 339 | this.chkCustomBanner.Location = new System.Drawing.Point(120, 12); 340 | this.chkCustomBanner.Name = "chkCustomBanner"; 341 | this.chkCustomBanner.Size = new System.Drawing.Size(118, 17); 342 | this.chkCustomBanner.TabIndex = 0; 343 | this.chkCustomBanner.Text = "Use custom banner"; 344 | this.chkCustomBanner.UseVisualStyleBackColor = true; 345 | this.chkCustomBanner.CheckedChanged += new System.EventHandler(this.chkCustomBanner_CheckedChanged); 346 | // 347 | // bannerOnLabel 348 | // 349 | this.bannerOnLabel.AutoSize = true; 350 | this.bannerOnLabel.Location = new System.Drawing.Point(6, 16); 351 | this.bannerOnLabel.Name = "bannerOnLabel"; 352 | this.bannerOnLabel.Size = new System.Drawing.Size(83, 13); 353 | this.bannerOnLabel.TabIndex = 31; 354 | this.bannerOnLabel.Text = "Colored Banner:"; 355 | // 356 | // browseBannerOn 357 | // 358 | this.browseBannerOn.Location = new System.Drawing.Point(176, 30); 359 | this.browseBannerOn.Name = "browseBannerOn"; 360 | this.browseBannerOn.Size = new System.Drawing.Size(62, 22); 361 | this.browseBannerOn.TabIndex = 2; 362 | this.browseBannerOn.Text = "Browse"; 363 | this.browseBannerOn.UseVisualStyleBackColor = true; 364 | this.browseBannerOn.Click += new System.EventHandler(this.browseBannerOn_Click); 365 | // 366 | // bannerOnDir 367 | // 368 | this.bannerOnDir.AllowDrop = true; 369 | this.bannerOnDir.Location = new System.Drawing.Point(9, 32); 370 | this.bannerOnDir.Name = "bannerOnDir"; 371 | this.bannerOnDir.Size = new System.Drawing.Size(161, 20); 372 | this.bannerOnDir.TabIndex = 1; 373 | this.bannerOnDir.DragDrop += new System.Windows.Forms.DragEventHandler(this.Dir_DragDrop); 374 | this.bannerOnDir.DragEnter += new System.Windows.Forms.DragEventHandler(this.Dir_DragEnter); 375 | this.bannerOnDir.LostFocus += new System.EventHandler(this.bannerDir_LostFocus); 376 | // 377 | // bannerOffLabel 378 | // 379 | this.bannerOffLabel.AutoSize = true; 380 | this.bannerOffLabel.Location = new System.Drawing.Point(6, 54); 381 | this.bannerOffLabel.Name = "bannerOffLabel"; 382 | this.bannerOffLabel.Size = new System.Drawing.Size(69, 13); 383 | this.bannerOffLabel.TabIndex = 34; 384 | this.bannerOffLabel.Text = "Grey Banner:"; 385 | // 386 | // browseBannerOff 387 | // 388 | this.browseBannerOff.Location = new System.Drawing.Point(176, 68); 389 | this.browseBannerOff.Name = "browseBannerOff"; 390 | this.browseBannerOff.Size = new System.Drawing.Size(62, 22); 391 | this.browseBannerOff.TabIndex = 4; 392 | this.browseBannerOff.Text = "Browse"; 393 | this.browseBannerOff.UseVisualStyleBackColor = true; 394 | this.browseBannerOff.Click += new System.EventHandler(this.browseBannerOff_Click); 395 | // 396 | // bannerOffDir 397 | // 398 | this.bannerOffDir.AllowDrop = true; 399 | this.bannerOffDir.Location = new System.Drawing.Point(9, 70); 400 | this.bannerOffDir.Name = "bannerOffDir"; 401 | this.bannerOffDir.Size = new System.Drawing.Size(161, 20); 402 | this.bannerOffDir.TabIndex = 3; 403 | this.bannerOffDir.DragDrop += new System.Windows.Forms.DragEventHandler(this.Dir_DragDrop); 404 | this.bannerOffDir.DragEnter += new System.Windows.Forms.DragEventHandler(this.Dir_DragEnter); 405 | this.bannerOffDir.LostFocus += new System.EventHandler(this.bannerDir_LostFocus); 406 | // 407 | // pc98Settings 408 | // 409 | this.pc98Settings.Controls.Add(this.openNP2Folder); 410 | this.pc98Settings.Controls.Add(this.launchHDI); 411 | this.pc98Settings.Controls.Add(this.hdiLabel); 412 | this.pc98Settings.Controls.Add(this.browseHDI); 413 | this.pc98Settings.Controls.Add(this.hdiDir); 414 | this.pc98Settings.Location = new System.Drawing.Point(335, 127); 415 | this.pc98Settings.Name = "pc98Settings"; 416 | this.pc98Settings.Size = new System.Drawing.Size(244, 107); 417 | this.pc98Settings.TabIndex = 2; 418 | this.pc98Settings.TabStop = false; 419 | this.pc98Settings.Text = "PC-98 Game Settings"; 420 | // 421 | // openNP2Folder 422 | // 423 | this.openNP2Folder.AutoEllipsis = true; 424 | this.openNP2Folder.Location = new System.Drawing.Point(9, 80); 425 | this.openNP2Folder.Name = "openNP2Folder"; 426 | this.openNP2Folder.Size = new System.Drawing.Size(229, 23); 427 | this.openNP2Folder.TabIndex = 3; 428 | this.openNP2Folder.Text = "Open Neko Project II Folder"; 429 | this.openNP2Folder.UseVisualStyleBackColor = true; 430 | this.openNP2Folder.Click += new System.EventHandler(this.openNP2Folder_Click); 431 | // 432 | // launchHDI 433 | // 434 | this.launchHDI.AutoEllipsis = true; 435 | this.launchHDI.Location = new System.Drawing.Point(183, 58); 436 | this.launchHDI.Name = "launchHDI"; 437 | this.launchHDI.Size = new System.Drawing.Size(55, 22); 438 | this.launchHDI.TabIndex = 2; 439 | this.launchHDI.Text = "Launch"; 440 | this.launchHDI.UseVisualStyleBackColor = true; 441 | this.launchHDI.Click += new System.EventHandler(this.launchHDI_Click); 442 | // 443 | // hdiLabel 444 | // 445 | this.hdiLabel.AutoSize = true; 446 | this.hdiLabel.Location = new System.Drawing.Point(6, 16); 447 | this.hdiLabel.Name = "hdiLabel"; 448 | this.hdiLabel.Size = new System.Drawing.Size(60, 13); 449 | this.hdiLabel.TabIndex = 22; 450 | this.hdiLabel.Text = "Game HDI:"; 451 | // 452 | // browseHDI 453 | // 454 | this.browseHDI.Location = new System.Drawing.Point(9, 58); 455 | this.browseHDI.Name = "browseHDI"; 456 | this.browseHDI.Size = new System.Drawing.Size(62, 22); 457 | this.browseHDI.TabIndex = 1; 458 | this.browseHDI.Text = "Browse"; 459 | this.browseHDI.UseVisualStyleBackColor = true; 460 | this.browseHDI.Click += new System.EventHandler(this.browseHDI_Click); 461 | // 462 | // hdiDir 463 | // 464 | this.hdiDir.AllowDrop = true; 465 | this.hdiDir.Location = new System.Drawing.Point(9, 32); 466 | this.hdiDir.Name = "hdiDir"; 467 | this.hdiDir.Size = new System.Drawing.Size(229, 20); 468 | this.hdiDir.TabIndex = 0; 469 | this.hdiDir.DragDrop += new System.Windows.Forms.DragEventHandler(this.Dir_DragDrop); 470 | this.hdiDir.DragEnter += new System.Windows.Forms.DragEventHandler(this.Dir_DragEnter); 471 | this.hdiDir.LostFocus += new System.EventHandler(this.Dir_LostFocus); 472 | // 473 | // bannerSettings 474 | // 475 | this.bannerSettings.Controls.Add(this.chkCustomText); 476 | this.bannerSettings.Controls.Add(this.btnCustomText); 477 | this.bannerSettings.Controls.Add(this.bannerSize); 478 | this.bannerSettings.Controls.Add(this.bannerOnLabel); 479 | this.bannerSettings.Controls.Add(this.chkCustomBanner); 480 | this.bannerSettings.Controls.Add(this.bannerOffLabel); 481 | this.bannerSettings.Controls.Add(this.bannerOnDir); 482 | this.bannerSettings.Controls.Add(this.browseBannerOff); 483 | this.bannerSettings.Controls.Add(this.browseBannerOn); 484 | this.bannerSettings.Controls.Add(this.bannerOffDir); 485 | this.bannerSettings.Location = new System.Drawing.Point(335, 3); 486 | this.bannerSettings.Name = "bannerSettings"; 487 | this.bannerSettings.Size = new System.Drawing.Size(244, 120); 488 | this.bannerSettings.TabIndex = 1; 489 | this.bannerSettings.TabStop = false; 490 | this.bannerSettings.Text = "Banner Settings"; 491 | // 492 | // chkCustomText 493 | // 494 | this.chkCustomText.AutoSize = true; 495 | this.chkCustomText.Location = new System.Drawing.Point(110, 97); 496 | this.chkCustomText.Name = "chkCustomText"; 497 | this.chkCustomText.Size = new System.Drawing.Size(128, 17); 498 | this.chkCustomText.TabIndex = 6; 499 | this.chkCustomText.Text = "Use custom text color"; 500 | this.chkCustomText.UseVisualStyleBackColor = true; 501 | this.chkCustomText.CheckedChanged += new System.EventHandler(this.chkCustomText_CheckedChanged); 502 | // 503 | // btnCustomText 504 | // 505 | this.btnCustomText.Location = new System.Drawing.Point(9, 93); 506 | this.btnCustomText.Name = "btnCustomText"; 507 | this.btnCustomText.Size = new System.Drawing.Size(95, 22); 508 | this.btnCustomText.TabIndex = 5; 509 | this.btnCustomText.Text = "Set Color"; 510 | this.btnCustomText.UseVisualStyleBackColor = true; 511 | this.btnCustomText.Click += new System.EventHandler(this.btnCustomText_Click); 512 | // 513 | // bannerSize 514 | // 515 | this.bannerSize.AutoSize = true; 516 | this.bannerSize.Location = new System.Drawing.Point(183, 54); 517 | this.bannerSize.Name = "bannerSize"; 518 | this.bannerSize.Size = new System.Drawing.Size(55, 13); 519 | this.bannerSize.TabIndex = 35; 520 | this.bannerSize.Text = "* 120 x 44"; 521 | // 522 | // windowsSettings 523 | // 524 | this.windowsSettings.Controls.Add(this.crapCfg); 525 | this.windowsSettings.Controls.Add(this.crapGame); 526 | this.windowsSettings.Controls.Add(this.openAppdata); 527 | this.windowsSettings.Controls.Add(this.jpLabel); 528 | this.windowsSettings.Controls.Add(this.openvpatch); 529 | this.windowsSettings.Controls.Add(this.enApplocale); 530 | this.windowsSettings.Controls.Add(this.jpDir); 531 | this.windowsSettings.Controls.Add(this.crapApplocale); 532 | this.windowsSettings.Controls.Add(this.enDir); 533 | this.windowsSettings.Controls.Add(this.defaultApplocale); 534 | this.windowsSettings.Controls.Add(this.customDir); 535 | this.windowsSettings.Controls.Add(this.customApplocale); 536 | this.windowsSettings.Controls.Add(this.browseJP); 537 | this.windowsSettings.Controls.Add(this.launchcrap); 538 | this.windowsSettings.Controls.Add(this.enLabel); 539 | this.windowsSettings.Controls.Add(this.customLabel); 540 | this.windowsSettings.Controls.Add(this.crapLabel); 541 | this.windowsSettings.Controls.Add(this.openReplays); 542 | this.windowsSettings.Controls.Add(this.browseEN); 543 | this.windowsSettings.Controls.Add(this.launchJP); 544 | this.windowsSettings.Controls.Add(this.browseCustom); 545 | this.windowsSettings.Controls.Add(this.launchEN); 546 | this.windowsSettings.Controls.Add(this.jpApplocale); 547 | this.windowsSettings.Controls.Add(this.launchCustom); 548 | this.windowsSettings.Controls.Add(this.defaultExec); 549 | this.windowsSettings.Controls.Add(this.defaultLabel); 550 | this.windowsSettings.Location = new System.Drawing.Point(3, 3); 551 | this.windowsSettings.Name = "windowsSettings"; 552 | this.windowsSettings.Size = new System.Drawing.Size(328, 255); 553 | this.windowsSettings.TabIndex = 0; 554 | this.windowsSettings.TabStop = false; 555 | this.windowsSettings.Text = "Windows Game Settings"; 556 | // 557 | // crapCfg 558 | // 559 | this.crapCfg.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; 560 | this.crapCfg.FormattingEnabled = true; 561 | this.crapCfg.Items.AddRange(new object[] { 562 | "None"}); 563 | this.crapCfg.Location = new System.Drawing.Point(128, 171); 564 | this.crapCfg.Name = "crapCfg"; 565 | this.crapCfg.Size = new System.Drawing.Size(130, 21); 566 | this.crapCfg.TabIndex = 15; 567 | this.crapCfg.SelectedIndexChanged += new System.EventHandler(this.crapCfg_SelectedIndexChanged); 568 | // 569 | // crapGame 570 | // 571 | this.crapGame.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; 572 | this.crapGame.FormattingEnabled = true; 573 | this.crapGame.Items.AddRange(new object[] { 574 | "None"}); 575 | this.crapGame.Location = new System.Drawing.Point(6, 171); 576 | this.crapGame.Name = "crapGame"; 577 | this.crapGame.Size = new System.Drawing.Size(116, 21); 578 | this.crapGame.TabIndex = 14; 579 | this.crapGame.SelectedIndexChanged += new System.EventHandler(this.crapCfg_SelectedIndexChanged); 580 | // 581 | // openAppdata 582 | // 583 | this.openAppdata.AutoEllipsis = true; 584 | this.openAppdata.Location = new System.Drawing.Point(9, 227); 585 | this.openAppdata.Name = "openAppdata"; 586 | this.openAppdata.Size = new System.Drawing.Size(91, 23); 587 | this.openAppdata.TabIndex = 19; 588 | this.openAppdata.Text = "Appdata Folder"; 589 | this.openAppdata.UseVisualStyleBackColor = true; 590 | this.openAppdata.Click += new System.EventHandler(this.openAppdata_Click); 591 | // 592 | // ConfigForm 593 | // 594 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); 595 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 596 | this.ClientSize = new System.Drawing.Size(584, 262); 597 | this.Controls.Add(this.windowsSettings); 598 | this.Controls.Add(this.bannerSettings); 599 | this.Controls.Add(this.openFolder); 600 | this.Controls.Add(this.pc98Settings); 601 | this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; 602 | this.Icon = global::Touhou_Launcher.Properties.Resources.thicon; 603 | this.MaximizeBox = false; 604 | this.Name = "ConfigForm"; 605 | this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; 606 | this.Text = "Game Configuration: "; 607 | this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.ConfigForm_Closing); 608 | this.Load += new System.EventHandler(this.ConfigForm_Load); 609 | this.pc98Settings.ResumeLayout(false); 610 | this.pc98Settings.PerformLayout(); 611 | this.bannerSettings.ResumeLayout(false); 612 | this.bannerSettings.PerformLayout(); 613 | this.windowsSettings.ResumeLayout(false); 614 | this.windowsSettings.PerformLayout(); 615 | this.ResumeLayout(false); 616 | 617 | } 618 | 619 | #endregion 620 | 621 | private System.Windows.Forms.Button openFolder; 622 | private System.Windows.Forms.Button openvpatch; 623 | private System.Windows.Forms.TextBox jpDir; 624 | private System.Windows.Forms.TextBox enDir; 625 | private System.Windows.Forms.TextBox customDir; 626 | private System.Windows.Forms.Button browseJP; 627 | private System.Windows.Forms.Label jpLabel; 628 | private System.Windows.Forms.Label enLabel; 629 | private System.Windows.Forms.Label customLabel; 630 | private System.Windows.Forms.Button openReplays; 631 | private System.Windows.Forms.Button browseEN; 632 | private System.Windows.Forms.Button browseCustom; 633 | private System.Windows.Forms.CheckBox jpApplocale; 634 | private System.Windows.Forms.ComboBox defaultExec; 635 | private System.Windows.Forms.Label defaultLabel; 636 | private System.Windows.Forms.Button launchCustom; 637 | private System.Windows.Forms.Button launchEN; 638 | private System.Windows.Forms.Button launchJP; 639 | private System.Windows.Forms.Button launchcrap; 640 | private System.Windows.Forms.Label crapLabel; 641 | private System.Windows.Forms.CheckBox customApplocale; 642 | private System.Windows.Forms.CheckBox defaultApplocale; 643 | private System.Windows.Forms.CheckBox crapApplocale; 644 | private System.Windows.Forms.CheckBox enApplocale; 645 | private System.Windows.Forms.CheckBox chkCustomBanner; 646 | private System.Windows.Forms.Label bannerOnLabel; 647 | private System.Windows.Forms.Button browseBannerOn; 648 | private System.Windows.Forms.TextBox bannerOnDir; 649 | private System.Windows.Forms.Label bannerOffLabel; 650 | private System.Windows.Forms.Button browseBannerOff; 651 | private System.Windows.Forms.TextBox bannerOffDir; 652 | private System.Windows.Forms.GroupBox pc98Settings; 653 | private System.Windows.Forms.Button launchHDI; 654 | private System.Windows.Forms.Label hdiLabel; 655 | private System.Windows.Forms.Button browseHDI; 656 | private System.Windows.Forms.TextBox hdiDir; 657 | private System.Windows.Forms.GroupBox bannerSettings; 658 | private System.Windows.Forms.GroupBox windowsSettings; 659 | private System.Windows.Forms.Button openAppdata; 660 | private System.Windows.Forms.Button openNP2Folder; 661 | private System.Windows.Forms.Label bannerSize; 662 | private System.Windows.Forms.ComboBox crapGame; 663 | private System.Windows.Forms.ComboBox crapCfg; 664 | private System.Windows.Forms.CheckBox chkCustomText; 665 | private System.Windows.Forms.Button btnCustomText; 666 | } 667 | } 668 | -------------------------------------------------------------------------------- /Touhou Launcher/ConfigForm.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Data; 5 | using System.Drawing; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Windows.Forms; 9 | using System.IO; 10 | using System.Diagnostics; 11 | using Newtonsoft.Json; 12 | 13 | namespace Touhou_Launcher 14 | { 15 | public partial class ConfigForm : Form 16 | { 17 | public int game; 18 | Button parentButton; 19 | Dictionary crap = new Dictionary(); 20 | 21 | public ConfigForm(Button parentBtn) 22 | { 23 | InitializeComponent(); 24 | parentButton = parentBtn; 25 | game = MainForm.nameToID[parentBtn.Name.Substring(3)]; 26 | InitializeLanguage(); 27 | chkCustomBanner.Checked = MainForm.curCfg.gameCFG[game].customBanner; 28 | bannerOffDir.Text = MainForm.curCfg.gameCFG[game].bannerOff; 29 | bannerOnDir.Text = MainForm.curCfg.gameCFG[game].bannerOn; 30 | chkCustomText.Checked = MainForm.curCfg.gameCFG[game].customText; 31 | } 32 | 33 | private void ConfigForm_Load(object sender, EventArgs e) 34 | { 35 | if (game > 4) 36 | { 37 | foreach (Control ctrl in pc98Settings.Controls) 38 | ctrl.Enabled = false; 39 | jpDir.Text = MainForm.curCfg.gameCFG[game].GameDir[0]; 40 | jpApplocale.Checked = MainForm.curCfg.gameCFG[game].appLocale[0]; 41 | enDir.Text = MainForm.curCfg.gameCFG[game].GameDir[1]; 42 | enApplocale.Checked = MainForm.curCfg.gameCFG[game].appLocale[1]; 43 | customDir.Text = MainForm.curCfg.gameCFG[game].GameDir[2]; 44 | customApplocale.Checked = MainForm.curCfg.gameCFG[game].appLocale[2]; 45 | Refreshcrap(); 46 | crapApplocale.Checked = MainForm.curCfg.gameCFG[game].appLocale[3]; 47 | defaultExec.SelectedIndex = MainForm.curCfg.gameCFG[game].DefaultDir; 48 | defaultApplocale.Checked = MainForm.curCfg.gameCFG[game].DefaultApplocale; 49 | } 50 | else 51 | { 52 | foreach (Control ctrl in windowsSettings.Controls) 53 | { 54 | ctrl.Enabled = false; 55 | } 56 | hdiDir.Text = MainForm.curCfg.gameCFG[game].GameDir[0]; 57 | } 58 | } 59 | 60 | public void Refreshcrap() 61 | { 62 | crapCfg.Items.Clear(); 63 | crapCfg.Items.Add("None"); 64 | crapGame.Items.Clear(); 65 | crapGame.Items.Add("None"); 66 | if (MainForm.curCfg.crapDir != "") 67 | { 68 | if (File.Exists(MainForm.curCfg.crapDir + "\\config\\games.js")) 69 | { 70 | crap = JsonConvert.DeserializeObject>(File.ReadAllText(MainForm.curCfg.crapDir + "\\config\\games.js")); 71 | foreach (KeyValuePair line in crap) 72 | { 73 | int number = Int32.TryParse(new String(line.Key.Where(Char.IsDigit).ToArray()), out number) ? number : 0; 74 | if (number == MainForm.idToNumber[game] || !line.Key.StartsWith("th")) 75 | { 76 | crapGame.Items.Add(line.Key); 77 | } 78 | } 79 | } 80 | foreach (FileInfo file in new DirectoryInfo(MainForm.curCfg.crapDir).CreateSubdirectory("config").GetFiles("*.js").Where(n => n.Name != "games.js" && n.Name != "config.js")) 81 | { 82 | crapCfg.Items.Add(file.Name); 83 | } 84 | } 85 | if (MainForm.curCfg.crapDir != "") 86 | crapCfg.Items.Add("Custom"); 87 | crapGame.SelectedIndexChanged -= crapCfg_SelectedIndexChanged; 88 | crapCfg.SelectedIndexChanged -= crapCfg_SelectedIndexChanged; 89 | crapGame.SelectedItem = MainForm.curCfg.gameCFG[game].crapCFG[0]; 90 | crapCfg.SelectedItem = MainForm.curCfg.gameCFG[game].crapCFG[1]; 91 | crapGame.SelectedIndexChanged += crapCfg_SelectedIndexChanged; 92 | crapCfg.SelectedIndexChanged += crapCfg_SelectedIndexChanged; 93 | } 94 | 95 | private void InitializeLanguage() 96 | { 97 | foreach (Button btn in MainForm.GetAll(this, typeof(Button))) 98 | { 99 | if (btn.Name.Contains("browse")) 100 | btn.Text = MainForm.rm.GetString("browse"); 101 | else if (btn.Name.Contains("launch")) 102 | btn.Text = MainForm.rm.GetString("launch"); 103 | else 104 | btn.Text = MainForm.rm.GetString(btn.Name); 105 | } 106 | foreach (CheckBox chk in MainForm.GetAll(this, typeof(CheckBox))) 107 | { 108 | if (chk.Name.Contains("Applocale")) 109 | chk.Text = MainForm.rm.GetString("useApplocale"); 110 | else 111 | chk.Text = MainForm.rm.GetString(chk.Name); 112 | } 113 | foreach (Label lbl in MainForm.GetAll(this, typeof(Label))) 114 | { 115 | lbl.Text = MainForm.rm.GetString(lbl.Name); 116 | } 117 | foreach (GroupBox box in MainForm.GetAll(this, typeof(GroupBox))) 118 | { 119 | box.Text = MainForm.rm.GetString(box.Name); 120 | } 121 | defaultExec.Items.Clear(); 122 | defaultExec.Items.AddRange(MainForm.rm.GetString("defaultExec").Split(new string[] {", "}, 4, StringSplitOptions.None)); 123 | this.Text = MainForm.rm.GetString("gameConfiguration") + MainForm.rm.GetString(MainForm.nameToID.FirstOrDefault(t => t.Value == game).Key); 124 | } 125 | 126 | private void ConfigForm_Closing(object sender, FormClosingEventArgs e) 127 | { 128 | this.Focus(); 129 | if (MainForm.curCfg.gameCFG[game].GameDir[MainForm.curCfg.gameCFG[game].DefaultDir] == "") 130 | for (int i = 0; i < MainForm.curCfg.gameCFG[game].GameDir.Count; i++) 131 | { 132 | if (MainForm.curCfg.gameCFG[game].GameDir[i] != "") 133 | { 134 | MainForm.curCfg.gameCFG[game].DefaultDir = i; 135 | break; 136 | } 137 | } 138 | MainForm.RefreshButton(parentButton); 139 | MainForm.curCfg.Save(); 140 | } 141 | 142 | private void Dir_LostFocus(object sender, EventArgs e) 143 | { 144 | if (File.Exists(((TextBox)sender).Text) || ((TextBox)sender).Text == "") 145 | { 146 | ((TextBox)sender).BackColor = SystemColors.Window; 147 | int dirID = game > 4 ? MainForm.dirToNumber[((TextBox)sender).Name.Replace("Dir", "")] : 0; 148 | MainForm.curCfg.gameCFG[game].GameDir[dirID] = ((TextBox)sender).Text; 149 | } 150 | else 151 | { 152 | ((TextBox)sender).BackColor = Color.Red; 153 | } 154 | } 155 | 156 | private void Dir_DragEnter(object sender, DragEventArgs e) 157 | { 158 | if (e.Data.GetDataPresent(DataFormats.FileDrop)) 159 | e.Effect = DragDropEffects.Copy; 160 | } 161 | 162 | private void Dir_DragDrop(object sender, DragEventArgs e) 163 | { 164 | ((TextBox)sender).Text = ((string[])e.Data.GetData(DataFormats.FileDrop)).FirstOrDefault(n => File.Exists(n)); 165 | if (((TextBox)sender).Name.Contains("banner")) 166 | bannerDir_LostFocus(sender, new EventArgs()); 167 | else 168 | Dir_LostFocus(sender, new EventArgs()); 169 | } 170 | 171 | private void Applocale_CheckedChanged(object sender, EventArgs e) 172 | { 173 | MainForm.curCfg.gameCFG[game].appLocale[MainForm.dirToNumber[((CheckBox)sender).Name.Replace("Applocale", "")]] = ((CheckBox)sender).Checked; 174 | } 175 | 176 | private void browse_Click(object sender, EventArgs e) 177 | { 178 | Control txtBox = windowsSettings.Controls.Find(((Button)sender).Name.ToLower().Substring(6) + "Dir", false).FirstOrDefault(n => n.GetType() == typeof(TextBox)); 179 | foreach (string path in MainForm.FileBrowser(MainForm.rm.GetString("gameSelectTitle"), MainForm.rm.GetString("executableFilter") + " (*.exe, *.bat, *.lnk)|*.exe;*.bat;*.lnk|" + MainForm.rm.GetString("allFilter") + " (*.*)|*.*")) 180 | { 181 | int type = MainForm.dirToNumber[txtBox.Name.Replace("Dir", "")]; 182 | txtBox.Text = path; 183 | MainForm.curCfg.gameCFG[game].GameDir[type] = path; 184 | string jpPath = Path.GetDirectoryName(path) + "\\th" + (MainForm.idToNumber[game]).ToString("00") + ".exe"; 185 | string enPath = Path.GetDirectoryName(path) + "\\th" + (MainForm.idToNumber[game]).ToString("00") + "e.exe"; 186 | string customPath = Path.GetDirectoryName(path); 187 | customPath += MainForm.idToNumber[game] == 75 ? "\\Config.exe" : "\\custom.exe"; 188 | if (type != 0 && File.Exists(jpPath) && MainForm.curCfg.gameCFG[game].GameDir[0] == "") 189 | { 190 | jpDir.Text = jpPath; 191 | MainForm.curCfg.gameCFG[game].GameDir[0] = jpPath; 192 | } 193 | if (type != 1 && File.Exists(enPath) && MainForm.curCfg.gameCFG[game].GameDir[1] == "") 194 | { 195 | enDir.Text = enPath; 196 | MainForm.curCfg.gameCFG[game].GameDir[1] = enPath; 197 | } 198 | if (type != 2 && File.Exists(customPath) && MainForm.curCfg.gameCFG[game].GameDir[2] == "") 199 | { 200 | customDir.Text = customPath; 201 | MainForm.curCfg.gameCFG[game].GameDir[2] = customPath; 202 | } 203 | break; 204 | } 205 | } 206 | 207 | private void launch_Click(object sender, EventArgs e) 208 | { 209 | int dir = MainForm.dirToNumber[((Button)sender).Name.ToLower().Substring(6)]; 210 | MainForm.launchGame(game, dir, MainForm.curCfg.gameCFG[game].appLocale[dir]); 211 | } 212 | 213 | private void crapCfg_SelectedIndexChanged(object sender, EventArgs e) 214 | { 215 | MainForm.curCfg.gameCFG[game].crapCFG[0] = crapGame.SelectedItem.ToString(); 216 | if (crapCfg.SelectedItem.ToString() == "Custom") 217 | { 218 | thcrap profileConfig = new thcrap(this); 219 | profileConfig.ShowDialog(); 220 | } 221 | else 222 | MainForm.curCfg.gameCFG[game].crapCFG[1] = crapCfg.SelectedItem.ToString(); 223 | if (crap.ContainsKey(MainForm.curCfg.gameCFG[game].crapCFG[0])) 224 | MainForm.curCfg.gameCFG[game].GameDir[3] = MainForm.curCfg.gameCFG[game].crapCFG[0] != "None" ? crap[MainForm.curCfg.gameCFG[game].crapCFG[0]] : ""; 225 | } 226 | 227 | private void launchcrap_Click(object sender, EventArgs e) 228 | { 229 | MainForm.launchcrap(game); 230 | } 231 | 232 | private void defaultExec_SelectedIndexChanged(object sender, EventArgs e) 233 | { 234 | MainForm.curCfg.gameCFG[game].DefaultDir = defaultExec.SelectedIndex; 235 | } 236 | 237 | private void defaultApplocale_CheckedChanged(object sender, EventArgs e) 238 | { 239 | MainForm.curCfg.gameCFG[game].DefaultApplocale = defaultApplocale.Checked; 240 | } 241 | 242 | private void browseBannerOn_Click(object sender, EventArgs e) 243 | { 244 | foreach (string file in MainForm.FileBrowser(MainForm.rm.GetString("bannerOnSelectTitle"), MainForm.rm.GetString("imageFilter") + " (*.png, *.jpg, *.bmp)|*.png;*.jpg;*.bmp|" + MainForm.rm.GetString("allFilter") + " (*.*)|*.*")) 245 | { 246 | try 247 | { 248 | Image.FromFile(file); 249 | MainForm.curCfg.gameCFG[game].bannerOn = file; 250 | bannerOnDir.Text = file; 251 | } 252 | catch (OutOfMemoryException ex) 253 | { 254 | MessageBox.Show(MainForm.rm.GetString("errorOpenImage") + ex); 255 | } 256 | } 257 | } 258 | 259 | private void browseBannerOff_Click(object sender, EventArgs e) 260 | { 261 | foreach (string file in MainForm.FileBrowser(MainForm.rm.GetString("bannerOffSelectTitle"), MainForm.rm.GetString("imageFilter") + " (*.png, *.jpg, *.bmp)|*.png;*.jpg;*.bmp|" + MainForm.rm.GetString("allFilter") + " (*.*)|*.*")) 262 | { 263 | try 264 | { 265 | Image.FromFile(file); 266 | MainForm.curCfg.gameCFG[game].bannerOff = file; 267 | bannerOffDir.Text = file; 268 | } 269 | catch (OutOfMemoryException ex) 270 | { 271 | MessageBox.Show(MainForm.rm.GetString("errorOpenImage") + ex); 272 | } 273 | } 274 | } 275 | 276 | private void bannerDir_LostFocus(object sender, EventArgs e) 277 | { 278 | bool onTxtBox = ((TextBox)sender).Name.Contains("On"); 279 | if (((TextBox)sender).Text != "") 280 | { 281 | try 282 | { 283 | Image.FromFile(((TextBox)sender).Text); 284 | } 285 | catch (OutOfMemoryException ex) 286 | { 287 | ((TextBox)sender).BackColor = SystemColors.Window; 288 | MessageBox.Show(MainForm.rm.GetString("errorOpenImage") + ex); 289 | } 290 | catch (FileNotFoundException) 291 | { 292 | ((TextBox)sender).BackColor = Color.Red; 293 | } 294 | } 295 | else 296 | ((TextBox)sender).BackColor = SystemColors.Window; 297 | if (onTxtBox) 298 | MainForm.curCfg.gameCFG[game].bannerOn = ((TextBox)sender).Text; 299 | else 300 | MainForm.curCfg.gameCFG[game].bannerOff = ((TextBox)sender).Text; 301 | } 302 | 303 | private void chkCustomBanner_CheckedChanged(object sender, EventArgs e) 304 | { 305 | MainForm.curCfg.gameCFG[game].customBanner = chkCustomBanner.Checked; 306 | } 307 | 308 | private void chkCustomText_CheckedChanged(object sender, EventArgs e) 309 | { 310 | MainForm.curCfg.gameCFG[game].customText = chkCustomText.Checked; 311 | } 312 | 313 | private void btnCustomText_Click(object sender, EventArgs e) 314 | { 315 | ColorDialog colorSet = new ColorDialog(); 316 | colorSet.Color = Color.FromArgb(MainForm.curCfg.gameCFG[game].textColor); 317 | if (colorSet.ShowDialog() == System.Windows.Forms.DialogResult.OK) 318 | MainForm.curCfg.gameCFG[game].textColor = colorSet.Color.ToArgb(); 319 | } 320 | 321 | private void browseHDI_Click(object sender, EventArgs e) 322 | { 323 | foreach (string file in MainForm.FileBrowser(MainForm.rm.GetString("hdiSelectTitle"), MainForm.rm.GetString("hdiFilter") + " (*.hdi)|*.hdi|" + MainForm.rm.GetString("allFilter") + " (*.*)|*.*")) 324 | { 325 | hdiDir.Text = file; 326 | MainForm.curCfg.gameCFG[game].GameDir[0] = file; 327 | } 328 | } 329 | 330 | private void launchHDI_Click(object sender, EventArgs e) 331 | { 332 | MainForm.launchHDI(MainForm.curCfg.gameCFG[game].GameDir[0]); 333 | } 334 | 335 | private void openFolder_Click(object sender, EventArgs e) 336 | { 337 | string path = ""; 338 | if (game > 4) 339 | { 340 | foreach (TextBox dir in MainForm.GetAll(windowsSettings, typeof(TextBox))) 341 | { 342 | if (dir.Text != "") 343 | { 344 | path = Path.GetDirectoryName(dir.Text); 345 | if (Directory.Exists(path)) 346 | break; 347 | } 348 | } 349 | } 350 | else 351 | { 352 | if (hdiDir.Text != "") 353 | { 354 | if (Directory.Exists(Path.GetDirectoryName(hdiDir.Text))) 355 | path = Path.GetDirectoryName(hdiDir.Text); 356 | } 357 | } 358 | if (path != "") 359 | Process.Start(path); 360 | } 361 | 362 | private void openAppdata_Click(object sender, EventArgs e) 363 | { 364 | string path = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData, Environment.SpecialFolderOption.DoNotVerify) + "\\ShanghaiAlice\\th" + (MainForm.idToNumber[game]).ToString("00"); 365 | if (Directory.Exists(path)) 366 | Process.Start(path); 367 | else if (Directory.Exists(path + "tr")) 368 | Process.Start(path + "tr"); 369 | else 370 | MessageBox.Show(MainForm.rm.GetString("errorAppdataNotFound")); 371 | } 372 | 373 | private void openReplays_Click(object sender, EventArgs e) 374 | { 375 | string path = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData, Environment.SpecialFolderOption.DoNotVerify) + "\\ShanghaiAlice\\th"; 376 | if (Directory.Exists(path + MainForm.idToNumber[game].ToString("00") + "\\replay")) 377 | { 378 | Process.Start(path + MainForm.idToNumber[game].ToString("00") + "\\replay"); 379 | return; 380 | } 381 | else if (Directory.Exists(path + MainForm.idToNumber[game].ToString("00") + "tr\\replay")) 382 | { 383 | Process.Start(path + MainForm.idToNumber[game].ToString("00") + "tr\\replay"); 384 | return; 385 | } 386 | else 387 | { 388 | foreach (TextBox dir in MainForm.GetAll(windowsSettings, typeof(TextBox))) 389 | { 390 | if (dir.Text != "") 391 | { 392 | string path2 = Path.GetDirectoryName(dir.Text) + "\\replay"; 393 | if (Directory.Exists(path2)) 394 | { 395 | Process.Start(path2); 396 | return; 397 | } 398 | } 399 | } 400 | } 401 | MessageBox.Show(MainForm.rm.GetString("errorReplaysNotFound")); 402 | } 403 | 404 | private void openvpatch_Click(object sender, EventArgs e) 405 | { 406 | foreach (TextBox txt in windowsSettings.Controls.OfType()) 407 | { 408 | if (txt.Text != "") 409 | { 410 | string path = Path.GetDirectoryName(txt.Text) + "\\vpatch.ini"; 411 | if (File.Exists(path)) 412 | { 413 | Process.Start(path); 414 | return; 415 | } 416 | } 417 | } 418 | MessageBox.Show(MainForm.rm.GetString("errorvpatchNotFound")); 419 | } 420 | 421 | private void openNP2Folder_Click(object sender, EventArgs e) 422 | { 423 | if (MainForm.curCfg.np2Dir != "") 424 | Process.Start(Path.GetDirectoryName(MainForm.curCfg.np2Dir)); 425 | else 426 | MessageBox.Show(MainForm.rm.GetString("errorNP2NotFound")); 427 | } 428 | } 429 | } 430 | -------------------------------------------------------------------------------- /Touhou Launcher/ConfigForm.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | -------------------------------------------------------------------------------- /Touhou Launcher/MainForm.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | 17, 17 122 | 123 | 124 | 469, 17 125 | 126 | 127 | 17, 56 128 | 129 | 130 | 269, 17 131 | 132 | 133 | 172, 17 134 | 135 | 136 | Created by: David_Jones (DVN) (Started: 07/02/2019) (DD/MM/YYYY) 137 | Original Touhou Launcher created by: Widdiful 138 | Russian translation by: Lensrub 139 | 140 | This is a nonprofit project developed independently by a fan 141 | Touhou belongs to Team Shanghai Alice 142 | 143 | Thank you for using this program. 144 | I hope you'll enjoy it as much as I enjoyed making it. 145 | 146 | I guess I have a github now: https://github.com/David-JonesDVN/Touhou-Relauncher 147 | Use that if you have any feature requests, bug reports, etc. 148 | You can also probably find me in the touhou-launcher Discord/IRC server: 149 | 150 | 151 | 148, 56 152 | 153 | 154 | 252, 56 155 | 156 | -------------------------------------------------------------------------------- /Touhou Launcher/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Windows.Forms; 5 | 6 | namespace Touhou_Launcher 7 | { 8 | static class Program 9 | { 10 | /// 11 | /// The main entry point for the application. 12 | /// 13 | [STAThread] 14 | static void Main() 15 | { 16 | Application.EnableVisualStyles(); 17 | Application.SetCompatibleTextRenderingDefault(false); 18 | AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve); 19 | Application.Run(new MainForm()); 20 | } 21 | 22 | static System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args) 23 | { 24 | string str = ""; 25 | if (args.Name.Contains("Newtonsoft.Json")) 26 | str = "Touhou_Launcher.jsonnet.Newtonsoft.Json.dll"; 27 | if (str != "") 28 | { 29 | using (var stream = System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream(str)) 30 | { 31 | try 32 | { 33 | var assemblyData = new Byte[stream.Length]; 34 | stream.Read(assemblyData, 0, assemblyData.Length); 35 | return System.Reflection.Assembly.Load(assemblyData); 36 | } 37 | catch (System.IO.IOException) 38 | { 39 | return null; 40 | } 41 | catch (BadImageFormatException) 42 | { 43 | return null; 44 | } 45 | } 46 | } 47 | else 48 | return null; 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Touhou Launcher/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("Touhou Launcher")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("DVN")] 12 | [assembly: AssemblyProduct("Touhou Launcher")] 13 | [assembly: AssemblyCopyright("")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("bfba53c3-6a74-48c2-b5a7-894e2aa7d442")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.3.0")] 36 | [assembly: AssemblyFileVersion("1.0.3.0")] 37 | -------------------------------------------------------------------------------- /Touhou Launcher/Properties/Settings.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace Touhou_Launcher.Properties { 12 | 13 | 14 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 15 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.9.0.0")] 16 | public sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { 17 | 18 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); 19 | 20 | public static Settings Default { 21 | get { 22 | return defaultInstance; 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Touhou Launcher/Properties/Settings.settings: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /Touhou Launcher/Resources_en.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | Antinomy of Common Flowers 122 | 123 | 124 | Touhou 15.5: Antinomy of Common Flowers 125 | 126 | 127 | Double Dealing Character 128 | 129 | 130 | Touhou 14: Double Dealing Character 131 | 132 | 133 | Double Spoiler 134 | 135 | 136 | Touhou 12.5: Double Spoiler 137 | 138 | 139 | Embodiment of Scarlet Devil 140 | 141 | 142 | Touhou 06: the Embodiment of Scarlet Devil 143 | 144 | 145 | Great Fairy Wars 146 | 147 | 148 | Touhou 12.8: Great Fairy Wars 149 | 150 | 151 | Hopeless Masquerade 152 | 153 | 154 | Touhou 13.5: Hopeless Masquerade 155 | 156 | 157 | Highly Responsive to Prayers 158 | 159 | 160 | Touhou 01: Highly Responsive to Prayers 161 | 162 | 163 | Hidden Star in Four Seasons 164 | 165 | 166 | Touhou 16: Hidden Star in Four Seasons 167 | 168 | 169 | Immaterial and Missing Power 170 | 171 | 172 | Touhou 7.5: Immaterial and Missing Power 173 | 174 | 175 | Imperishable Night 176 | 177 | 178 | Touhou 08: Imperishable Night 179 | 180 | 181 | Impossible Spell Card 182 | 183 | 184 | Touhou 14.3: Impossible Spell Card 185 | 186 | 187 | Lotus Land Story 188 | 189 | 190 | Touhou 04: Lotus Land Story 191 | 192 | 193 | Legacy of Lunatic Kingdom 194 | 195 | 196 | Touhou 15: Legacy of Lunatic Kingdom 197 | 198 | 199 | Mountain of Faith 200 | 201 | 202 | Touhou 10: Mountain of Faith 203 | 204 | 205 | Mystic Square 206 | 207 | 208 | Touhou 05: Mystic Square 209 | 210 | 211 | Perfect Cherry Blossom 212 | 213 | 214 | Touhou 07: Perfect Cherry Blossom 215 | 216 | 217 | Phantasmagoria of Dim. Dream 218 | 219 | 220 | Touhou 03: Phantasmagoria of Dim. Dream 221 | 222 | 223 | Phantasmagoria of Flower View 224 | 225 | 226 | Touhou 09: Phantasmagoria of Flower View 227 | 228 | 229 | Subterranean Animism 230 | 231 | 232 | Touhou 11: Subterranean Animism 233 | 234 | 235 | Story of Eastern Wonderland 236 | 237 | 238 | Touhou 02: the Story of Eastern Wonderland 239 | 240 | 241 | Shoot the Bullet 242 | 243 | 244 | Touhou 9.5: Shoot the Bullet 245 | 246 | 247 | Scarlet Weather Rhapsody 248 | 249 | 250 | Touhou 10.5: Scarlet Weather Rhapsody 251 | 252 | 253 | Ten Desires 254 | 255 | 256 | Touhou 13: Ten Desires 257 | 258 | 259 | Undefined Fantastic Object 260 | 261 | 262 | Touhou 12: Undefined Fantastic Object 263 | 264 | 265 | Urban Legend in Limbo 266 | 267 | 268 | Touhou 14.5: Urban Legend in Limbo 269 | 270 | 271 | Hisoutensoku 272 | 273 | 274 | Touhou 12.3: Hisoutensoku 275 | 276 | 277 | Violet Detector 278 | 279 | 280 | Touhou 16.5: Violet Detector 281 | 282 | 283 | Random 284 | 285 | 286 | Run a Random Game 287 | 288 | 289 | Touhou Launcher 290 | 291 | 292 | Twilight Frontier Games 293 | 294 | 295 | Main Games 296 | 297 | 298 | PC-98 Games 299 | 300 | 301 | AoCF 302 | 303 | 304 | Auto-Close 305 | 306 | 307 | Automatically close the launcher after launching a game 308 | 309 | 310 | Grey Banner 311 | 312 | 313 | Colored Banner 314 | 315 | 316 | Banner Settings 317 | 318 | 319 | Browse 320 | 321 | 322 | Use custom banner 323 | 324 | 325 | Configure Game 326 | 327 | 328 | thcrap Profile: 329 | 330 | 331 | Add Game 332 | 333 | 334 | Custom Games 335 | 336 | 337 | Custom.exe: 338 | 339 | 340 | DDC 341 | 342 | 343 | Default Executable: 344 | 345 | 346 | Delete Category 347 | 348 | 349 | DS 350 | 351 | 352 | English Executable: 353 | 354 | 355 | EoSD 356 | 357 | 358 | Games 359 | 360 | 361 | GFW 362 | 363 | 364 | Game HDI: 365 | 366 | 367 | HM 368 | 369 | 370 | HRtP 371 | 372 | 373 | HSiFS 374 | 375 | 376 | IaMP 377 | 378 | 379 | Info 380 | 381 | 382 | IN 383 | 384 | 385 | ISC 386 | 387 | 388 | Japanese/vpatch Executable: 389 | 390 | 391 | Language: 392 | 393 | 394 | Launch 395 | 396 | 397 | Launcher Settings 398 | 399 | 400 | LLS 401 | 402 | 403 | LoLK 404 | 405 | 406 | MoF 407 | 408 | 409 | MS 410 | 411 | 412 | New Category 413 | 414 | 415 | Neko Project II Location: 416 | 417 | 418 | Open Folder 419 | 420 | 421 | Open Neko Project II Folder 422 | 423 | 424 | Open Replays Folder 425 | 426 | 427 | Edit vpatch.ini 428 | 429 | 430 | PC-98 Game Settings 431 | 432 | 433 | PCB 434 | 435 | 436 | PoDD 437 | 438 | 439 | PoFV 440 | 441 | 442 | Select All 443 | 444 | 445 | Games that will be included in the 446 | random game option: 447 | 448 | 449 | Select None 450 | 451 | 452 | Random Game Settings 453 | 454 | 455 | Rename Category 456 | 457 | 458 | Replays 459 | 460 | 461 | SA 462 | 463 | 464 | Settings 465 | 466 | 467 | SoEW 468 | 469 | 470 | StB 471 | 472 | 473 | SWR 474 | 475 | 476 | TD 477 | 478 | 479 | UFO 480 | 481 | 482 | ULiL 483 | 484 | 485 | Hisoutensoku 486 | 487 | 488 | With Applocale 489 | 490 | 491 | VD 492 | 493 | 494 | Windows Game Settings 495 | 496 | 497 | All Files 498 | 499 | 500 | Ascending 501 | 502 | 503 | Select the grey banner 504 | 505 | 506 | Select the colored banner 507 | 508 | 509 | Japanese/vpatch.ini, English (non-THCRAP), Custom.exe, thcrap 510 | 511 | 512 | Delete 513 | 514 | 515 | Descending 516 | 517 | 518 | Details 519 | 520 | 521 | Cannot find Appdata Folder 522 | 523 | 524 | File could not be found 525 | 526 | 527 | Please set Neko Project 2's location 528 | 529 | 530 | Cannot open file as image: 531 | 532 | 533 | 534 | Cannot find Replays folder 535 | 536 | 537 | Cannot find vpatch.ini 538 | 539 | 540 | Executable Files 541 | 542 | 543 | Select Executable 544 | 545 | 546 | Hard Disk Image Files 547 | 548 | 549 | Select the game's HDI 550 | 551 | 552 | Image Files 553 | 554 | 555 | Large Icons 556 | 557 | 558 | List 559 | 560 | 561 | Select Neko Project II's executable 562 | 563 | 564 | Appdata Folder 565 | 566 | 567 | Open Folder 568 | 569 | 570 | Open With Applocale 571 | 572 | 573 | Play Random 574 | 575 | 576 | Rename 577 | 578 | 579 | Small Icons 580 | 581 | 582 | Sort 583 | 584 | 585 | Tile 586 | 587 | 588 | View 589 | 590 | 591 | Neko Project II's configuration ini is not valid. 592 | 593 | 594 | Cannot find game. Please check the path in the right click menu. 595 | 596 | 597 | Replay Files 598 | 599 | 600 | Download '{0}' to: 601 | '{1}' 602 | 603 | 604 | Player replays full and Touhou 10 does not support user replays. 605 | 606 | 607 | 608 | Game Configuration: 609 | 610 | 611 | Minimize to tray 612 | 613 | 614 | Always show tray icon 615 | 616 | 617 | Delete Category '{0}' and all of its contents? 618 | 619 | 620 | Delete '{0}'? 621 | 622 | 623 | Please set thcrap's location 624 | 625 | 626 | Configure thcrap 627 | 628 | 629 | thcrap_loader Location: 630 | 631 | 632 | Please set thcrap's profile 633 | 634 | 635 | No Games Selected 636 | 637 | 638 | Download Replay? 639 | 640 | 641 | Exit 642 | 643 | 644 | Open 645 | 646 | 647 | Random Game 648 | 649 | 650 | Remove Game 651 | 652 | 653 | Description 654 | 655 | 656 | Game Profiles 657 | 658 | 659 | Game ID 660 | 661 | 662 | ID 663 | 664 | 665 | Patch 666 | 667 | 668 | Custom Profile 669 | 670 | 671 | Game Path 672 | 673 | 674 | Profile Configuration: 675 | 676 | 677 | Title 678 | 679 | 680 | Default 681 | 682 | 683 | thcrap Starting Repository: 684 | 685 | 686 | * 120 x 44 687 | 688 | 689 | Set Color 690 | 691 | 692 | Use custom text color 693 | 694 | 695 | Show banner? 696 | 697 | 698 | Edit Button 699 | 700 | 701 | Show Text? 702 | 703 | 704 | Selected Patches 705 | 706 | 707 | Wily Beast and Weakest Creature 708 | 709 | 710 | WBaWC 711 | 712 | 713 | Touhou 17: Wily Beast and Weakest Creature 714 | 715 | 716 | Unconnected Marketeers 717 | 718 | 719 | UM 720 | 721 | 722 | Touhou 18: Unconnected Marketeers 723 | 724 | 725 | Gouyoku Ibun 726 | 727 | 728 | GI 729 | 730 | 731 | Touhou 17.5: Gouyoku Ibun 732 | 733 | 734 | No Category Selected 735 | 736 | 737 | 100th Black Market 738 | 739 | 740 | 100BM 741 | 742 | 743 | Touhou 18.5: 100th Black Market 744 | 745 | 746 | Spinoffs 747 | 748 | 749 | Unfinished Dream of All Living Ghost 750 | 751 | 752 | UDoALG 753 | 754 | 755 | Touhou 19: Unfinished Dream of All Living Ghost 756 | 757 | -------------------------------------------------------------------------------- /Touhou Launcher/Resources_jp.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | 東方憑依華 122 | 123 | 124 | 東方憑依華 ~ Antinomy of Common Flowers 125 | 126 | 127 | 東方輝針城 128 | 129 | 130 | 東方輝針城 ~ Double Dealing Character 131 | 132 | 133 | ダブルスポイラー 134 | 135 | 136 | ダブルスポイラー ~ 東方文花帖 137 | 138 | 139 | 東方紅魔郷 140 | 141 | 142 | 東方紅魔郷 ~ the Embodiment of Scarlet Devil 143 | 144 | 145 | 妖精大戦争 146 | 147 | 148 | 妖精大戦争 ~ 東方三月精 149 | 150 | 151 | 東方心綺楼 152 | 153 | 154 | 東方心綺楼 ~ Hopeless Masquerade 155 | 156 | 157 | 東方靈異伝 158 | 159 | 160 | 東方靈異伝 ~ Highly Responsive to Prayers 161 | 162 | 163 | 東方天空璋 164 | 165 | 166 | 東方天空璋 ~ Hidden Star in Four Seasons 167 | 168 | 169 | 東方萃夢想 170 | 171 | 172 | 東方萃夢想 ~ Immaterial and Missing Power 173 | 174 | 175 | 東方永夜抄 176 | 177 | 178 | 東方永夜抄 ~ Imperishable Night 179 | 180 | 181 | アマノジャク 182 | 183 | 184 | 弾幕アマノジャク ~ Impossible Spell Card 185 | 186 | 187 | 東方幻想郷 188 | 189 | 190 | 東方幻想郷 ~ Lotus Land Story 191 | 192 | 193 | 東方紺珠伝 194 | 195 | 196 | 東方紺珠伝 ~ Legacy of Lunatic Kingdom 197 | 198 | 199 | 東方風神録 200 | 201 | 202 | 東方風神録 ~ Mountain of Faith 203 | 204 | 205 | 東方怪綺談 206 | 207 | 208 | 東方怪綺談 ~ Mystic Square 209 | 210 | 211 | 東方妖々夢 212 | 213 | 214 | 東方妖々夢 ~ Perfect Cherry Blossom 215 | 216 | 217 | 東方夢時空 218 | 219 | 220 | 東方夢時空 ~ Phantasmagoria of Dim.Dream 221 | 222 | 223 | 東方花映塚 224 | 225 | 226 | 東方花映塚 ~ Phantasmagoria of Flower View 227 | 228 | 229 | 東方地霊殿 230 | 231 | 232 | 東方地霊殿 ~ Subterranean Animism 233 | 234 | 235 | 東方封魔録 236 | 237 | 238 | 東方封魔録 ~ the Story of Eastern Wonderland 239 | 240 | 241 | 東方文花帖 242 | 243 | 244 | 東方文花帖 ~ Shoot the Bullet 245 | 246 | 247 | 東方緋想天 248 | 249 | 250 | 東方緋想天 ~ Scarlet Weather Rhapsody 251 | 252 | 253 | 東方神霊廟 254 | 255 | 256 | 東方神霊廟 ~ Ten Desires 257 | 258 | 259 | 東方星蓮船 260 | 261 | 262 | 東方星蓮船 ~ Undefined Fantastic Object 263 | 264 | 265 | 東方深秘録 266 | 267 | 268 | 東方深秘録 ~ Urban Legend in Limbo 269 | 270 | 271 | 東方非想天則 272 | 273 | 274 | 東方非想天則 ~ 超弩級ギニョルの謎を追え 275 | 276 | 277 | 秘封ナイトメアダイアリー 278 | 279 | 280 | 秘封ナイトメアダイアリー 〜 Violet Detector 281 | 282 | 283 | ランダム 284 | 285 | 286 | ランダムでゲームを起動します 287 | 288 | 289 | 東方ランチャー 290 | 291 | 292 | 黄昏フロンティア作 293 | 294 | 295 | 整数作 296 | 297 | 298 | 旧作 299 | 300 | 301 | 憑依華 302 | 303 | 304 | 自動終了 305 | 306 | 307 | ゲームを起動した後、自動的にランチャーを閉じます 308 | 309 | 310 | バナー(白黒) 311 | 312 | 313 | バナー 314 | 315 | 316 | バナーの設定 317 | 318 | 319 | 参照 320 | 321 | 322 | カスタムバナーを使用 323 | 324 | 325 | 設定 326 | 327 | 328 | thcrapプロファイル: 329 | 330 | 331 | ゲームを追加 332 | 333 | 334 | 同人ゲーム 335 | 336 | 337 | Custom.exe: 338 | 339 | 340 | 輝針城 341 | 342 | 343 | デフォルトで開く: 344 | 345 | 346 | 削除 347 | 348 | 349 | ダブルスポイラー 350 | 351 | 352 | English Executable: 353 | 354 | 355 | 紅魔郷 356 | 357 | 358 | ゲーム 359 | 360 | 361 | 妖精大戦争 362 | 363 | 364 | HDIファイル: 365 | 366 | 367 | 心綺楼 368 | 369 | 370 | 靈異伝 371 | 372 | 373 | 天空璋 374 | 375 | 376 | 萃夢想 377 | 378 | 379 | 東方ランチャーについて 380 | 381 | 382 | 永夜抄 383 | 384 | 385 | アマノジャク 386 | 387 | 388 | 実行ファイルの場所: 389 | 390 | 391 | 言語: 392 | 393 | 394 | 起動 395 | 396 | 397 | 全般 398 | 399 | 400 | 幻想郷 401 | 402 | 403 | 紺珠伝 404 | 405 | 406 | 風神録 407 | 408 | 409 | 怪綺談 410 | 411 | 412 | 新規作成 413 | 414 | 415 | Neko Project IIの場所: 416 | 417 | 418 | フォルダを開く 419 | 420 | 421 | Neko Project IIのフォルダを開く 422 | 423 | 424 | replayフォルダ 425 | 426 | 427 | vpatch.iniを編集 428 | 429 | 430 | PC-98版用 431 | 432 | 433 | 妖々夢 434 | 435 | 436 | 夢時空 437 | 438 | 439 | 花映塚 440 | 441 | 442 | すべて 443 | 444 | 445 | ランダムで起動したいゲームを選んでください 446 | 447 | 448 | なし 449 | 450 | 451 | ランダム起動 452 | 453 | 454 | 名前の変更 455 | 456 | 457 | リプレイ 458 | 459 | 460 | 地霊殿 461 | 462 | 463 | 設定 464 | 465 | 466 | 封魔録 467 | 468 | 469 | 文花帖 470 | 471 | 472 | 緋想天 473 | 474 | 475 | 神霊廟 476 | 477 | 478 | 星蓮船 479 | 480 | 481 | 深秘録 482 | 483 | 484 | 非想天則 485 | 486 | 487 | AppLocaleで実行 488 | 489 | 490 | ナイトメアダイアリー 491 | 492 | 493 | Windows版用 494 | 495 | 496 | すべてのファイル 497 | 498 | 499 | 昇順 500 | 501 | 502 | バナー(白黒)を指定する 503 | 504 | 505 | バナーを指定する 506 | 507 | 508 | 日本語/vpatch.ini, 英語 (non-THCRAP), Custom.exe, thcrap 509 | 510 | 511 | 削除 512 | 513 | 514 | 降順 515 | 516 | 517 | 詳細 518 | 519 | 520 | Appdataフォルダが見つりません 521 | 522 | 523 | ファイルが見つかりません 524 | 525 | 526 | Neko Project 2のパスを指定してください 527 | 528 | 529 | 画像ファイルではありません: 530 | 531 | 532 | 533 | replayフォルダが見つかりません 534 | 535 | 536 | vpatch.iniが見つかりません 537 | 538 | 539 | 実行ファイル 540 | 541 | 542 | ゲームの実行ファイルを指定する 543 | 544 | 545 | HDIファイル 546 | 547 | 548 | ゲームのHDIファイルを指定する 549 | 550 | 551 | 画像ファイル 552 | 553 | 554 | 大アイコン 555 | 556 | 557 | 一覧 558 | 559 | 560 | Neko Project IIの実行ファイルを指定する 561 | 562 | 563 | Appdataフォルダ 564 | 565 | 566 | フォルダを開く 567 | 568 | 569 | Applocaleで開く 570 | 571 | 572 | ランダムでゲームを起動 573 | 574 | 575 | 名前の変更 576 | 577 | 578 | 小アイコン 579 | 580 | 581 | 並べ替え 582 | 583 | 584 | 並べて表示 585 | 586 | 587 | 表示 588 | 589 | 590 | Neko Project IIのコンフィグiniは有効ではありません。 591 | 592 | 593 | ゲームファイルが見つからない。右クリックメニューでパスを指定してください。 594 | 595 | 596 | リプレイファイル 597 | 598 | 599 | '{1}'に'{0}'をダウンロードします 600 | 601 | 602 | リプレイリストがいっぱいです。(風神録はユーザーリプレイをサポートしていません) 603 | 604 | 605 | 606 | ゲームの設定: 607 | 608 | 609 | トレイに最小化 610 | 611 | 612 | トレイアイコンを常に表示する 613 | 614 | 615 | 「{0}」とその中にいるすべてを削除しますか? 616 | 617 | 618 | 「{0}」を削除しますか? 619 | 620 | 621 | thcrapのパスを指定してください 622 | 623 | 624 | thcrapの設定 625 | 626 | 627 | thcrap_loaderの場所: 628 | 629 | 630 | thcrapのプロファイルを設定してください 631 | 632 | 633 | ゲームが選択されていません 634 | 635 | 636 | リプレイをダウンロードしますか? 637 | 638 | 639 | 終了 640 | 641 | 642 | 表示 643 | 644 | 645 | ランダムでゲームを起動 646 | 647 | 648 | ゲームを削除する 649 | 650 | 651 | 説明 652 | 653 | 654 | ゲームプロファイル 655 | 656 | 657 | ゲームID 658 | 659 | 660 | ID 661 | 662 | 663 | パッチ 664 | 665 | 666 | カスタムプロファイル 667 | 668 | 669 | ゲームパス 670 | 671 | 672 | プロファイルの設定: 673 | 674 | 675 | タイトル 676 | 677 | 678 | デフォルト 679 | 680 | 681 | thcrap起動用リポジトリ: 682 | 683 | 684 | * 120 x 44 685 | 686 | 687 | 色を指定 688 | 689 | 690 | 指定した色を使用 691 | 692 | 693 | バナーの表示 694 | 695 | 696 | 表示 697 | 698 | 699 | タイトルの表示 700 | 701 | 702 | 選択されたパッチ 703 | 704 | 705 | 東方鬼形獣 706 | 707 | 708 | 鬼形獣 709 | 710 | 711 | 東方鬼形獣 ~ Wily Beast and Weakest Creature 712 | 713 | 714 | 東方虹龍洞 715 | 716 | 717 | 虹龍洞 718 | 719 | 720 | 東方虹龍洞 ~ Unconnected Marketeers 721 | 722 | 723 | 東方剛欲異聞 724 | 725 | 726 | 剛欲異聞 727 | 728 | 729 | 東方剛欲異聞 ~ 水没した沈愁地獄 730 | 731 | 732 | カテゴリーが選択されていません 733 | 734 | 735 | バレットフィリア達の闇市場 736 | 737 | 738 | バレットフィリア 739 | 740 | 741 | バレットフィリア達の闇市場 〜 100th Black Market 742 | 743 | 744 | 小数点作 745 | 746 | 747 | 東方獣王園 748 | 749 | 750 | 獣王園 751 | 752 | 753 | 東方獣王園 〜 Unfinished Dream of All Living Ghost 754 | 755 | -------------------------------------------------------------------------------- /Touhou Launcher/Resources_ru.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | Antinomy of Common Flowers 122 | 123 | 124 | Touhou 15.5: Antinomy of Common Flowers 125 | 126 | 127 | Double Dealing Character 128 | 129 | 130 | Touhou 14: Double Dealing Character 131 | 132 | 133 | Double Spoiler 134 | 135 | 136 | Touhou 12.5: Double Spoiler 137 | 138 | 139 | Embodiment of Scarlet Devil 140 | 141 | 142 | Touhou 06: the Embodiment of Scarlet Devil 143 | 144 | 145 | Great Fairy Wars 146 | 147 | 148 | Touhou 12.8: Great Fairy Wars 149 | 150 | 151 | Hopeless Masquerade 152 | 153 | 154 | Touhou 13.5: Hopeless Masquerade 155 | 156 | 157 | Highly Responsive to Prayers 158 | 159 | 160 | Touhou 01: Highly Responsive to Prayers 161 | 162 | 163 | Hidden Star in Four Seasons 164 | 165 | 166 | Touhou 16: Hidden Star in Four Seasons 167 | 168 | 169 | Immaterial and Missing Power 170 | 171 | 172 | Touhou 7.5: Immaterial and Missing Power 173 | 174 | 175 | Imperishable Night 176 | 177 | 178 | Touhou 08: Imperishable Night 179 | 180 | 181 | Impossible Spell Card 182 | 183 | 184 | Touhou 14.3: Impossible Spell Card 185 | 186 | 187 | Lotus Land Story 188 | 189 | 190 | Touhou 04: Lotus Land Story 191 | 192 | 193 | Legacy of Lunatic Kingdom 194 | 195 | 196 | Touhou 15: Legacy of Lunatic Kingdom 197 | 198 | 199 | Mountain of Faith 200 | 201 | 202 | Touhou 10: Mountain of Faith 203 | 204 | 205 | Mystic Square 206 | 207 | 208 | Touhou 05: Mystic Square 209 | 210 | 211 | Perfect Cherry Blossom 212 | 213 | 214 | Touhou 07: Perfect Cherry Blossom 215 | 216 | 217 | Phantasmagoria of Dim. Dream 218 | 219 | 220 | Touhou 03: Phantasmagoria of Dim. Dream 221 | 222 | 223 | Phantasmagoria of Flower View 224 | 225 | 226 | Touhou 09: Phantasmagoria of Flower View 227 | 228 | 229 | Subterranean Animism 230 | 231 | 232 | Touhou 11: Subterranean Animism 233 | 234 | 235 | Story of Eastern Wonderland 236 | 237 | 238 | Touhou 02: the Story of Eastern Wonderland 239 | 240 | 241 | Shoot the Bullet 242 | 243 | 244 | Touhou 9.5: Shoot the Bullet 245 | 246 | 247 | Scarlet Weather Rhapsody 248 | 249 | 250 | Touhou 10.5: Scarlet Weather Rhapsody 251 | 252 | 253 | Ten Desires 254 | 255 | 256 | Touhou 13: Ten Desires 257 | 258 | 259 | Undefined Fantastic Object 260 | 261 | 262 | Touhou 12: Undefined Fantastic Object 263 | 264 | 265 | Urban Legend in Limbo 266 | 267 | 268 | Touhou 14.5: Urban Legend in Limbo 269 | 270 | 271 | Hisoutensoku 272 | 273 | 274 | Touhou 12.3: Hisoutensoku 275 | 276 | 277 | Violet Detector 278 | 279 | 280 | Touhou 16.5: Violet Detector 281 | 282 | 283 | Случайная 284 | 285 | 286 | Запуск случайной игры 287 | 288 | 289 | Touhou Launcher 290 | 291 | 292 | Игры от Tasogare Frontier 293 | 294 | 295 | Основные игры 296 | 297 | 298 | Игры PC-98 299 | 300 | 301 | AoCF 302 | 303 | 304 | Автозакрытие 305 | 306 | 307 | Автоматически закрывать лаучер после запуска игры 308 | 309 | 310 | Чёрно-белая обложка 311 | 312 | 313 | Цветная обложка 314 | 315 | 316 | Настройка обложек 317 | 318 | 319 | Обзор 320 | 321 | 322 | Кастомные обложки 323 | 324 | 325 | Настройка игры 326 | 327 | 328 | Профиль thcrap: 329 | 330 | 331 | Добавить игру 332 | 333 | 334 | Кастомные игры 335 | 336 | 337 | Custom.exe: 338 | 339 | 340 | DDC 341 | 342 | 343 | Запуск по умолч. 344 | 345 | 346 | Удалить категорию 347 | 348 | 349 | DS 350 | 351 | 352 | Английский файл запуска: 353 | 354 | 355 | EoSD 356 | 357 | 358 | Игры 359 | 360 | 361 | GFW 362 | 363 | 364 | Игра в .HDI: 365 | 366 | 367 | HM 368 | 369 | 370 | HRtP 371 | 372 | 373 | HSiFS 374 | 375 | 376 | IaMP 377 | 378 | 379 | Инфо 380 | 381 | 382 | IN 383 | 384 | 385 | ISC 386 | 387 | 388 | Японский/vpatch файл запуска: 389 | 390 | 391 | Язык: 392 | 393 | 394 | Запуск 395 | 396 | 397 | Настройка запуска 398 | 399 | 400 | LLS 401 | 402 | 403 | LoLK 404 | 405 | 406 | MoF 407 | 408 | 409 | MS 410 | 411 | 412 | Новая категория 413 | 414 | 415 | Путь к Neko Project II 416 | 417 | 418 | Открыть папку игры 419 | 420 | 421 | Открыть папку Neko Project II 422 | 423 | 424 | Папка повторов 425 | 426 | 427 | Изм. vpatch.ini 428 | 429 | 430 | Настройки игры PC-98 431 | 432 | 433 | PCB 434 | 435 | 436 | PoDD 437 | 438 | 439 | PoFV 440 | 441 | 442 | Добавить всё 443 | 444 | 445 | Игры которые участвуют в случайном запуске 446 | 447 | 448 | Убрать всё 449 | 450 | 451 | Настройка случайных игр 452 | 453 | 454 | Переименовать категорию 455 | 456 | 457 | Повторы 458 | 459 | 460 | SA 461 | 462 | 463 | Настройки 464 | 465 | 466 | SoEW 467 | 468 | 469 | StB 470 | 471 | 472 | SWR 473 | 474 | 475 | TD 476 | 477 | 478 | UFO 479 | 480 | 481 | ULiL 482 | 483 | 484 | Hisoutensoku 485 | 486 | 487 | Вкл. Applocale 488 | 489 | 490 | VD 491 | 492 | 493 | Настройка игры Windows 494 | 495 | 496 | Все файлы 497 | 498 | 499 | По возрастанию 500 | 501 | 502 | Выбор чёрно-белой обложки 503 | 504 | 505 | Выбор цветной обложки 506 | 507 | 508 | Япон./vpatch.ini, Англ. (non-THCRAP), Custom.exe, thcrap 509 | 510 | 511 | Удалить 512 | 513 | 514 | По убыванию 515 | 516 | 517 | Детали 518 | 519 | 520 | Не удаётся найти папку Appdata 521 | 522 | 523 | Файл не найден 524 | 525 | 526 | Пожалуйста, укажите путь к Neko Project II 527 | 528 | 529 | Не удаётся открыть изображение: 530 | 531 | 532 | Папка повторов не найдена 533 | 534 | 535 | vpatch.ini не найден 536 | 537 | 538 | Исполняемый файл 539 | 540 | 541 | Выберите исполняемы файл 542 | 543 | 544 | Файлы образов жесткого диска 545 | 546 | 547 | Выберите игры в .HDI 548 | 549 | 550 | Файл изображения 551 | 552 | 553 | Крупные иконки 554 | 555 | 556 | Список 557 | 558 | 559 | Укажите путь к Neko Project II 560 | 561 | 562 | Папка Appdata 563 | 564 | 565 | Открыть папку 566 | 567 | 568 | Открыть с Applocale 569 | 570 | 571 | Запустить случайно 572 | 573 | 574 | Переименовать 575 | 576 | 577 | Мелкие иконки 578 | 579 | 580 | Сортировка 581 | 582 | 583 | Плитка 584 | 585 | 586 | Просмотр 587 | 588 | 589 | Файлы "ini" Neko Project II недействителен 590 | 591 | 592 | Игра не найдена. Please check the path in the right click menu. 593 | 594 | 595 | Файл повтров 596 | 597 | 598 | Скачать '{0}' в: 599 | '{1}' 600 | 601 | 602 | Повторы игрока заполнены и Touhou 10 не поддерживает пользовательские повторы. 603 | 604 | 605 | 606 | Настройка игры: 607 | 608 | 609 | Сворачивать в трей 610 | 611 | 612 | Всегда отображать иконку в трее 613 | 614 | 615 | Удалить категорию '{0}' и весь контент в ней? 616 | 617 | 618 | Удалить '{0}'? 619 | 620 | 621 | Пожалуйста, укажите путь к thcrap 622 | 623 | 624 | Настройка thcrap 625 | 626 | 627 | Путь к thcrap_loader: 628 | 629 | 630 | Пожалуйста, укажите профиль thcrap 631 | 632 | 633 | Не одна игра не выбрана 634 | 635 | 636 | Скачать повтор? 637 | 638 | 639 | Выход 640 | 641 | 642 | Открыть 643 | 644 | 645 | Случайная игра 646 | 647 | 648 | Удалить игру 649 | 650 | 651 | Описание 652 | 653 | 654 | Игровые профили 655 | 656 | 657 | ID игры 658 | 659 | 660 | ID 661 | 662 | 663 | Патч 664 | 665 | 666 | Кастомный профиль 667 | 668 | 669 | Путь игры 670 | 671 | 672 | Конфигурация профиля: 673 | 674 | 675 | Заглавие 676 | 677 | 678 | По умолчанию 679 | 680 | 681 | thcrap исходная папка: 682 | 683 | 684 | * 120 x 44 685 | 686 | 687 | Задать цвет 688 | 689 | 690 | Кастомный цвет текста 691 | 692 | 693 | Отображать обложки? 694 | 695 | 696 | Кнопка Изменить 697 | 698 | 699 | Отображать текст? 700 | 701 | 702 | выбранные патчи 703 | 704 | 705 | Wily Beast and Weakest Creature 706 | 707 | 708 | WBaWC 709 | 710 | 711 | Touhou 17: Wily Beast and Weakest Creature 712 | 713 | 714 | Unconnected Marketeers 715 | 716 | 717 | UM 718 | 719 | 720 | Touhou 18: Unconnected Marketeers 721 | 722 | 723 | Gouyoku Ibun 724 | 725 | 726 | GI 727 | 728 | 729 | Touhou 17.5: Gouyoku Ibun 730 | 731 | 732 | Не выбрана ни одна категория 733 | 734 | 735 | 100th Black Market 736 | 737 | 738 | 100BM 739 | 740 | 741 | Touhou 18.5: 100th Black Market 742 | 743 | 744 | Спиноффы 745 | 746 | 747 | Unfinished Dream of All Living Ghost 748 | 749 | 750 | UDoALG 751 | 752 | 753 | Touhou 19: Unfinished Dream of All Living Ghost 754 | 755 | -------------------------------------------------------------------------------- /Touhou Launcher/Touhou Launcher.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {DC2E240A-725B-4A6C-83B0-73DBAAB13D1D} 8 | WinExe 9 | Properties 10 | Touhou_Launcher 11 | Touhou Launcher 12 | v4.8 13 | 512 14 | 15 | 16 | 17 | AnyCPU 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | true 26 | false 27 | 28 | 29 | AnyCPU 30 | pdbonly 31 | true 32 | bin\Release\ 33 | TRACE 34 | prompt 35 | 4 36 | false 37 | 38 | 39 | thicon.ico 40 | 41 | 42 | 43 | jsonnet\Newtonsoft.Json.dll 44 | False 45 | global 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | Form 62 | 63 | 64 | MainForm.cs 65 | 66 | 67 | Form 68 | 69 | 70 | ConfigForm.cs 71 | 72 | 73 | 74 | 75 | True 76 | True 77 | Resources_en.resx 78 | 79 | 80 | True 81 | True 82 | Resources_jp.resx 83 | 84 | 85 | True 86 | True 87 | Resources_ru.resx 88 | 89 | 90 | Form 91 | 92 | 93 | thcrap.cs 94 | 95 | 96 | ConfigForm.cs 97 | 98 | 99 | MainForm.cs 100 | 101 | 102 | PublicResXFileCodeGenerator 103 | Resources.Designer.cs 104 | Designer 105 | 106 | 107 | True 108 | Resources.resx 109 | True 110 | 111 | 112 | PublicResXFileCodeGenerator 113 | Resources_en.Designer.cs 114 | 115 | 116 | PublicResXFileCodeGenerator 117 | Resources_jp.Designer.cs 118 | Designer 119 | 120 | 121 | PublicResXFileCodeGenerator 122 | Resources_ru.Designer.cs 123 | Designer 124 | 125 | 126 | thcrap.cs 127 | 128 | 129 | 130 | PublicSettingsSingleFileGenerator 131 | Settings.Designer.cs 132 | 133 | 134 | True 135 | Settings.settings 136 | True 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 152 | -------------------------------------------------------------------------------- /Touhou Launcher/app.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /Touhou Launcher/jsonnet/LICENSE.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | The MIT License (MIT) 4 | 5 | Copyright (c) 2007 James Newton-King 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 8 | 9 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 10 | 11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 12 | -------------------------------------------------------------------------------- /Touhou Launcher/jsonnet/Newtonsoft.Json.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/David-JonesDVN/Touhou-Relauncher/cae8d10958177629af911af3bfae711019d64376/Touhou Launcher/jsonnet/Newtonsoft.Json.dll -------------------------------------------------------------------------------- /Touhou Launcher/thcrap.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace Touhou_Launcher 2 | { 3 | partial class thcrap 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Windows Form Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(thcrap)); 32 | this.repoList = new System.Windows.Forms.ListView(); 33 | this.titleColumn = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); 34 | this.idColumn = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); 35 | this.gameList = new System.Windows.Forms.ListView(); 36 | this.gameIDColumn = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); 37 | this.pathColumn = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); 38 | this.path = new System.Windows.Forms.TextBox(); 39 | this.gameID = new System.Windows.Forms.Label(); 40 | this.gamePath = new System.Windows.Forms.Label(); 41 | this.gameGroup = new System.Windows.Forms.GroupBox(); 42 | this.id = new System.Windows.Forms.TextBox(); 43 | this.removeGame = new System.Windows.Forms.Button(); 44 | this.addGame = new System.Windows.Forms.Button(); 45 | this.browsePath = new System.Windows.Forms.Button(); 46 | this.patchGroup = new System.Windows.Forms.GroupBox(); 47 | this.patchList = new System.Windows.Forms.ListView(); 48 | this.patchColumn = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); 49 | this.descriptionColumn = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); 50 | this.gameGroup.SuspendLayout(); 51 | this.patchGroup.SuspendLayout(); 52 | this.SuspendLayout(); 53 | // 54 | // repoList 55 | // 56 | this.repoList.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) 57 | | System.Windows.Forms.AnchorStyles.Left))); 58 | this.repoList.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { 59 | this.titleColumn, 60 | this.idColumn}); 61 | this.repoList.FullRowSelect = true; 62 | this.repoList.GridLines = true; 63 | this.repoList.HeaderStyle = System.Windows.Forms.ColumnHeaderStyle.Nonclickable; 64 | this.repoList.HideSelection = false; 65 | this.repoList.Location = new System.Drawing.Point(6, 19); 66 | this.repoList.MultiSelect = false; 67 | this.repoList.Name = "repoList"; 68 | this.repoList.ShowItemToolTips = true; 69 | this.repoList.Size = new System.Drawing.Size(275, 319); 70 | this.repoList.TabIndex = 0; 71 | this.repoList.UseCompatibleStateImageBehavior = false; 72 | this.repoList.View = System.Windows.Forms.View.Details; 73 | this.repoList.SelectedIndexChanged += new System.EventHandler(this.repoList_SelectedIndexChanged); 74 | // 75 | // titleColumn 76 | // 77 | this.titleColumn.Name = "titleColumn"; 78 | this.titleColumn.Text = "Title"; 79 | this.titleColumn.Width = 175; 80 | // 81 | // idColumn 82 | // 83 | this.idColumn.Name = "idColumn"; 84 | this.idColumn.Text = "ID"; 85 | this.idColumn.Width = 95; 86 | // 87 | // gameList 88 | // 89 | this.gameList.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { 90 | this.gameIDColumn, 91 | this.pathColumn}); 92 | this.gameList.FullRowSelect = true; 93 | this.gameList.GridLines = true; 94 | this.gameList.HeaderStyle = System.Windows.Forms.ColumnHeaderStyle.Nonclickable; 95 | this.gameList.Location = new System.Drawing.Point(6, 19); 96 | this.gameList.Name = "gameList"; 97 | this.gameList.Size = new System.Drawing.Size(275, 115); 98 | this.gameList.TabIndex = 0; 99 | this.gameList.UseCompatibleStateImageBehavior = false; 100 | this.gameList.View = System.Windows.Forms.View.Details; 101 | this.gameList.SelectedIndexChanged += new System.EventHandler(this.gameList_SelectedIndexChanged); 102 | // 103 | // gameIDColumn 104 | // 105 | this.gameIDColumn.Name = "gameIDColumn"; 106 | this.gameIDColumn.Text = "Game ID"; 107 | this.gameIDColumn.Width = 87; 108 | // 109 | // pathColumn 110 | // 111 | this.pathColumn.Name = "pathColumn"; 112 | this.pathColumn.Text = "Game Path"; 113 | this.pathColumn.Width = 183; 114 | // 115 | // path 116 | // 117 | this.path.Location = new System.Drawing.Point(287, 74); 118 | this.path.Name = "path"; 119 | this.path.Size = new System.Drawing.Size(189, 20); 120 | this.path.TabIndex = 2; 121 | // 122 | // gameID 123 | // 124 | this.gameID.AutoSize = true; 125 | this.gameID.Location = new System.Drawing.Point(287, 19); 126 | this.gameID.Name = "gameID"; 127 | this.gameID.Size = new System.Drawing.Size(52, 13); 128 | this.gameID.TabIndex = 5; 129 | this.gameID.Text = "Game ID:"; 130 | // 131 | // gamePath 132 | // 133 | this.gamePath.AutoSize = true; 134 | this.gamePath.Location = new System.Drawing.Point(287, 58); 135 | this.gamePath.Name = "gamePath"; 136 | this.gamePath.Size = new System.Drawing.Size(63, 13); 137 | this.gamePath.TabIndex = 6; 138 | this.gamePath.Text = "Game Path:"; 139 | // 140 | // gameGroup 141 | // 142 | this.gameGroup.Controls.Add(this.id); 143 | this.gameGroup.Controls.Add(this.removeGame); 144 | this.gameGroup.Controls.Add(this.addGame); 145 | this.gameGroup.Controls.Add(this.browsePath); 146 | this.gameGroup.Controls.Add(this.gamePath); 147 | this.gameGroup.Controls.Add(this.gameList); 148 | this.gameGroup.Controls.Add(this.gameID); 149 | this.gameGroup.Controls.Add(this.path); 150 | this.gameGroup.Location = new System.Drawing.Point(9, 362); 151 | this.gameGroup.Margin = new System.Windows.Forms.Padding(0); 152 | this.gameGroup.Name = "gameGroup"; 153 | this.gameGroup.Size = new System.Drawing.Size(563, 140); 154 | this.gameGroup.TabIndex = 1; 155 | this.gameGroup.TabStop = false; 156 | this.gameGroup.Text = "Game Profiles"; 157 | // 158 | // id 159 | // 160 | this.id.Location = new System.Drawing.Point(290, 36); 161 | this.id.Name = "id"; 162 | this.id.Size = new System.Drawing.Size(267, 20); 163 | this.id.TabIndex = 1; 164 | // 165 | // removeGame 166 | // 167 | this.removeGame.Location = new System.Drawing.Point(427, 111); 168 | this.removeGame.Name = "removeGame"; 169 | this.removeGame.Size = new System.Drawing.Size(130, 23); 170 | this.removeGame.TabIndex = 5; 171 | this.removeGame.Text = "Remove Game"; 172 | this.removeGame.UseVisualStyleBackColor = true; 173 | this.removeGame.Click += new System.EventHandler(this.removeGame_Click); 174 | // 175 | // addGame 176 | // 177 | this.addGame.Location = new System.Drawing.Point(290, 111); 178 | this.addGame.Name = "addGame"; 179 | this.addGame.Size = new System.Drawing.Size(130, 23); 180 | this.addGame.TabIndex = 4; 181 | this.addGame.Text = "Add Game"; 182 | this.addGame.UseVisualStyleBackColor = true; 183 | this.addGame.Click += new System.EventHandler(this.addGame_Click); 184 | // 185 | // browsePath 186 | // 187 | this.browsePath.Location = new System.Drawing.Point(482, 72); 188 | this.browsePath.Name = "browsePath"; 189 | this.browsePath.Size = new System.Drawing.Size(75, 23); 190 | this.browsePath.TabIndex = 3; 191 | this.browsePath.Text = "Browse"; 192 | this.browsePath.UseVisualStyleBackColor = true; 193 | this.browsePath.Click += new System.EventHandler(this.browsePath_Click); 194 | // 195 | // patchGroup 196 | // 197 | this.patchGroup.Controls.Add(this.patchList); 198 | this.patchGroup.Controls.Add(this.repoList); 199 | this.patchGroup.Location = new System.Drawing.Point(9, 9); 200 | this.patchGroup.Margin = new System.Windows.Forms.Padding(0); 201 | this.patchGroup.Name = "patchGroup"; 202 | this.patchGroup.Size = new System.Drawing.Size(566, 347); 203 | this.patchGroup.TabIndex = 0; 204 | this.patchGroup.TabStop = false; 205 | this.patchGroup.Text = "Custom Profile"; 206 | // 207 | // patchList 208 | // 209 | this.patchList.CheckBoxes = true; 210 | this.patchList.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { 211 | this.patchColumn, 212 | this.descriptionColumn}); 213 | this.patchList.FullRowSelect = true; 214 | this.patchList.GridLines = true; 215 | this.patchList.HeaderStyle = System.Windows.Forms.ColumnHeaderStyle.Nonclickable; 216 | this.patchList.HideSelection = false; 217 | this.patchList.Location = new System.Drawing.Point(287, 19); 218 | this.patchList.MultiSelect = false; 219 | this.patchList.Name = "patchList"; 220 | this.patchList.ShowItemToolTips = true; 221 | this.patchList.Size = new System.Drawing.Size(273, 319); 222 | this.patchList.TabIndex = 1; 223 | this.patchList.UseCompatibleStateImageBehavior = false; 224 | this.patchList.View = System.Windows.Forms.View.Details; 225 | // 226 | // patchColumn 227 | // 228 | this.patchColumn.Name = "patchColumn"; 229 | this.patchColumn.Text = "Patch"; 230 | this.patchColumn.Width = 100; 231 | // 232 | // descriptionColumn 233 | // 234 | this.descriptionColumn.Name = "descriptionColumn"; 235 | this.descriptionColumn.Text = "Description"; 236 | this.descriptionColumn.Width = 169; 237 | // 238 | // thcrap 239 | // 240 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); 241 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 242 | this.ClientSize = new System.Drawing.Size(584, 512); 243 | this.Controls.Add(this.patchGroup); 244 | this.Controls.Add(this.gameGroup); 245 | this.Icon = global::Touhou_Launcher.Properties.Resources.thicon; 246 | this.Name = "thcrap"; 247 | this.Text = "Profile Configuration: "; 248 | this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.thcrap_Closing); 249 | this.Load += new System.EventHandler(this.thcrap_Load); 250 | this.gameGroup.ResumeLayout(false); 251 | this.gameGroup.PerformLayout(); 252 | this.patchGroup.ResumeLayout(false); 253 | this.ResumeLayout(false); 254 | 255 | } 256 | 257 | #endregion 258 | 259 | private System.Windows.Forms.ListView repoList; 260 | private System.Windows.Forms.ColumnHeader titleColumn; 261 | private System.Windows.Forms.ColumnHeader idColumn; 262 | private System.Windows.Forms.ListView gameList; 263 | private System.Windows.Forms.ColumnHeader gameIDColumn; 264 | private System.Windows.Forms.ColumnHeader pathColumn; 265 | private System.Windows.Forms.TextBox path; 266 | private System.Windows.Forms.Label gameID; 267 | private System.Windows.Forms.Label gamePath; 268 | private System.Windows.Forms.GroupBox gameGroup; 269 | private System.Windows.Forms.Button removeGame; 270 | private System.Windows.Forms.Button addGame; 271 | private System.Windows.Forms.Button browsePath; 272 | private System.Windows.Forms.GroupBox patchGroup; 273 | private System.Windows.Forms.ListView patchList; 274 | private System.Windows.Forms.ColumnHeader patchColumn; 275 | private System.Windows.Forms.ColumnHeader descriptionColumn; 276 | private System.Windows.Forms.TextBox id; 277 | 278 | } 279 | } -------------------------------------------------------------------------------- /Touhou Launcher/thcrap.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Windows.Forms; 6 | using System.IO; 7 | using System.Net; 8 | using Newtonsoft.Json; 9 | 10 | namespace Touhou_Launcher 11 | { 12 | public partial class thcrap : Form 13 | { 14 | internal class repoData 15 | { 16 | public string contact = ""; 17 | public string id = ""; 18 | public List neighbors = new List(); 19 | public Dictionary patches = new Dictionary(); 20 | public List servers = new List(); 21 | public string title = ""; 22 | } 23 | 24 | internal class patchData 25 | { 26 | public List dependencies = new List(); 27 | public string id = ""; 28 | public List servers = new List(); 29 | public string title = ""; 30 | public Dictionary fonts = new Dictionary(); 31 | } 32 | 33 | internal class profileData 34 | { 35 | public bool console = false; 36 | public bool dat_dump = false; 37 | public List> patches = new List>(); 38 | } 39 | 40 | ConfigForm cfgForm; 41 | string gamejs; 42 | Dictionary repos = new Dictionary(); 43 | List checkedRepos = new List(); 44 | List patchStates = new List(); 45 | Dictionary games = new Dictionary(); 46 | Queue repoQueue = new Queue(); 47 | 48 | private void InitializeLanguage() 49 | { 50 | this.Text = MainForm.rm.GetString("thcrapTitle") + MainForm.rm.GetString(MainForm.nameToID.FirstOrDefault(t => t.Value == cfgForm.game).Key); 51 | foreach (ListView list in MainForm.GetAll(this, typeof(ListView))) 52 | { 53 | foreach (ColumnHeader column in list.Columns) 54 | { 55 | column.Text = MainForm.rm.GetString(column.Name); 56 | } 57 | } 58 | gameGroup.Text = MainForm.rm.GetString("gameGroup"); 59 | patchGroup.Text = MainForm.rm.GetString("patchGroup"); 60 | gameID.Text = MainForm.rm.GetString("gameIDColumn") + ":"; 61 | gamePath.Text = MainForm.rm.GetString("pathColumn") + ":"; 62 | browsePath.Text = MainForm.rm.GetString("browse"); 63 | addGame.Text = MainForm.rm.GetString("customAdd"); 64 | removeGame.Text = MainForm.rm.GetString("customRemove"); 65 | } 66 | 67 | private void RefreshProfiles() 68 | { 69 | gameList.Items.Clear(); 70 | foreach (KeyValuePair game in games) 71 | { 72 | ListViewItem gameID = gameList.Items.Add(game.Key); 73 | gameID.SubItems.Add(game.Value); 74 | } 75 | } 76 | 77 | public thcrap(ConfigForm cfg) 78 | { 79 | cfgForm = cfg; 80 | gamejs = MainForm.curCfg.crapDir + "\\config\\launcher" + MainForm.idToNumber[cfg.game] + ".js"; 81 | InitializeComponent(); 82 | InitializeLanguage(); 83 | } 84 | 85 | private void thcrap_Load(object sender, EventArgs e) 86 | { 87 | repoList.Items.Add(MainForm.rm.GetString("selectedPatches")); 88 | if (File.Exists(gamejs)) 89 | { 90 | profileData profile = JsonConvert.DeserializeObject(File.ReadAllText(gamejs)); 91 | foreach (Dictionary patch in profile.patches) 92 | { 93 | if (!patchStates.Contains(patch["archive"])) 94 | patchStates.Add(patch["archive"].Substring(6)); 95 | } 96 | } 97 | foreach (FileInfo localRepo in new DirectoryInfo(MainForm.curCfg.crapDir).CreateSubdirectory("repos").GetFiles("repo.js", SearchOption.AllDirectories)) 98 | { 99 | addRepo(File.ReadAllText(localRepo.FullName), true); 100 | } 101 | searchRepo(MainForm.curCfg.StartingRepo); 102 | if (File.Exists(MainForm.curCfg.crapDir + "\\config\\games.js")) 103 | games = JsonConvert.DeserializeObject>(File.ReadAllText(MainForm.curCfg.crapDir + "\\config\\games.js")); 104 | for (int i = 0; i < 3; i += 2) 105 | { 106 | if (MainForm.curCfg.gameCFG[cfgForm.game].GameDir[i] != "" && !games.ContainsValue(MainForm.curCfg.gameCFG[cfgForm.game].GameDir[i].Replace("\\", "/"))) 107 | { 108 | string augment = i == 2 ? "_custom" : ""; 109 | games.Add("th" + (MainForm.idToNumber[cfgForm.game]).ToString("00") + augment, MainForm.curCfg.gameCFG[cfgForm.game].GameDir[i].Replace("\\", "/")); 110 | } 111 | } 112 | RefreshProfiles(); 113 | } 114 | 115 | private async void searchRepo(string address) 116 | { 117 | WebClient wc = new WebClient(); 118 | wc.Encoding = Encoding.UTF8; 119 | while (true) 120 | { 121 | if (!checkedRepos.Contains(address)) 122 | { 123 | try 124 | { 125 | addRepo(await wc.DownloadStringTaskAsync(address + "/repo.js")); 126 | checkedRepos.Add(address); 127 | } 128 | catch (Exception ex) 129 | { 130 | /* Code for exploring the thcrap mirror manually. 131 | using (var reader = new StreamReader(WebRequest.Create(address).GetResponse().GetResponseStream())) 132 | { 133 | string result = reader.ReadToEnd(); 134 | System.Text.RegularExpressions.MatchCollection matches = new System.Text.RegularExpressions.Regex("(?.*)").Matches(result); 135 | //Alt Regex: ]*?\s+)?href=(["'])(.*?)\1 136 | foreach (System.Text.RegularExpressions.Match match in matches) 137 | { 138 | if (!match.Success) { continue; } 139 | if (match.Groups["name"].Value.EndsWith("/")) 140 | searchRepo(address + match.Groups["name"].Value, true); 141 | } 142 | } 143 | */ 144 | } 145 | } 146 | if (repoQueue.Count > 0) 147 | { 148 | address = repoQueue.Dequeue(); 149 | } 150 | else break; 151 | } 152 | } 153 | 154 | private void addRepo(string repojs, bool offline = false) 155 | { 156 | try 157 | { 158 | repoData data = JsonConvert.DeserializeObject(repojs); 159 | FileInfo jsPath = new FileInfo(MainForm.curCfg.crapDir + "\\repos\\" + data.id + "\\repo.js"); 160 | jsPath.Directory.Create(); 161 | File.WriteAllText(jsPath.FullName, repojs); 162 | if (!repoList.Items.ContainsKey(data.id) || (bool)repoList.Items[data.id].Tag == true) 163 | { 164 | foreach (string neighbor in data.neighbors) 165 | { 166 | repoQueue.Enqueue(neighbor); 167 | } 168 | repos[data.id] = data; 169 | if (!repoList.Items.ContainsKey(data.id)) 170 | { 171 | ListViewItem title = repoList.Items.Add(data.title); 172 | title.Name = data.id; 173 | title.Tag = offline; 174 | title.SubItems.Add(data.id); 175 | } 176 | else 177 | { 178 | ListViewItem title = repoList.Items[data.id]; 179 | title.Tag = offline; 180 | } 181 | repoList_SelectedIndexChanged(repoList.Items[data.id], new EventArgs()); 182 | } 183 | } 184 | catch (Exception ex) 185 | { 186 | MessageBox.Show(ex.ToString()); 187 | } 188 | } 189 | 190 | private void onPatchGet(object sender, DownloadStringCompletedEventArgs e) 191 | { 192 | if (e.Error == null) 193 | { 194 | patchData patch = JsonConvert.DeserializeObject(e.Result); 195 | FileInfo jsPath = new FileInfo(MainForm.curCfg.crapDir + "\\repos\\" + (string)e.UserState + "\\" + patch.id + "\\patch.js"); 196 | jsPath.Directory.Create(); 197 | File.WriteAllText(jsPath.FullName, e.Result); 198 | foreach (string dependency in patch.dependencies) 199 | { 200 | string[] dependencySet = dependency.Split('/'); 201 | string repository = ""; 202 | if (dependencySet.Length == 1) 203 | { 204 | foreach (KeyValuePair repo in repos) 205 | { 206 | if (repo.Value.patches.ContainsKey(dependencySet[0])) 207 | { 208 | repository = repo.Key; 209 | } 210 | } 211 | } 212 | else 213 | repository = dependencySet[0]; 214 | addPatch(repository, dependencySet[dependencySet.Length - 1], patchStates.IndexOf((string)e.UserState + "/" + patch.id + "/")); 215 | } 216 | } 217 | } 218 | 219 | private void addPatch(string repo, string patch, int dependent = -1) 220 | { 221 | if (!patchStates.Contains(repo + "/" + patch + "/")) 222 | { 223 | patchStates.Insert(dependent == -1 ? patchStates.Count : dependent, repo + "/" + patch + "/"); 224 | repoList_SelectedIndexChanged(repoList.Items[repo], new EventArgs()); 225 | } 226 | WebClient wc = new WebClient(); 227 | wc.Encoding = Encoding.UTF8; 228 | wc.DownloadStringCompleted += onPatchGet; 229 | wc.DownloadStringAsync(new Uri(repos[repo].servers[0] + "/" + patch + "/patch.js"), repo); 230 | } 231 | 232 | private void thcrap_Closing(object sender, FormClosingEventArgs e) 233 | { 234 | profileData profile = new profileData(); 235 | foreach (string patch in patchStates) 236 | { 237 | profile.patches.Add(new Dictionary { {"archive", "repos/" + patch} }); 238 | } 239 | File.WriteAllText(gamejs, JsonConvert.SerializeObject(profile, Formatting.Indented)); 240 | Dictionary games = new Dictionary(); 241 | foreach (ListViewItem game in gameList.Items) 242 | { 243 | games[game.Text] = game.SubItems[1].Text; 244 | } 245 | File.WriteAllText(MainForm.curCfg.crapDir + "\\config\\games.js", JsonConvert.SerializeObject(games, Formatting.Indented)); 246 | cfgForm.Refreshcrap(); 247 | } 248 | 249 | private void repoList_SelectedIndexChanged(object sender, EventArgs e) 250 | { 251 | if (sender == repoList || repoList.SelectedItems.Contains((ListViewItem)sender) || repoList.SelectedIndices.Contains(0)) 252 | { 253 | patchList.Items.Clear(); 254 | if (repoList.SelectedItems.Count > 0) 255 | { 256 | patchList.ItemChecked -= patchList_ItemChecked; 257 | if (repoList.SelectedIndices[0] == 0) 258 | { 259 | foreach (string patch in patchStates) 260 | { 261 | string[] patchSet = patch.Split('/'); 262 | ListViewItem title = patchList.Items.Add(patch); 263 | title.SubItems.Add(repos[patchSet[0]].patches[patchSet[1]]); 264 | title.Checked = true; 265 | } 266 | } 267 | else 268 | { 269 | foreach (KeyValuePair patch in repos[repoList.SelectedItems[0].SubItems[1].Text].patches) 270 | { 271 | ListViewItem title = patchList.Items.Add(patch.Key); 272 | title.SubItems.Add(patch.Value); 273 | title.Checked = patchStates.Contains(repoList.SelectedItems[0].SubItems[1].Text + "/" + patch.Key + "/"); 274 | } 275 | } 276 | patchList.ItemChecked += patchList_ItemChecked; 277 | } 278 | } 279 | } 280 | 281 | private void patchList_ItemChecked(object sender, ItemCheckedEventArgs e) 282 | { 283 | string id = repoList.SelectedIndices[0] == 0 ? e.Item.Text : repoList.SelectedItems[0].SubItems[1].Text + "/" + e.Item.Text + "/"; 284 | if (e.Item.Checked) 285 | { 286 | addPatch(repoList.SelectedItems[0].SubItems[1].Text, e.Item.Text); 287 | } 288 | else 289 | { 290 | patchStates.Remove(id); 291 | if (repoList.SelectedIndices[0] == 0) 292 | e.Item.Remove(); 293 | } 294 | } 295 | 296 | private void browsePath_Click(object sender, EventArgs e) 297 | { 298 | foreach (string file in MainForm.FileBrowser(MainForm.rm.GetString("gameSelectTitle"), MainForm.rm.GetString("executableFilter") + " (*.exe, *.bat, *.lnk)|*.exe;*.bat;*.lnk|" + MainForm.rm.GetString("allFilter") + " (*.*)|*.*")) 299 | path.Text = file; 300 | } 301 | 302 | private void addGame_Click(object sender, EventArgs e) 303 | { 304 | if (File.Exists(path.Text)) 305 | { 306 | games[id.Text] = path.Text.Replace("\\", "/"); 307 | RefreshProfiles(); 308 | } 309 | } 310 | 311 | private void removeGame_Click(object sender, EventArgs e) 312 | { 313 | games.Remove(id.Text); 314 | RefreshProfiles(); 315 | } 316 | 317 | private void gameList_SelectedIndexChanged(object sender, EventArgs e) 318 | { 319 | if (gameList.SelectedItems.Count > 0) 320 | { 321 | id.Text = gameList.SelectedItems[0].Text; 322 | path.Text = gameList.SelectedItems[0].SubItems[1].Text.Replace("/", "\\"); 323 | } 324 | } 325 | } 326 | } 327 | -------------------------------------------------------------------------------- /Touhou Launcher/thcrap.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | -------------------------------------------------------------------------------- /Touhou Launcher/thicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/David-JonesDVN/Touhou-Relauncher/cae8d10958177629af911af3bfae711019d64376/Touhou Launcher/thicon.ico --------------------------------------------------------------------------------