Initial (pretty broken) US SAV2 loading/viewing

This commit is contained in:
Michael Scire 2016-09-02 14:20:39 -07:00
parent c0750647f6
commit 2e938a6ab2
17 changed files with 1342 additions and 24 deletions

View file

@ -169,7 +169,7 @@ namespace PKHeX
public static string[] gendersymbols = { "♂", "♀", "-" };
public static string[] specieslist, movelist, itemlist, abilitylist, types, natures, forms,
memories, genloc, trainingbags, trainingstage, characteristics,
encountertypelist, gamelanguages, balllist, gamelist, pokeblocks, g3items, g1items = { };
encountertypelist, gamelanguages, balllist, gamelist, pokeblocks, g3items, g2items, g1items = { };
public static string[] metGSC_00000, metRSEFRLG_00000 = { };
public static string[] metHGSS_00000, metHGSS_02000, metHGSS_03000 = { };
public static string[] metBW2_00000, metBW2_30000, metBW2_40000, metBW2_60000 = { };
@ -874,9 +874,10 @@ namespace PKHeX
GB_Markings.Visible = SAV.Generation > 2;
Label_HeldItem.Visible = CB_HeldItem.Visible = SAV.Generation > 1;
Label_Total.Visible = TB_IVTotal.Visible = TB_EVTotal.Visible = L_Potential.Visible =
Label_HiddenPowerPrefix.Visible = CB_HPType.Visible = SAV.Generation > 1;
Label_CharacteristicPrefix.Visible = L_Characteristic.Visible = SAV.Generation > 1;
Label_Total.Visible = TB_IVTotal.Visible = TB_EVTotal.Visible = L_Potential.Visible = SAV.Generation > 2;
Label_HiddenPowerPrefix.Visible = CB_HPType.Visible = SAV.Generation > 1;
CB_HPType.Enabled = SAV.Generation > 2;
Label_CharacteristicPrefix.Visible = L_Characteristic.Visible = SAV.Generation > 2;
Label_ContestStats.Visible = Label_Cool.Visible = Label_Tough.Visible = Label_Smart.Visible =
Label_Sheen.Visible = Label_Beauty.Visible = Label_Cute.Visible = TB_Cool.Visible = TB_Tough.Visible =
TB_Smart.Visible = TB_Sheen.Visible = TB_Beauty.Visible = TB_Cute.Visible = Label_Nature.Visible =
@ -941,6 +942,11 @@ namespace PKHeX
getPKMfromFields = preparePK1;
extraBytes = new byte[] {};
break;
case 2:
getFieldsfromPKM = populateFieldsPK2;
getPKMfromFields = preparePK2;
extraBytes = new byte[] { };
break;
case 3:
getFieldsfromPKM = populateFieldsPK3;
getPKMfromFields = preparePK3;
@ -970,7 +976,7 @@ namespace PKHeX
bool init = fieldsInitialized;
fieldsInitialized = false;
populateFilteredDataSources();
populateFields((pkm.Format != SAV.Generation || SAV.Generation == 1) ? SAV.BlankPKM : pk);
populateFields((pkm.Format != SAV.Generation || SAV.Generation < 3) ? SAV.BlankPKM : pk);
fieldsInitialized |= init;
// SAV Specific Limits
@ -1046,6 +1052,7 @@ namespace PKHeX
// Past Generation strings
g3items = Util.getStringList("ItemsG3", "en");
g2items = Util.getStringList("ItemsG2", "en");
g1items = Util.getStringList("ItemsG1", "en");
metRSEFRLG_00000 = Util.getStringList("rsefrlg_00000", "en");
metGSC_00000 = Util.getStringList("gsc_00000", "en");
@ -1271,6 +1278,8 @@ namespace PKHeX
string[] items = itemlist;
if (SAV.Generation == 3)
items = g3items;
if (SAV.Generation == 2)
items = g2items;
ItemDataSource = Util.getCBList(items, (HaX ? Enumerable.Range(0, SAV.MaxItemID) : SAV.HeldItems.Select(i => (int)i)).ToArray());
CB_HeldItem.DataSource = new BindingSource(ItemDataSource.Where(i => i.Value <= SAV.MaxItemID).ToList(), null);
@ -1410,7 +1419,7 @@ namespace PKHeX
bool isShiny = pkm.IsShiny;
// Set the Controls
BTN_Shinytize.Visible = BTN_Shinytize.Enabled = !isShiny && SAV.Generation > 2;
BTN_Shinytize.Visible = BTN_Shinytize.Enabled = !isShiny && SAV.Generation > 1;
Label_IsShiny.Visible = isShiny && SAV.Generation > 1;
// Refresh Markings (for Shiny Star if applicable)
@ -1707,6 +1716,16 @@ namespace PKHeX
if (SAV.Generation < 3)
{
TB_HPIV.Text = pkm.IV_HP.ToString("00");
if (SAV.Generation == 2)
{
Label_Gender.Text = gendersymbols[pkm.Gender];
Label_Gender.ForeColor = pkm.Gender == 2
? Label_Species.ForeColor
: (pkm.Gender == 1 ? Color.Red : Color.Blue);
CB_Form.SelectedIndex = pkm.AltForm;
setIsShiny(null);
getQuickFiller(dragout);
}
}
CB_HPType.SelectedValue = pkm.HPType;
@ -2260,6 +2279,8 @@ namespace PKHeX
{
CHK_Nicknamed.Checked = false;
TB_Friendship.Text = "1";
if (SAV.Generation == 2)
pkm.IsEgg = true;
// If we are an egg, it won't have a met location.
CHK_AsEgg.Checked = true;
@ -2273,6 +2294,9 @@ namespace PKHeX
if (!CHK_Nicknamed.Checked)
updateNickname(null, null);
if (SAV.Generation == 2)
pkm.IsEgg = false;
TB_Friendship.Text = SAV.Personal[Util.getIndex(CB_Species)].BaseFriendship.ToString();
if (CB_EggLocation.SelectedIndex == 0)
@ -2284,7 +2308,7 @@ namespace PKHeX
}
// Display hatch counter if it is an egg, Display Friendship if it is not.
Label_HatchCounter.Visible = CHK_IsEgg.Checked && SAV.Generation > 1;
Label_Friendship.Visible = !CHK_IsEgg.Checked && SAV.Generation > 2;
Label_Friendship.Visible = !CHK_IsEgg.Checked && SAV.Generation > 1;
// Update image to (not) show egg.
@ -2313,7 +2337,16 @@ namespace PKHeX
pkm.AltForm = CB_Form.SelectedIndex;
pkm.Version = Util.getIndex(CB_GameOrigin);
pkm.setShinyPID();
if (pkm.Format > 2)
pkm.setShinyPID();
else
{
TB_ATKIV.Text = "15";
TB_DEFIV.Text = "10";
TB_SPEIV.Text = "10";
TB_SPAIV.Text = "10";
updateIVs(null, null);
}
TB_PID.Text = pkm.PID.ToString("X8");
if (pkm.GenNumber < 6 && TB_EC.Visible)
@ -3454,7 +3487,7 @@ namespace PKHeX
new SAV_PokedexORAS().ShowDialog();
else if (SAV.XY)
new SAV_PokedexXY().ShowDialog();
else if (SAV.RBY)
else if (SAV.RBY || SAV.GSC)
new SAV_SimplePokedex().ShowDialog();
}
private void B_OUTPasserby_Click(object sender, EventArgs e)

133
PKHeX/MainWindow/MainPK2.cs Normal file
View file

@ -0,0 +1,133 @@
using System;
using System.Drawing;
namespace PKHeX
{
public partial class Main
{
private void populateFieldsPK2()
{
PK2 pk2 = pkm as PK2;
if (pk2 == null)
return;
// Do first
pk2.Stat_Level = PKX.getLevel(pk2.Species, pk2.EXP);
if (pk2.Stat_Level == 100)
pk2.EXP = PKX.getEXP(pk2.Stat_Level, pk2.Species);
CB_Species.SelectedValue = pk2.Species;
TB_Level.Text = pk2.Stat_Level.ToString();
TB_EXP.Text = pk2.EXP.ToString();
CB_HeldItem.SelectedValue = pk2.HeldItem;
CB_Form.SelectedIndex = pk2.AltForm;
CHK_IsEgg.Checked = pk2.IsEgg;
// Load rest
TB_TID.Text = pk2.TID.ToString("00000");
CHK_Nicknamed.Checked = pk2.IsNicknamed;
TB_Nickname.Text = pk2.Nickname;
TB_OT.Text = pk2.OT_Name;
GB_OT.BackgroundImage = null;
// Reset Label and ComboBox visibility, as well as non-data checked status.
Label_PKRS.Visible = false;
Label_PKRSdays.Visible = false;
TB_HPIV.Text = pk2.IV_HP.ToString();
TB_ATKIV.Text = pk2.IV_ATK.ToString();
TB_DEFIV.Text = pk2.IV_DEF.ToString();
TB_SPEIV.Text = pk2.IV_SPE.ToString();
TB_SPAIV.Text = pk2.IV_SPA.ToString();
TB_HPEV.Text = pk2.EV_HP.ToString();
TB_ATKEV.Text = pk2.EV_ATK.ToString();
TB_DEFEV.Text = pk2.EV_DEF.ToString();
TB_SPEEV.Text = pk2.EV_SPE.ToString();
TB_SPAEV.Text = pk2.EV_SPA.ToString();
CB_Move1.SelectedValue = pk2.Move1;
CB_Move2.SelectedValue = pk2.Move2;
CB_Move3.SelectedValue = pk2.Move3;
CB_Move4.SelectedValue = pk2.Move4;
CB_PPu1.SelectedIndex = pk2.Move1_PPUps;
CB_PPu2.SelectedIndex = pk2.Move2_PPUps;
CB_PPu3.SelectedIndex = pk2.Move3_PPUps;
CB_PPu4.SelectedIndex = pk2.Move4_PPUps;
TB_PP1.Text = pk2.Move1_PP.ToString();
TB_PP2.Text = pk2.Move2_PP.ToString();
TB_PP3.Text = pk2.Move3_PP.ToString();
TB_PP4.Text = pk2.Move4_PP.ToString();
CB_Language.SelectedIndex = pk2.Japanese ? 0 : 1;
updateStats();
setIsShiny(null);
Label_Gender.Text = gendersymbols[pk2.Gender];
Label_Gender.ForeColor = pk2.Gender == 2 ? Label_Species.ForeColor : (pk2.Gender == 1 ? Color.Red : Color.Blue);
TB_EXP.Text = pk2.EXP.ToString();
}
private PKM preparePK2()
{
PK2 pk2 = pkm as PK2;
if (pk2 == null)
return null;
pk2.Species = Util.getIndex(CB_Species);
pk2.TID = Util.ToInt32(TB_TID.Text);
pk2.EXP = Util.ToUInt32(TB_EXP.Text);
pk2.HeldItem = Util.getIndex(CB_HeldItem);
pk2.IsEgg = CHK_IsEgg.Checked;
pk2.EV_HP = Util.ToInt32(TB_HPEV.Text);
pk2.EV_ATK = Util.ToInt32(TB_ATKEV.Text);
pk2.EV_DEF = Util.ToInt32(TB_DEFEV.Text);
pk2.EV_SPE = Util.ToInt32(TB_SPEEV.Text);
pk2.EV_SPC = Util.ToInt32(TB_SPAEV.Text);
pk2.Nickname = TB_Nickname.Text;
pk2.Move1 = Util.getIndex(CB_Move1);
pk2.Move2 = Util.getIndex(CB_Move2);
pk2.Move3 = Util.getIndex(CB_Move3);
pk2.Move4 = Util.getIndex(CB_Move4);
pk2.Move1_PP = Util.getIndex(CB_Move1) > 0 ? Util.ToInt32(TB_PP1.Text) : 0;
pk2.Move2_PP = Util.getIndex(CB_Move2) > 0 ? Util.ToInt32(TB_PP2.Text) : 0;
pk2.Move3_PP = Util.getIndex(CB_Move3) > 0 ? Util.ToInt32(TB_PP3.Text) : 0;
pk2.Move4_PP = Util.getIndex(CB_Move4) > 0 ? Util.ToInt32(TB_PP4.Text) : 0;
pk2.Move1_PPUps = Util.getIndex(CB_Move1) > 0 ? CB_PPu1.SelectedIndex : 0;
pk2.Move2_PPUps = Util.getIndex(CB_Move2) > 0 ? CB_PPu2.SelectedIndex : 0;
pk2.Move3_PPUps = Util.getIndex(CB_Move3) > 0 ? CB_PPu3.SelectedIndex : 0;
pk2.Move4_PPUps = Util.getIndex(CB_Move4) > 0 ? CB_PPu4.SelectedIndex : 0;
pk2.IV_HP = Util.ToInt32(TB_HPIV.Text);
pk2.IV_ATK = Util.ToInt32(TB_ATKIV.Text);
pk2.IV_DEF = Util.ToInt32(TB_DEFIV.Text);
pk2.IV_SPE = Util.ToInt32(TB_SPEIV.Text);
pk2.IV_SPA = Util.ToInt32(TB_SPAIV.Text);
pk2.OT_Name = TB_OT.Text;
// Toss in Party Stats
Array.Resize(ref pk2.Data, pk2.SIZE_PARTY);
pk2.Stat_Level = Util.ToInt32(TB_Level.Text);
pk2.Stat_HPCurrent = Util.ToInt32(Stat_HP.Text);
pk2.Stat_HPMax = Util.ToInt32(Stat_HP.Text);
pk2.Stat_ATK = Util.ToInt32(Stat_ATK.Text);
pk2.Stat_DEF = Util.ToInt32(Stat_DEF.Text);
pk2.Stat_SPE = Util.ToInt32(Stat_SPE.Text);
pk2.Stat_SPA = Util.ToInt32(Stat_SPA.Text);
pk2.Stat_SPD = Util.ToInt32(Stat_SPD.Text);
if (HaX)
{
pk2.Stat_Level = (byte)Math.Min(Convert.ToInt32(MT_Level.Text), byte.MaxValue);
}
// Fix Moves if a slot is empty
pk2.FixMoves();
return pk2;
}
}
}

BIN
PKHeX/Misc/personal_gs Normal file

Binary file not shown.

View file

@ -73,6 +73,9 @@
<Compile Include="Legality\Tables3.cs" />
<Compile Include="Legality\Tables5.cs" />
<Compile Include="Legality\Tables4.cs" />
<Compile Include="MainWindow\MainPK2.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="MainWindow\MainPK1.cs">
<SubType>Form</SubType>
</Compile>
@ -93,6 +96,7 @@
<Compile Include="PersonalInfo\PersonalInfo.cs" />
<Compile Include="PersonalInfo\PersonalInfoB2W2.cs" />
<Compile Include="PersonalInfo\PersonalInfoBW.cs" />
<Compile Include="PersonalInfo\PersonalInfoG2.cs" />
<Compile Include="PersonalInfo\PersonalInfoG1.cs" />
<Compile Include="PersonalInfo\PersonalInfoG3.cs" />
<Compile Include="PersonalInfo\PersonalInfoG4.cs" />
@ -100,6 +104,7 @@
<Compile Include="PersonalInfo\PersonalInfoXY.cs" />
<Compile Include="PersonalInfo\PersonalTable.cs" />
<Compile Include="PKM\PK1.cs" />
<Compile Include="PKM\PK2.cs" />
<Compile Include="PKM\PKM.cs" />
<Compile Include="PKM\PKMConverter.cs" />
<Compile Include="PKM\ShowdownSet.cs" />
@ -119,6 +124,7 @@
<Compile Include="Saves\BlockInfo.cs" />
<Compile Include="Saves\BoxWallpaper.cs" />
<Compile Include="Saves\Inventory.cs" />
<Compile Include="Saves\SAV2.cs" />
<Compile Include="Saves\SAV1.cs" />
<Compile Include="Saves\SAV3.cs" />
<Compile Include="Saves\SAV4.cs" />
@ -422,6 +428,7 @@
<SubType>Designer</SubType>
</EmbeddedResource>
<None Include="app.config" />
<None Include="Misc\personal_gs" />
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
@ -471,9 +478,11 @@
<None Include="Resources\byte\lvlmove_xy.pkl" />
<None Include="Resources\byte\personal_b2w2" />
<None Include="Resources\byte\personal_bw" />
<None Include="Resources\byte\personal_c" />
<None Include="Resources\byte\personal_dp" />
<None Include="Resources\byte\personal_e" />
<None Include="Resources\byte\personal_fr" />
<None Include="Resources\byte\personal_gs" />
<None Include="Resources\byte\personal_hgss" />
<None Include="Resources\byte\personal_lg" />
<None Include="Resources\byte\personal_pt" />
@ -2746,6 +2755,9 @@
<ItemGroup>
<None Include="Resources\text\gen3\text_ItemsG1_en.txt" />
</ItemGroup>
<ItemGroup>
<Content Include="Resources\text\gen3\text_ItemsG2_en.txt" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.

View file

@ -18,7 +18,7 @@ namespace PKHeX
internal const int STRLEN_U = 11;
private int StringLength => Japanese ? STRLEN_J : STRLEN_U;
public override int Format => 1;
public override int Format => 2;
public bool Japanese => otname.Length == STRLEN_J;
@ -92,8 +92,7 @@ namespace PKHeX
{
// Oh god this is such total abuse of what this method is meant to do
// Please forgive me
return (byte[]) Data.Clone();
// return new PokemonList1(this).GetBytes();
return new PokemonList2(this).GetBytes();
}
// Please forgive me.
@ -213,8 +212,7 @@ namespace PKHeX
public override bool getGenderIsValid()
{
return true;
int gv = PersonalTable.GSC[Species].Gender;
int gv = PersonalTable.C[Species].Gender;
if (gv == 255)
return Gender == 2;
@ -222,29 +220,90 @@ namespace PKHeX
return Gender == 0;
if (gv == 0)
return Gender == 1;
if (gv <= (PID & 0xFF))
return Gender == 0;
if ((PID & 0xFF) < gv)
return Gender == 1;
switch (gv)
{
case 191:
return IV_ATK >= 2 ? Gender == 0 : Gender == 1;
case 127:
return IV_ATK >= 5 ? Gender == 0 : Gender == 1;
case 63:
return IV_ATK >= 7 ? Gender == 0 : Gender == 1;
case 31:
return IV_ATK >= 12 ? Gender == 0 : Gender == 1;
}
return false;
}
public override bool IsEgg { get; set; }
public override int Gender { get { return 0; } set { } }
public override int Gender
{
get
{
int gv = PersonalTable.C[Species].Gender;
if (gv == 255)
return 2;
if (gv == 254)
return 0;
if (gv == 0)
return 1;
switch (gv)
{
case 191:
return IV_ATK >= 2 ? 0 : 1;
case 127:
return IV_ATK >= 5 ? 0 : 1;
case 63:
return IV_ATK >= 7 ? 0 : 1;
case 31:
return IV_ATK >= 12 ? 0 : 1;
}
Console.WriteLine("Unknown Gender value: " + gv);
return 0;
}
set { }
}
public bool hasMetData => CaughtData != 0;
public override bool CanHoldItem(ushort[] ValidArray)
{
return false;
return ValidArray.Contains((ushort)HeldItem);
}
#region Future, Unused Attributes
public override uint EncryptionConstant { get { return 0; } set { } }
public override uint PID { get { return 0; } set { } }
public override int Nature { get { return 0; } set { } }
public override int AltForm { get { return 0; } set { } }
public override int AltForm
{
get
{
if (Species != 201) // Unown
return 0;
else
{
uint formeVal = 0;
formeVal |= (uint)((IV_ATK & 0x6) << 5);
formeVal |= (uint)((IV_DEF & 0x6) << 3);
formeVal |= (uint)((IV_SPE & 0x6) << 1);
formeVal |= (uint)((IV_SPC & 0x6) >> 1);
return (int)(formeVal / 10);
}
}
set{ }
}
public override int HPType
{
get { return 4 * (IV_ATK % 4) + (IV_DEF % 4); }
set
{
}
}
public override bool IsShiny => IV_DEF == 10 && IV_SPE == 10 && IV_SPC == 10 && (new[] { 2, 3, 6, 7, 10, 11, 14, 15 }).Contains(IV_ATK);
public override ushort Sanity { get { return 0; } set { } }
public override bool ChecksumValid => true;
public override ushort Checksum { get { return 0; } set { } }

View file

@ -226,7 +226,7 @@ namespace PKHeX
public abstract int CurrentHandler { get; set; }
// Derived
public bool IsShiny => TSV == PSV;
public virtual bool IsShiny => TSV == PSV;
public bool Gen6 => Version >= 24 && Version <= 29;
public bool XY => Version == (int)GameVersion.X || Version == (int)GameVersion.Y;
public bool AO => Version == (int)GameVersion.AS || Version == (int)GameVersion.OR;
@ -335,7 +335,7 @@ namespace PKHeX
get { return new[] { CNT_Cool, CNT_Beauty, CNT_Cute, CNT_Smart, CNT_Tough, CNT_Sheen }; }
set { if (value?.Length != 6) return; CNT_Cool = value[0]; CNT_Beauty = value[1]; CNT_Cute = value[2]; CNT_Smart = value[3]; CNT_Tough = value[4]; CNT_Sheen = value[5]; }
}
public int HPType
public virtual int HPType
{
get { return 15 * ((IV_HP & 1) + 2 * (IV_ATK & 1) + 4 * (IV_DEF & 1) + 8 * (IV_SPE & 1) + 16 * (IV_SPA & 1) + 32 * (IV_SPD & 1)) / 63; }
set

View file

@ -528,6 +528,8 @@ namespace PKHeX
Image itemimg = (Image)Resources.ResourceManager.GetObject("item_" + item) ?? Resources.helditem;
if ((generation == 3 || generation == 4) && 328 <= item && item <= 419) // gen3/4 TM
itemimg = Resources.item_tm;
if (generation == 2)
itemimg = Resources.helditem; // Don't even try
// Redraw
baseImage = Util.LayerImage(baseImage, itemimg, 22 + (15 - itemimg.Width) / 2, 15 + (15 - itemimg.Height), 1);

View file

@ -0,0 +1,80 @@
using System.Linq;
namespace PKHeX
{
public class PersonalInfoG2 : PersonalInfo
{
protected PersonalInfoG2() { }
public const int SIZE = 0x20;
public PersonalInfoG2(byte[] data)
{
if (data.Length != SIZE)
return;
Data = data;
TMHM = getBits(Data.Skip(0x18).Take(0x8).ToArray());
}
public override byte[] Write()
{
setBits(TMHM).CopyTo(Data, 0x18);
return Data;
}
public int DEX_ID { get { return Data[0x00]; } set { Data[0x00] = (byte)value; } }
public override int HP { get { return Data[0x01]; } set { Data[0x01] = (byte)value; } }
public override int ATK { get { return Data[0x02]; } set { Data[0x02] = (byte)value; } }
public override int DEF { get { return Data[0x03]; } set { Data[0x03] = (byte)value; } }
public override int SPE { get { return Data[0x04]; } set { Data[0x04] = (byte)value; } }
public override int SPA { get { return Data[0x05]; } set { Data[0x05] = (byte)value; } }
public override int SPD { get { return Data[0x06]; } set { Data[0x06] = (byte)value; } }
public override int[] Types
{
get { return new int[] { Data[0x07], Data[0x08] }; }
set
{
if (value?.Length != 2) return;
Data[0x07] = (byte)value[0];
Data[0x08] = (byte)value[1];
}
}
public override int CatchRate { get { return Data[0x09]; } set { Data[0x09] = (byte)value; } }
public override int BaseEXP { get { return Data[0x0A]; } set { Data[0x0A] = (byte)value; } }
public override int[] Items
{
get { return new int[] { Data[0xB], Data[0xC] }; }
set
{
if (value?.Length != 2) return;
Data[0xB] = (byte) value[0];
Data[0xC] = (byte) value[1];
}
}
public override int Gender { get { return Data[0xD]; } set { Data[0xD] = (byte)value; } }
public override int HatchCycles { get { return Data[0xF]; } set { Data[0xF] = (byte)value; } }
public override int EXPGrowth { get { return Data[0x16]; } set { Data[0x16] = (byte)value; } }
public override int[] EggGroups
{
get { return new int[] { Data[0x17] >> 4, Data[0x17] & 0xF }; }
set
{
if (value?.Length != 2) return;
Data[0x17] = (byte)(((value[0] & 0xF) << 4) | (value[1] & 0xF));
}
}
// EV Yields are just aliases for base stats in Gen I
public override int EV_HP { get { return HP; } set { } }
public override int EV_ATK { get { return ATK; } set { } }
public override int EV_DEF { get { return DEF; } set { } }
public override int EV_SPE { get { return SPE; } set { } }
public override int EV_SPA { get { return SPA; } set { } }
public override int EV_SPD { get { return SPD; } set { } }
// Future game values, unused
public override int[] Abilities { get { return new[] { 0, 0 }; } set { } }
public override int BaseFriendship { get { return 0; } set { } }
public override int EscapeRate { get { return 0; } set { } }
public override int Color { get { return 0; } set { } }
}
}

View file

@ -15,6 +15,8 @@ namespace PKHeX
internal static readonly PersonalTable FR = new PersonalTable(Properties.Resources.personal_fr, GameVersion.FR);
internal static readonly PersonalTable E = new PersonalTable(Properties.Resources.personal_e, GameVersion.E);
internal static readonly PersonalTable RS = new PersonalTable(Properties.Resources.personal_rs, GameVersion.RS);
internal static readonly PersonalTable C = new PersonalTable(Properties.Resources.personal_c, GameVersion.C);
internal static readonly PersonalTable GS = new PersonalTable(Properties.Resources.personal_c, GameVersion.GS);
internal static readonly PersonalTable RBY = new PersonalTable(Properties.Resources.personal_rby, GameVersion.RBY);
private static byte[][] splitBytes(byte[] data, int size)
@ -33,6 +35,8 @@ namespace PKHeX
switch (format)
{
case GameVersion.RBY: size = PersonalInfoG1.SIZE; break;
case GameVersion.GS:
case GameVersion.C: size = PersonalInfoG2.SIZE; break;
case GameVersion.RS:
case GameVersion.E:
case GameVersion.FR:
@ -58,6 +62,11 @@ namespace PKHeX
for (int i = 0; i < d.Length; i++)
d[i] = new PersonalInfoG1(entries[i]);
break;
case GameVersion.GS:
case GameVersion.C:
for (int i = 0; i < d.Length; i++)
d[i] = new PersonalInfoG2(entries[i]);
break;
case GameVersion.RS:
case GameVersion.E:
case GameVersion.FR:

View file

@ -15495,6 +15495,16 @@ namespace PKHeX.Properties {
}
}
/// <summary>
/// Looks up a localized resource of type System.Byte[].
/// </summary>
internal static byte[] personal_c {
get {
object obj = ResourceManager.GetObject("personal_c", resourceCulture);
return ((byte[])(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Byte[].
/// </summary>
@ -15525,6 +15535,16 @@ namespace PKHeX.Properties {
}
}
/// <summary>
/// Looks up a localized resource of type System.Byte[].
/// </summary>
internal static byte[] personal_gs {
get {
object obj = ResourceManager.GetObject("personal_gs", resourceCulture);
return ((byte[])(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Byte[].
/// </summary>
@ -25209,6 +25229,60 @@ namespace PKHeX.Properties {
}
}
/// <summary>
/// Looks up a localized string similar to (None)
///Master Ball
///Ultra Ball
///BrightPowder
///Great Ball
///Poké Ball
///Teru-sama (0)
///Bicycle
///Moon Stone
///Antidote
///Burn Heal
///Ice Heal
///Awakening
///Parlyz Heal
///Full Restore
///Max Potion
///Hyper Potion
///Super Potion
///Potion
///Escape Rope
///Repel
///Max Elixer
///Fire Stone
///Thunder Stone
///Water Stone
///Teru-sama (1)
///HP Up
///Protein
///Iron
///Carbos
///Lucky Punch
///Calcium
///Rare Candy
///X Accuracy
///Leaf Stone
///Metal Powder
///Nugget
///Poké Doll
///Full Heal
///Revive
///Max Revive
///Guard Spec.
///Super Repel
///Max Repel
///Dire Hit
///Ter [rest of string was truncated]&quot;;.
/// </summary>
internal static string text_ItemsG2_en {
get {
return ResourceManager.GetString("text_ItemsG2_en", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to (None)
///Master Ball

View file

@ -6403,4 +6403,13 @@
<data name="text_ItemsG1_en" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\text\gen3\text_ItemsG1_en.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-16</value>
</data>
<data name="personal_c" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\resources\byte\personal_c;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="personal_gs" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\resources\byte\personal_gs;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="text_ItemsG2_en" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\resources\text\gen3\text_itemsg2_en.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
</data>
</root>

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1,255 @@
(None)
Master Ball
Ultra Ball
BrightPowder
Great Ball
Poké Ball
Teru-sama (0)
Bicycle
Moon Stone
Antidote
Burn Heal
Ice Heal
Awakening
Parlyz Heal
Full Restore
Max Potion
Hyper Potion
Super Potion
Potion
Escape Rope
Repel
Max Elixer
Fire Stone
Thunder Stone
Water Stone
Teru-sama (1)
HP Up
Protein
Iron
Carbos
Lucky Punch
Calcium
Rare Candy
X Accuracy
Leaf Stone
Metal Powder
Nugget
Poké Doll
Full Heal
Revive
Max Revive
Guard Spec.
Super Repel
Max Repel
Dire Hit
Teru-sama (2)
Fresh Water
Soda Pop
Lemonade
X Attack
Teru-sama (3)
X Defend
X Speed
X Special
Coin Case
Itemfinder
Teru-sama (4)
Exp Share
Old Rod
Good Rod
Silver Leaf
Super Rod
PP Up
Ether
Max Ether
Elixer
Red Scale
SecretPotion
S.S. Ticket
Mystery Egg
Clear Bell*
Silver Wing
Moomoo Milk
Quick Claw
PSNCureBerry
Gold Leaf
Soft Sand
Sharp Beak
PRZCureBerry
Burnt Berry
Ice Berry
Poison Barb
King's Rock
Bitter Berry
Mint Berry
Red Apricorn
TinyMushroom
Big Mushroom
SilverPowder
Blu Apricorn
Teru-sama (5)
Amulet Coin
Ylw Apricorn
Grn Apricorn
Cleanse Tag
Mystic Water
TwistedSpoon
Wht Apricorn
Black Belt
Blk Apricorn
Teru-sama (6)
Pnk Apricorn
BlackGlasses
SlowpokeTail
Pink Bow
Stick
Smoke Ball
NeverMeltIce
Magnet
MiracleBerry
Pearl
Big Pearl
Everstone
Spell Tag
RageCandyBar
GS Ball*
Blue Card*
Miracle Seed
Thick Club
Focus Band
Teru-sama (7)
EnergyPowder
Energy Root
Heal Powder
Revival Herb
Hard Stone
Lucky Egg
Card Key
Machine Part
Egg Ticket*
Lost Item
Stardust
Star Piece
Basement Key
Pass
Teru-sama (8)
Teru-sama (9)
Teru-sama (10)
Charcoal
Berry Juice
Scope Lens
Teru-sama (11)
Teru-sama (12)
Metal Coat
Dragon Fang
Teru-sama (13)
Leftovers
Teru-sama (14)
Teru-sama (15)
Teru-sama (16)
MysteryBerry
Dragon Scale
Berserk Gene
Teru-sama (17)
Teru-sama (18)
Teru-sama (19)
Sacred Ash
Heavy Ball
Flower Mail
Level Ball
Lure Ball
Fast Ball
Teru-sama (20)
Light Ball
Friend Ball
Moon Ball
Love Ball
Normal Box
Gorgeous Box
Sun Stone
Polkadot Bow
Teru-sama (21)
Up-Grade
Berry
Gold Berry
SquirtBottle
Teru-sama (22)
Park Ball
Rainbow Wing
Teru-sama (23)
Brick Piece
Surf Mail
Litebluemail
Portraitmail
Lovely Mail
Eon Mail
Morph Mail
Bluesky Mail
Music Mail
Mirage Mail
Teru-sama (24)
TM01
TM02
TM03
TM04
TM04 (Unused)
TM05
TM06
TM07
TM08
TM09
TM10
TM11
TM12
TM13
TM14
TM15
TM16
TM17
TM18
TM19
TM20
TM21
TM22
TM23
TM24
TM25
TM26
TM27
TM28
TM28 (Unused)
TM29
TM30
TM31
TM32
TM33
TM34
TM35
TM36
TM37
TM38
TM39
TM40
TM41
TM42
TM43
TM44
TM45
TM46
TM47
TM48
TM49
TM50
HM01
HM02
HM03
HM04
HM05
HM06
HM07
HM08 (Unused)
HM09 (Unused)
HM10 (Unused)
HM11 (Unused)
HM12 (Unused)

569
PKHeX/Saves/SAV2.cs Normal file
View file

@ -0,0 +1,569 @@
using System;
using System.Linq;
namespace PKHeX
{
public sealed class SAV2 : SaveFile
{
public override string BAKName => $"{FileName} [{OT} ({Version})" +/* - {LastSavedTime}*/ "].bak";
public override string Filter => "SAV File|*.sav";
public override string Extension => ".sav";
public SAV2(byte[] data = null)
{
Data = data == null ? new byte[SaveUtil.SIZE_G2RAW] : (byte[])data.Clone();
BAK = (byte[])Data.Clone();
Exportable = !Data.SequenceEqual(new byte[Data.Length]);
Version = data == null ? GameVersion.GSC : SaveUtil.getIsG2SAV(Data);
if (Version == GameVersion.Invalid)
return;
Box = Data.Length;
Array.Resize(ref Data, Data.Length + SIZE_RESERVED);
Party = getPartyOffset(0);
Japanese = false;
Personal = Version == GameVersion.GS ? PersonalTable.GS : PersonalTable.C;
OptionsOffset = 0x2000;
Trainer1 = 0x2009;
switch (Version)
{
case GameVersion.GS:
DaylightSavingsOffset = Japanese ? -1 : 0x2037;
TimePlayedOffset = Japanese ? -1 : 0x2053;
PaletteOffset = Japanese ? -1 : 0x206B;
MoneyOffset = Japanese ? -1 : 0x23DB;
JohtoBadgesOffset = Japanese ? -1 : 0xD57C;
CurrentBoxIndexOffset = Japanese ? -1 : 0x2724;
BoxNamesOffset = Japanese ? -1 : 0x2727;
PartyOffset = Japanese ? 0x283E : 0x288A;
PokedexCaughtOffset = Japanese ? -1 : 0x2A4C;
PokedexSeenOffset = Japanese ? -1 : 0x2A6C;
CurrentBoxOffset = Japanese ? -1 : 0x2D6C;
GenderOffset = -1; // No gender in GSC
break;
case GameVersion.C:
DaylightSavingsOffset = Japanese ? -1 : 0x2037;
TimePlayedOffset = Japanese ? -1 : 0x2054;
PaletteOffset = Japanese ? -1 : 0x206A;
MoneyOffset = Japanese ? -1 : 0x23DC;
JohtoBadgesOffset = Japanese ? -1 : 0x23E5;
CurrentBoxIndexOffset = Japanese ? -1 : 0x2700;
BoxNamesOffset = Japanese ? 0x2708 : 0x2703;
PartyOffset = Japanese ? 0x281A : 0x2865;
PokedexCaughtOffset = Japanese ? -1 : 0x2A27;
PokedexSeenOffset = Japanese ? -1 : 0x2A47;
CurrentBoxOffset = 0x2D10;
GenderOffset = Japanese ? -1 : 0x3E3D;
break;
}
LegalItems = new ushort[] { 3, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 46, 47, 48, 49, 51, 52, 53, 57, 60, 62, 63, 64, 65, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 91, 92, 93, 94, 95, 96, 97, 98, 99, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 117, 118, 119, 121, 122, 123, 124, 125, 126, 131, 132, 138, 139, 140, 143, 144, 146, 150, 151, 152, 156, 158, 163, 168, 169, 170, 172, 173, 174, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189 };
LegalBalls = new ushort[] { 1, 2, 4, 5, 157, 159, 160, 161, 164, 165, 166, 167};
HeldItems = new ushort[] {0}.Concat(LegalItems).Concat(LegalBalls).ToArray();
Array.Sort(HeldItems);
// Stash boxes after the save file's end.
byte[] TempBox = new byte[SIZE_STOREDBOX];
for (int i = 0; i < BoxCount; i++)
{
if (i < (Japanese ? 6 : 7))
Array.Copy(Data, 0x4000 + i * (TempBox.Length + 2), TempBox, 0, TempBox.Length);
else
Array.Copy(Data, 0x6000 + (i - (Japanese ? 6 : 7)) * (TempBox.Length + 2), TempBox, 0, TempBox.Length);
PokemonList2 PL2 = new PokemonList2(TempBox, Japanese ? PokemonList2.CapacityType.StoredJP : PokemonList2.CapacityType.Stored, Japanese);
for (int j = 0; j < PL2.Pokemon.Length; j++)
{
if (j < PL2.Count)
{
byte[] pkDat = new PokemonList2(PL2[j]).GetBytes();
pkDat.CopyTo(Data, Data.Length - SIZE_RESERVED + i * SIZE_BOX + j * SIZE_STORED);
}
else
{
byte[] pkDat = new byte[PokemonList2.GetDataLength(PokemonList2.CapacityType.Single, Japanese)];
pkDat.CopyTo(Data, Data.Length - SIZE_RESERVED + i * SIZE_BOX + j * SIZE_STORED);
}
}
}
Array.Copy(Data, CurrentBoxOffset, TempBox, 0, TempBox.Length);
PokemonList2 curBoxPL = new PokemonList2(TempBox, Japanese ? PokemonList2.CapacityType.StoredJP : PokemonList2.CapacityType.Stored, Japanese);
for (int i = 0; i < curBoxPL.Pokemon.Length; i++)
{
if (i < curBoxPL.Count)
{
byte[] pkDat = new PokemonList2(curBoxPL[i]).GetBytes();
pkDat.CopyTo(Data, Data.Length - SIZE_RESERVED + CurrentBox * SIZE_BOX + i * SIZE_STORED);
}
else
{
byte[] pkDat = new byte[PokemonList2.GetDataLength(PokemonList2.CapacityType.Single, Japanese)];
pkDat.CopyTo(Data, Data.Length - SIZE_RESERVED + CurrentBox * SIZE_BOX + i * SIZE_STORED);
}
}
byte[] TempParty = new byte[PokemonList2.GetDataLength(PokemonList2.CapacityType.Party, Japanese)];
Array.Copy(Data, PartyOffset, TempParty, 0, TempParty.Length);
PokemonList2 partyList = new PokemonList2(TempParty, PokemonList2.CapacityType.Party, Japanese);
for (int i = 0; i < partyList.Pokemon.Length; i++)
{
if (i < partyList.Count)
{
byte[] pkDat = new PokemonList2(partyList[i]).GetBytes();
pkDat.CopyTo(Data, getPartyOffset(i));
}
else
{
byte[] pkDat = new byte[PokemonList2.GetDataLength(PokemonList2.CapacityType.Single, Japanese)];
pkDat.CopyTo(Data, getPartyOffset(i));
}
}
/*
byte[] rawDC = new byte[0x38];
Array.Copy(Data, Japanese ? 0x2CA7 : 0x2CF4, rawDC, 0, rawDC.Length);
byte[] TempDaycare = new byte[PokemonList1.GetDataLength(PokemonList1.CapacityType.Single, Japanese)];
TempDaycare[0] = rawDC[0];
Array.Copy(rawDC, 1, TempDaycare, 2 + 1 + PKX.SIZE_1PARTY + StringLength, StringLength);
Array.Copy(rawDC, 1 + StringLength, TempDaycare, 2 + 1 + PKX.SIZE_1PARTY, StringLength);
Array.Copy(rawDC, 1 + 2 * StringLength, TempDaycare, 2 + 1, PKX.SIZE_1STORED);
PokemonList1 daycareList = new PokemonList1(TempDaycare, PokemonList1.CapacityType.Single, Japanese);
daycareList.GetBytes().CopyTo(Data, getPartyOffset(7));
Daycare = getPartyOffset(7);
*/
// Enable Pokedex editing
Console.WriteLine(SIZE_STOREDBOX.ToString("X"));
PokeDex = 0;
if (!Exportable)
resetBoxes();
}
private const int SIZE_RESERVED = 0x8000; // unpacked box data
public override byte[] Write(bool DSV)
{
for (int i = 0; i < BoxCount; i++)
{
PokemonList1 boxPL = new PokemonList1(Japanese ? PokemonList1.CapacityType.StoredJP : PokemonList1.CapacityType.Stored, Japanese);
int slot = 0;
for (int j = 0; j < boxPL.Pokemon.Length; j++)
{
PK1 boxPK = (PK1) getPKM(getData(getBoxOffset(i) + j*SIZE_STORED, SIZE_STORED));
if (boxPK.Species > 0)
boxPL[slot++] = boxPK;
}
if (i < BoxCount / 2)
boxPL.GetBytes().CopyTo(Data, 0x4000 + i * SIZE_STOREDBOX);
else
boxPL.GetBytes().CopyTo(Data, 0x6000 + (i - BoxCount / 2) * SIZE_STOREDBOX);
if (i == CurrentBox)
boxPL.GetBytes().CopyTo(Data, Japanese ? 0x302D : 0x30C0);
}
PokemonList1 partyPL = new PokemonList1(PokemonList1.CapacityType.Party, Japanese);
int pSlot = 0;
for (int i = 0; i < 6; i++)
{
PK1 partyPK = (PK1)getPKM(getData(getPartyOffset(i), SIZE_STORED));
if (partyPK.Species > 0)
partyPL[pSlot++] = partyPK;
}
partyPL.GetBytes().CopyTo(Data, Japanese ? 0x2ED5 : 0x2F2C);
// Daycare is read-only, but in case it ever becomes editable, copy it back in.
byte[] rawDC = getData(getDaycareSlotOffset(loc: 0, slot: 0), SIZE_STORED);
byte[] dc = new byte[1 + 2*StringLength + PKX.SIZE_1STORED];
dc[0] = rawDC[0];
Array.Copy(rawDC, 2 + 1 + PKX.SIZE_1PARTY + StringLength, dc, 1, StringLength);
Array.Copy(rawDC, 2 + 1 + PKX.SIZE_1PARTY, dc, 1 + StringLength, StringLength);
Array.Copy(rawDC, 2 + 1, dc, 1 + 2*StringLength, PKX.SIZE_1STORED);
dc.CopyTo(Data, Japanese ? 0x2CA7 : 0x2CF4);
setChecksums();
byte[] outData = new byte[Data.Length - SIZE_RESERVED];
Array.Copy(Data, outData, outData.Length);
return outData;
}
// Configuration
public override SaveFile Clone() { return new SAV2(Data.Take(Data.Length - SIZE_RESERVED).ToArray()); }
public override int SIZE_STORED => Japanese ? PKX.SIZE_2JLIST : PKX.SIZE_2ULIST;
public override int SIZE_PARTY => Japanese ? PKX.SIZE_2JLIST : PKX.SIZE_2ULIST;
public int SIZE_BOX => BoxSlotCount*SIZE_STORED;
public int SIZE_STOREDBOX => PokemonList2.GetDataLength(Japanese ? PokemonList2.CapacityType.StoredJP : PokemonList2.CapacityType.Stored, Japanese);
public override PKM BlankPKM => new PK2(null, null, Japanese);
protected override Type PKMType => typeof(PK2);
public override int MaxMoveID => 251;
public override int MaxSpeciesID => 251;
public override int MaxAbilityID => 0;
public override int MaxItemID => 255;
public override int MaxBallID => 0;
public override int MaxGameID => 99; // What do I set this to...?
public override int BoxCount => Japanese ? 9 : 14;
public override int MaxEV => 65535;
public override int MaxIV => 15;
public override int Generation => 2;
protected override int GiftCountMax => 0;
public override int OTLength => Japanese ? 5 : 7;
public override int NickLength => Japanese ? 5 : 10;
public override int BoxSlotCount => Japanese ? 30 : 20;
public override bool HasParty => true;
private int StringLength => Japanese ? PK2.STRLEN_J : PK2.STRLEN_U;
// Offsets
protected int OptionsOffset { get; set; } = int.MinValue;
protected int DaylightSavingsOffset { get; set; } = int.MinValue;
protected int TimePlayedOffset { get; set; } = int.MinValue;
protected int PaletteOffset { get; set; } = int.MinValue;
protected int MoneyOffset { get; set; } = int.MinValue;
protected int JohtoBadgesOffset { get; set; } = int.MinValue;
protected int CurrentBoxIndexOffset { get; set; } = int.MinValue;
protected int BoxNamesOffset { get; set; } = int.MinValue;
protected int PartyOffset { get; set; } = int.MinValue;
protected int PokedexSeenOffset { get; set; } = int.MinValue;
protected int PokedexCaughtOffset { get; set; } = int.MinValue;
protected int CurrentBoxOffset { get; set; } = int.MinValue;
protected int GenderOffset { get; set; } = int.MinValue;
// Checksums
protected override void setChecksums()
{
ushort accum = 0;
for (int i = 0x2009; i <= 0x2B3A; i++)
accum += Data[i];
if (Version == GameVersion.C && Japanese)
BitConverter.GetBytes(Util.SwapEndianness(accum)).CopyTo(Data, 0x2D0D);
for (int i = 0x2B3B; i <= 0x2B82; i++)
accum += Data[i];
if (Version == GameVersion.C && !Japanese)
BitConverter.GetBytes(Util.SwapEndianness(accum)).CopyTo(Data, 0x2D0D);
/* TODO: Find Japanese GS Checksum region */
for (int i = 0x2B83; i <= 0x2D68; i++)
accum += Data[i];
if (Version == GameVersion.GS && !Japanese)
BitConverter.GetBytes(Util.SwapEndianness(accum)).CopyTo(Data, 0x2D69);
}
public override bool ChecksumsValid
{
get
{
ushort accum = 0;
for (int i = 0x2009; i <= 0x2B3A; i++)
accum += Data[i];
if (Version == GameVersion.C && Japanese)
return accum == Util.SwapEndianness(BitConverter.ToUInt16(Data, 0x2D0D)); // Japanese Crystal
for (int i = 0x2B3B; i <= 0x2B82; i++)
accum += Data[i];
if (Version == GameVersion.C && !Japanese)
return accum == Util.SwapEndianness(BitConverter.ToUInt16(Data, 0x2D0D)); // Japanese Crystal
/* TODO: Find Japanese GS Checksum region */
for (int i = 0x2B83; i <= 0x2D68; i++)
accum += Data[i];
if (Version == GameVersion.GS && !Japanese)
return accum == Util.SwapEndianness(BitConverter.ToUInt16(Data, 0x2D69)); // US Gold/Silver
return false;
}
}
public override string ChecksumInfo => ChecksumsValid ? "Checksum valid." : "Checksum invalid";
// Trainer Info
public override GameVersion Version { get; protected set; }
public override string OT
{
get { return PKX.getG1Str(Data.Skip(0x200B).Take(StringLength).ToArray(), Japanese); }
set
{
byte[] strdata = PKX.setG1Str(value, Japanese);
if (strdata.Length > StringLength)
throw new ArgumentException("OT Name too long for given save file.");
strdata.CopyTo(Data, 0x200B);
}
}
public override int Gender
{
get { return 0; }
set { }
}
public override ushort TID
{
get { return Util.SwapEndianness(BitConverter.ToUInt16(Data, 0x2009)); }
set { BitConverter.GetBytes(Util.SwapEndianness(value)).CopyTo(Data, 0x2009); }
}
public override ushort SID
{
get { return 0; }
set { }
}
public override int PlayedHours
{
get { return BitConverter.ToUInt16(Data, Japanese ? 0x2CA0 : 0x2CED); }
set { BitConverter.GetBytes((ushort)value).CopyTo(Data, Japanese ? 0x2CA0 : 0x2CED); }
}
public override int PlayedMinutes
{
get { return Data[Japanese ? 0x2CA2 : 0x2CEF]; }
set { Data[Japanese ? 0x2CA2 : 0x2CEF] = (byte)value; }
}
public override int PlayedSeconds
{
get { return Data[Japanese ? 0x2CA3 : 0x2CF0]; }
set { Data[Japanese ? 0x2CA3 : 0x2CF0] = (byte)value; }
}
public int Badges
{
get { return Data[Japanese ? 0x25F8 : 0x2602]; }
set { if (value < 0) return; Data[Japanese ? 0x25F8 : 0x2602] = (byte)value; }
}
private byte Options
{
get { return Data[Japanese ? 0x25F7 : 0x2601]; }
set { Data[Japanese ? 0x25F7 : 0x2601] = value; }
}
public bool BattleEffects
{
get { return (Options & 0x80) == 0; }
set { Options = (byte)((Options & 0x7F) | (value ? 0 : 0x80)); }
}
public bool BattleStyleSwitch
{
get { return (Options & 0x40) == 0; }
set { Options = (byte)((Options & 0xBF) | (value ? 0 : 0x40)); }
}
public int Sound
{
get { return (Options & 0x30) >> 4; }
set
{
var new_sound = value;
if (new_sound > 3)
new_sound = 3;
if (new_sound < 0)
new_sound = 0;
Options = (byte)((Options & 0xCF) | (new_sound << 4));
}
}
public int TextSpeed
{
get { return Options & 0x7; }
set
{
var new_speed = value;
if (new_speed > 7)
new_speed = 7;
if (new_speed < 0)
new_speed = 0;
Options = (byte)((Options & 0xF8) | new_speed);
}
}
public override uint Money
{
get { return uint.Parse((Util.SwapEndianness(BitConverter.ToUInt32(Data, Japanese ? 0x25EE : 0x25F3)) >> 8).ToString("X6")); }
set
{
BitConverter.GetBytes(Util.SwapEndianness(Convert.ToUInt32(value.ToString("000000"), 16))).Skip(1).ToArray().CopyTo(Data, Japanese ? 0x25EE : 0x25F3);
}
}
public uint Coin
{
get
{
return uint.Parse(Util.SwapEndianness(BitConverter.ToUInt16(Data, Japanese ? 0x2846 : 0x2850)).ToString("X4"));
}
set
{
BitConverter.GetBytes(Util.SwapEndianness(Convert.ToUInt16(value.ToString("0000"), 16))).ToArray().CopyTo(Data, Japanese ? 0x2846 : 0x2850);
}
}
private readonly ushort[] LegalItems, LegalKeyItems, LegalBalls, LegalTMHMs, LegalBerries;
public override InventoryPouch[] Inventory
{
get
{
ushort[] legalItems = LegalItems;
InventoryPouch[] pouch =
{
new InventoryPouch(InventoryType.Items, legalItems, 99, Japanese ? 0x25C4 : 0x25C9, 20),
new InventoryPouch(InventoryType.MailItems, legalItems, 99, Japanese ? 0x27DC : 0x27E6, 50)
};
foreach (var p in pouch)
{
p.getPouchG1(ref Data);
}
return pouch;
}
set
{
foreach (var p in value)
{
int ofs = 0;
for (int i = 0; i < p.Count; i++)
{
while (p.Items[ofs].Count == 0)
ofs++;
p.Items[i] = p.Items[ofs++];
}
while (ofs < p.Items.Length)
p.Items[ofs++] = new InventoryItem { Count = 0, Index = 0 };
p.setPouchG1(ref Data);
}
}
}
public override int getDaycareSlotOffset(int loc, int slot)
{
return Daycare;
}
public override ulong? getDaycareRNGSeed(int loc)
{
return null;
}
public override uint? getDaycareEXP(int loc, int slot)
{
return null;
}
public override bool? getDaycareOccupied(int loc, int slot)
{
return null;
}
public override void setDaycareEXP(int loc, int slot, uint EXP)
{
}
public override void setDaycareOccupied(int loc, int slot, bool occupied)
{
}
// Storage
public override int PartyCount
{
get { return Data[PartyOffset]; }
protected set
{
Data[PartyOffset] = (byte)value;
}
}
public override int getBoxOffset(int box)
{
return Data.Length - SIZE_RESERVED + box * SIZE_BOX;
}
public override int getPartyOffset(int slot)
{
return Data.Length - SIZE_RESERVED + BoxCount * SIZE_BOX + slot * SIZE_STORED;
}
public override int CurrentBox
{
get { return Data[CurrentBoxIndexOffset] & 0x7F; }
set { Data[CurrentBoxIndexOffset] = (byte)((Data[Japanese ? 0x2842 : 0x284C] & 0x80) | (value & 0x7F)); }
}
public override int getBoxWallpaper(int box)
{
return 0;
}
public override string getBoxName(int box)
{
return PKX.getG1Str(Data.Skip(BoxNamesOffset + box*9).Take(9).ToArray(), Japanese);
}
public override void setBoxName(int box, string value)
{
// Don't allow for custom box names
}
public override PKM getPKM(byte[] data)
{
if (data.Length == SIZE_STORED)
return new PokemonList2(data, PokemonList2.CapacityType.Single, Japanese)[0];
return new PK2(data);
}
public override byte[] decryptPKM(byte[] data)
{
return data;
}
// Pokédex
public override bool getSeen(PKM pkm)
{
if (pkm.Species == 0)
return false;
if (pkm.Species > MaxSpeciesID)
return false;
if (Version == GameVersion.Unknown)
return false;
int bit = pkm.Species - 1;
int ofs = bit >> 3;
byte bitval = (byte)(1 << (bit & 7));
// Get the Seen Flag
return (Data[PokedexSeenOffset + ofs] & bitval) != 0;
}
public override bool getCaught(PKM pkm)
{
if (pkm.Species == 0)
return false;
if (pkm.Species > MaxSpeciesID)
return false;
if (Version == GameVersion.Unknown)
return false;
int bit = pkm.Species - 1;
int ofs = bit >> 3;
byte bitval = (byte)(1 << (bit & 7));
// Get the Caught Flag
return (Data[PokedexCaughtOffset + ofs] & bitval) != 0;
}
protected internal override void setSeen(PKM pkm, bool seen = true)
{
if (pkm.Species == 0)
return;
if (pkm.Species > MaxSpeciesID)
return;
if (Version == GameVersion.Unknown)
return;
int bit = pkm.Species - 1;
int ofs = bit >> 3;
byte bitval = (byte)(1 << (bit & 7));
// Set the Seen Flag
Data[PokedexSeenOffset + ofs] &= (byte)(~bitval);
if (seen)
Data[PokedexSeenOffset + ofs] |= bitval;
}
protected internal override void setCaught(PKM pkm, bool caught = true)
{
if (pkm.Species == 0)
return;
if (pkm.Species > MaxSpeciesID)
return;
if (Version == GameVersion.Unknown)
return;
int bit = pkm.Species - 1;
int ofs = bit >> 3;
byte bitval = (byte)(1 << (bit & 7));
// Set the Captured Flag
Data[PokedexCaughtOffset + ofs] &= (byte)(~bitval);
if (caught)
Data[PokedexCaughtOffset + ofs] |= bitval;
}
}
}

View file

@ -63,6 +63,8 @@ namespace PKHeX
public bool RS => Version == GameVersion.RS;
public bool RBY => Version == GameVersion.RBY;
public bool GSC => Version == GameVersion.GS || Version == GameVersion.C;
public virtual int MaxMoveID => int.MaxValue;
public virtual int MaxSpeciesID => int.MaxValue;
public virtual int MaxAbilityID => int.MaxValue;

View file

@ -3,11 +3,15 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace PKHeX
{
public enum GameVersion
{
/* I don't want to assign Gen I/II... */
GS = -4,
C = -3,
Invalid = -2,
Any = -1,
Unknown = 0,
@ -45,6 +49,10 @@ namespace PKHeX
internal const int SIZE_G4RAW = 0x80000;
internal const int SIZE_G3RAW = 0x20000;
internal const int SIZE_G3RAWHALF = 0x10000;
internal const int SIZE_G2RAW = 0x8000;
internal const int SIZE_G2BAT = 0x802C;
internal const int SIZE_G2EMU = 0x10000;
internal const int SIZE_G2EMUBAT = 0x1002C;
internal const int SIZE_G1RAW = 0x8000;
internal const int SIZE_G1BAT = 0x802C;
@ -57,6 +65,8 @@ namespace PKHeX
{
if (getIsG1SAV(data) != GameVersion.Invalid)
return 1;
if (getIsG2SAV(data) != GameVersion.Invalid)
return 2;
if (getIsG3SAV(data) != GameVersion.Invalid)
return 3;
if (getIsG4SAV(data) != GameVersion.Invalid)
@ -108,6 +118,71 @@ namespace PKHeX
}
return true;
}
/// <summary>Determines the type of 2nd gen save</summary>
/// <param name="data">Save data of which to determine the type</param>
/// <returns>Version Identifier or Invalid if type cannot be determined.</returns>
public static GameVersion getIsG2SAV(byte[] data)
{
if (data.Length != SIZE_G2RAW && data.Length != SIZE_G2BAT && data.Length != SIZE_G2EMU && data.Length != SIZE_G2EMUBAT)
return GameVersion.Invalid;
// Check if it's not an american save or a japanese save
if (getIsG2SAVU(data) != GameVersion.Invalid)
return getIsG2SAVU(data);
if (getIsG2SAVJ(data) != GameVersion.Invalid)
return getIsG2SAVJ(data);
return GameVersion.Invalid;
}
/// <summary>Determines if 2nd gen save is non-japanese</summary>
/// <param name="data">Save data of which to determine the region</param>
/// <returns>True if a valid non-japanese save, False otherwise.</returns>
public static GameVersion getIsG2SAVU(byte[] data)
{
bool gs = true;
bool c = true;
foreach (int ofs in new[] { 0x288A, 0x2D6C })
{
byte num_entries = data[ofs];
if (num_entries > 20 || data[ofs + 1 + num_entries] != 0xFF)
gs = false;
}
foreach (int ofs in new[] { 0x2865, 0x2D10 })
{
byte num_entries = data[ofs];
if (num_entries > 20 || data[ofs + 1 + num_entries] != 0xFF)
c = false;
}
if (gs)
return GameVersion.GS;
if (c)
return GameVersion.C;
return GameVersion.Invalid;
}
/// <summary>Determines if 2nd gen save is japanese</summary>
/// <param name="data">Save data of which to determine the region</param>
/// <returns>True if a valid japanese save, False otherwise.</returns>
public static GameVersion getIsG2SAVJ(byte[] data)
{
bool gs = true;
bool c = true;
foreach (int ofs in new[] { 0x283E, 0x2D10 })
{
byte num_entries = data[ofs];
if (num_entries > 30 || data[ofs + 1 + num_entries] != 0xFF)
gs = false;
}
foreach (int ofs in new[] { 0x281A, 0x2D10 })
{
byte num_entries = data[ofs];
if (num_entries > 30 || data[ofs + 1 + num_entries] != 0xFF)
c = false;
}
if (gs)
return GameVersion.GS;
if (c)
return GameVersion.C;
return GameVersion.Invalid;
}
/// <summary>Determines the type of 3th gen save</summary>
/// <param name="data">Save data of which to determine the type</param>
/// <returns>Version Identifier or Invalid if type cannot be determined.</returns>
@ -218,6 +293,10 @@ namespace PKHeX
case GameVersion.RBY:
return GameVersion.RBY;
case GameVersion.GS:
case GameVersion.C:
return GameVersion.GSC;
case GameVersion.R:
case GameVersion.S:
return GameVersion.RS;
@ -270,6 +349,8 @@ namespace PKHeX
{
case 1:
return new SAV1(data);
case 2:
return new SAV2(data);
case 3:
return new SAV3(data);
case 4: