mirror of
https://github.com/kwsch/PKHeX.git
synced 2026-08-17 15:47:36 -05:00
Create initial movesets for Alpha entities correctly, verify initial mastery (#3489)
* Draft checks for encounter slot mastery * Check encounter mastery flags * Add moves for LA static encounters that don't follow learnset * Add moves on crossover LA static encounters * add alpha moveset population method Now generates and applies moves as the game does Updates some handling of other methods to use Span * Show better message for bad mastery init flags * Insert descending if candidates have same level Level 78 Yanmega: - [01] [10] Quick Attack - [06] [15] Gust - [11] [20] Silver Wind - [18] [28] Hypnosis - [25] [35] Air Slash - [34] [45] Ancient Power - [43] [54] Crunch - [43] [54] Bug Buzz Yields: AlphaMove Crunch* Bug Buzz* Ancient Power * Descending order due to iteration Co-authored-by: Lusamine <30205550+Lusamine@users.noreply.github.com>
This commit is contained in:
@@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace PKHeX.Core
|
||||
{
|
||||
@@ -56,12 +55,12 @@ public static void SetMoves(this PKM pk, int[] moves, bool maxPP = false)
|
||||
/// </summary>
|
||||
/// <param name="pk">Pokémon to modify.</param>
|
||||
/// <param name="moves"><see cref="PKM.Moves"/> to use (if already known). Will fetch the current <see cref="PKM.Moves"/> if not provided.</param>
|
||||
public static void SetMaximumPPCurrent(this PKM pk, IReadOnlyList<int> moves)
|
||||
public static void SetMaximumPPCurrent(this PKM pk, ReadOnlySpan<int> moves)
|
||||
{
|
||||
pk.Move1_PP = moves.Count == 0 ? 0 : pk.GetMovePP(moves[0], pk.Move1_PPUps);
|
||||
pk.Move2_PP = moves.Count <= 1 ? 0 : pk.GetMovePP(moves[1], pk.Move2_PPUps);
|
||||
pk.Move3_PP = moves.Count <= 2 ? 0 : pk.GetMovePP(moves[2], pk.Move3_PPUps);
|
||||
pk.Move4_PP = moves.Count <= 3 ? 0 : pk.GetMovePP(moves[3], pk.Move4_PPUps);
|
||||
pk.Move1_PP = moves.Length == 0 ? 0 : pk.GetMovePP(moves[0], pk.Move1_PPUps);
|
||||
pk.Move2_PP = moves.Length <= 1 ? 0 : pk.GetMovePP(moves[1], pk.Move2_PPUps);
|
||||
pk.Move3_PP = moves.Length <= 2 ? 0 : pk.GetMovePP(moves[2], pk.Move3_PPUps);
|
||||
pk.Move4_PP = moves.Length <= 3 ? 0 : pk.GetMovePP(moves[3], pk.Move4_PPUps);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -54,6 +54,7 @@ public static partial class Legal
|
||||
internal static readonly EggMoves6[] EggMovesBDSP = EggMoves6.GetArray(Get(Util.GetBinaryResource("eggmove_bdsp.pkl"), "bs"));
|
||||
internal static readonly Learnset[] LevelUpBDSP = LearnsetReader.GetArray(Get(Util.GetBinaryResource("lvlmove_bdsp.pkl"), "bs"));
|
||||
internal static readonly Learnset[] LevelUpLA = LearnsetReader.GetArray(Get(Util.GetBinaryResource("lvlmove_la.pkl"), "la"));
|
||||
internal static readonly Learnset[] MasteryLA = LearnsetReader.GetArray(Get(Util.GetBinaryResource("mastery_la.pkl"), "la"));
|
||||
|
||||
public static IReadOnlyList<byte> GetPPTable(PKM pkm, int format) => format switch
|
||||
{
|
||||
|
||||
@@ -25,16 +25,16 @@ internal static class Encounters8a
|
||||
new(493,000,75,M,M) { Location = 109, FlawlessIVCount = 3, Gift = true, Method = Fixed, Ball = (int)Ball.LAPoke, Fateful = true }, // Arceus
|
||||
|
||||
// Static Encounters - Scripted Table Slots
|
||||
new(480,000,70,M,M) { Location = 111, FlawlessIVCount = 3 }, // Uxie
|
||||
new(481,000,70,M,M) { Location = 104, FlawlessIVCount = 3 }, // Mesprit
|
||||
new(482,000,70,M,M) { Location = 105, FlawlessIVCount = 3 }, // Azelf
|
||||
new(485,000,70,M,M) { Location = 068, FlawlessIVCount = 3 }, // Heatran
|
||||
new(488,000,70,M,M) { Location = 082, FlawlessIVCount = 3 }, // Cresselia
|
||||
new(480,000,70,M,M) { Location = 111, FlawlessIVCount = 3, Moves = new[] {129,326,832,095} }, // Uxie
|
||||
new(481,000,70,M,M) { Location = 104, FlawlessIVCount = 3, Moves = new[] {129,326,832,105} }, // Mesprit
|
||||
new(482,000,70,M,M) { Location = 105, FlawlessIVCount = 3, Moves = new[] {129,458,326,832} }, // Azelf
|
||||
new(485,000,70,M,M) { Location = 068, FlawlessIVCount = 3, Moves = new[] {442,242,414,463} }, // Heatran
|
||||
new(488,000,70,M,M) { Location = 082, FlawlessIVCount = 3, Moves = new[] {427,094,585,849} }, // Cresselia
|
||||
|
||||
new(641,000,70,M,M) { Location = 090, FlawlessIVCount = 3 }, // Tornadus
|
||||
new(642,000,70,M,M) { Location = 009, FlawlessIVCount = 3 }, // Thundurus
|
||||
new(645,000,70,M,M) { Location = 027, FlawlessIVCount = 3 }, // Landorus
|
||||
new(905,000,70,M,M) { Location = 038, FlawlessIVCount = 3 }, // Enamorus
|
||||
new(641,000,70,M,M) { Location = 090, FlawlessIVCount = 3, Moves = new[] {326,242,542,846} }, // Tornadus
|
||||
new(642,000,70,M,M) { Location = 009, FlawlessIVCount = 3, Moves = new[] {326,242,087,847} }, // Thundurus
|
||||
new(645,000,70,M,M) { Location = 027, FlawlessIVCount = 3, Moves = new[] {326,242,414,848} }, // Landorus
|
||||
new(905,000,70,M,M) { Location = 038, FlawlessIVCount = 3, Moves = new[] {326,242,585,831} }, // Enamorus
|
||||
|
||||
new(077,000,15 ) { Location = 014, Shiny = Always}, // Ponyta*
|
||||
new(442,000,60,M,M) { Location = 043, FlawlessIVCount = 3 }, // Spiritomb
|
||||
@@ -42,13 +42,13 @@ internal static class Encounters8a
|
||||
new(570,001,28 ) { Location = 027 }, // Zorua
|
||||
new(570,001,29 ) { Location = 027 }, // Zorua
|
||||
|
||||
new(489,000,33 ) { Location = 064, Fateful = true }, // Phione
|
||||
new(489,000,34 ) { Location = 064, Fateful = true }, // Phione
|
||||
new(489,000,35 ) { Location = 064, Fateful = true }, // Phione
|
||||
new(489,000,36 ) { Location = 064, Fateful = true }, // Phione
|
||||
new(490,000,50,M,M) { Location = 064, FlawlessIVCount = 3, Fateful = true }, // Manaphy
|
||||
new(491,000,70,M,M) { Location = 010, FlawlessIVCount = 3, Fateful = true }, // Darkrai
|
||||
new(492,000,70,M,M) { Location = 026, FlawlessIVCount = 3, Fateful = true }, // Shaymin
|
||||
new(489,000,33 ) { Location = 064, Fateful = true, Moves = new[] {145,352,151,428} }, // Phione
|
||||
new(489,000,34 ) { Location = 064, Fateful = true, Moves = new[] {145,352,151,428} }, // Phione
|
||||
new(489,000,35 ) { Location = 064, Fateful = true, Moves = new[] {145,352,151,428} }, // Phione
|
||||
new(489,000,36 ) { Location = 064, Fateful = true, Moves = new[] {145,352,151,428} }, // Phione
|
||||
new(490,000,50,M,M) { Location = 064, FlawlessIVCount = 3, Fateful = true, Moves = new[] {352,428,585,145} }, // Manaphy
|
||||
new(491,000,70,M,M) { Location = 010, FlawlessIVCount = 3, Fateful = true, Moves = new[] {506,399,094,464} }, // Darkrai
|
||||
new(492,000,70,M,M) { Location = 026, FlawlessIVCount = 3, Fateful = true, Moves = new[] {403,412,414,465} }, // Shaymin
|
||||
|
||||
// Unown Notes
|
||||
new(201,000,25,U) { Location = 040, Method = Fixed }, // Unown A
|
||||
@@ -88,10 +88,10 @@ internal static class Encounters8a
|
||||
new(201,024,25,U) { Location = 097, Method = Fixed }, // Unown Y
|
||||
new(201,006,25,U) { Location = 007, Method = Fixed }, // Unown G
|
||||
|
||||
new(642,000,70,M,M) { Location = 059, FlawlessIVCount = 3 }, // Thundurus (Lunker’s Lair)
|
||||
new(642,000,70,M,M) { Location = 129, FlawlessIVCount = 3 }, // Thundurus (Sand’s Reach)
|
||||
new(488,000,70,M,M) { Location = 010, FlawlessIVCount = 3 }, // Cresselia (Coronet Highlands)
|
||||
new(491,000,70,M,M) { Location = 074, FlawlessIVCount = 3, Fateful = true }, // Darkrai (Lonely Spring)
|
||||
new(642,000,70,M,M) { Location = 059, FlawlessIVCount = 3, Moves = new[] {326,242,087,847} }, // Thundurus (Lunker’s Lair)
|
||||
new(642,000,70,M,M) { Location = 129, FlawlessIVCount = 3, Moves = new[] {326,242,087,847} }, // Thundurus (Sand’s Reach)
|
||||
new(488,000,70,M,M) { Location = 010, FlawlessIVCount = 3, Moves = new[] {427,094,585,849} }, // Cresselia (Coronet Highlands)
|
||||
new(491,000,70,M,M) { Location = 074, FlawlessIVCount = 3, Fateful = true, Moves = new[] {506,399,094,464} }, // Darkrai (Lonely Spring)
|
||||
|
||||
// Static Encounters
|
||||
new(046,000,50,M,M) { Location = 019, Method = Fixed }, // paras01: Paras
|
||||
@@ -106,11 +106,11 @@ internal static class Encounters8a
|
||||
new(486,000,70,M,M) { Location = 095, Method = Fixed, FlawlessIVCount = 3 }, // regigigas01: Regigigas
|
||||
new(487,001,70,M,M) { Location = 067, Method = Fixed, FlawlessIVCount = 3 }, // giratina02: Giratina-1
|
||||
|
||||
new(362,000,64,A,A) { Location = 011, Method = Fixed, IsAlpha = true, Moves = new[] {442,059,556,242}, Mastery = new[] {true,true,true, true } }, // onigohri01: Glalie
|
||||
new(402,000,12,A,A) { Location = 007, Method = Fixed, IsAlpha = true, Gender = 0, Moves = new[] {206,071,033,332}, Mastery = new[] {true,true,false,false} }, // mev002: Kricketune
|
||||
new(416,000,60,A,A) { Location = 022, Method = Fixed, IsAlpha = true, Gender = 1, FlawlessIVCount = 3, Moves = new[] {188,403,408,405}, Mastery = new[] {true,true,true ,true } }, // beequen01: Vespiquen
|
||||
new(571,001,58,M,M) { Location = 111, Method = Fixed, IsAlpha = true, Moves = new[] {555,421,841,417}, Mastery = new[] {true,true,true ,true } }, // zoroark01: Zoroark-1
|
||||
new(706,001,58,M,M) { Location = 104, Method = Fixed, IsAlpha = true, Moves = new[] {231,406,842,056}, Mastery = new[] {true,true,true ,true } }, // numelgon01: Goodra-1
|
||||
new(904,000,58,M,M) { Location = 105, Method = Fixed, IsAlpha = true, Moves = new[] {301,398,401,038}, Mastery = new[] {true,true,true ,false} }, // harysen01: Overqwil
|
||||
new(362,000,64,A,A) { Location = 011, Method = Fixed, IsAlpha = true, Moves = new[] {442,059,556,242} }, // onigohri01: Glalie
|
||||
new(402,000,12,A,A) { Location = 007, Method = Fixed, IsAlpha = true, Gender = 0, Moves = new[] {206,071,033,332} }, // mev002: Kricketune
|
||||
new(416,000,60,A,A) { Location = 022, Method = Fixed, IsAlpha = true, Gender = 1, FlawlessIVCount = 3, Moves = new[] {188,403,408,405} }, // beequen01: Vespiquen
|
||||
new(571,001,58,M,M) { Location = 111, Method = Fixed, IsAlpha = true, Moves = new[] {555,421,841,417} }, // zoroark01: Zoroark-1
|
||||
new(706,001,58,M,M) { Location = 104, Method = Fixed, IsAlpha = true, Moves = new[] {231,406,842,056} }, // numelgon01: Goodra-1
|
||||
new(904,000,58,M,M) { Location = 105, Method = Fixed, IsAlpha = true, Moves = new[] {301,398,401,038} }, // harysen01: Overqwil
|
||||
};
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ internal sealed record EncounterSlot3Swarm : EncounterSlot3, IMoveset
|
||||
|
||||
protected override void SetEncounterMoves(PKM pk, GameVersion version, int level)
|
||||
{
|
||||
var moves = Moves;
|
||||
var moves = (int[])Moves;
|
||||
pk.SetMoves(moves);
|
||||
pk.SetMaximumPPCurrent(moves);
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ namespace PKHeX.Core;
|
||||
/// Encounter Slot found in <see cref="GameVersion.SWSH"/>.
|
||||
/// </summary>
|
||||
/// <inheritdoc cref="EncounterSlot"/>
|
||||
public sealed record EncounterSlot8a : EncounterSlot, IAlpha
|
||||
public sealed record EncounterSlot8a : EncounterSlot, IAlpha, IMasteryInitialMoveShop8
|
||||
{
|
||||
public override int Generation => 8;
|
||||
public SlotType Type => Area.Type;
|
||||
@@ -25,9 +25,9 @@ public EncounterSlot8a(EncounterArea8a area, ushort species, byte form, byte min
|
||||
|
||||
public bool HasAlphaMove => IsAlpha && Type is not SlotType.Landmark;
|
||||
|
||||
protected override void ApplyDetails(ITrainerInfo sav, EncounterCriteria criteria, PKM pk)
|
||||
protected override void SetPINGA(PKM pk, EncounterCriteria criteria)
|
||||
{
|
||||
base.ApplyDetails(sav, criteria, pk);
|
||||
base.SetPINGA(pk, criteria);
|
||||
if (Gender != Gender.Random)
|
||||
pk.Gender = (int)Gender;
|
||||
|
||||
@@ -35,20 +35,39 @@ protected override void ApplyDetails(ITrainerInfo sav, EncounterCriteria criteri
|
||||
var (_, slotSeed) = Overworld8aRNG.ApplyDetails(pk, criteria, para, HasAlphaMove);
|
||||
if (LevelMin != LevelMax)
|
||||
pk.CurrentLevel = pk.Met_Level = Overworld8aRNG.GetRandomLevel(slotSeed, LevelMin, LevelMax);
|
||||
}
|
||||
|
||||
protected override void SetEncounterMoves(PKM pk, GameVersion version, int level)
|
||||
{
|
||||
var pa8 = (PA8)pk;
|
||||
Span<int> moves = stackalloc int[4];
|
||||
var index = PersonalTable.LA.GetFormIndex(Species, Form);
|
||||
var mastery = Legal.MasteryLA[index];
|
||||
var learn = Legal.LevelUpLA[index];
|
||||
if (pa8.AlphaMove != 0)
|
||||
{
|
||||
moves[0] = pa8.AlphaMove;
|
||||
learn.SetEncounterMovesBackwards(level, moves, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
learn.SetEncounterMoves(level, moves);
|
||||
}
|
||||
pk.SetMoves(moves);
|
||||
pk.SetMaximumPPCurrent(moves);
|
||||
foreach (var move in moves)
|
||||
{
|
||||
if (mastery.GetMoveLevel(move) <= level)
|
||||
pa8.SetMasteryFlagMove(move);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void SetFormatSpecificData(PKM pk)
|
||||
{
|
||||
var pa8 = (PA8)pk;
|
||||
if (IsAlpha)
|
||||
{
|
||||
if (pk is IAlpha a)
|
||||
a.IsAlpha = true;
|
||||
if (pk is PA8 { AlphaMove: not 0 } pa)
|
||||
pk.PushMove(pa.AlphaMove);
|
||||
}
|
||||
|
||||
if (pk is PA8 pa8)
|
||||
{
|
||||
pa8.HeightScalarCopy = pa8.HeightScalar;
|
||||
pa8.SetMasteryFlags();
|
||||
}
|
||||
pa8.IsAlpha = true;
|
||||
pa8.HeightScalarCopy = pa8.HeightScalar;
|
||||
}
|
||||
|
||||
protected override void ApplyDetailsBall(PKM pk) => pk.Ball = (int)Ball.LAPoke;
|
||||
@@ -71,8 +90,10 @@ private EncounterMatchRating GetMatchRatingInternal(PKM pkm)
|
||||
return EncounterMatchRating.DeferredErrors;
|
||||
if (IsFormArgMismatch(pkm))
|
||||
return EncounterMatchRating.DeferredErrors;
|
||||
if (!IsForcedMasteryCorrect(pkm))
|
||||
return EncounterMatchRating.DeferredErrors;
|
||||
|
||||
return GetAlphaMoveCompatibility(pkm);
|
||||
return GetMoveCompatibility(pkm);
|
||||
}
|
||||
|
||||
private bool IsFormArgMismatch(PKM pkm) => pkm.Species switch
|
||||
@@ -83,7 +104,7 @@ private EncounterMatchRating GetMatchRatingInternal(PKM pkm)
|
||||
_ => false,
|
||||
};
|
||||
|
||||
private EncounterMatchRating GetAlphaMoveCompatibility(PKM pkm)
|
||||
private EncounterMatchRating GetMoveCompatibility(PKM pkm)
|
||||
{
|
||||
// Check for Alpha move compatibility.
|
||||
if (pkm is not PA8 pa)
|
||||
@@ -115,6 +136,30 @@ private EncounterMatchRating GetAlphaMoveCompatibility(PKM pkm)
|
||||
return EncounterMatchRating.Match;
|
||||
}
|
||||
|
||||
public bool IsForcedMasteryCorrect(PKM pkm)
|
||||
{
|
||||
if (pkm is not IMoveShop8Mastery p)
|
||||
return true; // Can't check.
|
||||
|
||||
Span<int> moves = stackalloc int[4];
|
||||
var level = pkm.Met_Level;
|
||||
var index = PersonalTable.LA.GetFormIndex(Species, Form);
|
||||
var mastery = Legal.MasteryLA[index];
|
||||
var learn = Legal.LevelUpLA[index];
|
||||
ushort alpha = 0;
|
||||
if (pkm is PA8 { AlphaMove: not 0 } pa8)
|
||||
{
|
||||
moves[0] = alpha = pa8.AlphaMove;
|
||||
learn.SetEncounterMovesBackwards(level, moves, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
learn.SetEncounterMoves(level, moves);
|
||||
}
|
||||
|
||||
return p.IsValidMasteredEncounter(moves, mastery, level, alpha);
|
||||
}
|
||||
|
||||
private OverworldParam8a GetParams()
|
||||
{
|
||||
var pt = PersonalTable.LA;
|
||||
|
||||
@@ -156,9 +156,9 @@ protected virtual void SetMetData(PKM pk, int level, DateTime today)
|
||||
pk.MetDate = today;
|
||||
}
|
||||
|
||||
private void SetEncounterMoves(PKM pk, GameVersion version, int level)
|
||||
protected virtual void SetEncounterMoves(PKM pk, GameVersion version, int level)
|
||||
{
|
||||
var moves = Moves.Count > 0 ? Moves : MoveLevelUp.GetEncounterMoves(pk, level, version);
|
||||
var moves = Moves.Count > 0 ? (int[])Moves : MoveLevelUp.GetEncounterMoves(pk, level, version);
|
||||
pk.SetMoves(moves);
|
||||
pk.SetMaximumPPCurrent(moves);
|
||||
}
|
||||
|
||||
@@ -6,9 +6,8 @@ namespace PKHeX.Core;
|
||||
/// Generation 8 Static Encounter
|
||||
/// </summary>
|
||||
/// <inheritdoc cref="EncounterStatic"/>
|
||||
public sealed record EncounterStatic8a(GameVersion Version) : EncounterStatic(Version), IAlpha
|
||||
public sealed record EncounterStatic8a(GameVersion Version) : EncounterStatic(Version), IAlpha, IMasteryInitialMoveShop8
|
||||
{
|
||||
public bool[]? Mastery;
|
||||
public override int Generation => 8;
|
||||
|
||||
public byte HeightScalar { get; }
|
||||
@@ -33,31 +32,20 @@ public EncounterStatic8a(ushort species, ushort form, byte level, byte h = NoSca
|
||||
protected override void ApplyDetails(ITrainerInfo sav, EncounterCriteria criteria, PKM pk)
|
||||
{
|
||||
base.ApplyDetails(sav, criteria, pk);
|
||||
if (pk is IScaledSize s)
|
||||
{
|
||||
if (HasFixedHeight)
|
||||
s.HeightScalar = HeightScalar;
|
||||
if (HasFixedWeight)
|
||||
s.WeightScalar = WeightScalar;
|
||||
if (pk is IScaledSizeValue v)
|
||||
{
|
||||
v.ResetHeight();
|
||||
v.ResetWeight();
|
||||
}
|
||||
}
|
||||
|
||||
if (IsAlpha && pk is IAlpha a)
|
||||
a.IsAlpha = true;
|
||||
var pa = (PA8)pk;
|
||||
|
||||
if (pk is PA8 pa)
|
||||
{
|
||||
if (IsAlpha && Moves.Count != 0)
|
||||
pa.AlphaMove = (ushort)Moves[0];
|
||||
if (pa.AlphaMove != 0)
|
||||
pk.PushMove(pa.AlphaMove);
|
||||
pa.SetMasteryFlags();
|
||||
pa.HeightScalarCopy = pa.HeightScalar;
|
||||
}
|
||||
if (IsAlpha)
|
||||
pa.IsAlpha = true;
|
||||
|
||||
if (HasFixedHeight)
|
||||
pa.HeightScalar = HeightScalar;
|
||||
if (HasFixedWeight)
|
||||
pa.WeightScalar = WeightScalar;
|
||||
pa.HeightScalarCopy = pa.HeightScalar;
|
||||
|
||||
pa.ResetHeight();
|
||||
pa.ResetWeight();
|
||||
}
|
||||
|
||||
protected override void SetPINGA(PKM pk, EncounterCriteria criteria)
|
||||
@@ -97,9 +85,6 @@ public override bool IsMatchExact(PKM pkm, IDexLevel evo)
|
||||
|
||||
public override EncounterMatchRating GetMatchRating(PKM pkm)
|
||||
{
|
||||
if (!IsForcedMasteryCorrect(pkm))
|
||||
return EncounterMatchRating.PartialMatch;
|
||||
|
||||
var result = GetMatchRatingInternal(pkm);
|
||||
var orig = base.GetMatchRating(pkm);
|
||||
return result > orig ? result : orig;
|
||||
@@ -116,39 +101,61 @@ private EncounterMatchRating GetMatchRatingInternal(PKM pkm)
|
||||
if (orig is not EncounterMatchRating.Match)
|
||||
return orig;
|
||||
|
||||
if (!IsForcedMasteryCorrect(pkm))
|
||||
return EncounterMatchRating.DeferredErrors;
|
||||
|
||||
if (IsAlpha && pkm is PA8 { AlphaMove: 0 })
|
||||
return EncounterMatchRating.Deferred;
|
||||
|
||||
return EncounterMatchRating.Match;
|
||||
}
|
||||
|
||||
private bool IsForcedMasteryCorrect(PKM pkm)
|
||||
public bool IsForcedMasteryCorrect(PKM pkm)
|
||||
{
|
||||
if (Mastery is not { } m)
|
||||
return true;
|
||||
|
||||
ushort alpha = 0;
|
||||
if (IsAlpha && Moves.Count != 0)
|
||||
{
|
||||
if (pkm is PA8 pa && pa.AlphaMove != Moves[0])
|
||||
if (pkm is PA8 pa && (alpha = pa.AlphaMove) != Moves[0])
|
||||
return false;
|
||||
}
|
||||
|
||||
if (pkm is not IMoveShop8Mastery p)
|
||||
return true;
|
||||
|
||||
for (int i = 0; i < m.Length; i++)
|
||||
{
|
||||
if (!m[i])
|
||||
continue;
|
||||
var move = Moves[i];
|
||||
var index = p.MoveShopPermitIndexes.IndexOf((ushort)move);
|
||||
if (index == -1)
|
||||
continue; // manually mastered for encounter, not a tutor
|
||||
if (!p.GetMasteredRecordFlag(index))
|
||||
return false;
|
||||
}
|
||||
Span<int> m = stackalloc int[4];
|
||||
var level = pkm.Met_Level;
|
||||
var index = PersonalTable.LA.GetFormIndex(Species, Form);
|
||||
var mastery = Legal.MasteryLA[index];
|
||||
if (Moves.Count != 0)
|
||||
m = (int[])Moves;
|
||||
else
|
||||
Legal.LevelUpLA[index].SetEncounterMoves(level, m);
|
||||
|
||||
return true;
|
||||
return p.IsValidMasteredEncounter(m, mastery, level, alpha);
|
||||
}
|
||||
|
||||
protected override void SetEncounterMoves(PKM pk, GameVersion version, int level)
|
||||
{
|
||||
var pa8 = (PA8)pk;
|
||||
Span<int> moves = stackalloc int[4];
|
||||
var index = PersonalTable.LA.GetFormIndex(Species, Form);
|
||||
var mastery = Legal.MasteryLA[index];
|
||||
var learn = Legal.LevelUpLA[index];
|
||||
if (IsAlpha && Moves.Count != 0)
|
||||
{
|
||||
moves = (int[])Moves;
|
||||
}
|
||||
else
|
||||
{
|
||||
learn.SetEncounterMoves(level, moves);
|
||||
}
|
||||
pk.SetMoves(moves);
|
||||
pk.SetMaximumPPCurrent(moves);
|
||||
foreach (var move in moves)
|
||||
{
|
||||
if (mastery.GetMoveLevel(move) <= level)
|
||||
pa8.SetMasteryFlagMove(move);
|
||||
}
|
||||
}
|
||||
|
||||
private OverworldParam8a GetParams()
|
||||
|
||||
@@ -161,8 +161,8 @@ private void SetMoves(PKM pk, GameVersion version, int level)
|
||||
var moves = Moves.Count != 0 ? Moves : MoveLevelUp.GetEncounterMoves(pk, level, version);
|
||||
if (pk.Format == 1 && moves.All(z => z == 0))
|
||||
moves = ((PersonalInfoG1)PersonalTable.RB[Species]).Moves;
|
||||
pk.SetMoves(moves);
|
||||
pk.SetMaximumPPCurrent(moves);
|
||||
pk.SetMoves((int[])moves);
|
||||
pk.SetMaximumPPCurrent((int[])moves);
|
||||
}
|
||||
|
||||
private void SetEggMetData(PKM pk, DateTime time)
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace PKHeX.Core;
|
||||
|
||||
public interface IMasteryInitialMoveShop8
|
||||
{
|
||||
bool IsForcedMasteryCorrect(PKM pkm);
|
||||
}
|
||||
@@ -142,6 +142,7 @@ public static class LegalityCheckStrings
|
||||
public static string LEncGiftVersionNotDistributed { get; set; } = "Mystery Gift cannot be received by this version.";
|
||||
|
||||
public static string LEncInvalid { get; set; } = "Unable to match an encounter from origin game.";
|
||||
public static string LEncMasteryInitial { get; set; } = "Initial move mastery flags do not match the encounter's expected state.";
|
||||
|
||||
public static string LEncTradeChangedNickname { get; set; } = "In-game Trade Nickname has been altered.";
|
||||
public static string LEncTradeChangedOT { get; set; } = "In-game Trade OT has been altered.";
|
||||
|
||||
@@ -42,9 +42,11 @@ public int[] GetMoves(int maxLevel, int minLevel = 0)
|
||||
int end = Array.FindLastIndex(Levels, z => z <= maxLevel);
|
||||
if (end < 0)
|
||||
return Array.Empty<int>();
|
||||
int[] result = new int[end - start + 1];
|
||||
Array.Copy(Moves, start, result, 0, result.Length);
|
||||
return result;
|
||||
|
||||
var length = end - start + 1;
|
||||
if (length == Moves.Length)
|
||||
return Moves;
|
||||
return Moves.AsSpan(start, length).ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -121,6 +123,34 @@ public void SetEncounterMoves(int level, Span<int> moves, int ctr = 0)
|
||||
}
|
||||
}
|
||||
|
||||
public void SetEncounterMovesBackwards(int level, Span<int> moves, int ctr = 0)
|
||||
{
|
||||
int index = Array.FindLastIndex(Levels, z => z <= level);
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (index == -1)
|
||||
return; // no moves to add?
|
||||
|
||||
// In the event we have multiple moves at the same level, insert them in regular descending order.
|
||||
int start = index;
|
||||
while (start != 0 && Levels[start] == Levels[start - 1])
|
||||
start--;
|
||||
|
||||
for (int i = start; i <= index; i++)
|
||||
{
|
||||
var move = Moves[i];
|
||||
if (moves.IndexOf(move) == -1)
|
||||
moves[ctr++] = move;
|
||||
|
||||
if (ctr == 4)
|
||||
return;
|
||||
}
|
||||
|
||||
index = start - 1;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Adds the learned moves by level up to the specified level.</summary>
|
||||
public void SetLevelUpMoves(int startLevel, int endLevel, Span<int> moves, int ctr = 0)
|
||||
{
|
||||
@@ -228,6 +258,14 @@ public int GetMinMoveLevel(int level)
|
||||
return Math.Max(end - 4, 1);
|
||||
}
|
||||
|
||||
public int GetMoveLevel(int move)
|
||||
{
|
||||
var index = Array.LastIndexOf(Moves, move);
|
||||
if (index == -1)
|
||||
return -1;
|
||||
return Levels[index];
|
||||
}
|
||||
|
||||
private Dictionary<int, int>? Learn;
|
||||
|
||||
private Dictionary<int, int> GetDictionary()
|
||||
|
||||
@@ -114,6 +114,11 @@ public override void Verify(LegalityAnalysis data)
|
||||
if (!valid)
|
||||
data.AddLine(GetInvalid(LPIDTypeMismatch));
|
||||
}
|
||||
else if (enc is IMasteryInitialMoveShop8 m)
|
||||
{
|
||||
if (!m.IsForcedMasteryCorrect(pkm))
|
||||
data.AddLine(GetInvalid(LEncMasteryInitial));
|
||||
}
|
||||
|
||||
VerifyMiscFatefulEncounter(data);
|
||||
VerifyMiscPokerus(data);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using static System.Buffers.Binary.BinaryPrimitives;
|
||||
|
||||
namespace PKHeX.Core
|
||||
@@ -110,7 +111,7 @@ private void EncryptPK()
|
||||
public override bool IsPokémon { get => PGTGiftType is GiftType.Pokémon or GiftType.PokémonEgg or GiftType.ManaphyEgg; set { } }
|
||||
|
||||
public override int Species { get => IsManaphyEgg ? 490 : PK.Species; set => PK.Species = value; }
|
||||
public override IReadOnlyList<int> Moves { get => PK.Moves; set => PK.SetMoves(value); }
|
||||
public override IReadOnlyList<int> Moves { get => PK.Moves; set => PK.SetMoves(value.ToArray()); }
|
||||
public override int HeldItem { get => PK.HeldItem; set => PK.HeldItem = value; }
|
||||
public override bool IsShiny => PK.IsShiny;
|
||||
public override int Gender { get => PK.Gender; set => PK.Gender = value; }
|
||||
|
||||
@@ -168,8 +168,9 @@ private void SetMoves(PK3 pk)
|
||||
Moves = moves;
|
||||
}
|
||||
|
||||
pk.SetMoves(Moves);
|
||||
pk.SetMaximumPPCurrent(Moves);
|
||||
var m = (int[])Moves;
|
||||
pk.SetMoves(m);
|
||||
pk.SetMaximumPPCurrent(m);
|
||||
}
|
||||
|
||||
private void SetPINGA(PK3 pk, EncounterCriteria _)
|
||||
|
||||
@@ -18,3 +18,52 @@ public interface IMoveShop8Mastery : IMoveShop8
|
||||
void SetMasteredRecordFlag(int index, bool value);
|
||||
bool GetMasteredRecordFlagAny();
|
||||
}
|
||||
|
||||
public static class MoveShop8MasteryExtensions
|
||||
{
|
||||
public static bool IsValidMasteredEncounter(this IMoveShop8Mastery shop, Span<int> moves, Learnset mastery, int level, ushort alpha)
|
||||
{
|
||||
foreach (var move in moves)
|
||||
{
|
||||
if (move == 0)
|
||||
continue;
|
||||
var index = shop.MoveShopPermitIndexes.IndexOf((ushort)move);
|
||||
if (index == -1)
|
||||
continue; // manually mastered for encounter, not a tutor
|
||||
|
||||
bool p = shop.GetPurchasedRecordFlag(index);
|
||||
bool m = shop.GetMasteredRecordFlag(index);
|
||||
|
||||
var masteryLevel = mastery.GetMoveLevel(move);
|
||||
if (masteryLevel > level && move != alpha) // no master flag set
|
||||
{
|
||||
if (!p && m)
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (p || !m)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool IsPurchasedEncounterMove(IMoveShop8 p, Span<int> moves)
|
||||
{
|
||||
foreach (var move in moves)
|
||||
{
|
||||
if (move == 0)
|
||||
continue;
|
||||
var index = p.MoveShopPermitIndexes.IndexOf((ushort)move);
|
||||
if (index == -1)
|
||||
continue; // manually mastered for encounter, not a tutor
|
||||
|
||||
if (p.GetPurchasedRecordFlag(index))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -439,7 +439,7 @@ public int[] Stats
|
||||
public int[] Moves
|
||||
{
|
||||
get => new[] { Move1, Move2, Move3, Move4 };
|
||||
set => SetMoves(value);
|
||||
set => SetMoves(value.AsSpan());
|
||||
}
|
||||
|
||||
public void PushMove(int move)
|
||||
@@ -464,12 +464,12 @@ public void GetMoves(Span<int> value)
|
||||
value[0] = Move1;
|
||||
}
|
||||
|
||||
public void SetMoves(IReadOnlyList<int> value)
|
||||
public void SetMoves(ReadOnlySpan<int> value)
|
||||
{
|
||||
Move1 = value.Count > 0 ? value[0] : 0;
|
||||
Move2 = value.Count > 1 ? value[1] : 0;
|
||||
Move3 = value.Count > 2 ? value[2] : 0;
|
||||
Move4 = value.Count > 3 ? value[3] : 0;
|
||||
Move1 = value.Length > 0 ? value[0] : 0;
|
||||
Move2 = value.Length > 1 ? value[1] : 0;
|
||||
Move3 = value.Length > 2 ? value[2] : 0;
|
||||
Move4 = value.Length > 3 ? value[3] : 0;
|
||||
}
|
||||
|
||||
public int[] RelearnMoves
|
||||
|
||||
BIN
PKHeX.Core/Resources/legality/misc/mastery_la.pkl
Normal file
BIN
PKHeX.Core/Resources/legality/misc/mastery_la.pkl
Normal file
Binary file not shown.
Reference in New Issue
Block a user