mirror of
https://github.com/kwsch/PKHeX
synced 2024-11-26 14:00:21 +00:00
PKHeX.Core Nullable cleanup (#2401)
* Handle some nullable cases Refactor MysteryGift into a second abstract class (backed by a byte array, or fake data) Make some classes have explicit constructors instead of { } initialization * Handle bits more obviously without null * Make SaveFile.BAK explicitly readonly again * merge constructor methods to have readonly fields * Inline some properties * More nullable handling * Rearrange box actions define straightforward classes to not have any null properties * Make extrabyte reference array immutable * Move tooltip creation to designer * Rearrange some logic to reduce nesting * Cache generated fonts * Split mystery gift album purpose * Handle more tooltips * Disallow null setters * Don't capture RNG object, only type enum * Unify learnset objects Now have readonly properties which are never null don't new() empty learnsets (>800 Learnset objects no longer created, total of 2400 objects since we also new() a move & level array) optimize g1/2 reader for early abort case * Access rewrite Initialize blocks in a separate object, and get via that object removes a couple hundred "might be null" warnings since blocks are now readonly getters some block references have been relocated, but interfaces should expose all that's needed put HoF6 controls in a groupbox, and disable * Readonly personal data * IVs non nullable for mystery gift * Explicitly initialize forced encounter moves * Make shadow objects readonly & non-null Put murkrow fix in binary data resource, instead of on startup * Assign dex form fetch on constructor Fixes legality parsing edge cases also handle cxd parse for valid; exit before exception is thrown in FrameGenerator * Remove unnecessary null checks * Keep empty value until init SetPouch sets the value to an actual one during load, but whatever * Readonly team lock data * Readonly locks Put locked encounters at bottom (favor unlocked) * Mail readonly data / offset Rearrange some call flow and pass defaults Add fake classes for SaveDataEditor mocking Always party size, no need to check twice in stat editor use a fake save file as initial data for savedata editor, and for gamedata (wow i found a usage) constrain eventwork editor to struct variable types (uint, int, etc), thus preventing null assignment errors
This commit is contained in:
parent
a70769dc76
commit
02420d3e93
340 changed files with 4945 additions and 4367 deletions
|
@ -79,7 +79,7 @@ namespace PKHeX.Core
|
|||
/// <param name="propertyName">Property Name to fetch the type for</param>
|
||||
/// <param name="typeIndex">Type index (within <see cref="Types"/>. Leave empty (0) for a nonspecific format.</param>
|
||||
/// <returns>Short name of the property's type.</returns>
|
||||
public static string GetPropertyType(string propertyName, int typeIndex = 0)
|
||||
public static string? GetPropertyType(string propertyName, int typeIndex = 0)
|
||||
{
|
||||
if (CustomProperties.Contains(propertyName))
|
||||
return "Custom";
|
||||
|
@ -164,6 +164,8 @@ namespace PKHeX.Core
|
|||
return false;
|
||||
try
|
||||
{
|
||||
if (pi == null)
|
||||
continue;
|
||||
if (pi.IsValueEqual(obj, cmd.PropertyValue) == cmd.Evaluator)
|
||||
continue;
|
||||
}
|
||||
|
@ -248,7 +250,7 @@ namespace PKHeX.Core
|
|||
if (cmd.PropertyValue == CONST_SUGGEST)
|
||||
return SetSuggestedPKMProperty(cmd.PropertyName, info);
|
||||
if (cmd.PropertyValue == CONST_RAND && cmd.PropertyName == nameof(PKM.Moves))
|
||||
return SetMoves(pk, pk.GetMoveSet(true, info.Legality));
|
||||
return SetMoves(pk, pk.GetMoveSet(info.Legality, true));
|
||||
|
||||
if (SetComplexProperty(pk, cmd))
|
||||
return ModifyResult.Modified;
|
||||
|
@ -321,7 +323,7 @@ namespace PKHeX.Core
|
|||
if (cmd.PropertyName != IdentifierContains)
|
||||
return false;
|
||||
|
||||
bool result = pk.Identifier.Contains(cmd.PropertyValue);
|
||||
bool result = pk.Identifier?.Contains(cmd.PropertyValue) ?? false;
|
||||
return result == cmd.Evaluator;
|
||||
}
|
||||
|
||||
|
@ -451,7 +453,7 @@ namespace PKHeX.Core
|
|||
else if (cmd.PropertyName == nameof(PKM.PID) && cmd.PropertyValue == CONST_SHINY)
|
||||
pk.SetShiny();
|
||||
else if (cmd.PropertyName == nameof(PKM.Species) && cmd.PropertyValue == "0")
|
||||
pk.Data = new byte[pk.Data.Length];
|
||||
Array.Clear(pk.Data, 0, pk.Data.Length);
|
||||
else if (cmd.PropertyName.StartsWith("IV") && cmd.PropertyValue == CONST_RAND)
|
||||
SetRandomIVs(pk, cmd);
|
||||
else if (cmd.PropertyName == nameof(PKM.IsNicknamed) && string.Equals(cmd.PropertyValue, "false", StringComparison.OrdinalIgnoreCase))
|
||||
|
|
|
@ -10,11 +10,11 @@ namespace PKHeX.Core
|
|||
internal PKM pkm { get; }
|
||||
internal PKMInfo(PKM pk) { pkm = pk; }
|
||||
|
||||
private LegalityAnalysis la;
|
||||
internal LegalityAnalysis Legality => la ?? (la = new LegalityAnalysis(pkm));
|
||||
private LegalityAnalysis? la;
|
||||
internal LegalityAnalysis Legality => la ??= new LegalityAnalysis(pkm);
|
||||
|
||||
public bool Legal => Legality.Valid;
|
||||
internal IReadOnlyList<int> SuggestedRelearn => Legality.GetSuggestedRelearn();
|
||||
internal EncounterStatic SuggestedEncounter => Legality.GetSuggestedMetInfo();
|
||||
internal EncounterStatic? SuggestedEncounter => Legality.GetSuggestedMetInfo();
|
||||
}
|
||||
}
|
|
@ -20,6 +20,12 @@ namespace PKHeX.Core
|
|||
public string PropertyValue { get; private set; }
|
||||
public bool Evaluator { get; private set; }
|
||||
|
||||
public StringInstruction(string name, string value)
|
||||
{
|
||||
PropertyName = name;
|
||||
PropertyValue = value;
|
||||
}
|
||||
|
||||
public void SetScreenedValue(string[] arr)
|
||||
{
|
||||
int index = Array.IndexOf(arr, PropertyValue);
|
||||
|
@ -72,7 +78,7 @@ namespace PKHeX.Core
|
|||
let eval = line[0] == Require
|
||||
let split = line.Substring(1).Split(SplitInstruction)
|
||||
where split.Length == 2 && !string.IsNullOrWhiteSpace(split[0])
|
||||
select new StringInstruction { PropertyName = split[0], PropertyValue = split[1], Evaluator = eval };
|
||||
select new StringInstruction(split[0], split[1]) { Evaluator = eval };
|
||||
}
|
||||
|
||||
public static IEnumerable<StringInstruction> GetInstructions(IEnumerable<string> lines)
|
||||
|
@ -81,7 +87,7 @@ namespace PKHeX.Core
|
|||
return from line in raw
|
||||
select line.Split(SplitInstruction) into split
|
||||
where split.Length == 2
|
||||
select new StringInstruction { PropertyName = split[0], PropertyValue = split[1] };
|
||||
select new StringInstruction(split[0], split[1]);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -13,23 +13,26 @@ namespace PKHeX.Core
|
|||
|
||||
private const string SetSeparator = ";";
|
||||
|
||||
public StringInstructionSet(IList<StringInstruction> filters, IList<StringInstruction> instructions)
|
||||
{
|
||||
Filters = filters;
|
||||
Instructions = instructions;
|
||||
}
|
||||
|
||||
public StringInstructionSet(ICollection<string> set)
|
||||
{
|
||||
Filters = StringInstruction.GetFilters(set).ToList();
|
||||
Instructions = StringInstruction.GetInstructions(set).ToList();
|
||||
}
|
||||
|
||||
public static IEnumerable<StringInstructionSet> GetBatchSets(IList<string> lines)
|
||||
{
|
||||
int start = 0;
|
||||
while (start < lines.Count)
|
||||
{
|
||||
var list = lines.Skip(start).TakeWhile(_ => !lines[start++].StartsWith(SetSeparator)).ToList();
|
||||
yield return GetBatchSet(list);
|
||||
yield return new StringInstructionSet(list);
|
||||
}
|
||||
}
|
||||
|
||||
private static StringInstructionSet GetBatchSet(ICollection<string> set)
|
||||
{
|
||||
return new StringInstructionSet
|
||||
{
|
||||
Filters = StringInstruction.GetFilters(set).ToList(),
|
||||
Instructions = StringInstruction.GetInstructions(set).ToList(),
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -597,6 +597,18 @@ namespace PKHeX.Core
|
|||
pb.ResetCP();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a moveset for the provided <see cref="PKM"/> data.
|
||||
/// </summary>
|
||||
/// <param name="pkm">PKM to generate for</param>
|
||||
/// <param name="random">Full movepool & shuffling</param>
|
||||
/// <returns>4 moves</returns>
|
||||
public static int[] GetMoveSet(this PKM pkm, bool random = false)
|
||||
{
|
||||
var la = new LegalityAnalysis(pkm);
|
||||
return pkm.GetMoveSet(la, random);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a moveset for the provided <see cref="PKM"/> data.
|
||||
/// </summary>
|
||||
|
@ -604,10 +616,8 @@ namespace PKHeX.Core
|
|||
/// <param name="random">Full movepool & shuffling</param>
|
||||
/// <param name="la">Precomputed optional</param>
|
||||
/// <returns>4 moves</returns>
|
||||
public static int[] GetMoveSet(this PKM pkm, bool random = false, LegalityAnalysis la = null)
|
||||
public static int[] GetMoveSet(this PKM pkm, LegalityAnalysis la, bool random = false)
|
||||
{
|
||||
if (la == null)
|
||||
la = new LegalityAnalysis(pkm);
|
||||
int[] m = la.GetSuggestedMoves(tm: random, tutor: random, reminder: random);
|
||||
if (m == null)
|
||||
return pkm.Moves;
|
||||
|
|
|
@ -85,7 +85,7 @@ namespace PKHeX.Core
|
|||
return true; // no mods necessary
|
||||
|
||||
// Required HP type doesn't match IVs. Make currently-flawless IVs flawed.
|
||||
int[] best = GetSuggestedHiddenPowerIVs(hpVal, IVs);
|
||||
int[]? best = GetSuggestedHiddenPowerIVs(hpVal, IVs);
|
||||
if (best == null)
|
||||
return false; // can't force hidden power?
|
||||
|
||||
|
@ -95,12 +95,12 @@ namespace PKHeX.Core
|
|||
return true;
|
||||
}
|
||||
|
||||
private static int[] GetSuggestedHiddenPowerIVs(int hpVal, int[] IVs)
|
||||
private static int[]? GetSuggestedHiddenPowerIVs(int hpVal, int[] IVs)
|
||||
{
|
||||
var flawless = IVs.Select((v, i) => v == 31 ? i : -1).Where(v => v != -1).ToArray();
|
||||
var permutations = GetPermutations(flawless, flawless.Length);
|
||||
int flawedCount = 0;
|
||||
int[] best = null;
|
||||
int[]? best = null;
|
||||
foreach (var permute in permutations)
|
||||
{
|
||||
var ivs = (int[])IVs.Clone();
|
||||
|
|
|
@ -13,7 +13,7 @@ namespace PKHeX.Core
|
|||
private readonly ushort[] Stats;
|
||||
protected readonly PKM pkm; // protected for children generating extra properties
|
||||
|
||||
public string Position => pkm.Identifier;
|
||||
public string? Position => pkm.Identifier;
|
||||
public string Nickname => pkm.Nickname;
|
||||
public string Species => Get(Strings.specieslist, pkm.Species);
|
||||
public string Nature => Get(Strings.natures, pkm.Nature);
|
||||
|
@ -124,6 +124,6 @@ namespace PKHeX.Core
|
|||
/// <param name="arr">Array of strings</param>
|
||||
/// <param name="val">Index to fetch</param>
|
||||
/// <returns>Null if array is null</returns>
|
||||
private static string Get(IReadOnlyList<string> arr, int val) => (uint)val < arr?.Count ? arr[val] : null;
|
||||
private static string Get(IReadOnlyList<string> arr, int val) => (uint)val < arr?.Count ? arr[val] : string.Empty;
|
||||
}
|
||||
}
|
75
PKHeX.Core/Editing/Saves/BoxManipBase.cs
Normal file
75
PKHeX.Core/Editing/Saves/BoxManipBase.cs
Normal file
|
@ -0,0 +1,75 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using PKHeX.Core.Searching;
|
||||
|
||||
namespace PKHeX.Core
|
||||
{
|
||||
public abstract class BoxManipBase : IBoxManip
|
||||
{
|
||||
protected BoxManipBase(BoxManipType type, Func<SaveFile, bool> usable)
|
||||
{
|
||||
Type = type;
|
||||
Usable = usable;
|
||||
}
|
||||
|
||||
public BoxManipType Type { get; }
|
||||
public Func<SaveFile, bool> Usable { get; }
|
||||
|
||||
public abstract string GetPrompt(bool all);
|
||||
public abstract string GetFail(bool all);
|
||||
public abstract string GetSuccess(bool all);
|
||||
public abstract int Execute(SaveFile SAV, BoxManipParam param);
|
||||
|
||||
public static readonly IReadOnlyList<BoxManipBase> SortCommon = new List<BoxManipBase>
|
||||
{
|
||||
new BoxManipSort(BoxManipType.SortSpecies, PKMSorting.OrderBySpecies),
|
||||
new BoxManipSort(BoxManipType.SortSpeciesReverse, PKMSorting.OrderByDescendingSpecies),
|
||||
new BoxManipSort(BoxManipType.SortLevel, PKMSorting.OrderByLevel),
|
||||
new BoxManipSort(BoxManipType.SortLevelReverse, PKMSorting.OrderByDescendingLevel),
|
||||
new BoxManipSort(BoxManipType.SortDate, PKMSorting.OrderByDateObtained, s => s.Generation >= 4),
|
||||
new BoxManipSort(BoxManipType.SortName, list => list.OrderBySpeciesName(GameInfo.Strings.Species)),
|
||||
new BoxManipSort(BoxManipType.SortFavorite, list => list.OrderByCustom(pk => pk is PB7 pb7 && pb7.Favorite), s => s is SAV7b),
|
||||
new BoxManipSortComplex(BoxManipType.SortParty, (list, sav) => list.OrderByCustom(pk => ((SAV7b)sav).Blocks.Storage.GetPartyIndex(pk.Box - 1, pk.Slot - 1)), s => s is SAV7b),
|
||||
new BoxManipSort(BoxManipType.SortShiny, list => list.OrderByCustom(pk => !pk.IsShiny)),
|
||||
new BoxManipSort(BoxManipType.SortRandom, list => list.OrderByCustom(_ => Util.Rand32())),
|
||||
};
|
||||
|
||||
public static readonly IReadOnlyList<BoxManipBase> SortAdvanced = new List<BoxManipBase>
|
||||
{
|
||||
new BoxManipSort(BoxManipType.SortUsage, PKMSorting.OrderByUsage, s => s.Generation >= 3),
|
||||
new BoxManipSort(BoxManipType.SortPotential, list => list.OrderByCustom(pk => (pk.MaxIV * 6) - pk.IVTotal)),
|
||||
new BoxManipSort(BoxManipType.SortTraining, list => list.OrderByCustom(pk => (pk.MaxEV * 6) - pk.EVTotal)),
|
||||
new BoxManipSortComplex(BoxManipType.SortOwner, (list, sav) => list.OrderByOwnership(sav)),
|
||||
new BoxManipSort(BoxManipType.SortType, list => list.OrderByCustom(pk => pk.PersonalInfo.Type1, pk => pk.PersonalInfo.Type2)),
|
||||
new BoxManipSort(BoxManipType.SortVersion, list => list.OrderByCustom(pk => pk.GenNumber, pk => pk.Version, pk => pk.Met_Location), s => s.Generation >= 3),
|
||||
new BoxManipSort(BoxManipType.SortBST, list => list.OrderByCustom(pk => pk.PersonalInfo.BST)),
|
||||
new BoxManipSort(BoxManipType.SortCP, list => list.OrderByCustom(pk => pk is PB7 pb7 ? pb7.Stat_CP : 0), s => s is SAV7b),
|
||||
new BoxManipSort(BoxManipType.SortLegal, list => list.OrderByCustom(pk => !new LegalityAnalysis(pk).Valid)),
|
||||
new BoxManipSort(BoxManipType.SortEncounterType, list => list.OrderByCustom(pk => new LegalityAnalysis(pk).Info?.EncounterMatch.GetEncounterTypeName() ?? string.Empty)),
|
||||
};
|
||||
|
||||
public static readonly IReadOnlyList<BoxManipBase> ClearCommon = new List<BoxManipBase>
|
||||
{
|
||||
new BoxManipClear(BoxManipType.DeleteAll, _ => true),
|
||||
new BoxManipClear(BoxManipType.DeleteEggs, pk => pk.IsEgg, s => s.Generation >= 2),
|
||||
new BoxManipClearComplex(BoxManipType.DeletePastGen, (pk, sav) => pk.GenNumber != sav.Generation, s => s.Generation >= 4),
|
||||
new BoxManipClearComplex(BoxManipType.DeleteForeign, (pk, sav) => !sav.IsOriginalHandler(pk, pk.Format > 2)),
|
||||
new BoxManipClear(BoxManipType.DeleteUntrained, pk => pk.EVTotal == 0),
|
||||
new BoxManipClear(BoxManipType.DeleteItemless, pk => pk.HeldItem == 0),
|
||||
new BoxManipClear(BoxManipType.DeleteIllegal, pk => !new LegalityAnalysis(pk).Valid),
|
||||
new BoxManipClearDuplicate<string>(BoxManipType.DeleteClones, pk => SearchUtil.GetCloneDetectMethod(CloneDetectionMethod.HashDetails)(pk)),
|
||||
};
|
||||
|
||||
public static readonly IReadOnlyList<BoxManipModify> ModifyCommon = new List<BoxManipModify>
|
||||
{
|
||||
new BoxManipModify(BoxManipType.ModifyHatchEggs, pk => pk.ForceHatchPKM(), s => s.Generation >= 2),
|
||||
new BoxManipModify(BoxManipType.ModifyMaxFriendship, pk => pk.MaximizeFriendship()),
|
||||
new BoxManipModify(BoxManipType.ModifyMaxLevel, pk => pk.MaximizeLevel()),
|
||||
new BoxManipModify(BoxManipType.ModifyResetMoves, pk => pk.SetMoves(pk.GetMoveSet()), s => s.Generation >= 3),
|
||||
new BoxManipModify(BoxManipType.ModifyRandomMoves, pk => pk.SetMoves(pk.GetMoveSet(true))),
|
||||
new BoxManipModify(BoxManipType.ModifyHyperTrain,pk => pk.SetSuggestedHyperTrainingData(), s => s.Generation >= 7),
|
||||
new BoxManipModify(BoxManipType.ModifyRemoveNicknames, pk => pk.SetDefaultNickname()),
|
||||
new BoxManipModify(BoxManipType.ModifyRemoveItem, pk => pk.HeldItem = 0, s => s.Generation >= 2),
|
||||
};
|
||||
}
|
||||
}
|
|
@ -1,78 +1,21 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using PKHeX.Core.Searching;
|
||||
|
||||
namespace PKHeX.Core
|
||||
{
|
||||
public class BoxManipClear : IBoxManip
|
||||
public sealed class BoxManipClear : BoxManipBase
|
||||
{
|
||||
public BoxManipType Type { get; protected set; }
|
||||
public Func<SaveFile, bool> Usable { get; set; }
|
||||
private readonly Func<PKM, bool> Criteria;
|
||||
public BoxManipClear(BoxManipType type, Func<PKM, bool> criteria) : this(type, criteria, _ => true) { }
|
||||
public BoxManipClear(BoxManipType type, Func<PKM, bool> criteria, Func<SaveFile, bool> usable) : base(type, usable) => Criteria = criteria;
|
||||
|
||||
public string GetPrompt(bool all) => all ? MessageStrings.MsgSaveBoxClearAll : MessageStrings.MsgSaveBoxClearCurrent;
|
||||
public string GetFail(bool all) => all ? MessageStrings.MsgSaveBoxClearAllFailBattle : MessageStrings.MsgSaveBoxClearCurrentFailBattle;
|
||||
public string GetSuccess(bool all) => all ? MessageStrings.MsgSaveBoxClearAllSuccess : MessageStrings.MsgSaveBoxClearCurrentSuccess;
|
||||
|
||||
protected Func<PKM, bool> CriteriaSimple { private get; set; }
|
||||
protected Func<PKM, SaveFile, bool> CriteriaSAV { private get; set; }
|
||||
|
||||
public virtual int Execute(SaveFile SAV, BoxManipParam param)
|
||||
{
|
||||
bool Method(PKM p) => param.Reverse ^ (CriteriaSAV?.Invoke(p, SAV) ?? CriteriaSimple?.Invoke(p) ?? true);
|
||||
return SAV.ClearBoxes(param.Start, param.Stop, Method);
|
||||
}
|
||||
|
||||
protected BoxManipClear() { }
|
||||
|
||||
private BoxManipClear(BoxManipType type, Func<PKM, bool> criteria, Func<SaveFile, bool> usable = null)
|
||||
{
|
||||
Type = type;
|
||||
CriteriaSimple = criteria;
|
||||
Usable = usable;
|
||||
}
|
||||
|
||||
private BoxManipClear(BoxManipType type, Func<PKM, SaveFile, bool> criteria, Func<SaveFile, bool> usable = null)
|
||||
{
|
||||
Type = type;
|
||||
CriteriaSAV = criteria;
|
||||
Usable = usable;
|
||||
}
|
||||
|
||||
public static readonly IReadOnlyList<BoxManipClear> Common = new List<BoxManipClear>
|
||||
{
|
||||
new BoxManipClear(BoxManipType.DeleteAll, _ => true),
|
||||
new BoxManipClear(BoxManipType.DeleteEggs, pk => pk.IsEgg, s => s.Generation >= 2),
|
||||
new BoxManipClear(BoxManipType.DeletePastGen, (pk, sav) => pk.GenNumber != sav.Generation, s => s.Generation >= 4),
|
||||
new BoxManipClear(BoxManipType.DeleteForeign, (pk, sav) => !sav.IsOriginalHandler(pk, pk.Format > 2)),
|
||||
new BoxManipClear(BoxManipType.DeleteUntrained, pk => pk.EVTotal == 0),
|
||||
new BoxManipClear(BoxManipType.DeleteItemless, pk => pk.HeldItem == 0),
|
||||
new BoxManipClear(BoxManipType.DeleteIllegal, pk => !new LegalityAnalysis(pk).Valid),
|
||||
new BoxManipClearDuplicate<string>(BoxManipType.DeleteClones, pk => SearchUtil.GetCloneDetectMethod(CloneDetectionMethod.HashDetails)(pk)),
|
||||
};
|
||||
}
|
||||
|
||||
public sealed class BoxManipClearDuplicate<T> : BoxManipClear
|
||||
{
|
||||
private readonly HashSet<T> HashSet = new HashSet<T>();
|
||||
public override string GetPrompt(bool all) => all ? MessageStrings.MsgSaveBoxClearAll : MessageStrings.MsgSaveBoxClearCurrent;
|
||||
public override string GetFail(bool all) => all ? MessageStrings.MsgSaveBoxClearAllFailBattle : MessageStrings.MsgSaveBoxClearCurrentFailBattle;
|
||||
public override string GetSuccess(bool all) => all ? MessageStrings.MsgSaveBoxClearAllSuccess : MessageStrings.MsgSaveBoxClearCurrentSuccess;
|
||||
|
||||
public override int Execute(SaveFile SAV, BoxManipParam param)
|
||||
{
|
||||
HashSet.Clear();
|
||||
return base.Execute(SAV, param);
|
||||
}
|
||||
|
||||
public BoxManipClearDuplicate(BoxManipType type, Func<PKM, T> criteria, Func<SaveFile, bool> usable = null)
|
||||
{
|
||||
Type = type;
|
||||
Usable = usable;
|
||||
CriteriaSimple = pk =>
|
||||
{
|
||||
var result = criteria(pk);
|
||||
if (HashSet.Contains(result))
|
||||
return true;
|
||||
HashSet.Add(result);
|
||||
return false;
|
||||
};
|
||||
bool Method(PKM p) => param.Reverse ^ Criteria(p);
|
||||
return SAV.ClearBoxes(param.Start, param.Stop, Method);
|
||||
}
|
||||
}
|
||||
}
|
21
PKHeX.Core/Editing/Saves/BoxManipClearComplex.cs
Normal file
21
PKHeX.Core/Editing/Saves/BoxManipClearComplex.cs
Normal file
|
@ -0,0 +1,21 @@
|
|||
using System;
|
||||
|
||||
namespace PKHeX.Core
|
||||
{
|
||||
public sealed class BoxManipClearComplex : BoxManipBase
|
||||
{
|
||||
private readonly Func<PKM, SaveFile, bool> Criteria;
|
||||
public BoxManipClearComplex(BoxManipType type, Func<PKM, SaveFile, bool> criteria) : this(type, criteria, _ => true) { }
|
||||
public BoxManipClearComplex(BoxManipType type, Func<PKM, SaveFile, bool> criteria, Func<SaveFile, bool> usable) : base(type, usable) => Criteria = criteria;
|
||||
|
||||
public override string GetPrompt(bool all) => all ? MessageStrings.MsgSaveBoxClearAll : MessageStrings.MsgSaveBoxClearCurrent;
|
||||
public override string GetFail(bool all) => all ? MessageStrings.MsgSaveBoxClearAllFailBattle : MessageStrings.MsgSaveBoxClearCurrentFailBattle;
|
||||
public override string GetSuccess(bool all) => all ? MessageStrings.MsgSaveBoxClearAllSuccess : MessageStrings.MsgSaveBoxClearCurrentSuccess;
|
||||
|
||||
public override int Execute(SaveFile SAV, BoxManipParam param)
|
||||
{
|
||||
bool Method(PKM p) => param.Reverse ^ Criteria(p, SAV);
|
||||
return SAV.ClearBoxes(param.Start, param.Stop, Method);
|
||||
}
|
||||
}
|
||||
}
|
35
PKHeX.Core/Editing/Saves/BoxManipClearDuplicate.cs
Normal file
35
PKHeX.Core/Editing/Saves/BoxManipClearDuplicate.cs
Normal file
|
@ -0,0 +1,35 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace PKHeX.Core
|
||||
{
|
||||
public sealed class BoxManipClearDuplicate<T> : BoxManipBase
|
||||
{
|
||||
private readonly HashSet<T> HashSet = new HashSet<T>();
|
||||
private readonly Func<PKM, bool> Criteria;
|
||||
public BoxManipClearDuplicate(BoxManipType type, Func<PKM, T> criteria) : this(type, criteria, _ => true) { }
|
||||
|
||||
public BoxManipClearDuplicate(BoxManipType type, Func<PKM, T> criteria, Func<SaveFile, bool> usable) : base(type, usable)
|
||||
{
|
||||
Criteria = pk =>
|
||||
{
|
||||
var result = criteria(pk);
|
||||
if (HashSet.Contains(result))
|
||||
return true;
|
||||
HashSet.Add(result);
|
||||
return false;
|
||||
};
|
||||
}
|
||||
|
||||
public override string GetPrompt(bool all) => all ? MessageStrings.MsgSaveBoxClearAll : MessageStrings.MsgSaveBoxClearCurrent;
|
||||
public override string GetFail(bool all) => all ? MessageStrings.MsgSaveBoxClearAllFailBattle : MessageStrings.MsgSaveBoxClearCurrentFailBattle;
|
||||
public override string GetSuccess(bool all) => all ? MessageStrings.MsgSaveBoxClearAllSuccess : MessageStrings.MsgSaveBoxClearCurrentSuccess;
|
||||
|
||||
public override int Execute(SaveFile SAV, BoxManipParam param)
|
||||
{
|
||||
HashSet.Clear();
|
||||
bool Method(PKM p) => param.Reverse ^ Criteria(p);
|
||||
return SAV.ClearBoxes(param.Start, param.Stop, Method);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,50 +1,17 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace PKHeX.Core
|
||||
{
|
||||
public sealed class BoxManipModify : IBoxManip
|
||||
public sealed class BoxManipModify : BoxManipBase
|
||||
{
|
||||
public BoxManipType Type { get; }
|
||||
public Func<SaveFile, bool> Usable { get; set; }
|
||||
|
||||
public string GetPrompt(bool all) => null;
|
||||
public string GetFail(bool all) => null;
|
||||
public string GetSuccess(bool all) => null;
|
||||
|
||||
private readonly Action<PKM> Action;
|
||||
private readonly Action<PKM, SaveFile> ActionComplex;
|
||||
public BoxManipModify(BoxManipType type, Action<PKM> action) : this(type, action, _ => true) { }
|
||||
public BoxManipModify(BoxManipType type, Action<PKM> action, Func<SaveFile, bool> usable) : base(type, usable) => Action = action;
|
||||
|
||||
public int Execute(SaveFile SAV, BoxManipParam param)
|
||||
{
|
||||
var method = Action ?? (px => ActionComplex(px, SAV));
|
||||
return SAV.ModifyBoxes(method, param.Start, param.Stop);
|
||||
}
|
||||
public override string GetPrompt(bool all) => string.Empty;
|
||||
public override string GetFail(bool all) => string.Empty;
|
||||
public override string GetSuccess(bool all) => string.Empty;
|
||||
|
||||
private BoxManipModify(BoxManipType type, Action<PKM> action, Func<SaveFile, bool> usable = null)
|
||||
{
|
||||
Type = type;
|
||||
Action = action;
|
||||
Usable = usable;
|
||||
}
|
||||
|
||||
private BoxManipModify(BoxManipType type, Action<PKM, SaveFile> action, Func<SaveFile, bool> usable = null)
|
||||
{
|
||||
Type = type;
|
||||
ActionComplex = action;
|
||||
Usable = usable;
|
||||
}
|
||||
|
||||
public static readonly IReadOnlyList<BoxManipModify> Common = new List<BoxManipModify>
|
||||
{
|
||||
new BoxManipModify(BoxManipType.ModifyHatchEggs, pk => pk.ForceHatchPKM(), s => s.Generation >= 2),
|
||||
new BoxManipModify(BoxManipType.ModifyMaxFriendship, pk => pk.MaximizeFriendship()),
|
||||
new BoxManipModify(BoxManipType.ModifyMaxLevel, pk => pk.MaximizeLevel()),
|
||||
new BoxManipModify(BoxManipType.ModifyResetMoves, pk => pk.SetMoves(pk.GetMoveSet()), s => s.Generation >= 3),
|
||||
new BoxManipModify(BoxManipType.ModifyRandomMoves, pk => pk.SetMoves(pk.GetMoveSet(true))),
|
||||
new BoxManipModify(BoxManipType.ModifyHyperTrain,pk => pk.SetSuggestedHyperTrainingData(), s => s.Generation >= 7),
|
||||
new BoxManipModify(BoxManipType.ModifyRemoveNicknames, pk => pk.SetDefaultNickname()),
|
||||
new BoxManipModify(BoxManipType.ModifyRemoveItem, pk => pk.HeldItem = 0, s => s.Generation >= 2),
|
||||
};
|
||||
public override int Execute(SaveFile SAV, BoxManipParam param) => SAV.ModifyBoxes(Action, param.Start, param.Stop);
|
||||
}
|
||||
}
|
17
PKHeX.Core/Editing/Saves/BoxManipModifyComplex.cs
Normal file
17
PKHeX.Core/Editing/Saves/BoxManipModifyComplex.cs
Normal file
|
@ -0,0 +1,17 @@
|
|||
using System;
|
||||
|
||||
namespace PKHeX.Core
|
||||
{
|
||||
public sealed class BoxManipModifyComplex : BoxManipBase
|
||||
{
|
||||
private readonly Action<PKM, SaveFile> Action;
|
||||
public BoxManipModifyComplex(BoxManipType type, Action<PKM, SaveFile> action) : this(type, action, _ => true) { }
|
||||
public BoxManipModifyComplex(BoxManipType type, Action<PKM, SaveFile> action, Func<SaveFile, bool> usable) : base(type, usable) => Action = action;
|
||||
|
||||
public override string GetPrompt(bool all) => string.Empty;
|
||||
public override string GetFail(bool all) => string.Empty;
|
||||
public override string GetSuccess(bool all) => string.Empty;
|
||||
|
||||
public override int Execute(SaveFile SAV, BoxManipParam param) => SAV.ModifyBoxes(pk => Action(pk, SAV), param.Start, param.Stop);
|
||||
}
|
||||
}
|
|
@ -3,64 +3,20 @@ using System.Collections.Generic;
|
|||
|
||||
namespace PKHeX.Core
|
||||
{
|
||||
public sealed class BoxManipSort : IBoxManip
|
||||
public sealed class BoxManipSort : BoxManipBase
|
||||
{
|
||||
public BoxManipType Type { get; }
|
||||
public Func<SaveFile, bool> Usable { get; set; }
|
||||
private readonly Func<IEnumerable<PKM>, IEnumerable<PKM>> Sorter;
|
||||
public BoxManipSort(BoxManipType type, Func<IEnumerable<PKM>, IEnumerable<PKM>> sorter) : this(type, sorter, _ => true) { }
|
||||
public BoxManipSort(BoxManipType type, Func<IEnumerable<PKM>, IEnumerable<PKM>> sorter, Func<SaveFile, bool> usable) : base(type, usable) => Sorter = sorter;
|
||||
|
||||
public string GetPrompt(bool all) => all ? MessageStrings.MsgSaveBoxSortAll : MessageStrings.MsgSaveBoxSortCurrent;
|
||||
public string GetFail(bool all) => all ? MessageStrings.MsgSaveBoxSortAllFailBattle: MessageStrings.MsgSaveBoxSortCurrentFailBattle;
|
||||
public string GetSuccess(bool all) => all ? MessageStrings.MsgSaveBoxSortAllSuccess : MessageStrings.MsgSaveBoxSortCurrentSuccess;
|
||||
public override string GetPrompt(bool all) => all ? MessageStrings.MsgSaveBoxSortAll : MessageStrings.MsgSaveBoxSortCurrent;
|
||||
public override string GetFail(bool all) => all ? MessageStrings.MsgSaveBoxSortAllFailBattle: MessageStrings.MsgSaveBoxSortCurrentFailBattle;
|
||||
public override string GetSuccess(bool all) => all ? MessageStrings.MsgSaveBoxSortAllSuccess : MessageStrings.MsgSaveBoxSortCurrentSuccess;
|
||||
|
||||
private readonly Func<IEnumerable<PKM>, IEnumerable<PKM>> SorterSimple;
|
||||
private readonly Func<IEnumerable<PKM>, SaveFile, IEnumerable<PKM>> SorterComplex;
|
||||
|
||||
public int Execute(SaveFile SAV, BoxManipParam param)
|
||||
public override int Execute(SaveFile SAV, BoxManipParam param)
|
||||
{
|
||||
IEnumerable<PKM> Method(IEnumerable<PKM> p) => SorterSimple != null ? SorterSimple(p) : SorterComplex(p, SAV);
|
||||
IEnumerable<PKM> Method(IEnumerable<PKM> p) => Sorter(p);
|
||||
return SAV.SortBoxes(param.Start, param.Stop, Method, param.Reverse);
|
||||
}
|
||||
|
||||
private BoxManipSort(BoxManipType type, Func<IEnumerable<PKM>, IEnumerable<PKM>> sorter, Func<SaveFile, bool> usable = null)
|
||||
{
|
||||
Type = type;
|
||||
SorterSimple = sorter;
|
||||
Usable = usable;
|
||||
}
|
||||
|
||||
private BoxManipSort(BoxManipType type, Func<IEnumerable<PKM>, SaveFile, IEnumerable<PKM>> sorter, Func<SaveFile, bool> usable = null)
|
||||
{
|
||||
Type = type;
|
||||
SorterComplex = sorter;
|
||||
Usable = usable;
|
||||
}
|
||||
|
||||
public static readonly IReadOnlyList<BoxManipSort> Common = new List<BoxManipSort>
|
||||
{
|
||||
new BoxManipSort(BoxManipType.SortSpecies, PKMSorting.OrderBySpecies),
|
||||
new BoxManipSort(BoxManipType.SortSpeciesReverse, PKMSorting.OrderByDescendingSpecies),
|
||||
new BoxManipSort(BoxManipType.SortLevel, PKMSorting.OrderByLevel),
|
||||
new BoxManipSort(BoxManipType.SortLevelReverse, PKMSorting.OrderByDescendingLevel),
|
||||
new BoxManipSort(BoxManipType.SortDate, PKMSorting.OrderByDateObtained, s => s.Generation >= 4),
|
||||
new BoxManipSort(BoxManipType.SortName, list => list.OrderBySpeciesName(GameInfo.Strings.Species)),
|
||||
new BoxManipSort(BoxManipType.SortFavorite, list => list.OrderByCustom(pk => !(pk as PB7)?.Favorite), s => s is SAV7b),
|
||||
new BoxManipSort(BoxManipType.SortParty, (list, sav) => list.OrderByCustom(pk => ((SAV7b)sav).Storage.GetPartyIndex(pk.Box - 1, pk.Slot - 1)), s => s is SAV7b),
|
||||
new BoxManipSort(BoxManipType.SortShiny, list => list.OrderByCustom(pk => !pk.IsShiny)),
|
||||
new BoxManipSort(BoxManipType.SortRandom, list => list.OrderByCustom(_ => Util.Rand32())),
|
||||
};
|
||||
|
||||
public static readonly IReadOnlyList<BoxManipSort> Advanced = new List<BoxManipSort>
|
||||
{
|
||||
new BoxManipSort(BoxManipType.SortUsage, PKMSorting.OrderByUsage, s => s.Generation >= 3),
|
||||
new BoxManipSort(BoxManipType.SortPotential, list => list.OrderByCustom(pk => (pk.MaxIV * 6) - pk.IVTotal)),
|
||||
new BoxManipSort(BoxManipType.SortTraining, list => list.OrderByCustom(pk => (pk.MaxEV * 6) - pk.EVTotal)),
|
||||
new BoxManipSort(BoxManipType.SortOwner, (list, sav) => list.OrderByOwnership(sav)),
|
||||
new BoxManipSort(BoxManipType.SortType, list => list.OrderByCustom(pk => pk.PersonalInfo.Type1, pk => pk.PersonalInfo.Type2)),
|
||||
new BoxManipSort(BoxManipType.SortVersion, list => list.OrderByCustom(pk => pk.GenNumber, pk => pk.Version, pk => pk.Met_Location), s => s.Generation >= 3),
|
||||
new BoxManipSort(BoxManipType.SortBST, list => list.OrderByCustom(pk => pk.PersonalInfo.BST)),
|
||||
new BoxManipSort(BoxManipType.SortCP, list => list.OrderByCustom(pk => (pk as PB7)?.Stat_CP), s => s is SAV7b),
|
||||
new BoxManipSort(BoxManipType.SortLegal, list => list.OrderByCustom(pk => !new LegalityAnalysis(pk).Valid)),
|
||||
new BoxManipSort(BoxManipType.SortEncounterType, list => list.OrderByCustom(pk => new LegalityAnalysis(pk).Info?.EncounterMatch.GetEncounterTypeName())),
|
||||
};
|
||||
}
|
||||
}
|
22
PKHeX.Core/Editing/Saves/BoxManipSortComplex.cs
Normal file
22
PKHeX.Core/Editing/Saves/BoxManipSortComplex.cs
Normal file
|
@ -0,0 +1,22 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace PKHeX.Core
|
||||
{
|
||||
public sealed class BoxManipSortComplex : BoxManipBase
|
||||
{
|
||||
private readonly Func<IEnumerable<PKM>, SaveFile, IEnumerable<PKM>> Sorter;
|
||||
public BoxManipSortComplex(BoxManipType type, Func<IEnumerable<PKM>, SaveFile, IEnumerable<PKM>> sorter) : this(type, sorter, _ => true) { }
|
||||
public BoxManipSortComplex(BoxManipType type, Func<IEnumerable<PKM>, SaveFile, IEnumerable<PKM>> sorter, Func<SaveFile, bool> usable) : base(type, usable) => Sorter = sorter;
|
||||
|
||||
public override string GetPrompt(bool all) => all ? MessageStrings.MsgSaveBoxSortAll : MessageStrings.MsgSaveBoxSortCurrent;
|
||||
public override string GetFail(bool all) => all ? MessageStrings.MsgSaveBoxSortAllFailBattle : MessageStrings.MsgSaveBoxSortCurrentFailBattle;
|
||||
public override string GetSuccess(bool all) => all ? MessageStrings.MsgSaveBoxSortAllSuccess : MessageStrings.MsgSaveBoxSortCurrentSuccess;
|
||||
|
||||
public override int Execute(SaveFile SAV, BoxManipParam param)
|
||||
{
|
||||
IEnumerable<PKM> Method(IEnumerable<PKM> p) => Sorter(p, SAV);
|
||||
return SAV.SortBoxes(param.Start, param.Stop, Method, param.Reverse);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -10,10 +10,10 @@ namespace PKHeX.Core
|
|||
/// </summary>
|
||||
public static readonly IReadOnlyList<IBoxManip>[] ManipCategories =
|
||||
{
|
||||
BoxManipClear.Common,
|
||||
BoxManipSort.Common,
|
||||
BoxManipSort.Advanced,
|
||||
BoxManipModify.Common,
|
||||
BoxManipBase.ClearCommon,
|
||||
BoxManipBase.SortCommon,
|
||||
BoxManipBase.SortAdvanced,
|
||||
BoxManipBase.ModifyCommon,
|
||||
};
|
||||
|
||||
public static readonly string[] ManipCategoryNames =
|
||||
|
@ -36,7 +36,7 @@ namespace PKHeX.Core
|
|||
/// </summary>
|
||||
/// <param name="type">Manipulation type.</param>
|
||||
/// <returns>Category Name</returns>
|
||||
public static string GetManipCategoryName(this BoxManipType type)
|
||||
public static string? GetManipCategoryName(this BoxManipType type)
|
||||
{
|
||||
for (int i = 0; i < ManipCategories.Length; i++)
|
||||
{
|
||||
|
@ -51,7 +51,7 @@ namespace PKHeX.Core
|
|||
/// </summary>
|
||||
/// <param name="manip">Manipulation type.</param>
|
||||
/// <returns>Category Name</returns>
|
||||
public static string GetManipCategoryName(this IBoxManip manip)
|
||||
public static string? GetManipCategoryName(this IBoxManip manip)
|
||||
{
|
||||
for (int i = 0; i < ManipCategories.Length; i++)
|
||||
{
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
/// <returns>True if operation succeeded, false if no changes made.</returns>
|
||||
public bool Execute(IBoxManip manip, int box, bool allBoxes, bool reverse = false)
|
||||
{
|
||||
bool usable = manip.Usable?.Invoke(SAV) ?? true;
|
||||
bool usable = manip.Usable.Invoke(SAV);
|
||||
if (!usable)
|
||||
return false;
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ namespace PKHeX.Core
|
|||
/// Event number storage for more complex logic events.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
public sealed class EventWork<T> : EventVar
|
||||
public sealed class EventWork<T> : EventVar where T : struct
|
||||
{
|
||||
public T Value;
|
||||
public readonly IList<EventWorkVal> Options = new List<EventWorkVal> { new EventWorkVal() };
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using static PKHeX.Core.MessageStrings;
|
||||
|
@ -10,7 +11,7 @@ namespace PKHeX.Core
|
|||
/// </summary>
|
||||
public class EventBlockDiff
|
||||
{
|
||||
public string Message { get; private set; }
|
||||
public string Message { get; protected set; } = string.Empty;
|
||||
public readonly List<int> SetFlags = new List<int>();
|
||||
public readonly List<int> ClearedFlags = new List<int>();
|
||||
public readonly List<string> WorkDiff = new List<string>();
|
||||
|
@ -24,6 +25,11 @@ namespace PKHeX.Core
|
|||
return;
|
||||
var s1 = SaveUtil.GetVariantSAV(f1);
|
||||
var s2 = SaveUtil.GetVariantSAV(f2);
|
||||
if (s1 == null || s2 == null || s1.GetType() != s2.GetType())
|
||||
{
|
||||
Message = MsgSaveDifferentTypes;
|
||||
return;
|
||||
}
|
||||
Diff(s1, s2);
|
||||
}
|
||||
|
||||
|
@ -83,7 +89,7 @@ namespace PKHeX.Core
|
|||
public sealed class EventWorkDiff7b : EventBlockDiff
|
||||
{
|
||||
public readonly List<int> WorkChanged = new List<int>();
|
||||
private SaveFile S1;
|
||||
private SaveFile? S1;
|
||||
|
||||
public EventWorkDiff7b(string f1, string f2)
|
||||
{
|
||||
|
@ -91,6 +97,11 @@ namespace PKHeX.Core
|
|||
return;
|
||||
var s1 = SaveUtil.GetVariantSAV(f1);
|
||||
var s2 = SaveUtil.GetVariantSAV(f2);
|
||||
if (s1 == null || s2 == null || s1.GetType() != s2.GetType())
|
||||
{
|
||||
Message = MsgSaveDifferentTypes;
|
||||
return;
|
||||
}
|
||||
Diff(s1, s2);
|
||||
}
|
||||
|
||||
|
@ -101,14 +112,16 @@ namespace PKHeX.Core
|
|||
if (!SanityCheckSaveInfo(s1, s2))
|
||||
return;
|
||||
|
||||
EventWorkUtil.DiffSavesFlag(((SAV7b)s1).EventWork, ((SAV7b)s2).EventWork, SetFlags, ClearedFlags);
|
||||
EventWorkUtil.DiffSavesWork(((SAV7b)s1).EventWork, ((SAV7b)s2).EventWork, WorkChanged, WorkDiff);
|
||||
EventWorkUtil.DiffSavesFlag(((SAV7b)s1).Blocks.EventWork, ((SAV7b)s2).Blocks.EventWork, SetFlags, ClearedFlags);
|
||||
EventWorkUtil.DiffSavesWork(((SAV7b)s1).Blocks.EventWork, ((SAV7b)s2).Blocks.EventWork, WorkChanged, WorkDiff);
|
||||
S1 = s1;
|
||||
}
|
||||
|
||||
public List<string> Summarize()
|
||||
public IReadOnlyList<string> Summarize()
|
||||
{
|
||||
var ew = ((SAV7b)S1).EventWork;
|
||||
if (S1 == null)
|
||||
return Array.Empty<string>();
|
||||
var ew = ((SAV7b)S1).Blocks.EventWork;
|
||||
|
||||
var fOn = SetFlags.Select(z => new { Type = ew.GetFlagType(z, out var subIndex), Index = subIndex, Raw = z })
|
||||
.Select(z => $"{z.Raw:0000}\t{true }\t{z.Index:0000}\t{z.Type}").ToArray();
|
||||
|
|
|
@ -103,7 +103,7 @@ namespace PKHeX.Core
|
|||
{
|
||||
var b = before.GetWork(i);
|
||||
var a = after.GetWork(i);
|
||||
if (b.Equals(a))
|
||||
if (b is null || b.Equals(a))
|
||||
continue;
|
||||
|
||||
changed.Add(i);
|
||||
|
|
|
@ -7,7 +7,7 @@ namespace PKHeX.Core
|
|||
/// Editor object that unpacks <see cref="EventWork{T}"/> into flags & work groups, and handles value get/set operations.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
public sealed class SplitEventEditor<T>
|
||||
public sealed class SplitEventEditor<T> where T : struct
|
||||
{
|
||||
public readonly IList<EventVarGroup> Work;
|
||||
public readonly IList<EventVarGroup> Flag;
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
namespace PKHeX.Core
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace PKHeX.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Environment for editing a <see cref="SaveFile"/>
|
||||
|
@ -8,13 +11,77 @@
|
|||
{
|
||||
public readonly SaveFile SAV;
|
||||
public readonly SlotEditor<T> Slots;
|
||||
public readonly IPKMView PKMEditor;
|
||||
|
||||
public IPKMView PKMEditor { get; set; }
|
||||
public SaveDataEditor() : this(FakeSaveFile.Default) { }
|
||||
|
||||
public SaveDataEditor(SaveFile sav)
|
||||
{
|
||||
SAV = sav;
|
||||
Slots = new SlotEditor<T>(sav);
|
||||
PKMEditor = new FakePKMEditor(SAV.BlankPKM);
|
||||
}
|
||||
|
||||
public SaveDataEditor(SaveFile sav, IPKMView editor)
|
||||
{
|
||||
SAV = sav;
|
||||
Slots = new SlotEditor<T>(sav);
|
||||
PKMEditor = editor;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fakes the <see cref="IPKMView"/> interface interactions.
|
||||
/// </summary>
|
||||
public sealed class FakePKMEditor : IPKMView
|
||||
{
|
||||
public FakePKMEditor(PKM template) => Data = template;
|
||||
|
||||
public PKM Data { get; private set; }
|
||||
public bool Unicode => true;
|
||||
public bool HaX => false;
|
||||
public bool ChangingFields { get; set; }
|
||||
public bool EditsComplete => true;
|
||||
|
||||
public PKM PreparePKM(bool click = true) => Data;
|
||||
public void PopulateFields(PKM pk, bool focus = true, bool skipConversionCheck = false) => Data = pk;
|
||||
}
|
||||
|
||||
public sealed class FakeSaveFile : SaveFile
|
||||
{
|
||||
public static readonly FakeSaveFile Default = new FakeSaveFile();
|
||||
protected override string BAKText => "Fake Save File";
|
||||
public override SaveFile Clone() => this;
|
||||
public override string Filter => string.Empty;
|
||||
public override string Extension => string.Empty;
|
||||
public override bool ChecksumsValid => true;
|
||||
public override string ChecksumInfo => string.Empty;
|
||||
public override int Generation => PKX.Generation;
|
||||
public override string GetString(byte[] data, int offset, int length) => string.Empty;
|
||||
public override byte[] SetString(string value, int maxLength, int PadToSize = 0, ushort PadWith = 0) => Array.Empty<byte>();
|
||||
public override PersonalTable Personal => PKX.Personal;
|
||||
public override int MaxEV => 0;
|
||||
public override IReadOnlyList<ushort> HeldItems => Legal.HeldItems_GG;
|
||||
public override int GetBoxOffset(int box) => -1;
|
||||
public override string GetBoxName(int box) => $"Box {box:00}";
|
||||
public override void SetBoxName(int box, string value) { }
|
||||
public override int OTLength => 5;
|
||||
public override int NickLength => 5;
|
||||
public override int MaxMoveID => 5;
|
||||
public override int MaxSpeciesID => 1;
|
||||
public override int MaxItemID => 5;
|
||||
public override int MaxBallID => 5;
|
||||
public override int MaxGameID => 5;
|
||||
public override int MaxAbilityID => 0;
|
||||
public override int BoxCount => 1;
|
||||
public override int GetPartyOffset(int slot) => -1;
|
||||
protected override void SetChecksums() { }
|
||||
|
||||
public override Type PKMType => typeof(PKM);
|
||||
protected override PKM GetPKM(byte[] data) => BlankPKM;
|
||||
protected override byte[] DecryptPKM(byte[] data) => data;
|
||||
public override PKM BlankPKM => new PK7();
|
||||
public override int SIZE_STORED => 0;
|
||||
protected override int SIZE_PARTY => 0;
|
||||
}
|
||||
}
|
|
@ -5,7 +5,7 @@ namespace PKHeX.Core
|
|||
public interface IBoxManip
|
||||
{
|
||||
BoxManipType Type { get; }
|
||||
Func<SaveFile, bool> Usable { get; set; }
|
||||
Func<SaveFile, bool> Usable { get; }
|
||||
|
||||
string GetPrompt(bool all);
|
||||
string GetFail(bool all);
|
||||
|
|
|
@ -119,7 +119,7 @@ namespace PKHeX.Core
|
|||
{
|
||||
var list = new List<SlotInfoMisc>
|
||||
{
|
||||
new SlotInfoMisc(0, sav.GTS) {Type = StorageSlotType.GTS},
|
||||
new SlotInfoMisc(0, sav.AllBlocks[07].Offset) {Type = StorageSlotType.GTS},
|
||||
new SlotInfoMisc(0, sav.GetFusedSlotOffset(0)) {Type = StorageSlotType.Fused}
|
||||
};
|
||||
if (sav is SAV7USUM)
|
||||
|
|
|
@ -24,9 +24,6 @@ namespace PKHeX.Core
|
|||
|
||||
public ISlotInfo Undo()
|
||||
{
|
||||
if (!CanUndo)
|
||||
return null;
|
||||
|
||||
var change = UndoStack.Pop();
|
||||
var revert = GetReversion(change.Info, SAV);
|
||||
AddRedo(revert);
|
||||
|
@ -36,9 +33,6 @@ namespace PKHeX.Core
|
|||
|
||||
public ISlotInfo Redo()
|
||||
{
|
||||
if (!CanRedo)
|
||||
return null;
|
||||
|
||||
var change = RedoStack.Pop();
|
||||
var revert = GetReversion(change.Info, SAV);
|
||||
AddUndo(revert);
|
||||
|
|
|
@ -100,12 +100,16 @@
|
|||
|
||||
public void Undo()
|
||||
{
|
||||
if (!Changelog.CanUndo)
|
||||
return;
|
||||
var slot = Changelog.Undo();
|
||||
NotifySlotChanged(slot, SlotTouchType.Set, slot.Read(SAV));
|
||||
}
|
||||
|
||||
public void Redo()
|
||||
{
|
||||
if (!Changelog.CanRedo)
|
||||
return;
|
||||
var slot = Changelog.Redo();
|
||||
NotifySlotChanged(slot, SlotTouchType.Set, slot.Read(SAV));
|
||||
}
|
||||
|
|
|
@ -12,9 +12,9 @@ namespace PKHeX.Core
|
|||
/// </summary>
|
||||
public List<ISlotViewer<T>> Subscribers { get; } = new List<ISlotViewer<T>>();
|
||||
|
||||
public ISlotInfo Previous { get; private set; }
|
||||
public ISlotInfo? Previous { get; private set; }
|
||||
public SlotTouchType PreviousType { get; private set; } = SlotTouchType.None;
|
||||
public PKM PreviousPKM { get; private set; }
|
||||
public PKM? PreviousPKM { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Notifies all <see cref="Subscribers"/> with the latest slot change details.
|
||||
|
@ -33,13 +33,18 @@ namespace PKHeX.Core
|
|||
|
||||
private void ResetView(ISlotViewer<T> sub, ISlotInfo slot, SlotTouchType type, PKM pkm)
|
||||
{
|
||||
if (PreviousPKM != null)
|
||||
if (Previous != null)
|
||||
sub.NotifySlotOld(Previous);
|
||||
|
||||
if (!(slot is SlotInfoBox b) || sub.ViewIndex == b.Box)
|
||||
sub.NotifySlotChanged(slot, type, pkm);
|
||||
}
|
||||
|
||||
public void ResetView(ISlotViewer<T> sub) => ResetView(sub, Previous, PreviousType, PreviousPKM);
|
||||
public void ResetView(ISlotViewer<T> sub)
|
||||
{
|
||||
if (Previous == null || PreviousPKM == null)
|
||||
return;
|
||||
ResetView(sub, Previous, PreviousType, PreviousPKM);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,11 +6,17 @@ namespace PKHeX.Core
|
|||
/// <typeparam name="T"></typeparam>
|
||||
public sealed class SlotViewInfo<T>
|
||||
{
|
||||
public ISlotInfo Slot;
|
||||
public ISlotViewer<T> View;
|
||||
public readonly ISlotInfo Slot;
|
||||
public readonly ISlotViewer<T> View;
|
||||
|
||||
public PKM ReadCurrent() => Slot.Read(View.SAV);
|
||||
public bool CanWriteTo() => Slot.CanWriteTo(View.SAV);
|
||||
public WriteBlockedMessage CanWriteTo(PKM pkm) => Slot.CanWriteTo(View.SAV, pkm);
|
||||
|
||||
public SlotViewInfo(ISlotInfo slot, ISlotViewer<T> view)
|
||||
{
|
||||
Slot = slot;
|
||||
View = view;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -257,7 +257,7 @@ namespace PKHeX.Core
|
|||
return GetText(strings);
|
||||
}
|
||||
|
||||
private string GetText(GameStrings strings = null)
|
||||
private string GetText(GameStrings? strings = null)
|
||||
{
|
||||
if (Species <= 0 || Species > MAX_SPECIES)
|
||||
return string.Empty;
|
||||
|
|
|
@ -30,7 +30,17 @@ namespace PKHeX.Core
|
|||
LegalMoveDataSource = HaXMoveDataSource.Where(m => !Legal.Z_Moves.Contains(m.Value)).ToList();
|
||||
|
||||
VersionDataSource = GetVersionList(s);
|
||||
InitializeMetSources();
|
||||
|
||||
MetGen2 = CreateGen2(s);
|
||||
MetGen3 = CreateGen3(s);
|
||||
MetGen3CXD = CreateGen3CXD(s);
|
||||
MetGen4 = CreateGen4(s);
|
||||
MetGen5 = CreateGen5(s);
|
||||
MetGen6 = CreateGen6(s);
|
||||
MetGen7 = CreateGen7(s);
|
||||
MetGen7GG = CreateGen7GG(s);
|
||||
MetGen8 = CreateGen8(s);
|
||||
|
||||
Memories = new MemoryStrings(s);
|
||||
}
|
||||
|
||||
|
@ -46,17 +56,17 @@ namespace PKHeX.Core
|
|||
public readonly IReadOnlyList<ComboItem> HaXMoveDataSource;
|
||||
public readonly IReadOnlyList<ComboItem> EncounterTypeDataSource;
|
||||
|
||||
private IReadOnlyList<ComboItem> MetGen2 { get; set; }
|
||||
private IReadOnlyList<ComboItem> MetGen3 { get; set; }
|
||||
private IReadOnlyList<ComboItem> MetGen3CXD { get; set; }
|
||||
private IReadOnlyList<ComboItem> MetGen4 { get; set; }
|
||||
private IReadOnlyList<ComboItem> MetGen5 { get; set; }
|
||||
private IReadOnlyList<ComboItem> MetGen6 { get; set; }
|
||||
private IReadOnlyList<ComboItem> MetGen7 { get; set; }
|
||||
private IReadOnlyList<ComboItem> MetGen7GG { get; set; }
|
||||
private IReadOnlyList<ComboItem> MetGen8 { get; set; }
|
||||
private readonly IReadOnlyList<ComboItem> MetGen2;
|
||||
private readonly IReadOnlyList<ComboItem> MetGen3;
|
||||
private readonly IReadOnlyList<ComboItem> MetGen3CXD;
|
||||
private readonly IReadOnlyList<ComboItem> MetGen4;
|
||||
private readonly IReadOnlyList<ComboItem> MetGen5;
|
||||
private readonly IReadOnlyList<ComboItem> MetGen6;
|
||||
private readonly IReadOnlyList<ComboItem> MetGen7;
|
||||
private readonly IReadOnlyList<ComboItem> MetGen7GG;
|
||||
private readonly IReadOnlyList<ComboItem> MetGen8;
|
||||
|
||||
private IReadOnlyList<ComboItem> GetVersionList(GameStrings s)
|
||||
private static IReadOnlyList<ComboItem> GetVersionList(GameStrings s)
|
||||
{
|
||||
var list = s.gamelist;
|
||||
var ver = Util.GetCBList(list,
|
||||
|
@ -72,95 +82,102 @@ namespace PKHeX.Core
|
|||
return ver;
|
||||
}
|
||||
|
||||
private void InitializeMetSources()
|
||||
private List<ComboItem> CreateGen2(GameStrings s)
|
||||
{
|
||||
var s = Source;
|
||||
// Gen 2
|
||||
{
|
||||
var met_list = Util.GetCBList(s.metGSC_00000, Enumerable.Range(0, 0x5F).ToArray());
|
||||
Util.AddCBWithOffset(met_list, s.metGSC_00000, 00000, 0x7E, 0x7F);
|
||||
MetGen2 = met_list;
|
||||
}
|
||||
// Gen 3
|
||||
{
|
||||
var met_list = Util.GetCBList(s.metRSEFRLG_00000, Enumerable.Range(0, 213).ToArray());
|
||||
Util.AddCBWithOffset(met_list, s.metRSEFRLG_00000, 00000, 253, 254, 255);
|
||||
MetGen3 = met_list;
|
||||
|
||||
MetGen3CXD = Util.GetCBList(s.metCXD_00000, Enumerable.Range(0, s.metCXD_00000.Length).ToArray()).Where(c => c.Text.Length > 0).ToList();
|
||||
}
|
||||
// Gen 4
|
||||
{
|
||||
var met_list = Util.GetCBList(s.metHGSS_00000, 0);
|
||||
Util.AddCBWithOffset(met_list, s.metHGSS_02000, 2000, Locations.Daycare4);
|
||||
Util.AddCBWithOffset(met_list, s.metHGSS_02000, 2000, Locations.LinkTrade4);
|
||||
Util.AddCBWithOffset(met_list, s.metHGSS_03000, 3000, Locations.Ranger4);
|
||||
Util.AddCBWithOffset(met_list, s.metHGSS_00000, 0000, Legal.Met_HGSS_0);
|
||||
Util.AddCBWithOffset(met_list, s.metHGSS_02000, 2000, Legal.Met_HGSS_2);
|
||||
Util.AddCBWithOffset(met_list, s.metHGSS_03000, 3000, Legal.Met_HGSS_3);
|
||||
MetGen4 = met_list;
|
||||
}
|
||||
// Gen 5
|
||||
{
|
||||
var met_list = Util.GetCBList(s.metBW2_00000, 0);
|
||||
Util.AddCBWithOffset(met_list, s.metBW2_60000, 60001, Locations.Daycare5);
|
||||
Util.AddCBWithOffset(met_list, s.metBW2_30000, 30001, Locations.LinkTrade5);
|
||||
Util.AddCBWithOffset(met_list, s.metBW2_00000, 00000, Legal.Met_BW2_0);
|
||||
Util.AddCBWithOffset(met_list, s.metBW2_30000, 30001, Legal.Met_BW2_3);
|
||||
Util.AddCBWithOffset(met_list, s.metBW2_40000, 40001, Legal.Met_BW2_4);
|
||||
Util.AddCBWithOffset(met_list, s.metBW2_60000, 60001, Legal.Met_BW2_6);
|
||||
MetGen5 = met_list;
|
||||
}
|
||||
// Gen 6
|
||||
{
|
||||
var met_list = Util.GetCBList(s.metXY_00000, 0);
|
||||
Util.AddCBWithOffset(met_list, s.metXY_60000, 60001, Locations.Daycare5);
|
||||
Util.AddCBWithOffset(met_list, s.metXY_30000, 30001, Locations.LinkTrade6);
|
||||
Util.AddCBWithOffset(met_list, s.metXY_00000, 00000, Legal.Met_XY_0);
|
||||
Util.AddCBWithOffset(met_list, s.metXY_30000, 30001, Legal.Met_XY_3);
|
||||
Util.AddCBWithOffset(met_list, s.metXY_40000, 40001, Legal.Met_XY_4);
|
||||
Util.AddCBWithOffset(met_list, s.metXY_60000, 60001, Legal.Met_XY_6);
|
||||
MetGen6 = met_list;
|
||||
}
|
||||
// Gen 7
|
||||
{
|
||||
var met_list = Util.GetCBList(s.metSM_00000, 0);
|
||||
Util.AddCBWithOffset(met_list, s.metSM_60000, 60001, Locations.Daycare5);
|
||||
Util.AddCBWithOffset(met_list, s.metSM_30000, 30001, Locations.LinkTrade6);
|
||||
Util.AddCBWithOffset(met_list, s.metSM_00000, 00000, Legal.Met_SM_0);
|
||||
Util.AddCBWithOffset(met_list, s.metSM_30000, 30001, Legal.Met_SM_3);
|
||||
Util.AddCBWithOffset(met_list, s.metSM_40000, 40001, Legal.Met_SM_4);
|
||||
Util.AddCBWithOffset(met_list, s.metSM_60000, 60001, Legal.Met_SM_6);
|
||||
MetGen7 = met_list;
|
||||
}
|
||||
// Gen 7 GG
|
||||
{
|
||||
var met_list = Util.GetCBList(s.metGG_00000, 0);
|
||||
Util.AddCBWithOffset(met_list, s.metGG_60000, 60001, 60002);
|
||||
Util.AddCBWithOffset(met_list, s.metGG_30000, 30001, Locations.LinkTrade6);
|
||||
Util.AddCBWithOffset(met_list, s.metGG_00000, 00000, Legal.Met_GG_0);
|
||||
Util.AddCBWithOffset(met_list, s.metGG_30000, 30001, Legal.Met_GG_3);
|
||||
Util.AddCBWithOffset(met_list, s.metGG_40000, 40001, Legal.Met_GG_4);
|
||||
Util.AddCBWithOffset(met_list, s.metGG_60000, 60001, Legal.Met_GG_6);
|
||||
MetGen7GG = met_list;
|
||||
}
|
||||
// Gen 8
|
||||
{
|
||||
var met_list = Util.GetCBList(s.metSWSH_00000, 0);
|
||||
Util.AddCBWithOffset(met_list, s.metSWSH_60000, 60001, 60002);
|
||||
Util.AddCBWithOffset(met_list, s.metSWSH_30000, 30001, Locations.LinkTrade6);
|
||||
Util.AddCBWithOffset(met_list, s.metSWSH_00000, 00000, Legal.Met_SWSH_0);
|
||||
Util.AddCBWithOffset(met_list, s.metSWSH_30000, 30001, Legal.Met_SWSH_3);
|
||||
Util.AddCBWithOffset(met_list, s.metSWSH_40000, 40001, Legal.Met_SWSH_4);
|
||||
Util.AddCBWithOffset(met_list, s.metSWSH_60000, 60001, Legal.Met_SWSH_6);
|
||||
MetGen8 = met_list;
|
||||
}
|
||||
var met_list = Util.GetCBList(s.metGSC_00000, Enumerable.Range(0, 0x5F).ToArray());
|
||||
Util.AddCBWithOffset(met_list, s.metGSC_00000, 00000, 0x7E, 0x7F);
|
||||
return met_list;
|
||||
}
|
||||
|
||||
public IReadOnlyList<ComboItem> GetItemDataSource(GameVersion game, int generation, int MaxItemID, IEnumerable<ushort> allowed = null, bool HaX = false)
|
||||
private List<ComboItem> CreateGen3(GameStrings s)
|
||||
{
|
||||
var met_list = Util.GetCBList(s.metRSEFRLG_00000, Enumerable.Range(0, 213).ToArray());
|
||||
Util.AddCBWithOffset(met_list, s.metRSEFRLG_00000, 00000, 253, 254, 255);
|
||||
return met_list;
|
||||
}
|
||||
|
||||
|
||||
private static List<ComboItem> CreateGen3CXD(GameStrings s)
|
||||
{
|
||||
return Util.GetCBList(s.metCXD_00000, Enumerable.Range(0, s.metCXD_00000.Length).ToArray()).Where(c => c.Text.Length > 0).ToList();
|
||||
}
|
||||
|
||||
private static List<ComboItem> CreateGen4(GameStrings s)
|
||||
{
|
||||
var met_list = Util.GetCBList(s.metHGSS_00000, 0);
|
||||
Util.AddCBWithOffset(met_list, s.metHGSS_02000, 2000, Locations.Daycare4);
|
||||
Util.AddCBWithOffset(met_list, s.metHGSS_02000, 2000, Locations.LinkTrade4);
|
||||
Util.AddCBWithOffset(met_list, s.metHGSS_03000, 3000, Locations.Ranger4);
|
||||
Util.AddCBWithOffset(met_list, s.metHGSS_00000, 0000, Legal.Met_HGSS_0);
|
||||
Util.AddCBWithOffset(met_list, s.metHGSS_02000, 2000, Legal.Met_HGSS_2);
|
||||
Util.AddCBWithOffset(met_list, s.metHGSS_03000, 3000, Legal.Met_HGSS_3);
|
||||
return met_list;
|
||||
}
|
||||
private static List<ComboItem> CreateGen5(GameStrings s)
|
||||
{
|
||||
var met_list = Util.GetCBList(s.metBW2_00000, 0);
|
||||
Util.AddCBWithOffset(met_list, s.metBW2_60000, 60001, Locations.Daycare5);
|
||||
Util.AddCBWithOffset(met_list, s.metBW2_30000, 30001, Locations.LinkTrade5);
|
||||
Util.AddCBWithOffset(met_list, s.metBW2_00000, 00000, Legal.Met_BW2_0);
|
||||
Util.AddCBWithOffset(met_list, s.metBW2_30000, 30001, Legal.Met_BW2_3);
|
||||
Util.AddCBWithOffset(met_list, s.metBW2_40000, 40001, Legal.Met_BW2_4);
|
||||
Util.AddCBWithOffset(met_list, s.metBW2_60000, 60001, Legal.Met_BW2_6);
|
||||
return met_list;
|
||||
}
|
||||
|
||||
private static List<ComboItem> CreateGen6(GameStrings s)
|
||||
{
|
||||
var met_list = Util.GetCBList(s.metXY_00000, 0);
|
||||
Util.AddCBWithOffset(met_list, s.metXY_60000, 60001, Locations.Daycare5);
|
||||
Util.AddCBWithOffset(met_list, s.metXY_30000, 30001, Locations.LinkTrade6);
|
||||
Util.AddCBWithOffset(met_list, s.metXY_00000, 00000, Legal.Met_XY_0);
|
||||
Util.AddCBWithOffset(met_list, s.metXY_30000, 30001, Legal.Met_XY_3);
|
||||
Util.AddCBWithOffset(met_list, s.metXY_40000, 40001, Legal.Met_XY_4);
|
||||
Util.AddCBWithOffset(met_list, s.metXY_60000, 60001, Legal.Met_XY_6);
|
||||
return met_list;
|
||||
}
|
||||
|
||||
private static List<ComboItem> CreateGen7(GameStrings s)
|
||||
{
|
||||
var met_list = Util.GetCBList(s.metSM_00000, 0);
|
||||
Util.AddCBWithOffset(met_list, s.metSM_60000, 60001, Locations.Daycare5);
|
||||
Util.AddCBWithOffset(met_list, s.metSM_30000, 30001, Locations.LinkTrade6);
|
||||
Util.AddCBWithOffset(met_list, s.metSM_00000, 00000, Legal.Met_SM_0);
|
||||
Util.AddCBWithOffset(met_list, s.metSM_30000, 30001, Legal.Met_SM_3);
|
||||
Util.AddCBWithOffset(met_list, s.metSM_40000, 40001, Legal.Met_SM_4);
|
||||
Util.AddCBWithOffset(met_list, s.metSM_60000, 60001, Legal.Met_SM_6);
|
||||
return met_list;
|
||||
}
|
||||
|
||||
private static List<ComboItem> CreateGen7GG(GameStrings s)
|
||||
{
|
||||
var met_list = Util.GetCBList(s.metGG_00000, 0);
|
||||
Util.AddCBWithOffset(met_list, s.metGG_60000, 60001, 60002);
|
||||
Util.AddCBWithOffset(met_list, s.metGG_30000, 30001, Locations.LinkTrade6);
|
||||
Util.AddCBWithOffset(met_list, s.metGG_00000, 00000, Legal.Met_GG_0);
|
||||
Util.AddCBWithOffset(met_list, s.metGG_30000, 30001, Legal.Met_GG_3);
|
||||
Util.AddCBWithOffset(met_list, s.metGG_40000, 40001, Legal.Met_GG_4);
|
||||
Util.AddCBWithOffset(met_list, s.metGG_60000, 60001, Legal.Met_GG_6);
|
||||
return met_list;
|
||||
}
|
||||
|
||||
private static List<ComboItem> CreateGen8(GameStrings s)
|
||||
{
|
||||
var met_list = Util.GetCBList(s.metSWSH_00000, 0);
|
||||
Util.AddCBWithOffset(met_list, s.metSWSH_60000, 60001, 60002);
|
||||
Util.AddCBWithOffset(met_list, s.metSWSH_30000, 30001, Locations.LinkTrade6);
|
||||
Util.AddCBWithOffset(met_list, s.metSWSH_00000, 00000, Legal.Met_SWSH_0);
|
||||
Util.AddCBWithOffset(met_list, s.metSWSH_30000, 30001, Legal.Met_SWSH_3);
|
||||
Util.AddCBWithOffset(met_list, s.metSWSH_40000, 40001, Legal.Met_SWSH_4);
|
||||
Util.AddCBWithOffset(met_list, s.metSWSH_60000, 60001, Legal.Met_SWSH_6);
|
||||
return met_list;
|
||||
}
|
||||
|
||||
public IReadOnlyList<ComboItem> GetItemDataSource(GameVersion game, int generation, int MaxItemID, IEnumerable<ushort>? allowed = null, bool HaX = false)
|
||||
{
|
||||
var items = Source.GetItemStrings(generation, game);
|
||||
return Util.GetCBList(items, (allowed == null || HaX ? Enumerable.Range(0, MaxItemID) : allowed.Select(i => (int)i)).ToArray());
|
||||
var range = (allowed == null || HaX ? Enumerable.Range(0, MaxItemID) : allowed.Select(i => (int) i)).ToArray();
|
||||
return Util.GetCBList(items, range);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -22,22 +22,17 @@ namespace PKHeX.Core
|
|||
|
||||
public static GameStrings GetStrings(int index)
|
||||
{
|
||||
return Languages[index] ?? (Languages[index] = new GameStrings(GameLanguage.Language2Char(index)));
|
||||
return Languages[index] ??= new GameStrings(GameLanguage.Language2Char(index));
|
||||
}
|
||||
|
||||
public static GameStrings Strings
|
||||
{
|
||||
get => _strings;
|
||||
set
|
||||
{
|
||||
_strings = value;
|
||||
Sources = new GameDataSource(_strings);
|
||||
FilteredSources = null;
|
||||
}
|
||||
set => Sources = new GameDataSource(_strings = value);
|
||||
}
|
||||
|
||||
public static GameDataSource Sources { get; set; }
|
||||
public static FilteredGameDataSource FilteredSources { get; set; }
|
||||
public static GameDataSource Sources { get; private set; } = new GameDataSource(_strings);
|
||||
public static FilteredGameDataSource FilteredSources { get; set; } = new FilteredGameDataSource(FakeSaveFile.Default, Sources, false);
|
||||
|
||||
public static string GetVersionName(GameVersion version)
|
||||
{
|
||||
|
|
|
@ -22,7 +22,7 @@ namespace PKHeX.Core
|
|||
/// </summary>
|
||||
public IReadOnlyList<CheckResult> Results => Parse;
|
||||
|
||||
private IEncounterable EncounterOriginalGB;
|
||||
private IEncounterable? EncounterOriginalGB;
|
||||
|
||||
/// <summary>
|
||||
/// Matched encounter data for the <see cref="pkm"/>.
|
||||
|
@ -52,7 +52,7 @@ namespace PKHeX.Core
|
|||
/// <summary>
|
||||
/// Contains various data reused for multiple checks.
|
||||
/// </summary>
|
||||
public LegalInfo Info { get; private set; }
|
||||
public readonly LegalInfo Info;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a report message with optional verbosity for in-depth analysis.
|
||||
|
@ -85,7 +85,7 @@ namespace PKHeX.Core
|
|||
}
|
||||
}
|
||||
|
||||
private int[] _allSuggestedMoves, _allSuggestedRelearnMoves;
|
||||
private int[]? _allSuggestedMoves, _allSuggestedRelearnMoves;
|
||||
public int[] AllSuggestedMovesAndRelearn => AllSuggestedMoves.Concat(AllSuggestedRelearnMoves).ToArray();
|
||||
|
||||
private string EncounterName
|
||||
|
@ -97,7 +97,7 @@ namespace PKHeX.Core
|
|||
}
|
||||
}
|
||||
|
||||
private string EncounterLocation
|
||||
private string? EncounterLocation
|
||||
{
|
||||
get
|
||||
{
|
||||
|
@ -111,15 +111,22 @@ namespace PKHeX.Core
|
|||
/// </summary>
|
||||
/// <param name="pk">Input data to check</param>
|
||||
/// <param name="table"><see cref="SaveFile"/> specific personal data</param>
|
||||
public LegalityAnalysis(PKM pk, PersonalTable table = null)
|
||||
public LegalityAnalysis(PKM pk, PersonalTable? table = null)
|
||||
{
|
||||
pkm = pk;
|
||||
PersonalInfo = table?.GetFormeEntry(pkm.Species, pkm.AltForm) ?? pkm.PersonalInfo;
|
||||
|
||||
if (pkm.Format <= 2) // prior to storing GameVersion
|
||||
pkm.TradebackStatus = GBRestrictions.GetTradebackStatusInitial(pkm);
|
||||
|
||||
#if SUPPRESS
|
||||
try
|
||||
#endif
|
||||
{
|
||||
PersonalInfo = table?.GetFormeEntry(pkm.Species, pkm.AltForm) ?? pkm.PersonalInfo;
|
||||
ParseLegality();
|
||||
Info = EncounterFinder.FindVerifiedEncounter(pkm);
|
||||
if (!pkm.IsOriginValid)
|
||||
AddLine(Severity.Invalid, LEncConditionBadSpecies, CheckIdentifier.GameOrigin);
|
||||
GetParseMethod()();
|
||||
|
||||
if (Parse.Count == 0)
|
||||
return;
|
||||
|
@ -134,6 +141,7 @@ namespace PKHeX.Core
|
|||
#if SUPPRESS
|
||||
catch (Exception e)
|
||||
{
|
||||
Info = new LegalInfo(pkm);
|
||||
System.Diagnostics.Debug.WriteLine(e.Message);
|
||||
Valid = false;
|
||||
AddLine(Severity.Invalid, L_AError, CheckIdentifier.Misc);
|
||||
|
@ -143,33 +151,33 @@ namespace PKHeX.Core
|
|||
Parsed = true;
|
||||
}
|
||||
|
||||
private void ParseLegality()
|
||||
private Action GetParseMethod()
|
||||
{
|
||||
if (!pkm.IsOriginValid)
|
||||
AddLine(Severity.Invalid, LEncConditionBadSpecies, CheckIdentifier.GameOrigin);
|
||||
|
||||
if (pkm.Format <= 2) // prior to storing GameVersion
|
||||
{
|
||||
ParsePK1();
|
||||
return;
|
||||
}
|
||||
switch (pkm.GenNumber)
|
||||
{
|
||||
case 3: ParsePK3(); return;
|
||||
case 4: ParsePK4(); return;
|
||||
case 5: ParsePK5(); return;
|
||||
case 6: ParsePK6(); return;
|
||||
return ParsePK1;
|
||||
|
||||
case 1: case 2:
|
||||
case 7: ParsePK7(); return;
|
||||
int gen = pkm.GenNumber;
|
||||
if (gen <= 0)
|
||||
gen = pkm.Format;
|
||||
return gen switch
|
||||
{
|
||||
3 => ParsePK3,
|
||||
4 => ParsePK4,
|
||||
5 => ParsePK5,
|
||||
6 => ParsePK6,
|
||||
|
||||
case 8: ParsePK8(); return;
|
||||
}
|
||||
1 => ParsePK7,
|
||||
2 => ParsePK7,
|
||||
7 => ParsePK7,
|
||||
|
||||
8 => (Action)ParsePK8,
|
||||
|
||||
_ => throw new Exception()
|
||||
};
|
||||
}
|
||||
|
||||
private void ParsePK1()
|
||||
{
|
||||
pkm.TradebackStatus = GBRestrictions.GetTradebackStatusInitial(pkm);
|
||||
UpdateInfo();
|
||||
if (pkm.TradebackStatus == TradebackType.Any && Info.Generation != pkm.Format)
|
||||
pkm.TradebackStatus = TradebackType.WasTradeback; // Example: GSC Pokemon with only possible encounters in RBY, like the legendary birds
|
||||
|
@ -267,7 +275,6 @@ namespace PKHeX.Core
|
|||
|
||||
private void UpdateInfo()
|
||||
{
|
||||
Info = EncounterFinder.FindVerifiedEncounter(pkm);
|
||||
Parse.AddRange(Info.Parse);
|
||||
}
|
||||
|
||||
|
@ -385,7 +392,11 @@ namespace PKHeX.Core
|
|||
lines.Add(string.Format(L_F0_1, "Location", loc));
|
||||
if (pkm.VC)
|
||||
lines.Add(string.Format(L_F0_1, nameof(GameVersion), Info.Game));
|
||||
var pidiv = Info.PIDIV ?? MethodFinder.Analyze(pkm);
|
||||
|
||||
if (!Info.PIDParsed)
|
||||
Info.PIDIV = MethodFinder.Analyze(pkm);
|
||||
|
||||
var pidiv = Info.PIDIV;
|
||||
if (pidiv != null)
|
||||
{
|
||||
if (!pidiv.NoSeed)
|
||||
|
@ -456,6 +467,6 @@ namespace PKHeX.Core
|
|||
/// <summary>
|
||||
/// Gets an object containing met data properties that might be legal.
|
||||
/// </summary>
|
||||
public EncounterStatic GetSuggestedMetInfo() => EncounterSuggestion.GetSuggestedMetInfo(pkm);
|
||||
public EncounterStatic? GetSuggestedMetInfo() => EncounterSuggestion.GetSuggestedMetInfo(pkm);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ namespace PKHeX.Core
|
|||
public abstract class EncounterArea
|
||||
{
|
||||
public int Location;
|
||||
public EncounterSlot[] Slots;
|
||||
public EncounterSlot[] Slots = Array.Empty<EncounterSlot>();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the encounter areas for species with same level range and same slot type at same location
|
||||
|
|
|
@ -27,7 +27,7 @@ namespace PKHeX.Core
|
|||
|
||||
protected override IEnumerable<EncounterSlot> GetFilteredSlots(PKM pkm, IEnumerable<EncounterSlot> slots, int minLevel)
|
||||
{
|
||||
EncounterSlot slotMax = null;
|
||||
EncounterSlot? slotMax = null;
|
||||
foreach (EncounterSlot s in slots)
|
||||
{
|
||||
if (Legal.WildForms.Contains(pkm.Species) && s.Form != pkm.AltForm)
|
||||
|
|
|
@ -11,7 +11,7 @@ namespace PKHeX.Core
|
|||
{
|
||||
protected override IEnumerable<EncounterSlot> GetFilteredSlots(PKM pkm, IEnumerable<EncounterSlot> slots, int minLevel)
|
||||
{
|
||||
EncounterSlot slotMax = null;
|
||||
EncounterSlot? slotMax = null;
|
||||
void CachePressureSlot(EncounterSlot s)
|
||||
{
|
||||
if (slotMax == null || s.LevelMax > slotMax.LevelMax)
|
||||
|
|
|
@ -21,7 +21,7 @@ namespace PKHeX.Core
|
|||
yield break;
|
||||
}
|
||||
|
||||
EncounterSlot slotMax = null;
|
||||
EncounterSlot? slotMax = null;
|
||||
void CachePressureSlot(EncounterSlot s)
|
||||
{
|
||||
if (slotMax != null && s.LevelMax > slotMax.LevelMax)
|
||||
|
|
|
@ -30,26 +30,19 @@ namespace PKHeX.Core
|
|||
|
||||
internal static TreesArea[] GetArray(byte[][] entries) => entries.Select(z => new TreesArea(z)).ToArray();
|
||||
|
||||
public int Location { get; private set; }
|
||||
private TreeEncounterAvailable[] TrainerModerateEncounterTree { get; set; }
|
||||
private TreeEncounterAvailable[] TrainerLowEncounterTree { get; set; }
|
||||
private int[] ValidTreeIndex { get; set; }
|
||||
private int[] InvalidTreeIndex { get; set; }
|
||||
private TreeCoordinates[] ValidTrees { get; set; }
|
||||
private TreeCoordinates[] InvalidTrees { get; set; }
|
||||
public readonly int Location;
|
||||
private readonly TreeEncounterAvailable[] TrainerModerateEncounterTree;
|
||||
private readonly TreeEncounterAvailable[] TrainerLowEncounterTree;
|
||||
private readonly int[] ValidTreeIndex;
|
||||
private readonly int[] InvalidTreeIndex;
|
||||
private readonly TreeCoordinates[] ValidTrees;
|
||||
private readonly TreeCoordinates[] InvalidTrees;
|
||||
|
||||
public TreeEncounterAvailable[] GetTrees(SlotType t) => t == SlotType.Headbutt
|
||||
? TrainerModerateEncounterTree
|
||||
: TrainerLowEncounterTree;
|
||||
|
||||
private TreesArea(byte[] entry)
|
||||
{
|
||||
ReadAreaRawData(entry);
|
||||
GenerateAreaTreeIndex();
|
||||
GenerateAreaTrainerEncounters();
|
||||
}
|
||||
|
||||
private void ReadAreaRawData(byte[] entry)
|
||||
{
|
||||
// Coordinates of trees were obtained with the program G2Map
|
||||
// ValidTrees are those accessible by the player
|
||||
|
@ -64,18 +57,12 @@ namespace PKHeX.Core
|
|||
ofs++;
|
||||
for (int i = 0; i < InvalidTrees.Length; i++, ofs += 2)
|
||||
InvalidTrees[i] = new TreeCoordinates(entry[ofs], entry[ofs + 1]);
|
||||
}
|
||||
|
||||
private void GenerateAreaTreeIndex()
|
||||
{
|
||||
// For legality purposes, only the tree index is needed.
|
||||
// Group the trees data by their index; trees that share indexes are indistinguishable from one another
|
||||
ValidTreeIndex = ValidTrees.Select(t => t.Index).Distinct().OrderBy(i => i).ToArray();
|
||||
InvalidTreeIndex = InvalidTrees.Select(t => t.Index).Distinct().OrderBy(i => i).Except(ValidTreeIndex).ToArray();
|
||||
}
|
||||
|
||||
private void GenerateAreaTrainerEncounters()
|
||||
{
|
||||
// Check for every trainer pivot index if there are trees with moderate encounter and low encounter available in the area
|
||||
TrainerModerateEncounterTree = new TreeEncounterAvailable[PivotCount];
|
||||
TrainerLowEncounterTree = new TreeEncounterAvailable[PivotCount];
|
||||
|
|
|
@ -16,56 +16,59 @@ namespace PKHeX.Core
|
|||
public static string EReaderBerryDisplayName => string.Format(LegalityCheckStrings.L_XEnigmaBerry_0, Util.ToTitleCase(EReaderBerryName.ToLower()));
|
||||
|
||||
// Gen 1
|
||||
internal static readonly Learnset[] LevelUpRB = Learnset1.GetArray(Util.GetBinaryResource("lvlmove_rb.pkl"), MaxSpeciesID_1);
|
||||
internal static readonly Learnset[] LevelUpY = Learnset1.GetArray(Util.GetBinaryResource("lvlmove_y.pkl"), MaxSpeciesID_1);
|
||||
internal static readonly Learnset[] LevelUpRB = LearnsetReader.GetArray(Util.GetBinaryResource("lvlmove_rb.pkl"), MaxSpeciesID_1);
|
||||
internal static readonly Learnset[] LevelUpY = LearnsetReader.GetArray(Util.GetBinaryResource("lvlmove_y.pkl"), MaxSpeciesID_1);
|
||||
|
||||
// Gen 2
|
||||
internal static readonly EggMoves[] EggMovesGS = EggMoves2.GetArray(Util.GetBinaryResource("eggmove_gs.pkl"), MaxSpeciesID_2);
|
||||
internal static readonly Learnset[] LevelUpGS = Learnset1.GetArray(Util.GetBinaryResource("lvlmove_gs.pkl"), MaxSpeciesID_2);
|
||||
internal static readonly Learnset[] LevelUpGS = LearnsetReader.GetArray(Util.GetBinaryResource("lvlmove_gs.pkl"), MaxSpeciesID_2);
|
||||
internal static readonly EggMoves[] EggMovesC = EggMoves2.GetArray(Util.GetBinaryResource("eggmove_c.pkl"), MaxSpeciesID_2);
|
||||
internal static readonly Learnset[] LevelUpC = Learnset1.GetArray(Util.GetBinaryResource("lvlmove_c.pkl"), MaxSpeciesID_2);
|
||||
internal static readonly Learnset[] LevelUpC = LearnsetReader.GetArray(Util.GetBinaryResource("lvlmove_c.pkl"), MaxSpeciesID_2);
|
||||
|
||||
// Gen 3
|
||||
internal static readonly Learnset[] LevelUpE = Learnset6.GetArray(Data.UnpackMini(Util.GetBinaryResource("lvlmove_e.pkl"), "em"));
|
||||
internal static readonly Learnset[] LevelUpRS = Learnset6.GetArray(Data.UnpackMini(Util.GetBinaryResource("lvlmove_rs.pkl"), "rs"));
|
||||
internal static readonly Learnset[] LevelUpFR = Learnset6.GetArray(Data.UnpackMini(Util.GetBinaryResource("lvlmove_fr.pkl"), "fr"));
|
||||
internal static readonly Learnset[] LevelUpLG = Learnset6.GetArray(Data.UnpackMini(Util.GetBinaryResource("lvlmove_lg.pkl"), "lg"));
|
||||
internal static readonly EggMoves[] EggMovesRS = EggMoves6.GetArray(Data.UnpackMini(Util.GetBinaryResource("eggmove_rs.pkl"), "rs"));
|
||||
internal static readonly Learnset[] LevelUpE = LearnsetReader.GetArray(Data.UnpackMini(Util.GetBinaryResource("lvlmove_e.pkl"), "em"));
|
||||
internal static readonly Learnset[] LevelUpRS = LearnsetReader.GetArray(Data.UnpackMini(Util.GetBinaryResource("lvlmove_rs.pkl"), "rs"));
|
||||
internal static readonly Learnset[] LevelUpFR = LearnsetReader.GetArray(Data.UnpackMini(Util.GetBinaryResource("lvlmove_fr.pkl"), "fr"));
|
||||
internal static readonly Learnset[] LevelUpLG = LearnsetReader.GetArray(Data.UnpackMini(Util.GetBinaryResource("lvlmove_lg.pkl"), "lg"));
|
||||
internal static readonly EggMoves6[] EggMovesRS = EggMoves6.GetArray(Data.UnpackMini(Util.GetBinaryResource("eggmove_rs.pkl"), "rs"));
|
||||
|
||||
// Gen 4
|
||||
internal static readonly Learnset[] LevelUpDP = Learnset6.GetArray(Data.UnpackMini(Util.GetBinaryResource("lvlmove_dp.pkl"), "dp"));
|
||||
internal static readonly Learnset[] LevelUpPt = Learnset6.GetArray(Data.UnpackMini(Util.GetBinaryResource("lvlmove_pt.pkl"), "pt"));
|
||||
internal static readonly Learnset[] LevelUpHGSS = Learnset6.GetArray(Data.UnpackMini(Util.GetBinaryResource("lvlmove_hgss.pkl"), "hs"));
|
||||
internal static readonly EggMoves[] EggMovesDPPt = EggMoves6.GetArray(Data.UnpackMini(Util.GetBinaryResource("eggmove_dppt.pkl"), "dp"));
|
||||
internal static readonly EggMoves[] EggMovesHGSS = EggMoves6.GetArray(Data.UnpackMini(Util.GetBinaryResource("eggmove_hgss.pkl"), "hs"));
|
||||
internal static readonly Learnset[] LevelUpDP = LearnsetReader.GetArray(Data.UnpackMini(Util.GetBinaryResource("lvlmove_dp.pkl"), "dp"));
|
||||
internal static readonly Learnset[] LevelUpPt = LearnsetReader.GetArray(Data.UnpackMini(Util.GetBinaryResource("lvlmove_pt.pkl"), "pt"));
|
||||
internal static readonly Learnset[] LevelUpHGSS = LearnsetReader.GetArray(Data.UnpackMini(Util.GetBinaryResource("lvlmove_hgss.pkl"), "hs"));
|
||||
internal static readonly EggMoves6[] EggMovesDPPt = EggMoves6.GetArray(Data.UnpackMini(Util.GetBinaryResource("eggmove_dppt.pkl"), "dp"));
|
||||
internal static readonly EggMoves6[] EggMovesHGSS = EggMoves6.GetArray(Data.UnpackMini(Util.GetBinaryResource("eggmove_hgss.pkl"), "hs"));
|
||||
|
||||
// Gen 5
|
||||
internal static readonly Learnset[] LevelUpBW = Learnset6.GetArray(Data.UnpackMini(Util.GetBinaryResource("lvlmove_bw.pkl"), "51"));
|
||||
internal static readonly Learnset[] LevelUpB2W2 = Learnset6.GetArray(Data.UnpackMini(Util.GetBinaryResource("lvlmove_b2w2.pkl"), "52"));
|
||||
internal static readonly EggMoves[] EggMovesBW = EggMoves6.GetArray(Data.UnpackMini(Util.GetBinaryResource("eggmove_bw.pkl"), "bw"));
|
||||
internal static readonly Learnset[] LevelUpBW = LearnsetReader.GetArray(Data.UnpackMini(Util.GetBinaryResource("lvlmove_bw.pkl"), "51"));
|
||||
internal static readonly Learnset[] LevelUpB2W2 = LearnsetReader.GetArray(Data.UnpackMini(Util.GetBinaryResource("lvlmove_b2w2.pkl"), "52"));
|
||||
internal static readonly EggMoves6[] EggMovesBW = EggMoves6.GetArray(Data.UnpackMini(Util.GetBinaryResource("eggmove_bw.pkl"), "bw"));
|
||||
|
||||
// Gen 6
|
||||
internal static readonly EggMoves[] EggMovesXY = EggMoves6.GetArray(Data.UnpackMini(Util.GetBinaryResource("eggmove_xy.pkl"), "xy"));
|
||||
internal static readonly Learnset[] LevelUpXY = Learnset6.GetArray(Data.UnpackMini(Util.GetBinaryResource("lvlmove_xy.pkl"), "xy"));
|
||||
internal static readonly EggMoves[] EggMovesAO = EggMoves6.GetArray(Data.UnpackMini(Util.GetBinaryResource("eggmove_ao.pkl"), "ao"));
|
||||
internal static readonly Learnset[] LevelUpAO = Learnset6.GetArray(Data.UnpackMini(Util.GetBinaryResource("lvlmove_ao.pkl"), "ao"));
|
||||
internal static readonly EggMoves6[] EggMovesXY = EggMoves6.GetArray(Data.UnpackMini(Util.GetBinaryResource("eggmove_xy.pkl"), "xy"));
|
||||
internal static readonly Learnset[] LevelUpXY = LearnsetReader.GetArray(Data.UnpackMini(Util.GetBinaryResource("lvlmove_xy.pkl"), "xy"));
|
||||
internal static readonly EggMoves6[] EggMovesAO = EggMoves6.GetArray(Data.UnpackMini(Util.GetBinaryResource("eggmove_ao.pkl"), "ao"));
|
||||
internal static readonly Learnset[] LevelUpAO = LearnsetReader.GetArray(Data.UnpackMini(Util.GetBinaryResource("lvlmove_ao.pkl"), "ao"));
|
||||
|
||||
// Gen 7
|
||||
internal static readonly EggMoves[] EggMovesSM = EggMoves7.GetArray(Data.UnpackMini(Util.GetBinaryResource("eggmove_sm.pkl"), "sm"));
|
||||
internal static readonly Learnset[] LevelUpSM = Learnset6.GetArray(Data.UnpackMini(Util.GetBinaryResource("lvlmove_sm.pkl"), "sm"));
|
||||
internal static readonly EggMoves[] EggMovesUSUM = EggMoves7.GetArray(Data.UnpackMini(Util.GetBinaryResource("eggmove_uu.pkl"), "uu"));
|
||||
internal static readonly Learnset[] LevelUpUSUM = Learnset6.GetArray(Data.UnpackMini(Util.GetBinaryResource("lvlmove_uu.pkl"), "uu"));
|
||||
internal static readonly Learnset[] LevelUpGG = Learnset6.GetArray(Data.UnpackMini(Util.GetBinaryResource("lvlmove_gg.pkl"), "gg"));
|
||||
internal static readonly EggMoves7[] EggMovesSM = EggMoves7.GetArray(Data.UnpackMini(Util.GetBinaryResource("eggmove_sm.pkl"), "sm"));
|
||||
internal static readonly Learnset[] LevelUpSM = LearnsetReader.GetArray(Data.UnpackMini(Util.GetBinaryResource("lvlmove_sm.pkl"), "sm"));
|
||||
internal static readonly EggMoves7[] EggMovesUSUM = EggMoves7.GetArray(Data.UnpackMini(Util.GetBinaryResource("eggmove_uu.pkl"), "uu"));
|
||||
internal static readonly Learnset[] LevelUpUSUM = LearnsetReader.GetArray(Data.UnpackMini(Util.GetBinaryResource("lvlmove_uu.pkl"), "uu"));
|
||||
internal static readonly Learnset[] LevelUpGG = LearnsetReader.GetArray(Data.UnpackMini(Util.GetBinaryResource("lvlmove_gg.pkl"), "gg"));
|
||||
|
||||
// Gen 8
|
||||
internal static readonly EggMoves[] EggMovesSWSH = EggMoves7.GetArray(Data.UnpackMini(Util.GetBinaryResource("eggmove_sm.pkl"), "sm"));
|
||||
internal static readonly Learnset[] LevelUpSWSH = Learnset6.GetArray(Data.UnpackMini(Util.GetBinaryResource("lvlmove_sm.pkl"), "sm"));
|
||||
internal static readonly EggMoves7[] EggMovesSWSH = EggMoves7.GetArray(Data.UnpackMini(Util.GetBinaryResource("eggmove_sm.pkl"), "sm"));
|
||||
internal static readonly Learnset[] LevelUpSWSH = LearnsetReader.GetArray(Data.UnpackMini(Util.GetBinaryResource("lvlmove_sm.pkl"), "sm"));
|
||||
|
||||
// Setup Help
|
||||
static Legal()
|
||||
{
|
||||
// Misc Fixes to Data pertaining to legality constraints
|
||||
Array.Resize(ref EggMovesUSUM[198].Moves, 15); // Remove Punishment from USUM Murkrow (no species can pass it #1829)
|
||||
|
||||
// Remove Punishment from USUM Murkrow (no species can pass it #1829)
|
||||
// DONE: Egg Move Data for EggMovesUSUM no longer has it at the end
|
||||
|
||||
// Prevent Silvally from being tutored Fire/Water Pledge (logic can only tutor one, and Grass is first)
|
||||
var pi = PersonalTable.USUM[773];
|
||||
pi.TypeTutors[1] = false; // fire
|
||||
|
@ -563,7 +566,7 @@ namespace PKHeX.Core
|
|||
|
||||
// Check also if the current encounter include the evolve move as an special move
|
||||
// That means the pokemon have the move from the encounter level
|
||||
if (info.EncounterMatch is IMoveset s && s.Moves?.Any(m => moves.Contains(m)) == true)
|
||||
if (info.EncounterMatch is IMoveset s && s.Moves.Any(m => moves.Contains(m)))
|
||||
LearnLevel = Math.Min(LearnLevel, info.EncounterMatch.LevelMin);
|
||||
|
||||
// If the encounter is a player hatched egg check if the move could be an egg move or inherited level up move
|
||||
|
|
|
@ -10,13 +10,13 @@ namespace PKHeX.Core
|
|||
/// <param name="fileData">Packed data</param>
|
||||
/// <param name="identifier">Signature expected in the first two bytes (ASCII)</param>
|
||||
/// <returns>Unpacked array containing all files that were packed.</returns>
|
||||
public static byte[][] UnpackMini(byte[] fileData, string identifier)
|
||||
public static byte[][] UnpackMini(byte[]? fileData, string identifier)
|
||||
{
|
||||
if (fileData == null || fileData.Length < 4)
|
||||
return null;
|
||||
throw new ArgumentException(nameof(fileData));
|
||||
|
||||
if (identifier[0] != fileData[0] || identifier[1] != fileData[1])
|
||||
return null;
|
||||
throw new ArgumentException(nameof(identifier));
|
||||
|
||||
int count = BitConverter.ToUInt16(fileData, 2); int ctr = 4;
|
||||
int start = BitConverter.ToInt32(fileData, ctr); ctr += 4;
|
||||
|
|
|
@ -38,11 +38,11 @@ namespace PKHeX.Core
|
|||
private static HashSet<PGF> GetPGFDB(byte[] bin) => new HashSet<PGF>(ArrayUtil.EnumerateSplit(bin, PGF.Size).Select(d => new PGF(d)));
|
||||
|
||||
private static HashSet<WC6> GetWC6DB(byte[] wc6bin, byte[] wc6full) => new HashSet<WC6>(
|
||||
ArrayUtil.EnumerateSplit(wc6full, WC6.SizeFull).Select(d => new WC6(d))
|
||||
ArrayUtil.EnumerateSplit(wc6full, WC6Full.Size).Select(d => new WC6Full(d).Gift)
|
||||
.Concat(ArrayUtil.EnumerateSplit(wc6bin, WC6.Size).Select(d => new WC6(d))));
|
||||
|
||||
private static HashSet<WC7> GetWC7DB(byte[] wc7bin, byte[] wc7full) => new HashSet<WC7>(
|
||||
ArrayUtil.EnumerateSplit(wc7full, WC7.SizeFull).Select(d => new WC7(d))
|
||||
ArrayUtil.EnumerateSplit(wc7full, WC7Full.Size).Select(d => new WC7Full(d).Gift)
|
||||
.Concat(ArrayUtil.EnumerateSplit(wc7bin, WC7.Size).Select(d => new WC7(d))));
|
||||
|
||||
private static HashSet<WB7> GetWB7DB(byte[] wc7full) => new HashSet<WB7>(ArrayUtil.EnumerateSplit(wc7full, WB7.SizeFull).Select(d => new WB7(d)));
|
||||
|
|
|
@ -243,13 +243,13 @@ namespace PKHeX.Core
|
|||
internal static void MarkEncounterTradeStrings(EncounterTrade[] table, string[][] strings)
|
||||
{
|
||||
int half = strings[1].Length / 2;
|
||||
for (var i = 0; i < half; i++)
|
||||
for (int i = 0; i < half; i++)
|
||||
{
|
||||
var t = table[i];
|
||||
t.Nicknames = getNames(i, strings);
|
||||
t.TrainerNames = getNames(i + half, strings);
|
||||
}
|
||||
string[] getNames(int i, IEnumerable<string[]> names) => names?.Select(z => z?.Length > i ? z[i] : null).ToArray();
|
||||
string[] getNames(int i, IEnumerable<string[]> names) => names.Select(z => z.Length > i ? z[i] : string.Empty).ToArray();
|
||||
}
|
||||
|
||||
internal static void MarkEncounterGame(IEnumerable<IVersion> table, GameVersion version)
|
||||
|
|
|
@ -31,7 +31,7 @@ namespace PKHeX.Core
|
|||
StaticRBY.SetVersion(GameVersion.RBY);
|
||||
}
|
||||
|
||||
internal static readonly string[] TradeOTG1 = {null, "トレーナー", "Trainer", "Dresseur", "Allenatore", "Trainer", null, "Entrenador", "트레이너"};
|
||||
internal static readonly string[] TradeOTG1 = {string.Empty, "トレーナー", "Trainer", "Dresseur", "Allenatore", "Trainer", string.Empty, "Entrenador", "트레이너"};
|
||||
|
||||
private static EncounterArea1[] GetAreas()
|
||||
{
|
||||
|
|
|
@ -273,6 +273,13 @@ namespace PKHeX.Core
|
|||
private static readonly string[][] TradeRSE = Util.GetLanguageStrings7(tradeRSE);
|
||||
private static readonly string[][] TradeFRLG = Util.GetLanguageStrings7(tradeFRLG);
|
||||
|
||||
private static readonly int[] MoveSwarmSurskit = { 145, 098 }; /* Bubble, Quick Attack */
|
||||
private static readonly int[] MoveSwarmSeedot = { 145, 098 }; /* Bide, Harden, Leech Seed */
|
||||
private static readonly int[] MoveSwarmNuzleaf = { 145, 098 }; /* Harden, Growth, Nature Power, Leech Seed */
|
||||
private static readonly int[] MoveSwarmSeedotF = { 202, 218, 076, 073 }; /* Giga Drain, Frustration, Solar Beam, Leech Seed */
|
||||
private static readonly int[] MoveSwarmSkittyRS = { 045, 033 }; /* Growl, Tackle */
|
||||
private static readonly int[] MoveSwarmSkittyE = { 045, 033, 039, 213 }; /* Growl, Tackle, Tail Whip, Attract */
|
||||
|
||||
#region AltSlots
|
||||
private static readonly EncounterArea3[] SlotsRSEAlt =
|
||||
{
|
||||
|
@ -280,38 +287,38 @@ namespace PKHeX.Core
|
|||
// Encounter Percent is a 50% call
|
||||
new EncounterArea3 {
|
||||
Location = 17, // Route 102
|
||||
Slots = new[]
|
||||
Slots = new EncounterSlot[]
|
||||
{
|
||||
new EncounterSlotMoves { Species = 283, LevelMin = 03, LevelMax = 03, Type = SlotType.Swarm, Moves = new[] {145, 098} /* Bubble, Quick Attack */ }, // Surskit (R/S)
|
||||
new EncounterSlotMoves { Species = 273, LevelMin = 03, LevelMax = 03, Type = SlotType.Swarm, Moves = new[] {117, 106, 073} /* Bide, Harden, Leech Seed */ }, // Seedot (E)
|
||||
new EncounterSlot3Swarm(MoveSwarmSurskit) { Species = 283, LevelMin = 03, LevelMax = 03, Type = SlotType.Swarm },
|
||||
new EncounterSlot3Swarm(MoveSwarmSeedot) { Species = 273, LevelMin = 03, LevelMax = 03, Type = SlotType.Swarm },
|
||||
},},
|
||||
new EncounterArea3 {
|
||||
Location = 29, // Route 114
|
||||
Slots = new[]
|
||||
Slots = new EncounterSlot[]
|
||||
{
|
||||
new EncounterSlotMoves { Species = 283, LevelMin = 15, LevelMax = 15, Type = SlotType.Swarm, Moves = new[] {145, 098} /* Bubble, Quick Attack */ }, // Surskit (R/S)
|
||||
new EncounterSlotMoves { Species = 274, LevelMin = 15, LevelMax = 15, Type = SlotType.Swarm, Moves = new[] {106, 074, 267, 073} /* Harden, Growth, Nature Power, Leech Seed */ }, // Nuzleaf (E)
|
||||
new EncounterSlot3Swarm(MoveSwarmSurskit) { Species = 283, LevelMin = 15, LevelMax = 15, Type = SlotType.Swarm },
|
||||
new EncounterSlot3Swarm(MoveSwarmNuzleaf) { Species = 274, LevelMin = 15, LevelMax = 15, Type = SlotType.Swarm },
|
||||
},},
|
||||
new EncounterArea3 {
|
||||
Location = 31, // Route 116
|
||||
Slots = new[]
|
||||
Slots = new EncounterSlot[]
|
||||
{
|
||||
new EncounterSlotMoves { Species = 300, LevelMin = 15, LevelMax = 15, Type = SlotType.Swarm, Moves = new[] {045, 033} /* Growl, Tackle */ }, // Skitty (R/S)
|
||||
new EncounterSlotMoves { Species = 300, LevelMin = 08, LevelMax = 08, Type = SlotType.Swarm, Moves = new[] {045, 033, 039, 213} /* Growl, Tackle, Tail Whip, Attract */ }, // Skitty (E)
|
||||
new EncounterSlot3Swarm(MoveSwarmSkittyRS) { Species = 300, LevelMin = 15, LevelMax = 15, Type = SlotType.Swarm },
|
||||
new EncounterSlot3Swarm(MoveSwarmSkittyE) { Species = 300, LevelMin = 08, LevelMax = 08, Type = SlotType.Swarm },
|
||||
},},
|
||||
new EncounterArea3 {
|
||||
Location = 32, // Route 117
|
||||
Slots = new[]
|
||||
Slots = new EncounterSlot[]
|
||||
{
|
||||
new EncounterSlotMoves { Species = 283, LevelMin = 15, LevelMax = 15, Type = SlotType.Swarm, Moves = new[] {145, 098} /* Bubble, Quick Attack */ }, // Surskit (R/S)
|
||||
new EncounterSlotMoves { Species = 273, LevelMin = 13, LevelMax = 13, Type = SlotType.Swarm, Moves = new[] {106, 074, 267, 073} /* Harden, Growth, Nature Power, Leech Seed */ }, // Seedot (E)
|
||||
new EncounterSlot3Swarm(MoveSwarmSurskit) { Species = 283, LevelMin = 15, LevelMax = 15, Type = SlotType.Swarm },
|
||||
new EncounterSlot3Swarm(MoveSwarmNuzleaf) { Species = 273, LevelMin = 13, LevelMax = 13, Type = SlotType.Swarm }, // Has same moves as Nuzleaf
|
||||
},},
|
||||
new EncounterArea3 {
|
||||
Location = 35, // Route 120
|
||||
Slots = new[]
|
||||
Slots = new EncounterSlot[]
|
||||
{
|
||||
new EncounterSlotMoves { Species = 283, LevelMin = 28, LevelMax = 28, Type = SlotType.Swarm, Moves = new[] {145, 098} /* Bubble, Quick Attack */ }, // Surskit (R/S)
|
||||
new EncounterSlotMoves { Species = 273, LevelMin = 25, LevelMax = 25, Type = SlotType.Swarm, Moves = new[] {202, 218, 076, 073} /* Giga Drain, Frustration, Solar Beam, Leech Seed */ }, // Seedot (E)
|
||||
new EncounterSlot3Swarm(MoveSwarmSurskit) { Species = 283, LevelMin = 28, LevelMax = 28, Type = SlotType.Swarm },
|
||||
new EncounterSlot3Swarm(MoveSwarmSeedotF) { Species = 273, LevelMin = 25, LevelMax = 25, Type = SlotType.Swarm },
|
||||
},},
|
||||
|
||||
// Feebas fishing spot
|
||||
|
@ -356,7 +363,7 @@ namespace PKHeX.Core
|
|||
new EncounterStatic { Gift = true, Species = 196, Level = 25, Location = 254, Gender = 0 }, // Espeon
|
||||
new EncounterStatic { Gift = true, Species = 197, Level = 26, Location = 254, Gender = 0, Moves = new[] {044} }, // Umbreon (Bite)
|
||||
|
||||
new EncounterStaticShadow { Species = 296, Level = 30, Gauge = 03000, Moves = new[] {193,116,233,238}, Location = 005, Locks = ColoMakuhita }, // Makuhita: Miror B.Peon Trudly @ Phenac City
|
||||
new EncounterStaticShadow(ColoMakuhita) { Species = 296, Level = 30, Gauge = 03000, Moves = new[] {193,116,233,238}, Location = 005 }, // Makuhita: Miror B.Peon Trudly @ Phenac City
|
||||
|
||||
new EncounterStaticShadow { Species = 153, Level = 30, Gauge = 03000, Moves = new[] {241,235,075,034}, Location = 003 }, // Bayleef: Cipher Peon Verde @ Phenac City
|
||||
new EncounterStaticShadow { Species = 156, Level = 30, Gauge = 03000, Moves = new[] {241,108,091,172}, Location = 003 }, // Quilava: Cipher Peon Rosso @ Phenac City
|
||||
|
@ -415,8 +422,6 @@ namespace PKHeX.Core
|
|||
new EncounterStaticShadow { Species = 243, Level = 40, Gauge = 13000, Moves = new[] {240,043,098,087}, Location = 125 }, // Raikou: Cipher Admin Ein @ Deep Colosseum
|
||||
new EncounterStaticShadow { Species = 243, Level = 40, Gauge = 13000, Moves = new[] {240,043,098,087}, Location = 069 }, // Raikou: Cipher Admin Ein @ Shadow PKMN Lab
|
||||
|
||||
new EncounterStaticShadow { Species = 207, Level = 43, Gauge = 06000, Moves = new[] {185,028,040,163}, Location = 058, Locks = Gligar }, // Gligar: Hunter Frena @ The Under Subway
|
||||
new EncounterStaticShadow { Species = 207, Level = 43, Gauge = 06000, Moves = new[] {185,028,040,163}, Location = 133, Locks = Gligar }, // Gligar: Hunter Frena @ Snagem Hideout
|
||||
new EncounterStaticShadow { Species = 234, Level = 43, Gauge = 06000, Moves = new[] {310,095,043,036}, Location = 058 }, // Stantler: Chaser Liaks @ The Under Subway
|
||||
new EncounterStaticShadow { Species = 234, Level = 43, Gauge = 06000, Moves = new[] {310,095,043,036}, Location = 133 }, // Stantler: Chaser Liaks @ Snagem Hideout
|
||||
new EncounterStaticShadow { Species = 221, Level = 43, Gauge = 06000, Moves = new[] {203,316,091,059}, Location = 058 }, // Piloswine: Bodybuilder Lonia @ The Under Subway
|
||||
|
@ -424,7 +429,6 @@ namespace PKHeX.Core
|
|||
new EncounterStaticShadow { Species = 215, Level = 43, Gauge = 06000, Moves = new[] {185,103,154,196}, Location = 058 }, // Sneasel: Rider Nelis @ The Under Subway
|
||||
new EncounterStaticShadow { Species = 215, Level = 43, Gauge = 06000, Moves = new[] {185,103,154,196}, Location = 134 }, // Sneasel: Rider Nelis @ Snagem Hideout
|
||||
new EncounterStaticShadow { Species = 190, Level = 43, Gauge = 06000, Moves = new[] {226,321,154,129}, Location = 067 }, // Aipom: Cipher Peon Cole @ Shadow PKMN Lab
|
||||
new EncounterStaticShadow { Species = 198, Level = 43, Gauge = 06000, Moves = new[] {185,212,101,019}, Location = 067, Locks = Murkrow }, // Murkrow: Cipher Peon Lare @ Shadow PKMN Lab
|
||||
new EncounterStaticShadow { Species = 205, Level = 43, Gauge = 06000, Moves = new[] {153,182,117,229}, Location = 067 }, // Forretress: Cipher Peon Vana @ Shadow PKMN Lab
|
||||
new EncounterStaticShadow { Species = 168, Level = 43, Gauge = 06000, Moves = new[] {169,184,141,188}, Location = 069 }, // Ariados: Cipher Peon Lesar @ Shadow PKMN Lab
|
||||
new EncounterStaticShadow { Species = 210, Level = 43, Gauge = 06000, Moves = new[] {044,184,046,070}, Location = 069 }, // Granbull: Cipher Peon Tanie @ Shadow PKMN Lab
|
||||
|
@ -432,7 +436,6 @@ namespace PKHeX.Core
|
|||
|
||||
new EncounterStaticShadow { Species = 192, Level = 45, Gauge = 07000, Moves = new[] {241,074,275,076}, Location = 109 }, // Sunflora: Cipher Peon Baila @ Realgam Tower
|
||||
new EncounterStaticShadow { Species = 225, Level = 45, Gauge = 07000, Moves = new[] {059,213,217,019}, Location = 109 }, // Delibird: Cipher Peon Arton @ Realgam Tower
|
||||
new EncounterStaticShadow { Species = 214, Level = 45, Gauge = 07000, Moves = new[] {179,203,068,280}, Location = 111, Locks = Heracross }, // Heracross: Cipher Peon Dioge @ Realgam Tower
|
||||
new EncounterStaticShadow { Species = 227, Level = 47, Gauge = 13000, Moves = new[] {065,319,314,211}, Location = 117 }, // Skarmory: Snagem Head Gonzap @ Realgam Tower
|
||||
new EncounterStaticShadow { Species = 192, Level = 45, Gauge = 07000, Moves = new[] {241,074,275,076}, Location = 132 }, // Sunflora: Cipher Peon Baila @ Snagem Hideout
|
||||
new EncounterStaticShadow { Species = 225, Level = 45, Gauge = 07000, Moves = new[] {059,213,217,019}, Location = 132 }, // Delibird: Cipher Peon Arton @ Snagem Hideout
|
||||
|
@ -446,12 +449,17 @@ namespace PKHeX.Core
|
|||
new EncounterStaticShadow { Species = 376, Level = 50, Gauge = 15000, Moves = new[] {063,334,232,094}, Location = 118 }, // Metagross: Cipher Nascour @ Tower Colosseum
|
||||
new EncounterStaticShadow { Species = 248, Level = 55, Gauge = 20000, Moves = new[] {242,087,157,059}, Location = 118 }, // Tyranitar: Cipher Head Evice @ Tower Colosseum
|
||||
new EncounterStaticShadow { Species = 235, Level = 45, Gauge = 07000, Moves = new[] {166,039,003,231}, Location = 132 }, // Smeargle: Team Snagem Biden @ Snagem Hideout
|
||||
new EncounterStaticShadow { Species = 217, Level = 45, Gauge = 07000, Moves = new[] {185,313,122,163}, Location = 132, Locks = Ursaring }, // Ursaring: Team Snagem Agrev @ Snagem Hideout
|
||||
new EncounterStaticShadow { Species = 213, Level = 45, Gauge = 07000, Moves = new[] {219,227,156,117}, Location = 125 }, // Shuckle: Deep King Agnol @ Deep Colosseum
|
||||
new EncounterStaticShadow { Species = 176, Level = 20, Gauge = 05000, Moves = new[] {118,204,186,281}, Location = 001 }, // Togetic: Cipher Peon Fein @ Outskirt Stand
|
||||
new EncounterStaticShadow { Species = 175, Level = 20, Gauge = 00000, Moves = new[] {118,204,186,281}, IVs = new[] {0,0,0,0,0,0}, EReader = true, Locks = CTogepi }, // Togepi: Chaser ボデス @ Card e Room (Japanese games only)
|
||||
new EncounterStaticShadow { Species = 179, Level = 37, Gauge = 00000, Moves = new[] {087,084,086,178}, IVs = new[] {0,0,0,0,0,0}, EReader = true, Locks = CMareep }, // Mareep: Hunter ホル @ Card e Room (Japanese games only)
|
||||
new EncounterStaticShadow { Species = 212, Level = 50, Gauge = 00000, Moves = new[] {210,232,014,163}, IVs = new[] {0,0,0,0,0,0}, EReader = true, Locks = CScizor }, // Scizor: Bodybuilder ワーバン @ Card e Room (Japanese games only)
|
||||
|
||||
new EncounterStaticShadow(Gligar) { Species = 207, Level = 43, Gauge = 06000, Moves = new[] {185,028,040,163}, Location = 058 }, // Gligar: Hunter Frena @ The Under Subway
|
||||
new EncounterStaticShadow(Gligar) { Species = 207, Level = 43, Gauge = 06000, Moves = new[] {185,028,040,163}, Location = 133 }, // Gligar: Hunter Frena @ Snagem Hideout
|
||||
new EncounterStaticShadow(Murkrow) { Species = 198, Level = 43, Gauge = 06000, Moves = new[] {185,212,101,019}, Location = 067 }, // Murkrow: Cipher Peon Lare @ Shadow PKMN Lab
|
||||
new EncounterStaticShadow(Heracross) { Species = 214, Level = 45, Gauge = 07000, Moves = new[] {179,203,068,280}, Location = 111, }, // Heracross: Cipher Peon Dioge @ Realgam Tower
|
||||
new EncounterStaticShadow(Ursaring) { Species = 217, Level = 45, Gauge = 07000, Moves = new[] {185,313,122,163}, Location = 132 }, // Ursaring: Team Snagem Agrev @ Snagem Hideout
|
||||
new EncounterStaticShadow(CTogepi) { Species = 175, Level = 20, Gauge = 00000, Moves = new[] {118,204,186,281}, IVs = new[] {0,0,0,0,0,0}, EReader = true }, // Togepi: Chaser ボデス @ Card e Room (Japanese games only)
|
||||
new EncounterStaticShadow(CMareep) { Species = 179, Level = 37, Gauge = 00000, Moves = new[] {087,084,086,178}, IVs = new[] {0,0,0,0,0,0}, EReader = true }, // Mareep: Hunter ホル @ Card e Room (Japanese games only)
|
||||
new EncounterStaticShadow(CScizor) { Species = 212, Level = 50, Gauge = 00000, Moves = new[] {210,232,014,163}, IVs = new[] {0,0,0,0,0,0}, EReader = true }, // Scizor: Bodybuilder ワーバン @ Card e Room (Japanese games only)
|
||||
};
|
||||
#endregion
|
||||
|
||||
|
@ -474,113 +482,113 @@ namespace PKHeX.Core
|
|||
new EncounterStatic { Fateful = true, Gift = true, Species = 158, Level = 05, Location = 016, Moves = new[] {242,010,043,308} }, // Totodile
|
||||
|
||||
new EncounterStaticShadow { Fateful = true, Species = 216, Level = 11, Gauge = 03000, Moves = new[] {216,287,122,232}, Location = 143 }, // Teddiursa: Cipher Peon Naps @ Pokémon HQ Lab
|
||||
new EncounterStaticShadow { Fateful = true, Species = 165, Level = 10, Gauge = 02500, Moves = new[] {060,287,332,048}, Location = 153, Locks = Ledyba, }, // Ledyba: Casual Guy Cyle @ Gateon Port
|
||||
new EncounterStaticShadow { Fateful = true, Species = 261, Level = 10, Gauge = 02500, Moves = new[] {091,215,305,336}, Location = 162, Locks = Poochyena, }, // Poochyena: Bodybuilder Kilen @ Gateon Port
|
||||
new EncounterStaticShadow { Fateful = true, Species = 228, Level = 17, Gauge = 01500, Moves = new[] {185,204,052,046}, Location = 011, }, // Houndour: Cipher Peon Resix @ Cipher Lab
|
||||
new EncounterStaticShadow { Fateful = true, Species = 343, Level = 17, Gauge = 01500, Moves = new[] {317,287,189,060}, Location = 011, }, // Baltoy: Cipher Peon Browsix @ Cipher Lab
|
||||
new EncounterStaticShadow { Fateful = true, Species = 179, Level = 17, Gauge = 01500, Moves = new[] {034,215,084,086}, Location = 011, }, // Mareep: Cipher Peon Yellosix @ Cipher Lab
|
||||
new EncounterStaticShadow { Fateful = true, Species = 273, Level = 17, Gauge = 01500, Moves = new[] {202,287,331,290}, Location = 011, Locks = Seedot, }, // Seedot: Cipher Peon Greesix @ Cipher Lab
|
||||
new EncounterStaticShadow { Fateful = true, Species = 363, Level = 17, Gauge = 01500, Moves = new[] {062,204,055,189}, Location = 011, Locks = Spheal, }, // Spheal: Cipher Peon Blusix @ Cipher Lab
|
||||
new EncounterStaticShadow { Fateful = true, Species = 316, Level = 17, Gauge = 01500, Moves = new[] {351,047,124,092}, Location = 011, Locks = Gulpin, }, // Gulpin: Cipher Peon Purpsix @ Cipher Lab
|
||||
new EncounterStaticShadow { Fateful = true, Species = 167, Level = 14, Gauge = 01500, Moves = new[] {091,287,324,101}, Location = 010, Locks = Spinarak, }, // Spinarak: Cipher Peon Nexir @ Cipher Lab
|
||||
new EncounterStaticShadow { Fateful = true, Species = 322, Level = 14, Gauge = 01500, Moves = new[] {036,204,091,052}, Location = 009, Locks = Numel, }, // Numel: Cipher Peon Solox @ Cipher Lab
|
||||
new EncounterStaticShadow { Fateful = true, Species = 318, Level = 15, Gauge = 01700, Moves = new[] {352,287,184,044}, Location = 008, }, // Carvanha: Cipher Peon Cabol @ Cipher Lab
|
||||
new EncounterStaticShadow { Fateful = true, Species = 285, Level = 15, Gauge = 01800, Moves = new[] {206,287,072,078}, Location = 008, Locks = Shroomish, }, // Shroomish: Cipher R&D Klots @ Cipher Lab
|
||||
new EncounterStaticShadow { Fateful = true, Species = 301, Level = 18, Gauge = 02500, Moves = new[] {290,186,213,351}, Location = 008, Locks = Delcatty, }, // Delcatty: Cipher Admin Lovrina @ Cipher Lab
|
||||
new EncounterStaticShadow { Fateful = true, Species = 100, Level = 19, Gauge = 02500, Moves = new[] {243,287,209,129}, Location = 092, Locks = Voltorb, }, // Voltorb: Wanderer Miror B. @ Cave Poké Spot
|
||||
new EncounterStaticShadow { Fateful = true, Species = 296, Level = 18, Gauge = 02000, Moves = new[] {280,287,292,317}, Location = 109, Locks = Makuhita, }, // Makuhita: Cipher Peon Torkin @ ONBS Building
|
||||
new EncounterStaticShadow { Fateful = true, Species = 037, Level = 18, Gauge = 02000, Moves = new[] {257,204,052,091}, Location = 109, Locks = Vulpix, }, // Vulpix: Cipher Peon Mesin @ ONBS Building
|
||||
new EncounterStaticShadow { Fateful = true, Species = 355, Level = 19, Gauge = 02200, Moves = new[] {247,270,310,109}, Location = 110, Locks = Duskull, }, // Duskull: Cipher Peon Lobar @ ONBS Building
|
||||
new EncounterStaticShadow { Fateful = true, Species = 280, Level = 20, Gauge = 02200, Moves = new[] {351,047,115,093}, Location = 119, Locks = Ralts, }, // Ralts: Cipher Peon Feldas @ ONBS Building
|
||||
new EncounterStaticShadow { Fateful = true, Species = 303, Level = 22, Gauge = 02500, Moves = new[] {206,047,011,334}, Location = 111, Locks = Mawile, }, // Mawile: Cipher Cmdr Exol @ ONBS Building
|
||||
new EncounterStaticShadow { Fateful = true, Species = 361, Level = 20, Gauge = 02500, Moves = new[] {352,047,044,196}, Location = 097, Locks = Snorunt }, // Snorunt: Cipher Peon Exinn @ Phenac City
|
||||
new EncounterStaticShadow { Fateful = true, Species = 204, Level = 20, Gauge = 02500, Moves = new[] {042,287,191,068}, Location = 096, Locks = Pineco, }, // Pineco: Cipher Peon Gonrap @ Phenac City
|
||||
new EncounterStaticShadow { Fateful = true, Species = 177, Level = 22, Gauge = 02500, Moves = new[] {248,226,101,332}, Location = 094, Locks = Natu, }, // Natu: Cipher Peon Eloin @ Phenac City
|
||||
|
||||
new EncounterStaticShadow { Fateful = true, Species = 315, Level = 22, Gauge = 03000, Moves = new[] {345,186,320,073}, Location = 113, Locks = Roselia }, // Roselia: Cipher Peon Fasin @ Phenac City
|
||||
new EncounterStaticShadow { Fateful = true, Species = 315, Level = 22, Gauge = 03000, Moves = new[] {345,186,320,073}, Location = 094, Locks = Roselia }, // Roselia: Cipher Peon Fasin @ Phenac City
|
||||
new EncounterStaticShadow { Fateful = true, Species = 052, Level = 22, Gauge = 03500, Moves = new[] {163,047,006,044}, Location = 113, Locks = Meowth }, // Meowth: Cipher Peon Fostin @ Phenac City
|
||||
new EncounterStaticShadow { Fateful = true, Species = 052, Level = 22, Gauge = 03500, Moves = new[] {163,047,006,044}, Location = 094, Locks = Meowth }, // Meowth: Cipher Peon Fostin @ Phenac City
|
||||
|
||||
new EncounterStaticShadow { Fateful = true, Species = 220, Level = 22, Gauge = 02500, Moves = new[] {246,204,054,341}, Location = 100, Locks = Swinub }, // Swinub: Cipher Peon Greck @ Phenac City
|
||||
|
||||
new EncounterStaticShadow { Fateful = true, Species = 021, Level = 22, Gauge = 04500, Moves = new[] {206,226,043,332}, Location = 059, Locks = Spearow }, // Spearow: Cipher Peon Ezin @ Phenac Stadium
|
||||
new EncounterStaticShadow { Fateful = true, Species = 021, Level = 22, Gauge = 04500, Moves = new[] {206,226,043,332}, Location = 107, Locks = Spearow }, // Spearow: Cipher Peon Ezin @ Phenac Stadium
|
||||
new EncounterStaticShadow { Fateful = true, Species = 088, Level = 23, Gauge = 03000, Moves = new[] {188,270,325,107}, Location = 059, Locks = Grimer }, // Grimer: Cipher Peon Faltly @ Phenac Stadium
|
||||
new EncounterStaticShadow { Fateful = true, Species = 088, Level = 23, Gauge = 03000, Moves = new[] {188,270,325,107}, Location = 107, Locks = Grimer }, // Grimer: Cipher Peon Faltly @ Phenac Stadium
|
||||
|
||||
new EncounterStaticShadow { Fateful = true, Species = 086, Level = 23, Gauge = 03500, Moves = new[] {057,270,219,058}, Location = 107, Locks = Seel }, // Seel: Cipher Peon Egrog @ Phenac Stadium
|
||||
new EncounterStaticShadow { Fateful = true, Species = 337, Level = 25, Gauge = 05000, Moves = new[] {094,226,240,317}, Location = 107, Locks = Lunatone }, // Lunatone: Cipher Admin Snattle @ Phenac Stadium
|
||||
new EncounterStaticShadow { Fateful = true, Species = 175, Level = 25, Gauge = 04500, Moves = new[] {266,161,246,270}, Location = 164, Gift = true }, // Togepi: Pokémon Trainer Hordel @ Outskirt Stand
|
||||
|
||||
new EncounterStaticShadow { Fateful = true, Species = 299, Level = 26, Gauge = 04000, Moves = new[] {085,270,086,157}, Location = 090, Locks = Nosepass }, // Nosepass: Wanderer Miror B. @ Pyrite Colosseum/Realgam Colosseum/Poké Spots
|
||||
new EncounterStaticShadow { Fateful = true, Species = 299, Level = 26, Gauge = 04000, Moves = new[] {085,270,086,157}, Location = 113, Locks = Nosepass }, // Nosepass: Wanderer Miror B. @ Pyrite Colosseum/Realgam Colosseum/Poké Spots
|
||||
|
||||
new EncounterStaticShadow { Fateful = true, Species = 335, Level = 28, Gauge = 05000, Moves = new[] {280,287,068,306}, Location = 071 }, // Zangoose: Thug Zook @ Cipher Key Lair
|
||||
new EncounterStaticShadow { Fateful = true, Species = 335, Level = 28, Gauge = 05000, Moves = new[] {280,287,068,306}, Location = 090 }, // Zangoose: Thug Zook @ Cipher Key Lair
|
||||
|
||||
new EncounterStaticShadow { Fateful = true, Species = 046, Level = 28, Gauge = 04000, Moves = new[] {147,287,163,206}, Location = 064, Locks = Paras }, // Paras: Cipher Peon Humah @ Cipher Key Lair
|
||||
|
||||
new EncounterStaticShadow { Fateful = true, Species = 058, Level = 28, Gauge = 04000, Moves = new[] {053,204,044,036}, Location = 064, Locks = Growlithe }, // Growlithe: Cipher Peon Humah @ Cipher Key Lair
|
||||
new EncounterStaticShadow { Fateful = true, Species = 058, Level = 28, Gauge = 04000, Moves = new[] {053,204,044,036}, Location = 113, Locks = Growlithe }, // Growlithe: Cipher Peon Humah @ Cipher Key Lair
|
||||
|
||||
new EncounterStaticShadow { Fateful = true, Species = 015, Level = 30, Gauge = 04500, Moves = new[] {188,226,041,014}, Location = 059 }, // Beedrill: Cipher Peon Lok @ Cipher Key Lair
|
||||
new EncounterStaticShadow { Fateful = true, Species = 012, Level = 30, Gauge = 04000, Moves = new[] {094,234,079,332}, Location = 059, Locks = Butterfree }, // Butterfree: Cipher Peon Targ @ Cipher Key Lair
|
||||
new EncounterStaticShadow { Fateful = true, Species = 049, Level = 32, Gauge = 04000, Moves = new[] {318,287,164,094}, Location = 059, Locks = Venomoth }, // Venomoth: Cipher Peon Angic @ Cipher Key Lair
|
||||
new EncounterStaticShadow { Fateful = true, Species = 097, Level = 34, Gauge = 05500, Moves = new[] {094,226,096,247}, Location = 059, Locks = Hypno }, // Hypno: Cipher Admin Gorigan @ Cipher Key Lair
|
||||
new EncounterStaticShadow { Fateful = true, Species = 354, Level = 37, Gauge = 07000, Moves = new[] {185,270,247,174}, Location = 059, Locks = Banette }, // Banette: Cipher Peon Litnar @ Citadark Isle
|
||||
|
||||
new EncounterStaticShadow { Fateful = true, Species = 090, Level = 29, Gauge = 04000, Moves = new[] {036,287,057,062}, Location = 065 }, // Shellder: Cipher Peon Gorog @ Cipher Key Lair
|
||||
new EncounterStaticShadow { Fateful = true, Species = 015, Level = 30, Gauge = 04500, Moves = new[] {188,226,041,014}, Location = 066 }, // Beedrill: Cipher Peon Lok @ Cipher Key Lair
|
||||
new EncounterStaticShadow { Fateful = true, Species = 017, Level = 30, Gauge = 04000, Moves = new[] {017,287,211,297}, Location = 066, Locks = Pidgeotto }, // Pidgeotto: Cipher Peon Lok @ Cipher Key Lair
|
||||
new EncounterStaticShadow { Fateful = true, Species = 114, Level = 30, Gauge = 04000, Moves = new[] {076,234,241,275}, Location = 067, Locks = Tangela }, // Tangela: Cipher Peon Targ @ Cipher Key Lair
|
||||
new EncounterStaticShadow { Fateful = true, Species = 012, Level = 30, Gauge = 04000, Moves = new[] {094,234,079,332}, Location = 067, Locks = Butterfree }, // Butterfree: Cipher Peon Targ @ Cipher Key Lair
|
||||
new EncounterStaticShadow { Fateful = true, Species = 082, Level = 30, Gauge = 04500, Moves = new[] {038,287,240,087}, Location = 067, Locks = Magneton }, // Magneton: Cipher Peon Snidle @ Cipher Key Lair
|
||||
new EncounterStaticShadow { Fateful = true, Species = 049, Level = 32, Gauge = 04000, Moves = new[] {318,287,164,094}, Location = 070, Locks = Venomoth }, // Venomoth: Cipher Peon Angic @ Cipher Key Lair
|
||||
new EncounterStaticShadow { Fateful = true, Species = 070, Level = 32, Gauge = 04000, Moves = new[] {345,234,188,230}, Location = 070, Locks = Weepinbell }, // Weepinbell: Cipher Peon Angic @ Cipher Key Lair
|
||||
new EncounterStaticShadow { Fateful = true, Species = 024, Level = 33, Gauge = 05000, Moves = new[] {188,287,137,044}, Location = 070, Locks = Arbok }, // Arbok: Cipher Peon Smarton @ Cipher Key Lair
|
||||
new EncounterStaticShadow { Fateful = true, Species = 057, Level = 34, Gauge = 06000, Moves = new[] {238,270,116,179}, Location = 069, Locks = Primeape }, // Primeape: Cipher Admin Gorigan @ Cipher Key Lair
|
||||
new EncounterStaticShadow { Fateful = true, Species = 097, Level = 34, Gauge = 05500, Moves = new[] {094,226,096,247}, Location = 069, Locks = Hypno }, // Hypno: Cipher Admin Gorigan @ Cipher Key Lair
|
||||
new EncounterStaticShadow { Fateful = true, Species = 055, Level = 33, Gauge = 06500, Moves = new[] {127,204,244,280}, Location = 088, Locks = Golduck }, // Golduck: Navigator Abson @ Citadark Isle
|
||||
new EncounterStaticShadow { Fateful = true, Species = 302, Level = 33, Gauge = 07000, Moves = new[] {247,270,185,105}, Location = 088, Locks = Sableye }, // Sableye: Navigator Abson @ Citadark Isle
|
||||
new EncounterStaticShadow { Fateful = true, Species = 085, Level = 34, Gauge = 08000, Moves = new[] {065,226,097,161}, Location = 076, Locks = Dodrio }, // Dodrio: Chaser Furgy @ Citadark Isle
|
||||
new EncounterStaticShadow { Fateful = true, Species = 020, Level = 34, Gauge = 06000, Moves = new[] {162,287,184,158}, Location = 076, Locks = Raticate }, // Raticate: Chaser Furgy @ Citadark Isle
|
||||
new EncounterStaticShadow { Fateful = true, Species = 083, Level = 36, Gauge = 05500, Moves = new[] {163,226,014,332}, Location = 076, Locks = Farfetchd }, // Farfetch'd: Cipher Admin Lovrina @ Citadark Isle
|
||||
new EncounterStaticShadow { Fateful = true, Species = 334, Level = 36, Gauge = 06500, Moves = new[] {225,215,076,332}, Location = 076, Locks = Altaria }, // Altaria: Cipher Admin Lovrina @ Citadark Isle
|
||||
new EncounterStaticShadow { Fateful = true, Species = 115, Level = 35, Gauge = 06000, Moves = new[] {089,047,039,146}, Location = 085, Locks = Kangaskhan }, // Kangaskhan: Cipher Peon Litnar @ Citadark Isle
|
||||
new EncounterStaticShadow { Fateful = true, Species = 354, Level = 37, Gauge = 07000, Moves = new[] {185,270,247,174}, Location = 085, Locks = Banette }, // Banette: Cipher Peon Litnar @ Citadark Isle
|
||||
new EncounterStaticShadow { Fateful = true, Species = 126, Level = 36, Gauge = 07000, Moves = new[] {126,266,238,009}, Location = 077, Locks = Magmar }, // Magmar: Cipher Peon Grupel @ Citadark Isle
|
||||
new EncounterStaticShadow { Fateful = true, Species = 127, Level = 35, Gauge = 07000, Moves = new[] {012,270,206,066}, Location = 077, Locks = Pinsir }, // Pinsir: Cipher Peon Grupel @ Citadark Isle
|
||||
new EncounterStaticShadow { Fateful = true, Species = 078, Level = 40, Gauge = 06000, Moves = new[] {076,226,241,053}, Location = 080, Locks = Rapidash }, // Rapidash: Cipher Peon Kolest @ Citadark Isle
|
||||
new EncounterStaticShadow { Fateful = true, Species = 219, Level = 38, Gauge = 05500, Moves = new[] {257,287,089,053}, Location = 080, Locks = Magcargo }, // Magcargo: Cipher Peon Kolest @ Citadark Isle
|
||||
new EncounterStaticShadow { Fateful = true, Species = 107, Level = 38, Gauge = 06000, Moves = new[] {005,270,170,327}, Location = 081, Locks = Hitmonchan }, // Hitmonchan: Cipher Peon Karbon @ Citadark Isle
|
||||
new EncounterStaticShadow { Fateful = true, Species = 106, Level = 38, Gauge = 07000, Moves = new[] {136,287,170,025}, Location = 081, Locks = Hitmonlee }, // Hitmonlee: Cipher Peon Petro @ Citadark Isle
|
||||
new EncounterStaticShadow { Fateful = true, Species = 108, Level = 38, Gauge = 05000, Moves = new[] {038,270,111,205}, Location = 084, Locks = Lickitung }, // Lickitung: Cipher Peon Geftal @ Citadark Isle
|
||||
new EncounterStaticShadow { Fateful = true, Species = 123, Level = 40, Gauge = 08000, Moves = new[] {013,234,318,163}, Location = 084, Locks = Scyther }, // Scyther: Cipher Peon Leden @ Citadark Isle
|
||||
|
||||
new EncounterStaticShadow { Fateful = true, Species = 113, Level = 39, Gauge = 04000, Moves = new[] {085,186,135,285}, Location = 084, Locks = Chansey }, // Chansey: Cipher Peon Leden @ Citadark Isle
|
||||
new EncounterStaticShadow { Fateful = true, Species = 113, Level = 39, Gauge = 04000, Moves = new[] {085,186,135,285}, Location = 087, Locks = Chansey }, // Chansey: Cipher Peon Leden @ Citadark Isle
|
||||
|
||||
new EncounterStaticShadow { Fateful = true, Species = 338, Level = 41, Gauge = 07500, Moves = new[] {094,226,241,322}, Location = 087, Locks = Solrock }, // Solrock: Cipher Admin Snattle @ Citadark Isle
|
||||
new EncounterStaticShadow { Fateful = true, Species = 121, Level = 41, Gauge = 07500, Moves = new[] {127,287,058,105}, Location = 087, Locks = Starmie }, // Starmie: Cipher Admin Snattle @ Citadark Isle
|
||||
new EncounterStaticShadow { Fateful = true, Species = 277, Level = 43, Gauge = 07000, Moves = new[] {143,226,097,263}, Location = 087 }, // Swellow: Cipher Admin Ardos @ Citadark Isle
|
||||
new EncounterStaticShadow { Fateful = true, Species = 125, Level = 43, Gauge = 07000, Moves = new[] {238,266,086,085}, Location = 087, Locks = Electabuzz }, // Electabuzz: Cipher Admin Ardos @ Citadark Isle
|
||||
new EncounterStaticShadow { Fateful = true, Species = 143, Level = 43, Gauge = 09000, Moves = new[] {090,287,174,034}, Location = 087, Locks = Snorlax }, // Snorlax: Cipher Admin Ardos @ Citadark Isle
|
||||
new EncounterStaticShadow { Fateful = true, Species = 062, Level = 42, Gauge = 07500, Moves = new[] {056,270,240,280}, Location = 087, Locks = Poliwrath }, // Poliwrath: Cipher Admin Gorigan @ Citadark Isle
|
||||
new EncounterStaticShadow { Fateful = true, Species = 122, Level = 42, Gauge = 06500, Moves = new[] {094,266,227,009}, Location = 087, Locks = MrMime }, // Mr. Mime: Cipher Admin Gorigan @ Citadark Isle
|
||||
new EncounterStaticShadow { Fateful = true, Species = 051, Level = 40, Gauge = 05000, Moves = new[] {089,204,201,161}, Location = 075, Locks = Dugtrio }, // Dugtrio: Cipher Peon Kolax @ Citadark Isle
|
||||
new EncounterStaticShadow { Fateful = true, Species = 310, Level = 44, Gauge = 07000, Moves = new[] {087,287,240,044}, Location = 073, Locks = Manectric }, // Manectric: Cipher Admin Eldes @ Citadark Isle
|
||||
new EncounterStaticShadow { Fateful = true, Species = 373, Level = 50, Gauge = 09000, Moves = new[] {337,287,349,332}, Location = 073, Locks = Salamence }, // Salamence: Cipher Admin Eldes @ Citadark Isle
|
||||
new EncounterStaticShadow { Fateful = true, Species = 105, Level = 44, Gauge = 06500, Moves = new[] {089,047,014,157}, Location = 073, Locks = Marowak }, // Marowak: Cipher Admin Eldes @ Citadark Isle
|
||||
new EncounterStaticShadow { Fateful = true, Species = 131, Level = 44, Gauge = 06000, Moves = new[] {056,215,240,059}, Location = 073, Locks = Lapras }, // Lapras: Cipher Admin Eldes @ Citadark Isle
|
||||
new EncounterStaticShadow { Fateful = true, Species = 249, Level = 50, Gauge = 12000, Moves = new[] {354,297,089,056}, Location = 074 }, // Lugia: Grand Master Greevil @ Citadark Isle
|
||||
new EncounterStaticShadow { Fateful = true, Species = 112, Level = 46, Gauge = 07000, Moves = new[] {224,270,184,089}, Location = 074 }, // Rhydon: Grand Master Greevil @ Citadark Isle
|
||||
new EncounterStaticShadow { Fateful = true, Species = 146, Level = 50, Gauge = 10000, Moves = new[] {326,234,261,053}, Location = 074, Locks = Moltres }, // Moltres: Grand Master Greevil @ Citadark Isle
|
||||
new EncounterStaticShadow { Fateful = true, Species = 103, Level = 46, Gauge = 09000, Moves = new[] {094,287,095,246}, Location = 074, Locks = Exeggutor }, // Exeggutor: Grand Master Greevil @ Citadark Isle
|
||||
new EncounterStaticShadow { Fateful = true, Species = 128, Level = 46, Gauge = 09000, Moves = new[] {089,287,039,034}, Location = 074, Locks = Tauros }, // Tauros: Grand Master Greevil @ Citadark Isle
|
||||
new EncounterStaticShadow { Fateful = true, Species = 144, Level = 50, Gauge = 10000, Moves = new[] {326,215,114,058}, Location = 074, Locks = Articuno }, // Articuno: Grand Master Greevil @ Citadark Isle
|
||||
new EncounterStaticShadow { Fateful = true, Species = 145, Level = 50, Gauge = 10000, Moves = new[] {326,226,319,085}, Location = 074, Locks = Zapdos }, // Zapdos: Grand Master Greevil @ Citadark Isle
|
||||
new EncounterStaticShadow { Fateful = true, Species = 149, Level = 55, Gauge = 09000, Moves = new[] {063,215,349,089}, Location = 162, Locks = Dragonite }, // Dragonite: Wanderer Miror B. @ Gateon Port
|
||||
new EncounterStaticShadow { Fateful = true, Species = 277, Level = 43, Gauge = 07000, Moves = new[] {143,226,097,263}, Location = 087 }, // Swellow: Cipher Admin Ardos @ Citadark Isle
|
||||
|
||||
new EncounterStaticShadow(Ledyba) { Fateful = true, Species = 165, Level = 10, Gauge = 02500, Moves = new[] {060,287,332,048}, Location = 153 }, // Ledyba: Casual Guy Cyle @ Gateon Port
|
||||
new EncounterStaticShadow(Poochyena){ Fateful = true, Species = 261, Level = 10, Gauge = 02500, Moves = new[] {091,215,305,336}, Location = 162 }, // Poochyena: Bodybuilder Kilen @ Gateon Port
|
||||
new EncounterStaticShadow(Seedot) { Fateful = true, Species = 273, Level = 17, Gauge = 01500, Moves = new[] {202,287,331,290}, Location = 011 }, // Seedot: Cipher Peon Greesix @ Cipher Lab
|
||||
new EncounterStaticShadow(Spheal) { Fateful = true, Species = 363, Level = 17, Gauge = 01500, Moves = new[] {062,204,055,189}, Location = 011 }, // Spheal: Cipher Peon Blusix @ Cipher Lab
|
||||
new EncounterStaticShadow(Gulpin) { Fateful = true, Species = 316, Level = 17, Gauge = 01500, Moves = new[] {351,047,124,092}, Location = 011 }, // Gulpin: Cipher Peon Purpsix @ Cipher Lab
|
||||
new EncounterStaticShadow(Spinarak) { Fateful = true, Species = 167, Level = 14, Gauge = 01500, Moves = new[] {091,287,324,101}, Location = 010 }, // Spinarak: Cipher Peon Nexir @ Cipher Lab
|
||||
new EncounterStaticShadow(Numel) { Fateful = true, Species = 322, Level = 14, Gauge = 01500, Moves = new[] {036,204,091,052}, Location = 009 }, // Numel: Cipher Peon Solox @ Cipher Lab
|
||||
new EncounterStaticShadow(Shroomish){ Fateful = true, Species = 285, Level = 15, Gauge = 01800, Moves = new[] {206,287,072,078}, Location = 008 }, // Shroomish: Cipher R&D Klots @ Cipher Lab
|
||||
new EncounterStaticShadow(Delcatty) { Fateful = true, Species = 301, Level = 18, Gauge = 02500, Moves = new[] {290,186,213,351}, Location = 008 }, // Delcatty: Cipher Admin Lovrina @ Cipher Lab
|
||||
new EncounterStaticShadow(Voltorb) { Fateful = true, Species = 100, Level = 19, Gauge = 02500, Moves = new[] {243,287,209,129}, Location = 092 }, // Voltorb: Wanderer Miror B. @ Cave Poké Spot
|
||||
new EncounterStaticShadow(Makuhita) { Fateful = true, Species = 296, Level = 18, Gauge = 02000, Moves = new[] {280,287,292,317}, Location = 109 }, // Makuhita: Cipher Peon Torkin @ ONBS Building
|
||||
new EncounterStaticShadow(Vulpix) { Fateful = true, Species = 037, Level = 18, Gauge = 02000, Moves = new[] {257,204,052,091}, Location = 109 }, // Vulpix: Cipher Peon Mesin @ ONBS Building
|
||||
new EncounterStaticShadow(Duskull) { Fateful = true, Species = 355, Level = 19, Gauge = 02200, Moves = new[] {247,270,310,109}, Location = 110 }, // Duskull: Cipher Peon Lobar @ ONBS Building
|
||||
new EncounterStaticShadow(Ralts) { Fateful = true, Species = 280, Level = 20, Gauge = 02200, Moves = new[] {351,047,115,093}, Location = 119 }, // Ralts: Cipher Peon Feldas @ ONBS Building
|
||||
new EncounterStaticShadow(Mawile) { Fateful = true, Species = 303, Level = 22, Gauge = 02500, Moves = new[] {206,047,011,334}, Location = 111 }, // Mawile: Cipher Cmdr Exol @ ONBS Building
|
||||
new EncounterStaticShadow(Snorunt) { Fateful = true, Species = 361, Level = 20, Gauge = 02500, Moves = new[] {352,047,044,196}, Location = 097 }, // Snorunt: Cipher Peon Exinn @ Phenac City
|
||||
new EncounterStaticShadow(Pineco) { Fateful = true, Species = 204, Level = 20, Gauge = 02500, Moves = new[] {042,287,191,068}, Location = 096 }, // Pineco: Cipher Peon Gonrap @ Phenac City
|
||||
new EncounterStaticShadow(Natu) { Fateful = true, Species = 177, Level = 22, Gauge = 02500, Moves = new[] {248,226,101,332}, Location = 094 }, // Natu: Cipher Peon Eloin @ Phenac City
|
||||
|
||||
new EncounterStaticShadow(Roselia) { Fateful = true, Species = 315, Level = 22, Gauge = 03000, Moves = new[] {345,186,320,073}, Location = 113, }, // Roselia: Cipher Peon Fasin @ Phenac City
|
||||
new EncounterStaticShadow(Roselia) { Fateful = true, Species = 315, Level = 22, Gauge = 03000, Moves = new[] {345,186,320,073}, Location = 094, }, // Roselia: Cipher Peon Fasin @ Phenac City
|
||||
new EncounterStaticShadow(Meowth) { Fateful = true, Species = 052, Level = 22, Gauge = 03500, Moves = new[] {163,047,006,044}, Location = 113, }, // Meowth: Cipher Peon Fostin @ Phenac City
|
||||
new EncounterStaticShadow(Meowth) { Fateful = true, Species = 052, Level = 22, Gauge = 03500, Moves = new[] {163,047,006,044}, Location = 094, }, // Meowth: Cipher Peon Fostin @ Phenac City
|
||||
|
||||
new EncounterStaticShadow(Swinub) { Fateful = true, Species = 220, Level = 22, Gauge = 02500, Moves = new[] {246,204,054,341}, Location = 100, }, // Swinub: Cipher Peon Greck @ Phenac City
|
||||
|
||||
new EncounterStaticShadow(Spearow) { Fateful = true, Species = 021, Level = 22, Gauge = 04500, Moves = new[] {206,226,043,332}, Location = 059, }, // Spearow: Cipher Peon Ezin @ Phenac Stadium
|
||||
new EncounterStaticShadow(Spearow) { Fateful = true, Species = 021, Level = 22, Gauge = 04500, Moves = new[] {206,226,043,332}, Location = 107, }, // Spearow: Cipher Peon Ezin @ Phenac Stadium
|
||||
new EncounterStaticShadow(Grimer) { Fateful = true, Species = 088, Level = 23, Gauge = 03000, Moves = new[] {188,270,325,107}, Location = 059, }, // Grimer: Cipher Peon Faltly @ Phenac Stadium
|
||||
new EncounterStaticShadow(Grimer) { Fateful = true, Species = 088, Level = 23, Gauge = 03000, Moves = new[] {188,270,325,107}, Location = 107, }, // Grimer: Cipher Peon Faltly @ Phenac Stadium
|
||||
|
||||
new EncounterStaticShadow(Seel) { Fateful = true, Species = 086, Level = 23, Gauge = 03500, Moves = new[] {057,270,219,058}, Location = 107, }, // Seel: Cipher Peon Egrog @ Phenac Stadium
|
||||
new EncounterStaticShadow(Lunatone) { Fateful = true, Species = 337, Level = 25, Gauge = 05000, Moves = new[] {094,226,240,317}, Location = 107, }, // Lunatone: Cipher Admin Snattle @ Phenac Stadium
|
||||
|
||||
new EncounterStaticShadow(Nosepass) { Fateful = true, Species = 299, Level = 26, Gauge = 04000, Moves = new[] {085,270,086,157}, Location = 090, }, // Nosepass: Wanderer Miror B. @ Pyrite Colosseum/Realgam Colosseum/Poké Spots
|
||||
new EncounterStaticShadow(Nosepass) { Fateful = true, Species = 299, Level = 26, Gauge = 04000, Moves = new[] {085,270,086,157}, Location = 113, }, // Nosepass: Wanderer Miror B. @ Pyrite Colosseum/Realgam Colosseum/Poké Spots
|
||||
|
||||
new EncounterStaticShadow(Paras) { Fateful = true, Species = 046, Level = 28, Gauge = 04000, Moves = new[] {147,287,163,206}, Location = 064, }, // Paras: Cipher Peon Humah @ Cipher Key Lair
|
||||
|
||||
new EncounterStaticShadow(Growlithe) { Fateful = true, Species = 058, Level = 28, Gauge = 04000, Moves = new[] {053,204,044,036}, Location = 064 }, // Growlithe: Cipher Peon Humah @ Cipher Key Lair
|
||||
new EncounterStaticShadow(Growlithe) { Fateful = true, Species = 058, Level = 28, Gauge = 04000, Moves = new[] {053,204,044,036}, Location = 113 }, // Growlithe: Cipher Peon Humah @ Cipher Key Lair
|
||||
new EncounterStaticShadow(Butterfree){ Fateful = true, Species = 012, Level = 30, Gauge = 04000, Moves = new[] {094,234,079,332}, Location = 059, }, // Butterfree: Cipher Peon Targ @ Cipher Key Lair
|
||||
new EncounterStaticShadow(Venomoth) { Fateful = true, Species = 049, Level = 32, Gauge = 04000, Moves = new[] {318,287,164,094}, Location = 059, }, // Venomoth: Cipher Peon Angic @ Cipher Key Lair
|
||||
new EncounterStaticShadow(Hypno) { Fateful = true, Species = 097, Level = 34, Gauge = 05500, Moves = new[] {094,226,096,247}, Location = 059, }, // Hypno: Cipher Admin Gorigan @ Cipher Key Lair
|
||||
new EncounterStaticShadow(Banette) { Fateful = true, Species = 354, Level = 37, Gauge = 07000, Moves = new[] {185,270,247,174}, Location = 059, }, // Banette: Cipher Peon Litnar @ Citadark Isle
|
||||
|
||||
new EncounterStaticShadow(Pidgeotto) { Fateful = true, Species = 017, Level = 30, Gauge = 04000, Moves = new[] {017,287,211,297}, Location = 066, }, // Pidgeotto: Cipher Peon Lok @ Cipher Key Lair
|
||||
new EncounterStaticShadow(Tangela) { Fateful = true, Species = 114, Level = 30, Gauge = 04000, Moves = new[] {076,234,241,275}, Location = 067, }, // Tangela: Cipher Peon Targ @ Cipher Key Lair
|
||||
new EncounterStaticShadow(Butterfree){ Fateful = true, Species = 012, Level = 30, Gauge = 04000, Moves = new[] {094,234,079,332}, Location = 067, }, // Butterfree: Cipher Peon Targ @ Cipher Key Lair
|
||||
new EncounterStaticShadow(Magneton) { Fateful = true, Species = 082, Level = 30, Gauge = 04500, Moves = new[] {038,287,240,087}, Location = 067, }, // Magneton: Cipher Peon Snidle @ Cipher Key Lair
|
||||
new EncounterStaticShadow(Venomoth) { Fateful = true, Species = 049, Level = 32, Gauge = 04000, Moves = new[] {318,287,164,094}, Location = 070, }, // Venomoth: Cipher Peon Angic @ Cipher Key Lair
|
||||
new EncounterStaticShadow(Weepinbell){ Fateful = true, Species = 070, Level = 32, Gauge = 04000, Moves = new[] {345,234,188,230}, Location = 070, }, // Weepinbell: Cipher Peon Angic @ Cipher Key Lair
|
||||
new EncounterStaticShadow(Arbok) { Fateful = true, Species = 024, Level = 33, Gauge = 05000, Moves = new[] {188,287,137,044}, Location = 070, }, // Arbok: Cipher Peon Smarton @ Cipher Key Lair
|
||||
new EncounterStaticShadow(Primeape) { Fateful = true, Species = 057, Level = 34, Gauge = 06000, Moves = new[] {238,270,116,179}, Location = 069, }, // Primeape: Cipher Admin Gorigan @ Cipher Key Lair
|
||||
new EncounterStaticShadow(Hypno) { Fateful = true, Species = 097, Level = 34, Gauge = 05500, Moves = new[] {094,226,096,247}, Location = 069, }, // Hypno: Cipher Admin Gorigan @ Cipher Key Lair
|
||||
new EncounterStaticShadow(Golduck) { Fateful = true, Species = 055, Level = 33, Gauge = 06500, Moves = new[] {127,204,244,280}, Location = 088, }, // Golduck: Navigator Abson @ Citadark Isle
|
||||
new EncounterStaticShadow(Sableye) { Fateful = true, Species = 302, Level = 33, Gauge = 07000, Moves = new[] {247,270,185,105}, Location = 088, }, // Sableye: Navigator Abson @ Citadark Isle
|
||||
new EncounterStaticShadow(Dodrio) { Fateful = true, Species = 085, Level = 34, Gauge = 08000, Moves = new[] {065,226,097,161}, Location = 076, }, // Dodrio: Chaser Furgy @ Citadark Isle
|
||||
new EncounterStaticShadow(Raticate) { Fateful = true, Species = 020, Level = 34, Gauge = 06000, Moves = new[] {162,287,184,158}, Location = 076, }, // Raticate: Chaser Furgy @ Citadark Isle
|
||||
new EncounterStaticShadow(Farfetchd) { Fateful = true, Species = 083, Level = 36, Gauge = 05500, Moves = new[] {163,226,014,332}, Location = 076, }, // Farfetch'd: Cipher Admin Lovrina @ Citadark Isle
|
||||
new EncounterStaticShadow(Altaria) { Fateful = true, Species = 334, Level = 36, Gauge = 06500, Moves = new[] {225,215,076,332}, Location = 076, }, // Altaria: Cipher Admin Lovrina @ Citadark Isle
|
||||
new EncounterStaticShadow(Kangaskhan){ Fateful = true, Species = 115, Level = 35, Gauge = 06000, Moves = new[] {089,047,039,146}, Location = 085, }, // Kangaskhan: Cipher Peon Litnar @ Citadark Isle
|
||||
new EncounterStaticShadow(Banette) { Fateful = true, Species = 354, Level = 37, Gauge = 07000, Moves = new[] {185,270,247,174}, Location = 085, }, // Banette: Cipher Peon Litnar @ Citadark Isle
|
||||
new EncounterStaticShadow(Magmar) { Fateful = true, Species = 126, Level = 36, Gauge = 07000, Moves = new[] {126,266,238,009}, Location = 077, }, // Magmar: Cipher Peon Grupel @ Citadark Isle
|
||||
new EncounterStaticShadow(Pinsir) { Fateful = true, Species = 127, Level = 35, Gauge = 07000, Moves = new[] {012,270,206,066}, Location = 077, }, // Pinsir: Cipher Peon Grupel @ Citadark Isle
|
||||
new EncounterStaticShadow(Rapidash) { Fateful = true, Species = 078, Level = 40, Gauge = 06000, Moves = new[] {076,226,241,053}, Location = 080, }, // Rapidash: Cipher Peon Kolest @ Citadark Isle
|
||||
new EncounterStaticShadow(Magcargo) { Fateful = true, Species = 219, Level = 38, Gauge = 05500, Moves = new[] {257,287,089,053}, Location = 080, }, // Magcargo: Cipher Peon Kolest @ Citadark Isle
|
||||
new EncounterStaticShadow(Hitmonchan){ Fateful = true, Species = 107, Level = 38, Gauge = 06000, Moves = new[] {005,270,170,327}, Location = 081, }, // Hitmonchan: Cipher Peon Karbon @ Citadark Isle
|
||||
new EncounterStaticShadow(Hitmonlee) { Fateful = true, Species = 106, Level = 38, Gauge = 07000, Moves = new[] {136,287,170,025}, Location = 081, }, // Hitmonlee: Cipher Peon Petro @ Citadark Isle
|
||||
new EncounterStaticShadow(Lickitung) { Fateful = true, Species = 108, Level = 38, Gauge = 05000, Moves = new[] {038,270,111,205}, Location = 084, }, // Lickitung: Cipher Peon Geftal @ Citadark Isle
|
||||
new EncounterStaticShadow(Scyther) { Fateful = true, Species = 123, Level = 40, Gauge = 08000, Moves = new[] {013,234,318,163}, Location = 084, }, // Scyther: Cipher Peon Leden @ Citadark Isle
|
||||
|
||||
new EncounterStaticShadow(Chansey) { Fateful = true, Species = 113, Level = 39, Gauge = 04000, Moves = new[] {085,186,135,285}, Location = 084, }, // Chansey: Cipher Peon Leden @ Citadark Isle
|
||||
new EncounterStaticShadow(Chansey) { Fateful = true, Species = 113, Level = 39, Gauge = 04000, Moves = new[] {085,186,135,285}, Location = 087, }, // Chansey: Cipher Peon Leden @ Citadark Isle
|
||||
|
||||
new EncounterStaticShadow(Solrock) { Fateful = true, Species = 338, Level = 41, Gauge = 07500, Moves = new[] {094,226,241,322}, Location = 087, }, // Solrock: Cipher Admin Snattle @ Citadark Isle
|
||||
new EncounterStaticShadow(Starmie) { Fateful = true, Species = 121, Level = 41, Gauge = 07500, Moves = new[] {127,287,058,105}, Location = 087, }, // Starmie: Cipher Admin Snattle @ Citadark Isle
|
||||
new EncounterStaticShadow(Electabuzz){ Fateful = true, Species = 125, Level = 43, Gauge = 07000, Moves = new[] {238,266,086,085}, Location = 087, }, // Electabuzz: Cipher Admin Ardos @ Citadark Isle
|
||||
new EncounterStaticShadow(Snorlax) { Fateful = true, Species = 143, Level = 43, Gauge = 09000, Moves = new[] {090,287,174,034}, Location = 087, }, // Snorlax: Cipher Admin Ardos @ Citadark Isle
|
||||
new EncounterStaticShadow(Poliwrath) { Fateful = true, Species = 062, Level = 42, Gauge = 07500, Moves = new[] {056,270,240,280}, Location = 087, }, // Poliwrath: Cipher Admin Gorigan @ Citadark Isle
|
||||
new EncounterStaticShadow(MrMime) { Fateful = true, Species = 122, Level = 42, Gauge = 06500, Moves = new[] {094,266,227,009}, Location = 087, }, // Mr. Mime: Cipher Admin Gorigan @ Citadark Isle
|
||||
new EncounterStaticShadow(Dugtrio) { Fateful = true, Species = 051, Level = 40, Gauge = 05000, Moves = new[] {089,204,201,161}, Location = 075, }, // Dugtrio: Cipher Peon Kolax @ Citadark Isle
|
||||
new EncounterStaticShadow(Manectric) { Fateful = true, Species = 310, Level = 44, Gauge = 07000, Moves = new[] {087,287,240,044}, Location = 073, }, // Manectric: Cipher Admin Eldes @ Citadark Isle
|
||||
new EncounterStaticShadow(Salamence) { Fateful = true, Species = 373, Level = 50, Gauge = 09000, Moves = new[] {337,287,349,332}, Location = 073, }, // Salamence: Cipher Admin Eldes @ Citadark Isle
|
||||
new EncounterStaticShadow(Marowak) { Fateful = true, Species = 105, Level = 44, Gauge = 06500, Moves = new[] {089,047,014,157}, Location = 073, }, // Marowak: Cipher Admin Eldes @ Citadark Isle
|
||||
new EncounterStaticShadow(Lapras) { Fateful = true, Species = 131, Level = 44, Gauge = 06000, Moves = new[] {056,215,240,059}, Location = 073, }, // Lapras: Cipher Admin Eldes @ Citadark Isle
|
||||
new EncounterStaticShadow(Moltres) { Fateful = true, Species = 146, Level = 50, Gauge = 10000, Moves = new[] {326,234,261,053}, Location = 074, }, // Moltres: Grand Master Greevil @ Citadark Isle
|
||||
new EncounterStaticShadow(Exeggutor) { Fateful = true, Species = 103, Level = 46, Gauge = 09000, Moves = new[] {094,287,095,246}, Location = 074, }, // Exeggutor: Grand Master Greevil @ Citadark Isle
|
||||
new EncounterStaticShadow(Tauros) { Fateful = true, Species = 128, Level = 46, Gauge = 09000, Moves = new[] {089,287,039,034}, Location = 074, }, // Tauros: Grand Master Greevil @ Citadark Isle
|
||||
new EncounterStaticShadow(Articuno) { Fateful = true, Species = 144, Level = 50, Gauge = 10000, Moves = new[] {326,215,114,058}, Location = 074, }, // Articuno: Grand Master Greevil @ Citadark Isle
|
||||
new EncounterStaticShadow(Zapdos) { Fateful = true, Species = 145, Level = 50, Gauge = 10000, Moves = new[] {326,226,319,085}, Location = 074, }, // Zapdos: Grand Master Greevil @ Citadark Isle
|
||||
new EncounterStaticShadow(Dragonite) { Fateful = true, Species = 149, Level = 55, Gauge = 09000, Moves = new[] {063,215,349,089}, Location = 162, }, // Dragonite: Wanderer Miror B. @ Gateon Port
|
||||
}.SelectMany(CloneMirorB).ToArray();
|
||||
|
||||
internal static readonly EncounterArea3[] SlotsXD =
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -996,7 +996,7 @@ namespace PKHeX.Core
|
|||
Encounter_HGSS_Regular);
|
||||
#endregion
|
||||
#region Trade Tables
|
||||
private static readonly string[] RanchOTNames = { null, "ユカリ", "Hayley", "EULALIE", "GIULIA", "EUKALIA", null, "Eulalia" };
|
||||
private static readonly string[] RanchOTNames = { string.Empty, "ユカリ", "Hayley", "EULALIE", "GIULIA", "EUKALIA", string.Empty, "Eulalia" };
|
||||
|
||||
private static readonly EncounterTrade[] RanchGifts =
|
||||
{
|
||||
|
|
|
@ -100,7 +100,7 @@ namespace PKHeX.Core
|
|||
var list = new List<EncounterStatic>();
|
||||
foreach (EncounterStatic s in t)
|
||||
{
|
||||
if (s.Moves == null || s.Moves.Length <= 1) // no special moves
|
||||
if (s.Moves.Length <= 1) // no special moves
|
||||
{
|
||||
list.Add(s);
|
||||
continue;
|
||||
|
@ -745,8 +745,8 @@ namespace PKHeX.Core
|
|||
private const string tradeB2W2 = "tradeb2w2";
|
||||
private static readonly string[][] TradeBW = Util.GetLanguageStrings8(tradeBW);
|
||||
private static readonly string[][] TradeB2W2 = Util.GetLanguageStrings8(tradeB2W2);
|
||||
private static readonly string[] TradeOT_B2W2_F = {null, "ルリ", "Yancy", "Brenda", "Lilì", "Sabine", null, "Belinda", "루리"};
|
||||
private static readonly string[] TradeOT_B2W2_M = {null, "テツ", "Curtis", "Julien", "Dadi", "Markus", null, "Julián", "철권"};
|
||||
private static readonly string[] TradeOT_B2W2_F = {string.Empty, "ルリ", "Yancy", "Brenda", "Lilì", "Sabine", string.Empty, "Belinda", "루리"};
|
||||
private static readonly string[] TradeOT_B2W2_M = {string.Empty, "テツ", "Curtis", "Julien", "Dadi", "Markus", string.Empty, "Julián", "철권"};
|
||||
|
||||
internal static readonly EncounterTrade[] TradeGift_B2W2 = TradeGift_B2W2_Regular.Concat(TradeGift_B2W2_YancyCurtis).ToArray();
|
||||
|
||||
|
|
|
@ -26,9 +26,11 @@ namespace PKHeX.Core
|
|||
MarkG7REGSlots(ref REG_MN);
|
||||
MarkG7SMSlots(ref SOS_SN);
|
||||
MarkG7SMSlots(ref SOS_MN);
|
||||
InitializePelagoAreas();
|
||||
SlotsSN = AddExtraTableSlots(REG_SN, SOS_SN, Encounter_Pelago_SN);
|
||||
SlotsMN = AddExtraTableSlots(REG_MN, SOS_MN, Encounter_Pelago_MN);
|
||||
int[] pelagoMin = { 1, 11, 21, 37, 49 };
|
||||
InitializePelagoSM(pelagoMin, out var p_sn, out var p_mn);
|
||||
InitializePelagoUltra(pelagoMin, out var p_us, out var p_um);
|
||||
SlotsSN = AddExtraTableSlots(REG_SN, SOS_SN, p_sn);
|
||||
SlotsMN = AddExtraTableSlots(REG_MN, SOS_MN, p_mn);
|
||||
|
||||
var REG_US = GetEncounterTables<EncounterArea7>("uu", "us");
|
||||
var REG_UM = GetEncounterTables<EncounterArea7>("uu", "um");
|
||||
|
@ -38,12 +40,12 @@ namespace PKHeX.Core
|
|||
MarkG7REGSlots(ref REG_UM);
|
||||
MarkG7SMSlots(ref SOS_US);
|
||||
MarkG7SMSlots(ref SOS_UM);
|
||||
SlotsUS = AddExtraTableSlots(REG_US, SOS_US, Encounter_Pelago_US);
|
||||
SlotsUM = AddExtraTableSlots(REG_UM, SOS_UM, Encounter_Pelago_UM);
|
||||
SlotsUS = AddExtraTableSlots(REG_US, SOS_US, p_us);
|
||||
SlotsUM = AddExtraTableSlots(REG_UM, SOS_UM, p_um);
|
||||
|
||||
MarkEncounterAreaArray(SOS_SN, SOS_MN, SOS_US, SOS_UM,
|
||||
Encounter_Pelago_SN, Encounter_Pelago_MN,
|
||||
Encounter_Pelago_US, Encounter_Pelago_UM);
|
||||
p_sn, p_mn,
|
||||
p_us, p_um);
|
||||
|
||||
MarkEncountersGeneration(7, SlotsSN, SlotsMN, SlotsUS, SlotsUM);
|
||||
MarkEncountersGeneration(7, StaticSN, StaticMN, StaticUS, StaticUM, TradeGift_SM, TradeGift_USUM);
|
||||
|
@ -407,11 +409,8 @@ namespace PKHeX.Core
|
|||
private static readonly string[][] TradeSM = Util.GetLanguageStrings10(tradeSM);
|
||||
private static readonly string[][] TradeUSUM = Util.GetLanguageStrings10(tradeUSUM);
|
||||
|
||||
private static EncounterArea7[] Encounter_Pelago_SN, Encounter_Pelago_MN, Encounter_Pelago_US, Encounter_Pelago_UM;
|
||||
|
||||
private static void InitializePelagoAreas()
|
||||
private static void InitializePelagoSM(int[] minLevels, out EncounterArea7[] sn, out EncounterArea7[] mn)
|
||||
{
|
||||
int[] minLevels = { 1, 11, 21, 37, 49 };
|
||||
int[][] speciesSM =
|
||||
{
|
||||
new[] {627/*SN*/, 021, 041, 090, 278, 731}, // 1-7
|
||||
|
@ -420,10 +419,13 @@ namespace PKHeX.Core
|
|||
new[] {227, 375, 707}, // 37-43
|
||||
new[] {123, 131, 429, 587}, // 49-55
|
||||
};
|
||||
Encounter_Pelago_SN = GetPelagoArea(speciesSM, minLevels);
|
||||
sn = GetPelagoArea(speciesSM, minLevels);
|
||||
speciesSM[0][0] = 629; // Rufflet -> Vullaby
|
||||
Encounter_Pelago_MN = GetPelagoArea(speciesSM, minLevels);
|
||||
mn = GetPelagoArea(speciesSM, minLevels);
|
||||
}
|
||||
|
||||
private static void InitializePelagoUltra(int[] minLevels, out EncounterArea7[] us, out EncounterArea7[] um)
|
||||
{
|
||||
int[][] speciesUU =
|
||||
{
|
||||
new[] {731, 278, 041, 742, 086}, // 1-7
|
||||
|
@ -432,9 +434,9 @@ namespace PKHeX.Core
|
|||
new[] {131, 354, 200, /* US */ 228}, // 37-43
|
||||
new[] {209, 667, 357, 430}, // 49-55
|
||||
};
|
||||
Encounter_Pelago_US = GetPelagoArea(speciesUU, minLevels);
|
||||
us = GetPelagoArea(speciesUU, minLevels);
|
||||
speciesUU[3][3] = 309; // Houndour -> Electrike
|
||||
Encounter_Pelago_UM = GetPelagoArea(speciesUU, minLevels);
|
||||
um = GetPelagoArea(speciesUU, minLevels);
|
||||
}
|
||||
|
||||
private static EncounterArea7[] GetPelagoArea(int[][] species, int[] min)
|
||||
|
|
|
@ -60,14 +60,14 @@ namespace PKHeX.Core
|
|||
new EncounterStatic { Species = 059, Level = 16, Location = 33, Gift = true, IVs = new[] {25,30,25,31,30,25}, Version = GameVersion.GE }, // Arcanine @ Vermillion City (Outside Fan Club)
|
||||
};
|
||||
|
||||
private static readonly string[] T1 = { null, "ミニコ", "Tatianna", "BarbaRatatta", "Addoloratta", "Barbaratt", null, "Tatiana", "미니꼬", "小幂妮", "小幂妮", };
|
||||
private static readonly string[] T2 = { null, "ボーアイス", "Nicholice", "Iceman-4L0L4", "Goffreddo", "Eisper", null, "Gelasio", "보아이스", "露冰冰", "露冰冰", };
|
||||
private static readonly string[] T3 = { null, "レディダグ", "Diggette", "Taupilady", "Lady Glett", "Digga", null, "Glenda", "레이디그다", "蒂淑", "蒂淑", };
|
||||
private static readonly string[] T4 = { null, "ワルモン", "Darko", "AlolaZeDark", "Mattetro", "Bösbert", null, "Sinesio", "나뻐기", "达怀丹", "达怀丹", };
|
||||
private static readonly string[] T5 = { null, "エリッチ", "Psytrice", "TopDeTonCœur", "Chulia", "Assana", null, "Menchu", "엘리츄", "晶莹丘", "晶莹丘", };
|
||||
private static readonly string[] T6 = { null, "ジェンガラ", "Genmar", "OSS-Dandy7", "Mr. Owak", "Knoggelius", null, "Mario", "젠구리", "申史加拉", "申史加拉", };
|
||||
private static readonly string[] T7 = { null, "マニシ", "Exemann", "Koko-fan", "Exechiele", "Einrich", null, "Gunter", "마니시", "艾浩舒", "艾浩舒", };
|
||||
private static readonly string[] T8 = { null, "コツブ", "Higeo", "Montagnou", "George", "Karstein", null, "Georgie", "산돌", "科布", "科布", };
|
||||
private static readonly string[] T1 = { string.Empty, "ミニコ", "Tatianna", "BarbaRatatta", "Addoloratta", "Barbaratt", string.Empty, "Tatiana", "미니꼬", "小幂妮", "小幂妮", };
|
||||
private static readonly string[] T2 = { string.Empty, "ボーアイス", "Nicholice", "Iceman-4L0L4", "Goffreddo", "Eisper", string.Empty, "Gelasio", "보아이스", "露冰冰", "露冰冰", };
|
||||
private static readonly string[] T3 = { string.Empty, "レディダグ", "Diggette", "Taupilady", "Lady Glett", "Digga", string.Empty, "Glenda", "레이디그다", "蒂淑", "蒂淑", };
|
||||
private static readonly string[] T4 = { string.Empty, "ワルモン", "Darko", "AlolaZeDark", "Mattetro", "Bösbert", string.Empty, "Sinesio", "나뻐기", "达怀丹", "达怀丹", };
|
||||
private static readonly string[] T5 = { string.Empty, "エリッチ", "Psytrice", "TopDeTonCœur", "Chulia", "Assana", string.Empty, "Menchu", "엘리츄", "晶莹丘", "晶莹丘", };
|
||||
private static readonly string[] T6 = { string.Empty, "ジェンガラ", "Genmar", "OSS-Dandy7", "Mr. Owak", "Knoggelius", string.Empty, "Mario", "젠구리", "申史加拉", "申史加拉", };
|
||||
private static readonly string[] T7 = { string.Empty, "マニシ", "Exemann", "Koko-fan", "Exechiele", "Einrich", string.Empty, "Gunter", "마니시", "艾浩舒", "艾浩舒", };
|
||||
private static readonly string[] T8 = { string.Empty, "コツブ", "Higeo", "Montagnou", "George", "Karstein", string.Empty, "Georgie", "산돌", "科布", "科布", };
|
||||
|
||||
internal static readonly EncounterTrade[] TradeGift_GG =
|
||||
{
|
||||
|
@ -145,33 +145,39 @@ namespace PKHeX.Core
|
|||
|
||||
private class RareSpawn
|
||||
{
|
||||
public int Species;
|
||||
public int[] Locations;
|
||||
public readonly int Species;
|
||||
public readonly byte[] Locations;
|
||||
|
||||
protected internal RareSpawn(int species, params byte[] locations)
|
||||
{
|
||||
Species = species;
|
||||
Locations = locations;
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly int[] Sky = {003, 004, 005, 006, 009, 010, 011, 012, 013, 014, 015, 016, 017, 018, 019, 020, 021, 022, 023, 024, 025, 026, 027};
|
||||
private static readonly byte[] Sky = {003, 004, 005, 006, 009, 010, 011, 012, 013, 014, 015, 016, 017, 018, 019, 020, 021, 022, 023, 024, 025, 026, 027};
|
||||
|
||||
private static readonly RareSpawn[] Rare =
|
||||
{
|
||||
// Normal
|
||||
new RareSpawn {Species = 001, Locations = new[] {039}},
|
||||
new RareSpawn {Species = 004, Locations = new[] {005, 006, 041}},
|
||||
new RareSpawn {Species = 007, Locations = new[] {026, 027, 044}},
|
||||
new RareSpawn {Species = 106, Locations = new[] {045}},
|
||||
new RareSpawn {Species = 107, Locations = new[] {045}},
|
||||
new RareSpawn {Species = 113, Locations = new[] {007, 008, 010, 011, 012, 013, 014, 015, 016, 017, 018, 019, 020, 023, 025, 040, 042, 043, 045, 047, 051}},
|
||||
new RareSpawn {Species = 137, Locations = new[] {009}},
|
||||
new RareSpawn {Species = 143, Locations = new[] {046}},
|
||||
new RareSpawn(001, 039),
|
||||
new RareSpawn(004, 005, 006, 041),
|
||||
new RareSpawn(007, 026, 027, 044),
|
||||
new RareSpawn(106, 045),
|
||||
new RareSpawn(107, 045),
|
||||
new RareSpawn(113, 007, 008, 010, 011, 012, 013, 014, 015, 016, 017, 018, 019, 020, 023, 025, 040, 042, 043, 045, 047, 051),
|
||||
new RareSpawn(137, 009),
|
||||
new RareSpawn(143, 046),
|
||||
|
||||
// Water
|
||||
new RareSpawn {Species = 131, Locations = new[] {021, 022}},
|
||||
new RareSpawn(131, 021, 022),
|
||||
|
||||
// Fly
|
||||
new RareSpawn {Species = 006, Locations = Sky,},
|
||||
new RareSpawn {Species = 144, Locations = Sky,},
|
||||
new RareSpawn {Species = 145, Locations = Sky,},
|
||||
new RareSpawn {Species = 146, Locations = Sky,},
|
||||
new RareSpawn {Species = 149, Locations = Sky,},
|
||||
new RareSpawn(006, Sky),
|
||||
new RareSpawn(144, Sky),
|
||||
new RareSpawn(145, Sky),
|
||||
new RareSpawn(146, Sky),
|
||||
new RareSpawn(149, Sky),
|
||||
};
|
||||
|
||||
private static void ManuallyAddRareSpawns(IEnumerable<EncounterArea> areas)
|
||||
|
@ -179,7 +185,7 @@ namespace PKHeX.Core
|
|||
foreach (var table in areas)
|
||||
{
|
||||
var loc = table.Location;
|
||||
var species = Rare.Where(z => z.Locations.Contains(loc)).Select(z => z.Species).ToArray();
|
||||
var species = Rare.Where(z => z.Locations.Contains((byte)loc)).Select(z => z.Species).ToArray();
|
||||
if (species.Length == 0)
|
||||
continue;
|
||||
var slots = table.Slots;
|
||||
|
|
|
@ -25,9 +25,9 @@ namespace PKHeX.Core
|
|||
private static IEnumerable<WC3> GetIngameCXDData()
|
||||
{
|
||||
var langs = new[]{LanguageID.Japanese, LanguageID.English, LanguageID.French, LanguageID.Italian, LanguageID.German, LanguageID.Spanish};
|
||||
var h = new[] {null, "ダニー", "HORDEL", "VOLKER", "ODINO", "HORAZ", null, "HORDEL"};
|
||||
var d = new[] {null, "ギンザル", "DUKING", "DOKING", "RODRIGO", "GRAND", null, "GERMÁN"};
|
||||
var m = new[] {null, "バトルやま", "MATTLE", "MT BATAILL", "MONTE LOTT", "DUELLBERG", null, "ERNESTO"}; // truncated on ck3->pk3 transfer
|
||||
var h = new[] {string.Empty, "ダニー", "HORDEL", "VOLKER", "ODINO", "HORAZ", string.Empty, "HORDEL"};
|
||||
var d = new[] {string.Empty, "ギンザル", "DUKING", "DOKING", "RODRIGO", "GRAND", string.Empty, "GERMÁN"};
|
||||
var m = new[] {string.Empty, "バトルやま", "MATTLE", "MT BATAILL", "MONTE LOTT", "DUELLBERG", string.Empty, "ERNESTO"}; // truncated on ck3->pk3 transfer
|
||||
|
||||
return langs.SelectMany(l => GetIngame((int)l));
|
||||
IEnumerable<WC3> GetIngame(int l)
|
||||
|
|
|
@ -77,7 +77,7 @@ namespace PKHeX.Core
|
|||
case (int)Core.Species.Scatterbug:
|
||||
case (int)Core.Species.Spewpa:
|
||||
case (int)Core.Species.Vivillon:
|
||||
pk.AltForm = Legal.GetVivillonPattern(SAV.Country, SAV.SubRegion);
|
||||
pk.AltForm = Legal.GetVivillonPattern((byte)SAV.Country, (byte)SAV.SubRegion);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,8 @@ namespace PKHeX.Core
|
|||
/// </summary>
|
||||
public sealed class EncounterInvalid : IEncounterable
|
||||
{
|
||||
public static readonly EncounterInvalid Default = new EncounterInvalid();
|
||||
|
||||
public int Species { get; }
|
||||
public int LevelMin { get; }
|
||||
public int LevelMax { get; }
|
||||
|
@ -15,6 +17,8 @@ namespace PKHeX.Core
|
|||
public string Name => "Invalid";
|
||||
public string LongName => "Invalid";
|
||||
|
||||
private EncounterInvalid() { }
|
||||
|
||||
public EncounterInvalid(PKM pkm)
|
||||
{
|
||||
Species = pkm.Species;
|
||||
|
|
|
@ -50,12 +50,12 @@ namespace PKHeX.Core
|
|||
public EncounterType TypeEncounter { get; set; } = EncounterType.None;
|
||||
public int SlotNumber { get; set; }
|
||||
public int Generation { get; set; } = -1;
|
||||
internal EncounterSlotPermissions _perm;
|
||||
private EncounterSlotPermissions? _perm;
|
||||
public EncounterSlotPermissions Permissions => _perm ??= new EncounterSlotPermissions();
|
||||
public GameVersion Version { get; set; }
|
||||
|
||||
internal EncounterArea Area { private get; set; }
|
||||
public int Location { get => Area.Location; set { } }
|
||||
internal EncounterArea? Area { private get; set; }
|
||||
public int Location { get => Area?.Location ?? 0; set { } }
|
||||
public bool EggEncounter => false;
|
||||
public int EggLocation { get => 0; set { } }
|
||||
|
||||
|
@ -122,7 +122,7 @@ namespace PKHeX.Core
|
|||
|
||||
private void SetEncounterMoves(PKM pk, GameVersion version, int level)
|
||||
{
|
||||
var moves = this is EncounterSlotMoves m ? m.Moves : MoveLevelUp.GetEncounterMoves(pk, level, version);
|
||||
var moves = this is IMoveset m ? m.Moves : MoveLevelUp.GetEncounterMoves(pk, level, version);
|
||||
pk.Moves = moves;
|
||||
pk.SetMaximumPPCurrent(moves);
|
||||
}
|
||||
|
@ -205,7 +205,7 @@ namespace PKHeX.Core
|
|||
|
||||
int spec = pk.Species;
|
||||
if (spec == (int)Core.Species.Scatterbug || spec == (int)Core.Species.Spewpa || spec == (int)Core.Species.Vivillon)
|
||||
return Legal.GetVivillonPattern(SAV.Country, SAV.SubRegion);
|
||||
return Legal.GetVivillonPattern((byte)SAV.Country, (byte)SAV.SubRegion);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
9
PKHeX.Core/Legality/Encounters/EncounterSlot3Swarm.cs
Normal file
9
PKHeX.Core/Legality/Encounters/EncounterSlot3Swarm.cs
Normal file
|
@ -0,0 +1,9 @@
|
|||
namespace PKHeX.Core
|
||||
{
|
||||
internal sealed class EncounterSlot3Swarm : EncounterSlot, IMoveset
|
||||
{
|
||||
public int[] Moves { get; }
|
||||
|
||||
public EncounterSlot3Swarm(int[] moves) => Moves = moves;
|
||||
}
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
namespace PKHeX.Core
|
||||
{
|
||||
internal sealed class EncounterSlotMoves : EncounterSlot, IMoveset
|
||||
{
|
||||
public int[] Moves { get; set; }
|
||||
}
|
||||
}
|
|
@ -12,7 +12,7 @@ namespace PKHeX.Core
|
|||
public class EncounterStatic : IEncounterable, IMoveset, IGeneration, ILocation, IContestStats, IVersion
|
||||
{
|
||||
public int Species { get; set; }
|
||||
public int[] Moves { get; set; }
|
||||
public int[] Moves { get; set; } = Array.Empty<int>();
|
||||
public int Level { get; set; }
|
||||
|
||||
public int LevelMin => Level;
|
||||
|
@ -29,7 +29,7 @@ namespace PKHeX.Core
|
|||
public bool Gift { get; set; }
|
||||
public int Ball { get; set; } = 4; // Only checked when is Gift
|
||||
public GameVersion Version { get; set; } = GameVersion.Any;
|
||||
public int[] IVs { get; set; }
|
||||
public int[] IVs { get; set; } = Array.Empty<int>();
|
||||
public int FlawlessIVCount { get; set; }
|
||||
|
||||
public int[] Contest { set => this.SetContestStats(value); }
|
||||
|
@ -52,9 +52,9 @@ namespace PKHeX.Core
|
|||
private void CloneArrays()
|
||||
{
|
||||
// dereference original arrays with new copies
|
||||
Moves = (int[])Moves?.Clone();
|
||||
Relearn = (int[])Relearn.Clone();
|
||||
IVs = (int[])IVs?.Clone();
|
||||
Moves = Moves.Length == 0 ? Moves : (int[])Moves.Clone();
|
||||
Relearn = Relearn.Length == 0 ? Relearn : (int[])Relearn.Clone();
|
||||
IVs = IVs.Length == 0 ? IVs : (int[])IVs.Clone();
|
||||
}
|
||||
|
||||
internal virtual EncounterStatic Clone()
|
||||
|
@ -176,7 +176,7 @@ namespace PKHeX.Core
|
|||
|
||||
private void SetEncounterMoves(PKM pk, GameVersion version, int level)
|
||||
{
|
||||
var moves = Moves?.Length > 0 ? Moves : MoveLevelUp.GetEncounterMoves(pk, level, version);
|
||||
var moves = Moves.Length > 0 ? Moves : MoveLevelUp.GetEncounterMoves(pk, level, version);
|
||||
pk.Moves = moves;
|
||||
pk.SetMaximumPPCurrent(moves);
|
||||
}
|
||||
|
@ -196,7 +196,7 @@ namespace PKHeX.Core
|
|||
|
||||
protected void SetIVs(PKM pk)
|
||||
{
|
||||
if (IVs != null)
|
||||
if (IVs.Length != 0)
|
||||
pk.SetRandomIVs(IVs, FlawlessIVCount);
|
||||
else if (FlawlessIVCount > 0)
|
||||
pk.SetRandomIVs(flawless: FlawlessIVCount);
|
||||
|
@ -353,7 +353,7 @@ namespace PKHeX.Core
|
|||
if (EggLocation == Locations.Daycare5 && Relearn.Length == 0 && pkm.RelearnMoves.Any(z => z != 0)) // gen7 eevee edge case
|
||||
return false;
|
||||
|
||||
if (IVs != null && (Generation > 2 || pkm.Format <= 2)) // 1,2->7 regenerates IVs, only check if original IVs still exist
|
||||
if (IVs.Length != 0 && (Generation > 2 || pkm.Format <= 2)) // 1,2->7 regenerates IVs, only check if original IVs still exist
|
||||
{
|
||||
if (!Legal.GetIsFixedIVSequenceValidSkipRand(IVs, pkm))
|
||||
return false;
|
||||
|
|
|
@ -10,7 +10,7 @@ namespace PKHeX.Core
|
|||
/// <summary>
|
||||
/// Team Specification with required <see cref="Species"/>, <see cref="Nature"/> and Gender.
|
||||
/// </summary>
|
||||
public TeamLock[] Locks { get; internal set; } = Array.Empty<TeamLock>();
|
||||
public readonly TeamLock[] Locks;
|
||||
|
||||
/// <summary>
|
||||
/// Initial Shadow Gauge value.
|
||||
|
@ -20,19 +20,9 @@ namespace PKHeX.Core
|
|||
/// <summary>
|
||||
/// Originates from the EReader scans (Japanese Only)
|
||||
/// </summary>
|
||||
public bool EReader { get; set; }
|
||||
public bool EReader { get; internal set; }
|
||||
|
||||
internal override EncounterStatic Clone()
|
||||
{
|
||||
var result = (EncounterStaticShadow)base.Clone();
|
||||
|
||||
if (Locks.Length == 0)
|
||||
return result;
|
||||
|
||||
result.Locks = new TeamLock[Locks.Length];
|
||||
for (int i = 0; i < Locks.Length; i++)
|
||||
result.Locks[i] = Locks[i].Clone();
|
||||
return result;
|
||||
}
|
||||
public EncounterStaticShadow(TeamLock[] locks) => Locks = locks;
|
||||
public EncounterStaticShadow() => Locks = Array.Empty<TeamLock>();
|
||||
}
|
||||
}
|
|
@ -12,7 +12,7 @@ namespace PKHeX.Core
|
|||
public class EncounterTrade : IEncounterable, IMoveset, IGeneration, ILocation, IContestStats, IVersion
|
||||
{
|
||||
public int Species { get; set; }
|
||||
public int[] Moves { get; set; }
|
||||
public int[] Moves { get; set; } = Array.Empty<int>();
|
||||
public int Level { get; set; }
|
||||
public int LevelMin => Level;
|
||||
public int LevelMax => 100;
|
||||
|
@ -24,7 +24,7 @@ namespace PKHeX.Core
|
|||
public int TID { get; set; }
|
||||
public int SID { get; set; }
|
||||
public GameVersion Version { get; set; } = GameVersion.Any;
|
||||
public int[] IVs { get; set; }
|
||||
public int[] IVs { get; set; } = Array.Empty<int>();
|
||||
public int Form { get; set; }
|
||||
public virtual Shiny Shiny { get; set; } = Shiny.Never;
|
||||
public int Gender { get; set; } = -1;
|
||||
|
@ -58,11 +58,12 @@ namespace PKHeX.Core
|
|||
public bool Fateful { get; set; }
|
||||
public bool IsNicknamed { get; set; } = true;
|
||||
|
||||
public string[] Nicknames { get; internal set; }
|
||||
public string[] TrainerNames { get; internal set; }
|
||||
public string GetNickname(int language) => Nicknames?.Length > language ? Nicknames[language] : null;
|
||||
public string GetOT(int language) => TrainerNames?.Length > language ? TrainerNames[language] : null;
|
||||
public bool HasNickname => Nicknames != null;
|
||||
public string[] Nicknames { get; internal set; } = Array.Empty<string>();
|
||||
public string[] TrainerNames { get; internal set; } = Array.Empty<string>();
|
||||
public string GetNickname(int language) => (uint)language < Nicknames.Length ? Nicknames[language] : string.Empty;
|
||||
public string GetOT(int language) => (uint)language < TrainerNames.Length ? TrainerNames[language] : string.Empty;
|
||||
public bool HasNickname => Nicknames.Length != 0;
|
||||
public bool HasTrainerName => TrainerNames.Length != 0;
|
||||
|
||||
public static readonly int[] DefaultMetLocation =
|
||||
{
|
||||
|
@ -160,7 +161,7 @@ namespace PKHeX.Core
|
|||
|
||||
protected void SetIVs(PKM pk)
|
||||
{
|
||||
if (IVs != null)
|
||||
if (IVs.Length != 0)
|
||||
pk.SetRandomIVs(IVs, 0);
|
||||
else
|
||||
pk.SetRandomIVs(flawless: 3);
|
||||
|
@ -168,7 +169,7 @@ namespace PKHeX.Core
|
|||
|
||||
private void SetMoves(PKM pk, GameVersion version, int level)
|
||||
{
|
||||
var moves = Moves ?? MoveLevelUp.GetEncounterMoves(pk, level, version);
|
||||
var moves = Moves.Length != 0 ? Moves : MoveLevelUp.GetEncounterMoves(pk, level, version);
|
||||
if (pk.Format == 1 && moves.All(z => z == 0))
|
||||
moves = ((PersonalInfoG1)PersonalTable.RB[Species]).Moves;
|
||||
pk.Moves = moves;
|
||||
|
@ -230,7 +231,7 @@ namespace PKHeX.Core
|
|||
|
||||
public bool IsMatch(PKM pkm, int lvl)
|
||||
{
|
||||
if (IVs != null)
|
||||
if (IVs.Length != 0)
|
||||
{
|
||||
if (!Legal.GetIsFixedIVSequenceValidSkipRand(IVs, pkm))
|
||||
return false;
|
||||
|
@ -332,7 +333,7 @@ namespace PKHeX.Core
|
|||
{
|
||||
if (Gender >= 0 && Gender != pkm.Gender)
|
||||
return false;
|
||||
if (IVs != null && !Legal.GetIsFixedIVSequenceValidNoRand(IVs, pkm))
|
||||
if (IVs.Length != 0 && !Legal.GetIsFixedIVSequenceValidNoRand(IVs, pkm))
|
||||
return false;
|
||||
}
|
||||
if (pkm.Met_Location != 0 && pkm.Format == 2 && pkm.Met_Location != 126)
|
||||
|
|
|
@ -45,7 +45,7 @@
|
|||
|
||||
public static EncounterCriteria GetCriteria(ShowdownSet s)
|
||||
{
|
||||
int gender = s.Gender == null ? -1 : PKX.GetGenderFromString(s.Gender);
|
||||
int gender = string.IsNullOrWhiteSpace(s.Gender) ? -1 : PKX.GetGenderFromString(s.Gender);
|
||||
return new EncounterCriteria
|
||||
{
|
||||
Gender = gender,
|
||||
|
|
|
@ -22,7 +22,7 @@ namespace PKHeX.Core
|
|||
/// </returns>
|
||||
public static LegalInfo FindVerifiedEncounter(PKM pkm)
|
||||
{
|
||||
LegalInfo info = new LegalInfo(pkm);
|
||||
var info = new LegalInfo(pkm);
|
||||
var encounters = EncounterGenerator.GetEncounters(pkm, info);
|
||||
|
||||
using var encounter = new PeekEnumerator<IEncounterable>(encounters);
|
||||
|
|
|
@ -69,7 +69,7 @@ namespace PKHeX.Core
|
|||
else if (z is EncounterStaticShadow s)
|
||||
{
|
||||
bool valid = false;
|
||||
if (s.IVs == null) // not ereader
|
||||
if (s.IVs.Length == 0) // not ereader
|
||||
{
|
||||
valid = LockFinder.IsAllShadowLockValid(s, info.PIDIV, pkm);
|
||||
}
|
||||
|
@ -280,7 +280,7 @@ namespace PKHeX.Core
|
|||
case EncounterTrade t:
|
||||
return t.Generation == 2 ? GBEncounterPriority.TradeEncounterG2 : GBEncounterPriority.TradeEncounterG1;
|
||||
case EncounterStatic s:
|
||||
if (s.Moves != null && s.Moves[0] != 0 && pkm.Moves.Contains(s.Moves[0]))
|
||||
if (s.Moves.Length != 0 && s.Moves[0] != 0 && pkm.Moves.Contains(s.Moves[0]))
|
||||
return GBEncounterPriority.SpecialEncounter;
|
||||
return GBEncounterPriority.StaticEncounter;
|
||||
case EncounterSlot _:
|
||||
|
|
|
@ -15,10 +15,11 @@ namespace PKHeX.Core
|
|||
/// Order in which <see cref="IEncounterable"/> objects are yielded from the <see cref="GenerateVersionEncounters"/> generator.
|
||||
/// </summary>
|
||||
// ReSharper disable once AutoPropertyCanBeMadeGetOnly.Global
|
||||
public static IReadOnlyCollection<EncounterOrder> PriorityList { get; set; }
|
||||
|
||||
static EncounterMovesetGenerator() => ResetFilters();
|
||||
public static IReadOnlyCollection<EncounterOrder> PriorityList { get; set; } = PriorityList = (EncounterOrder[])Enum.GetValues(typeof(EncounterOrder));
|
||||
|
||||
/// <summary>
|
||||
/// Resets the <see cref="PriorityList"/> to the default values.
|
||||
/// </summary>
|
||||
public static void ResetFilters() => PriorityList = (EncounterOrder[])Enum.GetValues(typeof(EncounterOrder));
|
||||
|
||||
/// <summary>
|
||||
|
@ -29,7 +30,7 @@ namespace PKHeX.Core
|
|||
/// <param name="moves">Moves that the resulting <see cref="IEncounterable"/> must be able to learn.</param>
|
||||
/// <param name="versions">Any specific version(s) to iterate for. If left blank, all will be checked.</param>
|
||||
/// <returns>A consumable <see cref="PKM"/> list of possible results.</returns>
|
||||
public static IEnumerable<PKM> GeneratePKMs(PKM pk, ITrainerInfo info, int[] moves = null, params GameVersion[] versions)
|
||||
public static IEnumerable<PKM> GeneratePKMs(PKM pk, ITrainerInfo info, int[]? moves = null, params GameVersion[] versions)
|
||||
{
|
||||
pk.TID = info.TID;
|
||||
var m = moves ?? pk.Moves;
|
||||
|
@ -57,7 +58,7 @@ namespace PKHeX.Core
|
|||
/// <param name="info">Trainer information of the receiver.</param>
|
||||
/// <param name="generation">Specific generation to iterate versions for.</param>
|
||||
/// <param name="moves">Moves that the resulting <see cref="IEncounterable"/> must be able to learn.</param>
|
||||
public static IEnumerable<PKM> GeneratePKMs(PKM pk, ITrainerInfo info, int generation, int[] moves = null)
|
||||
public static IEnumerable<PKM> GeneratePKMs(PKM pk, ITrainerInfo info, int generation, int[]? moves = null)
|
||||
{
|
||||
var vers = GameUtil.GetVersionsInGeneration(generation, pk.Version);
|
||||
return GeneratePKMs(pk, info, moves, vers);
|
||||
|
@ -70,7 +71,7 @@ namespace PKHeX.Core
|
|||
/// <param name="generation">Specific generation to iterate versions for.</param>
|
||||
/// <param name="moves">Moves that the resulting <see cref="IEncounterable"/> must be able to learn.</param>
|
||||
/// <returns>A consumable <see cref="IEncounterable"/> list of possible encounters.</returns>
|
||||
public static IEnumerable<IEncounterable> GenerateEncounter(PKM pk, int generation, int[] moves = null)
|
||||
public static IEnumerable<IEncounterable> GenerateEncounter(PKM pk, int generation, int[]? moves = null)
|
||||
{
|
||||
var vers = GameUtil.GetVersionsInGeneration(generation, pk.Version);
|
||||
return GenerateEncounters(pk, moves, vers);
|
||||
|
@ -83,14 +84,14 @@ namespace PKHeX.Core
|
|||
/// <param name="moves">Moves that the resulting <see cref="IEncounterable"/> must be able to learn.</param>
|
||||
/// <param name="versions">Any specific version(s) to iterate for. If left blank, all will be checked.</param>
|
||||
/// <returns>A consumable <see cref="IEncounterable"/> list of possible encounters.</returns>
|
||||
public static IEnumerable<IEncounterable> GenerateEncounters(PKM pk, int[] moves = null, params GameVersion[] versions)
|
||||
public static IEnumerable<IEncounterable> GenerateEncounters(PKM pk, int[]? moves = null, params GameVersion[] versions)
|
||||
{
|
||||
var m = moves ?? pk.Moves;
|
||||
moves ??= pk.Moves;
|
||||
if (versions.Length > 0)
|
||||
return GenerateEncounters(pk, moves, (IReadOnlyList<GameVersion>)versions);
|
||||
|
||||
var vers = GameUtil.GetVersionsWithinRange(pk, pk.Format);
|
||||
return vers.SelectMany(ver => GenerateVersionEncounters(pk, m, ver));
|
||||
return vers.SelectMany(ver => GenerateVersionEncounters(pk, moves, ver));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -100,10 +101,10 @@ namespace PKHeX.Core
|
|||
/// <param name="moves">Moves that the resulting <see cref="IEncounterable"/> must be able to learn.</param>
|
||||
/// <param name="vers">Any specific version(s) to iterate for. If left blank, all will be checked.</param>
|
||||
/// <returns>A consumable <see cref="IEncounterable"/> list of possible encounters.</returns>
|
||||
public static IEnumerable<IEncounterable> GenerateEncounters(PKM pk, int[] moves, IReadOnlyList<GameVersion> vers)
|
||||
public static IEnumerable<IEncounterable> GenerateEncounters(PKM pk, int[]? moves, IReadOnlyList<GameVersion> vers)
|
||||
{
|
||||
var m = moves ?? pk.Moves;
|
||||
return vers.SelectMany(ver => GenerateVersionEncounters(pk, m, ver));
|
||||
moves ??= pk.Moves;
|
||||
return vers.SelectMany(ver => GenerateVersionEncounters(pk, moves, ver));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -59,7 +59,7 @@ namespace PKHeX.Core
|
|||
return table.Where(f => p.Any(r => r.Species == f.Species));
|
||||
}
|
||||
|
||||
private static IEnumerable<EncounterTrade> GetEncounterTradeTableVC(GameVersion gameSource)
|
||||
private static IEnumerable<EncounterTrade>? GetEncounterTradeTableVC(GameVersion gameSource)
|
||||
{
|
||||
if (GameVersion.RBY.Contains(gameSource))
|
||||
return !ParseSettings.AllowGen1Tradeback ? Encounters1.TradeGift_RBY_NoTradeback : Encounters1.TradeGift_RBY_Tradeback;
|
||||
|
@ -68,7 +68,7 @@ namespace PKHeX.Core
|
|||
return null;
|
||||
}
|
||||
|
||||
private static IEnumerable<EncounterTrade> GetEncounterTradeTable(PKM pkm)
|
||||
private static IEnumerable<EncounterTrade>? GetEncounterTradeTable(PKM pkm)
|
||||
{
|
||||
return pkm.GenNumber switch
|
||||
{
|
||||
|
|
|
@ -8,10 +8,10 @@ namespace PKHeX.Core
|
|||
/// Iterates a generic collection with the ability to peek into the collection to see if the next element exists.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Generic Collection Element Type</typeparam>
|
||||
public sealed class PeekEnumerator<T> : IEnumerator<T>
|
||||
public sealed class PeekEnumerator<T> : IEnumerator<T> where T : class
|
||||
{
|
||||
private readonly IEnumerator<T> Enumerator;
|
||||
private T peek;
|
||||
private T? peek;
|
||||
private bool didPeek;
|
||||
|
||||
#region IEnumerator Implementation
|
||||
|
@ -34,12 +34,13 @@ namespace PKHeX.Core
|
|||
public void Reset()
|
||||
{
|
||||
Enumerator.Reset();
|
||||
peek = default;
|
||||
didPeek = false;
|
||||
}
|
||||
|
||||
object IEnumerator.Current => Current;
|
||||
object? IEnumerator.Current => Current;
|
||||
public void Dispose() => Enumerator.Dispose();
|
||||
public T Current => didPeek ? peek : Enumerator.Current;
|
||||
public T Current => didPeek ? peek! : Enumerator.Current;
|
||||
|
||||
#endregion
|
||||
|
||||
|
@ -68,10 +69,10 @@ namespace PKHeX.Core
|
|||
if (!TryFetchPeek())
|
||||
throw new InvalidOperationException("Enumeration already finished.");
|
||||
|
||||
return peek;
|
||||
return peek!;
|
||||
}
|
||||
|
||||
public T PeekOrDefault() => !TryFetchPeek() ? default : peek;
|
||||
public T? PeekOrDefault() => !TryFetchPeek() ? default : peek;
|
||||
|
||||
/// <summary>
|
||||
/// Checks if a Next element exists
|
||||
|
|
|
@ -7,11 +7,8 @@ namespace PKHeX.Core
|
|||
/// </summary>
|
||||
public static class EncounterSuggestion
|
||||
{
|
||||
public static EncounterStatic GetSuggestedMetInfo(PKM pkm)
|
||||
public static EncounterStatic? GetSuggestedMetInfo(PKM pkm)
|
||||
{
|
||||
if (pkm == null)
|
||||
return null;
|
||||
|
||||
int loc = GetSuggestedTransferLocation(pkm);
|
||||
|
||||
if (pkm.WasEgg)
|
||||
|
|
|
@ -9,9 +9,9 @@ namespace PKHeX.Core
|
|||
/// </summary>
|
||||
public sealed class ValidEncounterMoves
|
||||
{
|
||||
public List<int>[] LevelUpMoves { get; } = Empty;
|
||||
public List<int>[] TMHMMoves { get; } = Empty;
|
||||
public List<int>[] TutorMoves { get; } = Empty;
|
||||
public IReadOnlyList<int>[] LevelUpMoves { get; } = Empty;
|
||||
public IReadOnlyList<int>[] TMHMMoves { get; } = Empty;
|
||||
public IReadOnlyList<int>[] TutorMoves { get; } = Empty;
|
||||
public int[] Relearn = Array.Empty<int>();
|
||||
|
||||
private const int EmptyCount = PKX.Generation + 1; // one for each generation index (and 0th)
|
||||
|
@ -28,6 +28,10 @@ namespace PKHeX.Core
|
|||
{
|
||||
LevelUpMoves = levelup;
|
||||
}
|
||||
public ValidEncounterMoves()
|
||||
{
|
||||
LevelUpMoves = Array.Empty<int[]>();
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class LevelUpRestriction
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace PKHeX.Core
|
||||
{
|
||||
|
@ -22,20 +23,17 @@ namespace PKHeX.Core
|
|||
get => _match;
|
||||
set
|
||||
{
|
||||
if (_match != null && (value.LevelMin != _match.LevelMin || value.Species != _match.Species))
|
||||
if (_match != EncounterInvalid.Default && (value.LevelMin != _match.LevelMin || value.Species != _match.Species))
|
||||
_evochains = null; // clear if evo chain has the potential to be different
|
||||
_match = value;
|
||||
Parse.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
private IEncounterable _match;
|
||||
|
||||
/// <summary>Indicates whether or not the <see cref="PKM"/> originated from <see cref="GameVersion.XD"/>.</summary>
|
||||
public bool WasXD => pkm?.Version == 15 && EncounterMatch is IVersion v && v.Version == GameVersion.XD;
|
||||
private IEncounterable _match = EncounterInvalid.Default;
|
||||
|
||||
/// <summary>Base Relearn Moves for the <see cref="EncounterMatch"/>.</summary>
|
||||
public IReadOnlyList<int> RelearnBase { get; internal set; }
|
||||
public IReadOnlyList<int> RelearnBase { get; internal set; } = Array.Empty<int>();
|
||||
|
||||
/// <summary>Top level Legality Check result list for the <see cref="EncounterMatch"/>.</summary>
|
||||
public readonly List<CheckResult> Parse = new List<CheckResult>();
|
||||
|
@ -43,12 +41,24 @@ namespace PKHeX.Core
|
|||
public CheckResult[] Relearn { get; internal set; } = new CheckResult[4];
|
||||
public CheckMoveResult[] Moves { get; internal set; } = new CheckMoveResult[4];
|
||||
|
||||
public ValidEncounterMoves EncounterMoves { get; internal set; }
|
||||
private static readonly ValidEncounterMoves NONE = new ValidEncounterMoves();
|
||||
public ValidEncounterMoves EncounterMoves { get; internal set; } = NONE;
|
||||
public IReadOnlyList<EvoCriteria>[] EvoChainsAllGens => _evochains ??= EvolutionChain.GetEvolutionChainsAllGens(pkm, EncounterMatch);
|
||||
private IReadOnlyList<EvoCriteria>[] _evochains;
|
||||
private IReadOnlyList<EvoCriteria>[]? _evochains;
|
||||
|
||||
/// <summary><see cref="RNG"/> related information that generated the <see cref="PKM.PID"/>/<see cref="PKM.IVs"/> value(s).</summary>
|
||||
public PIDIV PIDIV { get; internal set; }
|
||||
public PIDIV PIDIV
|
||||
{
|
||||
get => _pidiv;
|
||||
internal set
|
||||
{
|
||||
_pidiv = value;
|
||||
PIDParsed = true;
|
||||
}
|
||||
}
|
||||
|
||||
public bool PIDParsed { get; private set; }
|
||||
private PIDIV _pidiv = PIDIV.None;
|
||||
|
||||
/// <summary>Indicates whether or not the <see cref="PIDIV"/> can originate from the <see cref="EncounterMatch"/>.</summary>
|
||||
/// <remarks>This boolean is true until all valid <see cref="PIDIV"/> encounters are tested, after which it is false.</remarks>
|
||||
|
@ -58,12 +68,9 @@ namespace PKHeX.Core
|
|||
/// <remarks>This boolean is true until all valid <see cref="Frame"/> entries are tested for all possible <see cref="EncounterSlot"/> matches, after which it is false.</remarks>
|
||||
public bool FrameMatches { get; internal set; } = true;
|
||||
|
||||
public readonly bool Korean;
|
||||
|
||||
public LegalInfo(PKM pk)
|
||||
{
|
||||
pkm = pk;
|
||||
Korean = pk.Korean;
|
||||
|
||||
// Store repeatedly accessed values
|
||||
Game = (GameVersion)pkm.Version;
|
||||
|
@ -71,7 +78,7 @@ namespace PKHeX.Core
|
|||
}
|
||||
|
||||
/// <summary>List of all near-matches that were rejected for a given reason.</summary>
|
||||
public List<EncounterRejected> InvalidMatches;
|
||||
public List<EncounterRejected>? InvalidMatches;
|
||||
|
||||
internal void Reject(CheckResult c)
|
||||
{
|
||||
|
|
|
@ -43,15 +43,17 @@ namespace PKHeX.Core
|
|||
var restrict = new LevelUpRestriction(pkm, info);
|
||||
info.EncounterMoves = new ValidEncounterMoves(pkm, restrict);
|
||||
|
||||
List<int> defaultG1LevelMoves = null;
|
||||
List<int> defaultG2LevelMoves = null;
|
||||
IReadOnlyList<int> defaultG1LevelMoves = Array.Empty<int>();
|
||||
IReadOnlyList<int> defaultG2LevelMoves = Array.Empty<int>();
|
||||
var defaultTradeback = pkm.TradebackStatus;
|
||||
bool gb = false;
|
||||
if (info.EncounterMatch is IGeneration g && g.Generation <= 2)
|
||||
{
|
||||
gb = true;
|
||||
defaultG1LevelMoves = info.EncounterMoves.LevelUpMoves[1];
|
||||
defaultG2LevelMoves = pkm.InhabitedGeneration(2) ? info.EncounterMoves.LevelUpMoves[2] : null;
|
||||
if (pkm.InhabitedGeneration(2))
|
||||
defaultG2LevelMoves = info.EncounterMoves.LevelUpMoves[2];
|
||||
|
||||
// Generation 1 can have different minimum level in different encounter of the same species; update valid level moves
|
||||
UpdateGen1LevelUpMoves(pkm, info.EncounterMoves, restrict.MinimumLevelGen1, g.Generation, info);
|
||||
|
||||
|
@ -179,7 +181,7 @@ namespace PKHeX.Core
|
|||
return ParseMovesSpecialMoveset(pkm, Moves, info);
|
||||
var InitialMoves = Array.Empty<int>();
|
||||
var SpecialMoves = GetSpecialMoves(info.EncounterMatch);
|
||||
var games = info.EncounterMatch is IGeneration g && g.Generation == 1 ? GBRestrictions.GetGen1Versions(info) : GBRestrictions.GetGen2Versions(info);
|
||||
var games = info.EncounterMatch is IGeneration g && g.Generation == 1 ? GBRestrictions.GetGen1Versions(info) : GBRestrictions.GetGen2Versions(info, pkm.Korean);
|
||||
foreach (var ver in games)
|
||||
{
|
||||
var VerInitialMoves = MoveLevelUp.GetEncounterMoves(G1Encounter.Species, 0, G1Encounter.LevelMin, ver);
|
||||
|
@ -212,7 +214,7 @@ namespace PKHeX.Core
|
|||
|
||||
private static int[] GetSpecialMoves(IEncounterable EncounterMatch)
|
||||
{
|
||||
if (EncounterMatch is IMoveset mg && mg.Moves != null)
|
||||
if (EncounterMatch is IMoveset mg)
|
||||
return mg.Moves;
|
||||
return Array.Empty<int>();
|
||||
}
|
||||
|
@ -258,7 +260,7 @@ namespace PKHeX.Core
|
|||
return res;
|
||||
|
||||
// Encapsulate arguments to simplify method calls
|
||||
var moveInfo = new LearnInfo(pkm) { Source = source };
|
||||
var moveInfo = new LearnInfo(pkm, source);
|
||||
// Check moves going backwards, marking the move valid in the most current generation when it can be learned
|
||||
int[] generations = GetGenMovesCheckOrder(pkm);
|
||||
if (pkm.Format <= 2)
|
||||
|
@ -549,7 +551,7 @@ namespace PKHeX.Core
|
|||
}
|
||||
}
|
||||
|
||||
private static void ParseEvolutionsIncompatibleMoves(PKM pkm, IList<CheckMoveResult> res, int[] moves, List<int> tmhm)
|
||||
private static void ParseEvolutionsIncompatibleMoves(PKM pkm, IList<CheckMoveResult> res, IReadOnlyList<int> moves, IReadOnlyList<int> tmhm)
|
||||
{
|
||||
GBRestrictions.GetIncompatibleEvolutionMoves(pkm, moves, tmhm,
|
||||
out var prevSpeciesID,
|
||||
|
@ -829,7 +831,7 @@ namespace PKHeX.Core
|
|||
{
|
||||
if (generation >= 3)
|
||||
return;
|
||||
var lvlG1 = info.EncounterMatch?.LevelMin + 1 ?? 6;
|
||||
var lvlG1 = info.EncounterMatch.LevelMin + 1;
|
||||
if (lvlG1 == defaultLvlG1)
|
||||
return;
|
||||
EncounterMoves.LevelUpMoves[1] = Legal.GetValidMoves(pkm, info.EvoChainsAllGens[1], generation: 1, minLvLG1: lvlG1, LVL: true, Tutor: false, Machine: false, MoveReminder: false).ToList();
|
||||
|
@ -839,7 +841,7 @@ namespace PKHeX.Core
|
|||
{
|
||||
if (generation >= 3)
|
||||
return;
|
||||
var lvlG2 = info.EncounterMatch?.LevelMin + 1 ?? 6;
|
||||
var lvlG2 = info.EncounterMatch.LevelMin + 1;
|
||||
if (lvlG2 == defaultLvlG2)
|
||||
return;
|
||||
EncounterMoves.LevelUpMoves[2] = Legal.GetValidMoves(pkm, info.EvoChainsAllGens[2], generation: 2, minLvLG2: defaultLvlG2, LVL: true, Tutor: false, Machine: false, MoveReminder: false).ToList();
|
||||
|
|
|
@ -15,7 +15,7 @@ namespace PKHeX.Core
|
|||
int species = BitConverter.ToUInt16(data, offset + 4);
|
||||
|
||||
if (method == 0)
|
||||
return null;
|
||||
throw new ArgumentException(nameof(data));
|
||||
|
||||
// To have the same structure as gen 6
|
||||
// Gen 4 Method 6 is Gen 6 Method 7, G4 7 = G6 8, and so on
|
||||
|
|
|
@ -15,7 +15,7 @@ namespace PKHeX.Core
|
|||
int species = BitConverter.ToUInt16(data, offset + 4);
|
||||
|
||||
if (method == 0)
|
||||
return null;
|
||||
throw new ArgumentException(nameof(data));
|
||||
|
||||
var evo = new EvolutionMethod
|
||||
{
|
||||
|
|
|
@ -104,7 +104,7 @@ namespace PKHeX
|
|||
return new[] { moves1, moves2 };
|
||||
}
|
||||
|
||||
internal static void GetIncompatibleEvolutionMoves(PKM pkm, int[] moves, List<int> tmhm, out int previousspecies, out IList<int> incompatible_previous, out IList<int> incompatible_current)
|
||||
internal static void GetIncompatibleEvolutionMoves(PKM pkm, IReadOnlyList<int> moves, IReadOnlyList<int> tmhm, out int previousspecies, out IList<int> incompatible_previous, out IList<int> incompatible_current)
|
||||
{
|
||||
switch (pkm.Species)
|
||||
{
|
||||
|
@ -154,7 +154,7 @@ namespace PKHeX
|
|||
previousspecies = 0;
|
||||
}
|
||||
|
||||
internal static int GetRequiredMoveCount(PKM pk, int[] moves, LegalInfo info, int[] initialmoves)
|
||||
internal static int GetRequiredMoveCount(PKM pk, IReadOnlyList<int> moves, LegalInfo info, IReadOnlyList<int> initialmoves)
|
||||
{
|
||||
if (!pk.Gen1_NotTradeback) // No Move Deleter in Gen 1
|
||||
return 1; // Move Deleter exits, slots from 2 onwards can always be empty
|
||||
|
@ -174,7 +174,7 @@ namespace PKHeX
|
|||
return Math.Min(4, required);
|
||||
}
|
||||
|
||||
private static int GetRequiredMoveCount(PKM pk, int[] moves, List<int>[] learn, int[] initialmoves)
|
||||
private static int GetRequiredMoveCount(PKM pk, IReadOnlyList<int> moves, IReadOnlyList<int>[] learn, IReadOnlyList<int> initialmoves)
|
||||
{
|
||||
if (SpecialMinMoveSlots.Contains(pk.Species))
|
||||
return GetRequiredMoveCountSpecial(pk, moves, learn);
|
||||
|
@ -185,7 +185,7 @@ namespace PKHeX
|
|||
return required != 0 ? required : GetRequiredMoveCountDecrement(pk, moves, learn, initialmoves);
|
||||
}
|
||||
|
||||
private static int GetRequiredMoveSlotsRegular(PKM pk, int[] moves, List<int>[] learn, int[] initialmoves)
|
||||
private static int GetRequiredMoveSlotsRegular(PKM pk, IReadOnlyList<int> moves, IReadOnlyList<int>[] learn, IReadOnlyList<int> initialmoves)
|
||||
{
|
||||
int species = pk.Species;
|
||||
int catch_rate = ((PK1)pk).Catch_Rate;
|
||||
|
@ -209,7 +209,7 @@ namespace PKHeX
|
|||
return IsMoveCountRequired3(species, pk.CurrentLevel, moves) ? 3 : 0; // no match
|
||||
}
|
||||
|
||||
private static bool IsMoveCountRequired3(int species, int level, int[] moves)
|
||||
private static bool IsMoveCountRequired3(int species, int level, IReadOnlyList<int> moves)
|
||||
{
|
||||
// Species that evolve and learn the 4th move as evolved species at a greather level than base species
|
||||
// The 4th move is included in the level up table set as a preevolution move,
|
||||
|
@ -228,7 +228,7 @@ namespace PKHeX
|
|||
}
|
||||
}
|
||||
|
||||
private static int GetRequiredMoveCountDecrement(PKM pk, int[] moves, List<int>[] learn, int[] initialmoves)
|
||||
private static int GetRequiredMoveCountDecrement(PKM pk, IReadOnlyList<int> moves, IReadOnlyList<int>[] learn, IReadOnlyList<int> initialmoves)
|
||||
{
|
||||
int usedslots = initialmoves.Union(learn[1]).Where(m => m != 0).Distinct().Count();
|
||||
switch (pk.Species)
|
||||
|
@ -272,7 +272,7 @@ namespace PKHeX
|
|||
return usedslots;
|
||||
}
|
||||
|
||||
private static int GetRequiredMoveCountSpecial(PKM pk, int[] moves, List<int>[] learn)
|
||||
private static int GetRequiredMoveCountSpecial(PKM pk, IReadOnlyList<int> moves, IReadOnlyList<int>[] learn)
|
||||
{
|
||||
// Species with few mandatory slots, species with stone evolutions that could evolve at lower level and do not learn any more moves
|
||||
// and Pikachu and Nidoran family, those only have mandatory the initial moves and a few have one level up moves,
|
||||
|
@ -322,9 +322,9 @@ namespace PKHeX
|
|||
return MoveLevelUp.GetMovesLevelUp1(basespecies, 0, maxlevel, minlevel);
|
||||
}
|
||||
|
||||
internal static IEnumerable<GameVersion> GetGen2Versions(LegalInfo Info)
|
||||
internal static IEnumerable<GameVersion> GetGen2Versions(LegalInfo Info, bool korean)
|
||||
{
|
||||
if (ParseSettings.AllowGen2Crystal(Info.Korean) && Info.Game.Contains(GameVersion.C))
|
||||
if (ParseSettings.AllowGen2Crystal(korean) && Info.Game.Contains(GameVersion.C))
|
||||
yield return GameVersion.C;
|
||||
yield return GameVersion.GS;
|
||||
}
|
||||
|
|
|
@ -6,22 +6,23 @@ namespace PKHeX.Core
|
|||
/// <summary>
|
||||
/// Level Up Learn Movepool Information
|
||||
/// </summary>
|
||||
public abstract class Learnset
|
||||
public sealed class Learnset
|
||||
{
|
||||
/// <summary>
|
||||
/// Amount of moves present.
|
||||
/// </summary>
|
||||
protected int Count;
|
||||
|
||||
/// <summary>
|
||||
/// Moves that can be learned.
|
||||
/// </summary>
|
||||
protected int[] Moves;
|
||||
private readonly int[] Moves;
|
||||
|
||||
/// <summary>
|
||||
/// Levels at which a move at a given index can be learned.
|
||||
/// </summary>
|
||||
protected int[] Levels;
|
||||
private readonly int[] Levels;
|
||||
|
||||
public Learnset(int[] moves, int[] levels)
|
||||
{
|
||||
Moves = moves;
|
||||
Levels = levels;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the moves a Pokémon can learn between the specified level range.
|
||||
|
@ -147,7 +148,7 @@ namespace PKHeX.Core
|
|||
return Math.Max(end - 4, 1);
|
||||
}
|
||||
|
||||
private Dictionary<int, int> Learn;
|
||||
private Dictionary<int, int>? Learn;
|
||||
|
||||
private Dictionary<int, int> GetDictionary()
|
||||
{
|
||||
|
@ -165,7 +166,7 @@ namespace PKHeX.Core
|
|||
/// <returns>Level the move is learned at. If the result is below 0, the move cannot be learned by leveling up.</returns>
|
||||
public int GetLevelLearnMove(int move)
|
||||
{
|
||||
return (Learn ?? (Learn = GetDictionary())).TryGetValue(move, out var level) ? level : -1;
|
||||
return (Learn ??= GetDictionary()).TryGetValue(move, out var level) ? level : -1;
|
||||
}
|
||||
|
||||
/// <summary>Returns the level that a Pokémon can learn the specified move.</summary>
|
||||
|
|
|
@ -1,35 +0,0 @@
|
|||
namespace PKHeX.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Level Up Learn Movepool Information (Generation 1/2)
|
||||
/// </summary>
|
||||
public sealed class Learnset1 : Learnset
|
||||
{
|
||||
private Learnset1(byte[] data, ref int offset)
|
||||
{
|
||||
int end = offset; // scan for count
|
||||
while (data[end] != 0)
|
||||
end += 2;
|
||||
Count = (end - offset) / 2;
|
||||
Moves = new int[Count];
|
||||
Levels = new int[Count];
|
||||
for (int i = 0; i < Moves.Length; i++)
|
||||
{
|
||||
Levels[i] = data[offset++];
|
||||
Moves[i] = data[offset++];
|
||||
}
|
||||
++offset;
|
||||
}
|
||||
|
||||
public static Learnset[] GetArray(byte[] input, int maxSpecies)
|
||||
{
|
||||
var data = new Learnset[maxSpecies + 1];
|
||||
|
||||
int offset = 0;
|
||||
for (int s = 0; s < data.Length; s++)
|
||||
data[s] = new Learnset1(input, ref offset);
|
||||
|
||||
return data;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace PKHeX.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Level Up Learn Movepool Information
|
||||
/// </summary>
|
||||
public sealed class Learnset6 : Learnset
|
||||
{
|
||||
private Learnset6(byte[] data)
|
||||
{
|
||||
if (data.Length < 4 || data.Length % 4 != 0)
|
||||
{ Count = 0; Levels = Moves = Array.Empty<int>(); return; }
|
||||
Count = (data.Length / 4) - 1;
|
||||
Moves = new int[Count];
|
||||
Levels = new int[Count];
|
||||
using var ms = new MemoryStream(data);
|
||||
using var br = new BinaryReader(ms);
|
||||
for (int i = 0; i < Count; i++)
|
||||
{
|
||||
Moves[i] = br.ReadInt16();
|
||||
Levels[i] = br.ReadInt16();
|
||||
}
|
||||
}
|
||||
|
||||
public static Learnset[] GetArray(byte[][] entries)
|
||||
{
|
||||
Learnset[] data = new Learnset[entries.Length];
|
||||
for (int i = 0; i < data.Length; i++)
|
||||
data[i] = new Learnset6(entries[i]);
|
||||
return data;
|
||||
}
|
||||
}
|
||||
}
|
77
PKHeX.Core/Legality/Learnset/LearnsetReader.cs
Normal file
77
PKHeX.Core/Legality/Learnset/LearnsetReader.cs
Normal file
|
@ -0,0 +1,77 @@
|
|||
using System;
|
||||
|
||||
namespace PKHeX.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Unpacks <see cref="Learnset"/> data from legality binary inputs.
|
||||
/// </summary>
|
||||
public static class LearnsetReader
|
||||
{
|
||||
private static readonly Learnset EMPTY = new Learnset(Array.Empty<int>(), Array.Empty<int>());
|
||||
|
||||
public static Learnset[] GetArray(byte[] input, int maxSpecies)
|
||||
{
|
||||
var data = new Learnset[maxSpecies + 1];
|
||||
|
||||
int offset = 0;
|
||||
for (int s = 0; s < data.Length; s++)
|
||||
data[s] = ReadLearnset8(input, ref offset);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
public static Learnset[] GetArray(byte[][] entries)
|
||||
{
|
||||
Learnset[] data = new Learnset[entries.Length];
|
||||
for (int i = 0; i < data.Length; i++)
|
||||
data[i] = ReadLearnset16(entries[i]);
|
||||
return data;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a Level up move pool definition from a contiguous chunk of GB era ROM data.
|
||||
/// </summary>
|
||||
/// <remarks>Moves and Levels are 8-bit</remarks>
|
||||
private static Learnset ReadLearnset8(byte[] data, ref int offset)
|
||||
{
|
||||
int end = offset; // scan for count
|
||||
if (data[end] == 0)
|
||||
{
|
||||
++offset;
|
||||
return EMPTY;
|
||||
}
|
||||
do { end += 2; } while (data[end] != 0);
|
||||
|
||||
var Count = (end - offset) / 2;
|
||||
var Moves = new int[Count];
|
||||
var Levels = new int[Count];
|
||||
for (int i = 0; i < Moves.Length; i++)
|
||||
{
|
||||
Levels[i] = data[offset++];
|
||||
Moves[i] = data[offset++];
|
||||
}
|
||||
++offset;
|
||||
return new Learnset(Moves, Levels);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a Level up move pool definition from a single move pool definition.
|
||||
/// </summary>
|
||||
/// <remarks>Count of moves, followed by Moves and Levels which are 16-bit</remarks>
|
||||
private static Learnset ReadLearnset16(byte[] data)
|
||||
{
|
||||
if (data.Length < 4 || data.Length % 4 != 0)
|
||||
return EMPTY;
|
||||
var Count = (data.Length / 4) - 1;
|
||||
var Moves = new int[Count];
|
||||
var Levels = new int[Count];
|
||||
for (int i = 0; i < Count; i++)
|
||||
{
|
||||
int ofs = i * 4;
|
||||
Moves[i] = BitConverter.ToInt16(data, ofs);
|
||||
Levels[i] = BitConverter.ToInt16(data, ofs + 2);
|
||||
}
|
||||
return new Learnset(Moves, Levels);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -11,13 +11,14 @@ namespace PKHeX.Core
|
|||
public List<int> LevelUpEggMoves { get; } = new List<int>();
|
||||
public List<int> EventEggMoves { get; } = new List<int>();
|
||||
public List<int> IncenseMoves { get; } = new List<int>();
|
||||
public MoveParseSource Source { get; set; }
|
||||
|
||||
public readonly MoveParseSource Source;
|
||||
public readonly bool IsGen2Pkm;
|
||||
|
||||
public LearnInfo(PKM pkm)
|
||||
public LearnInfo(PKM pkm, MoveParseSource source)
|
||||
{
|
||||
IsGen2Pkm = pkm.Format == 2 || pkm.VC2;
|
||||
Source = source;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -30,49 +30,42 @@ namespace PKHeX.Core
|
|||
case 3:
|
||||
return EggMovesRS[species].Moves;
|
||||
case 4:
|
||||
switch (version)
|
||||
return version switch
|
||||
{
|
||||
case GameVersion.HG:
|
||||
case GameVersion.SS:
|
||||
return EggMovesHGSS[species].Moves;
|
||||
default:
|
||||
return EggMovesDPPt[species].Moves;
|
||||
}
|
||||
GameVersion.HG => EggMovesHGSS[species].Moves,
|
||||
GameVersion.SS => EggMovesHGSS[species].Moves,
|
||||
_ => EggMovesDPPt[species].Moves
|
||||
};
|
||||
case 5:
|
||||
return EggMovesBW[species].Moves;
|
||||
case 6: // entries per species
|
||||
switch (version)
|
||||
return version switch
|
||||
{
|
||||
case GameVersion.OR:
|
||||
case GameVersion.AS:
|
||||
return EggMovesAO[species].Moves;
|
||||
default:
|
||||
return EggMovesXY[species].Moves;
|
||||
}
|
||||
GameVersion.OR => EggMovesAO[species].Moves,
|
||||
GameVersion.AS => EggMovesAO[species].Moves,
|
||||
_ => EggMovesXY[species].Moves
|
||||
};
|
||||
|
||||
case 7: // entries per form if required
|
||||
switch (version)
|
||||
return version switch
|
||||
{
|
||||
case GameVersion.US:
|
||||
case GameVersion.UM:
|
||||
return GetFormEggMoves(species, formnum, EggMovesUSUM);
|
||||
default:
|
||||
return GetFormEggMoves(species, formnum, EggMovesSM);
|
||||
}
|
||||
GameVersion.US => GetFormEggMoves(species, formnum, EggMovesUSUM),
|
||||
GameVersion.UM => GetFormEggMoves(species, formnum, EggMovesUSUM),
|
||||
_ => GetFormEggMoves(species, formnum, EggMovesSM)
|
||||
};
|
||||
|
||||
case 8:
|
||||
switch (version)
|
||||
return version switch
|
||||
{
|
||||
default:
|
||||
return GetFormEggMoves(species, formnum, EggMovesSWSH);
|
||||
}
|
||||
_ => GetFormEggMoves(species, formnum, EggMovesSWSH)
|
||||
};
|
||||
|
||||
default:
|
||||
return Array.Empty<int>();
|
||||
}
|
||||
}
|
||||
|
||||
private static int[] GetFormEggMoves(int species, int formnum, EggMoves[] table)
|
||||
private static int[] GetFormEggMoves(int species, int formnum, IReadOnlyList<EggMoves7> table)
|
||||
{
|
||||
var entry = table[species];
|
||||
if (formnum > 0 && AlolanOriginForms.Contains(species))
|
||||
|
|
|
@ -239,7 +239,7 @@ namespace PKHeX.Core
|
|||
};
|
||||
}
|
||||
|
||||
private static Learnset GetDeoxysLearn3(int form, GameVersion ver = Any)
|
||||
private static Learnset? GetDeoxysLearn3(int form, GameVersion ver = Any)
|
||||
{
|
||||
const int index = (int)Species.Deoxys;
|
||||
if (ver == Any)
|
||||
|
@ -266,7 +266,7 @@ namespace PKHeX.Core
|
|||
version = (GameVersion)pkm.Version;
|
||||
return Generation switch
|
||||
{
|
||||
1 => (IEnumerable<int>) GetMovesLevelUp1(species, form, lvl, minlvlG1, version),
|
||||
1 => GetMovesLevelUp1(species, form, lvl, minlvlG1, version),
|
||||
2 => GetMovesLevelUp2(species, form, lvl, minlvlG2, pkm.Korean, pkm.LearnMovesNew2Disallowed(), version),
|
||||
3 => GetMovesLevelUp3(species, form, lvl, version),
|
||||
4 => GetMovesLevelUp4(species, form, lvl, version),
|
||||
|
@ -274,7 +274,7 @@ namespace PKHeX.Core
|
|||
6 => GetMovesLevelUp6(species, form, lvl, version),
|
||||
7 => GetMovesLevelUp7(species, form, lvl, MoveReminder, version),
|
||||
8 => GetMovesLevelUp8(species, form, lvl, MoveReminder, version),
|
||||
_ => Array.Empty<int>()
|
||||
_ => (IEnumerable<int>)Array.Empty<int>()
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -13,13 +13,10 @@ namespace PKHeX.Core
|
|||
/// <returns><see cref="IEnumerable{Frame}"/> to yield possible encounter details for further filtering</returns>
|
||||
public static IEnumerable<Frame> GetFrames(PIDIV pidiv, PKM pk)
|
||||
{
|
||||
if (pidiv.RNG == null)
|
||||
return Enumerable.Empty<Frame>();
|
||||
FrameGenerator info = new FrameGenerator(pidiv, pk);
|
||||
if (info.FrameType == FrameType.None)
|
||||
if (pk.Version == (int)GameVersion.CXD)
|
||||
return Enumerable.Empty<Frame>();
|
||||
|
||||
info.Nature = pk.EncryptionConstant % 25;
|
||||
var info = new FrameGenerator(pk) {Nature = pk.EncryptionConstant % 25};
|
||||
|
||||
// gather possible nature determination seeds until a same-nature PID breaks the unrolling
|
||||
var seeds = pk.Species == 201 && pk.FRLG // reversed await case
|
||||
|
@ -280,12 +277,12 @@ namespace PKHeX.Core
|
|||
if (!sync && !reg) // doesn't generate nature frame
|
||||
continue;
|
||||
|
||||
uint prev = pidiv.RNG.Prev(s);
|
||||
uint prev = RNG.LCRNG.Prev(s);
|
||||
if (info.AllowLeads && reg) // check for failed sync
|
||||
{
|
||||
var failsync = (info.DPPt ? prev >> 31 : (prev >> 16) & 1) != 1;
|
||||
if (failsync)
|
||||
yield return info.GetFrame(pidiv.RNG.Prev(prev), LeadRequired.SynchronizeFail);
|
||||
yield return info.GetFrame(RNG.LCRNG.Prev(prev), LeadRequired.SynchronizeFail);
|
||||
}
|
||||
if (sync)
|
||||
yield return info.GetFrame(prev, LeadRequired.Synchronize);
|
||||
|
@ -298,7 +295,7 @@ namespace PKHeX.Core
|
|||
else
|
||||
{
|
||||
if (info.Safari3)
|
||||
prev = pidiv.RNG.Prev(prev); // wasted RNG call
|
||||
prev = RNG.LCRNG.Prev(prev); // wasted RNG call
|
||||
yield return info.GetFrame(prev, LeadRequired.None);
|
||||
}
|
||||
}
|
||||
|
@ -382,7 +379,7 @@ namespace PKHeX.Core
|
|||
if (nature != info.Nature)
|
||||
continue;
|
||||
|
||||
var prev = pidiv.RNG.Prev(s);
|
||||
var prev = RNG.LCRNG.Prev(s);
|
||||
var proc = prev >> 16;
|
||||
bool charmProc = (info.DPPt ? proc / 0x5556 : proc % 3) != 0; // 2/3 odds
|
||||
if (!charmProc)
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
namespace PKHeX.Core
|
||||
using System;
|
||||
|
||||
namespace PKHeX.Core
|
||||
{
|
||||
public sealed class FrameGenerator
|
||||
{
|
||||
|
@ -23,13 +25,13 @@
|
|||
};
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Search Criteria parameters necessary for generating <see cref="SeedInfo"/> and <see cref="Frame"/> objects.
|
||||
/// Gets the Search Criteria parameters necessary for generating <see cref="SeedInfo"/> and <see cref="Frame"/> objects for Gen3/4 mainline games.
|
||||
/// </summary>
|
||||
/// <param name="pidiv">Info used to determine the <see cref="FrameType"/>.</param>
|
||||
/// <param name="pk"><see cref="PKM"/> object containing various accessible information required for the encounter.</param>
|
||||
/// <returns>Object containing search criteria to be passed by reference to search/filter methods.</returns>
|
||||
public FrameGenerator(PIDIV pidiv, PKM pk)
|
||||
public FrameGenerator(PKM pk)
|
||||
{
|
||||
RNG = RNG.LCRNG;
|
||||
var ver = (GameVersion)pk.Version;
|
||||
switch (ver)
|
||||
{
|
||||
|
@ -41,7 +43,6 @@
|
|||
case GameVersion.E:
|
||||
DPPt = false;
|
||||
FrameType = FrameType.MethodH;
|
||||
RNG = pidiv.RNG;
|
||||
Safari3 = pk.Ball == 5 && !pk.FRLG;
|
||||
|
||||
if (ver != GameVersion.E)
|
||||
|
@ -68,7 +69,7 @@
|
|||
DPPt = true;
|
||||
AllowLeads = true;
|
||||
FrameType = FrameType.MethodJ;
|
||||
RNG = pidiv.RNG;
|
||||
RNG = RNG.LCRNG;
|
||||
return;
|
||||
|
||||
// Method K
|
||||
|
@ -77,8 +78,10 @@
|
|||
DPPt = false;
|
||||
AllowLeads = true;
|
||||
FrameType = FrameType.MethodK;
|
||||
RNG = pidiv.RNG;
|
||||
RNG = RNG.LCRNG;
|
||||
return;
|
||||
default:
|
||||
throw new ArgumentException(nameof(ver));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@ namespace PKHeX.Core
|
|||
yield return new SeedInfo { Seed = seed };
|
||||
|
||||
var s1 = seed;
|
||||
var s2 = pidiv.RNG.Prev(s1);
|
||||
var s2 = RNG.LCRNG.Prev(s1);
|
||||
while (true)
|
||||
{
|
||||
var a = s2 >> 16;
|
||||
|
@ -39,8 +39,8 @@ namespace PKHeX.Core
|
|||
break;
|
||||
}
|
||||
|
||||
s1 = pidiv.RNG.Prev(s2);
|
||||
s2 = pidiv.RNG.Prev(s1);
|
||||
s1 = RNG.LCRNG.Prev(s2);
|
||||
s2 = RNG.LCRNG.Prev(s1);
|
||||
|
||||
yield return new SeedInfo { Seed = s1, Charm3 = charm3 };
|
||||
}
|
||||
|
@ -59,7 +59,7 @@ namespace PKHeX.Core
|
|||
yield return new SeedInfo { Seed = seed };
|
||||
|
||||
var s1 = seed;
|
||||
var s2 = pidiv.RNG.Prev(s1);
|
||||
var s2 = RNG.LCRNG.Prev(s1);
|
||||
while (true)
|
||||
{
|
||||
var a = s2 >> 16;
|
||||
|
@ -77,8 +77,8 @@ namespace PKHeX.Core
|
|||
}
|
||||
}
|
||||
|
||||
s1 = pidiv.RNG.Prev(s2);
|
||||
s2 = pidiv.RNG.Prev(s1);
|
||||
s1 = RNG.LCRNG.Prev(s2);
|
||||
s2 = RNG.LCRNG.Prev(s1);
|
||||
|
||||
yield return new SeedInfo { Seed = s1 };
|
||||
}
|
||||
|
|
|
@ -2,13 +2,24 @@ namespace PKHeX.Core
|
|||
{
|
||||
public sealed class TeamLock
|
||||
{
|
||||
public int Species;
|
||||
public string Comment;
|
||||
public NPCLock[] Locks;
|
||||
public readonly int Species;
|
||||
public readonly string Comment;
|
||||
public readonly NPCLock[] Locks;
|
||||
|
||||
internal TeamLock Clone()
|
||||
internal TeamLock Clone() => new TeamLock(Species, Comment, (NPCLock[])Locks.Clone());
|
||||
|
||||
public TeamLock(int species, NPCLock[] locks)
|
||||
{
|
||||
return new TeamLock { Comment = Comment, Locks = (NPCLock[])Locks.Clone() };
|
||||
Species = species;
|
||||
Locks = locks;
|
||||
Comment = string.Empty;
|
||||
}
|
||||
|
||||
public TeamLock(int species, string comment, NPCLock[] locks)
|
||||
{
|
||||
Species = species;
|
||||
Locks = locks;
|
||||
Comment = comment;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -76,7 +76,7 @@ namespace PKHeX.Core
|
|||
/// <param name="frame">Frame at which the search starts/continues at.</param>
|
||||
/// <param name="prior">Prior <see cref="NPCLock"/> data. If this is the last lock in the CPU Team, this is null.</param>
|
||||
/// <returns>True if the <see cref="Specifications"/> are valid.</returns>
|
||||
private bool FindLockSeed(int frame = 0, NPCLock prior = null)
|
||||
private bool FindLockSeed(int frame = 0, NPCLock? prior = null)
|
||||
{
|
||||
if (Locks.Count == 0) // full team reverse-generated
|
||||
return VerifyNPC(frame);
|
||||
|
@ -102,7 +102,7 @@ namespace PKHeX.Core
|
|||
/// <param name="current">Current lock criteria to satisfy. Used to find valid <see cref="SeedFrame"/> results to yield.</param>
|
||||
/// <param name="prior">Prior lock criteria. Used for determining when the traversal stops.</param>
|
||||
/// <returns>List of possible locks for the provided input.</returns>
|
||||
private IEnumerable<SeedFrame> GetPossibleLocks(int ctr, NPCLock current, NPCLock prior)
|
||||
private IEnumerable<SeedFrame> GetPossibleLocks(int ctr, NPCLock current, NPCLock? prior)
|
||||
{
|
||||
if (prior?.Shadow != false)
|
||||
return GetSingleLock(ctr, current);
|
||||
|
|
|
@ -10,7 +10,6 @@ namespace PKHeX.Core
|
|||
/// </summary>
|
||||
public static class MethodFinder
|
||||
{
|
||||
private static readonly PIDIV NonMatch = new PIDIV {NoSeed = true, Type = PIDType.None};
|
||||
|
||||
/// <summary>
|
||||
/// Analyzes a <see cref="PKM"/> to find a matching PIDIV method.
|
||||
|
@ -99,7 +98,7 @@ namespace PKHeX.Core
|
|||
var ivD = D >> 16 & 0x7FFF;
|
||||
if (iv2 == ivD) // ABCD
|
||||
{
|
||||
pidiv = new PIDIV {OriginSeed = seed, RNG = RNG.LCRNG, Type = PIDType.Method_1};
|
||||
pidiv = new PIDIV {OriginSeed = seed, RNG = RNGType.LCRNG, Type = PIDType.Method_1};
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -107,7 +106,7 @@ namespace PKHeX.Core
|
|||
var ivE = E >> 16 & 0x7FFF;
|
||||
if (iv2 == ivE) // ABCE
|
||||
{
|
||||
pidiv = new PIDIV {OriginSeed = seed, RNG = RNG.LCRNG, Type = PIDType.Method_4};
|
||||
pidiv = new PIDIV {OriginSeed = seed, RNG = RNGType.LCRNG, Type = PIDType.Method_4};
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -122,7 +121,7 @@ namespace PKHeX.Core
|
|||
var ivE = E >> 16 & 0x7FFF;
|
||||
if (iv2 == ivE) // ABDE
|
||||
{
|
||||
pidiv = new PIDIV {OriginSeed = seed, RNG = RNG.LCRNG, Type = PIDType.Method_2};
|
||||
pidiv = new PIDIV {OriginSeed = seed, RNG = RNGType.LCRNG, Type = PIDType.Method_2};
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -142,7 +141,7 @@ namespace PKHeX.Core
|
|||
var ivE = E >> 16 & 0x7FFF;
|
||||
if (iv2 != ivE)
|
||||
continue;
|
||||
pidiv = new PIDIV {OriginSeed = seed, RNG = RNG.LCRNG, Type = PIDType.Method_3};
|
||||
pidiv = new PIDIV {OriginSeed = seed, RNG = RNGType.LCRNG, Type = PIDType.Method_3};
|
||||
return true;
|
||||
}
|
||||
return GetNonMatch(out pidiv);
|
||||
|
@ -168,7 +167,7 @@ namespace PKHeX.Core
|
|||
var ivD = D >> 16 & 0x7FFF;
|
||||
if (iv2 == ivD) // BACD
|
||||
{
|
||||
pidiv = new PIDIV {OriginSeed = seed, RNG = RNG.LCRNG, Type = PIDType.Method_1_Unown};
|
||||
pidiv = new PIDIV {OriginSeed = seed, RNG = RNGType.LCRNG, Type = PIDType.Method_1_Unown};
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -176,7 +175,7 @@ namespace PKHeX.Core
|
|||
var ivE = E >> 16 & 0x7FFF;
|
||||
if (iv2 == ivE) // BACE
|
||||
{
|
||||
pidiv = new PIDIV {OriginSeed = seed, RNG = RNG.LCRNG, Type = PIDType.Method_4_Unown};
|
||||
pidiv = new PIDIV {OriginSeed = seed, RNG = RNGType.LCRNG, Type = PIDType.Method_4_Unown};
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -191,7 +190,7 @@ namespace PKHeX.Core
|
|||
var ivE = E >> 16 & 0x7FFF;
|
||||
if (iv2 == ivE) // BADE
|
||||
{
|
||||
pidiv = new PIDIV {OriginSeed = seed, RNG = RNG.LCRNG, Type = PIDType.Method_2_Unown};
|
||||
pidiv = new PIDIV {OriginSeed = seed, RNG = RNGType.LCRNG, Type = PIDType.Method_2_Unown};
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -211,7 +210,7 @@ namespace PKHeX.Core
|
|||
var ivE = E >> 16 & 0x7FFF;
|
||||
if (iv2 != ivE)
|
||||
continue;
|
||||
pidiv = new PIDIV {OriginSeed = seed, RNG = RNG.LCRNG, Type = PIDType.Method_3_Unown};
|
||||
pidiv = new PIDIV {OriginSeed = seed, RNG = RNGType.LCRNG, Type = PIDType.Method_3_Unown};
|
||||
return true;
|
||||
}
|
||||
return GetNonMatch(out pidiv);
|
||||
|
@ -230,7 +229,7 @@ namespace PKHeX.Core
|
|||
if (iv1 != ivC)
|
||||
continue;
|
||||
|
||||
pidiv = new PIDIV {OriginSeed = seed, RNG = RNG.LCRNG, Type = PIDType.Method_1_Roamer};
|
||||
pidiv = new PIDIV {OriginSeed = seed, RNG = RNGType.LCRNG, Type = PIDType.Method_1_Roamer};
|
||||
return true;
|
||||
}
|
||||
return GetNonMatch(out pidiv);
|
||||
|
@ -272,7 +271,7 @@ namespace PKHeX.Core
|
|||
}
|
||||
pidiv = new PIDIVTSV
|
||||
{
|
||||
OriginSeed = RNG.XDRNG.Prev(A), RNG = RNG.XDRNG, Type = PIDType.CXDAnti,
|
||||
OriginSeed = RNG.XDRNG.Prev(A), RNG = RNGType.XDRNG, Type = PIDType.CXDAnti,
|
||||
TSV1 = tsv1, TSV2 = tsv2,
|
||||
};
|
||||
return true;
|
||||
|
@ -280,7 +279,7 @@ namespace PKHeX.Core
|
|||
continue;
|
||||
}
|
||||
|
||||
pidiv = new PIDIV {OriginSeed = RNG.XDRNG.Prev(A), RNG = RNG.XDRNG, Type = PIDType.CXD};
|
||||
pidiv = new PIDIV {OriginSeed = RNG.XDRNG.Prev(A), RNG = RNGType.XDRNG, Type = PIDType.CXD};
|
||||
return true;
|
||||
}
|
||||
return GetNonMatch(out pidiv);
|
||||
|
@ -315,7 +314,7 @@ namespace PKHeX.Core
|
|||
if (seed >> 16 != pk.SID)
|
||||
continue;
|
||||
|
||||
pidiv = new PIDIV {OriginSeed = RNG.XDRNG.Prev(seed), RNG = RNG.XDRNG, Type = PIDType.Channel};
|
||||
pidiv = new PIDIV {OriginSeed = RNG.XDRNG.Prev(seed), RNG = RNGType.XDRNG, Type = PIDType.Channel};
|
||||
return true;
|
||||
}
|
||||
return GetNonMatch(out pidiv);
|
||||
|
@ -333,7 +332,7 @@ namespace PKHeX.Core
|
|||
if (!IVsMatch(C >> 16, D >> 16, IVs))
|
||||
continue;
|
||||
|
||||
pidiv = new PIDIV {OriginSeed = seed, RNG = RNG.LCRNG, Type = PIDType.G4MGAntiShiny};
|
||||
pidiv = new PIDIV {OriginSeed = seed, RNG = RNGType.LCRNG, Type = PIDType.G4MGAntiShiny};
|
||||
return true;
|
||||
}
|
||||
return GetNonMatch(out pidiv);
|
||||
|
@ -375,7 +374,7 @@ namespace PKHeX.Core
|
|||
if (nature + rate != pid)
|
||||
break;
|
||||
|
||||
pidiv = new PIDIV {NoSeed = true, RNG = RNG.LCRNG, Type = PIDType.CuteCharm};
|
||||
pidiv = new PIDIV {NoSeed = true, RNG = RNGType.LCRNG, Type = PIDType.CuteCharm};
|
||||
return true;
|
||||
case 1: // female
|
||||
if (pid >= 25)
|
||||
|
@ -383,7 +382,7 @@ namespace PKHeX.Core
|
|||
if (254 <= getRatio()) // no modification for PID
|
||||
break;
|
||||
|
||||
pidiv = new PIDIV {NoSeed = true, RNG = RNG.LCRNG, Type = PIDType.CuteCharm};
|
||||
pidiv = new PIDIV {NoSeed = true, RNG = RNGType.LCRNG, Type = PIDType.CuteCharm};
|
||||
return true;
|
||||
}
|
||||
return GetNonMatch(out pidiv);
|
||||
|
@ -426,7 +425,7 @@ namespace PKHeX.Core
|
|||
continue;
|
||||
|
||||
s = RNG.LCRNG.Reverse(lower, 2); // unroll one final time to get the origin seed
|
||||
pidiv = new PIDIV {OriginSeed = s, RNG = RNG.LCRNG, Type = PIDType.ChainShiny};
|
||||
pidiv = new PIDIV {OriginSeed = s, RNG = RNGType.LCRNG, Type = PIDType.ChainShiny};
|
||||
return true;
|
||||
}
|
||||
return GetNonMatch(out pidiv);
|
||||
|
@ -478,11 +477,11 @@ namespace PKHeX.Core
|
|||
if ((sn & 0xFFFF0000) != 0)
|
||||
continue;
|
||||
// shift from unrestricted enum val to restricted enum val
|
||||
pidiv = new PIDIV {OriginSeed = sn, RNG = RNG.LCRNG, Type = --type };
|
||||
pidiv = new PIDIV {OriginSeed = sn, RNG = RNGType.LCRNG, Type = --type };
|
||||
return true;
|
||||
}
|
||||
// no restricted seed found, thus unrestricted
|
||||
pidiv = new PIDIV {OriginSeed = s, RNG = RNG.LCRNG, Type = type};
|
||||
pidiv = new PIDIV {OriginSeed = s, RNG = RNGType.LCRNG, Type = type};
|
||||
return true;
|
||||
}
|
||||
return GetNonMatch(out pidiv);
|
||||
|
@ -506,7 +505,7 @@ namespace PKHeX.Core
|
|||
if (!(gender == 0 && IsAzurillEdgeCaseM(pk, nature, oldpid)))
|
||||
return GetNonMatch(out pidiv);
|
||||
}
|
||||
pidiv = new PIDIV {NoSeed = true, RNG = RNG.LCRNG, Type = PIDType.Pokewalker};
|
||||
pidiv = new PIDIV {NoSeed = true, RNG = RNGType.LCRNG, Type = PIDType.Pokewalker};
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -541,7 +540,7 @@ namespace PKHeX.Core
|
|||
if (!LockFinder.IsColoStarterValid(pk.Species, ref origin, pk.TID, pk.SID, pk.PID, iv1, iv2))
|
||||
continue;
|
||||
|
||||
pidiv = new PIDIV { OriginSeed = origin, RNG = RNG.XDRNG, Type = PIDType.CXD_ColoStarter };
|
||||
pidiv = new PIDIV { OriginSeed = origin, RNG = RNGType.XDRNG, Type = PIDType.CXD_ColoStarter };
|
||||
return true;
|
||||
}
|
||||
return GetNonMatch(out pidiv);
|
||||
|
@ -555,7 +554,7 @@ namespace PKHeX.Core
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static bool GetNonMatch(out PIDIV pidiv)
|
||||
{
|
||||
pidiv = NonMatch;
|
||||
pidiv = PIDIV.None;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -622,7 +621,7 @@ namespace PKHeX.Core
|
|||
private static PIDIV AnalyzeGB(PKM _)
|
||||
{
|
||||
// not implemented; correlation between IVs and RNG hasn't been converted to code.
|
||||
return NonMatch;
|
||||
return PIDIV.None;
|
||||
}
|
||||
|
||||
private static IEnumerable<uint> GetSeedsFromPID(RNG method, uint a, uint b)
|
||||
|
@ -760,7 +759,7 @@ namespace PKHeX.Core
|
|||
|
||||
var C = RNG.XDRNG.Advance(A, 7);
|
||||
|
||||
yield return new PIDIV { OriginSeed = RNG.XDRNG.Prev(C), RNG = RNG.XDRNG, Type = PIDType.CXD };
|
||||
yield return new PIDIV { OriginSeed = RNG.XDRNG.Prev(C), RNG = RNGType.XDRNG, Type = PIDType.CXD };
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -778,7 +777,7 @@ namespace PKHeX.Core
|
|||
// check for valid encounter slot info
|
||||
if (!IsPokeSpotActivation(slot, seed, out uint s))
|
||||
continue;
|
||||
yield return new PIDIV {OriginSeed = s, RNG = RNG.XDRNG, Type = PIDType.PokeSpot};
|
||||
yield return new PIDIV {OriginSeed = s, RNG = RNGType.XDRNG, Type = PIDType.PokeSpot};
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,8 +2,10 @@
|
|||
{
|
||||
public class PIDIV
|
||||
{
|
||||
public static readonly PIDIV None = new PIDIV { NoSeed = true, Type = PIDType.None };
|
||||
|
||||
/// <summary> The RNG that generated the PKM from the <see cref="OriginSeed"/> </summary>
|
||||
public RNG RNG;
|
||||
public RNGType RNG;
|
||||
|
||||
/// <summary> The RNG seed which immediately generates the PIDIV (starting with PID or IVs, whichever comes first). </summary>
|
||||
public uint OriginSeed;
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace PKHeX.Core
|
||||
|
@ -219,4 +220,26 @@ namespace PKHeX.Core
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum RNGType
|
||||
{
|
||||
None,
|
||||
LCRNG,
|
||||
XDRNG,
|
||||
ARNG,
|
||||
}
|
||||
|
||||
public static class RNGTypeUtil
|
||||
{
|
||||
public static RNG GetRNG(this RNGType type)
|
||||
{
|
||||
return type switch
|
||||
{
|
||||
RNGType.LCRNG => RNG.LCRNG,
|
||||
RNGType.XDRNG => RNG.XDRNG,
|
||||
RNGType.ARNG => RNG.ARNG,
|
||||
_ => throw new ArgumentException(nameof(type))
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,25 +1,18 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace PKHeX.Core
|
||||
{
|
||||
public abstract class EggMoves
|
||||
{
|
||||
protected int Count;
|
||||
public int[] Moves;
|
||||
public int FormTableIndex;
|
||||
|
||||
public readonly int[] Moves;
|
||||
protected EggMoves(int[] moves) => Moves = moves;
|
||||
public bool GetHasEggMove(int move) => Moves.Contains(move);
|
||||
}
|
||||
|
||||
public sealed class EggMoves2 : EggMoves
|
||||
{
|
||||
private EggMoves2(byte[] data)
|
||||
{
|
||||
Count = data.Length;
|
||||
Moves = data.Select(i => (int) i).ToArray();
|
||||
}
|
||||
private EggMoves2(byte[] data) : base(data.Select(i => (int)i).ToArray()) { }
|
||||
|
||||
public static EggMoves[] GetArray(byte[] data, int count)
|
||||
{
|
||||
|
@ -42,46 +35,56 @@ namespace PKHeX.Core
|
|||
|
||||
public sealed class EggMoves6 : EggMoves
|
||||
{
|
||||
private EggMoves6(byte[] data)
|
||||
private static readonly EggMoves6 None = new EggMoves6(Array.Empty<int>());
|
||||
|
||||
private EggMoves6(int[] moves) : base(moves) { }
|
||||
|
||||
private static EggMoves6 Get(byte[] data)
|
||||
{
|
||||
if (data.Length < 2 || data.Length % 2 != 0)
|
||||
{ Count = 0; Moves = Array.Empty<int>(); return; }
|
||||
return None;
|
||||
|
||||
using BinaryReader br = new BinaryReader(new MemoryStream(data));
|
||||
Moves = new int[Count = br.ReadUInt16()];
|
||||
for (int i = 0; i < Count; i++)
|
||||
Moves[i] = br.ReadUInt16();
|
||||
int count = BitConverter.ToInt16(data, 0);
|
||||
var moves = new int[count];
|
||||
for (int i = 0; i < moves.Length; i++)
|
||||
moves[i] = BitConverter.ToInt16(data, 2 + (i * 2));
|
||||
return new EggMoves6(moves);
|
||||
}
|
||||
|
||||
public static EggMoves[] GetArray(byte[][] entries)
|
||||
public static EggMoves6[] GetArray(byte[][] entries)
|
||||
{
|
||||
EggMoves[] data = new EggMoves[entries.Length];
|
||||
EggMoves6[] data = new EggMoves6[entries.Length];
|
||||
for (int i = 0; i < data.Length; i++)
|
||||
data[i] = new EggMoves6(entries[i]);
|
||||
data[i] = Get(entries[i]);
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class EggMoves7 : EggMoves
|
||||
{
|
||||
private EggMoves7(byte[] data)
|
||||
private static readonly EggMoves7 None = new EggMoves7(Array.Empty<int>());
|
||||
public readonly int FormTableIndex;
|
||||
|
||||
private EggMoves7(int[] moves, int formIndex = 0) : base(moves) => FormTableIndex = formIndex;
|
||||
|
||||
private static EggMoves7 Get(byte[] data)
|
||||
{
|
||||
if (data.Length < 2 || data.Length % 2 != 0)
|
||||
{ Count = 0; Moves = Array.Empty<int>(); return; }
|
||||
return None;
|
||||
|
||||
using var br = new BinaryReader(new MemoryStream(data));
|
||||
FormTableIndex = br.ReadUInt16();
|
||||
Count = br.ReadUInt16();
|
||||
Moves = new int[Count];
|
||||
for (int i = 0; i < Count; i++)
|
||||
Moves[i] = br.ReadUInt16();
|
||||
int formIndex = BitConverter.ToInt16(data, 0);
|
||||
int count = BitConverter.ToInt16(data, 2);
|
||||
var moves = new int[count];
|
||||
for (int i = 0; i < moves.Length; i++)
|
||||
moves[i] = BitConverter.ToInt16(data, 4 + (i * 2));
|
||||
return new EggMoves7(moves, formIndex);
|
||||
}
|
||||
|
||||
public static EggMoves[] GetArray(byte[][] entries)
|
||||
public static EggMoves7[] GetArray(byte[][] entries)
|
||||
{
|
||||
EggMoves[] data = new EggMoves[entries.Length];
|
||||
EggMoves7[] data = new EggMoves7[entries.Length];
|
||||
for (int i = 0; i < data.Length; i++)
|
||||
data[i] = new EggMoves7(entries[i]);
|
||||
data[i] = Get(entries[i]);
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,14 +10,12 @@
|
|||
{
|
||||
public static int GetLocation(this ILocation encounter)
|
||||
{
|
||||
if (encounter == null)
|
||||
return -1;
|
||||
return encounter.Location != 0
|
||||
? encounter.Location
|
||||
: encounter.EggLocation;
|
||||
}
|
||||
|
||||
internal static string GetEncounterLocation(this ILocation Encounter, int gen, int version = -1)
|
||||
internal static string? GetEncounterLocation(this ILocation Encounter, int gen, int version = -1)
|
||||
{
|
||||
int loc = Encounter.GetLocation();
|
||||
if (loc < 0)
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using static PKHeX.Core.LegalityCheckStrings;
|
||||
using System;
|
||||
using static PKHeX.Core.LegalityCheckStrings;
|
||||
|
||||
namespace PKHeX.Core
|
||||
{
|
||||
|
|
|
@ -109,7 +109,7 @@ namespace PKHeX.Core
|
|||
case (int)Species.Spewpa:
|
||||
if (pkm.AltForm > 17) // Fancy & Pokéball
|
||||
return GetInvalid(LFormVivillonEventPre);
|
||||
if (!Legal.CheckVivillonPattern(pkm.AltForm, pkm.Country, pkm.Region))
|
||||
if (!Legal.CheckVivillonPattern(pkm.AltForm, (byte)pkm.Country, (byte)pkm.Region))
|
||||
data.AddLine(Get(LFormVivillonInvalid, Severity.Fishy));
|
||||
break;
|
||||
case (int)Species.Vivillon:
|
||||
|
@ -119,7 +119,7 @@ namespace PKHeX.Core
|
|||
return GetInvalid(LFormVivillonInvalid);
|
||||
return GetValid(LFormVivillon);
|
||||
}
|
||||
if (!Legal.CheckVivillonPattern(pkm.AltForm, pkm.Country, pkm.Region))
|
||||
if (!Legal.CheckVivillonPattern(pkm.AltForm, (byte)pkm.Country, (byte)pkm.Region))
|
||||
data.AddLine(Get(LFormVivillonInvalid, Severity.Fishy));
|
||||
break;
|
||||
|
||||
|
|
|
@ -47,8 +47,8 @@ namespace PKHeX.Core
|
|||
|
||||
private void VerifyIVsMystery(LegalityAnalysis data, MysteryGift g)
|
||||
{
|
||||
int[] IVs = g.IVs;
|
||||
if (IVs == null)
|
||||
var IVs = g.IVs;
|
||||
if (IVs.Length == 0)
|
||||
return;
|
||||
|
||||
var ivflag = Array.Find(IVs, iv => (byte)(iv - 0xFC) < 3);
|
||||
|
|
|
@ -13,6 +13,8 @@ namespace PKHeX.Core
|
|||
{
|
||||
protected override CheckIdentifier Identifier => CheckIdentifier.Memory;
|
||||
|
||||
private static readonly CheckResult NONE = new CheckResult(CheckIdentifier.Memory);
|
||||
|
||||
public override void Verify(LegalityAnalysis data)
|
||||
{
|
||||
if (data.pkm.Format < 6)
|
||||
|
@ -161,7 +163,7 @@ namespace PKHeX.Core
|
|||
|
||||
private bool VerifyHistoryUntradedHandler(PKM pkm, out CheckResult result)
|
||||
{
|
||||
result = null;
|
||||
result = NONE;
|
||||
if (pkm.CurrentHandler != 0) // Badly edited; PKHeX doesn't trip this.
|
||||
result = GetInvalid(LMemoryHTFlagInvalid);
|
||||
else if (pkm.HT_Friendship != 0)
|
||||
|
@ -176,7 +178,7 @@ namespace PKHeX.Core
|
|||
|
||||
private bool VerifyHistoryUntradedEvolution(PKM pkm, IReadOnlyList<EvoCriteria>[] chain, out CheckResult result)
|
||||
{
|
||||
result = null;
|
||||
result = NONE;
|
||||
// Handling Trainer string is empty implying it has not been traded.
|
||||
// If it must be trade evolved, flag it.
|
||||
|
||||
|
|
|
@ -185,8 +185,8 @@ namespace PKHeX.Core
|
|||
data.AddLine(GetInvalid(LEggPP, Egg));
|
||||
|
||||
var EncounterMatch = data.EncounterOriginal;
|
||||
var HatchCycles = (EncounterMatch as EncounterStatic)?.EggCycles;
|
||||
if (HatchCycles == 0 || HatchCycles == null)
|
||||
var HatchCycles = EncounterMatch is EncounterStatic s ? s.EggCycles : 0;
|
||||
if (HatchCycles == 0) // no value set
|
||||
HatchCycles = pkm.PersonalInfo.HatchCycles;
|
||||
if (pkm.CurrentFriendship > HatchCycles)
|
||||
data.AddLine(GetInvalid(LEggHatchCycles, Egg));
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using static PKHeX.Core.LegalityCheckStrings;
|
||||
using static PKHeX.Core.LanguageID;
|
||||
|
||||
namespace PKHeX.Core
|
||||
{
|
||||
|
@ -57,9 +58,9 @@ namespace PKHeX.Core
|
|||
if (ParseSettings.CheckWordFilter && pkm.IsNicknamed)
|
||||
{
|
||||
if (WordFilter.IsFiltered(nickname, out string bad))
|
||||
data.AddLine(GetInvalid($"Wordfilter: {bad}"));
|
||||
data.AddLine(GetInvalid($"Word Filter: {bad}"));
|
||||
if (TrainerNameVerifier.ContainsTooManyNumbers(nickname, data.Info.Generation))
|
||||
data.AddLine(GetInvalid("Wordfilter: Too many numbers."));
|
||||
data.AddLine(GetInvalid("Word Filter: Too many numbers."));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -82,7 +83,7 @@ namespace PKHeX.Core
|
|||
}
|
||||
if (nickname.Length > Legal.GetMaxLengthNickname(data.Info.Generation, (LanguageID)pkm.Language))
|
||||
{
|
||||
var severe = data.EncounterOriginal.EggEncounter && pkm.WasTradedEgg && nickname.Length <= Legal.GetMaxLengthNickname(data.Info.Generation, LanguageID.English)
|
||||
var severe = data.EncounterOriginal.EggEncounter && pkm.WasTradedEgg && nickname.Length <= Legal.GetMaxLengthNickname(data.Info.Generation, English)
|
||||
? Severity.Fishy
|
||||
: Severity.Invalid;
|
||||
data.AddLine(Get(LNickLengthLong, severe));
|
||||
|
@ -105,7 +106,7 @@ namespace PKHeX.Core
|
|||
return false;
|
||||
}
|
||||
|
||||
private bool IsNicknameValid(PKM pkm, IEncounterable EncounterMatch, string nickname)
|
||||
private static bool IsNicknameValid(PKM pkm, IEncounterable EncounterMatch, string nickname)
|
||||
{
|
||||
if (SpeciesName.GetSpeciesNameGeneration(pkm.Species, pkm.Language, pkm.Format) == nickname)
|
||||
return true;
|
||||
|
@ -205,7 +206,7 @@ namespace PKHeX.Core
|
|||
}
|
||||
}
|
||||
|
||||
private void VerifyTrade12(LegalityAnalysis data, EncounterTrade t)
|
||||
private static void VerifyTrade12(LegalityAnalysis data, EncounterTrade t)
|
||||
{
|
||||
if (t.TID != 0) // Gen2 Trade
|
||||
return; // already checked all relevant properties when fetching with getValidEncounterTradeVC2
|
||||
|
@ -214,7 +215,7 @@ namespace PKHeX.Core
|
|||
data.AddLine(GetInvalid(LEncTradeChangedOT, CheckIdentifier.Trainer));
|
||||
}
|
||||
|
||||
private void VerifyTrade3(LegalityAnalysis data, EncounterTrade t)
|
||||
private static void VerifyTrade3(LegalityAnalysis data, EncounterTrade t)
|
||||
{
|
||||
var pkm = data.pkm;
|
||||
int lang = pkm.Language;
|
||||
|
@ -223,7 +224,7 @@ namespace PKHeX.Core
|
|||
VerifyTrade(data, t, lang);
|
||||
}
|
||||
|
||||
private void VerifyTrade4(LegalityAnalysis data, EncounterTrade t)
|
||||
private static void VerifyTrade4(LegalityAnalysis data, EncounterTrade t)
|
||||
{
|
||||
var pkm = data.pkm;
|
||||
if (pkm.TID == 1000)
|
||||
|
@ -249,7 +250,7 @@ namespace PKHeX.Core
|
|||
if (lang == 1 && (pkm.Version == (int)GameVersion.D || pkm.Version == (int)GameVersion.P))
|
||||
{
|
||||
// DP English origin are Japanese lang
|
||||
if (pkm.OT_Name != t.TrainerNames[1]) // not japanese
|
||||
if (pkm.OT_Name != t.GetOT(1)) // not japanese
|
||||
lang = 2; // English
|
||||
}
|
||||
break;
|
||||
|
@ -259,9 +260,9 @@ namespace PKHeX.Core
|
|||
|
||||
private static void FlagKoreanIncompatibleSameGenTrade(LegalityAnalysis data, PKM pkm, int lang)
|
||||
{
|
||||
if (pkm.Format != 4 || lang != (int)LanguageID.Korean)
|
||||
if (pkm.Format != 4 || lang != (int)Korean)
|
||||
return; // transferred or not appropriate
|
||||
if (ParseSettings.ActiveTrainer.Language != (int)LanguageID.Korean && ParseSettings.ActiveTrainer.Language >= 0)
|
||||
if (ParseSettings.ActiveTrainer.Language != (int)Korean && ParseSettings.ActiveTrainer.Language >= 0)
|
||||
data.AddLine(GetInvalid(string.Format(LTransferOriginFInvalid0_1, L_XKorean, L_XKoreanNon), CheckIdentifier.Language));
|
||||
}
|
||||
|
||||
|
@ -279,49 +280,49 @@ namespace PKHeX.Core
|
|||
|
||||
private static int DetectTradeLanguageG3DANTAEJynx(PKM pk, int currentLanguageID)
|
||||
{
|
||||
if (currentLanguageID != (int)LanguageID.Italian)
|
||||
if (currentLanguageID != (int)Italian)
|
||||
return currentLanguageID;
|
||||
|
||||
if (pk.Version == (int)GameVersion.LG)
|
||||
currentLanguageID = (int)LanguageID.English; // translation error; OT was not localized => same as English
|
||||
currentLanguageID = (int)English; // translation error; OT was not localized => same as English
|
||||
return currentLanguageID;
|
||||
}
|
||||
|
||||
private static int DetectTradeLanguageG4MeisterMagikarp(PKM pkm, EncounterTrade t, int currentLanguageID)
|
||||
{
|
||||
if (currentLanguageID == (int)LanguageID.English)
|
||||
return (int)LanguageID.German;
|
||||
if (currentLanguageID == (int)English)
|
||||
return (int)German;
|
||||
|
||||
// All have German, regardless of origin version.
|
||||
var lang = DetectTradeLanguage(pkm.OT_Name, t, currentLanguageID);
|
||||
if (lang == (int)LanguageID.English) // possible collision with FR/ES/DE. Check nickname
|
||||
return pkm.Nickname == t.Nicknames[(int)LanguageID.French] ? (int)LanguageID.French : (int)LanguageID.Spanish; // Spanish is same as English
|
||||
if (lang == (int)English) // possible collision with FR/ES/DE. Check nickname
|
||||
return pkm.Nickname == t.Nicknames[(int)French] ? (int)French : (int)Spanish; // Spanish is same as English
|
||||
|
||||
return lang;
|
||||
}
|
||||
|
||||
private static int DetectTradeLanguageG4SurgePikachu(PKM pkm, EncounterTrade t, int currentLanguageID)
|
||||
{
|
||||
if (currentLanguageID == (int)LanguageID.French)
|
||||
return (int)LanguageID.English;
|
||||
if (currentLanguageID == (int)French)
|
||||
return (int)English;
|
||||
|
||||
// All have English, regardless of origin version.
|
||||
var lang = DetectTradeLanguage(pkm.OT_Name, t, currentLanguageID);
|
||||
if (lang == 2) // possible collision with ES/IT. Check nickname
|
||||
return pkm.Nickname == t.Nicknames[(int)LanguageID.Italian] ? (int)LanguageID.Italian : (int)LanguageID.Spanish;
|
||||
return pkm.Nickname == t.Nicknames[(int)Italian] ? (int)Italian : (int)Spanish;
|
||||
|
||||
return lang;
|
||||
}
|
||||
|
||||
private void VerifyTrade5(LegalityAnalysis data, EncounterTrade t)
|
||||
private static void VerifyTrade5(LegalityAnalysis data, EncounterTrade t)
|
||||
{
|
||||
var pkm = data.pkm;
|
||||
int lang = pkm.Language;
|
||||
// Trades for JPN games have language ID of 0, not 1.
|
||||
if (pkm.BW)
|
||||
{
|
||||
if (pkm.Format == 5 && lang == (int)LanguageID.Japanese)
|
||||
data.AddLine(GetInvalid(string.Format(LOTLanguage, 0, LanguageID.Japanese), CheckIdentifier.Language));
|
||||
if (pkm.Format == 5 && lang == (int)Japanese)
|
||||
data.AddLine(GetInvalid(string.Format(LOTLanguage, 0, Japanese), CheckIdentifier.Language));
|
||||
|
||||
lang = Math.Max(lang, 1);
|
||||
VerifyTrade(data, t, lang);
|
||||
|
|
|
@ -58,8 +58,8 @@
|
|||
ActiveTrainer = sav;
|
||||
if (sav.Generation >= 3)
|
||||
return AllowGBCartEra = false;
|
||||
string path = sav.FileName;
|
||||
bool vc = path.EndsWith("dat");
|
||||
var path = sav.FileName;
|
||||
bool vc = path?.EndsWith("dat") ?? false;
|
||||
return AllowGBCartEra = !vc; // physical cart selected
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
public RibbonResult(string prop, bool invalid = true)
|
||||
{
|
||||
Name = RibbonStrings.GetName(prop) ?? prop;
|
||||
Name = RibbonStrings.GetName(prop);
|
||||
Invalid = invalid;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace PKHeX.Core
|
||||
{
|
||||
|
@ -20,10 +21,7 @@ namespace PKHeX.Core
|
|||
string[] split = line.Split('\t');
|
||||
if (split.Length != 2)
|
||||
continue;
|
||||
if (RibbonNames.ContainsKey(split[0]))
|
||||
RibbonNames[split[0]] = split[1];
|
||||
else
|
||||
RibbonNames.Add(split[0], split[1]);
|
||||
RibbonNames[split[0]] = split[1];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -34,9 +32,9 @@ namespace PKHeX.Core
|
|||
/// <returns>Ribbon display name</returns>
|
||||
public static string GetName(string propertyName)
|
||||
{
|
||||
if (RibbonNames.TryGetValue(propertyName, out string value))
|
||||
return value;
|
||||
return null;
|
||||
if (!RibbonNames.TryGetValue(propertyName, out string value))
|
||||
throw new ArgumentException(propertyName);
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -63,8 +63,10 @@ namespace PKHeX.Core
|
|||
if (encounterContent is IRibbonSetEvent4 event4)
|
||||
RibbonNames = RibbonNames.Except(event4.RibbonNames());
|
||||
|
||||
foreach (object RibbonValue in RibbonNames.Select(RibbonName => ReflectUtil.GetValue(pkm, RibbonName)))
|
||||
foreach (var RibbonValue in RibbonNames.Select(RibbonName => ReflectUtil.GetValue(pkm, RibbonName)))
|
||||
{
|
||||
if (RibbonValue is null)
|
||||
continue;
|
||||
if (HasFlag(RibbonValue) || HasCount(RibbonValue))
|
||||
return true;
|
||||
|
||||
|
@ -334,7 +336,7 @@ namespace PKHeX.Core
|
|||
yield break;
|
||||
var names = set1.RibbonNames();
|
||||
var sb = set1.RibbonBits();
|
||||
var eb = (encounterContent as IRibbonSetEvent3).RibbonBits();
|
||||
var eb = encounterContent is IRibbonSetEvent3 e3 ? e3.RibbonBits() : new bool[sb.Length];
|
||||
|
||||
if (pkm.Gen3)
|
||||
{
|
||||
|
@ -360,7 +362,7 @@ namespace PKHeX.Core
|
|||
yield break;
|
||||
var names = set2.RibbonNames();
|
||||
var sb = set2.RibbonBits();
|
||||
var eb = (encounterContent as IRibbonSetEvent4).RibbonBits();
|
||||
var eb = encounterContent is IRibbonSetEvent4 e4 ? e4.RibbonBits() : new bool[sb.Length];
|
||||
|
||||
if (encounterContent is EncounterStatic s && s.RibbonWishing)
|
||||
eb[1] = true; // require Wishing Ribbon
|
||||
|
|
|
@ -8,243 +8,140 @@ namespace PKHeX.Core
|
|||
{
|
||||
private class CountryTable
|
||||
{
|
||||
public byte CountryID;
|
||||
public byte BaseForm;
|
||||
public FormSubregionTable[] SubRegionForms;
|
||||
public readonly byte BaseForm;
|
||||
public readonly byte CountryID;
|
||||
public readonly FormSubregionTable[] SubRegionForms;
|
||||
|
||||
internal CountryTable(byte form, byte country, params FormSubregionTable[] subs)
|
||||
{
|
||||
BaseForm = form;
|
||||
CountryID = country;
|
||||
SubRegionForms = subs;
|
||||
}
|
||||
}
|
||||
|
||||
private class FormSubregionTable
|
||||
{
|
||||
public byte Form;
|
||||
public int[] Regions;
|
||||
public readonly byte Form;
|
||||
public readonly byte[] Regions;
|
||||
|
||||
internal FormSubregionTable(byte form, byte[] regions)
|
||||
{
|
||||
Form = form;
|
||||
Regions = regions;
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly int[][] VivillonCountryTable =
|
||||
private static readonly byte[][] VivillonCountryTable =
|
||||
{
|
||||
//missing ID 051,068,102,127,160,186
|
||||
/* 0 Icy Snow */ new[] { 018, 076, 096, 100, 107 },
|
||||
/* 1 Polar */ new[] { 010, 018, 020, 049, 076, 096, 100, 107 },
|
||||
/* 2 Tundra */ new[] { 001, 081, 096, },
|
||||
/* 3 Continental */ new[] { 010, 067, 073, 074, 075, 077, 078, 084, 087, 094, 096, 097, 100, 107, 136},
|
||||
/* 4 Garden */ new[] { 065, 082, 095, 097, 101, 110, 125},
|
||||
/* 5 Elegant */ new[] { 001 },
|
||||
/* 6 Meadow */ new[] { 066, 077, 078, 083, 086, 088, 105, 108, 122},
|
||||
/* 7 Modern */ new[] { 018, 049},
|
||||
/* 8 Marine */ new[] { 020, 064, 066, 070, 071, 073, 077, 078, 079, 080, 083, 089, 090, 091, 098, 099, 103, 105, 123, 124, 126, 184, 185},
|
||||
/* 9 Archipelago */ new[] { 008, 009, 011, 012, 013, 017, 021, 023, 024, 028, 029, 032, 034, 035, 036, 037, 038, 043, 044, 045, 047, 048, 049, 052, 085, 104,},
|
||||
/*10 High Plains */ new[] { 018, 036, 049, 100, 113},
|
||||
/*11 Sandstorm */ new[] { 072, 109, 118, 119, 120, 121, 168, 174},
|
||||
/*12 River */ new[] { 065, 069, 085, 093, 104, 105, 114, 115, 116, 117},
|
||||
/*13 Monsoon */ new[] { 001, 128, 144, 169},
|
||||
/*14-Savanna */ new[] { 010, 015, 016, 041, 042, 050},
|
||||
/*15 Sun */ new[] { 036, 014, 019, 026, 030, 033, 036, 039, 065, 092, 106, 111, 112},
|
||||
/*16 Ocean */ new[] { 049, 077},
|
||||
/*17 Jungle */ new[] { 016, 021, 022, 025, 027, 031, 040, 046, 052, 169, 153, 156},
|
||||
/* 0 Icy Snow */ new byte[] { 018, 076, 096, 100, 107 },
|
||||
/* 1 Polar */ new byte[] { 010, 018, 020, 049, 076, 096, 100, 107 },
|
||||
/* 2 Tundra */ new byte[] { 001, 081, 096, },
|
||||
/* 3 Continental */ new byte[] { 010, 067, 073, 074, 075, 077, 078, 084, 087, 094, 096, 097, 100, 107, 136},
|
||||
/* 4 Garden */ new byte[] { 065, 082, 095, 097, 101, 110, 125},
|
||||
/* 5 Elegant */ new byte[] { 001 },
|
||||
/* 6 Meadow */ new byte[] { 066, 077, 078, 083, 086, 088, 105, 108, 122},
|
||||
/* 7 Modern */ new byte[] { 018, 049},
|
||||
/* 8 Marine */ new byte[] { 020, 064, 066, 070, 071, 073, 077, 078, 079, 080, 083, 089, 090, 091, 098, 099, 103, 105, 123, 124, 126, 184, 185},
|
||||
/* 9 Archipelago */ new byte[] { 008, 009, 011, 012, 013, 017, 021, 023, 024, 028, 029, 032, 034, 035, 036, 037, 038, 043, 044, 045, 047, 048, 049, 052, 085, 104,},
|
||||
/*10 High Plains */ new byte[] { 018, 036, 049, 100, 113},
|
||||
/*11 Sandstorm */ new byte[] { 072, 109, 118, 119, 120, 121, 168, 174},
|
||||
/*12 River */ new byte[] { 065, 069, 085, 093, 104, 105, 114, 115, 116, 117},
|
||||
/*13 Monsoon */ new byte[] { 001, 128, 144, 169},
|
||||
/*14-Savanna */ new byte[] { 010, 015, 016, 041, 042, 050},
|
||||
/*15 Sun */ new byte[] { 036, 014, 019, 026, 030, 033, 036, 039, 065, 092, 106, 111, 112},
|
||||
/*16 Ocean */ new byte[] { 049, 077},
|
||||
/*17 Jungle */ new byte[] { 016, 021, 022, 025, 027, 031, 040, 046, 052, 169, 153, 156},
|
||||
};
|
||||
|
||||
private static readonly CountryTable[] RegionFormTable =
|
||||
{
|
||||
new CountryTable{
|
||||
CountryID = 001, // Japan
|
||||
BaseForm = 05, // Elegant
|
||||
SubRegionForms = new[]
|
||||
{
|
||||
new FormSubregionTable { Form = 02, Regions = new[] {03,04} },
|
||||
new FormSubregionTable { Form = 13, Regions = new[] {48} },
|
||||
}
|
||||
},
|
||||
new CountryTable{
|
||||
CountryID = 049, // USA
|
||||
BaseForm = 07, // Modern
|
||||
SubRegionForms = new[]
|
||||
{
|
||||
new FormSubregionTable { Form = 01, Regions = new[] {03,09,21,23,24,32,33,36,40,41,48,50} },
|
||||
new FormSubregionTable { Form = 09, Regions = new[] {53} },
|
||||
new FormSubregionTable { Form = 10, Regions = new[] {06,07,08,15,28,34,35,39,46,49} },
|
||||
}
|
||||
},
|
||||
new CountryTable{
|
||||
CountryID = 018, // Canada
|
||||
BaseForm = 01, // Polar
|
||||
SubRegionForms = new[]
|
||||
{
|
||||
new FormSubregionTable { Form = 00, Regions = new[] {12,13,14} },
|
||||
new FormSubregionTable { Form = 07, Regions = new[] {05} },
|
||||
new FormSubregionTable { Form = 10, Regions = new[] {04} },
|
||||
}
|
||||
},
|
||||
new CountryTable{
|
||||
CountryID = 016, // Brazil
|
||||
BaseForm = 14, // Savanna
|
||||
SubRegionForms = new[]
|
||||
{
|
||||
new FormSubregionTable { Form = 17, Regions = new[] {03,06} },
|
||||
}
|
||||
},
|
||||
new CountryTable{
|
||||
CountryID = 010, // Argentina
|
||||
BaseForm = 14, // Savanna
|
||||
SubRegionForms = new[]
|
||||
{
|
||||
new FormSubregionTable { Form = 01, Regions = new[] {21,24} },
|
||||
new FormSubregionTable { Form = 03, Regions = new[] {16} },
|
||||
}
|
||||
},
|
||||
new CountryTable{
|
||||
CountryID = 020, // Chile
|
||||
BaseForm = 08, // Marine
|
||||
SubRegionForms = new[]
|
||||
{
|
||||
new FormSubregionTable { Form = 01, Regions = new[] {12} },
|
||||
}
|
||||
},
|
||||
new CountryTable{
|
||||
CountryID = 036, // Mexico
|
||||
BaseForm = 15, // Sun
|
||||
SubRegionForms = new[]
|
||||
{
|
||||
new FormSubregionTable { Form = 09, Regions = new[] {32} },
|
||||
new FormSubregionTable { Form = 10, Regions = new[] {04,08,09,12,15,19,20,23,26,27,29} },
|
||||
}
|
||||
},
|
||||
new CountryTable{
|
||||
CountryID = 052, // Venezuela
|
||||
BaseForm = 09, // Archipelago
|
||||
SubRegionForms = new[]
|
||||
{
|
||||
new FormSubregionTable { Form = 17, Regions = new[] {17} },
|
||||
}
|
||||
},
|
||||
new CountryTable{
|
||||
CountryID = 065, // Australia
|
||||
BaseForm = 09, // River
|
||||
SubRegionForms = new[]
|
||||
{
|
||||
new FormSubregionTable { Form = 04, Regions = new[] {07} },
|
||||
new FormSubregionTable { Form = 15, Regions = new[] {04} },
|
||||
}
|
||||
},
|
||||
new CountryTable{
|
||||
CountryID = 066, // Austria
|
||||
BaseForm = 08, // Marine
|
||||
SubRegionForms = new[]
|
||||
{
|
||||
new FormSubregionTable { Form = 06, Regions = new[] {10} },
|
||||
}
|
||||
},
|
||||
new CountryTable{
|
||||
CountryID = 073, // Czecg Republic
|
||||
BaseForm = 08, // Marine
|
||||
SubRegionForms = new[]
|
||||
{
|
||||
new FormSubregionTable { Form = 03, Regions = new[] {03} },
|
||||
}
|
||||
},
|
||||
new CountryTable{
|
||||
CountryID = 076, // Finland
|
||||
BaseForm = 00, // Icy Snow
|
||||
SubRegionForms = new[]
|
||||
{
|
||||
new FormSubregionTable { Form = 01, Regions = new[] {27} },
|
||||
}
|
||||
},
|
||||
new CountryTable{
|
||||
CountryID = 077, // France
|
||||
BaseForm = 06, // Meadow
|
||||
SubRegionForms = new[]
|
||||
{
|
||||
new FormSubregionTable { Form = 03, Regions = new[] {18} },
|
||||
new FormSubregionTable { Form = 08, Regions = new[] {04,06,08,19} },
|
||||
new FormSubregionTable { Form = 16, Regions = new[] {27} },
|
||||
}
|
||||
},
|
||||
new CountryTable{
|
||||
CountryID = 078, // Germany
|
||||
BaseForm = 03, // Continental
|
||||
SubRegionForms = new[]
|
||||
{
|
||||
new FormSubregionTable { Form = 06, Regions = new[] {04,13} },
|
||||
new FormSubregionTable { Form = 08, Regions = new[] {05} },
|
||||
}
|
||||
},
|
||||
new CountryTable{
|
||||
CountryID = 078, // Italy
|
||||
BaseForm = 08, // Marine
|
||||
SubRegionForms = new[]
|
||||
{
|
||||
new FormSubregionTable { Form = 06, Regions = new[] {04,06} },
|
||||
}
|
||||
},
|
||||
new CountryTable{
|
||||
CountryID = 085, // Lesotho
|
||||
BaseForm = 09, // Archipelago ??
|
||||
SubRegionForms = new[]
|
||||
{
|
||||
new FormSubregionTable { Form = 12, Regions = new[] {04} },
|
||||
}
|
||||
},
|
||||
new CountryTable{
|
||||
CountryID = 096, // Norway
|
||||
BaseForm = 03, // Continental ??
|
||||
SubRegionForms = new[]
|
||||
{
|
||||
new FormSubregionTable { Form = 00, Regions = new[] {11} },
|
||||
new FormSubregionTable { Form = 01, Regions = new[] {12,15,16,17,20,22} },
|
||||
new FormSubregionTable { Form = 02, Regions = new[] {13,14} },
|
||||
}
|
||||
},
|
||||
new CountryTable{
|
||||
CountryID = 097, // Poland
|
||||
BaseForm = 03, // Continental
|
||||
SubRegionForms = new[]
|
||||
{
|
||||
new FormSubregionTable { Form = 04, Regions = new[] {11} },
|
||||
}
|
||||
},
|
||||
new CountryTable{
|
||||
CountryID = 100, // Russia
|
||||
BaseForm = 01, // Polar
|
||||
SubRegionForms = new[]
|
||||
{
|
||||
new FormSubregionTable { Form = 00, Regions = new[] {14,22,34,38,40,52,66,88} },
|
||||
new FormSubregionTable { Form = 03, Regions = new[] {29,46,51,69} },
|
||||
new FormSubregionTable { Form = 10, Regions = new[] {20,24,25,28,33,71,73} },
|
||||
}
|
||||
},
|
||||
new CountryTable{
|
||||
CountryID = 104, //South Africa
|
||||
BaseForm = 12, // River ??
|
||||
SubRegionForms = new[]
|
||||
{
|
||||
new FormSubregionTable { Form = 03, Regions = new[] {03,05} },
|
||||
}
|
||||
},
|
||||
new CountryTable{
|
||||
CountryID = 105, // Spain
|
||||
BaseForm = 08, // Marine
|
||||
SubRegionForms = new[]
|
||||
{
|
||||
new FormSubregionTable { Form = 06, Regions = new[] {11} },
|
||||
new FormSubregionTable { Form = 12, Regions = new[] {07} },
|
||||
}
|
||||
},
|
||||
new CountryTable{
|
||||
CountryID = 107, // Sweden
|
||||
BaseForm = 03, // Continental
|
||||
SubRegionForms = new[]
|
||||
{
|
||||
new FormSubregionTable { Form = 00, Regions = new[] {11,21} },
|
||||
new FormSubregionTable { Form = 01, Regions = new[] {09,13} },
|
||||
}
|
||||
},
|
||||
new CountryTable{
|
||||
CountryID = 169, // India
|
||||
BaseForm = 13, // Monsoon ??
|
||||
SubRegionForms = new[]
|
||||
{
|
||||
new FormSubregionTable { Form = 17, Regions = new[] {12} },
|
||||
}
|
||||
},
|
||||
new CountryTable(05, 1, // Japan: Elegant
|
||||
new FormSubregionTable(02, new byte[] {03,04}),
|
||||
new FormSubregionTable(13, new byte[] {48})),
|
||||
|
||||
new CountryTable(07, 49, // USA: Modern
|
||||
new FormSubregionTable(01, new byte[] {03,09,21,23,24,32,33,36,40,41,48,50}),
|
||||
new FormSubregionTable(09, new byte[] {53}),
|
||||
new FormSubregionTable(10, new byte[] {06,07,08,15,28,34,35,39,46,49})),
|
||||
|
||||
new CountryTable(01, 18, // Canada: Polar
|
||||
new FormSubregionTable(00, new byte[] {12,13,14}),
|
||||
new FormSubregionTable(07, new byte[] {05}),
|
||||
new FormSubregionTable(10, new byte[] {04})),
|
||||
|
||||
new CountryTable(14, 16, // Brazil: Savanna
|
||||
new FormSubregionTable(17, new byte[] {03,06})),
|
||||
|
||||
new CountryTable(14, 10, // Argentina: Savanna
|
||||
new FormSubregionTable(01, new byte[] {21,24}),
|
||||
new FormSubregionTable(03, new byte[] {16})),
|
||||
|
||||
new CountryTable(08, 20, // Chile: Marine
|
||||
new FormSubregionTable(01, new byte[] {12})),
|
||||
|
||||
new CountryTable(15, 36, // Mexico: Sun
|
||||
new FormSubregionTable(09, new byte[] {32}),
|
||||
new FormSubregionTable(10, new byte[] {04,08,09,12,15,19,20,23,26,27,29})),
|
||||
|
||||
new CountryTable(09, 52, // Venezuela: Archipelago
|
||||
new FormSubregionTable(17, new byte[] {17})),
|
||||
|
||||
new CountryTable(09, 65, // Australia: River
|
||||
new FormSubregionTable(04, new byte[] {07}),
|
||||
new FormSubregionTable(15, new byte[] {04})),
|
||||
|
||||
new CountryTable(08, 66, // Austria: Marine
|
||||
new FormSubregionTable(06, new byte[] {10})),
|
||||
|
||||
new CountryTable(08, 73, // Czech Republic: Marine
|
||||
new FormSubregionTable(03, new byte[] {03})),
|
||||
|
||||
new CountryTable(00, 76, // Finland: Icy Snow
|
||||
new FormSubregionTable(01, new byte[] {27})),
|
||||
|
||||
new CountryTable(06, 77, // France: Meadow
|
||||
new FormSubregionTable(03, new byte[] {18}),
|
||||
new FormSubregionTable(08, new byte[] {04,06,08,19}),
|
||||
new FormSubregionTable(16, new byte[] {27})),
|
||||
|
||||
new CountryTable(03, 078, // Germany: Continental
|
||||
new FormSubregionTable(06, new byte[] {04,13}),
|
||||
new FormSubregionTable(08, new byte[] {05})),
|
||||
|
||||
new CountryTable(08, 83, // Italy: Marine
|
||||
new FormSubregionTable(06, new byte[] {04,06})),
|
||||
|
||||
new CountryTable(09, 85, // Lesotho: Archipelago ??
|
||||
new FormSubregionTable(12, new byte[] {04})),
|
||||
|
||||
new CountryTable(03, 96, // Norway: Continental ??
|
||||
new FormSubregionTable(00, new byte[] {11}),
|
||||
new FormSubregionTable(01, new byte[] {12,15,16,17,20,22}),
|
||||
new FormSubregionTable(02, new byte[] {13,14})),
|
||||
|
||||
new CountryTable(03, 97, // Poland: Continental
|
||||
new FormSubregionTable(04, new byte[] {11})),
|
||||
|
||||
new CountryTable(01, 100, // Russia: Polar
|
||||
new FormSubregionTable(00, new byte[] {14,22,34,38,40,52,66,88}),
|
||||
new FormSubregionTable(03, new byte[] {29,46,51,69}),
|
||||
new FormSubregionTable(10, new byte[] {20,24,25,28,33,71,73})),
|
||||
|
||||
new CountryTable(12, 104, // South Affrica: River ??
|
||||
new FormSubregionTable(03, new byte[] {03,05})),
|
||||
|
||||
new CountryTable(08, 105, // Spain: Marine
|
||||
new FormSubregionTable(06, new byte[] {11}),
|
||||
new FormSubregionTable(12, new byte[] {07})),
|
||||
|
||||
new CountryTable(03, 107, // Sweden: Continental
|
||||
new FormSubregionTable(00, new byte[] {11,21}),
|
||||
new FormSubregionTable(01, new byte[] {09,13})),
|
||||
|
||||
new CountryTable(13, 169, // India: Monsoon ??
|
||||
new FormSubregionTable(17, new byte[] {12})),
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
|
@ -254,7 +151,7 @@ namespace PKHeX.Core
|
|||
/// <param name="country">Country ID</param>
|
||||
/// <param name="region">Console Region ID</param>
|
||||
/// <returns></returns>
|
||||
public static bool CheckVivillonPattern(int form, int country, int region)
|
||||
public static bool CheckVivillonPattern(int form, byte country, byte region)
|
||||
{
|
||||
if (!VivillonCountryTable[form].Contains(country))
|
||||
return false; // Country mismatch
|
||||
|
@ -274,7 +171,7 @@ namespace PKHeX.Core
|
|||
/// </summary>
|
||||
/// <param name="country">Country ID</param>
|
||||
/// <param name="region">Console Region ID</param>
|
||||
public static int GetVivillonPattern(int country, int region)
|
||||
public static int GetVivillonPattern(byte country, byte region)
|
||||
{
|
||||
var ct = Array.Find(RegionFormTable, t => t.CountryID == country);
|
||||
if (ct == default(CountryTable)) // empty = no forms referenced
|
||||
|
@ -289,7 +186,7 @@ namespace PKHeX.Core
|
|||
return ct.BaseForm;
|
||||
}
|
||||
|
||||
private static int GetVivillonPattern(int country)
|
||||
private static int GetVivillonPattern(byte country)
|
||||
{
|
||||
var form = Array.FindIndex(VivillonCountryTable, z => z.Contains(country));
|
||||
return Math.Max(0, form);
|
||||
|
|
|
@ -18,6 +18,8 @@ namespace PKHeX.Core
|
|||
/// </summary>
|
||||
private static readonly Dictionary<string, string> Lookup = new Dictionary<string, string>(INIT_COUNT);
|
||||
|
||||
private const string NoMatch = "";
|
||||
|
||||
/// <summary>
|
||||
/// Checks to see if a phrase contains filtered content.
|
||||
/// </summary>
|
||||
|
@ -28,7 +30,7 @@ namespace PKHeX.Core
|
|||
{
|
||||
if (string.IsNullOrWhiteSpace(message) || message.Length <= 1)
|
||||
{
|
||||
regMatch = null;
|
||||
regMatch = NoMatch;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -37,7 +39,7 @@ namespace PKHeX.Core
|
|||
lock (dictLock)
|
||||
{
|
||||
if (Lookup.TryGetValue(msg, out regMatch))
|
||||
return regMatch != null;
|
||||
return !ReferenceEquals(regMatch, NoMatch);
|
||||
}
|
||||
|
||||
// not in dictionary, check patterns
|
||||
|
@ -58,7 +60,7 @@ namespace PKHeX.Core
|
|||
{
|
||||
if ((Lookup.Count & ~MAX_COUNT) != 0)
|
||||
Lookup.Clear(); // reset
|
||||
Lookup.Add(msg, regMatch = null);
|
||||
Lookup.Add(msg, regMatch = NoMatch);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -1,9 +1,39 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace PKHeX.Core
|
||||
{
|
||||
public abstract class DataMysteryGift : MysteryGift
|
||||
{
|
||||
public readonly byte[] Data;
|
||||
|
||||
protected DataMysteryGift(byte[] data) => Data = data;
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
int hash = 17;
|
||||
foreach (var b in Data)
|
||||
hash = (hash * 31) + b;
|
||||
return hash;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Creates a deep copy of the <see cref="MysteryGift"/> object data.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public override MysteryGift Clone()
|
||||
{
|
||||
byte[] data = (byte[])Data.Clone();
|
||||
var result = GetMysteryGift(data);
|
||||
if (result == null)
|
||||
throw new ArgumentException(nameof(MysteryGift));
|
||||
return result;
|
||||
}
|
||||
|
||||
public override bool Empty => Data.IsRangeAll(0, 0, Data.Length);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Mystery Gift Template File
|
||||
/// </summary>
|
||||
|
@ -16,7 +46,7 @@ namespace PKHeX.Core
|
|||
/// <returns>A boolean indicating whether or not the given length is valid for a mystery gift.</returns>
|
||||
public static bool IsMysteryGift(long len) => MGSizes.Contains((int)len);
|
||||
|
||||
private static readonly HashSet<int> MGSizes = new HashSet<int>{WC6.SizeFull, WC6.Size, PGF.Size, PGT.Size, PCD.Size };
|
||||
private static readonly HashSet<int> MGSizes = new HashSet<int>{ WC6Full.Size, WC6.Size, PGF.Size, PGT.Size, PCD.Size };
|
||||
|
||||
/// <summary>
|
||||
/// Converts the given data to a <see cref="MysteryGift"/>.
|
||||
|
@ -25,7 +55,7 @@ namespace PKHeX.Core
|
|||
/// <param name="ext">Extension of the file from which the <paramref name="data"/> was retrieved.</param>
|
||||
/// <returns>An instance of <see cref="MysteryGift"/> representing the given data, or null if <paramref name="data"/> or <paramref name="ext"/> is invalid.</returns>
|
||||
/// <remarks>This overload differs from <see cref="GetMysteryGift(byte[])"/> by checking the <paramref name="data"/>/<paramref name="ext"/> combo for validity. If either is invalid, a null reference is returned.</remarks>
|
||||
public static MysteryGift GetMysteryGift(byte[] data, string ext)
|
||||
public static DataMysteryGift? GetMysteryGift(byte[] data, string ext)
|
||||
{
|
||||
if (ext == null)
|
||||
return GetMysteryGift(data);
|
||||
|
@ -35,10 +65,12 @@ namespace PKHeX.Core
|
|||
case WB7.SizeFull when ext == ".wb7full":
|
||||
case WB7.Size when ext == ".wb7":
|
||||
return new WB7(data);
|
||||
case WC7.SizeFull when ext == ".wc7full":
|
||||
case WC7Full.Size when ext == ".wc7full":
|
||||
return new WC7Full(data).Gift;
|
||||
case WC7.Size when ext == ".wc7":
|
||||
return new WC7(data);
|
||||
case WC6.SizeFull when ext == ".wc6full":
|
||||
case WC6Full.Size when ext == ".wc6full":
|
||||
return new WC6Full(data).Gift;
|
||||
case WC6.Size when ext == ".wc6":
|
||||
return new WC6(data);
|
||||
case WR7.Size when ext == ".wr7":
|
||||
|
@ -60,15 +92,15 @@ namespace PKHeX.Core
|
|||
/// </summary>
|
||||
/// <param name="data">Raw data of the mystery gift.</param>
|
||||
/// <returns>An instance of <see cref="MysteryGift"/> representing the given data, or null if <paramref name="data"/> is invalid.</returns>
|
||||
public static MysteryGift GetMysteryGift(byte[] data)
|
||||
public static DataMysteryGift? GetMysteryGift(byte[] data)
|
||||
{
|
||||
switch (data.Length)
|
||||
{
|
||||
case WC6.SizeFull:
|
||||
case WC6Full.Size:
|
||||
// Check WC7 size collision
|
||||
if (data[0x205] == 0) // 3 * 0x46 for gen6, now only 2.
|
||||
return new WC7(data);
|
||||
return new WC6(data);
|
||||
return new WC7Full(data).Gift;
|
||||
return new WC6Full(data).Gift;
|
||||
case WC6.Size:
|
||||
// Check year for WC7 size collision
|
||||
if (BitConverter.ToUInt32(data, 0x4C) / 10000 < 2000)
|
||||
|
@ -85,7 +117,6 @@ namespace PKHeX.Core
|
|||
|
||||
public string Extension => GetType().Name.ToLower();
|
||||
public string FileName => $"{CardHeader}.{Extension}";
|
||||
public byte[] Data { get; set; }
|
||||
public abstract int Format { get; }
|
||||
|
||||
public PKM ConvertToPKM(ITrainerInfo SAV) => ConvertToPKM(SAV, EncounterCriteria.Unrestricted);
|
||||
|
@ -107,11 +138,7 @@ namespace PKHeX.Core
|
|||
/// Creates a deep copy of the <see cref="MysteryGift"/> object data.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public MysteryGift Clone()
|
||||
{
|
||||
byte[] data = (byte[])Data.Clone();
|
||||
return GetMysteryGift(data);
|
||||
}
|
||||
public abstract MysteryGift Clone();
|
||||
|
||||
/// <summary>
|
||||
/// Gets a friendly name for the underlying <see cref="MysteryGift"/> type.
|
||||
|
@ -139,7 +166,7 @@ namespace PKHeX.Core
|
|||
|
||||
public abstract bool IsPokémon { get; set; }
|
||||
public virtual int Quantity { get => 1; set { } }
|
||||
public virtual bool Empty => Data.All(z => z == 0);
|
||||
public virtual bool Empty => false;
|
||||
|
||||
public virtual bool IsBP { get => false; set { } }
|
||||
public virtual int BP { get => 0; set { } }
|
||||
|
@ -148,19 +175,11 @@ namespace PKHeX.Core
|
|||
public virtual int BeanCount { get => 0; set { } }
|
||||
|
||||
public virtual string CardHeader => (CardID > 0 ? $"Card #: {CardID:0000}" : "N/A") + $" - {CardTitle.Replace('\u3000',' ').Trim()}";
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
int hash = 17;
|
||||
foreach (var b in Data)
|
||||
hash = (hash * 31) + b;
|
||||
return hash;
|
||||
}
|
||||
|
||||
|
||||
// Search Properties
|
||||
public virtual int[] Moves { get => Array.Empty<int>(); set { } }
|
||||
public virtual int[] RelearnMoves { get => Array.Empty<int>(); set { } }
|
||||
public virtual int[] IVs { get => null; set { } }
|
||||
public virtual int[] IVs { get => Array.Empty<int>(); set { } }
|
||||
public virtual bool IsShiny => false;
|
||||
public virtual bool IsEgg { get => false; set { } }
|
||||
public virtual int HeldItem { get => -1; set { } }
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue