Add ball auto suggestion

click ball sprite/label to cycle through legal balls
hold alt to use old behavior (set to pokeball)
hold shift to cycle through legal balls randomly (default behavior goes
poke->color->poke)

want to randomize setting balls? use the ApplyBallLegalRandom method at
the end :)

can't really get too fancy as only one color is stored in the personal
data, pkm aren't one single color.
This commit is contained in:
Kurt 2018-08-28 21:13:45 -07:00
parent 6abeec507f
commit 6abd60cc5c
2 changed files with 163 additions and 1 deletions

View file

@ -0,0 +1,152 @@
using System;
using System.Collections.Generic;
using System.Linq;
using static PKHeX.Core.Ball;
namespace PKHeX.Core
{
/// <summary>
/// Contains logic to apply a new <see cref="Ball"/> value to a <see cref="PKM"/>.
/// </summary>
public static class BallRandomizer
{
/// <summary>
/// Gets all balls that are legal for the input <see cref="PKM"/>.
/// </summary>
/// <param name="pkm">Pokémon to retrieve a list of valid balls for.</param>
/// <returns>Enumerable list of <see cref="Ball"/> values that the <see cref="PKM"/> is legal with.</returns>
public static IEnumerable<Ball> GetLegalBalls(PKM pkm)
{
var clone = pkm.Clone();
foreach (var b in BallList)
{
clone.Ball = (int)b;
if (new LegalityAnalysis(clone).Valid)
yield return b;
}
}
/// <summary>
/// Applies a random legal ball value if any exist.
/// </summary>
/// <param name="pkm">Pokémon to modify.</param>
public static int ApplyBallLegalRandom(PKM pkm)
{
var balls = GetBallListFromColor(pkm).ToArray();
Util.Shuffle(balls);
return ApplyFirstLegalBall(pkm, balls);
}
/// <summary>
/// Applies a legal ball value if any exist, ordered by color.
/// </summary>
/// <param name="pkm">Pokémon to modify.</param>
public static int ApplyBallLegalByColor(PKM pkm)
{
var balls = GetBallListFromColor(pkm);
return ApplyFirstLegalBall(pkm, balls);
}
/// <summary>
/// Applies a random ball value in a cyclical manner.
/// </summary>
/// <param name="pkm">Pokémon to modify.</param>
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<Ball> balls)
{
foreach (var b in balls)
{
pkm.Ball = (int)b;
if (new LegalityAnalysis(pkm).Valid)
break;
}
return pkm.Ball;
}
private static IEnumerable<Ball> GetBallList(int ball)
{
var balls = BallList;
var currentBall = (Ball)ball;
return GetCircularOnce(balls, currentBall);
}
private static IEnumerable<Ball> GetBallListFromColor(PKM pkm)
{
var pi = PKX.Personal.GetFormeEntry(pkm.Species, pkm.AltForm);
var color = (PersonalColor)pi.Color;
var balls = BallColors[color];
var currentBall = (Ball)pkm.Ball;
return GetCircularOnce(balls, currentBall);
}
private static IEnumerable<T> GetCircularOnce<T>(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();
}
}
/// <summary>
/// Priority Match ball IDs that match the color ID in descending order
/// </summary>
private static readonly Dictionary<PersonalColor, Ball[]> BallColors = new Dictionary<PersonalColor, Ball[]>
{
[PersonalColor.Red] = new[] { Cherish, Repeat, Fast, Heal, Great, Dream },
[PersonalColor.Blue] = new[] { Dive, Net, Great, Beast },
[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 },
};
/// <summary>
/// Personal Data color IDs
/// </summary>
private enum PersonalColor : byte
{
Red,
Blue,
Yellow,
Green,
Black,
Brown,
Purple,
Gray,
White,
Pink,
}
}
}

View file

@ -576,7 +576,17 @@ namespace PKHeX.WinForms.Controls
}
}
private void ClickBall(object sender, EventArgs e) => CB_Ball.SelectedIndex = 0;
private void ClickBall(object sender, EventArgs e)
{
pkm.Ball = WinFormsUtil.GetIndex(CB_Ball);
if (ModifierKeys.HasFlag(Keys.Alt))
CB_Ball.SelectedValue = (int)Ball.Poke;
else if (ModifierKeys.HasFlag(Keys.Shift))
CB_Ball.SelectedValue = BallRandomizer.ApplyBallLegalRandom(pkm);
else
CB_Ball.SelectedValue = BallRandomizer.ApplyBallLegalByColor(pkm);
}
private void ClickShinyLeaf(object sender, EventArgs e) => ShinyLeaf.CheckAll(ModifierKeys != Keys.Control);
private void ClickMetLocation(object sender, EventArgs e)