PKHeX/Subforms/Save Editors/SAV_Wondercard.cs
Kaphotics cd5ed794bc Mystery Gift editor updates
Prevent popup of "USED" prompt when opening the form.
Allow QR's for all generations (won't work for injection, just for
sharing).
Remove ".wc6" from Import/Export buttons (translation file).
Importing gift from QR now type checks.
2016-07-24 15:44:44 -07:00

470 lines
No EOL
18 KiB
C#

using System;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Windows.Forms;
namespace PKHeX
{
public partial class SAV_Wondercard : Form
{
public SAV_Wondercard(MysteryGift g = null)
{
InitializeComponent();
Util.TranslateInterface(this, Main.curlanguage);
mga = Main.SAV.GiftAlbum;
pba = new[]
{
PB_Card01, PB_Card02, PB_Card03, PB_Card04, PB_Card05, PB_Card06,
PB_Card07, PB_Card08, PB_Card09, PB_Card10, PB_Card11, PB_Card12,
PB_Card13, PB_Card14, PB_Card15, PB_Card16, PB_Card17, PB_Card18,
PB_Card19, PB_Card20, PB_Card21, PB_Card22, PB_Card23, PB_Card24,
};
foreach (PictureBox pb in pba)
{
pb.AllowDrop = true;
// The PictureBoxes have their own drag&drop event handlers.
}
// Hide slots not present on game
for (int i = mga.Gifts.Length; i < pba.Length; i++)
pba[i].Visible = false;
if (mga.Gifts.Length < 7)
L_r2.Visible = false;
if (mga.Gifts.Length < 13)
L_r3.Visible = false;
if (mga.Gifts.Length < 19)
L_r4.Visible = false;
if (SAV.Generation == 4) // pgt & pcd, split up
{
PB_Card09.Location = PB_Card19.Location;
PB_Card10.Location = PB_Card20.Location;
PB_Card11.Location = PB_Card21.Location;
L_r4.Visible = true;
L_r1.Text = "PGT 1-6";
L_r2.Text = "PGT 7-8";
L_r4.Text = "PCD 1-3";
}
setGiftBoxes();
getReceivedFlags();
if (LB_Received.Items.Count > 0)
LB_Received.SelectedIndex = 0;
DragEnter += tabMain_DragEnter;
DragDrop += tabMain_DragDrop;
if (g == null)
clickView(PB_Card01, null);
else
viewGiftData(g);
}
private readonly SaveFile SAV = Main.SAV.Clone();
private MysteryGiftAlbum mga;
private MysteryGift mg;
private readonly PictureBox[] pba;
// Repopulation Functions
private void setBackground(int index, Image bg)
{
for (int i = 0; i < mga.Gifts.Length; i++)
pba[i].BackgroundImage = index == i ? bg : null;
}
private void setGiftBoxes()
{
for (int i = 0; i < mga.Gifts.Length; i++)
{
MysteryGift m = mga.Gifts[i];
pba[i].Image = m.Empty ? null : getSprite(m);
}
}
private void viewGiftData(MysteryGift g)
{
try
{
// only check if the form is visible (not opening)
if (Visible && g.GiftUsed && DialogResult.Yes ==
Util.Prompt(MessageBoxButtons.YesNo,
"Wonder Card is marked as USED and will not be able to be picked up in-game.",
"Do you want to remove the USED flag so that it is UNUSED?"))
g.GiftUsed = false;
RTB.Text = getDescription(g);
PB_Preview.Image = getSprite(g);
mg = g;
}
catch (Exception e)
{
Util.Error("Loading of data failed... is this really a Wonder Card?", e.ToString());
RTB.Clear();
}
}
private void getReceivedFlags()
{
LB_Received.Items.Clear();
for (int i = 1; i < mga.Flags.Length; i++)
if (mga.Flags[i])
LB_Received.Items.Add(i.ToString("0000"));
if (LB_Received.Items.Count > 0)
LB_Received.SelectedIndex = 0;
}
private void setCardID(int cardID)
{
if (cardID <= 0 || cardID >= 0x100 * 8) return;
string card = cardID.ToString("0000");
if (!LB_Received.Items.Contains(card))
LB_Received.Items.Add(card);
LB_Received.SelectedIndex = LB_Received.Items.IndexOf(card);
}
// Wonder Card IO (.wc6<->window)
private string getFilter()
{
switch (SAV.Generation)
{
case 4:
return "Gen4 Mystery Gift|*.pgt;*.pcd|All Files|*.*";
case 5:
return "Gen5 Mystery Gift|*.pgf|All Files|*.*";
case 6:
return "Gen6 Mystery Gift|*.wc6;*.wc6full|All Files|*.*";
default:
return "";
}
}
private void B_Import_Click(object sender, EventArgs e)
{
OpenFileDialog import = new OpenFileDialog {Filter = getFilter()};
if (import.ShowDialog() != DialogResult.OK) return;
string path = import.FileName;
MysteryGift g = MysteryGift.getMysteryGift(File.ReadAllBytes(path), Path.GetExtension(path));
if (g == null)
{
Util.Error("File is not a Mystery Gift:", path);
return;
}
viewGiftData(g);
}
private void B_Output_Click(object sender, EventArgs e)
{
SaveFileDialog outputwc6 = new SaveFileDialog
{
Filter = getFilter(),
FileName = Util.CleanFileName($"{mg.CardID} - {mg.CardTitle}{mg.Extension}")
};
if (outputwc6.ShowDialog() != DialogResult.OK) return;
string path = outputwc6.FileName;
if (File.Exists(path)) // File already exists, save a .bak
File.WriteAllBytes(path + ".bak", File.ReadAllBytes(path));
File.WriteAllBytes(path, mg.Data);
}
// Wonder Card RW (window<->sav)
private void clickView(object sender, EventArgs e)
{
sender = ((sender as ToolStripItem)?.Owner as ContextMenuStrip)?.SourceControl ?? sender as PictureBox;
int index = Array.IndexOf(pba, sender);
setBackground(index, Properties.Resources.slotView);
viewGiftData(mga.Gifts[index]);
}
private void clickSet(object sender, EventArgs e)
{
if (!checkSpecialWonderCard(mg))
return;
sender = ((sender as ToolStripItem)?.Owner as ContextMenuStrip)?.SourceControl ?? sender as PictureBox;
int index = Array.IndexOf(pba, sender);
// Hijack to the latest unfilled slot if index creates interstitial empty slots.
int lastUnfilled = Array.FindIndex(pba, p => p.Image == null);
if (lastUnfilled > -1 && lastUnfilled < index)
index = lastUnfilled;
if (mg.Data.Length != mga.Gifts[index].Data.Length)
{
Util.Alert("Can't set slot here.", $"{mg.GetType()} != {mga.Gifts[index].GetType()}");
return;
}
setBackground(index, Properties.Resources.slotSet);
mga.Gifts[index] = mg;
setGiftBoxes();
setCardID(mg.CardID);
}
private void clickDelete(object sender, EventArgs e)
{
sender = ((sender as ToolStripItem)?.Owner as ContextMenuStrip)?.SourceControl ?? sender as PictureBox;
int index = Array.IndexOf(pba, sender);
setBackground(index, Properties.Resources.slotDel);
mga.Gifts[index].Data = new byte[mga.Gifts[index].Data.Length];
setGiftBoxes();
}
// Close Window
private void B_Cancel_Click(object sender, EventArgs e)
{
Close();
}
private void B_Save_Click(object sender, EventArgs e)
{
// Make sure all of the Received Flags are flipped!
bool[] flags = new bool[mga.Flags.Length];
foreach (var o in LB_Received.Items)
flags[Util.ToUInt32(o.ToString())] = true;
mga.Flags = flags;
SAV.GiftAlbum = mga;
Main.SAV.Data = SAV.Data;
Main.SAV.Edited = true;
Close();
}
// Delete WC Flag
private void clearRecievedFlag(object sender, EventArgs e)
{
if (LB_Received.SelectedIndex < 0) return;
if (LB_Received.Items.Count > 0)
LB_Received.Items.Remove(LB_Received.Items[LB_Received.SelectedIndex]);
if (LB_Received.Items.Count > 0)
LB_Received.SelectedIndex = 0;
}
// Drag & Drop Wonder Cards
private void tabMain_DragEnter(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(DataFormats.FileDrop)) e.Effect = DragDropEffects.Copy;
}
private void tabMain_DragDrop(object sender, DragEventArgs e)
{
string[] files = (string[])e.Data.GetData(DataFormats.FileDrop);
// Check for multiple wondercards
if (Directory.Exists(files[0]))
files = Directory.GetFiles(files[0], "*", SearchOption.AllDirectories);
if (files.Length == 1 && !Directory.Exists(files[0]))
{
string path = files[0]; // open first D&D
long len = new FileInfo(path).Length;
if (len > 0x1000) // arbitrary
{
Util.Alert("File is not a Mystery Gift.", path);
return;
}
MysteryGift g = MysteryGift.getMysteryGift(File.ReadAllBytes(path), Path.GetExtension(path));
if (g == null)
{
Util.Error("File is not a Mystery Gift:", path);
return;
}
viewGiftData(g);
return;
}
setGiftBoxes();
}
private bool checkSpecialWonderCard(MysteryGift g)
{
if (SAV.Generation != 6)
return true;
if (g is WC6)
{
if (g.CardID == 2048 && g.Item == 726) // Eon Ticket (OR/AS)
{
if (!Main.SAV.ORAS || ((SAV6)SAV).EonTicket < 0)
goto reject;
BitConverter.GetBytes(WC6.EonTicketConst).CopyTo(SAV.Data, ((SAV6)SAV).EonTicket);
}
}
return true;
reject: Util.Alert("Unable to insert the Mystery Gift.", "Does this Mystery Gift really belong to this game?");
return false;
}
private void L_QR_Click(object sender, EventArgs e)
{
if (ModifierKeys == Keys.Alt)
{
byte[] data = QR.getQRData();
if (data == null) return;
string[] types = mga.Gifts.Select(g => g.GetType().Name).Distinct().ToArray();
MysteryGift gift = MysteryGift.getMysteryGift(data);
string giftType = gift.GetType().Name;
if (mga.Gifts.All(card => card.Data.Length != data.Length))
Util.Alert("Decoded data not valid for loaded save file.", $"QR Data Size: 0x{data.Length.ToString("X")}");
else if (types.All(type => type != giftType))
Util.Alert("Gift type is not compatible with the save file.", $"QR Gift Type: {gift.GetType().Name}" + Environment.NewLine + $"Expected Types: {string.Join(", ", types)}");
else
try { viewGiftData(gift); }
catch { Util.Alert("Error loading Mystery Gift data."); }
}
else
{
if (mg.Data.SequenceEqual(new byte[mg.Data.Length]))
{ Util.Alert("No wondercard data found in loaded slot!"); return; }
if (SAV.Generation == 6 && mg.Item == 726 && mg.IsItem)
{ Util.Alert("Eon Ticket Wonder Cards will not function properly", "Inject to the save file instead."); return; }
const string server = "http://lunarcookies.github.io/wc.html#";
Image qr = QR.getQRImage(mg.Data, server);
if (qr == null) return;
string desc = $"({mg.GetType().Name}) {getDescription(mg)}";
new QR(qr, PB_Preview.Image, desc, "", "", "PKHeX Wonder Card @ ProjectPokemon.org").ShowDialog();
}
}
private void pbBoxSlot_MouseDown(object sender, MouseEventArgs e)
{
switch (ModifierKeys)
{
case Keys.Control: clickView(sender, e); return;
case Keys.Shift: clickSet(sender, e); return;
case Keys.Alt: clickDelete(sender, e); return;
}
PictureBox pb = sender as PictureBox;
if (pb?.Image == null)
return;
if (e.Button != MouseButtons.Left || e.Clicks != 1) return;
int index = Array.IndexOf(pba, sender);
wc_slot = index;
// Create Temp File to Drag
Cursor.Current = Cursors.Hand;
// Prepare Data
MysteryGift card = mga.Gifts[index];
string filename = Util.CleanFileName($"{card.CardID.ToString("0000")} - {card.CardTitle}.wc6");
// Make File
string newfile = Path.Combine(Path.GetTempPath(), Util.CleanFileName(filename));
try
{
File.WriteAllBytes(newfile, card.Data);
DoDragDrop(new DataObject(DataFormats.FileDrop, new[] { newfile }), DragDropEffects.Move);
}
catch (ArgumentException x)
{ Util.Error("Drag & Drop Error:", x.ToString()); }
File.Delete(newfile);
wc_slot = -1;
}
private void pbBoxSlot_DragDrop(object sender, DragEventArgs e)
{
int index = Array.IndexOf(pba, sender);
// Hijack to the latest unfilled slot if index creates interstitial empty slots.
int lastUnfilled = Array.FindIndex(pba, p => p.Image == null);
if (lastUnfilled < index)
index = lastUnfilled;
if (wc_slot == -1) // dropped
{
string[] files = (string[])e.Data.GetData(DataFormats.FileDrop);
if (files.Length < 1)
return;
if (PCD.Size < (int)new FileInfo(files[0]).Length)
{ Util.Alert("Data size invalid.", files[0]); return; }
byte[] data = File.ReadAllBytes(files[0]);
chk:
if (data.Length != mga.Gifts[index].Data.Length)
{
if (index < 8)
{
index = 8;
goto chk;
}
{ Util.Alert("Can't set slot here.", $"{data.Length} != {mga.Gifts[index].Data.Length}, {mga.Gifts[index].GetType()}", files[0]); return; }
}
mga.Gifts[index].Data = data;
setCardID(mga.Gifts[index].CardID);
viewGiftData(mga.Gifts[index]);
}
else // Swap Data
{
// Check to see if they copied beyond blank slots.
if (index > Math.Max(wc_slot, lastUnfilled - 1))
index = Math.Max(wc_slot, lastUnfilled - 1);
MysteryGift s1 = mga.Gifts[index];
MysteryGift s2 = mga.Gifts[wc_slot];
if (s1.Data.Length != s2.Data.Length)
{ Util.Alert("Can't swap these two slots."); return; }
mga.Gifts[wc_slot] = s1;
mga.Gifts[index] = s2;
}
setBackground(index, Properties.Resources.slotView);
setGiftBoxes();
}
private void pbBoxSlot_DragEnter(object sender, DragEventArgs e)
{
if (e.AllowedEffect == (DragDropEffects.Copy | DragDropEffects.Link)) // external file
e.Effect = DragDropEffects.Copy;
else if (e.Data != null) // within
e.Effect = DragDropEffects.Move;
}
private int wc_slot = -1;
private static Image getSprite(MysteryGift gift)
{
Image img;
if (gift.IsPokémon)
img = PKX.getSprite(gift.convertToPKM(Main.SAV));
else if (gift.IsItem)
img = (Image)(Properties.Resources.ResourceManager.GetObject("item_" + gift.Item) ?? Properties.Resources.unknown);
else
img = Properties.Resources.unknown;
if (gift.GiftUsed)
img = Util.LayerImage(new Bitmap(img.Width, img.Height), img, 0, 0, 0.3);
return img;
}
private static string getDescription(MysteryGift gift)
{
if (gift.Empty)
return "Empty Slot. No data!";
string s = gift.getCardHeader();
if (gift.IsItem)
{
s += "Item: " + Main.itemlist[gift.Item] + Environment.NewLine + "Quantity: " + gift.Quantity;
return s;
}
if (gift.IsPokémon)
{
PKM pk = gift.convertToPKM(Main.SAV);
try
{
s += $"{Main.specieslist[pk.Species]} @ {Main.itemlist[pk.HeldItem]} --- ";
s += (pk.IsEgg ? Main.eggname : $"{pk.OT_Name} - {pk.TID.ToString("00000")}/{pk.SID.ToString("00000")}") + Environment.NewLine;
s += $"{Main.movelist[pk.Move1]} / {Main.movelist[pk.Move2]} / {Main.movelist[pk.Move3]} / {Main.movelist[pk.Move4]}" + Environment.NewLine;
}
catch { s += "Unable to create gift description."; }
return s;
}
s += "Unknown Wonder Card Type!";
return s;
}
}
}