mirror of
https://github.com/kwsch/PKHeX
synced 2024-11-10 06:34:19 +00:00
Remove PersonalInfo.Abilities, use interfaces
If you must get a list of abilities, then use the span extension methods. Also reworks some initial moveset fetching to allocate less
This commit is contained in:
parent
a97e74e628
commit
1960b335fd
39 changed files with 321 additions and 466 deletions
|
@ -56,7 +56,7 @@ public static class CommonEdits
|
|||
{
|
||||
if (abil < 0)
|
||||
return;
|
||||
var index = pk.PersonalInfo.GetAbilityIndex(abil);
|
||||
var index = pk.PersonalInfo.GetIndexOfAbility(abil);
|
||||
index = Math.Max(0, index);
|
||||
pk.SetAbilityIndex(index);
|
||||
}
|
||||
|
|
|
@ -80,21 +80,18 @@ public sealed class FilteredGameDataSource
|
|||
|
||||
public IReadOnlyList<ComboItem> GetAbilityList(PKM pk)
|
||||
{
|
||||
var abilities = pk.PersonalInfo.Abilities;
|
||||
int format = pk.Format;
|
||||
return GetAbilityList(abilities, format);
|
||||
return GetAbilityList(pk.PersonalInfo, pk.Format);
|
||||
}
|
||||
|
||||
public IReadOnlyList<ComboItem> GetAbilityList(IReadOnlyList<int> abilities, int format)
|
||||
public IReadOnlyList<ComboItem> GetAbilityList(IPersonalAbility pi, int format)
|
||||
{
|
||||
var count = format == 3 && (abilities[1] == 0 || abilities[1] == abilities[0]) ? 1 : abilities.Count;
|
||||
var list = new ComboItem[count];
|
||||
var list = new ComboItem[pi.AbilityCount];
|
||||
|
||||
var alist = Source.Strings.Ability;
|
||||
var suffix = AbilityIndexSuffixes;
|
||||
for (int i = 0; i < list.Length; i++)
|
||||
{
|
||||
var ability = abilities[i];
|
||||
var ability = pi.GetAbilityAtIndex(i);
|
||||
list[i] = new ComboItem(alist[ability] + suffix[i], ability);
|
||||
}
|
||||
|
||||
|
|
|
@ -124,7 +124,8 @@ public abstract record EncounterSlot(EncounterArea Area, ushort Species, byte Fo
|
|||
|
||||
protected virtual void SetEncounterMoves(PKM pk, GameVersion version, int level)
|
||||
{
|
||||
var moves = MoveLevelUp.GetEncounterMoves(pk, level, version);
|
||||
Span<ushort> moves = stackalloc ushort[4];
|
||||
MoveLevelUp.GetEncounterMoves(moves, pk, level, version);
|
||||
pk.SetMoves(moves);
|
||||
pk.SetMaximumPPCurrent(moves);
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
using System;
|
||||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
/// <summary>
|
||||
|
@ -47,7 +49,8 @@ public sealed record EncounterSlot7GO : EncounterSlotGO
|
|||
|
||||
protected override void SetEncounterMoves(PKM pk, GameVersion version, int level)
|
||||
{
|
||||
var moves = MoveLevelUp.GetEncounterMoves(pk, level, GameVersion.GG);
|
||||
Span<ushort> moves = stackalloc ushort[4];
|
||||
MoveLevelUp.GetEncounterMoves(moves, pk, level, GameVersion.GG);
|
||||
pk.SetMoves(moves);
|
||||
pk.SetMaximumPPCurrent(moves);
|
||||
}
|
||||
|
|
|
@ -120,9 +120,8 @@ public sealed record EncounterSlot8GO : EncounterSlotGO, IFixedOTFriendship
|
|||
pk.Gender = gender;
|
||||
|
||||
pk.AbilityNumber = 1 << ability;
|
||||
var abilities = pi.Abilities;
|
||||
if ((uint)ability < abilities.Count)
|
||||
pk.Ability = abilities[ability];
|
||||
if ((uint)ability < pi.AbilityCount)
|
||||
pk.Ability = pi.GetAbilityAtIndex(ability);
|
||||
|
||||
pk.SetRandomIVsGO();
|
||||
base.SetPINGA(pk, criteria);
|
||||
|
@ -130,12 +129,20 @@ public sealed record EncounterSlot8GO : EncounterSlotGO, IFixedOTFriendship
|
|||
|
||||
protected override void SetEncounterMoves(PKM pk, GameVersion version, int level)
|
||||
{
|
||||
var moves = GetInitialMoves(level);
|
||||
Span<ushort> moves = stackalloc ushort[4];
|
||||
GetInitialMoves(level, moves);
|
||||
pk.SetMoves(moves);
|
||||
pk.SetMaximumPPCurrent(moves);
|
||||
}
|
||||
|
||||
public ReadOnlySpan<ushort> GetInitialMoves(int level) => MoveLevelUp.GetEncounterMoves(Species, Form, level, OriginGroup);
|
||||
public void GetInitialMoves(int level, Span<ushort> moves) => MoveLevelUp.GetEncounterMoves(moves, Species, Form, level, OriginGroup);
|
||||
|
||||
public ReadOnlySpan<ushort> GetInitialMoves(int level)
|
||||
{
|
||||
var result = new ushort[4];
|
||||
GetInitialMoves(level, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
public override EncounterMatchRating GetMatchRating(PKM pk)
|
||||
{
|
||||
|
|
|
@ -165,7 +165,8 @@ public abstract record EncounterStatic(GameVersion Version) : IEncounterable, IM
|
|||
}
|
||||
else
|
||||
{
|
||||
var moves = MoveLevelUp.GetEncounterMoves(pk, level, version);
|
||||
Span<ushort> moves = stackalloc ushort[4];
|
||||
MoveLevelUp.GetEncounterMoves(moves, pk, level, version);
|
||||
pk.SetMoves(moves);
|
||||
pk.SetMaximumPPCurrent(moves);
|
||||
}
|
||||
|
|
|
@ -50,12 +50,12 @@ public abstract record EncounterStatic8Nest<T>(GameVersion Version) : EncounterS
|
|||
var num = pk.AbilityNumber;
|
||||
if (num == 4)
|
||||
{
|
||||
if (Ability is not OnlyHidden && !AbilityVerifier.CanAbilityPatch(8, PersonalTable.SWSH.GetFormEntry(Species, Form).Abilities, pk.Species))
|
||||
if (Ability is not OnlyHidden && !AbilityVerifier.CanAbilityPatch(8, PersonalTable.SWSH.GetFormEntry(Species, Form), pk.Species))
|
||||
return EncounterMatchRating.DeferredErrors;
|
||||
}
|
||||
else if (Ability.IsSingleValue(out int index) && 1 << index != num) // Fixed regular ability
|
||||
{
|
||||
if (Ability is OnlyFirst or OnlySecond && !AbilityVerifier.CanAbilityCapsule(8, PersonalTable.SWSH.GetFormEntry(Species, Form).Abilities))
|
||||
if (Ability is OnlyFirst or OnlySecond && !AbilityVerifier.CanAbilityCapsule(8, PersonalTable.SWSH.GetFormEntry(Species, Form)))
|
||||
return EncounterMatchRating.DeferredErrors;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -165,7 +165,8 @@ public abstract record EncounterTrade(GameVersion Version) : IEncounterable, IMo
|
|||
}
|
||||
else
|
||||
{
|
||||
var moves = MoveLevelUp.GetEncounterMoves(pk, level, version);
|
||||
Span<ushort> moves = stackalloc ushort[4];
|
||||
MoveLevelUp.GetEncounterMoves(moves, pk, level, version);
|
||||
pk.SetMoves(moves);
|
||||
pk.SetMaximumPPCurrent(moves);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using static PKHeX.Core.AbilityPermission;
|
||||
|
||||
namespace PKHeX.Core;
|
||||
|
@ -106,22 +105,22 @@ public sealed record EncounterCriteria
|
|||
|
||||
private static AbilityPermission GetAbilityNumber(int ability, IPersonalAbility pi)
|
||||
{
|
||||
var abilities = pi.Abilities;
|
||||
if (abilities.Count < 2)
|
||||
return 0;
|
||||
var dual = GetAbilityValueDual(ability, abilities);
|
||||
if (abilities.Count == 2) // prior to gen5
|
||||
var count = pi.AbilityCount;
|
||||
if (count < 2 || pi is not IPersonalAbility12 a)
|
||||
return Any12;
|
||||
var dual = GetAbilityValueDual(ability, a);
|
||||
if (count == 2 || pi is not IPersonalAbility12H h) // prior to gen5
|
||||
return dual;
|
||||
if (abilities[2] == ability)
|
||||
return dual == 0 ? Any12H : OnlyHidden;
|
||||
if (ability == h.AbilityH)
|
||||
return dual == Any12 ? Any12H : OnlyHidden;
|
||||
return dual;
|
||||
}
|
||||
|
||||
private static AbilityPermission GetAbilityValueDual(int ability, IReadOnlyList<int> abilities)
|
||||
private static AbilityPermission GetAbilityValueDual(int ability, IPersonalAbility12 a)
|
||||
{
|
||||
if (ability == abilities[0])
|
||||
return ability != abilities[1] ? OnlyFirst : Any12;
|
||||
return ability == abilities[1] ? OnlySecond : Any12;
|
||||
if (ability == a.Ability1)
|
||||
return ability != a.Ability2 ? OnlyFirst : Any12;
|
||||
return ability == a.Ability2 ? OnlySecond : Any12;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -36,7 +36,9 @@ public static class LearnPossible
|
|||
return;
|
||||
if (enc is EncounterSlot8GO g)
|
||||
{
|
||||
SetAll(g.GetInitialMoves(pk.Met_Level), result);
|
||||
Span<ushort> initial = stackalloc ushort[4];
|
||||
g.GetInitialMoves(pk.Met_Level, initial);
|
||||
SetAll(initial, result);
|
||||
}
|
||||
else if (enc.Generation >= 6)
|
||||
{
|
||||
|
|
|
@ -49,10 +49,16 @@ internal static class LearnVerifierHistory
|
|||
|
||||
private static void MarkSpecialMoves(Span<MoveResult> result, ReadOnlySpan<ushort> current, IEncounterTemplate enc, PKM pk)
|
||||
{
|
||||
if (enc is IMoveset { Moves: {HasMoves: true} moves})
|
||||
if (enc is IMoveset { Moves: { HasMoves: true } moves })
|
||||
{
|
||||
MarkInitialMoves(result, current, moves);
|
||||
}
|
||||
else if (enc is EncounterSlot8GO g)
|
||||
MarkInitialMoves(result, current, g.GetInitialMoves(pk.Met_Level));
|
||||
{
|
||||
Span<ushort> initial = stackalloc ushort[4];
|
||||
g.GetInitialMoves(pk.Met_Level, initial);
|
||||
MarkInitialMoves(result, current, initial);
|
||||
}
|
||||
}
|
||||
|
||||
private static bool Iterate(Span<MoveResult> result, ReadOnlySpan<ushort> current, PKM pk, EvolutionHistory history, IEncounterTemplate enc, ILearnGroup game, MoveSourceType types, LearnOption option)
|
||||
|
|
|
@ -188,19 +188,6 @@ public sealed class Learnset
|
|||
}
|
||||
}
|
||||
|
||||
public IList<int> GetUniqueMovesLearned(IEnumerable<int> seed, int maxLevel, int minLevel = 0)
|
||||
{
|
||||
int start = Array.FindIndex(Levels, z => z >= minLevel);
|
||||
int end = Array.FindLastIndex(Levels, z => z <= maxLevel);
|
||||
var list = new List<int>(seed);
|
||||
for (int i = start; i <= end; i++)
|
||||
{
|
||||
if (!list.Contains(Moves[i]))
|
||||
list.Add(Moves[i]);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
/// <summary>Returns the index of the lowest level move if the Pokémon were encountered at the specified level.</summary>
|
||||
/// <remarks>Helps determine the minimum level an encounter can be at.</remarks>
|
||||
/// <param name="level">The level the Pokémon was encountered at.</param>
|
||||
|
|
|
@ -6,48 +6,45 @@ namespace PKHeX.Core;
|
|||
|
||||
public static class MoveLevelUp
|
||||
{
|
||||
public static ushort[] GetEncounterMoves(PKM pk, int level, GameVersion version)
|
||||
public static void GetEncounterMoves(Span<ushort> moves, PKM pk, int level, GameVersion version)
|
||||
{
|
||||
if (version <= 0)
|
||||
version = (GameVersion)pk.Version;
|
||||
return GetEncounterMoves(pk.Species, pk.Form, level, version);
|
||||
GetEncounterMoves(moves, pk.Species, pk.Form, level, version);
|
||||
}
|
||||
|
||||
private static ushort[] GetEncounterMoves1(ushort species, int level, GameVersion version)
|
||||
private static void GetEncounterMoves1(Span<ushort> result, ushort species, int level, GameVersion version)
|
||||
{
|
||||
var learn = GameData.GetLearnsets(version);
|
||||
var table = GameData.GetPersonal(version);
|
||||
var table = version is YW or RBY ? PersonalTable.Y : PersonalTable.RB;
|
||||
var index = table.GetFormIndex(species, 0);
|
||||
|
||||
Span<ushort> lvl0 = stackalloc ushort[4];
|
||||
((PersonalInfo1) table[index]).GetMoves(lvl0);
|
||||
int start = Math.Max(0, lvl0.IndexOf((ushort)0));
|
||||
// The initial moves are seeded from Personal rather than learn.
|
||||
table[index].GetMoves(result);
|
||||
int start = Math.Max(0, result.IndexOf((ushort)0));
|
||||
|
||||
learn[index].SetEncounterMoves(level, lvl0, start);
|
||||
return lvl0.ToArray();
|
||||
learn[index].SetEncounterMoves(level, result, start);
|
||||
}
|
||||
|
||||
private static ushort[] GetEncounterMoves2(ushort species, int level, GameVersion version)
|
||||
public static void GetEncounterMoves(Span<ushort> result, ushort species, byte form, int level, GameVersion version)
|
||||
{
|
||||
var learn = GameData.GetLearnsets(version);
|
||||
var table = GameData.GetPersonal(version);
|
||||
var index = table.GetFormIndex(species, 0);
|
||||
var lvl0 = learn[species].GetEncounterMoves(1);
|
||||
int start = Math.Max(0, Array.IndexOf(lvl0, (ushort)0));
|
||||
|
||||
learn[index].SetEncounterMoves(level, lvl0, start);
|
||||
return lvl0;
|
||||
if (RBY.Contains(version))
|
||||
{
|
||||
GetEncounterMoves1(result, species, level, version);
|
||||
}
|
||||
else
|
||||
{
|
||||
var learn = GameData.GetLearnsets(version);
|
||||
var table = GameData.GetPersonal(version);
|
||||
var index = table.GetFormIndex(species, form);
|
||||
learn[index].SetEncounterMoves(level, result);
|
||||
}
|
||||
}
|
||||
|
||||
public static ushort[] GetEncounterMoves(ushort species, byte form, int level, GameVersion version)
|
||||
{
|
||||
if (RBY.Contains(version))
|
||||
return GetEncounterMoves1(species, level, version);
|
||||
if (GSC.Contains(version))
|
||||
return GetEncounterMoves2(species, level, version);
|
||||
var learn = GameData.GetLearnsets(version);
|
||||
var table = GameData.GetPersonal(version);
|
||||
var index = table.GetFormIndex(species, form);
|
||||
return learn[index].GetEncounterMoves(level);
|
||||
var result = new ushort[4];
|
||||
GetEncounterMoves(result, species, form, level, version);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using static PKHeX.Core.LegalityCheckStrings;
|
||||
|
||||
namespace PKHeX.Core;
|
||||
|
@ -29,34 +28,33 @@ public sealed class AbilityVerifier : Verifier
|
|||
private CheckResult VerifyAbility(LegalityAnalysis data)
|
||||
{
|
||||
var pk = data.Entity;
|
||||
var pi = data.PersonalInfo;
|
||||
var abilities = (IPersonalAbility12)data.PersonalInfo;
|
||||
|
||||
// Check ability is possible (within bounds)
|
||||
int ability = pk.Ability;
|
||||
int abilIndex = pi.GetAbilityIndex(ability);
|
||||
int abilIndex = abilities.GetIndexOfAbility(ability);
|
||||
if (abilIndex < 0)
|
||||
return GetInvalid(LAbilityUnexpected);
|
||||
|
||||
var abilities = pi.Abilities;
|
||||
int format = pk.Format;
|
||||
if (format >= 6)
|
||||
{
|
||||
var num = pk.AbilityNumber;
|
||||
if (!IsValidAbilityBits(num))
|
||||
var bitNum = pk.AbilityNumber;
|
||||
if (!IsValidAbilityBits(bitNum))
|
||||
return INVALID;
|
||||
|
||||
// Check AbilityNumber points to ability
|
||||
int an = num >> 1;
|
||||
if (an >= abilities.Count || abilities[an] != ability)
|
||||
int abilityIndex = bitNum >> 1;
|
||||
if (abilityIndex >= abilities.AbilityCount || abilities.GetAbilityAtIndex(abilityIndex) != ability)
|
||||
return INVALID;
|
||||
|
||||
// Check AbilityNumber for transfers without unique abilities
|
||||
int gen = data.Info.Generation;
|
||||
if (gen is 3 or 4 or 5 && num != 4)
|
||||
if (gen is 3 or 4 or 5 && bitNum != 4)
|
||||
{
|
||||
// To determine AbilityNumber [PK5->PK6], check if the first ability in Personal matches the ability.
|
||||
// It is not possible to flip it to the other index as capsule requires unique abilities.
|
||||
if (abilities[0] == abilities[1] && num != 1)
|
||||
if (abilities.GetIsAbility12Same() && bitNum != 1)
|
||||
{
|
||||
// Check if any pre-evolution could have it flipped.
|
||||
var evos = data.Info.EvoChainsAllGens.Gen6;
|
||||
|
@ -70,14 +68,18 @@ public sealed class AbilityVerifier : Verifier
|
|||
if (format >= 8) // Ability Patch
|
||||
{
|
||||
var evos = data.Info.EvoChainsAllGens;
|
||||
if (pk.AbilityNumber == 4 && IsAccessibleAbilityPatch(evos))
|
||||
if (pk.AbilityNumber == 4 && IsAccessibleAbilityPatch(evos) && abilities is IPersonalAbility12H h)
|
||||
{
|
||||
if (CanAbilityPatch(format, abilities, pk.Species))
|
||||
if (CanAbilityPatch(format, h, pk.Species))
|
||||
return GetValid(LAbilityPatchUsed);
|
||||
|
||||
var e = data.EncounterOriginal;
|
||||
if (e.Species != pk.Species && CanAbilityPatch(format, PKX.Personal.GetFormEntry(e.Species, e.Form).Abilities, e.Species))
|
||||
return GetValid(LAbilityPatchUsed);
|
||||
if (e.Species != pk.Species)
|
||||
{
|
||||
var temp = (IPersonalAbility12H)PKX.Personal.GetFormEntry(e.Species, e.Form);
|
||||
if (CanAbilityPatch(format, temp, e.Species))
|
||||
return GetValid(LAbilityPatchUsed);
|
||||
}
|
||||
|
||||
// Verify later, it may be encountered with its hidden ability without using an ability patch.
|
||||
}
|
||||
|
@ -93,7 +95,7 @@ public sealed class AbilityVerifier : Verifier
|
|||
return VerifyAbility(data, abilities, abilIndex);
|
||||
}
|
||||
|
||||
public static bool IsValidAbilityBits(int num) => num is 1 or 2 or 4;
|
||||
public static bool IsValidAbilityBits(int bitNum) => bitNum is 1 or 2 or 4;
|
||||
|
||||
private static bool GetWasDual(ReadOnlySpan<EvoCriteria> evos, IPersonalTable pt, ISpeciesForm pk)
|
||||
{
|
||||
|
@ -102,16 +104,15 @@ public sealed class AbilityVerifier : Verifier
|
|||
if (evo.Species == pk.Species)
|
||||
continue;
|
||||
|
||||
var pe = pt.GetFormEntry(evo.Species, evo.Form);
|
||||
var abils = pe.Abilities;
|
||||
if (CanAbilityCapsule(6, abils))
|
||||
var abilities = (IPersonalAbility12)pt.GetFormEntry(evo.Species, evo.Form);
|
||||
if (CanAbilityCapsule(6, abilities))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private CheckResult VerifyAbility(LegalityAnalysis data, IReadOnlyList<int> abilities, int abilIndex)
|
||||
private CheckResult VerifyAbility(LegalityAnalysis data, IPersonalAbility12 abilities, int abilIndex)
|
||||
{
|
||||
var enc = data.EncounterMatch;
|
||||
var eabil = enc.Ability;
|
||||
|
@ -135,12 +136,12 @@ public sealed class AbilityVerifier : Verifier
|
|||
};
|
||||
}
|
||||
|
||||
private CheckResult VerifyAbility345(LegalityAnalysis data, IEncounterable enc, IReadOnlyList<int> abilities, int abilIndex)
|
||||
private CheckResult VerifyAbility345(LegalityAnalysis data, IEncounterable enc, IPersonalAbility12 abilities, int abilIndex)
|
||||
{
|
||||
var pk = data.Entity;
|
||||
int format = pk.Format;
|
||||
var state = AbilityState.MustMatch;
|
||||
if (format is (3 or 4 or 5) && abilities[0] != abilities[1]) // 3-4/5 and have 2 distinct abilities now
|
||||
if (format is (3 or 4 or 5) && !abilities.GetIsAbility12Same()) // 3-4/5 and have 2 distinct abilities now
|
||||
state = VerifyAbilityPreCapsule(data, abilities);
|
||||
|
||||
var encounterAbility = enc.Ability;
|
||||
|
@ -159,7 +160,7 @@ public sealed class AbilityVerifier : Verifier
|
|||
return CheckMatch(pk, abilities, gen, state, enc);
|
||||
}
|
||||
|
||||
private CheckResult VerifyFixedAbility(LegalityAnalysis data, IReadOnlyList<int> abilities, AbilityState state, AbilityPermission encounterAbility, int abilIndex)
|
||||
private CheckResult VerifyFixedAbility(LegalityAnalysis data, IPersonalAbility12 abilities, AbilityState state, AbilityPermission encounterAbility, int abilIndex)
|
||||
{
|
||||
var pk = data.Entity;
|
||||
var enc = data.Info.EncounterMatch;
|
||||
|
@ -210,7 +211,7 @@ public sealed class AbilityVerifier : Verifier
|
|||
return INVALID;
|
||||
}
|
||||
|
||||
private AbilityState VerifyAbilityPreCapsule(LegalityAnalysis data, IReadOnlyList<int> abilities)
|
||||
private AbilityState VerifyAbilityPreCapsule(LegalityAnalysis data, IPersonalAbility12 abilities)
|
||||
{
|
||||
var info = data.Info;
|
||||
// Gen4/5 origin
|
||||
|
@ -242,7 +243,7 @@ public sealed class AbilityVerifier : Verifier
|
|||
return VerifyAbilityGen3Transfer(data, abilities, maxGen3Species);
|
||||
}
|
||||
|
||||
private AbilityState VerifyAbilityGen3Transfer(LegalityAnalysis data, IReadOnlyList<int> abilities, int maxGen3Species)
|
||||
private AbilityState VerifyAbilityGen3Transfer(LegalityAnalysis data, IPersonalAbility12 abilities, int maxGen3Species)
|
||||
{
|
||||
var pk = data.Entity;
|
||||
var pers = PersonalTable.E[maxGen3Species];
|
||||
|
@ -259,7 +260,7 @@ public sealed class AbilityVerifier : Verifier
|
|||
if (pk.Ability == pers.Ability1) // Could evolve in Gen4/5 and have a Gen3 only ability
|
||||
return AbilityState.CanMismatch; // Not evolved in Gen4/5, doesn't need to match PIDAbility
|
||||
|
||||
if (pk.Ability == abilities[1]) // It could evolve in Gen4/5 and have Gen4 second ability
|
||||
if (pk.Ability == abilities.Ability2) // It could evolve in Gen4/5 and have Gen4 second ability
|
||||
return AbilityState.MustMatch; // Evolved in Gen4/5, must match PIDAbility
|
||||
}
|
||||
|
||||
|
@ -271,7 +272,7 @@ public sealed class AbilityVerifier : Verifier
|
|||
return AbilityState.CanMismatch;
|
||||
}
|
||||
|
||||
private CheckResult VerifyAbilityMG(LegalityAnalysis data, MysteryGift g, IReadOnlyList<int> abilities)
|
||||
private CheckResult VerifyAbilityMG(LegalityAnalysis data, MysteryGift g, IPersonalAbility12 abilities)
|
||||
{
|
||||
if (g is PCD d)
|
||||
return VerifyAbilityPCD(data, abilities, d);
|
||||
|
@ -312,7 +313,7 @@ public sealed class AbilityVerifier : Verifier
|
|||
return pk.Format < 6 ? GetInvalid(LAbilityMismatchPID) : INVALID;
|
||||
}
|
||||
|
||||
private CheckResult VerifyAbilityPCD(LegalityAnalysis data, IReadOnlyList<int> abilities, PCD pcd)
|
||||
private CheckResult VerifyAbilityPCD(LegalityAnalysis data, IPersonalAbility12 abilities, PCD pcd)
|
||||
{
|
||||
var pk = data.Entity;
|
||||
var format = pk.Format;
|
||||
|
@ -336,7 +337,7 @@ public sealed class AbilityVerifier : Verifier
|
|||
return pk.Ability == pcd.Gift.PK.Ability ? VALID : INVALID;
|
||||
}
|
||||
|
||||
private CheckResult VerifyAbility5(LegalityAnalysis data, IEncounterTemplate enc, IReadOnlyList<int> abilities)
|
||||
private CheckResult VerifyAbility5(LegalityAnalysis data, IEncounterTemplate enc, IPersonalAbility12 abilities)
|
||||
{
|
||||
var pk = data.Entity;
|
||||
|
||||
|
@ -396,7 +397,7 @@ public sealed class AbilityVerifier : Verifier
|
|||
/// <param name="gen">Generation</param>
|
||||
/// <param name="state">Permissive to allow ability to deviate under special circumstances</param>
|
||||
/// <param name="enc">Encounter template the <see cref="pk"/> was matched to.</param>
|
||||
private CheckResult CheckMatch(PKM pk, IReadOnlyList<int> abilities, int gen, AbilityState state, IEncounterTemplate enc)
|
||||
private CheckResult CheckMatch(PKM pk, IPersonalAbility12 abilities, int gen, AbilityState state, IEncounterTemplate enc)
|
||||
{
|
||||
if (gen is (3 or 4) && pk.AbilityNumber == 4)
|
||||
return GetInvalid(LAbilityHiddenUnavailable);
|
||||
|
@ -411,7 +412,7 @@ public sealed class AbilityVerifier : Verifier
|
|||
var abit = g3.AbilityBit;
|
||||
// We've sanitized our personal data to replace "None" abilities with the first ability.
|
||||
// Granbull, Vibrava, and Flygon have dual abilities being the same.
|
||||
if (abilities[0] == abilities[1] && g3.Species is not ((int)Species.Granbull or (int)Species.Vibrava or (int)Species.Flygon)) // Not a dual ability
|
||||
if (abilities.GetIsAbility12Same() && g3.Species is not ((int)Species.Granbull or (int)Species.Vibrava or (int)Species.Flygon)) // Not a dual ability
|
||||
{
|
||||
// Must not have the Ability bit flag set.
|
||||
// Shadow encounters set a random ability index; don't bother checking if it's a re-battle for ability bit flipping.
|
||||
|
@ -437,10 +438,11 @@ public sealed class AbilityVerifier : Verifier
|
|||
return GetPIDAbilityMatch(pk, abilities);
|
||||
}
|
||||
|
||||
private CheckResult GetPIDAbilityMatch(PKM pk, IReadOnlyList<int> abilities)
|
||||
private CheckResult GetPIDAbilityMatch(PKM pk, IPersonalAbility abilities)
|
||||
{
|
||||
// Ability Number bits are already verified as clean.
|
||||
var abil = abilities[pk.AbilityNumber >> 1];
|
||||
var index = pk.AbilityNumber >> 1;
|
||||
var abil = abilities.GetAbilityAtIndex(index);
|
||||
if (abil != pk.Ability)
|
||||
return GetInvalid(LAbilityMismatchPID);
|
||||
|
||||
|
@ -460,7 +462,7 @@ public sealed class AbilityVerifier : Verifier
|
|||
}
|
||||
|
||||
// Ability Capsule can change between 1/2
|
||||
private static bool IsAbilityCapsuleModified(PKM pk, IReadOnlyList<int> abilities, AbilityPermission encounterAbility, EvolutionHistory evos)
|
||||
private static bool IsAbilityCapsuleModified(PKM pk, IPersonalAbility12 abilities, AbilityPermission encounterAbility, EvolutionHistory evos)
|
||||
{
|
||||
if (!IsAccessibleAbilityCapsule(evos))
|
||||
return false; // Not available.
|
||||
|
@ -473,21 +475,20 @@ public sealed class AbilityVerifier : Verifier
|
|||
return true;
|
||||
}
|
||||
|
||||
public static bool CanAbilityCapsule(int format, IReadOnlyList<int> abilities)
|
||||
public static bool CanAbilityCapsule(int format, IPersonalAbility12 abilities)
|
||||
{
|
||||
if (format < 6) // Ability Capsule does not exist
|
||||
return false;
|
||||
return abilities[0] != abilities[1]; // Cannot alter ability index if it is the same as the other ability.
|
||||
return !abilities.GetIsAbility12Same(); // Cannot alter ability index if it is the same as the other ability.
|
||||
}
|
||||
|
||||
public static bool CanAbilityPatch(int format, IReadOnlyList<int> abilities, ushort species)
|
||||
public static bool CanAbilityPatch(int format, IPersonalAbility12H abilities, ushort species)
|
||||
{
|
||||
if (format < 8) // Ability Patch does not exist
|
||||
return false;
|
||||
|
||||
// Can alter ability index if it is different from the other abilities.
|
||||
var h = abilities[2];
|
||||
if (h != abilities[0] || h != abilities[1])
|
||||
if (abilities.GetIsAbilityPatchPossible())
|
||||
return true;
|
||||
|
||||
// Some species have a distinct hidden ability only on another form, and can change between that form and its current form.
|
||||
|
|
|
@ -448,7 +448,8 @@ public sealed class BallVerifier : Verifier
|
|||
{
|
||||
if (pk.AbilityNumber != 4)
|
||||
return false;
|
||||
return !AbilityVerifier.CanAbilityPatch(pk.Format, pk.PersonalInfo.Abilities, pk.Species);
|
||||
var abilities = (IPersonalAbility12H)pk.PersonalInfo;
|
||||
return !AbilityVerifier.CanAbilityPatch(pk.Format, abilities, pk.Species);
|
||||
}
|
||||
|
||||
private static bool IsGalarCatchAndBreed(ushort species)
|
||||
|
|
|
@ -73,9 +73,15 @@ public sealed class IndividualValueVerifier : Verifier
|
|||
{
|
||||
var pk = data.Entity;
|
||||
if (pk.GO)
|
||||
{
|
||||
VerifyIVsGoTransfer(data);
|
||||
else if (pk.AbilityNumber == 4 && !AbilityVerifier.CanAbilityPatch(pk.Format, pk.PersonalInfo.Abilities, pk.Species))
|
||||
VerifyIVsFlawless(data, 2); // Chain of 10 yields 5% HA and 2 flawless IVs
|
||||
}
|
||||
else if (pk.AbilityNumber == 4)
|
||||
{
|
||||
var abilities = (IPersonalAbility12H)pk.PersonalInfo;
|
||||
if (!AbilityVerifier.CanAbilityPatch(pk.Format, abilities, pk.Species))
|
||||
VerifyIVsFlawless(data, 2); // Chain of 10 yields 5% HA and 2 flawless IVs
|
||||
}
|
||||
}
|
||||
|
||||
private void VerifyIVsGen8(LegalityAnalysis data)
|
||||
|
|
|
@ -242,7 +242,11 @@ public sealed class PGF : DataMysteryGift, IRibbonSetEvent3, IRibbonSetEvent4, I
|
|||
pk.Version = (int)GameVersion.W + rnd.Next(4);
|
||||
|
||||
if (Move1 == 0) // No moves defined
|
||||
pk.Moves = MoveLevelUp.GetEncounterMoves(Species, Form, Level, (GameVersion)pk.Version);
|
||||
{
|
||||
Span<ushort> moves = stackalloc ushort[4];
|
||||
MoveLevelUp.GetEncounterMoves(moves, Species, Form, Level, (GameVersion)pk.Version);
|
||||
pk.SetMoves(moves);
|
||||
}
|
||||
|
||||
pk.SetMaximumPPCurrent();
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
using System;
|
||||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
/// <summary>
|
||||
|
@ -28,9 +30,12 @@ public static class BattleVersionExtensions
|
|||
/// <param name="version">Version to apply</param>
|
||||
public static void AdaptToBattleVersion(this IBattleVersion v, PKM pk, GameVersion version)
|
||||
{
|
||||
var moves = MoveLevelUp.GetEncounterMoves(pk, pk.CurrentLevel, version);
|
||||
pk.Move1 = pk.Move2 = pk.Move3 = pk.Move4 = 0;
|
||||
pk.RelearnMove1 = pk.RelearnMove2 = pk.RelearnMove3 = pk.RelearnMove4 = 0;
|
||||
var empty = new Moveset();
|
||||
pk.SetMoves(empty);
|
||||
pk.SetRelearnMoves(empty);
|
||||
|
||||
Span<ushort> moves = stackalloc ushort[4];
|
||||
MoveLevelUp.GetEncounterMoves(moves, pk, pk.CurrentLevel, version);
|
||||
pk.SetMoves(moves);
|
||||
pk.FixMoves();
|
||||
v.BattleVersion = (byte) version;
|
||||
|
|
|
@ -499,8 +499,10 @@ public sealed class PK6 : G6PKM, IRibbonSetEvent3, IRibbonSetEvent4, IRibbonSetC
|
|||
{
|
||||
case 1 or 2 or 4: // Valid Ability Numbers
|
||||
int index = an >> 1;
|
||||
if (PersonalInfo.Abilities[index] == Ability) // correct pair
|
||||
pk7.Ability = pk7.PersonalInfo.Abilities[index];
|
||||
|
||||
var abilities = (IPersonalAbility12H)PersonalInfo;
|
||||
if (abilities.GetAbilityAtIndex(index) == Ability) // correct pair
|
||||
pk7.Ability = pk7.PersonalInfo.GetAbilityAtIndex(index);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -503,7 +503,7 @@ public abstract class PKM : ISpeciesForm, ITrainerID, IGeneration, IShiny, ILang
|
|||
return -1;
|
||||
|
||||
if (Version == (int) CXD)
|
||||
return PersonalInfo.GetAbilityIndex(Ability); // Can mismatch; not tied to PID
|
||||
return PersonalInfo.GetIndexOfAbility(Ability); // Can mismatch; not tied to PID
|
||||
return (int)((Gen5 ? PID >> 16 : PID) & 1);
|
||||
}
|
||||
}
|
||||
|
@ -630,9 +630,9 @@ public abstract class PKM : ISpeciesForm, ITrainerID, IGeneration, IShiny, ILang
|
|||
public virtual void RefreshAbility(int n)
|
||||
{
|
||||
AbilityNumber = 1 << n;
|
||||
var abilities = PersonalInfo.Abilities;
|
||||
if ((uint)n < abilities.Count)
|
||||
Ability = abilities[n];
|
||||
IPersonalAbility pi = PersonalInfo;
|
||||
if ((uint)n < pi.AbilityCount)
|
||||
Ability = pi.GetAbilityAtIndex(n);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
|
@ -53,8 +52,9 @@ public sealed class PersonalInfo1 : PersonalInfo
|
|||
// Future game values, unused
|
||||
public override int EggGroup1 { get => 0; set { } }
|
||||
public override int EggGroup2 { get => 0; set { } }
|
||||
public override IReadOnlyList<int> Abilities { get => Array.Empty<int>(); set { } }
|
||||
public override int GetAbilityIndex(int abilityID) => -1;
|
||||
public override int GetIndexOfAbility(int abilityID) => -1;
|
||||
public override int GetAbilityAtIndex(int abilityIndex) => -1;
|
||||
public override int AbilityCount => 0;
|
||||
public override int Gender { get; set; }
|
||||
public override int HatchCycles { get => 0; set { } }
|
||||
public override int BaseFriendship { get => 0; set { } }
|
||||
|
|
|
@ -62,8 +62,9 @@ public sealed class PersonalInfo2 : PersonalInfo
|
|||
public override int EV_SPD { get => SPD; set { } }
|
||||
|
||||
// Future game values, unused
|
||||
public override IReadOnlyList<int> Abilities { get => Array.Empty<int>(); set { } }
|
||||
public override int GetAbilityIndex(int abilityID) => -1;
|
||||
public override int GetIndexOfAbility(int abilityID) => -1;
|
||||
public override int GetAbilityAtIndex(int abilityIndex) => -1;
|
||||
public override int AbilityCount => 0;
|
||||
public override int BaseFriendship { get => 70; set { } }
|
||||
public override int EscapeRate { get => 0; set { } }
|
||||
public override int Color { get => 0; set { } }
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using static System.Buffers.Binary.BinaryPrimitives;
|
||||
|
||||
namespace PKHeX.Core;
|
||||
|
@ -7,7 +6,7 @@ namespace PKHeX.Core;
|
|||
/// <summary>
|
||||
/// <see cref="PersonalInfo"/> class with values from Generation 3 games.
|
||||
/// </summary>
|
||||
public sealed class PersonalInfo3 : PersonalInfo
|
||||
public sealed class PersonalInfo3 : PersonalInfo, IPersonalAbility12
|
||||
{
|
||||
public const int SIZE = 0x1C;
|
||||
private readonly byte[] Data;
|
||||
|
@ -47,29 +46,14 @@ public sealed class PersonalInfo3 : PersonalInfo
|
|||
public override int Color { get => Data[0x19] & 0x7F; set => Data[0x19] = (byte)((Data[0x19] & 0x80) | value); }
|
||||
public bool NoFlip { get => Data[0x19] >> 7 == 1; set => Data[0x19] = (byte)(Color | (value ? 0x80 : 0)); }
|
||||
|
||||
public IReadOnlyList<int> Items
|
||||
public override int AbilityCount => 2;
|
||||
public override int GetIndexOfAbility(int abilityID) => abilityID == Ability1 ? 0 : abilityID == Ability2 ? 1 : -1;
|
||||
public override int GetAbilityAtIndex(int abilityIndex) => abilityIndex switch
|
||||
{
|
||||
get => new[] { Item1, Item2 };
|
||||
set
|
||||
{
|
||||
if (value.Count != 2) return;
|
||||
Item1 = value[0];
|
||||
Item2 = value[1];
|
||||
}
|
||||
}
|
||||
|
||||
public override IReadOnlyList<int> Abilities
|
||||
{
|
||||
get => new[] { Ability1, Ability2 };
|
||||
set
|
||||
{
|
||||
if (value.Count != 2) return;
|
||||
Ability1 = (byte)value[0];
|
||||
Ability2 = (byte)value[1];
|
||||
}
|
||||
}
|
||||
|
||||
public override int GetAbilityIndex(int abilityID) => abilityID == Ability1 ? 0 : abilityID == Ability2 ? 1 : -1;
|
||||
0 => Ability1,
|
||||
1 => Ability2,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(abilityIndex), abilityIndex, null),
|
||||
};
|
||||
public int GetAbility(bool second) => second && HasSecondAbility ? Ability2 : Ability1;
|
||||
|
||||
public bool HasSecondAbility => Ability1 != Ability2;
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using static System.Buffers.Binary.BinaryPrimitives;
|
||||
|
||||
namespace PKHeX.Core;
|
||||
|
@ -7,7 +6,7 @@ namespace PKHeX.Core;
|
|||
/// <summary>
|
||||
/// <see cref="PersonalInfo"/> class with values from Generation 4 games.
|
||||
/// </summary>
|
||||
public sealed class PersonalInfo4 : PersonalInfo
|
||||
public sealed class PersonalInfo4 : PersonalInfo, IPersonalAbility12
|
||||
{
|
||||
public const int SIZE = 0x2C;
|
||||
private readonly byte[] Data;
|
||||
|
@ -57,29 +56,14 @@ public sealed class PersonalInfo4 : PersonalInfo
|
|||
public override int Color { get => Data[0x19] & 0x7F; set => Data[0x19] = (byte)((Data[0x19] & 0x80) | value); }
|
||||
public bool NoFlip { get => Data[0x19] >> 7 == 1; set => Data[0x19] = (byte)(Color | (value ? 0x80 : 0)); }
|
||||
|
||||
public IReadOnlyList<int> Items
|
||||
public override int AbilityCount => 2;
|
||||
public override int GetIndexOfAbility(int abilityID) => abilityID == Ability1 ? 0 : abilityID == Ability2 ? 1 : -1;
|
||||
public override int GetAbilityAtIndex(int abilityIndex) => abilityIndex switch
|
||||
{
|
||||
get => new[] { Item1, Item2 };
|
||||
set
|
||||
{
|
||||
if (value.Count != 2) return;
|
||||
Item1 = value[0];
|
||||
Item2 = value[1];
|
||||
}
|
||||
}
|
||||
|
||||
public override IReadOnlyList<int> Abilities
|
||||
{
|
||||
get => new[] { Ability1, Ability2 };
|
||||
set
|
||||
{
|
||||
if (value.Count != 2) return;
|
||||
Ability1 = (byte)value[0];
|
||||
Ability2 = (byte)value[1];
|
||||
}
|
||||
}
|
||||
|
||||
public override int GetAbilityIndex(int abilityID) => abilityID == Ability1 ? 0 : abilityID == Ability2 ? 1 : -1;
|
||||
0 => Ability1,
|
||||
1 => Ability2,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(abilityIndex), abilityIndex, null),
|
||||
};
|
||||
public int GetAbility(bool second) => second && HasSecondAbility ? Ability2 : Ability1;
|
||||
|
||||
public bool HasSecondAbility => Ability1 != Ability2;
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using static System.Buffers.Binary.BinaryPrimitives;
|
||||
|
||||
namespace PKHeX.Core;
|
||||
|
@ -7,7 +6,7 @@ namespace PKHeX.Core;
|
|||
/// <summary>
|
||||
/// <see cref="PersonalInfo"/> class with values from the Black 2 & White 2 games.
|
||||
/// </summary>
|
||||
public sealed class PersonalInfo5B2W2 : PersonalInfo
|
||||
public sealed class PersonalInfo5B2W2 : PersonalInfo, IPersonalAbility12H
|
||||
{
|
||||
public const int SIZE = 0x4C;
|
||||
private readonly byte[] Data;
|
||||
|
@ -72,7 +71,7 @@ public sealed class PersonalInfo5B2W2 : PersonalInfo
|
|||
public override int EscapeRate { get => Data[0x1B]; set => Data[0x1B] = (byte)value; }
|
||||
public override int FormStatsIndex { get => ReadUInt16LittleEndian(Data.AsSpan(0x1C)); set => WriteUInt16LittleEndian(Data.AsSpan(0x1C), (ushort)value); }
|
||||
public int FormSprite { get => ReadUInt16LittleEndian(Data.AsSpan(0x1E)); set => WriteUInt16LittleEndian(Data.AsSpan(0x1E), (ushort)value); }
|
||||
public override byte FormCount { get => Data[0x20]; set => Data[0x20] = (byte)value; }
|
||||
public override byte FormCount { get => Data[0x20]; set => Data[0x20] = value; }
|
||||
public override int Color { get => Data[0x21] & 0x3F; set => Data[0x21] = (byte)((Data[0x21] & 0xC0) | (value & 0x3F)); }
|
||||
public bool SpriteFlip { get => ((Data[0x21] >> 6) & 1) == 1; set => Data[0x21] = (byte)((Data[0x21] & ~0x40) | (value ? 0x40 : 0)); }
|
||||
public bool SpriteForm { get => ((Data[0x21] >> 7) & 1) == 1; set => Data[0x21] = (byte)((Data[0x21] & ~0x80) | (value ? 0x80 : 0)); }
|
||||
|
@ -81,31 +80,15 @@ public sealed class PersonalInfo5B2W2 : PersonalInfo
|
|||
public override int Height { get => ReadUInt16LittleEndian(Data.AsSpan(0x24)); set => WriteUInt16LittleEndian(Data.AsSpan(0x24), (ushort)value); }
|
||||
public override int Weight { get => ReadUInt16LittleEndian(Data.AsSpan(0x26)); set => WriteUInt16LittleEndian(Data.AsSpan(0x26), (ushort)value); }
|
||||
|
||||
public IReadOnlyList<int> Items
|
||||
public override int AbilityCount => 3;
|
||||
public override int GetIndexOfAbility(int abilityID) => abilityID == Ability1 ? 0 : abilityID == Ability2 ? 1 : abilityID == AbilityH ? 2 : -1;
|
||||
public override int GetAbilityAtIndex(int abilityIndex) => abilityIndex switch
|
||||
{
|
||||
get => new[] { Item1, Item2, Item3 };
|
||||
set
|
||||
{
|
||||
if (value.Count != 3) return;
|
||||
Item1 = value[0];
|
||||
Item2 = value[1];
|
||||
Item3 = value[2];
|
||||
}
|
||||
}
|
||||
|
||||
public override IReadOnlyList<int> Abilities
|
||||
{
|
||||
get => new[] { Ability1, Ability2, AbilityH };
|
||||
set
|
||||
{
|
||||
if (value.Count != 3) return;
|
||||
Ability1 = (byte)value[0];
|
||||
Ability2 = (byte)value[1];
|
||||
AbilityH = (byte)value[2];
|
||||
}
|
||||
}
|
||||
|
||||
public override int GetAbilityIndex(int abilityID) => abilityID == Ability1 ? 0 : abilityID == Ability2 ? 1 : abilityID == AbilityH ? 2 : -1;
|
||||
0 => Ability1,
|
||||
1 => Ability2,
|
||||
2 => AbilityH,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(abilityIndex), abilityIndex, null),
|
||||
};
|
||||
|
||||
public bool HasHiddenAbility => AbilityH != Ability1;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using static System.Buffers.Binary.BinaryPrimitives;
|
||||
|
||||
namespace PKHeX.Core;
|
||||
|
@ -61,7 +60,7 @@ public sealed class PersonalInfo5BW : PersonalInfo, IPersonalAbility12H
|
|||
public override int EscapeRate { get => Data[0x1B]; set => Data[0x1B] = (byte)value; }
|
||||
public override int FormStatsIndex { get => ReadUInt16LittleEndian(Data.AsSpan(0x1C)); set => WriteUInt16LittleEndian(Data.AsSpan(0x1C), (ushort)value); }
|
||||
public int FormSprite { get => ReadUInt16LittleEndian(Data.AsSpan(0x1E)); set => WriteUInt16LittleEndian(Data.AsSpan(0x1E), (ushort)value); }
|
||||
public override byte FormCount { get => Data[0x20]; set => Data[0x20] = (byte)value; }
|
||||
public override byte FormCount { get => Data[0x20]; set => Data[0x20] = value; }
|
||||
public override int Color { get => Data[0x21] & 0x3F; set => Data[0x21] = (byte)((Data[0x21] & 0xC0) | (value & 0x3F)); }
|
||||
public bool SpriteFlip { get => ((Data[0x21] >> 6) & 1) == 1; set => Data[0x21] = (byte)((Data[0x21] & ~0x40) | (value ? 0x40 : 0)); }
|
||||
public bool SpriteForm { get => ((Data[0x21] >> 7) & 1) == 1; set => Data[0x21] = (byte)((Data[0x21] & ~0x80) | (value ? 0x80 : 0)); }
|
||||
|
@ -70,31 +69,13 @@ public sealed class PersonalInfo5BW : PersonalInfo, IPersonalAbility12H
|
|||
public override int Height { get => ReadUInt16LittleEndian(Data.AsSpan(0x24)); set => WriteUInt16LittleEndian(Data.AsSpan(0x24), (ushort)value); }
|
||||
public override int Weight { get => ReadUInt16LittleEndian(Data.AsSpan(0x26)); set => WriteUInt16LittleEndian(Data.AsSpan(0x26), (ushort)value); }
|
||||
|
||||
public IReadOnlyList<int> Items
|
||||
public override int AbilityCount => 3;
|
||||
public override int GetIndexOfAbility(int abilityID) => abilityID == Ability1 ? 0 : abilityID == Ability2 ? 1 : abilityID == AbilityH ? 2 : -1;
|
||||
public override int GetAbilityAtIndex(int abilityIndex) => abilityIndex switch
|
||||
{
|
||||
get => new[] { Item1, Item2, Item3 };
|
||||
set
|
||||
{
|
||||
if (value.Count != 3) return;
|
||||
Item1 = value[0];
|
||||
Item2 = value[1];
|
||||
Item3 = value[2];
|
||||
}
|
||||
}
|
||||
|
||||
public override IReadOnlyList<int> Abilities
|
||||
{
|
||||
get => new[] { Ability1, Ability2, AbilityH };
|
||||
set
|
||||
{
|
||||
if (value.Count != 3) return;
|
||||
Ability1 = (byte)value[0];
|
||||
Ability2 = (byte)value[1];
|
||||
AbilityH = (byte)value[2];
|
||||
}
|
||||
}
|
||||
|
||||
public override int GetAbilityIndex(int abilityID) => abilityID == Ability1 ? 0 : abilityID == Ability2 ? 1 : abilityID == AbilityH ? 2 : -1;
|
||||
|
||||
public bool HasHiddenAbility => AbilityH != Ability1;
|
||||
0 => Ability1,
|
||||
1 => Ability2,
|
||||
2 => AbilityH,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(abilityIndex), abilityIndex, null),
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using static System.Buffers.Binary.BinaryPrimitives;
|
||||
|
||||
namespace PKHeX.Core;
|
||||
|
@ -7,7 +6,7 @@ namespace PKHeX.Core;
|
|||
/// <summary>
|
||||
/// <see cref="PersonalInfo"/> class with values from the OR & AS games.
|
||||
/// </summary>
|
||||
public sealed class PersonalInfo6AO : PersonalInfo
|
||||
public sealed class PersonalInfo6AO : PersonalInfo, IPersonalAbility12H
|
||||
{
|
||||
public const int SIZE = 0x50;
|
||||
private readonly byte[] Data;
|
||||
|
@ -73,7 +72,7 @@ public sealed class PersonalInfo6AO : PersonalInfo
|
|||
public override int EscapeRate { get => Data[0x1B]; set => Data[0x1B] = (byte)value; }
|
||||
public override int FormStatsIndex { get => ReadUInt16LittleEndian(Data.AsSpan(0x1C)); set => WriteUInt16LittleEndian(Data.AsSpan(0x1C), (ushort)value); }
|
||||
public int FormSprite { get => ReadUInt16LittleEndian(Data.AsSpan(0x1E)); set => WriteUInt16LittleEndian(Data.AsSpan(0x1E), (ushort)value); }
|
||||
public override byte FormCount { get => Data[0x20]; set => Data[0x20] = (byte)value; }
|
||||
public override byte FormCount { get => Data[0x20]; set => Data[0x20] = value; }
|
||||
public override int Color { get => Data[0x21] & 0x3F; set => Data[0x21] = (byte)((Data[0x21] & 0xC0) | (value & 0x3F)); }
|
||||
public bool SpriteFlip { get => ((Data[0x21] >> 6) & 1) == 1; set => Data[0x21] = (byte)((Data[0x21] & ~0x40) | (value ? 0x40 : 0)); }
|
||||
public bool SpriteForm { get => ((Data[0x21] >> 7) & 1) == 1; set => Data[0x21] = (byte)((Data[0x21] & ~0x80) | (value ? 0x80 : 0)); }
|
||||
|
@ -82,31 +81,13 @@ public sealed class PersonalInfo6AO : PersonalInfo
|
|||
public override int Height { get => ReadUInt16LittleEndian(Data.AsSpan(0x24)); set => WriteUInt16LittleEndian(Data.AsSpan(0x24), (ushort)value); }
|
||||
public override int Weight { get => ReadUInt16LittleEndian(Data.AsSpan(0x26)); set => WriteUInt16LittleEndian(Data.AsSpan(0x26), (ushort)value); }
|
||||
|
||||
public IReadOnlyList<int> Items
|
||||
public override int AbilityCount => 3;
|
||||
public override int GetIndexOfAbility(int abilityID) => abilityID == Ability1 ? 0 : abilityID == Ability2 ? 1 : abilityID == AbilityH ? 2 : -1;
|
||||
public override int GetAbilityAtIndex(int abilityIndex) => abilityIndex switch
|
||||
{
|
||||
get => new[] { Item1, Item2, Item3 };
|
||||
set
|
||||
{
|
||||
if (value.Count != 3) return;
|
||||
Item1 = value[0];
|
||||
Item2 = value[1];
|
||||
Item3 = value[2];
|
||||
}
|
||||
}
|
||||
|
||||
public override IReadOnlyList<int> Abilities
|
||||
{
|
||||
get => new[] { Ability1, Ability2, AbilityH };
|
||||
set
|
||||
{
|
||||
if (value.Count != 3) return;
|
||||
Ability1 = (byte)value[0];
|
||||
Ability2 = (byte)value[1];
|
||||
AbilityH = (byte)value[2];
|
||||
}
|
||||
}
|
||||
|
||||
public override int GetAbilityIndex(int abilityID) => abilityID == Ability1 ? 0 : abilityID == Ability2 ? 1 : abilityID == AbilityH ? 2 : -1;
|
||||
|
||||
public bool HasHiddenAbility => AbilityH != Ability1;
|
||||
0 => Ability1,
|
||||
1 => Ability2,
|
||||
2 => AbilityH,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(abilityIndex), abilityIndex, null),
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using static System.Buffers.Binary.BinaryPrimitives;
|
||||
|
||||
namespace PKHeX.Core;
|
||||
|
@ -7,7 +6,7 @@ namespace PKHeX.Core;
|
|||
/// <summary>
|
||||
/// <see cref="PersonalInfo"/> class with values from the X & Y games.
|
||||
/// </summary>
|
||||
public sealed class PersonalInfo6XY : PersonalInfo
|
||||
public sealed class PersonalInfo6XY : PersonalInfo, IPersonalAbility12H
|
||||
{
|
||||
public const int SIZE = 0x40;
|
||||
private readonly byte[] Data;
|
||||
|
@ -62,7 +61,7 @@ public sealed class PersonalInfo6XY : PersonalInfo
|
|||
public override int EscapeRate { get => Data[0x1B]; set => Data[0x1B] = (byte)value; }
|
||||
public override int FormStatsIndex { get => ReadUInt16LittleEndian(Data.AsSpan(0x1C)); set => WriteUInt16LittleEndian(Data.AsSpan(0x1C), (ushort)value); }
|
||||
public int FormSprite { get => ReadUInt16LittleEndian(Data.AsSpan(0x1E)); set => WriteUInt16LittleEndian(Data.AsSpan(0x1E), (ushort)value); }
|
||||
public override byte FormCount { get => Data[0x20]; set => Data[0x20] = (byte)value; }
|
||||
public override byte FormCount { get => Data[0x20]; set => Data[0x20] = value; }
|
||||
public override int Color { get => Data[0x21] & 0x3F; set => Data[0x21] = (byte)((Data[0x21] & 0xC0) | (value & 0x3F)); }
|
||||
public bool SpriteFlip { get => ((Data[0x21] >> 6) & 1) == 1; set => Data[0x21] = (byte)((Data[0x21] & ~0x40) | (value ? 0x40 : 0)); }
|
||||
public bool SpriteForm { get => ((Data[0x21] >> 7) & 1) == 1; set => Data[0x21] = (byte)((Data[0x21] & ~0x80) | (value ? 0x80 : 0)); }
|
||||
|
@ -71,31 +70,13 @@ public sealed class PersonalInfo6XY : PersonalInfo
|
|||
public override int Height { get => ReadUInt16LittleEndian(Data.AsSpan(0x24)); set => WriteUInt16LittleEndian(Data.AsSpan(0x24), (ushort)value); }
|
||||
public override int Weight { get => ReadUInt16LittleEndian(Data.AsSpan(0x26)); set => WriteUInt16LittleEndian(Data.AsSpan(0x26), (ushort)value); }
|
||||
|
||||
public IReadOnlyList<int> Items
|
||||
public override int AbilityCount => 3;
|
||||
public override int GetIndexOfAbility(int abilityID) => abilityID == Ability1 ? 0 : abilityID == Ability2 ? 1 : abilityID == AbilityH ? 2 : -1;
|
||||
public override int GetAbilityAtIndex(int abilityIndex) => abilityIndex switch
|
||||
{
|
||||
get => new[] { Item1, Item2, Item3 };
|
||||
set
|
||||
{
|
||||
if (value.Count != 3) return;
|
||||
Item1 = value[0];
|
||||
Item2 = value[1];
|
||||
Item3 = value[2];
|
||||
}
|
||||
}
|
||||
|
||||
public override IReadOnlyList<int> Abilities
|
||||
{
|
||||
get => new[] { Ability1, Ability2, AbilityH };
|
||||
set
|
||||
{
|
||||
if (value.Count != 3) return;
|
||||
Ability1 = (byte)value[0];
|
||||
Ability2 = (byte)value[1];
|
||||
AbilityH = (byte)value[2];
|
||||
}
|
||||
}
|
||||
|
||||
public override int GetAbilityIndex(int abilityID) => abilityID == Ability1 ? 0 : abilityID == Ability2 ? 1 : abilityID == AbilityH ? 2 : -1;
|
||||
|
||||
public bool HasHiddenAbility => AbilityH != Ability1;
|
||||
0 => Ability1,
|
||||
1 => Ability2,
|
||||
2 => AbilityH,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(abilityIndex), abilityIndex, null),
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using static System.Buffers.Binary.BinaryPrimitives;
|
||||
|
||||
namespace PKHeX.Core;
|
||||
|
@ -7,7 +6,7 @@ namespace PKHeX.Core;
|
|||
/// <summary>
|
||||
/// <see cref="PersonalInfo"/> class with values from the Sun & Moon games.
|
||||
/// </summary>
|
||||
public sealed class PersonalInfo7 : PersonalInfo
|
||||
public sealed class PersonalInfo7 : PersonalInfo, IPersonalAbility12H
|
||||
{
|
||||
public const int SIZE = 0x54;
|
||||
private readonly byte[] Data;
|
||||
|
@ -66,7 +65,7 @@ public sealed class PersonalInfo7 : PersonalInfo
|
|||
public override int EscapeRate { get => Data[0x1B]; set => Data[0x1B] = (byte)value; }
|
||||
public override int FormStatsIndex { get => ReadUInt16LittleEndian(Data.AsSpan(0x1C)); set => WriteUInt16LittleEndian(Data.AsSpan(0x1C), (ushort)value); }
|
||||
public int FormSprite { get => ReadUInt16LittleEndian(Data.AsSpan(0x1E)); set => WriteUInt16LittleEndian(Data.AsSpan(0x1E), (ushort)value); }
|
||||
public override byte FormCount { get => Data[0x20]; set => Data[0x20] = (byte)value; }
|
||||
public override byte FormCount { get => Data[0x20]; set => Data[0x20] = value; }
|
||||
public override int Color { get => Data[0x21] & 0x3F; set => Data[0x21] = (byte)((Data[0x21] & 0xC0) | (value & 0x3F)); }
|
||||
public bool SpriteFlip { get => ((Data[0x21] >> 6) & 1) == 1; set => Data[0x21] = (byte)((Data[0x21] & ~0x40) | (value ? 0x40 : 0)); }
|
||||
public bool SpriteForm { get => ((Data[0x21] >> 7) & 1) == 1; set => Data[0x21] = (byte)((Data[0x21] & ~0x80) | (value ? 0x80 : 0)); }
|
||||
|
@ -75,36 +74,18 @@ public sealed class PersonalInfo7 : PersonalInfo
|
|||
public override int Height { get => ReadUInt16LittleEndian(Data.AsSpan(0x24)); set => WriteUInt16LittleEndian(Data.AsSpan(0x24), (ushort)value); }
|
||||
public override int Weight { get => ReadUInt16LittleEndian(Data.AsSpan(0x26)); set => WriteUInt16LittleEndian(Data.AsSpan(0x26), (ushort)value); }
|
||||
|
||||
public IReadOnlyList<int> Items
|
||||
{
|
||||
get => new[] { Item1, Item2, Item3 };
|
||||
set
|
||||
{
|
||||
if (value.Count != 3) return;
|
||||
Item1 = value[0];
|
||||
Item2 = value[1];
|
||||
Item3 = value[2];
|
||||
}
|
||||
}
|
||||
|
||||
public override IReadOnlyList<int> Abilities
|
||||
{
|
||||
get => new[] { Ability1, Ability2, AbilityH };
|
||||
set
|
||||
{
|
||||
if (value.Count != 3) return;
|
||||
Ability1 = (byte)value[0];
|
||||
Ability2 = (byte)value[1];
|
||||
AbilityH = (byte)value[2];
|
||||
}
|
||||
}
|
||||
|
||||
public override int GetAbilityIndex(int abilityID) => abilityID == Ability1 ? 0 : abilityID == Ability2 ? 1 : abilityID == AbilityH ? 2 : -1;
|
||||
|
||||
public bool HasHiddenAbility => AbilityH != Ability1;
|
||||
|
||||
public int SpecialZ_Item { get => ReadUInt16LittleEndian(Data.AsSpan(0x4C)); set => WriteUInt16LittleEndian(Data.AsSpan(0x4C), (ushort)value); }
|
||||
public int SpecialZ_BaseMove { get => ReadUInt16LittleEndian(Data.AsSpan(0x4E)); set => WriteUInt16LittleEndian(Data.AsSpan(0x4E), (ushort)value); }
|
||||
public int SpecialZ_ZMove { get => ReadUInt16LittleEndian(Data.AsSpan(0x50)); set => WriteUInt16LittleEndian(Data.AsSpan(0x50), (ushort)value); }
|
||||
public bool LocalVariant { get => Data[0x52] == 1; set => Data[0x52] = value ? (byte)1 : (byte)0; }
|
||||
|
||||
public override int AbilityCount => 3;
|
||||
public override int GetIndexOfAbility(int abilityID) => abilityID == Ability1 ? 0 : abilityID == Ability2 ? 1 : abilityID == AbilityH ? 2 : -1;
|
||||
public override int GetAbilityAtIndex(int abilityIndex) => abilityIndex switch
|
||||
{
|
||||
0 => Ability1,
|
||||
1 => Ability2,
|
||||
2 => AbilityH,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(abilityIndex), abilityIndex, null),
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using static System.Buffers.Binary.BinaryPrimitives;
|
||||
|
||||
namespace PKHeX.Core;
|
||||
|
@ -7,7 +6,7 @@ namespace PKHeX.Core;
|
|||
/// <summary>
|
||||
/// <see cref="PersonalInfo"/> class with values from the <see cref="GameVersion.GG"/> games.
|
||||
/// </summary>
|
||||
public sealed class PersonalInfo7GG : PersonalInfo
|
||||
public sealed class PersonalInfo7GG : PersonalInfo, IPersonalAbility12H
|
||||
{
|
||||
public const int SIZE = 0x54;
|
||||
private readonly byte[] Data;
|
||||
|
@ -60,7 +59,7 @@ public sealed class PersonalInfo7GG : PersonalInfo
|
|||
public override int EscapeRate { get => Data[0x1B]; set => Data[0x1B] = (byte)value; }
|
||||
public override int FormStatsIndex { get => ReadUInt16LittleEndian(Data.AsSpan(0x1C)); set => WriteUInt16LittleEndian(Data.AsSpan(0x1C), (ushort)value); }
|
||||
public int FormSprite { get => ReadUInt16LittleEndian(Data.AsSpan(0x1E)); set => WriteUInt16LittleEndian(Data.AsSpan(0x1E), (ushort)value); }
|
||||
public override byte FormCount { get => Data[0x20]; set => Data[0x20] = (byte)value; }
|
||||
public override byte FormCount { get => Data[0x20]; set => Data[0x20] = value; }
|
||||
public override int Color { get => Data[0x21] & 0x3F; set => Data[0x21] = (byte)((Data[0x21] & 0xC0) | (value & 0x3F)); }
|
||||
public bool SpriteFlip { get => ((Data[0x21] >> 6) & 1) == 1; set => Data[0x21] = (byte)((Data[0x21] & ~0x40) | (value ? 0x40 : 0)); }
|
||||
public bool SpriteForm { get => ((Data[0x21] >> 7) & 1) == 1; set => Data[0x21] = (byte)((Data[0x21] & ~0x80) | (value ? 0x80 : 0)); }
|
||||
|
@ -75,31 +74,13 @@ public sealed class PersonalInfo7GG : PersonalInfo
|
|||
public int SpecialZ_ZMove { get => ReadUInt16LittleEndian(Data.AsSpan(0x50)); set => WriteUInt16LittleEndian(Data.AsSpan(0x50), (ushort)value); }
|
||||
public bool LocalVariant { get => Data[0x52] == 1; set => Data[0x52] = value ? (byte)1 : (byte)0; }
|
||||
|
||||
public IReadOnlyList<int> Items
|
||||
public override int AbilityCount => 3;
|
||||
public override int GetIndexOfAbility(int abilityID) => abilityID == Ability1 ? 0 : abilityID == Ability2 ? 1 : abilityID == AbilityH ? 2 : -1;
|
||||
public override int GetAbilityAtIndex(int abilityIndex) => abilityIndex switch
|
||||
{
|
||||
get => new[] { Item1, Item2, Item3 };
|
||||
set
|
||||
{
|
||||
if (value.Count != 3) return;
|
||||
Item1 = value[0];
|
||||
Item2 = value[1];
|
||||
Item3 = value[2];
|
||||
}
|
||||
}
|
||||
|
||||
public override IReadOnlyList<int> Abilities
|
||||
{
|
||||
get => new[] { Ability1, Ability2, AbilityH };
|
||||
set
|
||||
{
|
||||
if (value.Count != 3) return;
|
||||
Ability1 = (byte)value[0];
|
||||
Ability2 = (byte)value[1];
|
||||
AbilityH = (byte)value[2];
|
||||
}
|
||||
}
|
||||
|
||||
public override int GetAbilityIndex(int abilityID) => abilityID == Ability1 ? 0 : abilityID == Ability2 ? 1 : abilityID == AbilityH ? 2 : -1;
|
||||
|
||||
public bool HasHiddenAbility => AbilityH != Ability1;
|
||||
0 => Ability1,
|
||||
1 => Ability2,
|
||||
2 => AbilityH,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(abilityIndex), abilityIndex, null),
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using static System.Buffers.Binary.BinaryPrimitives;
|
||||
|
||||
namespace PKHeX.Core;
|
||||
|
@ -7,7 +6,7 @@ namespace PKHeX.Core;
|
|||
/// <summary>
|
||||
/// <see cref="PersonalInfo"/> class with values from the <see cref="GameVersion.BDSP"/> games.
|
||||
/// </summary>
|
||||
public sealed class PersonalInfo8BDSP : PersonalInfo
|
||||
public sealed class PersonalInfo8BDSP : PersonalInfo, IPersonalAbility12H
|
||||
{
|
||||
public const int SIZE = 0x44;
|
||||
private const int CountTM = 100;
|
||||
|
@ -67,7 +66,7 @@ public sealed class PersonalInfo8BDSP : PersonalInfo
|
|||
public int AbilityH { get => ReadUInt16LittleEndian(Data.AsSpan(0x1C)); set => WriteUInt16LittleEndian(Data.AsSpan(0x1C), (ushort)value); }
|
||||
public override int EscapeRate { get => 0; set { } } // moved?
|
||||
public override int FormStatsIndex { get => ReadUInt16LittleEndian(Data.AsSpan(0x1E)); set => WriteUInt16LittleEndian(Data.AsSpan(0x1E), (ushort)value); }
|
||||
public override byte FormCount { get => Data[0x20]; set => Data[0x20] = (byte)value; }
|
||||
public override byte FormCount { get => Data[0x20]; set => Data[0x20] = value; }
|
||||
public override int Color { get => Data[0x21] & 0x3F; set => Data[0x21] = (byte)((Data[0x21] & 0xC0) | (value & 0x3F)); }
|
||||
public bool IsPresentInGame { get => ((Data[0x21] >> 6) & 1) == 1; set => Data[0x21] = (byte)((Data[0x21] & ~0x40) | (value ? 0x40 : 0)); }
|
||||
public override int BaseEXP { get => ReadUInt16LittleEndian(Data.AsSpan(0x22)); set => WriteUInt16LittleEndian(Data.AsSpan(0x22), (ushort)value); }
|
||||
|
@ -85,31 +84,15 @@ public sealed class PersonalInfo8BDSP : PersonalInfo
|
|||
public byte HatchFormIndex { get => (byte)ReadUInt16LittleEndian(Data.AsSpan(0x40)); set => WriteUInt16LittleEndian(Data.AsSpan(0x40), value); }
|
||||
public ushort PokeDexIndex { get => ReadUInt16LittleEndian(Data.AsSpan(0x42)); set => WriteUInt16LittleEndian(Data.AsSpan(0x42), value); }
|
||||
|
||||
public IReadOnlyList<int> Items
|
||||
public override int AbilityCount => 3;
|
||||
public override int GetIndexOfAbility(int abilityID) => abilityID == Ability1 ? 0 : abilityID == Ability2 ? 1 : abilityID == AbilityH ? 2 : -1;
|
||||
public override int GetAbilityAtIndex(int abilityIndex) => abilityIndex switch
|
||||
{
|
||||
get => new[] { Item1, Item2, Item3 };
|
||||
set
|
||||
{
|
||||
if (value.Count != 3) return;
|
||||
Item1 = value[0];
|
||||
Item2 = value[1];
|
||||
Item3 = value[2];
|
||||
}
|
||||
}
|
||||
|
||||
public override IReadOnlyList<int> Abilities
|
||||
{
|
||||
get => new[] { Ability1, Ability2, AbilityH };
|
||||
set
|
||||
{
|
||||
if (value.Count != 3) return;
|
||||
Ability1 = value[0];
|
||||
Ability2 = value[1];
|
||||
AbilityH = value[2];
|
||||
}
|
||||
}
|
||||
|
||||
public override int GetAbilityIndex(int abilityID) => abilityID == Ability1 ? 0 : abilityID == Ability2 ? 1 : abilityID == AbilityH ? 2 : -1;
|
||||
0 => Ability1,
|
||||
1 => Ability2,
|
||||
2 => AbilityH,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(abilityIndex), abilityIndex, null),
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the entry shows up in any of the built-in Pokédex.
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using static System.Buffers.Binary.BinaryPrimitives;
|
||||
|
||||
namespace PKHeX.Core;
|
||||
|
@ -7,7 +6,7 @@ namespace PKHeX.Core;
|
|||
/// <summary>
|
||||
/// <see cref="PersonalInfo"/> class with values from the <see cref="GameVersion.PLA"/> games.
|
||||
/// </summary>
|
||||
public sealed class PersonalInfo8LA : PersonalInfo
|
||||
public sealed class PersonalInfo8LA : PersonalInfo, IPersonalAbility12H
|
||||
{
|
||||
public const int SIZE = 0xB0;
|
||||
private readonly byte[] Data;
|
||||
|
@ -66,7 +65,7 @@ public sealed class PersonalInfo8LA : PersonalInfo
|
|||
public override int EscapeRate { get => 0; set { } } // moved?
|
||||
public override int FormStatsIndex { get => ReadUInt16LittleEndian(Data.AsSpan(0x1E)); set => WriteUInt16LittleEndian(Data.AsSpan(0x1E), (ushort)value); }
|
||||
public int FormSprite { get => ReadUInt16LittleEndian(Data.AsSpan(0x1E)); set => WriteUInt16LittleEndian(Data.AsSpan(0x1E), (ushort)value); } // ???
|
||||
public override byte FormCount { get => Data[0x20]; set => Data[0x20] = (byte)value; }
|
||||
public override byte FormCount { get => Data[0x20]; set => Data[0x20] = value; }
|
||||
public override int Color { get => Data[0x21] & 0x3F; set => Data[0x21] = (byte)((Data[0x21] & 0xC0) | (value & 0x3F)); }
|
||||
public bool IsPresentInGame { get => ((Data[0x21] >> 6) & 1) == 1; set => Data[0x21] = (byte)((Data[0x21] & ~0x40) | (value ? 0x40 : 0)); }
|
||||
public bool SpriteForm { get => ((Data[0x21] >> 7) & 1) == 1; set => Data[0x21] = (byte)((Data[0x21] & ~0x80) | (value ? 0x80 : 0)); }
|
||||
|
@ -74,32 +73,6 @@ public sealed class PersonalInfo8LA : PersonalInfo
|
|||
public override int Height { get => ReadUInt16LittleEndian(Data.AsSpan(0x24)); set => WriteUInt16LittleEndian(Data.AsSpan(0x24), (ushort)value); }
|
||||
public override int Weight { get => ReadUInt16LittleEndian(Data.AsSpan(0x26)); set => WriteUInt16LittleEndian(Data.AsSpan(0x26), (ushort)value); }
|
||||
|
||||
public IReadOnlyList<int> Items
|
||||
{
|
||||
get => new[] { Item1, Item2, Item3 };
|
||||
set
|
||||
{
|
||||
if (value.Count != 3) return;
|
||||
Item1 = value[0];
|
||||
Item2 = value[1];
|
||||
Item3 = value[2];
|
||||
}
|
||||
}
|
||||
|
||||
public override IReadOnlyList<int> Abilities
|
||||
{
|
||||
get => new[] { Ability1, Ability2, AbilityH };
|
||||
set
|
||||
{
|
||||
if (value.Count != 3) return;
|
||||
Ability1 = value[0];
|
||||
Ability2 = value[1];
|
||||
AbilityH = value[2];
|
||||
}
|
||||
}
|
||||
|
||||
public override int GetAbilityIndex(int abilityID) => abilityID == Ability1 ? 0 : abilityID == Ability2 ? 1 : abilityID == AbilityH ? 2 : -1;
|
||||
|
||||
public ushort HatchSpecies { get => ReadUInt16LittleEndian(Data.AsSpan(0x56)); set => WriteUInt16LittleEndian(Data.AsSpan(0x56), value); }
|
||||
public int HatchFormIndex { get => ReadUInt16LittleEndian(Data.AsSpan(0x58)); set => WriteUInt16LittleEndian(Data.AsSpan(0x58), (ushort)value); } // local region base form
|
||||
public ushort RegionalFlags { get => ReadUInt16LittleEndian(Data.AsSpan(0x5A)); set => WriteUInt16LittleEndian(Data.AsSpan(0x5A), value); }
|
||||
|
@ -113,6 +86,16 @@ public sealed class PersonalInfo8LA : PersonalInfo
|
|||
public ushort DexIndexLocal4 { get => ReadUInt16LittleEndian(Data.AsSpan(0x68)); set => WriteUInt16LittleEndian(Data.AsSpan(0x68), value); }
|
||||
public ushort DexIndexLocal5 { get => ReadUInt16LittleEndian(Data.AsSpan(0x6A)); set => WriteUInt16LittleEndian(Data.AsSpan(0x6A), value); }
|
||||
|
||||
public override int AbilityCount => 3;
|
||||
public override int GetIndexOfAbility(int abilityID) => abilityID == Ability1 ? 0 : abilityID == Ability2 ? 1 : abilityID == AbilityH ? 2 : -1;
|
||||
public override int GetAbilityAtIndex(int abilityIndex) => abilityIndex switch
|
||||
{
|
||||
0 => Ability1,
|
||||
1 => Ability2,
|
||||
2 => AbilityH,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(abilityIndex), abilityIndex, null),
|
||||
};
|
||||
|
||||
public int GetMoveShopCount()
|
||||
{
|
||||
// Return a count of true indexes from Tutors
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using static System.Buffers.Binary.BinaryPrimitives;
|
||||
|
||||
namespace PKHeX.Core;
|
||||
|
@ -7,7 +6,7 @@ namespace PKHeX.Core;
|
|||
/// <summary>
|
||||
/// <see cref="PersonalInfo"/> class with values from the <see cref="GameVersion.SWSH"/> games.
|
||||
/// </summary>
|
||||
public sealed class PersonalInfo8SWSH : PersonalInfo
|
||||
public sealed class PersonalInfo8SWSH : PersonalInfo, IPersonalAbility12H
|
||||
{
|
||||
public const int SIZE = 0xB0;
|
||||
public const int CountTM = 100;
|
||||
|
@ -86,7 +85,7 @@ public sealed class PersonalInfo8SWSH : PersonalInfo
|
|||
public override int EscapeRate { get => 0; set { } } // moved?
|
||||
public override int FormStatsIndex { get => ReadUInt16LittleEndian(Data.AsSpan(0x1E)); set => WriteUInt16LittleEndian(Data.AsSpan(0x1E), (ushort)value); }
|
||||
public int FormSprite { get => ReadUInt16LittleEndian(Data.AsSpan(0x1E)); set => WriteUInt16LittleEndian(Data.AsSpan(0x1E), (ushort)value); } // ???
|
||||
public override byte FormCount { get => Data[0x20]; set => Data[0x20] = (byte)value; }
|
||||
public override byte FormCount { get => Data[0x20]; set => Data[0x20] = value; }
|
||||
public override int Color { get => Data[0x21] & 0x3F; set => Data[0x21] = (byte)((Data[0x21] & 0xC0) | (value & 0x3F)); }
|
||||
public bool IsPresentInGame { get => ((Data[0x21] >> 6) & 1) == 1; set => Data[0x21] = (byte)((Data[0x21] & ~0x40) | (value ? 0x40 : 0)); }
|
||||
public bool SpriteForm { get => ((Data[0x21] >> 7) & 1) == 1; set => Data[0x21] = (byte)((Data[0x21] & ~0x80) | (value ? 0x80 : 0)); }
|
||||
|
@ -94,32 +93,6 @@ public sealed class PersonalInfo8SWSH : PersonalInfo
|
|||
public override int Height { get => ReadUInt16LittleEndian(Data.AsSpan(0x24)); set => WriteUInt16LittleEndian(Data.AsSpan(0x24), (ushort)value); }
|
||||
public override int Weight { get => ReadUInt16LittleEndian(Data.AsSpan(0x26)); set => WriteUInt16LittleEndian(Data.AsSpan(0x26), (ushort)value); }
|
||||
|
||||
public IReadOnlyList<int> Items
|
||||
{
|
||||
get => new[] { Item1, Item2, Item3 };
|
||||
set
|
||||
{
|
||||
if (value.Count != 3) return;
|
||||
Item1 = value[0];
|
||||
Item2 = value[1];
|
||||
Item3 = value[2];
|
||||
}
|
||||
}
|
||||
|
||||
public override IReadOnlyList<int> Abilities
|
||||
{
|
||||
get => new[] { Ability1, Ability2, AbilityH };
|
||||
set
|
||||
{
|
||||
if (value.Count != 3) return;
|
||||
Ability1 = value[0];
|
||||
Ability2 = value[1];
|
||||
AbilityH = value[2];
|
||||
}
|
||||
}
|
||||
|
||||
public override int GetAbilityIndex(int abilityID) => abilityID == Ability1 ? 0 : abilityID == Ability2 ? 1 : abilityID == AbilityH ? 2 : -1;
|
||||
|
||||
public ushort Species { get => ReadUInt16LittleEndian(Data.AsSpan(0x4C)); set => WriteUInt16LittleEndian(Data.AsSpan(0x4C), value); }
|
||||
|
||||
public ushort HatchSpecies { get => ReadUInt16LittleEndian(Data.AsSpan(0x56)); set => WriteUInt16LittleEndian(Data.AsSpan(0x56), value); }
|
||||
|
@ -141,5 +114,13 @@ public sealed class PersonalInfo8SWSH : PersonalInfo
|
|||
/// </summary>
|
||||
public bool IsInDex => PokeDexIndex != 0 || ArmorDexIndex != 0 || CrownDexIndex != 0;
|
||||
|
||||
public bool HasHiddenAbility => AbilityH != Ability1;
|
||||
public override int AbilityCount => 3;
|
||||
public override int GetIndexOfAbility(int abilityID) => abilityID == Ability1 ? 0 : abilityID == Ability2 ? 1 : abilityID == AbilityH ? 2 : -1;
|
||||
public override int GetAbilityAtIndex(int abilityIndex) => abilityIndex switch
|
||||
{
|
||||
0 => Ability1,
|
||||
1 => Ability2,
|
||||
2 => AbilityH,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(abilityIndex), abilityIndex, null),
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,23 +1,31 @@
|
|||
using System.Collections.Generic;
|
||||
using System;
|
||||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
public interface IPersonalAbility
|
||||
{
|
||||
/// <summary>
|
||||
/// Full list of <see cref="PKM.Ability"/> values the entry can have.
|
||||
/// </summary>
|
||||
IReadOnlyList<int> Abilities { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the ability index without creating an array and looking through it.
|
||||
/// Gets the index of the <see cref="abilityID"/> within the specification's list of abilities.
|
||||
/// </summary>
|
||||
/// <param name="abilityID">Ability ID</param>
|
||||
/// <returns>Ability Index</returns>
|
||||
int GetAbilityIndex(int abilityID);
|
||||
int GetIndexOfAbility(int abilityID);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the ability ID at the specified ability index.
|
||||
/// </summary>
|
||||
/// <param name="abilityIndex">Ability Index</param>
|
||||
/// <returns>Ability ID</returns>
|
||||
int GetAbilityAtIndex(int abilityIndex);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the count of abilities able to be selected.
|
||||
/// </summary>
|
||||
/// <remarks>Duplicate abilities still count separately.</remarks>
|
||||
int AbilityCount { get; }
|
||||
}
|
||||
|
||||
public interface IPersonalAbility12
|
||||
public interface IPersonalAbility12 : IPersonalAbility
|
||||
{
|
||||
int Ability1 { get; set; }
|
||||
int Ability2 { get; set; }
|
||||
|
@ -27,3 +35,32 @@ public interface IPersonalAbility12H : IPersonalAbility12
|
|||
{
|
||||
int AbilityH { get; set; }
|
||||
}
|
||||
|
||||
public static class PersonalAbilityExtensions
|
||||
{
|
||||
public static bool GetIsAbility12Same(this IPersonalAbility12 pi) => pi.Ability1 == pi.Ability2;
|
||||
public static bool GetIsAbilityHiddenUnique(this IPersonalAbility12H pi) => pi.Ability1 != pi.AbilityH;
|
||||
public static bool GetIsAbilityPatchPossible(this IPersonalAbility12H pi) => pi.Ability1 != pi.AbilityH || pi.Ability2 != pi.AbilityH;
|
||||
|
||||
public static void GetAbilities(this IPersonalAbility pi, Span<int> result)
|
||||
{
|
||||
if (pi is not IPersonalAbility12 a)
|
||||
return;
|
||||
result[0] = a.Ability1;
|
||||
result[1] = a.Ability2;
|
||||
if (a is not IPersonalAbility12H h)
|
||||
return;
|
||||
result[2] = h.AbilityH;
|
||||
}
|
||||
|
||||
public static void SetAbilities(this IPersonalAbility pi, Span<int> result)
|
||||
{
|
||||
if (pi is not IPersonalAbility12 a)
|
||||
return;
|
||||
a.Ability1 = result[0];
|
||||
a.Ability2 = result[1];
|
||||
if (a is not IPersonalAbility12H h)
|
||||
return;
|
||||
h.AbilityH = result[2];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
|
@ -31,8 +30,9 @@ public abstract class PersonalInfo : IPersonalInfo
|
|||
public abstract int HatchCycles { get; set; }
|
||||
public abstract int BaseFriendship { get; set; }
|
||||
public abstract int EXPGrowth { get; set; }
|
||||
public abstract IReadOnlyList<int> Abilities { get; set; }
|
||||
public abstract int GetAbilityIndex(int abilityID);
|
||||
public abstract int GetIndexOfAbility(int abilityID);
|
||||
public abstract int GetAbilityAtIndex(int abilityIndex);
|
||||
public abstract int AbilityCount { get; }
|
||||
public abstract int EscapeRate { get; set; }
|
||||
public virtual byte FormCount { get; set; } = 1;
|
||||
public virtual int FormStatsIndex { get; set; }
|
||||
|
|
|
@ -190,8 +190,9 @@ public sealed class GP1 : IEncounterInfo, IFixedAbilityNumber
|
|||
else if (isShiny)
|
||||
pk.PID ^= 0x1000_0000;
|
||||
|
||||
var moves = MoveLevelUp.GetEncounterMoves(pk, Level, GameVersion.GO);
|
||||
pk.Moves = moves;
|
||||
Span<ushort> moves = stackalloc ushort[4];
|
||||
MoveLevelUp.GetEncounterMoves(moves, pk, pk.CurrentLevel, GameVersion.GO);
|
||||
pk.SetMoves(moves);
|
||||
pk.SetMaximumPPCurrent(moves);
|
||||
pk.OT_Friendship = pk.PersonalInfo.BaseFriendship;
|
||||
|
||||
|
|
|
@ -405,14 +405,14 @@ public partial class PKMEditor
|
|||
private static int GetAbilityIndex4(PKM pk)
|
||||
{
|
||||
var pi = pk.PersonalInfo;
|
||||
int abilityIndex = pi.GetAbilityIndex(pk.Ability);
|
||||
int abilityIndex = pi.GetIndexOfAbility(pk.Ability);
|
||||
if (abilityIndex < 0)
|
||||
return 0;
|
||||
if (abilityIndex >= 2)
|
||||
return 2;
|
||||
|
||||
var abils = pi.Abilities;
|
||||
if (abils[0] == abils[1])
|
||||
var abils = (IPersonalAbility12)pi;
|
||||
if (abils.GetIsAbility12Same())
|
||||
return pk.PIDAbility;
|
||||
return abilityIndex;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Windows.Forms;
|
||||
using PKHeX.Core;
|
||||
|
@ -79,27 +78,21 @@ public partial class KChart : Form
|
|||
cells[c++].Value = p.SPD.ToString("000");
|
||||
cells[c].Style.BackColor = ColorUtil.ColorBaseStat(p.SPE);
|
||||
cells[c++].Value = p.SPE.ToString("000");
|
||||
var abils = p.Abilities;
|
||||
cells[c++].Value = GetAbility(abils, 0);
|
||||
cells[c++].Value = GetAbility(abils, 1);
|
||||
cells[c].Value = GetAbility(abils, 2);
|
||||
var abils = p.AbilityCount;
|
||||
cells[c++].Value = abilities[abils > 0 ? p.GetAbilityAtIndex(0) : 0];
|
||||
cells[c++].Value = abilities[abils > 1 ? p.GetAbilityAtIndex(1) : 0];
|
||||
cells[c].Value = abilities[abils > 2 ? p.GetAbilityAtIndex(2) : 0];
|
||||
|
||||
row.Height = SpriteUtil.Spriter.Height + 1;
|
||||
DGV.Rows.Add(row);
|
||||
}
|
||||
|
||||
private string GetAbility(IReadOnlyList<int> abilityIDs, int index)
|
||||
{
|
||||
if ((uint)index >= abilityIDs.Count)
|
||||
return abilities[0];
|
||||
return abilities[abilityIDs[index]];
|
||||
}
|
||||
|
||||
private static bool GetIsNative(IPersonalInfo personalInfo, ushort s) => personalInfo switch
|
||||
{
|
||||
PersonalInfo7 => s > 721 || Legal.PastGenAlolanNatives.Contains(s),
|
||||
PersonalInfo8SWSH ss => ss.IsInDex,
|
||||
PersonalInfo8BDSP bs => bs.IsInDex,
|
||||
PersonalInfo8LA bs => bs.IsPresentInGame,
|
||||
_ => true,
|
||||
};
|
||||
}
|
||||
|
|
|
@ -321,7 +321,7 @@ public partial class SAV_SecretBase : Form
|
|||
|
||||
private void SetAbilityList(ushort species, byte form, int abilityIndex)
|
||||
{
|
||||
var abilities = PersonalTable.AO.GetFormEntry(species, form).Abilities;
|
||||
var abilities = PersonalTable.AO.GetFormEntry(species, form);
|
||||
var list = GameInfo.FilteredSources.GetAbilityList(abilities, 6);
|
||||
CB_Ability.DataSource = new BindingSource(list, null);
|
||||
CB_Ability.SelectedIndex = abilityIndex < 3 ? abilityIndex : 0;
|
||||
|
|
Loading…
Reference in a new issue