private static void SetAbility(PKM pk, IBattleTemplate set, AbilityPermission preference) { if (pk.Ability != set.Ability && set.Ability != -1) { pk.SetAbility(set.Ability); } if (preference > 0) { var abilities = pk.PersonalInfo.Abilities; // Set unspecified abilities if (set.Ability == -1) { pk.RefreshAbility(preference.GetSingleValue()); if (pk is PK5 pk5 && preference == AbilityPermission.OnlyHidden) { pk5.HiddenAbility = true; } } // Set preferred ability number if applicable if (abilities[preference.GetSingleValue()] == set.Ability) { pk.AbilityNumber = (int)preference; } // 3/4/5 transferred to 6+ will have ability 1 if both abilitynum 1 and 2 are the same. Capsule cant convert 1 -> 2 if the abilities arnt unique if (pk.Format >= 6 && pk.Generation is 3 or 4 or 5 && pk.AbilityNumber != 4 && abilities[0] == abilities[1]) { pk.AbilityNumber = 1; } if (pk is G3PKM && abilities[0] == abilities[1]) { pk.AbilityNumber = 1; } } }
public static void IsFixedAbility(AbilityPermission value, bool expect, int zeroIndex) { var result = value.IsSingleValue(out var index); result.Should().Be(expect); if (result) { index.Should().Be(zeroIndex); } }
public static void ApplyDetails(PKM pk, EncounterCriteria criteria, Shiny shiny = Shiny.FixedValue, int flawless = -1, AbilityPermission ability = AbilityPermission.Any12) { if (shiny == Shiny.FixedValue) { shiny = criteria.Shiny is Shiny.Random or Shiny.Never ? Shiny.Never : Shiny.Always; } if (flawless == -1) { flawless = 0; } int ctr = 0; const int maxAttempts = 50_000; var rnd = Util.Rand; do { ulong s0 = rnd.Rand64(); ulong s1 = rnd.Rand64(); var xors = new XorShift128(s0, s1); if (TryApplyFromSeed(pk, criteria, shiny, flawless, xors, ability)) { return; } } while (++ctr != maxAttempts); { ulong s0 = rnd.Rand64(); ulong s1 = rnd.Rand64(); var xors = new XorShift128(s0, s1); TryApplyFromSeed(pk, EncounterCriteria.Unrestricted, shiny, flawless, xors, ability); } }
private static int RemapAbilityToParam(AbilityPermission a) => a switch {
public static bool TryApplyFromSeed(PKM pk, EncounterCriteria criteria, Shiny shiny, int flawless, XorShift128 xors, AbilityPermission ability) { // Encryption Constant pk.EncryptionConstant = xors.NextUInt(); // PID var fakeTID = xors.NextUInt(); // fakeTID var pid = xors.NextUInt(); pid = GetRevisedPID(fakeTID, pid, pk); if (shiny == Shiny.Never) { if (GetIsShiny(pk.TID, pk.SID, pid)) { return(false); } } else if (shiny != Shiny.Random) { if (!GetIsShiny(pk.TID, pk.SID, pid)) { return(false); } if (shiny == Shiny.AlwaysSquare && pk.ShinyXor != 0) { return(false); } if (shiny == Shiny.AlwaysStar && pk.ShinyXor == 0) { return(false); } } pk.PID = pid; // Check IVs: Create flawless IVs at random indexes, then the random IVs for not flawless. Span <int> ivs = stackalloc[] { UNSET, UNSET, UNSET, UNSET, UNSET, UNSET }; const int MAX = 31; var determined = 0; while (determined < flawless) { var idx = (int)xors.NextUInt(6); if (ivs[idx] != UNSET) { continue; } ivs[idx] = 31; determined++; } for (var i = 0; i < ivs.Length; i++) { if (ivs[i] == UNSET) { ivs[i] = xors.NextInt(0, MAX + 1); } } if (!criteria.IsIVsCompatible(ivs, 8)) { return(false); } pk.IV_HP = ivs[0]; pk.IV_ATK = ivs[1]; pk.IV_DEF = ivs[2]; pk.IV_SPA = ivs[3]; pk.IV_SPD = ivs[4]; pk.IV_SPE = ivs[5]; // Ability var n = ability switch { AbilityPermission.Any12 => (int)xors.NextUInt(2), AbilityPermission.Any12H => (int)xors.NextUInt(3), _ => (int)ability >> 1, }; pk.SetAbilityIndex(n); // Gender (skip this if gender is fixed) var genderRatio = PersonalTable.BDSP.GetFormEntry(pk.Species, pk.Form).Gender; if (genderRatio == PersonalInfo.RatioMagicGenderless) { pk.Gender = 2; } else if (genderRatio == PersonalInfo.RatioMagicMale) { pk.Gender = 0; } else if (genderRatio == PersonalInfo.RatioMagicFemale) { pk.Gender = 1; } else { var next = (((int)xors.NextUInt(253) + 1 < genderRatio) ? 1 : 0); if (criteria.Gender is 0 or 1 && next != criteria.Gender) { return(false); } pk.Gender = next; } if (criteria.Nature is Nature.Random) { pk.Nature = (int)xors.NextUInt(25); } else // Skip nature, assuming Synchronize { pk.Nature = (int)criteria.Nature; } pk.StatNature = pk.Nature; // Remainder var scale = (IScaledSize)pk; scale.HeightScalar = (byte)((int)xors.NextUInt(0x81) + (int)xors.NextUInt(0x80)); scale.WeightScalar = (byte)((int)xors.NextUInt(0x81) + (int)xors.NextUInt(0x80)); // Item, don't care return(true); }
public static int GetSingleValue(this AbilityPermission value) => value switch {
/// <summary> /// Set Nature and Ability of the pokemon /// </summary> /// <param name="pk">PKM to modify</param> /// <param name="set">Showdown Set to refer</param> /// <param name="enc">Encounter to reference</param> /// <param name="preference">Ability index (1/2/4) preferred; <= 0 for any</param> public static void SetNatureAbility(this PKM pk, IBattleTemplate set, IEncounterable enc, AbilityPermission preference = AbilityPermission.Any12H) { SetNature(pk, set, enc); SetAbility(pk, set, preference); }
public static void IsHiddenPossible(AbilityPermission value, bool expect) => value.CanBeHidden().Should().Be(expect);