PKHeX/PKHeX.Core/Legality/LegalityAnalysis.cs

489 lines
17 KiB
C#
Raw Normal View History

2017-11-09 06:59:18 +00:00
#define SUPPRESS
using System;
using System.Collections.Generic;
using System.Linq;
using static PKHeX.Core.LegalityAnalyzers;
using static PKHeX.Core.LegalityCheckStrings;
using static PKHeX.Core.ParseSettings;
namespace PKHeX.Core
{
/// <summary>
/// Legality Check object containing the <see cref="CheckResult"/> data and overview values from the parse.
/// </summary>
public sealed class LegalityAnalysis
{
internal readonly PKM pkm;
2018-07-21 03:22:46 +00:00
internal readonly PersonalInfo PersonalInfo;
private readonly List<CheckResult> Parse = new List<CheckResult>();
/// <summary>
/// Parse result list allowing view of the legality parse.
/// </summary>
public IReadOnlyList<CheckResult> Results => Parse;
2019-11-16 01:34:18 +00:00
/// <summary>
/// Only use this when trying to mutate the legality. Not for use when checking legality.
/// </summary>
public void ResetParse() => Parse.Clear();
2018-07-21 03:22:46 +00:00
/// <summary>
/// Matched encounter data for the <see cref="pkm"/>.
/// </summary>
public IEncounterable EncounterMatch => Info.EncounterMatch;
2018-07-21 03:22:46 +00:00
/// <summary>
/// Original encounter data for the <see cref="pkm"/>.
/// </summary>
/// <remarks>
/// Generation 1/2 <see cref="pkm"/> that are transferred forward to Generation 7 are restricted to new encounter details.
/// By retaining their original match, more information can be provided by the parse.
/// </remarks>
public IEncounterable EncounterOriginal => Info.EncounterOriginal;
2018-07-21 03:22:46 +00:00
/// <summary>
/// Indicates if all checks ran to completion.
/// </summary>
/// <remarks>This value is false if any checks encountered an error.</remarks>
public readonly bool Parsed;
2018-07-21 03:22:46 +00:00
/// <summary>
/// Indicates if all checks returned a <see cref="Severity.Valid"/> result.
/// </summary>
public readonly bool Valid;
2018-07-21 03:22:46 +00:00
/// <summary>
/// Contains various data reused for multiple checks.
/// </summary>
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
2019-10-17 01:47:31 +00:00
public readonly LegalInfo Info;
2018-07-21 03:22:46 +00:00
/// <summary>
/// Creates a report message with optional verbosity for in-depth analysis.
/// </summary>
/// <param name="verbose">Include all details in the parse, including valid check messages.</param>
/// <returns>Single line string</returns>
public string Report(bool verbose = false) => verbose ? GetVerboseLegalityReport() : GetLegalityReport();
2018-07-21 03:22:46 +00:00
private IEnumerable<int> AllSuggestedMoves
{
get
{
if (!Parsed)
return new int[4];
return _allSuggestedMoves ??= GetSuggestedCurrentMoves(true, true, true);
}
}
private IEnumerable<int> AllSuggestedRelearnMoves
{
get
{
if (!Parsed)
return new int[4];
return _allSuggestedRelearnMoves ??= MoveList.GetValidRelearn(pkm, Info.EncounterMatch.Species, Info.EncounterMatch.Form, (GameVersion)pkm.Version).ToArray();
}
}
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
2019-10-17 01:47:31 +00:00
private int[]? _allSuggestedMoves, _allSuggestedRelearnMoves;
public int[] AllSuggestedMovesAndRelearn() => AllSuggestedMoves.Concat(AllSuggestedRelearnMoves).ToArray();
private string EncounterName
{
get
{
var enc = EncounterOriginal;
var str = SpeciesStrings;
var name = (uint) enc.Species < str.Count ? str[enc.Species] : enc.Species.ToString();
return $"{enc.LongName} ({name})";
}
}
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
2019-10-17 01:47:31 +00:00
private string? EncounterLocation
{
get
{
var enc = EncounterOriginal as ILocation;
return enc?.GetEncounterLocation(Info.Generation, pkm.Version);
}
}
/// <summary>
/// Checks the input <see cref="PKM"/> data for legality. This is the best method for checking with context, as some games do not have all Alternate Form data available.
/// </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) : this(pk, table.GetFormeEntry(pk.Species, pk.AltForm)) { }
/// <summary>
/// Checks the input <see cref="PKM"/> data for legality.
/// </summary>
/// <param name="pk">Input data to check</param>
public LegalityAnalysis(PKM pk) : this(pk, pk.PersonalInfo) { }
/// <summary>
/// Checks the input <see cref="PKM"/> data for legality.
/// </summary>
/// <param name="pk">Input data to check</param>
/// <param name="pi">Personal info to parse with</param>
public LegalityAnalysis(PKM pk, PersonalInfo pi)
{
pkm = pk;
PersonalInfo = pi;
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
2019-10-17 01:47:31 +00:00
if (pkm.Format <= 2) // prior to storing GameVersion
pkm.TradebackStatus = GBRestrictions.GetTradebackStatusInitial(pkm);
#if SUPPRESS
try
#endif
{
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
2019-10-17 01:47:31 +00:00
Info = EncounterFinder.FindVerifiedEncounter(pkm);
if (!pkm.IsOriginValid)
AddLine(Severity.Invalid, LEncConditionBadSpecies, CheckIdentifier.GameOrigin);
GetParseMethod()();
if (Parse.Count == 0) // shouldn't ever happen as at least one is yielded above.
{
AddLine(Severity.Invalid, L_AError, CheckIdentifier.Misc);
return;
}
2018-05-12 15:13:39 +00:00
Valid = Parse.All(chk => chk.Valid)
&& Info.Moves.All(m => m.Valid)
&& Info.Relearn.All(m => m.Valid);
if (!Valid && pkm.FatefulEncounter && Info.Relearn.Any(chk => !chk.Valid) && EncounterMatch is EncounterInvalid)
AddLine(Severity.Indeterminate, LFatefulGiftMissing, CheckIdentifier.Fateful);
Parsed = true;
}
#if SUPPRESS
// We want to swallow any error from malformed input data from the user. The Valid state is all that we really need.
#pragma warning disable CA1031 // Do not catch general exception types
catch (Exception e)
#pragma warning restore CA1031 // Do not catch general exception types
{
System.Diagnostics.Debug.WriteLine(e.Message);
Info = new LegalInfo(pkm);
Valid = false;
AddLine(Severity.Invalid, L_AError, CheckIdentifier.Misc);
}
#endif
}
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
2019-10-17 01:47:31 +00:00
private Action GetParseMethod()
{
if (pkm.Format <= 2) // prior to storing GameVersion
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
2019-10-17 01:47:31 +00:00
return ParsePK1;
int gen = pkm.GenNumber;
if (gen <= 0)
gen = pkm.Format;
return gen switch
{
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
2019-10-17 01:47:31 +00:00
3 => ParsePK3,
4 => ParsePK4,
5 => ParsePK5,
6 => ParsePK6,
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
2019-10-17 01:47:31 +00:00
1 => ParsePK7,
2 => ParsePK7,
7 => ParsePK7,
2020-01-07 01:50:18 +00:00
8 => ParsePK8,
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
2019-10-17 01:47:31 +00:00
_ => throw new Exception()
};
}
private void ParsePK1()
{
UpdateInfo();
2018-07-25 02:33:42 +00:00
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
Nickname.Verify(this);
Level.Verify(this);
Level.VerifyG1(this);
Trainer.VerifyOTG1(this);
MiscValues.VerifyMiscG1(this);
if (pkm.Format == 2)
Item.Verify(this);
}
private void ParsePK3()
{
UpdateInfo();
UpdateChecks();
Refactor encounter matching exercise in deferred execution/state machine, only calculate possible matches until a sufficiently valid match is obtained. Previous setup would try to calculate the 'best match' and had band-aid workarounds in cases where a subsequent check may determine it to be a false match. There's still more ways to improve speed: - precalculate relationships for Encounter Slots rather than iterating over every area - yielding individual slots instead of an entire area - group non-egg wondercards by ID in a dict/hashtable for faster retrieval reworked some internals: - EncounterMatch is always an IEncounterable instead of an object, for easy pattern matching. - Splitbreed checking is done per encounter and is stored in the EncounterEgg result - Encounter validation uses Encounter/Move/RelearnMove/Evolution to whittle to the final encounter. As a part of the encounter matching, a lazy peek is used to check if an invalid encounter should be retained instead of discarded; if another encounter has not been checked, it'll stop the invalid checks and move on. If it is the last encounter, no other valid encounters exist so it will keep the parse for the invalid encounter. If no encounters are yielded, then there is no encountermatch. An EncounterInvalid is created to store basic details, and the parse is carried out. Breaks some legality checking features for flagging invalid moves in more detail, but those can be re-added in a separate check (if splitbreed & any move invalid -> check for other split moves). Should now be easier to follow the flow & maintain :smile:
2017-05-28 04:17:53 +00:00
if (pkm.Format > 3)
Transfer.VerifyTransferLegalityG3(this);
if (pkm.Version == (int)GameVersion.CXD)
CXD.Verify(this);
if (Info.EncounterMatch is WC3 z && z.NotDistributed)
AddLine(Severity.Invalid, LEncUnreleased, CheckIdentifier.Encounter);
if (pkm.Format >= 8)
Transfer.VerifyTransferLegalityG8(this);
}
private void ParsePK4()
{
UpdateInfo();
UpdateChecks();
Refactor encounter matching exercise in deferred execution/state machine, only calculate possible matches until a sufficiently valid match is obtained. Previous setup would try to calculate the 'best match' and had band-aid workarounds in cases where a subsequent check may determine it to be a false match. There's still more ways to improve speed: - precalculate relationships for Encounter Slots rather than iterating over every area - yielding individual slots instead of an entire area - group non-egg wondercards by ID in a dict/hashtable for faster retrieval reworked some internals: - EncounterMatch is always an IEncounterable instead of an object, for easy pattern matching. - Splitbreed checking is done per encounter and is stored in the EncounterEgg result - Encounter validation uses Encounter/Move/RelearnMove/Evolution to whittle to the final encounter. As a part of the encounter matching, a lazy peek is used to check if an invalid encounter should be retained instead of discarded; if another encounter has not been checked, it'll stop the invalid checks and move on. If it is the last encounter, no other valid encounters exist so it will keep the parse for the invalid encounter. If no encounters are yielded, then there is no encountermatch. An EncounterInvalid is created to store basic details, and the parse is carried out. Breaks some legality checking features for flagging invalid moves in more detail, but those can be re-added in a separate check (if splitbreed & any move invalid -> check for other split moves). Should now be easier to follow the flow & maintain :smile:
2017-05-28 04:17:53 +00:00
if (pkm.Format > 4)
Transfer.VerifyTransferLegalityG4(this);
if (pkm.Format >= 8)
Transfer.VerifyTransferLegalityG8(this);
}
private void ParsePK5()
{
UpdateInfo();
UpdateChecks();
NHarmonia.Verify(this);
if (pkm.Format >= 8)
Transfer.VerifyTransferLegalityG8(this);
}
private void ParsePK6()
{
UpdateInfo();
UpdateChecks();
if (pkm.Format >= 8)
Transfer.VerifyTransferLegalityG8(this);
}
private void ParsePK7()
{
UpdateInfo();
if (pkm.VC)
UpdateVCTransferInfo();
UpdateChecks();
if (pkm.Format >= 8)
Transfer.VerifyTransferLegalityG8(this);
}
private void ParsePK8()
{
UpdateInfo();
UpdateChecks();
2019-11-28 19:51:23 +00:00
Transfer.VerifyTransferLegalityG8(this);
}
2018-07-21 03:22:46 +00:00
/// <summary>
/// Adds a new Check parse value.
/// </summary>
/// <param name="s">Check severity</param>
/// <param name="c">Check comment</param>
/// <param name="i">Check type</param>
internal void AddLine(Severity s, string c, CheckIdentifier i) => AddLine(new CheckResult(s, c, i));
/// <summary>
/// Adds a new Check parse value.
/// </summary>
/// <param name="chk">Check result to add.</param>
2018-07-21 03:22:46 +00:00
internal void AddLine(CheckResult chk) => Parse.Add(chk);
2017-12-12 00:01:24 +00:00
private void UpdateVCTransferInfo()
{
var enc = (Info.EncounterOriginalGB = EncounterMatch);
if (enc is EncounterInvalid)
return;
var vc = EncounterStaticGenerator.GetVCStaticTransferEncounter(pkm, enc);
Info.EncounterMatch = vc;
foreach (var z in Transfer.VerifyVCEncounter(pkm, enc, vc, Info.Moves))
AddLine(z);
Transfer.VerifyTransferLegalityG12(this);
}
private void UpdateInfo()
{
Parse.AddRange(Info.Parse);
}
private void UpdateChecks()
{
PIDEC.Verify(this);
Nickname.Verify(this);
LanguageIndex.Verify(this);
Trainer.Verify(this);
IndividualValues.Verify(this);
EffortValues.Verify(this);
Level.Verify(this);
Ribbon.Verify(this);
AbilityValues.Verify(this);
BallIndex.Verify(this);
FormValues.Verify(this);
MiscValues.Verify(this);
GenderValues.Verify(this);
Item.Verify(this);
2017-12-12 00:01:24 +00:00
if (pkm.Format <= 6 && pkm.Format >= 4)
Gen4EncounterType.Verify(this); // Gen 6->7 transfer deletes encounter type data
Contest.Verify(this);
if (pkm.Format < 6)
return;
if (pkm.Format < 8)
ConsoleRegion.Verify(this); // Gen 7->8 transfer deletes geolocation tracking data
History.Verify(this);
if (pkm is ITrainerMemories)
Memory.Verify(this);
if (pkm is ISuperTrain)
2018-11-14 03:10:31 +00:00
Medal.Verify(this);
if (pkm.Format < 7)
return;
HyperTraining.Verify(this);
MiscValues.VerifyVersionEvolution(this);
2020-04-06 23:32:23 +00:00
if (pkm.Format < 8)
return;
Mark.Verify(this);
}
private string GetLegalityReport()
{
if (Valid)
return L_ALegal;
if (!Parsed)
return L_AnalysisUnavailable;
2018-05-12 15:13:39 +00:00
var lines = new List<string>();
var vMoves = Info.Moves;
var vRelearn = Info.Relearn;
for (int i = 0; i < 4; i++)
{
if (!vMoves[i].Valid)
lines.Add(vMoves[i].Format(L_F0_M_1_2, i + 1));
}
if (pkm.Format >= 6)
{
for (int i = 0; i < 4; i++)
{
if (!vRelearn[i].Valid)
lines.Add(vRelearn[i].Format(L_F0_RM_1_2, i + 1));
}
}
// Build result string...
var outputLines = Parse.Where(chk => !chk.Valid);
lines.AddRange(outputLines.Select(chk => chk.Format(L_F0_1)));
return string.Join(Environment.NewLine, lines);
}
private string GetVerboseLegalityReport()
{
if (!Parsed)
return L_AnalysisUnavailable;
const string separator = "===";
string[] br = {separator, string.Empty};
var lines = new List<string> {br[1]};
lines.AddRange(br);
int rl = lines.Count;
var vMoves = Info.Moves;
var vRelearn = Info.Relearn;
for (int i = 0; i < 4; i++)
{
var move = vMoves[i];
if (!move.Valid)
continue;
var msg = move.Format(L_F0_M_1_2, i + 1);
if (pkm.Format != move.Generation)
msg += $" [Gen{move.Generation}]";
lines.Add(msg);
}
if (pkm.Format >= 6)
{
for (int i = 0; i < 4; i++)
{
if (vRelearn[i].Valid)
lines.Add(vRelearn[i].Format(L_F0_RM_1_2, i + 1));
}
}
if (rl != lines.Count) // move info added, break for next section
lines.Add(br[1]);
2018-05-12 15:13:39 +00:00
var outputLines = Parse.Where(chk => chk?.Valid == true && chk.Comment != L_AValid).OrderBy(chk => chk.Judgement); // Fishy sorted to top
lines.AddRange(outputLines.Select(chk => chk.Format(L_F0_1)));
lines.AddRange(br);
lines.Add(string.Format(L_FEncounterType_0, EncounterName));
var loc = EncounterLocation;
if (!string.IsNullOrEmpty(loc))
lines.Add(string.Format(L_F0_1, "Location", loc));
if (pkm.VC)
lines.Add(string.Format(L_F0_1, nameof(GameVersion), Info.Game));
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
2019-10-17 01:47:31 +00:00
if (!Info.PIDParsed)
Info.PIDIV = MethodFinder.Analyze(pkm);
var pidiv = Info.PIDIV;
{
if (!pidiv.NoSeed)
lines.Add(string.Format(L_FOriginSeed_0, pidiv.OriginSeed.ToString("X8")));
lines.Add(string.Format(L_FPIDType_0, pidiv.Type));
}
if (!Valid && Info.InvalidMatches != null)
{
lines.Add("Other match(es):");
lines.AddRange(Info.InvalidMatches.Select(z => $"{z.LongName}: {z.Reason}"));
}
2018-05-12 15:13:39 +00:00
return GetLegalityReport() + string.Join(Environment.NewLine, lines);
}
2018-07-21 03:22:46 +00:00
/// <summary>
/// Gets the current <see cref="PKM.RelearnMoves"/> array of four moves that might be legal.
/// </summary>
public IReadOnlyList<int> GetSuggestedRelearnMovesFromEncounter()
{
var parsed = VerifyRelearnMoves.GetSuggestedRelearn(pkm, Info.EncounterOriginal, Info.Relearn);
if (parsed.Count == 0) // Always true for Origins < 6 and encounters without relearn permitted.
return new int[4];
if (!EncounterMatch.EggEncounter)
return parsed;
List<int> window = new List<int>(parsed.Where(z => z != 0));
window.AddRange(pkm.Moves.Where((_, i) => Info.Moves[i].ShouldBeInRelearnMoves()));
window = window.Distinct().ToList();
int[] moves = new int[4];
int start = Math.Max(0, window.Count - 4);
int count = Math.Min(4, window.Count);
window.CopyTo(start, moves, 0, count);
return moves;
}
2018-07-21 03:22:46 +00:00
/// <summary>
/// Gets four moves which can be learned depending on the input arguments.
/// </summary>
/// <param name="tm">Allow TM moves</param>
/// <param name="tutor">Allow Tutor moves</param>
/// <param name="reminder">Allow Move Reminder</param>
public int[] GetSuggestedCurrentMoves(bool tm, bool tutor, bool reminder)
{
if (!Parsed)
return new int[4];
if (pkm.IsEgg && pkm.Format >= 6)
return pkm.RelearnMoves;
return MoveListSuggest.GetSuggestedMoves(pkm, Info.EvoChainsAllGens, tm, !pkm.IsEgg && tutor, reminder, EncounterOriginal);
}
}
}