using System; using System.Diagnostics.CodeAnalysis; using static PKHeX.Core.LearnMethod; using static PKHeX.Core.LearnEnvironment; using static PKHeX.Core.PersonalInfo2; namespace PKHeX.Core; /// /// Exposes information about how moves are learned in . /// public sealed class LearnSource2GS : ILearnSource, IEggSource { public static readonly LearnSource2GS Instance = new(); private static readonly PersonalTable2 Personal = PersonalTable.GS; private static readonly MoveSource[] EggMoves = MoveSource.GetArray(BinLinkerAccessor16.Get(Util.GetBinaryResource("eggmove_gs.pkl"), "gs"u8)); private static readonly Learnset[] Learnsets = LearnsetReader.GetArray(BinLinkerAccessor16.Get(Util.GetBinaryResource("lvlmove_gs.pkl"), "gs"u8)); private const int MaxSpecies = Legal.MaxSpeciesID_2; private const LearnEnvironment Game = GS; public LearnEnvironment Environment => Game; public Learnset GetLearnset(ushort species, byte form) => Learnsets[species < Learnsets.Length ? species : 0]; public bool TryGetPersonal(ushort species, byte form, [NotNullWhen(true)] out PersonalInfo2? pi) { if (form is not 0 || species > MaxSpecies) { pi = null; return false; } pi = Personal[species]; return true; } public bool GetIsEggMove(ushort species, byte form, ushort move) { var arr = EggMoves; if (species >= arr.Length) return false; var moves = arr[species]; return moves.GetHasMove(move); } public ReadOnlySpan GetEggMoves(ushort species, byte form) { var arr = EggMoves; if (species >= arr.Length) return []; return arr[species].Moves; } // Present and not in Crystal: // 001 (Bulbasaur) += Charm // 016 (Pidgey) += SteelWing // 043 (Oddish) += Charm // 046 (Paras) += SweetScent // 083 (Farfetchd) += SteelWing // 120 (Staryu) += AuroraBeam, Barrier, Supersonic // 142 (Aerodactyl) += SteelWing // 143 (Snorlax) += Charm // 238 (Smoochum) += LovelyKiss // Added via Crystal, not in GS: // 023 (Ekans) += Crunch // 027 (Sandshrew) += MetalClaw // 054 (Psyduck) += CrossChop // 104 (Cubone) += SwordsDance // 152 (Chikorita) += SwordsDance // 155 (Cyndaquil) += Submission // 163 (Hoothoot) += SkyAttack // 198 (Murkrow) += SkyAttack // 216 (Teddiursa) += MetalClaw // 227 (Skarmory) += SkyAttack // 231 (Phanpy) += WaterGun // 239 (Elekid) += CrossChop // 240 (Magby) += CrossChop public MoveLearnInfo GetCanLearn(PKM pk, PersonalInfo2 pi, EvoCriteria evo, ushort move, MoveSourceType types = MoveSourceType.All, LearnOption option = LearnOption.Current) { if (move > Legal.MaxMoveID_2) // byte return default; if (types.HasFlag(MoveSourceType.Machine) && GetIsTM(pi, (byte)move)) return new(TMHM, Game); if (types.HasFlag(MoveSourceType.LevelUp)) { var learn = Learnsets[evo.Species]; if (learn.TryGetLevelLearnMove(move, out var level)) { if (evo.InsideLevelRange(level)) return new(LevelUp, Game, level); if (level == 1 && types.HasFlag(MoveSourceType.Evolve)) // Evolution return new(Evolution, Game, level); } } return default; } private static bool GetIsTM(PersonalInfo2 info, byte move) { var index = MachineMoves.IndexOf(move); if (index == -1) return false; return info.GetIsLearnTM(index); } public void GetAllMoves(Span result, PKM pk, EvoCriteria evo, MoveSourceType types = MoveSourceType.All) { if (!TryGetPersonal(evo.Species, evo.Form, out var pi)) return; bool removeVC = pk.Format == 1 || pk.VC1; if (types.HasFlag(MoveSourceType.LevelUp)) { var learn = Learnsets[evo.Species]; var span = learn.GetMoveRange(evo.LevelMax, evo.LevelMin); foreach (var move in span) { if (!removeVC || move <= Legal.MaxMoveID_1) result[move] = true; } } if (types.HasFlag(MoveSourceType.Machine)) pi.SetAllLearnTM(result, MachineMoves); } public static void GetEncounterMoves(IEncounterTemplate enc, Span init) { var species = enc.Species; var learn = Learnsets[species]; learn.SetEncounterMoves(enc.LevelMin, init); } }