using System; using System.Collections.Generic; using System.Linq; using static PKHeX.Core.Ball; namespace PKHeX.Core { /// /// Contains logic to apply a new value to a . /// public static class BallRandomizer { /// /// Gets all balls that are legal for the input . /// /// /// Requires checking the for every that is tried. /// /// Pokémon to retrieve a list of valid balls for. /// Enumerable list of values that the is legal with. public static IEnumerable GetLegalBalls(PKM pkm) { var clone = pkm.Clone(); foreach (var b in BallList) { clone.Ball = (int)b; if (new LegalityAnalysis(clone).Valid) yield return b; } } /// /// Applies a random legal ball value if any exist. /// /// /// Requires checking the for every that is tried. /// /// Pokémon to modify. public static int ApplyBallLegalRandom(PKM pkm) { var balls = GetBallListFromColor(pkm).ToArray(); Util.Shuffle(balls); return ApplyFirstLegalBall(pkm, balls); } /// /// Applies a legal ball value if any exist, ordered by color. /// /// /// Requires checking the for every that is tried. /// /// Pokémon to modify. public static int ApplyBallLegalByColor(PKM pkm) { var balls = GetBallListFromColor(pkm); return ApplyFirstLegalBall(pkm, balls); } /// /// Applies a random ball value in a cyclical manner. /// /// Pokémon to modify. public static int ApplyBallNext(PKM pkm) { var balls = GetBallList(pkm.Ball); var next = balls.First(); return pkm.Ball = (int)next; } private static int ApplyFirstLegalBall(PKM pkm, IEnumerable balls) { foreach (var b in balls) { pkm.Ball = (int)b; if (new LegalityAnalysis(pkm).Valid) break; } return pkm.Ball; } private static IEnumerable GetBallList(int ball) { var balls = BallList; var currentBall = (Ball)ball; return GetCircularOnce(balls, currentBall); } private static IEnumerable GetBallListFromColor(PKM pkm) { // Gen1/2 don't store color in personal info var pi = pkm.Format >= 3 ? pkm.PersonalInfo : PersonalTable.USUM.GetFormeEntry(pkm.Species, 0); var color = (PersonalColor)pi.Color; var balls = BallColors[color]; var currentBall = (Ball)pkm.Ball; return GetCircularOnce(balls, currentBall); } private static IEnumerable GetCircularOnce(T[] items, T current) { var currentIndex = Array.IndexOf(items, current); if (currentIndex < 0) currentIndex = items.Length - 2; for (int i = currentIndex + 1; i < items.Length; i++) yield return items[i]; for (int i = 0; i <= currentIndex; i++) yield return items[i]; } private static readonly Ball[] BallList = (Ball[]) Enum.GetValues(typeof(Ball)); static BallRandomizer() { var exclude = new[] {None, Poke}; var end = new[] {Poke}; var allBalls = BallList.Except(exclude).ToArray(); var colors = (PersonalColor[])Enum.GetValues(typeof(PersonalColor)); foreach (var c in colors) { var vals = BallColors[c]; var extra = allBalls.Except(vals).ToArray(); Util.Shuffle(extra); BallColors[c] = vals.Concat(extra).Concat(end).ToArray(); } } /// /// Priority Match ball IDs that match the color ID in descending order /// private static readonly Dictionary BallColors = new Dictionary { [PersonalColor.Red] = new[] { Cherish, Repeat, Fast, Heal, Great, Dream, Lure }, [PersonalColor.Blue] = new[] { Dive, Net, Great, Beast, Lure }, [PersonalColor.Yellow] = new[] { Level, Ultra, Repeat, Quick, Moon }, [PersonalColor.Green] = new[] { Safari, Friend, Nest, Dusk }, [PersonalColor.Black] = new[] { Luxury, Heavy, Ultra, Moon, Net, Beast }, [PersonalColor.Brown] = new[] { Level, Heavy }, [PersonalColor.Purple] = new[] { Master, Love, Dream, Heal }, [PersonalColor.Gray] = new[] { Heavy, Premier, Luxury }, [PersonalColor.White] = new[] { Premier, Timer, Luxury, Ultra }, [PersonalColor.Pink] = new[] { Love, Dream, Heal }, }; /// /// Personal Data color IDs /// private enum PersonalColor : byte { Red, Blue, Yellow, Green, Black, Brown, Purple, Gray, White, Pink, } } }