├── BulkImporter ├── BulkEggGenerator.csproj ├── BulkImporter.sln └── BulkEggGenerator.cs ├── BulkEggGenerator.sln ├── .gitattributes ├── README.md └── .gitignore /BulkImporter/BulkEggGenerator.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net90-windows 5 | 6 | Library 7 | 8 8 | enable 9 | 2.0.0 10 | true 11 | true 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /BulkImporter/BulkImporter.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.31129.286 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BulkImporter", "BulkImporter.csproj", "{EAE93960-86AE-480D-8578-EAFC2CE10A05}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {EAE93960-86AE-480D-8578-EAFC2CE10A05}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {EAE93960-86AE-480D-8578-EAFC2CE10A05}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {EAE93960-86AE-480D-8578-EAFC2CE10A05}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {EAE93960-86AE-480D-8578-EAFC2CE10A05}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {29E2C562-F23D-4420-9BFE-CCA6FDB15FEB} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /BulkEggGenerator.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.14.36109.1 d17.14 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BulkEggGenerator", "BulkImporter\BulkEggGenerator.csproj", "{A2DB1F31-4192-4965-B720-D36BF522DCA3}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {A2DB1F31-4192-4965-B720-D36BF522DCA3}.Debug|Any CPU.ActiveCfg = Release|Any CPU 15 | {A2DB1F31-4192-4965-B720-D36BF522DCA3}.Debug|Any CPU.Build.0 = Release|Any CPU 16 | {A2DB1F31-4192-4965-B720-D36BF522DCA3}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {A2DB1F31-4192-4965-B720-D36BF522DCA3}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {CBADA77B-A43F-4D2C-A8DE-14DB59E67D8F} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PKHeX Bulk Egg Generator 2 | ## About 3 | Previously called the Bulk Pokemon Importer. The Bulk Egg Generator is a PKHeX plugin that allows you to generate eggs in your Pokemon save files. There are additional options that allow the user to control certain aspects of the generated eggs, such as their typing, IVs, nature, and so on. 4 | 5 | ## Current Features 6 | * Generate one egg per Pokemon species 7 | * Restrict the generated eggs by one or more types, and opt to consider the eggs' future evolutions 8 | * Set the minimum and maxiumum IV values you want the generated eggs to have 9 | * Set the chance of a Pokemon being shiny 10 | * Set the chance of a Pokemon having its Hidden Ability (gen 5+) 11 | * Set the chance of a Pokemon having egg moves 12 | 13 | ## Installation 14 | - If it does not already exist, create a `plugins` folder in the same directory as `PKHeX.exe`. 15 | - Download the latest version of BulkEggGenerator from the releases page. 16 | - Place `BulkEggGenerator.dll` to the `plugins` folder. 17 | 18 | Example file structure: 19 | ``` 20 | PKHeX/ 21 | |- PKHeX.exe 22 | |- plugins/ 23 | |-- BulkEggGenerator.dll 24 | ``` 25 | 26 | 27 | ## Usage 28 | Once the plugin has been installed, you will see an option for "Egg Generator" appear under the "Tools" menu in PKHeX. Clicking on it will open the egg generation menu, where you can set the percentage for shiny chance, hidden ability chance, and so on. When you are satisfied, click "Generate Eggs" to populate your boxes with Pokemon eggs. 29 | 30 | ## Known Issues & FAQ 31 | ### I can't see the Egg Generator in the menu 32 | PKHeX sometimes fails to load plugins. You can keep closing and re-opening it to try (which is admittedly annoying), or change its `PluginLoadMethod`. You can do this by going to `Options > Settings > Startup` and changing `PluginLoadMethod` to `LoadFromFile`. Restart PKHeX after making the changes. You may still have to close and reopen PKHeX once or twice, but not nearly as many times as before. 33 | 34 | ### Shiny Pokemon In Gold/Silver/Crystal ignore the min/max IV settings! 35 | This is expected behaviour, and it's because of the way shinies work in Gen 2. From Gen 3 onward, shininess is determined by three things: the Pokemon's original trainer's ID and secret ID, and the Pokemon's personality value. In Gen 2, however, shininess is determined by the Pokemon's IVs. For a Pokemon to be shiny in Gen 2, it must have a value of 10 for its Speed, Defense, and Special IVs, and a value of 2, 3, 6, 7, 10, 11, 14 or 15 for its Attack IV. 36 | 37 | You can read more about the mechanic here. 38 | 39 | ### PKHeX is flagging all Scarlet & Violet Pokemon as illegal 40 | The Pokemon being generated *are* legal; PKHeX just has issues recognizing them as such. You can verify this by selecting any Pokemon, and unchecking and re-checking the `Is Egg` option in the `Main` tab. If you then click the error icon, it will change to the valid icon. 41 | 42 | This is a known issue, and is being looked into. 43 | 44 | ### PKHeX is flagging the generated Pokemon as illegal, but when I check each Pokemon individually it says they're fine 45 | This is a known issue, and a solution is being looked into. It affects the following games: 46 | * X and Y 47 | * Omega Ruby and Alpha Sapphire 48 | * Ruby, Sapphire, and Emerald 49 | * FireRed and LeafGreen 50 | 51 | ### One or more of the generated Pokemon is illegal 52 | Please log an issue in the issues tab, and include the problems PKHeX has with the Pokemon. 53 | 54 | 55 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | x64/ 19 | x86/ 20 | bld/ 21 | [Bb]in/ 22 | [Oo]bj/ 23 | [Ll]og/ 24 | 25 | # Visual Studio 2015 cache/options directory 26 | .vs/ 27 | # Uncomment if you have tasks that create the project's static files in wwwroot 28 | #wwwroot/ 29 | 30 | # MSTest test Results 31 | [Tt]est[Rr]esult*/ 32 | [Bb]uild[Ll]og.* 33 | 34 | # NUNIT 35 | *.VisualState.xml 36 | TestResult.xml 37 | 38 | # Build Results of an ATL Project 39 | [Dd]ebugPS/ 40 | [Rr]eleasePS/ 41 | dlldata.c 42 | 43 | # DNX 44 | project.lock.json 45 | project.fragment.lock.json 46 | artifacts/ 47 | 48 | *_i.c 49 | *_p.c 50 | *_i.h 51 | *.ilk 52 | *.meta 53 | *.obj 54 | *.pch 55 | *.pdb 56 | *.pgc 57 | *.pgd 58 | *.rsp 59 | *.sbr 60 | *.tlb 61 | *.tli 62 | *.tlh 63 | *.tmp 64 | *.tmp_proj 65 | *.log 66 | *.vspscc 67 | *.vssscc 68 | .builds 69 | *.pidb 70 | *.svclog 71 | *.scc 72 | 73 | # Chutzpah Test files 74 | _Chutzpah* 75 | 76 | # Visual C++ cache files 77 | ipch/ 78 | *.aps 79 | *.ncb 80 | *.opendb 81 | *.opensdf 82 | *.sdf 83 | *.cachefile 84 | *.VC.db 85 | *.VC.VC.opendb 86 | 87 | # Visual Studio profiler 88 | *.psess 89 | *.vsp 90 | *.vspx 91 | *.sap 92 | 93 | # TFS 2012 Local Workspace 94 | $tf/ 95 | 96 | # Guidance Automation Toolkit 97 | *.gpState 98 | 99 | # ReSharper is a .NET coding add-in 100 | _ReSharper*/ 101 | *.[Rr]e[Ss]harper 102 | *.DotSettings.user 103 | 104 | # JustCode is a .NET coding add-in 105 | .JustCode 106 | 107 | # TeamCity is a build add-in 108 | _TeamCity* 109 | 110 | # DotCover is a Code Coverage Tool 111 | *.dotCover 112 | 113 | # NCrunch 114 | _NCrunch_* 115 | .*crunch*.local.xml 116 | nCrunchTemp_* 117 | 118 | # MightyMoose 119 | *.mm.* 120 | AutoTest.Net/ 121 | 122 | # Web workbench (sass) 123 | .sass-cache/ 124 | 125 | # Installshield output folder 126 | [Ee]xpress/ 127 | 128 | # DocProject is a documentation generator add-in 129 | DocProject/buildhelp/ 130 | DocProject/Help/*.HxT 131 | DocProject/Help/*.HxC 132 | DocProject/Help/*.hhc 133 | DocProject/Help/*.hhk 134 | DocProject/Help/*.hhp 135 | DocProject/Help/Html2 136 | DocProject/Help/html 137 | 138 | # Click-Once directory 139 | publish/ 140 | 141 | # Publish Web Output 142 | *.[Pp]ublish.xml 143 | *.azurePubxml 144 | # TODO: Comment the next line if you want to checkin your web deploy settings 145 | # but database connection strings (with potential passwords) will be unencrypted 146 | #*.pubxml 147 | *.publishproj 148 | 149 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 150 | # checkin your Azure Web App publish settings, but sensitive information contained 151 | # in these scripts will be unencrypted 152 | PublishScripts/ 153 | 154 | # NuGet Packages 155 | *.nupkg 156 | # The packages folder can be ignored because of Package Restore 157 | **/packages/* 158 | # except build/, which is used as an MSBuild target. 159 | !**/packages/build/ 160 | # Uncomment if necessary however generally it will be regenerated when needed 161 | #!**/packages/repositories.config 162 | # NuGet v3's project.json files produces more ignoreable files 163 | *.nuget.props 164 | *.nuget.targets 165 | 166 | # Microsoft Azure Build Output 167 | csx/ 168 | *.build.csdef 169 | 170 | # Microsoft Azure Emulator 171 | ecf/ 172 | rcf/ 173 | 174 | # Windows Store app package directories and files 175 | AppPackages/ 176 | BundleArtifacts/ 177 | Package.StoreAssociation.xml 178 | _pkginfo.txt 179 | 180 | # Visual Studio cache files 181 | # files ending in .cache can be ignored 182 | *.[Cc]ache 183 | # but keep track of directories ending in .cache 184 | !*.[Cc]ache/ 185 | 186 | # Others 187 | ClientBin/ 188 | ~$* 189 | *~ 190 | *.dbmdl 191 | *.dbproj.schemaview 192 | *.jfm 193 | *.pfx 194 | *.publishsettings 195 | node_modules/ 196 | orleans.codegen.cs 197 | 198 | # Since there are multiple workflows, uncomment next line to ignore bower_components 199 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 200 | #bower_components/ 201 | 202 | # RIA/Silverlight projects 203 | Generated_Code/ 204 | 205 | # Backup & report files from converting an old project file 206 | # to a newer Visual Studio version. Backup files are not needed, 207 | # because we have git ;-) 208 | _UpgradeReport_Files/ 209 | Backup*/ 210 | UpgradeLog*.XML 211 | UpgradeLog*.htm 212 | 213 | # SQL Server files 214 | *.mdf 215 | *.ldf 216 | 217 | # Business Intelligence projects 218 | *.rdl.data 219 | *.bim.layout 220 | *.bim_*.settings 221 | 222 | # Microsoft Fakes 223 | FakesAssemblies/ 224 | 225 | # GhostDoc plugin setting file 226 | *.GhostDoc.xml 227 | 228 | # Node.js Tools for Visual Studio 229 | .ntvs_analysis.dat 230 | 231 | # Visual Studio 6 build log 232 | *.plg 233 | 234 | # Visual Studio 6 workspace options file 235 | *.opt 236 | 237 | # Visual Studio LightSwitch build output 238 | **/*.HTMLClient/GeneratedArtifacts 239 | **/*.DesktopClient/GeneratedArtifacts 240 | **/*.DesktopClient/ModelManifest.xml 241 | **/*.Server/GeneratedArtifacts 242 | **/*.Server/ModelManifest.xml 243 | _Pvt_Extensions 244 | 245 | # Paket dependency manager 246 | .paket/paket.exe 247 | paket-files/ 248 | 249 | # FAKE - F# Make 250 | .fake/ 251 | 252 | # JetBrains Rider 253 | .idea/ 254 | *.sln.iml 255 | 256 | # CodeRush 257 | .cr/ 258 | 259 | # Python Tools for Visual Studio (PTVS) 260 | __pycache__/ 261 | *.pyc -------------------------------------------------------------------------------- /BulkImporter/BulkEggGenerator.cs: -------------------------------------------------------------------------------- 1 | using PKHeX.Core; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Windows.Forms; 6 | 7 | namespace BulkEggGenerator 8 | { 9 | public class BulkEggGenerator : IPlugin 10 | { 11 | public string Name => nameof(BulkEggGenerator); 12 | public int Priority => 1; // Loading order, lowest is first. 13 | 14 | // Initialized on plugin load 15 | // Initialized on plugin load 16 | public ISaveFileProvider SaveFileEditor { get; private set; } = null!; 17 | public IPKMView PKMEditor { get; private set; } = null!; 18 | 19 | // Random number generator for form generation 20 | Random random = new Random(); 21 | 22 | // UI Forms 23 | private Form form = new Form(); 24 | private TextBox input = new TextBox(); 25 | 26 | private NumericUpDown numberToGenerate = new NumericUpDown(); 27 | private NumericUpDown shinyChance = new NumericUpDown(); 28 | private NumericUpDown eggMoveChance = new NumericUpDown(); 29 | private NumericUpDown hiddenAbilityChance = new NumericUpDown(); 30 | private NumericUpDown maxIVValue = new NumericUpDown(); 31 | private NumericUpDown minIVValue = new NumericUpDown(); 32 | 33 | private CheckedListBox typeSelection = new CheckedListBox(); 34 | private CheckBox considerFutureTypesYes = new CheckBox(); 35 | private CheckBox allowDuplicates = new CheckBox(); 36 | 37 | // Plugin initialization 38 | public void Initialize(params object[] args) 39 | { 40 | Console.WriteLine($"Loading {Name}..."); 41 | 42 | SaveFileEditor = (ISaveFileProvider)Array.Find(args, z => z is ISaveFileProvider); 43 | PKMEditor = (IPKMView)Array.Find(args, z => z is IPKMView); 44 | 45 | var menu = (ToolStrip)Array.Find(args, z => z is ToolStrip); 46 | var items = menu.Items; 47 | if (!(items.Find("Menu_Tools", false)[0] is ToolStripDropDownItem tools)) 48 | return; 49 | 50 | foreach (ToolStripItem item in tools.DropDownItems) 51 | { 52 | if (item.Name == "Egg Generator") 53 | { 54 | return; 55 | } 56 | } 57 | 58 | var menuItem = new ToolStripMenuItem("Egg Generator"); 59 | menuItem.Click += (sender, eventArgs) => generateForm(); 60 | tools.DropDownItems.Add(menuItem); 61 | 62 | NotifySaveLoaded(); 63 | } 64 | 65 | // Create the UI for the importer 66 | public void generateForm() 67 | { 68 | SaveFile sav = SaveFileEditor.SAV; // current savefile 69 | 70 | List formControls = new List(); 71 | Button createButton = new Button(); 72 | 73 | string[] pokemonTypes = { "Select All", "Normal", "Fire", "Fighting", "Water", "Flying", "Grass", "Poison", "Electric", "Ground", "Psychic", "Rock", "Ice", "Bug", "Dragon", "Ghost", "Dark", "Steel", "Fairy" }; 74 | typeSelection.Items.AddRange(pokemonTypes); 75 | 76 | // Set up form 77 | form.Size = new System.Drawing.Size(390, 500); 78 | form.Name = "Egg Generator"; 79 | 80 | // Set up Type Selection 81 | formControls.Add(new Label 82 | { 83 | Location = new System.Drawing.Point(8, 10), 84 | AutoSize = true, 85 | Text = "Types", 86 | Font = new System.Drawing.Font(Control.DefaultFont, System.Drawing.FontStyle.Bold) 87 | }); 88 | 89 | typeSelection.Location = new System.Drawing.Point(10, 30); 90 | typeSelection.Size = new System.Drawing.Size(150, 350); 91 | typeSelection.SelectedValueChanged += new EventHandler(SelectOrDeselectAllTypes); 92 | 93 | formControls.Add(new Label 94 | { 95 | Location = new System.Drawing.Point(170, 270), 96 | AutoSize = true, 97 | Text = "Consider typing of future\nevolutions?", 98 | Font = new System.Drawing.Font(Control.DefaultFont, System.Drawing.FontStyle.Bold) 99 | }); 100 | 101 | considerFutureTypesYes.Text = "Yes"; 102 | considerFutureTypesYes.Location = new System.Drawing.Point(175, 300); 103 | considerFutureTypesYes.TextAlign = System.Drawing.ContentAlignment.TopLeft; 104 | considerFutureTypesYes.AutoSize = true; 105 | considerFutureTypesYes.Checked = false; 106 | considerFutureTypesYes.Name = "considerFutureTypes"; 107 | 108 | ToolTip futureTypesTooltip = new ToolTip(); 109 | futureTypesTooltip.SetToolTip(considerFutureTypesYes, "If checked, the tool will include Pokemon that\ndo not have one of the specified types,\nbut have an evolution that does."); 110 | 111 | formControls.Add(typeSelection); 112 | formControls.Add(considerFutureTypesYes); 113 | 114 | // Set up the input for the min IV value 115 | formControls.Add(new Label 116 | { 117 | Location = new System.Drawing.Point(170, 20), 118 | AutoSize = true, 119 | Text = "Min IV Value", 120 | Font = new System.Drawing.Font(Control.DefaultFont, System.Drawing.FontStyle.Bold) 121 | }); 122 | 123 | minIVValue.Value = 0; 124 | minIVValue.Maximum = 31; 125 | minIVValue.Minimum = 0; 126 | minIVValue.Location = new System.Drawing.Point(170, 35); 127 | 128 | formControls.Add(minIVValue); 129 | 130 | //Set up the input for the max IV value 131 | formControls.Add(new Label 132 | { 133 | Location = new System.Drawing.Point(170, 70), 134 | AutoSize = true, 135 | Text = "Max IV Value", 136 | Font = new System.Drawing.Font(Control.DefaultFont, System.Drawing.FontStyle.Bold) 137 | }); 138 | 139 | maxIVValue.Value = 31; 140 | maxIVValue.Maximum = 31; 141 | maxIVValue.Minimum = 0; 142 | maxIVValue.Location = new System.Drawing.Point(170, 85); 143 | 144 | formControls.Add(maxIVValue); 145 | 146 | // Set up the input for shiny chance 147 | formControls.Add(new Label 148 | { 149 | Location = new System.Drawing.Point(170, 120), 150 | AutoSize = true, 151 | Text = "Shiny Chance (%)", 152 | Font = new System.Drawing.Font(Control.DefaultFont, System.Drawing.FontStyle.Bold) 153 | }); 154 | 155 | ToolTip shinyChanceToolTip = new ToolTip(); 156 | shinyChanceToolTip.SetToolTip(shinyChance, "In Gen 2, this will overwrite IV settings."); 157 | 158 | shinyChance.Value = 1; 159 | shinyChance.Maximum = 100; 160 | shinyChance.Minimum = 0; 161 | shinyChance.Location = new System.Drawing.Point(170, 135); 162 | 163 | formControls.Add(shinyChance); 164 | 165 | // Set up the input for Egg Move Chance 166 | formControls.Add(new Label 167 | { 168 | Location = new System.Drawing.Point(170, 170), 169 | AutoSize = true, 170 | Text = "Egg Move Chance (%)", 171 | Font = new System.Drawing.Font(Control.DefaultFont, System.Drawing.FontStyle.Bold) 172 | }); 173 | 174 | eggMoveChance.Value = 25; 175 | eggMoveChance.Maximum = 100; 176 | eggMoveChance.Minimum = 0; 177 | eggMoveChance.Location = new System.Drawing.Point(170, 185); 178 | 179 | formControls.Add(eggMoveChance); 180 | 181 | // Set up the input for Hidden Ability Chance 182 | formControls.Add(new Label 183 | { 184 | Location = new System.Drawing.Point(170, 220), 185 | AutoSize = true, 186 | Text = "Hidden Ability Chance (%)", 187 | Font = new System.Drawing.Font(Control.DefaultFont, System.Drawing.FontStyle.Bold) 188 | }); 189 | 190 | hiddenAbilityChance.Value = 25; 191 | hiddenAbilityChance.Maximum = 100; 192 | hiddenAbilityChance.Minimum = 0; 193 | hiddenAbilityChance.Location = new System.Drawing.Point(170, 235); 194 | 195 | if (sav.Generation < 5) 196 | { 197 | hiddenAbilityChance.Enabled = false; 198 | } 199 | else 200 | { 201 | hiddenAbilityChance.Enabled = true; 202 | } 203 | 204 | formControls.Add(hiddenAbilityChance); 205 | 206 | // Set up "Generate Pokemon" button 207 | createButton.Text = "Generate Pokemon"; 208 | createButton.Size = new System.Drawing.Size(185, 20); 209 | createButton.Location = new System.Drawing.Point(100, 420); 210 | createButton.Click += new EventHandler(AddToBoxesButtonClick); 211 | 212 | formControls.Add(createButton); 213 | 214 | // Add everything to the form, and show it 215 | form.Controls.AddRange(formControls.ToArray()); 216 | form.ShowDialog(); 217 | } 218 | 219 | public void SelectOrDeselectAllTypes(Object sender, EventArgs eventArgs) 220 | { 221 | if (typeSelection.SelectedIndex == 0) 222 | { 223 | bool checkItems = false; 224 | 225 | if (typeSelection.GetItemCheckState(0) == CheckState.Checked) 226 | { 227 | checkItems = true; 228 | } 229 | 230 | for (int i = 0; i < typeSelection.Items.Count; i++) 231 | { 232 | typeSelection.SetItemChecked(i, checkItems); 233 | } 234 | } 235 | } 236 | 237 | public bool IsPokemonValidType(PKM pkmn, EvolutionTree evoTree, byte generation, GameVersion gameVersion) 238 | { 239 | bool returnValue = false; 240 | var selectedTypes = typeSelection.CheckedItems; 241 | 242 | // Type validation. The first check looks for all types being selected, no types being selected, or Select All being checked; any of these 243 | // means that any Pokemon type goes. 244 | if (selectedTypes.Contains("Select All") || !selectedTypes.Contains("Select All") && selectedTypes.Count == 18 || selectedTypes.Count == 0) 245 | { 246 | returnValue = true; 247 | } 248 | else 249 | { 250 | // Loop through each type in the types selected by the user. First check the Pokemon's primary type. If it doesn't match, check the secondary type 251 | // (provided the Pokemon has one). Finally, if the user wants to consu 252 | foreach (string type in selectedTypes) 253 | { 254 | if (pkmn.PersonalInfo.Type1 != -1 && (int)(MoveType)Enum.Parse(typeof(MoveType), type) == pkmn.PersonalInfo.Type1) 255 | { 256 | returnValue = true; 257 | } 258 | else if (pkmn.PersonalInfo.Type2 != -1 && (int)(MoveType)Enum.Parse(typeof(MoveType), type) == pkmn.PersonalInfo.Type2) 259 | { 260 | returnValue = true; 261 | } 262 | } 263 | } 264 | 265 | // If the user wants to, look through the possible future evolutions to see if any of them fulfill the type requirements 266 | if (!returnValue && considerFutureTypesYes.Checked) 267 | { 268 | var evoSpecies = evoTree.GetEvolutionsAndPreEvolutions(pkmn.Species, pkmn.Form); 269 | 270 | foreach (var species in evoSpecies) 271 | { 272 | PKM evolvedPkmn = EntityBlank.GetBlank(generation, gameVersion); 273 | evolvedPkmn.Species = species.Species; 274 | evolvedPkmn.Form = species.Form; 275 | 276 | foreach (string type in selectedTypes) 277 | { 278 | if (evolvedPkmn.PersonalInfo.Type1 != -1 && (int)(MoveType)Enum.Parse(typeof(MoveType), type) == evolvedPkmn.PersonalInfo.Type1) 279 | { 280 | returnValue = true; 281 | } 282 | else if (evolvedPkmn.PersonalInfo.Type2 != -1 && (int)(MoveType)Enum.Parse(typeof(MoveType), type) == evolvedPkmn.PersonalInfo.Type2) 283 | { 284 | returnValue = true; 285 | } 286 | } 287 | } 288 | } 289 | 290 | return returnValue; 291 | } 292 | 293 | public ushort GenerateMove(ReadOnlySpan baseMoves, ushort[] eggMoves, int moveSlot) 294 | { 295 | ushort returnValue = 0; 296 | 297 | int eggMoveRand = random.Next(1, 100); 298 | 299 | if (eggMoveRand <= eggMoveChance.Value) 300 | { 301 | ushort moveIndex = (ushort)(random.Next(0, eggMoves.Length)); 302 | returnValue = eggMoves[moveIndex]; 303 | } 304 | else if (moveSlot < baseMoves.Length) 305 | { 306 | returnValue = baseMoves[moveSlot]; 307 | } 308 | 309 | return returnValue; 310 | } 311 | 312 | public bool IsPokemonValid(PKM pkmn, SaveFile sav) 313 | { 314 | bool returnValue = true; 315 | EvolutionTree evoTree = EvolutionTree.GetEvolutionTree(pkmn.Context); 316 | var baseForm = evoTree.GetBaseSpeciesForm(pkmn.Species, pkmn.Form); 317 | 318 | // Make sure the Pokemon actually exists in the game, AND can come from an egg. If it can't, skip it and continue the loop. 319 | if (baseForm.Species != pkmn.Species || 320 | !sav.Personal.IsSpeciesInGame(pkmn.Species) || 321 | !sav.Personal.IsPresentInGame(pkmn.Species, pkmn.Form) || 322 | !Breeding.CanHatchAsEgg(pkmn.Species) || 323 | (Species)pkmn.Species == Species.Shedinja) 324 | { 325 | returnValue = false; 326 | } 327 | 328 | // Make sure the Pokemon's type is OK 329 | if (!IsPokemonValidType(pkmn, evoTree, sav.Generation, sav.Version)) 330 | { 331 | returnValue = false; 332 | } 333 | 334 | return returnValue; 335 | } 336 | 337 | public static IEncounterEgg GeneratePokemonEgg(PKM pkmn, byte generation, GameVersion version) 338 | { 339 | if (generation == 2) 340 | { 341 | return new EncounterEgg2(pkmn.Species, version); 342 | } 343 | else if (generation == 3) 344 | { 345 | return new EncounterEgg3(pkmn.Species, version); 346 | } 347 | else if (generation == 4) 348 | { 349 | return new EncounterEgg4(pkmn.Species, version); 350 | } 351 | else if (generation == 5) 352 | { 353 | return new EncounterEgg5(pkmn.Species, pkmn.Form, version); 354 | } 355 | else if (generation == 6) 356 | { 357 | return new EncounterEgg6(pkmn.Species, pkmn.Form, version); 358 | } 359 | else if (generation == 7) 360 | { 361 | return new EncounterEgg7(pkmn.Species, pkmn.Form, version); 362 | } 363 | else if (generation == 8) 364 | { 365 | return new EncounterEgg8(pkmn.Species, pkmn.Form, version); 366 | } 367 | else if (generation == 9) 368 | { 369 | return new EncounterEgg9(pkmn.Species, pkmn.Form, version); 370 | } 371 | else 372 | { 373 | throw new NotImplementedException("Egg generation is not implemented for this generation."); 374 | } 375 | } 376 | 377 | public PKM GeneratePokemon(PKM pkmn, SaveFile sav, GameVersion version, byte generation) 378 | { 379 | 380 | IEncounterEgg pkmnAsEgg = GeneratePokemonEgg(pkmn, sav.Generation, sav.Version); 381 | 382 | LegalityAnalysis legality = new LegalityAnalysis(pkmn); 383 | 384 | pkmn = pkmnAsEgg.ConvertToPKM(sav); 385 | 386 | pkmn.Nickname = SpeciesName.GetSpeciesNameGeneration(0, sav.Language, sav.Generation); 387 | pkmn.IsNicknamed = true; 388 | pkmn.OriginalTrainerFriendship = (byte)EggStateLegality.GetMinimumEggHatchCycles(pkmn); 389 | pkmn.MetLocation = 0; 390 | pkmn.Gender = pkmn.GetSaneGender(); 391 | 392 | // There are a lot of quirks with how eggs are handled between generations, and even game versions; this collection of statements does some 393 | // fine-tuning to account for that. 394 | if (sav.Version == GameVersion.BD || sav.Version == GameVersion.SP || sav.Version == GameVersion.BDSP) 395 | { 396 | pkmn.MetLocation = 65535; // Eggs have no met location in BDSP 397 | } 398 | else if (sav.Version == GameVersion.Pt) 399 | { 400 | pkmn.EggLocation = 2000; // Daycare 401 | pkmn.IsNicknamed = false; 402 | pkmn.MetLevel = 0; 403 | pkmn.Version = sav.Version; 404 | } 405 | else if (sav.Generation == 4) 406 | { 407 | // HGSS Eggs aren't nicknamed 408 | pkmn.IsNicknamed = false; 409 | pkmn.Version = sav.Context.GetSingleGameVersion(); 410 | pkmn.EggLocation = 2000; 411 | } 412 | else if (sav.Version == GameVersion.FRLG || sav.Version == GameVersion.FR || sav.Version == GameVersion.LG) 413 | { 414 | pkmn.MetLocation = Locations.HatchLocationFRLG; // Four Island -- if location isn't set, it defaults to Littleroot Town 415 | } 416 | else if (sav.Version == GameVersion.RSE || sav.Version == GameVersion.RS || sav.Version == GameVersion.R || sav.Version == GameVersion.S || sav.Version == GameVersion.E) 417 | { 418 | pkmn.MetLocation = Locations.HatchLocationRSE; // Route 117 -- if location isn't set, it defaults to Littleroot Town 419 | pkmn.Version = sav.Context.GetSingleGameVersion(); 420 | } 421 | else if (sav.Generation == 2) 422 | { 423 | pkmn.SetNickname("EGG"); 424 | } 425 | else if (sav.Generation == 9) 426 | { 427 | // Set met location to South Province Area 1 428 | pkmn.MetLocation = Locations.HatchLocation9; 429 | 430 | // Set size 431 | if (pkmn is IScaledSize s) 432 | { 433 | s.HeightScalar = PokeSizeUtil.GetRandomScalar(); 434 | s.WeightScalar = PokeSizeUtil.GetRandomScalar(); 435 | 436 | if (pkmn is IScaledSize3 s3) 437 | s3.Scale = PokeSizeUtil.GetRandomScalar(); 438 | } 439 | // Set Tera Type 440 | if (pkmn is ITeraType tera) 441 | { 442 | var type = Tera9RNG.GetTeraTypeFromPersonal(pkmn.Species, pkmn.Form, Util.Rand.Rand64()); 443 | tera.TeraTypeOriginal = (MoveType)type; 444 | } 445 | } 446 | 447 | // Set the IVs based on min/max values 448 | pkmn.IV_HP = random.Next((int)minIVValue.Value, (int)maxIVValue.Value); 449 | pkmn.IV_ATK = random.Next((int)minIVValue.Value, (int)maxIVValue.Value); 450 | pkmn.IV_DEF = random.Next((int)minIVValue.Value, (int)maxIVValue.Value); 451 | pkmn.IV_SPA = random.Next((int)minIVValue.Value, (int)maxIVValue.Value); 452 | pkmn.IV_SPD = random.Next((int)minIVValue.Value, (int)maxIVValue.Value); 453 | pkmn.IV_SPE = random.Next((int)minIVValue.Value, (int)maxIVValue.Value); 454 | 455 | // Set ability 456 | pkmn.SetAbilityIndex(random.Next(0, 2)); 457 | if (sav.Generation >= 5) 458 | { 459 | int haValue = random.Next(1, 100); 460 | 461 | if (haValue <= hiddenAbilityChance.Value) 462 | { 463 | pkmn.SetAbilityIndex(2); // set hidden ability 464 | } 465 | } 466 | 467 | // Determine if Pokemon should be shiny 468 | if (shinyChance.Value > 0) 469 | { 470 | int shinyValue = random.Next(1, 100); 471 | 472 | if (shinyValue <= shinyChance.Value) 473 | { 474 | pkmn.SetIsShiny(true); 475 | } 476 | else 477 | { 478 | pkmn.SetIsShiny(false); 479 | } 480 | } 481 | 482 | // Determine moves 483 | var learnSource = GameData.GetLearnSource(sav.Version); 484 | var learnset = learnSource.GetLearnset(pkmn.Species, pkmn.Form); 485 | ReadOnlySpan baseMoves = learnset.GetBaseEggMoves(sav.Generation); 486 | ReadOnlySpan eggMoves = learnSource.GetEggMoves(pkmn.Species, pkmn.Form); 487 | 488 | // PKHeX is smart and will automatically fill in a Pokemon's moves if we don't provide them, 489 | // so there's no need to add any logic for handling situations where the user only wants base moves 490 | if (eggMoveChance.Value > 0 && eggMoves.Length > 0) 491 | { 492 | ushort nextMoveIndex = 0; 493 | int numTriesToGetMove = 0; 494 | do 495 | { 496 | nextMoveIndex = GenerateMove(baseMoves, eggMoves.ToArray(), pkmn.Moves.Length); 497 | pkmn.AddMove(nextMoveIndex); 498 | numTriesToGetMove++; 499 | 500 | } while (pkmn.MoveCount < 5 && nextMoveIndex != 0 && numTriesToGetMove < 20); 501 | 502 | pkmn.FixMoves(); 503 | 504 | if (sav.Generation > 5) 505 | { 506 | pkmn.SetRelearnMoves(pkmn.Moves); 507 | } 508 | 509 | Span fixedMoves = stackalloc ushort[4]; 510 | bool movesAreGood = MoveBreed.GetExpectedMoves(pkmn.Moves, pkmnAsEgg, fixedMoves); 511 | 512 | for (int j = 0; j < 4; j++) 513 | { 514 | pkmn.SetMove(j, fixedMoves[j]); 515 | } 516 | 517 | if (sav.Generation > 5) 518 | { 519 | LegalityAnalysis legalityAnalysis = new LegalityAnalysis(pkmn); 520 | Span moves = stackalloc ushort[4]; 521 | MoveListSuggest.GetSuggestedRelearnMovesFromEncounter(legalityAnalysis, moves, pkmnAsEgg); 522 | 523 | for (int j = 0; j < 4; j++) 524 | { 525 | pkmn.SetMove(j, moves[j]); 526 | pkmn.SetRelearnMove(j, moves[j]); 527 | } 528 | } 529 | 530 | pkmn.HealPP(); 531 | } 532 | 533 | pkmn.IsEgg = true; 534 | legality = new LegalityAnalysis(pkmn); 535 | string report = legality.Report(); 536 | 537 | if (report.Contains("Hidden Ability")) 538 | { 539 | pkmn.SetAbilityIndex(random.Next(0, 2)); 540 | } 541 | 542 | pkmn.Valid = legality.Valid; 543 | 544 | return pkmn; 545 | } 546 | 547 | public void AddToBoxesButtonClick(Object sender, EventArgs events) 548 | { 549 | SaveFile sav = SaveFileEditor.SAV; // current savefile 550 | List generatedPokemon = new List(); // the pokemon to add to the boxes at the end of all this 551 | int pokedexMaxNumber = sav.MaxSpeciesID; 552 | GameVersion version = sav.Version; 553 | var generator = EncounterGenerator.GetGenerator(version, sav.Generation); 554 | 555 | // Workaround for games like Ruby/Sapphire, which get counted as RS, but needs to be either R or S 556 | if (version == GameVersion.RS) 557 | { 558 | version = GameVersion.R; 559 | } 560 | // Diamond/Pearl 561 | else if (version == GameVersion.DP) 562 | { 563 | version = GameVersion.D; 564 | } 565 | else if (version == GameVersion.HGSS) 566 | { 567 | version = GameVersion.HG; 568 | } 569 | 570 | // Make sure the game can generate eggs; if it cannot, the generator will not work and inform the user as such 571 | if (!generator.CanGenerateEggs) 572 | { 573 | MessageBox.Show("Error! This game doesn't support egg generation. Please try another game. Game version " + sav.Context.GetSingleGameVersion().ToString()); 574 | return; 575 | } 576 | // loop for generating pokemon 577 | for (int i = 1; i < pokedexMaxNumber; i++) 578 | { 579 | // Get species, set up legality, form, etc. 580 | PKM pkmn = EntityBlank.GetBlank(sav.Generation, version); 581 | pkmn.Species = (ushort)i; 582 | pkmn.SetSuggestedFormArgument(pkmn.Species); 583 | 584 | 585 | if (IsPokemonValid(pkmn, sav)) 586 | { 587 | generatedPokemon.Add(GeneratePokemon(pkmn, sav, version, sav.Generation)); 588 | } 589 | } 590 | 591 | //Re-arrange the list so Pokemon aren't added in Pokedex order 592 | var rearrangedGeneratedPokemon = generatedPokemon.OrderBy(x => random.Next()).ToList(); 593 | 594 | sav.ImportPKMs(rearrangedGeneratedPokemon); 595 | SaveFileEditor.ReloadSlots(); 596 | 597 | } 598 | 599 | public void NotifySaveLoaded() 600 | { 601 | Console.WriteLine($"{Name} was notified that a Save File was just loaded."); 602 | } 603 | 604 | public bool TryLoadFile(string filePath) 605 | { 606 | Console.WriteLine($"{Name} was provided with the file path, but chose to do nothing with it."); 607 | return false; // no action taken 608 | } 609 | } 610 | } 611 | --------------------------------------------------------------------------------