2018-08-10 04:53:39 +00:00
|
|
|
|
using System;
|
2020-01-19 00:46:38 +00:00
|
|
|
|
using System.Collections.Generic;
|
2018-08-10 04:53:39 +00:00
|
|
|
|
|
|
|
|
|
namespace PKHeX.Core
|
|
|
|
|
{
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Generation 4 Mystery Gift Template File
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <remarks>
|
|
|
|
|
/// Big thanks to Grovyle91's Pokémon Mystery Gift Editor, from which the structure was referenced.
|
|
|
|
|
/// https://projectpokemon.org/home/profile/859-grovyle91/
|
|
|
|
|
/// https://projectpokemon.org/home/forums/topic/5870-pok%C3%A9mon-mystery-gift-editor-v143-now-with-bw-support/
|
|
|
|
|
/// See also: http://tccphreak.shiny-clique.net/debugger/pcdfiles.htm
|
|
|
|
|
/// </remarks>
|
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 sealed class PCD : DataMysteryGift
|
2018-08-10 04:53:39 +00:00
|
|
|
|
{
|
|
|
|
|
public const int Size = 0x358; // 856
|
|
|
|
|
public override int Format => 4;
|
|
|
|
|
|
|
|
|
|
public override int Level
|
|
|
|
|
{
|
|
|
|
|
get => Gift.Level;
|
|
|
|
|
set => Gift.Level = value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override int Ball
|
|
|
|
|
{
|
|
|
|
|
get => Gift.Ball;
|
|
|
|
|
set => Gift.Ball = value;
|
|
|
|
|
}
|
|
|
|
|
|
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 PCD() : this(new byte[Size]) { }
|
|
|
|
|
public PCD(byte[] data) : base(data) { }
|
2018-08-10 04:53:39 +00:00
|
|
|
|
|
2019-12-25 07:24:28 +00:00
|
|
|
|
public override byte[] Write()
|
|
|
|
|
{
|
|
|
|
|
// Ensure PGT content is encrypted
|
|
|
|
|
var clone = (PCD)Clone();
|
|
|
|
|
if (clone.Gift.VerifyPKEncryption())
|
|
|
|
|
clone.Gift = clone.Gift;
|
|
|
|
|
return clone.Data;
|
|
|
|
|
}
|
|
|
|
|
|
2018-08-10 04:53:39 +00:00
|
|
|
|
public PGT Gift
|
|
|
|
|
{
|
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
|
|
|
|
get => _gift ??= new PGT(Data.Slice(0, PGT.Size));
|
|
|
|
|
set => (_gift = value).Data.CopyTo(Data, 0);
|
2018-08-10 04:53:39 +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
|
|
|
|
private PGT? _gift;
|
2018-08-10 04:53:39 +00:00
|
|
|
|
|
|
|
|
|
public byte[] Information
|
|
|
|
|
{
|
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
|
|
|
|
get => Data.SliceEnd(PGT.Size);
|
|
|
|
|
set => value.CopyTo(Data, Data.Length - PGT.Size);
|
2018-08-10 04:53:39 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override object Content => Gift.PK;
|
|
|
|
|
public override bool GiftUsed { get => Gift.GiftUsed; set => Gift.GiftUsed = value; }
|
|
|
|
|
public override bool IsPokémon { get => Gift.IsPokémon; set => Gift.IsPokémon = value; }
|
|
|
|
|
public override bool IsItem { get => Gift.IsItem; set => Gift.IsItem = value; }
|
|
|
|
|
public override int ItemID { get => Gift.ItemID; set => Gift.ItemID = value; }
|
|
|
|
|
|
|
|
|
|
public override int CardID
|
|
|
|
|
{
|
|
|
|
|
get => BitConverter.ToUInt16(Data, 0x150);
|
|
|
|
|
set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x150);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private const int TitleLength = 0x48;
|
|
|
|
|
|
|
|
|
|
public override string CardTitle
|
|
|
|
|
{
|
2019-03-21 04:50:44 +00:00
|
|
|
|
get => StringConverter4.GetString4(Data, 0x104, TitleLength);
|
2018-08-10 04:53:39 +00:00
|
|
|
|
set
|
|
|
|
|
{
|
2019-03-21 04:50:44 +00:00
|
|
|
|
byte[] data = StringConverter4.SetString4(value, (TitleLength / 2) - 1, TitleLength / 2, 0xFFFF);
|
2018-08-10 04:53:39 +00:00
|
|
|
|
int len = data.Length;
|
|
|
|
|
Array.Resize(ref data, 0x48);
|
|
|
|
|
for (int i = 0; i < len; i++)
|
|
|
|
|
data[i] = 0xFF;
|
|
|
|
|
data.CopyTo(Data, 0x104);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public ushort CardCompatibility => BitConverter.ToUInt16(Data, 0x14C); // rest of bytes we don't really care about
|
|
|
|
|
|
|
|
|
|
public override int Species { get => Gift.IsManaphyEgg ? 490 : Gift.Species; set => Gift.Species = value; }
|
2020-01-19 00:46:38 +00:00
|
|
|
|
public override IReadOnlyList<int> Moves { get => Gift.Moves; set => Gift.Moves = value; }
|
2018-08-10 04:53:39 +00:00
|
|
|
|
public override int HeldItem { get => Gift.HeldItem; set => Gift.HeldItem = value; }
|
|
|
|
|
public override bool IsShiny => Gift.IsShiny;
|
|
|
|
|
public override bool IsEgg { get => Gift.IsEgg; set => Gift.IsEgg = value; }
|
|
|
|
|
public override int Gender { get => Gift.Gender; set => Gift.Gender = value; }
|
|
|
|
|
public override int Form { get => Gift.Form; set => Gift.Form = value; }
|
|
|
|
|
public override int TID { get => Gift.TID; set => Gift.TID = value; }
|
|
|
|
|
public override int SID { get => Gift.SID; set => Gift.SID = value; }
|
|
|
|
|
public override string OT_Name { get => Gift.OT_Name; set => Gift.OT_Name = value; }
|
|
|
|
|
|
|
|
|
|
// ILocation overrides
|
|
|
|
|
public override int Location { get => IsEgg ? 0 : Gift.EggLocation + 3000; set { } }
|
|
|
|
|
public override int EggLocation { get => IsEgg ? Gift.EggLocation + 3000 : 0; set { } }
|
|
|
|
|
|
|
|
|
|
public bool GiftEquals(PGT pgt)
|
|
|
|
|
{
|
|
|
|
|
// Skip over the PGT's "Corresponding PCD Slot" @ 0x02
|
|
|
|
|
byte[] g = pgt.Data;
|
|
|
|
|
byte[] c = Gift.Data;
|
|
|
|
|
if (g.Length != c.Length || g.Length < 3)
|
|
|
|
|
return false;
|
|
|
|
|
for (int i = 0; i < 2; i++)
|
|
|
|
|
{
|
|
|
|
|
if (g[i] != c[i])
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (int i = 3; i < g.Length; i++)
|
|
|
|
|
{
|
|
|
|
|
if (g[i] != c[i])
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-17 02:46:22 +00:00
|
|
|
|
public override PKM ConvertToPKM(ITrainerInfo sav, EncounterCriteria criteria)
|
2018-08-10 04:53:39 +00:00
|
|
|
|
{
|
2020-06-17 02:46:22 +00:00
|
|
|
|
return Gift.ConvertToPKM(sav, criteria);
|
2018-08-10 04:53:39 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public bool CanBeReceivedBy(int pkmVersion) => (CardCompatibility >> pkmVersion & 1) == 1;
|
2018-12-27 09:00:08 +00:00
|
|
|
|
|
2020-07-18 18:29:16 +00:00
|
|
|
|
protected override bool IsMatchExact(PKM pkm, DexLevel evo)
|
2018-12-27 09:00:08 +00:00
|
|
|
|
{
|
|
|
|
|
var wc = Gift.PK;
|
|
|
|
|
if (!wc.IsEgg)
|
|
|
|
|
{
|
|
|
|
|
if (wc.TID != pkm.TID) return false;
|
|
|
|
|
if (wc.SID != pkm.SID) return false;
|
|
|
|
|
if (wc.OT_Name != pkm.OT_Name) return false;
|
|
|
|
|
if (wc.OT_Gender != pkm.OT_Gender) return false;
|
|
|
|
|
if (wc.Language != 0 && wc.Language != pkm.Language) return false;
|
|
|
|
|
|
|
|
|
|
if (pkm.Format != 4) // transferred
|
|
|
|
|
{
|
|
|
|
|
// met location: deferred to general transfer check
|
|
|
|
|
if (wc.CurrentLevel > pkm.Met_Level) return false;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (wc.Egg_Location + 3000 != pkm.Met_Location) return false;
|
|
|
|
|
if (wc.CurrentLevel != pkm.Met_Level) return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else // Egg
|
|
|
|
|
{
|
2019-05-11 03:46:49 +00:00
|
|
|
|
if (wc.Egg_Location + 3000 != pkm.Egg_Location && pkm.Egg_Location != Locations.LinkTrade4) // traded
|
2018-12-27 09:00:08 +00:00
|
|
|
|
return false;
|
|
|
|
|
if (wc.CurrentLevel != pkm.Met_Level)
|
|
|
|
|
return false;
|
|
|
|
|
if (pkm.IsEgg && !pkm.IsNative)
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-21 23:35:49 +00:00
|
|
|
|
if (wc.AltForm != evo.Form && !Legal.IsFormChangeable(wc.Species, wc.AltForm, pkm.Format))
|
2018-12-27 09:00:08 +00:00
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
if (wc.Ball != pkm.Ball) return false;
|
|
|
|
|
if (wc.OT_Gender < 3 && wc.OT_Gender != pkm.OT_Gender) return false;
|
|
|
|
|
|
2020-09-03 21:28:51 +00:00
|
|
|
|
// Milotic is the only gift to come with Contest stats.
|
|
|
|
|
if (wc.Species == (int)Core.Species.Milotic && pkm is IContestStats s && s.IsContestBelow(wc))
|
|
|
|
|
return false;
|
|
|
|
|
|
2020-08-29 21:33:51 +00:00
|
|
|
|
if (wc.PID == 1)
|
|
|
|
|
{
|
|
|
|
|
// Random PID, never shiny
|
|
|
|
|
// PID=0 was never used (pure random).
|
|
|
|
|
if (pkm.IsShiny)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
// Don't check gender. All gifts that have PID=1 are genderless, with one exception.
|
|
|
|
|
// The KOR Arcanine can end up with either gender, even though the template may have a specified gender.
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// Fixed PID
|
|
|
|
|
if (wc.Gender != pkm.Gender)
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2018-12-27 09:00:08 +00:00
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected override bool IsMatchDeferred(PKM pkm)
|
|
|
|
|
{
|
|
|
|
|
if (!CanBeReceivedBy(pkm.Version))
|
|
|
|
|
return false;
|
|
|
|
|
return Species != pkm.Species;
|
|
|
|
|
}
|
2018-08-10 04:53:39 +00:00
|
|
|
|
}
|
|
|
|
|
}
|