2018-07-21 04:32:33 +00:00
using System ;
using System.Collections.Generic ;
using System.Diagnostics ;
using System.IO ;
using System.Linq ;
using static PKHeX . Core . MessageStrings ;
namespace PKHeX.Core
{
2019-07-14 22:06:45 +00:00
/// <summary>
/// Extension methods for <see cref="SaveFile"/> syntax sugar.
/// </summary>
2018-07-21 04:32:33 +00:00
public static class SaveExtensions
{
/// <summary>
/// Checks if the <see cref="PKM"/> is compatible with the input <see cref="SaveFile"/>, and makes any necessary modifications to force compatibility.
/// </summary>
/// <remarks>Should only be used when forcing a backwards conversion to sanitize the PKM fields to the target format.
/// If the PKM is compatible, some properties may be forced to sanitized values.</remarks>
2019-07-14 22:06:45 +00:00
/// <param name="sav">Save File target that the PKM will be injected.</param>
2018-07-21 04:32:33 +00:00
/// <param name="pk">PKM input that is to be injected into the Save File.</param>
/// <returns>Indication whether or not the PKM is compatible.</returns>
2019-07-14 22:06:45 +00:00
public static bool IsPKMCompatibleWithModifications ( this SaveFile sav , PKM pk ) = > PKMConverter . IsPKMCompatibleWithModifications ( pk , sav ) ;
2018-07-21 04:32:33 +00:00
/// <summary>
/// Sets the details of a path to a <see cref="SaveFile"/> object.
/// </summary>
/// <param name="sav">Save File to set path details to.</param>
/// <param name="path">Full Path of the file</param>
public static void SetFileInfo ( this SaveFile sav , string path )
{
if ( ! sav . Exportable ) // Blank save file
{
2019-02-15 08:50:23 +00:00
sav . FileFolder = sav . FilePath = string . Empty ;
2018-07-21 04:32:33 +00:00
sav . FileName = "Blank Save File" ;
return ;
}
sav . FilePath = path ;
sav . FileFolder = Path . GetDirectoryName ( path ) ;
2018-07-30 04:54:02 +00:00
sav . FileName = string . Empty ;
var bakName = Util . CleanFileName ( sav . BAKName ) ;
2018-07-21 04:32:33 +00:00
sav . FileName = Path . GetFileName ( path ) ;
2018-07-30 04:54:02 +00:00
if ( sav . FileName ? . EndsWith ( bakName ) = = true )
sav . FileName = sav . FileName . Substring ( 0 , sav . FileName . Length - bakName . Length ) ;
2018-07-21 04:32:33 +00:00
}
2019-02-19 05:59:57 +00:00
/// <summary>
2020-06-17 02:46:22 +00:00
/// Gets suggested export options for the save file.
2019-02-19 05:59:57 +00:00
/// </summary>
2019-07-14 22:06:45 +00:00
/// <param name="sav">SaveFile to be exported</param>
/// <param name="ext">Selected export extension</param>
2019-02-19 05:59:57 +00:00
public static ExportFlags GetSuggestedFlags ( this SaveFile sav , string ext )
{
var flags = ExportFlags . None ;
if ( ext = = ".dsv" )
flags | = ExportFlags . IncludeFooter ;
if ( ext = = ".gci" | | ( sav is IGCSaveFile gc & & ! gc . IsMemoryCardSave ) )
flags | = ExportFlags . IncludeHeader ;
return flags ;
}
2018-07-21 04:32:33 +00:00
/// <summary>
/// Checks a <see cref="PKM"/> file for compatibility to the <see cref="SaveFile"/>.
/// </summary>
2019-07-14 22:06:45 +00:00
/// <param name="sav"><see cref="SaveFile"/> that is being checked.</param>
2018-07-21 04:32:33 +00:00
/// <param name="pkm"><see cref="PKM"/> that is being tested for compatibility.</param>
/// <returns></returns>
2019-07-14 22:06:45 +00:00
public static IReadOnlyList < string > IsPKMCompatible ( this SaveFile sav , PKM pkm )
2018-07-21 04:32:33 +00:00
{
2019-07-14 22:06:45 +00:00
return sav . GetSaveFileErrata ( pkm , GameInfo . Strings ) ;
2018-07-21 04:32:33 +00:00
}
2019-07-14 22:06:45 +00:00
private static IReadOnlyList < string > GetSaveFileErrata ( this SaveFile sav , PKM pkm , IBasicStrings strings )
2018-07-21 04:32:33 +00:00
{
var errata = new List < string > ( ) ;
2020-01-25 20:16:45 +00:00
ushort held = ( ushort ) pkm . HeldItem ;
if ( sav . Generation > 1 & & held ! = 0 )
2018-07-21 04:32:33 +00:00
{
2020-01-25 20:16:45 +00:00
string? msg = null ;
if ( held > sav . MaxItemID )
msg = MsgIndexItemGame ;
2019-07-14 22:06:45 +00:00
else if ( ! pkm . CanHoldItem ( sav . HeldItems ) )
2020-01-25 20:16:45 +00:00
msg = MsgIndexItemHeld ;
if ( msg ! = null )
{
var itemstr = GameInfo . Strings . GetItemStrings ( pkm . Format , ( GameVersion ) pkm . Version ) ;
errata . Add ( $"{msg} {(held >= itemstr.Count ? held.ToString() : itemstr[held])}" ) ;
}
2018-07-21 04:32:33 +00:00
}
if ( pkm . Species > strings . Species . Count )
errata . Add ( $"{MsgIndexSpeciesRange} {pkm.Species}" ) ;
2019-07-14 22:06:45 +00:00
else if ( sav . MaxSpeciesID < pkm . Species )
2018-07-21 04:32:33 +00:00
errata . Add ( $"{MsgIndexSpeciesGame} {strings.Species[pkm.Species]}" ) ;
2019-07-14 22:06:45 +00:00
if ( ! sav . Personal [ pkm . Species ] . IsFormeWithinRange ( pkm . AltForm ) & & ! FormConverter . IsValidOutOfBoundsForme ( pkm . Species , pkm . AltForm , pkm . GenNumber ) )
errata . Add ( string . Format ( LegalityCheckStrings . LFormInvalidRange , Math . Max ( 0 , sav . Personal [ pkm . Species ] . FormeCount - 1 ) , pkm . AltForm ) ) ;
2018-07-21 04:32:33 +00:00
if ( pkm . Moves . Any ( m = > m > strings . Move . Count ) )
errata . Add ( $"{MsgIndexMoveRange} {string.Join(" , ", pkm.Moves.Where(m => m > strings.Move.Count).Select(m => m.ToString()))}" ) ;
2019-07-14 22:06:45 +00:00
else if ( pkm . Moves . Any ( m = > m > sav . MaxMoveID ) )
errata . Add ( $"{MsgIndexMoveGame} {string.Join(" , ", pkm.Moves.Where(m => m > sav.MaxMoveID).Select(m => strings.Move[m]))}" ) ;
2018-07-21 04:32:33 +00:00
if ( pkm . Ability > strings . Ability . Count )
errata . Add ( $"{MsgIndexAbilityRange} {pkm.Ability}" ) ;
2019-07-14 22:06:45 +00:00
else if ( pkm . Ability > sav . MaxAbilityID )
2018-07-21 04:32:33 +00:00
errata . Add ( $"{MsgIndexAbilityGame} {strings.Ability[pkm.Ability]}" ) ;
return errata ;
}
2018-12-29 01:58:13 +00:00
/// <summary>
2019-07-14 22:06:45 +00:00
/// Imports compatible <see cref="PKM"/> data to the <see cref="sav"/>, starting at the provided box.
2018-12-29 01:58:13 +00:00
/// </summary>
2019-07-14 22:06:45 +00:00
/// <param name="sav">Save File that will receive the <see cref="compat"/> data.</param>
/// <param name="compat">Compatible <see cref="PKM"/> data that can be set to the <see cref="sav"/> without conversion.</param>
2018-12-29 01:58:13 +00:00
/// <param name="overwrite">Overwrite existing full slots. If true, will only overwrite empty slots.</param>
/// <param name="boxStart">First box to start loading to. All prior boxes are not modified.</param>
/// <param name="noSetb">Bypass option to not modify <see cref="PKM"/> properties when setting to Save File.</param>
/// <returns>Count of injected <see cref="PKM"/>.</returns>
2019-07-14 22:06:45 +00:00
public static int ImportPKMs ( this SaveFile sav , IEnumerable < PKM > compat , bool overwrite = false , int boxStart = 0 , PKMImportSetting noSetb = PKMImportSetting . UseDefault )
2018-07-21 04:32:33 +00:00
{
2019-07-14 22:06:45 +00:00
int startCount = boxStart * sav . BoxSlotCount ;
int maxCount = sav . SlotCount ;
2018-12-29 01:58:13 +00:00
int index = startCount ;
2019-05-15 16:11:48 +00:00
int nonOverwriteImport = 0 ;
2018-07-21 04:32:33 +00:00
foreach ( var pk in compat )
{
2018-12-29 01:58:13 +00:00
if ( overwrite )
{
2019-07-14 22:06:45 +00:00
while ( sav . IsSlotOverwriteProtected ( index ) )
2018-12-29 01:58:13 +00:00
+ + index ;
2019-05-15 16:11:48 +00:00
2019-07-14 22:06:45 +00:00
sav . SetBoxSlotAtIndex ( pk , index , noSetb ) ;
2018-12-29 01:58:13 +00:00
}
else
2018-07-21 04:32:33 +00:00
{
2019-07-14 22:06:45 +00:00
index = sav . NextOpenBoxSlot ( index - 1 ) ;
2018-12-29 01:58:13 +00:00
if ( index < 0 ) // Boxes full!
break ;
2018-07-21 04:32:33 +00:00
2019-07-14 22:06:45 +00:00
sav . SetBoxSlotAtIndex ( pk , index , noSetb ) ;
2019-05-15 16:11:48 +00:00
nonOverwriteImport + + ;
}
2018-07-21 04:32:33 +00:00
2018-12-29 01:58:13 +00:00
if ( + + index = = maxCount ) // Boxes full!
2018-07-21 04:32:33 +00:00
break ;
}
2019-07-14 22:06:45 +00:00
return overwrite ? index - startCount : nonOverwriteImport ; // actual imported count
2018-07-21 04:32:33 +00:00
}
2019-07-14 22:06:45 +00:00
public static IEnumerable < PKM > GetCompatible ( this SaveFile sav , IEnumerable < PKM > pks )
2018-07-21 04:32:33 +00:00
{
2019-07-14 22:06:45 +00:00
var savtype = sav . PKMType ;
2018-07-21 04:32:33 +00:00
foreach ( var temp in pks )
{
var pk = PKMConverter . ConvertToType ( temp , savtype , out string c ) ;
if ( pk = = null )
{
Debug . WriteLine ( c ) ;
continue ;
}
2020-10-04 17:25:34 +00:00
if ( sav is ILangDeviantSave il & & PKMConverter . IsIncompatibleGB ( pk , il . Japanese , pk . Japanese ) )
2018-07-24 22:49:00 +00:00
{
2019-07-14 22:06:45 +00:00
c = PKMConverter . GetIncompatibleGBMessage ( pk , il . Japanese ) ;
2018-07-24 22:49:00 +00:00
Debug . WriteLine ( c ) ;
continue ;
}
2019-07-14 22:06:45 +00:00
var compat = sav . IsPKMCompatible ( pk ) ;
2018-07-21 04:32:33 +00:00
if ( compat . Count > 0 )
continue ;
yield return pk ;
}
}
2019-02-15 08:50:23 +00:00
/// <summary>
/// Gets a compatible <see cref="PKM"/> for editing with a new <see cref="SaveFile"/>.
/// </summary>
/// <param name="sav">SaveFile to receive the compatible <see cref="pk"/></param>
/// <param name="pk">Current Pokémon being edited</param>
/// <returns>Current Pokémon, assuming conversion is possible. If conversion is not possible, a blank <see cref="PKM"/> will be obtained from the <see cref="sav"/>.</returns>
2020-04-16 19:58:48 +00:00
public static PKM GetCompatiblePKM ( this SaveFile sav , PKM pk )
2019-02-15 08:50:23 +00:00
{
2020-04-16 19:58:48 +00:00
if ( pk . Format > = 3 | | sav . Generation > = 7 )
return PKMConverter . ConvertToType ( pk , sav . PKMType , out _ ) ? ? sav . BlankPKM ;
// gen1-2 compatibility check
if ( pk . Japanese ! = ( ( ILangDeviantSave ) sav ) . Japanese )
return sav . BlankPKM ;
if ( sav is SAV2 s2 & & s2 . Korean ! = pk . Korean )
2019-02-15 08:50:23 +00:00
return sav . BlankPKM ;
return PKMConverter . ConvertToType ( pk , sav . PKMType , out _ ) ? ? sav . BlankPKM ;
}
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
/// <summary>
/// Gets a blank file for the save file. If the template path exists, a template load will be attempted.
/// </summary>
/// <param name="sav">Save File to fetch a template for</param>
/// <returns>Template if it exists, or a blank <see cref="PKM"/> from the <see cref="sav"/></returns>
public static PKM LoadTemplate ( this SaveFile sav ) = > sav . BlankPKM ;
2019-02-15 08:50:23 +00:00
/// <summary>
/// Gets a blank file for the save file. If the template path exists, a template load will be attempted.
/// </summary>
/// <param name="sav">Save File to fetch a template for</param>
/// <param name="templatePath">Path to look for a template in</param>
/// <returns>Template if it exists, or a blank <see cref="PKM"/> from the <see cref="sav"/></returns>
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 static PKM LoadTemplate ( this SaveFile sav , string templatePath )
2019-02-15 08:50:23 +00:00
{
if ( ! Directory . Exists ( templatePath ) )
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 LoadTemplate ( sav ) ;
2019-02-15 08:50:23 +00:00
var di = new DirectoryInfo ( templatePath ) ;
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
string path = Path . Combine ( templatePath , $"{di.Name}.{sav.PKMType.Name.ToLower()}" ) ;
2019-02-15 08:50:23 +00:00
if ( ! File . Exists ( path ) | | ! PKX . IsPKM ( new FileInfo ( path ) . Length ) )
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 LoadTemplate ( sav ) ;
var pk = PKMConverter . GetPKMfromBytes ( File . ReadAllBytes ( path ) , prefer : sav . Generation ) ;
if ( pk = = null )
return LoadTemplate ( sav ) ;
2019-02-15 08:50:23 +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
2019-10-17 01:47:31 +00:00
return PKMConverter . ConvertToType ( pk , sav . BlankPKM . GetType ( ) , out _ ) ? ? LoadTemplate ( sav ) ;
2019-02-15 08:50:23 +00:00
}
2018-07-21 04:32:33 +00:00
}
}