diff --git a/pkNX.Randomization/Randomizers/EvolutionRandomizer.cs b/pkNX.Randomization/Randomizers/EvolutionRandomizer.cs index 691c3080..cbf7e26d 100644 --- a/pkNX.Randomization/Randomizers/EvolutionRandomizer.cs +++ b/pkNX.Randomization/Randomizers/EvolutionRandomizer.cs @@ -10,14 +10,16 @@ public class EvolutionRandomizer : Randomizer private readonly EvolutionSet[] Evolutions; private readonly GameInfo Game; private readonly PersonalTable Personal; - public readonly SpeciesRandomizer Randomizer; + public readonly SpeciesRandomizer RandSpec; + public readonly FormRandomizer RandForm; public EvolutionRandomizer(GameInfo game, EvolutionSet[] evolutions, PersonalTable t) { Game = game; Personal = t; Evolutions = evolutions; - Randomizer = new SpeciesRandomizer(Game, t); + RandSpec = new SpeciesRandomizer(Game, t); + RandForm = new FormRandomizer(t); } public override void Execute() @@ -44,8 +46,8 @@ private void Randomize(EvolutionSet evos, int species) { if (evo.Method != 0) { - evo.Species = Randomizer.GetRandomSpecies(evo.Species, species); - evo.Form = Legal.GetRandomForme(evo.Species, false, true, Game.SWSH, Personal); + evo.Species = RandSpec.GetRandomSpecies(evo.Species, species); + evo.Form = RandForm.GetRandomForme(evo.Species, false, true, Game.SWSH, Personal.Table); } } } diff --git a/pkNX.Randomization/Randomizers/FormRandomizer.cs b/pkNX.Randomization/Randomizers/FormRandomizer.cs index 8e2e2d65..b6d700ad 100644 --- a/pkNX.Randomization/Randomizers/FormRandomizer.cs +++ b/pkNX.Randomization/Randomizers/FormRandomizer.cs @@ -1,4 +1,5 @@ using pkNX.Structures; +using System; using System.Linq; using static pkNX.Structures.Species; @@ -13,11 +14,7 @@ public FormRandomizer(PersonalTable t) Personal = t; } - public bool AllowMega { get; set; } = false; - public bool AllowAlolanForm { get; set; } = true; - public bool AllowGalarianForm { get; set; } = true; - - public int GetRandomForme(int species, PersonalInfo[] stats = null) + public int GetRandomForme(int species, bool mega, bool alola, bool galar, PersonalInfo[] stats = null) { if (stats == null) stats = Personal.Table; @@ -30,7 +27,7 @@ public int GetRandomForme(int species, PersonalInfo[] stats = null) case Deerling: case Sawsbuck: return 31; // Random - case Greninja when !AllowMega: + case Greninja when !mega: case Eternatus: return 0; case Scatterbug: @@ -41,26 +38,42 @@ public int GetRandomForme(int species, PersonalInfo[] stats = null) return Util.Random.Next(7); // keep the core color a surprise // Galarian Forms - case Meowth when AllowGalarianForm: // Kanto, Alola, Galar + case Meowth when galar: // Kanto, Alola, Galar return Util.Random.Next(3); - case Darmanitan when AllowGalarianForm: // Standard, Zen, Galar Standard, Galar Zen + case Darmanitan when galar: // Standard, Zen, Galar Standard, Galar Zen return Util.Random.Next(4); - case Slowbro when AllowGalarianForm: // Slowbro-1 is Mega and Slowbro-2 is Galar, so only return 0 or 2 - { - int form = Util.Random.Next(2); - if (form == 1) - form++; - return form; - } + + // some species have 1 invalid form among several other valid forms, handle them here + case Pikachu when Personal.TableLength == 1181: + case Slowbro when galar: + { + int form = Util.Random.Next(stats[species].FormeCount - 1); + int banned = GetInvalidForm(species, galar, Personal); + if (form == banned) + form++; + return form; + } } - if (AllowAlolanForm && Legal.EvolveToAlolanForms.Contains(species)) + if (Personal.TableLength == 980 && (species == (int)Pikachu || species == (int)Eevee)) // gg tableB -- no starters, they crash trainer battles. + return 0; + if (alola && Legal.EvolveToAlolanForms.Contains(species)) return Util.Random.Next(2); - if (AllowGalarianForm && Legal.EvolveToGalarForms.Contains(species)) + if (galar && Legal.EvolveToGalarForms.Contains(species)) return Util.Random.Next(2); - if (!Legal.BattleExclusiveForms.Contains(species) || AllowMega) + if (!Legal.BattleExclusiveForms.Contains(species) || mega) return Util.Random.Next(stats[species].FormeCount); // Slot-Random return 0; } + + public int GetInvalidForm(int species, bool galar, PersonalTable stats) + { + return species switch + { + (int)Pikachu when stats.TableLength == 1181 => 8, // LGPE Partner Pikachu + (int)Slowbro when galar => 1, // Mega Slowbro + _ => throw new ArgumentOutOfRangeException(nameof(species)) + }; + } } } diff --git a/pkNX.Randomization/Randomizers/TrainerRandomizer.cs b/pkNX.Randomization/Randomizers/TrainerRandomizer.cs index 0f53948b..5ae5e42f 100644 --- a/pkNX.Randomization/Randomizers/TrainerRandomizer.cs +++ b/pkNX.Randomization/Randomizers/TrainerRandomizer.cs @@ -20,6 +20,7 @@ public class TrainerRandomizer : Randomizer public GenericRandomizer Class { get; set; } public LearnsetRandomizer Learn { get; set; } public SpeciesRandomizer RandSpec { get; set; } + public FormRandomizer RandForm { get; set; } public MoveRandomizer RandMove { get; set; } public int ClassCount { get; set; } public Func GetBlank { get; set; } @@ -161,7 +162,7 @@ private void RandomizeSpecFormItem(IPokeData pk, int Type) else // every other pkm { pk.Species = RandSpec.GetRandomSpeciesType(pk.Species, Type); - pk.Form = Legal.GetRandomForme(pk.Species, Settings.AllowRandomMegaForms, true, true, Personal); + pk.Form = RandForm.GetRandomForme(pk.Species, Settings.AllowRandomMegaForms, true, true, Personal.Table); } } @@ -180,7 +181,7 @@ private void RandomizeSpecForm(TrainerPoke7b pk, int type) else { pk.Species = RandSpec.GetRandomSpeciesType(pk.Species, type); - pk.Form = Legal.GetRandomForme(pk.Species, Settings.AllowRandomMegaForms, true, false, Personal); + pk.Form = RandForm.GetRandomForme(pk.Species, Settings.AllowRandomMegaForms, true, false, Personal.Table); } } @@ -254,7 +255,7 @@ private void UpdatePKMFromSettings(TrainerPoke pk) return; c.Species = AllowedGigantamaxes[Util.Random.Next(AllowedGigantamaxes.Length)]; - c.Form = c.Species == (int)Species.Pikachu || c.Species == (int)Species.Meowth ? 0 : Legal.GetRandomForme(c.Species, false, false, false, Personal); // Pikachu & Meowth altforms can't gmax + c.Form = c.Species == (int)Species.Pikachu || c.Species == (int)Species.Meowth ? 0 : RandForm.GetRandomForme(c.Species, false, false, false, Personal.Table); // Pikachu & Meowth altforms can't gmax } if (Settings.MaxDynamaxLevel && c.CanDynamax) c.DynamaxLevel = 10; diff --git a/pkNX.Structures/Legality/Legal.cs b/pkNX.Structures/Legality/Legal.cs index 03bb1114..69658236 100644 --- a/pkNX.Structures/Legality/Legal.cs +++ b/pkNX.Structures/Legality/Legal.cs @@ -6,58 +6,6 @@ namespace pkNX.Structures { public static partial class Legal { - public static int GetRandomForme(int species, bool mega, bool alola, bool galar, PersonalTable stats) - { - if (stats == null) - return 0; - if (stats[species].FormeCount <= 1) - return 0; - - if (species == (int)Species.Unown || species == (int)Species.Deerling || species == (int)Species.Sawsbuck) - return 31; // Random - if ((species == (int)Species.Greninja && !mega) || species == (int)Species.Eternatus) - return 0; - if (species == (int)Species.Scatterbug || species == (int)Species.Spewpa || species == (int)Species.Vivillon) - return 30; // save file specific - if (species == (int)Species.Minior) - return Util.Rand.Next(7); // keep the core color a surprise - - if (galar) - { - switch ((Species)species) - { - case Species.Meowth: - return Util.Rand.Next(3); // Kanto, Alola, Galar - case Species.Darmanitan: - return Util.Rand.Next(4); // Standard, Zen, Galar Standard, Galar Zen - case Species.Slowbro: - { - int form = Util.Rand.Next(2); // Slowbro-1 is Mega and Slowbro-2 is Galar, so only return 0 or 2 - if (form == 1) - form++; - return form; - } - } - } - - if (stats.TableLength == 980 && (species == (int)Species.Pikachu || species == (int)Species.Eevee)) // gg tableB -- no starters, they crash trainer battles. - return 0; - if (stats.TableLength == 1181 && species == (int)Species.Pikachu) // SWSH -- disallow Partner Pikachu from LGPE, but allow World Cap - { - int form = Util.Rand.Next(9); - if (form == 8) - form++; - return form; - } - if (EvolveToAlolanForms.Contains(species)) - return alola ? Util.Rand.Next(2) : 0; - if (EvolveToGalarForms.Contains(species)) - return galar ? Util.Rand.Next(2) : 0; - if (!BattleExclusiveForms.Contains(species) || mega) - return Util.Rand.Next(stats[species].FormeCount); // Slot-Random - return 0; - } - /// /// Multiplies the current level with a scaling factor, returning a modified level. /// @@ -176,6 +124,7 @@ public static int[] GetRandomItemList(GameVersion game) {362, new[] {763}}, // Glalie @ Glalitite {373, new[] {769}}, // Salamence @ Salamencite {376, new[] {758}}, // Metagross @ Metagrossite + // Rayquaza requires Dragon Ascent, no Held Item {428, new[] {768}}, // Lopunny @ Lopunnite {475, new[] {756}}, // Gallade @ Galladite {531, new[] {757}}, // Audino @ Audinite diff --git a/pkNX.Structures/Personal/PersonalTable.cs b/pkNX.Structures/Personal/PersonalTable.cs index 7d2ce03e..e8301d8c 100644 --- a/pkNX.Structures/Personal/PersonalTable.cs +++ b/pkNX.Structures/Personal/PersonalTable.cs @@ -136,7 +136,7 @@ public PersonalInfo GetFormeEntry(int species, int forme) } /// - /// Count of entries in the table, which includes default species entries and their separate AltForm ID entreis. + /// Count of entries in the table, which includes default species entries and their separate AltForm ID entries. /// public int TableLength => Table.Length; diff --git a/pkNX.WinForms/MainEditor/EditorGG.cs b/pkNX.WinForms/MainEditor/EditorGG.cs index 838fa179..9fe98119 100644 --- a/pkNX.WinForms/MainEditor/EditorGG.cs +++ b/pkNX.WinForms/MainEditor/EditorGG.cs @@ -120,11 +120,12 @@ void Randomize() var spec = EditUtil.Settings.Species; spec.Gen2 = spec.Gen3 = spec.Gen4 = spec.Gen5 = spec.Gen6 = spec.Gen7 = false; var srand = new SpeciesRandomizer(ROM.Info, ROM.Data.PersonalData); + var frand = new FormRandomizer(ROM.Data.PersonalData); srand.Initialize(spec); foreach (var t in objs) { t.Species = (Species)srand.GetRandomSpecies((int)t.Species); - t.Form = Legal.GetRandomForme((int)t.Species, false, true, false, ROM.Data.PersonalData); + t.Form = frand.GetRandomForme((int)t.Species, false, true, false, ROM.Data.PersonalData.Table); t.Nature = Nature.Random25; t.Gender = FixedGender.Random; t.Shiny = Shiny.Random; @@ -155,12 +156,13 @@ void Randomize() var spec = EditUtil.Settings.Species; spec.Gen2 = spec.Gen3 = spec.Gen4 = spec.Gen5 = spec.Gen6 = spec.Gen7 = false; var srand = new SpeciesRandomizer(ROM.Info, ROM.Data.PersonalData); + var frand = new FormRandomizer(ROM.Data.PersonalData); srand.Initialize(spec, 808, 809); // can only catch 1-151 in wild foreach (var t in objs) { t.Species = (Species)srand.GetRandomSpecies((int)t.Species); t.RequiredSpecies = (Species)srand.GetRandomSpecies((int)t.Species); - t.Form = Legal.GetRandomForme((int)t.Species, false, true, false, ROM.Data.PersonalData); + t.Form = frand.GetRandomForme((int)t.Species, false, true, false, ROM.Data.PersonalData.Table); t.RequiredForm = 0; // can't catch wild alolan forms t.Nature = Nature.Random - 1; t.Gender = FixedGender.Random; @@ -192,12 +194,13 @@ void Randomize() var spec = EditUtil.Settings.Species; spec.Gen2 = spec.Gen3 = spec.Gen4 = spec.Gen5 = spec.Gen6 = spec.Gen7 = false; var srand = new SpeciesRandomizer(ROM.Info, ROM.Data.PersonalData); + var frand = new FormRandomizer(ROM.Data.PersonalData); srand.Initialize(spec); for (int i = 2; i < objs.Length; i++) // skip starters { var t = objs[i]; t.Species = (Species)srand.GetRandomSpecies((int)t.Species); - t.Form = Legal.GetRandomForme((int)t.Species, false, true, false, ROM.Data.PersonalData); + t.Form = frand.GetRandomForme((int)t.Species, false, true, false, ROM.Data.PersonalData.Table); t.Nature = Nature.Random25; t.Gender = FixedGender.Random; t.Shiny = Shiny.Random; diff --git a/pkNX.WinForms/MainEditor/EditorSWSH.cs b/pkNX.WinForms/MainEditor/EditorSWSH.cs index e1742437..98e36367 100644 --- a/pkNX.WinForms/MainEditor/EditorSWSH.cs +++ b/pkNX.WinForms/MainEditor/EditorSWSH.cs @@ -237,13 +237,14 @@ void Randomize() var spec = EditUtil.Settings.Species; var srand = new SpeciesRandomizer(ROM.Info, ROM.Data.PersonalData); + var frand = new FormRandomizer(ROM.Data.PersonalData); srand.Initialize(spec, ban); foreach (var t in arr) { foreach (var p in t.Entries) { p.Species = srand.GetRandomSpecies(p.Species); - p.AltForm = Legal.GetRandomForme(p.Species, false, true, true, ROM.Data.PersonalData); + p.AltForm = frand.GetRandomForme(p.Species, false, true, true, ROM.Data.PersonalData.Table); p.Ability = 4; // "A4" -- 1, 2, or H p.Gender = 0; // random p.IsGigantamax = false; // don't allow gmax flag on non-gmax species @@ -278,9 +279,7 @@ void Randomize() foreach (var t in arr) { foreach (var i in t.Entries) - { i.ItemID = (uint)PossibleHeldItems[Randomization.Util.Random.Next(PossibleHeldItems.Length)]; - } } } @@ -310,9 +309,7 @@ void Randomize() foreach (var t in arr) { foreach (var i in t.Entries) - { i.ItemID = (uint)PossibleHeldItems[Randomization.Util.Random.Next(PossibleHeldItems.Length)]; - } } } @@ -345,13 +342,14 @@ void Randomize() var spec = EditUtil.Settings.Species; var srand = new SpeciesRandomizer(ROM.Info, ROM.Data.PersonalData); + var frand = new FormRandomizer(ROM.Data.PersonalData); srand.Initialize(spec, ban); foreach (var t in encounters) { if (t.Species >= Species.Zacian && t.Species <= Species.Eternatus) // Eternatus crashes when changed, keep Zacian and Zamazenta to make final boss battle fair continue; t.Species = (Species)srand.GetRandomSpecies((int)t.Species); - t.AltForm = Legal.GetRandomForme((int)t.Species, false, true, true, ROM.Data.PersonalData); + t.AltForm = frand.GetRandomForme((int)t.Species, false, true, true, ROM.Data.PersonalData.Table); t.Ability = Randomization.Util.Random.Next(1, 4); // 1, 2, or H t.HeldItem = PossibleHeldItems[Randomization.Util.Random.Next(PossibleHeldItems.Length)]; t.Nature = Nature.Random25; @@ -391,6 +389,7 @@ void Randomize() var spec = EditUtil.Settings.Species; var srand = new SpeciesRandomizer(ROM.Info, ROM.Data.PersonalData); + var frand = new FormRandomizer(ROM.Data.PersonalData); srand.Initialize(spec, ban); foreach (var t in gifts) { @@ -398,12 +397,12 @@ void Randomize() if (t.CanGigantamax) { t.Species = (Species)Legal.GigantamaxForms[Randomization.Util.Random.Next(Legal.GigantamaxForms.Length)]; - t.AltForm = t.Species == Species.Pikachu || t.Species == Species.Meowth ? 0 : Legal.GetRandomForme((int)t.Species, false, false, false, ROM.Data.PersonalData); // Pikachu & Meowth altforms can't gmax + t.AltForm = t.Species == Species.Pikachu || t.Species == Species.Meowth ? 0 : frand.GetRandomForme((int)t.Species, false, false, false, ROM.Data.PersonalData.Table); // Pikachu & Meowth altforms can't gmax } else { t.Species = (Species)srand.GetRandomSpecies((int)t.Species); - t.AltForm = Legal.GetRandomForme((int)t.Species, false, true, true, ROM.Data.PersonalData); + t.AltForm = frand.GetRandomForme((int)t.Species, false, true, true, ROM.Data.PersonalData.Table); } t.Ability = Randomization.Util.Random.Next(1, 4); // 1, 2, or H @@ -445,12 +444,13 @@ void Randomize() var spec = EditUtil.Settings.Species; var srand = new SpeciesRandomizer(ROM.Info, ROM.Data.PersonalData); + var frand = new FormRandomizer(ROM.Data.PersonalData); srand.Initialize(spec, ban); foreach (var t in trades) { // what you receive t.Species = (Species)srand.GetRandomSpecies((int)t.Species); - t.AltForm = Legal.GetRandomForme((int)t.Species, false, true, true, ROM.Data.PersonalData); + t.AltForm = frand.GetRandomForme((int)t.Species, false, true, true, ROM.Data.PersonalData.Table); t.Ability = Randomization.Util.Random.Next(1, 4); // 1, 2, or H t.Ball = (Ball)Randomization.Util.Random.Next(1, 15); // packed bit, only allows for 15 balls t.HeldItem = PossibleHeldItems[Randomization.Util.Random.Next(PossibleHeldItems.Length)]; @@ -463,7 +463,7 @@ void Randomize() // what you trade t.RequiredSpecies = (Species)srand.GetRandomSpecies((int)t.RequiredSpecies); - t.RequiredForm = Legal.GetRandomForme((int)t.RequiredSpecies, false, true, true, ROM.Data.PersonalData); + t.RequiredForm = frand.GetRandomForme((int)t.RequiredSpecies, false, true, true, ROM.Data.PersonalData.Table); t.RequiredNature = Nature.Random25; // any } } diff --git a/pkNX.WinForms/Subforms/BTTE.cs b/pkNX.WinForms/Subforms/BTTE.cs index bedf546d..47ab5df0 100644 --- a/pkNX.WinForms/Subforms/BTTE.cs +++ b/pkNX.WinForms/Subforms/BTTE.cs @@ -595,6 +595,7 @@ private TrainerRandomizer GetRandomizer() } var rspec = new SpeciesRandomizer(Game.Info, Personal); + var rform = new FormRandomizer(Personal); rspec.Initialize((SpeciesSettings)PG_Species.SelectedObject, ban); learn.Moves = moves; var evos = Game.Data.EvolutionData; @@ -604,6 +605,7 @@ private TrainerRandomizer GetRandomizer() Learn = learn, RandMove = rmove, RandSpec = rspec, + RandForm = rform, GetBlank = () => (Game.Info.SWSH ? (TrainerPoke)new TrainerPoke8() : new TrainerPoke7b()), // this should probably be less specific }; trand.Initialize((TrainerRandSettings)PG_RTrainer.SelectedObject, (SpeciesSettings)PG_Species.SelectedObject); diff --git a/pkNX.WinForms/Subforms/PokeDataUI.cs b/pkNX.WinForms/Subforms/PokeDataUI.cs index ae163502..cb4413ef 100644 --- a/pkNX.WinForms/Subforms/PokeDataUI.cs +++ b/pkNX.WinForms/Subforms/PokeDataUI.cs @@ -489,7 +489,7 @@ private void B_RandEvo_Click(object sender, EventArgs e) .Where(z => !z.Present).Select(z => z.Species).ToArray(); } - rand.Randomizer.Initialize(settings, ban); + rand.RandSpec.Initialize(settings, ban); rand.Execute(); LoadIndex(CB_Species.SelectedIndex); System.Media.SystemSounds.Asterisk.Play(); @@ -502,7 +502,7 @@ private void B_TradeEvo_Click(object sender, EventArgs e) if (ROM.Info.GG) settings.Gen2 = settings.Gen3 = settings.Gen4 = settings.Gen5 = settings.Gen6 = settings.Gen7 = settings.Gen8 = false; var rand = new EvolutionRandomizer(ROM.Info, Editor.Evolve.LoadAll(), Editor.Personal); - rand.Randomizer.Initialize(settings); + rand.RandSpec.Initialize(settings); rand.ExecuteTrade(); LoadIndex(CB_Species.SelectedIndex); System.Media.SystemSounds.Asterisk.Play(); diff --git a/pkNX.WinForms/Subforms/SSWE.cs b/pkNX.WinForms/Subforms/SSWE.cs index 562a98c7..e30caee0 100644 --- a/pkNX.WinForms/Subforms/SSWE.cs +++ b/pkNX.WinForms/Subforms/SSWE.cs @@ -192,7 +192,7 @@ void ApplyRand(IList slots) } s.Species = rand.GetRandomSpecies(s.Species); - s.Form = fr.GetRandomForme(s.Species); + s.Form = fr.GetRandomForme(s.Species, false, true, true, ROM.Data.PersonalData.Table); if (fill) s.Probability = RandomScaledRates[slots.Count][i]; }