using System;
using System.Linq;
namespace PKHeX.Core
{
///
/// Contains extension logic for modifying data.
///
public static class CommonEdits
{
///
/// Sets the to the provided value.
///
/// Pokémon to modify.
/// to set. If no nickname is provided, the is set to the default value for its current language and format.
public static void SetNickname(this PKM pk, string nick = null)
{
if (nick != null)
{
pk.IsNicknamed = true;
pk.Nickname = nick;
}
else
{
pk.IsNicknamed = false;
pk.Nickname = PKX.GetSpeciesNameGeneration(pk.Species, pk.Language, pk.Format);
if (pk is PK1 pk1) pk1.SetNotNicknamed();
if (pk is PK2 pk2) pk2.SetNotNicknamed();
}
}
///
/// Sets the value, with special consideration for values which derive the value.
///
/// Pokémon to modify.
/// Desired value to set.
public static void SetAltForm(this PKM pk, int form)
{
switch (pk.Format)
{
case 2:
while (pk.AltForm != form)
pk.SetRandomIVs();
break;
case 3:
pk.SetPIDUnown3(form);
break;
default:
pk.AltForm = form;
break;
}
}
///
/// Sets the value by sanity checking the provided against the possible pool of abilities.
///
/// Pokémon to modify.
/// Desired to set.
public static void SetAbility(this PKM pk, int abil)
{
var abilities = pk.PersonalInfo.Abilities;
int abilIndex = Array.IndexOf(abilities, abil);
abilIndex = Math.Max(0, abilIndex);
if (pk is PK5 pk5 && abilIndex == 2)
pk5.HiddenAbility = true;
else if (pk.Format <= 5)
pk.PID = PKX.GetRandomPID(pk.Species, pk.Gender, pk.Version, pk.Nature, pk.Format, (uint)(abilIndex * 0x10001));
pk.RefreshAbility(abilIndex);
}
///
/// Sets a Random value. The is not updated if the value should match the instead.
///
/// Pokémon to modify.
public static void SetRandomEC(this PKM pk)
{
int gen = pk.GenNumber;
if (gen < 6 && gen > 2)
pk.EncryptionConstant = pk.PID;
else
pk.EncryptionConstant = Util.Rand32();
}
///
/// Sets the derived value.
///
/// Pokémon to modify.
/// Desired state to set.
///
public static bool SetIsShiny(this PKM pk, bool shiny) => shiny ? pk.SetShiny() : pk.SetUnshiny();
///
/// Makes a shiny.
///
/// Pokémon to modify.
/// Returns if the data was modified.
public static bool SetShiny(this PKM pk)
{
if (pk.IsShiny)
return false;
if (pk.Format > 2)
pk.SetShinyPID();
else
pk.SetShinyIVs();
return true;
}
///
/// Makes a not-shiny.
///
/// Pokémon to modify.
/// Returns if the data was modified.
public static bool SetUnshiny(this PKM pk)
{
if (!pk.IsShiny)
return false;
pk.SetPIDGender(pk.Gender);
return true;
}
///
/// Sets the value, with special consideration for the values which derive the value.
///
/// Pokémon to modify.
/// Desired value to set.
public static void SetNature(this PKM pk, int nature)
{
if (pk.Format <= 4)
pk.SetPIDNature(Math.Max(0, nature));
else
pk.Nature = Math.Max(0, nature);
}
///
/// Sets the value, with special consideration for the values which derive the value.
///
/// Pokémon to modify.
/// Desired value to set.
public static void SetNature(this PKM pk, Nature nature) => pk.SetNature((int) nature);
///
/// Sets the individual PP Up count values depending if a Move is present in the moveslot or not.
///
/// Pokémon to modify.
/// to use (if already known). Will fetch the current if not provided.
public static void SetPPUps(this PKM pk, int[] Moves = null)
{
if (Moves == null)
Moves = pk.Moves;
pk.Move1_PP = pk.GetMovePP(Moves[0], pk.Move1_PPUps = GetPPUpCount(Moves[0]));
pk.Move2_PP = pk.GetMovePP(Moves[1], pk.Move2_PPUps = GetPPUpCount(Moves[1]));
pk.Move3_PP = pk.GetMovePP(Moves[2], pk.Move3_PPUps = GetPPUpCount(Moves[2]));
pk.Move4_PP = pk.GetMovePP(Moves[3], pk.Move4_PPUps = GetPPUpCount(Moves[3]));
int GetPPUpCount(int moveID) => moveID > 0 ? 3 : 0;
}
///
/// Sets the value, with special consideration for the values which derive the value.
///
/// Pokémon to modify.
/// Desired value to set.
public static void SetGender(this PKM pk, string gender)
{
if (gender == null)
return;
int Gender = PKX.GetGenderFromString(gender);
pk.SetGender(Gender);
}
///
/// Sets the value, with special consideration for the values which derive the value.
///
/// Pokémon to modify.
/// Desired value to set.
public static void SetGender(this PKM pk, int gender)
{
gender = Math.Min(2, Math.Max(0, gender));
if (pk.Format <= 2)
pk.SetATKIVGender(gender);
else if (pk.Format <= 4)
pk.SetPIDGender(gender);
else
pk.Gender = gender;
}
///
/// Sets to valid values which may best enhance the stats.
///
///
/// to use (if already known). Will fetch the current if not provided.
public static void SetSuggestedHyperTrainingData(this PKM pkm, int[] IVs = null)
{
if (pkm.Format < 7)
return;
if (pkm.CurrentLevel < 100)
{
pkm.HyperTrainFlags = 0;
return;
}
if (IVs == null)
IVs = pkm.IVs;
pkm.HT_HP = IVs[0] != 31;
pkm.HT_ATK = IVs[1] != 31 && IVs[1] > 2;
pkm.HT_DEF = IVs[2] != 31;
pkm.HT_SPE = IVs[3] != 31 && IVs[3] > 2;
pkm.HT_SPA = IVs[4] != 31;
pkm.HT_SPD = IVs[5] != 31;
}
///
/// Fetches based on the provided .
///
/// Pokémon to modify.
/// which contains parsed information pertaining to legality.
/// best suited for the current data.
public static int[] GetSuggestedRelearnMoves(this PKM pk, LegalityAnalysis legal)
{
int[] m = legal.GetSuggestedRelearn();
if (!m.All(z => z == 0))
return m;
if (pk.WasEgg || pk.WasEvent || pk.WasEventEgg || pk.WasLink)
return m;
var encounter = legal.GetSuggestedMetInfo();
if (encounter != null)
m = encounter.Relearn;
return m;
}
///
/// Sanity checks the provided value, and returns a sane value.
///
///
/// Current preference
/// Most-legal value
public static int GetSaneGender(this PKM pkm, int cg)
{
int gt = pkm.PersonalInfo.Gender;
switch (gt)
{
case 255: return 2; // Genderless
case 254: return 1; // Female-Only
case 0: return 0; // Male-Only
}
if (cg == 2 || pkm.GenNumber < 6)
return (byte)pkm.PID <= gt ? 1 : 0;
return cg;
}
///
/// Copies details to the .
///
/// Pokémon to modify.
/// details to copy from.
public static void ApplySetDetails(this PKM pk, ShowdownSet Set)
{
pk.Species = Set.Species;
pk.Moves = Set.Moves;
pk.HeldItem = Set.HeldItem < 0 ? 0 : Set.HeldItem;
pk.CurrentLevel = Set.Level;
pk.CurrentFriendship = Set.Friendship;
pk.IVs = Set.IVs;
pk.EVs = Set.EVs;
pk.ApplyMarkings();
pk.SetSuggestedHyperTrainingData(Set.IVs);
pk.SetNickname(Set.Nickname);
pk.SetGender(Set.Gender);
pk.SetAltForm(Set.FormIndex);
pk.SetPPUps(Set.Moves);
pk.SetAbility(Set.Ability);
pk.SetNature(Set.Nature);
pk.SetIsShiny(Set.Shiny);
pk.SetRandomEC();
var legal = new LegalityAnalysis(pk);
if (legal.Info.Relearn.Any(z => !z.Valid))
pk.RelearnMoves = pk.GetSuggestedRelearnMoves(legal);
}
///
/// Sets all Memory related data to the default value (zero).
///
/// Pokémon to modify.
public static void ClearMemories(this PKM pk)
{
pk.OT_Memory = pk.OT_Affection = pk.OT_Feeling = pk.OT_Intensity = pk.OT_TextVar =
pk.HT_Memory = pk.HT_Affection = pk.HT_Feeling = pk.HT_Intensity = pk.HT_TextVar = 0;
}
///
/// Sets the to indicate flawless (or near-flawless) .
///
/// Pokémon to modify.
/// to use (if already known). Will fetch the current if not provided.
public static void ApplyMarkings(this PKM pk, int[] IVs = null)
{
if (pk.Format <= 3)
return; // no markings (gen3 only has 4; can't mark stats intelligently
if (IVs == null)
IVs = pk.IVs;
var remapper = pk.Format < 7 ? (Func)GetSimpleMarking : GetComplexMarking;
pk.Markings = IVs.Select(remapper).ToArray();
int GetSimpleMarking(int val) => val == 31 ? 1 : 0;
int GetComplexMarking(int val)
{
if (val == 31 || val == 1)
return 1;
if (val == 30 || val == 0)
return 2;
return 0;
}
}
///
/// Sets one of the based on its index within the array.
///
/// Pokémon to modify.
/// Index to set to
/// Value to set
public static void SetEV(this PKM pk, int index, int value)
{
switch (index)
{
case 0: pk.EV_HP = value; break;
case 1: pk.EV_ATK = value; break;
case 2: pk.EV_DEF = value; break;
case 3: pk.EV_SPE = value; break;
case 4: pk.EV_SPA = value; break;
case 5: pk.EV_SPD = value; break;
default:
throw new ArgumentOutOfRangeException(nameof(index));
}
}
///
/// Sets one of the based on its index within the array.
///
/// Pokémon to modify.
/// Index to set to
/// Value to set
public static void SetIV(this PKM pk, int index, int value)
{
switch (index)
{
case 0: pk.IV_HP = value; break;
case 1: pk.IV_ATK = value; break;
case 2: pk.IV_DEF = value; break;
case 3: pk.IV_SPE = value; break;
case 4: pk.IV_SPA = value; break;
case 5: pk.IV_SPD = value; break;
default:
throw new ArgumentOutOfRangeException(nameof(index));
}
}
///
/// Updates the for a Generation 1/2 format .
///
/// Pokémon to modify.
/// Desired .
public static void SetATKIVGender(this PKM pk, int gender)
{
do { pk.IV_ATK = (int)(Util.Rand32() & pk.MaxIV); }
while (pk.Gender != gender);
}
///
/// Fetches the highest value the provided index can be while considering others.
///
/// Pokémon to modify.
/// Index to fetch for
/// Highest value the value can be.
public static int GetMaximumEV(this PKM pk, int index)
{
if (pk.Format < 3)
return ushort.MaxValue;
var EVs = pk.EVs;
EVs[index] = 0;
var sum = EVs.Sum();
int remaining = 510 - sum;
var newEV = Math.Min(Math.Max(remaining, 0), 252);
return newEV;
}
///
/// Fetches the highest value the provided .
///
/// Pokémon to modify.
/// Index to fetch for
/// Causes the returned value to be dropped down -1 if the value is already at a maxmimum.
/// Highest value the value can be.
public static int GetMaximumIV(this PKM pk, int index, bool Allow30 = false)
{
if (pk.IVs[index] == pk.MaxIV && Allow30)
return pk.MaxIV - 1;
return pk.MaxIV;
}
///
/// Sets the to match a provided .
///
/// Pokémon to modify.
/// Desired Hidden Power typing.
public static void SetHiddenPower(this PKM pk, int hptype)
{
var IVs = pk.IVs;
HiddenPower.SetIVsForType(hptype, pk.IVs);
pk.IVs = IVs;
}
///
/// Sets the to match a provided .
///
/// Pokémon to modify.
/// Desired Hidden Power typing.
public static void SetHiddenPower(this PKM pk, MoveType hptype) => pk.SetHiddenPower((int) hptype);
}
}