Initial support for Scarlet & Violet

This commit is contained in:
Manu 2022-11-17 12:58:07 +01:00
parent ed6f28be1e
commit 3da864fa1d
10 changed files with 339 additions and 36 deletions

View File

@ -26,12 +26,6 @@ namespace SwitchGiftDataManager.CommandLine
Console.ReadKey();
return;
}
else if (game is Games.SCVI)
{
Log("Scarlet and Violet are still not supported by this program. Please wait patiently.");
Console.ReadKey();
return;
}
var bcat = new BCATManager(game);

View File

@ -1,4 +1,5 @@
using System.Buffers.Binary;
using System.Reflection.Metadata.Ecma335;
using Enums;
namespace SwitchGiftDataManager.Core
@ -30,7 +31,7 @@ namespace SwitchGiftDataManager.Core
Games.SWSH => new WC8(data),
Games.BDSP => new WB8(data),
Games.PLA => new WA8(data),
//Games.SCVI => new WC9(data),
Games.SCVI => new WC9(data),
_ => throw new ArgumentOutOfRangeException(),
};
}
@ -119,10 +120,8 @@ namespace SwitchGiftDataManager.Core
return Games.SWSH;
else if (data.Length % (int)Wondercard.GetSize(Games.BDSP) == 0)
return Games.BDSP;
else if (data.Length % (int)Wondercard.GetSize(Games.PLA) == 0)
return Games.PLA;
else if (data.Length % (int)Wondercard.GetSize(Games.SCVI) == 0)
return Games.SCVI;
return data[Wondercard.GenOffset] != 0 ? Games.PLA : Games.SCVI;
else
return Games.None;
}
@ -147,6 +146,8 @@ namespace SwitchGiftDataManager.Core
var el3 = "";
var el4 = "";
var el5 = "";
var el6 = "";
var el7 = "";
if (WCList is not null && WCList.Count > 0 && WCList.Count >= index)
{
@ -179,11 +180,15 @@ namespace SwitchGiftDataManager.Core
el4 = str;
else if (el5.Equals(""))
el5 = str;
else if (el6.Equals(""))
el6 = str;
else if (el7.Equals(""))
el7 = str;
}
}
}
return new List<string> { wcid, el1, el2, el3, el4, el5 };
return new List<string> { wcid, el1, el2, el3, el4, el5, el6, el7 };
}
public List<ushort>? GetDuplicatedWCID()
@ -211,6 +216,7 @@ namespace SwitchGiftDataManager.Core
Games.SWSH => "normal",
Games.BDSP => "99",
Games.PLA => "normal",
Games.SCVI => "normal",
_ => throw new ArgumentOutOfRangeException(),
};
}
@ -223,6 +229,7 @@ namespace SwitchGiftDataManager.Core
Games.SWSH => "distribution_internet",
Games.BDSP => "99",
Games.PLA => "distribution_internet",
Games.SCVI => "distribution_internet",
_ => throw new ArgumentOutOfRangeException(),
};
}

View File

@ -83,6 +83,21 @@ namespace SwitchGiftDataManager.Core
else
str = ((GiftType8A)type).ToString();
}
else if (type.GetType() == typeof(GiftType9))
{
if ((GiftType9)type is GiftType9.Item)
str = Properties.Resources.Items.Split(new String[] { Environment.NewLine }, StringSplitOptions.None)[id];
else if ((GiftType9)type is GiftType9.Clothing)
{
var category = (ClothingType8A)id;
var description = ""; //TODO
if (string.IsNullOrWhiteSpace(description))
description = $"{opt:X4}";
str = $"[{category}] {description}";
}
else
str = ((GiftType8A)type).ToString();
}
return str;
}

View File

@ -0,0 +1,128 @@
using System.Buffers.Binary;
using Enums;
namespace SwitchGiftDataManager.Core
{
internal class WC9 : Wondercard
{
private const int WondercardIDOffset = 0x08;
private const int GiftTypeOffset = 0x11;
private const int ItemOffset = 0x18;
private const int QuantityOffset = 0x1A;
private const int ClothingOffset = 0x1C;
private const int TIDOffset = 0x18;
private const int SIDOffset = 0x1A;
private const int PIDOffset = 0x24;
private const int SpeciesOffset = 0x238;
private const int ShinyTypeOffset = 0x240;
private const int ChecksumOffset = 0x2C4;
public WC9(ReadOnlySpan<byte> data) : base(data)
{
WCID = BinaryPrimitives.ReadUInt16LittleEndian(data[WondercardIDOffset..]);
Type = (GiftType9)Data![GiftTypeOffset];
Content = Type switch
{
GiftType9.Pokemon => GetPokemon(),
_ => GetItems(),
};
}
private PokemonGift GetPokemon()
{
var species = BinaryPrimitives.ReadUInt16LittleEndian(Data.AsSpan(SpeciesOffset));
var pid = BinaryPrimitives.ReadUInt32LittleEndian(Data.AsSpan(PIDOffset));
var tid = BinaryPrimitives.ReadUInt16LittleEndian(Data.AsSpan(TIDOffset));
var sid = BinaryPrimitives.ReadUInt16LittleEndian(Data.AsSpan(SIDOffset));
var test = (ShinyType9)Data![ShinyTypeOffset];
var pidtype = (ShinyType9)Data![ShinyTypeOffset] switch
{
ShinyType9.Fixed => PIDType.FixedPID,
_ => PIDType.RandomPID,
};
var shinytype = (ShinyType9)Data![ShinyTypeOffset] switch
{
ShinyType9.Fixed => PokemonGift.IsShiny(pid, tid, sid) ? ShinyType.ShinyForced :
PokemonGift.IsTIDAbusePossible(tid, sid, pidtype) ? ShinyType.ShinyTIDAbuse : ShinyType.ShinyLocked,
ShinyType9.ShinyLocked => ShinyType.ShinyLocked,
ShinyType9.Shiny => ShinyType.ShinyForced,
ShinyType9.ShinyRandom => ShinyType.ShinyPossible,
ShinyType9.ShinyHighOdds => ShinyType.ShinyHighOdds,
_ => throw new ArgumentOutOfRangeException(),
};
return new PokemonGift
{
Species = species,
PID = pid,
TID = tid,
SID = sid,
ShinyType = shinytype,
PIDType = pidtype,
};
}
private List<OtherGift> GetItems()
{
List<OtherGift> items = new();
for (int i = 0; i < MaxItemCount; i++)
{
ushort item = 0;
ushort quantity = 0;
ushort opt = 0;
var type = (GiftType9)Type!;
if (type is GiftType9.Clothing)
{
item = BinaryPrimitives.ReadUInt16LittleEndian(Data.AsSpan(ItemOffset + (0x08 * i)));
opt = BinaryPrimitives.ReadUInt16LittleEndian(Data.AsSpan(ClothingOffset + (0x08 * i)));
}
else
{
item = BinaryPrimitives.ReadUInt16LittleEndian(Data.AsSpan(ItemOffset + (0x04 * i)));
quantity = BinaryPrimitives.ReadUInt16LittleEndian(Data.AsSpan(QuantityOffset + (0x04 * i)));
}
var gift = new OtherGift
{
Type = type,
Item = item,
Quantity = quantity,
Opt = opt,
};
if ((type is not GiftType9.Clothing && gift.Item != 0x00) || (type is GiftType9.Clothing && opt != 0xFFFF))
items.Add(gift);
}
return items;
}
public override bool IsChecksumValid()
{
if (Data is not null)
{
var oldChecksum = BinaryPrimitives.ReadUInt16LittleEndian(Data.AsSpan(ChecksumOffset));
var span = Data.ToArray().AsSpan();
BinaryPrimitives.WriteUInt16LittleEndian(span[ChecksumOffset..], 0x0);
var newchecksum = ChecksumCalculator.CalcCcittFalse(span);
if (oldChecksum == newchecksum)
return true;
}
return false;
}
public override void UpdateChecksum()
{
BinaryPrimitives.WriteUInt16LittleEndian(Data.AsSpan(ChecksumOffset), 0x0);
var checksum = ChecksumCalculator.CalcCcittFalse(Data.AsSpan());
BinaryPrimitives.WriteUInt16LittleEndian(Data.AsSpan(ChecksumOffset), checksum);
}
public override void SetID(ushort wcid)
{
BinaryPrimitives.WriteUInt16LittleEndian(Data.AsSpan(WondercardIDOffset), wcid);
WCID = wcid;
UpdateChecksum();
}
}
}

View File

@ -1,10 +1,12 @@
using Enums;
using System.Buffers.Binary;
namespace SwitchGiftDataManager.Core
{
internal abstract class Wondercard
{
protected const int MaxItemCount = 5;
public static int GenOffset = 0x0F;
protected const int MaxItemCount = 7;
public Games Game { get; }
public ushort WCID { get; protected set; }
@ -19,8 +21,7 @@ namespace SwitchGiftDataManager.Core
WondercardSize.WB7 => Games.LGPE,
WondercardSize.WC8 => Games.SWSH,
WondercardSize.WB8 => Games.BDSP,
WondercardSize.WA8 => Games.PLA,
WondercardSize.WC9 => Games.SCVI,
WondercardSize.WC9 => data[GenOffset] != 0 ? Games.PLA : Games.SCVI,
_ => Games.None,
};
Data = data.ToArray();

View File

@ -21,7 +21,7 @@
WC8 = 0x2D0,
WB8 = 0x2DC,
WA8 = 0x2C8,
WC9 = 0x2D1, //Placeholder
WC9 = 0x2C8,
}
internal enum GiftType7 : byte
@ -61,6 +61,15 @@
Clothing = 3,
}
internal enum GiftType9 : byte
{
None = 0,
Pokemon = 1,
Item = 2,
BP = 3,
Clothing = 4,
}
public enum PIDType
{
RandomPID,
@ -73,6 +82,7 @@
ShinyPossible,
ShinyForced,
ShinyTIDAbuse,
ShinyHighOdds,
}
internal enum ShinyType7 : byte
@ -92,6 +102,15 @@
Fixed = 4,
}
internal enum ShinyType9 : byte
{
Fixed = 0,
ShinyLocked = 1,
Shiny = 2,
ShinyRandom = 3,
ShinyHighOdds = 4,
}
internal enum ClothingType8: byte
{
Glasses = 0x06,

View File

@ -903,4 +903,109 @@ Ursaluna,
Basculegion,
Sneasler,
Overqwil,
Enamorus,
Enamorus,
Sprigatito,
Floragato,
Meowscarada,
Fuecoco,
Crocalor,
Skeledirge,
Quaxly,
Quaxwell,
Quaquaval,
Lechonk,
Oinkologne,
Dudunsparce,
Tarountula,
Spidops,
Nymble,
Lokix,
Rellor,
Rabsca,
Greavard,
Houndstone,
Flittle,
Espathra,
Farigiraf,
Wiglett,
Wugtrio,
Dondozo,
Veluza,
Finizen,
Palafin,
Smoliv,
Dolliv,
Arboliva,
Capsakid,
Scovillain,
Tadbulb,
Bellibolt,
Varoom,
Revavroom,
Orthworm,
Tandemaus,
Maushold,
Cetoddle,
Cetitan,
Frigibax,
Arctibax,
Baxcalibur,
Tatsugiri,
Cyclizar,
Pawmi,
Pawmo,
Pawmot,
Wattrel,
Kilowattrel,
Bombirdier,
Squawkabilly,
Flamigo,
Klawf,
Nacli,
Naclstack,
Garganacl,
Glimmet,
Glimmora,
Shroodle,
Grafaiai,
Fidough,
Dachsbun,
Maschiff,
Mabosstiff,
Bramblin,
Brambleghast,
Gimmighoul,
Gholdengo,
Great Tusk,
Brute Bonnet,
None,
Sandy Shocks,
Scream Tail,
Flutter Mane,
Slither Wing,
Roaring Moon,
Iron Treads,
None,
Iron Moth,
Iron Hands,
Iron Jugulis,
Iron Thorns,
Iron Bundle,
Iron Valiant,
Ting-Lu,
Chien-Pao,
Wo-Chien,
Chi-Yu,
Koraidon,
Miraidon,
Tinkatink,
Tinkatuff,
Tinkaton,
Charcadet,
Armarouge,
Ceruledge,
Toedscool,
Toedscruel,
Kingambit,
Clodsire,
Annihilape,

View File

@ -41,6 +41,8 @@
this.GrpBCAT = new System.Windows.Forms.GroupBox();
this.BtnApply = new System.Windows.Forms.Button();
this.GrpContent = new System.Windows.Forms.GroupBox();
this.LblInfo7 = new System.Windows.Forms.Label();
this.LblInfo6 = new System.Windows.Forms.Label();
this.LblInfo5 = new System.Windows.Forms.Label();
this.LblInfo4 = new System.Windows.Forms.Label();
this.LblInfo3 = new System.Windows.Forms.Label();
@ -147,9 +149,9 @@
" game. ");
this.ListBoxWC.DrawItem += new System.Windows.Forms.DrawItemEventHandler(this.ListBoxWC_DrawItem);
this.ListBoxWC.SelectedIndexChanged += new System.EventHandler(this.ListBoxWC_SelectedIndexChanged);
this.ListBoxWC.DragDrop += new System.Windows.Forms.DragEventHandler(this.FileDragDrop);
this.ListBoxWC.DragEnter += new System.Windows.Forms.DragEventHandler(this.FileDragEnter);
this.ListBoxWC.MouseUp += new System.Windows.Forms.MouseEventHandler(this.ListBoxWC_MouseUp);
this.ListBoxWC.DragEnter += new DragEventHandler(this.FileDragEnter);
this.ListBoxWC.DragDrop += new DragEventHandler(this.FileDragDrop);
//
// BtnOpen
//
@ -192,7 +194,7 @@
// BtnApply
//
this.BtnApply.Enabled = false;
this.BtnApply.Location = new System.Drawing.Point(426, 355);
this.BtnApply.Location = new System.Drawing.Point(426, 368);
this.BtnApply.Name = "BtnApply";
this.BtnApply.Size = new System.Drawing.Size(97, 32);
this.BtnApply.TabIndex = 11;
@ -202,6 +204,8 @@
//
// GrpContent
//
this.GrpContent.Controls.Add(this.LblInfo7);
this.GrpContent.Controls.Add(this.LblInfo6);
this.GrpContent.Controls.Add(this.LblInfo5);
this.GrpContent.Controls.Add(this.LblInfo4);
this.GrpContent.Controls.Add(this.LblInfo3);
@ -210,15 +214,37 @@
this.GrpContent.Enabled = false;
this.GrpContent.Location = new System.Drawing.Point(294, 99);
this.GrpContent.Name = "GrpContent";
this.GrpContent.Size = new System.Drawing.Size(358, 250);
this.GrpContent.Size = new System.Drawing.Size(358, 263);
this.GrpContent.TabIndex = 10;
this.GrpContent.TabStop = false;
this.GrpContent.Text = "Gift Content";
//
// LblInfo7
//
this.LblInfo7.AutoSize = true;
this.LblInfo7.Location = new System.Drawing.Point(158, 230);
this.LblInfo7.Name = "LblInfo7";
this.LblInfo7.Size = new System.Drawing.Size(49, 20);
this.LblInfo7.TabIndex = 6;
this.LblInfo7.Text = "Info_7";
this.LblInfo7.Visible = false;
this.LblInfo7.SizeChanged += new System.EventHandler(this.LblInfo_SizeChanged);
//
// LblInfo6
//
this.LblInfo6.AutoSize = true;
this.LblInfo6.Location = new System.Drawing.Point(158, 198);
this.LblInfo6.Name = "LblInfo6";
this.LblInfo6.Size = new System.Drawing.Size(49, 20);
this.LblInfo6.TabIndex = 5;
this.LblInfo6.Text = "Info_6";
this.LblInfo6.Visible = false;
this.LblInfo6.SizeChanged += new System.EventHandler(this.LblInfo_SizeChanged);
//
// LblInfo5
//
this.LblInfo5.AutoSize = true;
this.LblInfo5.Location = new System.Drawing.Point(152, 188);
this.LblInfo5.Location = new System.Drawing.Point(158, 165);
this.LblInfo5.Name = "LblInfo5";
this.LblInfo5.Size = new System.Drawing.Size(49, 20);
this.LblInfo5.TabIndex = 4;
@ -229,7 +255,7 @@
// LblInfo4
//
this.LblInfo4.AutoSize = true;
this.LblInfo4.Location = new System.Drawing.Point(152, 153);
this.LblInfo4.Location = new System.Drawing.Point(158, 132);
this.LblInfo4.Name = "LblInfo4";
this.LblInfo4.Size = new System.Drawing.Size(49, 20);
this.LblInfo4.TabIndex = 3;
@ -240,7 +266,7 @@
// LblInfo3
//
this.LblInfo3.AutoSize = true;
this.LblInfo3.Location = new System.Drawing.Point(152, 118);
this.LblInfo3.Location = new System.Drawing.Point(158, 99);
this.LblInfo3.Name = "LblInfo3";
this.LblInfo3.Size = new System.Drawing.Size(49, 20);
this.LblInfo3.TabIndex = 2;
@ -251,7 +277,7 @@
// LblInfo2
//
this.LblInfo2.AutoSize = true;
this.LblInfo2.Location = new System.Drawing.Point(152, 83);
this.LblInfo2.Location = new System.Drawing.Point(158, 66);
this.LblInfo2.Name = "LblInfo2";
this.LblInfo2.Size = new System.Drawing.Size(49, 20);
this.LblInfo2.TabIndex = 1;
@ -262,7 +288,7 @@
// LblInfo1
//
this.LblInfo1.AutoSize = true;
this.LblInfo1.Location = new System.Drawing.Point(152, 48);
this.LblInfo1.Location = new System.Drawing.Point(158, 33);
this.LblInfo1.Name = "LblInfo1";
this.LblInfo1.Size = new System.Drawing.Size(49, 20);
this.LblInfo1.TabIndex = 0;
@ -346,14 +372,15 @@
this.MinimizeBox = false;
this.Name = "MainWindow";
this.Text = "Switch Gift Data Manager v1.0.0";
this.DragDrop += new System.Windows.Forms.DragEventHandler(this.FileDragDrop);
this.DragEnter += new System.Windows.Forms.DragEventHandler(this.FileDragEnter);
this.GrpBCAT.ResumeLayout(false);
this.GrpBCAT.PerformLayout();
this.GrpContent.ResumeLayout(false);
this.GrpContent.PerformLayout();
this.ContextMenuStripWC.ResumeLayout(false);
this.ResumeLayout(false);
this.DragEnter += new DragEventHandler(this.FileDragEnter);
this.DragDrop += new DragEventHandler(this.FileDragDrop);
}
#endregion
@ -381,5 +408,7 @@
private OpenFileDialog OpenFileDialogWC;
private ToolStripMenuItem BtnRemoveAll;
private ToolTip ToolTipWcid;
private Label LblInfo7;
private Label LblInfo6;
}
}

View File

@ -164,12 +164,7 @@ namespace SwitchGiftDataManager.WinForm
private void BtnPLA_Click(object sender, EventArgs e) => ChangeGame(Games.PLA);
private void BtnSCVI_Click(object sender, EventArgs e) //=> ChangeGame(Games.SCVI);
{
ChangeGame(Games.SCVI);
GrpBCAT.Enabled = false;
MessageBox.Show("Scarlet and Violet features still not available.");
}
private void BtnSCVI_Click(object sender, EventArgs e) => ChangeGame(Games.SCVI);
private void BtnSave_Click(object sender, EventArgs e)
{
@ -234,14 +229,14 @@ namespace SwitchGiftDataManager.WinForm
void FileDragEnter(object sender, DragEventArgs e)
{
if(e.Data is not null && CurrentGame is not (Games.None or Games.SCVI))
if(e.Data is not null && CurrentGame is not Games.None)
if (e.Data.GetDataPresent(DataFormats.FileDrop))
e.Effect = DragDropEffects.Copy;
}
void FileDragDrop(object sender, DragEventArgs e)
{
if (e.Data is not null && CurrentGame is not (Games.None or Games.SCVI))
if (e.Data is not null && CurrentGame is not Games.None)
{
string[] files = (string[])e.Data.GetData(DataFormats.FileDrop);
LoadLocalFiles(files);
@ -330,6 +325,10 @@ namespace SwitchGiftDataManager.WinForm
LblInfo4.Text = content.ElementAt(4);
if (nItem >= 5)
LblInfo5.Text = content.ElementAt(5);
if (nItem >= 6)
LblInfo6.Text = content.ElementAt(6);
if (nItem >= 7)
LblInfo7.Text = content.ElementAt(7);
TxtWCID.Text = content.ElementAt(0);
EnableContent();
@ -386,6 +385,8 @@ namespace SwitchGiftDataManager.WinForm
LblInfo3.Visible = true;
LblInfo4.Visible = true;
LblInfo5.Visible = true;
LblInfo6.Visible = true;
LblInfo7.Visible = true;
GrpContent.Enabled = true;
}
@ -404,6 +405,10 @@ namespace SwitchGiftDataManager.WinForm
LblInfo4.Visible = false;
LblInfo5.Text = "";
LblInfo5.Visible = false;
LblInfo6.Text = "";
LblInfo6.Visible = false;
LblInfo7.Text = "";
LblInfo7.Visible = false;
GrpContent.Enabled = false;
BtnApply.Enabled = false;
}

View File

@ -171,7 +171,6 @@
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "SaveWindow";
this.ShowInTaskbar = false;
this.StartPosition = System.Windows.Forms.FormStartPosition.Manual;
this.Text = "Save BCAT Package";
this.GrpBuild.ResumeLayout(false);
@ -181,6 +180,7 @@
this.groupBox2.ResumeLayout(false);
this.groupBox2.PerformLayout();
this.ResumeLayout(false);
}
#endregion