2020-01-26 19:19:58 +00:00
|
|
|
using PKHeX.Core;
|
2018-07-29 23:39:15 +00:00
|
|
|
using System;
|
2016-10-27 01:49:40 +00:00
|
|
|
using System.Collections.Generic;
|
2022-03-23 06:02:46 +00:00
|
|
|
using System.Diagnostics;
|
2015-03-11 04:18:35 +00:00
|
|
|
using System.Drawing;
|
2015-03-11 01:44:51 +00:00
|
|
|
using System.IO;
|
2015-03-11 04:18:35 +00:00
|
|
|
using System.Linq;
|
2022-03-23 06:02:46 +00:00
|
|
|
using System.Threading.Tasks;
|
2014-06-28 21:22:05 +00:00
|
|
|
using System.Windows.Forms;
|
2021-11-27 23:48:08 +00:00
|
|
|
using PKHeX.Drawing.Misc;
|
2022-03-26 22:52:17 +00:00
|
|
|
using PKHeX.Drawing.PokeSprite;
|
2021-04-09 23:37:32 +00:00
|
|
|
using PKHeX.WinForms.Controls;
|
2018-04-07 04:23:09 +00:00
|
|
|
using static PKHeX.Core.MessageStrings;
|
2014-06-28 21:22:05 +00:00
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
namespace PKHeX.WinForms;
|
|
|
|
|
|
|
|
public partial class SAV_Wondercard : Form
|
2014-06-28 21:22:05 +00:00
|
|
|
{
|
2022-06-18 18:04:24 +00:00
|
|
|
private readonly SaveFile Origin;
|
|
|
|
private readonly SaveFile SAV;
|
|
|
|
private readonly SummaryPreviewer Summary = new();
|
|
|
|
|
|
|
|
public SAV_Wondercard(SaveFile sav, DataMysteryGift? g = null)
|
2014-06-28 21:22:05 +00:00
|
|
|
{
|
2022-06-18 18:04:24 +00:00
|
|
|
InitializeComponent();
|
|
|
|
WinFormsUtil.TranslateInterface(this, Main.CurrentLanguage);
|
|
|
|
SAV = (Origin = sav).Clone();
|
|
|
|
mga = SAV.GiftAlbum;
|
2018-07-29 23:39:15 +00:00
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
pba = SAV.Generation switch
|
2014-06-28 21:22:05 +00:00
|
|
|
{
|
2022-06-18 18:04:24 +00:00
|
|
|
4 => PopulateViewGiftsG4().ToArray(),
|
|
|
|
5 or 6 or 7 => PopulateViewGiftsG567().ToArray(),
|
|
|
|
_ => throw new ArgumentOutOfRangeException(nameof(SAV.Generation), "Game not supported."),
|
|
|
|
};
|
|
|
|
foreach (var pb in pba)
|
|
|
|
{
|
|
|
|
pb.AllowDrop = true;
|
|
|
|
pb.DragDrop += BoxSlot_DragDrop;
|
|
|
|
pb.DragEnter += BoxSlot_DragEnter;
|
|
|
|
pb.MouseDown += BoxSlot_MouseDown;
|
|
|
|
pb.ContextMenuStrip = mnuVSD;
|
|
|
|
pb.MouseHover += (_, _) => Summary.Show(pb, mga.Gifts[pba.IndexOf(pb)]);
|
2023-02-05 08:42:37 +00:00
|
|
|
pb.Enter += (sender, e) =>
|
|
|
|
{
|
|
|
|
var index = pba.IndexOf(pb);
|
|
|
|
if (index < 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
var enc = mga.Gifts[index];
|
|
|
|
pb.AccessibleDescription = string.Join(Environment.NewLine, SummaryPreviewer.GetTextLines(enc));
|
|
|
|
};
|
2022-06-18 18:04:24 +00:00
|
|
|
}
|
2018-05-12 15:13:39 +00:00
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
SetGiftBoxes();
|
|
|
|
GetReceivedFlags();
|
2016-07-06 02:12:18 +00:00
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
if (LB_Received.Items.Count > 0)
|
|
|
|
LB_Received.SelectedIndex = 0;
|
2018-05-12 15:13:39 +00:00
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
if (mga.Gifts[0] is WR7) // giftused is not a valid prop
|
|
|
|
B_UnusedAll.Visible = B_UsedAll.Visible = L_QR.Visible = false;
|
2014-12-10 23:24:34 +00:00
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
DragEnter += Main_DragEnter;
|
|
|
|
DragDrop += Main_DragDrop;
|
2021-09-16 20:45:41 +00:00
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
if (g == null)
|
|
|
|
ClickView(pba[0], EventArgs.Empty);
|
|
|
|
else
|
|
|
|
ViewGiftData(g);
|
|
|
|
}
|
2015-04-01 00:58:23 +00:00
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
private readonly MysteryGiftAlbum mga;
|
|
|
|
private DataMysteryGift? mg;
|
|
|
|
private readonly IList<PictureBox> pba;
|
2017-05-23 04:55:05 +00:00
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
// 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;
|
|
|
|
}
|
2014-06-28 21:22:05 +00:00
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
private void SetGiftBoxes()
|
|
|
|
{
|
|
|
|
for (int i = 0; i < mga.Gifts.Length; i++)
|
2015-12-19 04:48:47 +00:00
|
|
|
{
|
2022-06-18 18:04:24 +00:00
|
|
|
MysteryGift m = mga.Gifts[i];
|
|
|
|
pba[i].Image = m.Sprite();
|
2015-12-19 04:48:47 +00:00
|
|
|
}
|
2022-06-18 18:04:24 +00:00
|
|
|
}
|
2018-07-29 23:39:15 +00:00
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
private void ViewGiftData(DataMysteryGift g)
|
|
|
|
{
|
|
|
|
try
|
2014-06-28 21:22:05 +00:00
|
|
|
{
|
2022-06-18 18:04:24 +00:00
|
|
|
// only check if the form is visible (not opening)
|
2022-08-30 22:00:45 +00:00
|
|
|
if (Visible && g.GiftUsed)
|
|
|
|
{
|
|
|
|
var prompt = WinFormsUtil.Prompt(MessageBoxButtons.YesNo, MsgMsyteryGiftUsedAlert, MsgMysteryGiftUsedFix);
|
|
|
|
if (prompt == DialogResult.Yes)
|
|
|
|
g.GiftUsed = false;
|
|
|
|
}
|
2018-07-29 23:39:15 +00:00
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
RTB.Lines = g.GetDescription().ToArray();
|
|
|
|
PB_Preview.Image = g.Sprite();
|
|
|
|
mg = g;
|
|
|
|
}
|
|
|
|
// Some user input mystery gifts can have out-of-bounds values. Just swallow any exception.
|
|
|
|
catch (Exception e)
|
2014-06-28 21:22:05 +00:00
|
|
|
{
|
2022-06-18 18:04:24 +00:00
|
|
|
RTB.Clear();
|
2022-08-30 22:00:45 +00:00
|
|
|
WinFormsUtil.Error(MsgMysteryGiftParseTypeUnknown, e);
|
2014-06-28 21:22:05 +00:00
|
|
|
}
|
2022-06-18 18:04:24 +00:00
|
|
|
}
|
2018-07-29 23:39:15 +00:00
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
private void GetReceivedFlags()
|
|
|
|
{
|
|
|
|
LB_Received.Items.Clear();
|
|
|
|
for (int i = 1; i < mga.Flags.Length; i++)
|
2014-06-28 21:22:05 +00:00
|
|
|
{
|
2022-06-18 18:04:24 +00:00
|
|
|
if (mga.Flags[i])
|
|
|
|
LB_Received.Items.Add(i.ToString("0000"));
|
2014-06-28 21:22:05 +00:00
|
|
|
}
|
2018-07-29 23:39:15 +00:00
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
if (LB_Received.Items.Count > 0)
|
|
|
|
LB_Received.SelectedIndex = 0;
|
|
|
|
}
|
2014-06-28 21:22:05 +00:00
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
private void SetCardID(int cardID)
|
|
|
|
{
|
|
|
|
if (cardID is <= 0 or >= 0x100 * 8)
|
|
|
|
return;
|
2015-12-19 06:04:01 +00:00
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
string card = cardID.ToString("0000");
|
|
|
|
if (!LB_Received.Items.Contains(card))
|
|
|
|
LB_Received.Items.Add(card);
|
|
|
|
LB_Received.SelectedIndex = LB_Received.Items.IndexOf(card);
|
|
|
|
}
|
2015-03-12 04:44:12 +00:00
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
// Mystery Gift IO (.file<->window)
|
|
|
|
private void B_Import_Click(object sender, EventArgs e)
|
|
|
|
{
|
2022-11-25 01:42:17 +00:00
|
|
|
var fileFilter = WinFormsUtil.GetMysterGiftFilter(SAV.Context);
|
2022-08-30 22:00:45 +00:00
|
|
|
using var import = new OpenFileDialog { Filter = fileFilter };
|
|
|
|
if (import.ShowDialog() != DialogResult.OK)
|
|
|
|
return;
|
2018-07-29 23:39:15 +00:00
|
|
|
|
2022-08-30 22:00:45 +00:00
|
|
|
var path = import.FileName;
|
|
|
|
var data = File.ReadAllBytes(path);
|
|
|
|
var ext = Path.GetExtension(path);
|
|
|
|
var gift = MysteryGift.GetMysteryGift(data, ext);
|
|
|
|
if (gift == null)
|
2014-06-28 21:22:05 +00:00
|
|
|
{
|
2022-06-18 18:04:24 +00:00
|
|
|
WinFormsUtil.Error(MsgMysteryGiftInvalid, path);
|
|
|
|
return;
|
2014-06-28 21:22:05 +00:00
|
|
|
}
|
2022-08-30 22:00:45 +00:00
|
|
|
ViewGiftData(gift);
|
2022-06-18 18:04:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private void B_Output_Click(object sender, EventArgs e)
|
|
|
|
{
|
|
|
|
if (mg == null)
|
|
|
|
return;
|
2022-11-25 01:42:17 +00:00
|
|
|
WinFormsUtil.ExportMGDialog(mg);
|
2022-06-18 18:04:24 +00:00
|
|
|
}
|
2014-06-28 21:22:05 +00:00
|
|
|
|
2022-08-30 22:00:45 +00:00
|
|
|
private static int GetLastUnfilledByType(MysteryGift gift, MysteryGiftAlbum album)
|
2022-06-18 18:04:24 +00:00
|
|
|
{
|
2022-08-30 22:00:45 +00:00
|
|
|
var gifts = album.Gifts;
|
|
|
|
for (int i = 0; i < gifts.Length; i++)
|
2016-08-16 03:48:02 +00:00
|
|
|
{
|
2022-08-30 22:00:45 +00:00
|
|
|
var exist = gifts[i];
|
|
|
|
if (!exist.Empty)
|
2022-06-18 18:04:24 +00:00
|
|
|
continue;
|
2022-08-30 22:00:45 +00:00
|
|
|
if (exist.Type != gift.Type)
|
2022-06-18 18:04:24 +00:00
|
|
|
continue;
|
|
|
|
return i;
|
2016-08-16 03:48:02 +00:00
|
|
|
}
|
2022-06-18 18:04:24 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2022-08-30 22:00:45 +00:00
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
// Mystery Gift RW (window<->sav)
|
|
|
|
private void ClickView(object sender, EventArgs e)
|
|
|
|
{
|
|
|
|
var pb = WinFormsUtil.GetUnderlyingControl<PictureBox>(sender);
|
|
|
|
if (pb == null)
|
|
|
|
return;
|
|
|
|
int index = pba.IndexOf(pb);
|
2015-12-20 00:25:32 +00:00
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
SetBackground(index, Drawing.PokeSprite.Properties.Resources.slotView);
|
|
|
|
ViewGiftData(mga.Gifts[index]);
|
|
|
|
}
|
2018-07-29 23:39:15 +00:00
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
private void ClickSet(object sender, EventArgs e)
|
|
|
|
{
|
|
|
|
if (mg is not { } gift)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (!gift.IsCardCompatible(SAV, out var msg))
|
2014-06-28 21:22:05 +00:00
|
|
|
{
|
2022-06-18 18:04:24 +00:00
|
|
|
WinFormsUtil.Alert(MsgMysteryGiftSlotFail, msg);
|
|
|
|
return;
|
|
|
|
}
|
2020-10-18 18:02:39 +00:00
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
var pb = WinFormsUtil.GetUnderlyingControl<PictureBox>(sender);
|
|
|
|
if (pb == null)
|
|
|
|
return;
|
|
|
|
int index = pba.IndexOf(pb);
|
2016-03-31 01:28:28 +00:00
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
// Hijack to the latest unfilled slot if index creates interstitial empty slots.
|
|
|
|
int lastUnfilled = GetLastUnfilledByType(gift, mga);
|
|
|
|
if (lastUnfilled > -1 && lastUnfilled < index)
|
|
|
|
index = lastUnfilled;
|
|
|
|
if (gift is PCD { IsLockCapsule: true })
|
|
|
|
index = 11;
|
2018-07-29 23:39:15 +00:00
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
var gifts = mga.Gifts;
|
|
|
|
var other = gifts[index];
|
|
|
|
if (gift is PCD { CanConvertToPGT: true } pcd && other is PGT)
|
2014-06-28 21:22:05 +00:00
|
|
|
{
|
2022-06-18 18:04:24 +00:00
|
|
|
gift = pcd.Gift;
|
|
|
|
}
|
|
|
|
else if (gift.Type != other.Type)
|
|
|
|
{
|
|
|
|
WinFormsUtil.Alert(MsgMysteryGiftSlotFail, $"{gift.Type} != {other.Type}");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
else if (gift is PCD { IsLockCapsule: true } != (index == 11))
|
|
|
|
{
|
|
|
|
WinFormsUtil.Alert(MsgMysteryGiftSlotFail, $"{GameInfo.Strings.Item[533]} slot not valid.");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
gifts[index] = (DataMysteryGift)gift.Clone();
|
|
|
|
SetBackground(index, Drawing.PokeSprite.Properties.Resources.slotSet);
|
|
|
|
SetGiftBoxes();
|
|
|
|
SetCardID(gift.CardID);
|
|
|
|
}
|
2015-12-19 06:04:01 +00:00
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
private void ClickDelete(object sender, EventArgs e)
|
|
|
|
{
|
|
|
|
var pb = WinFormsUtil.GetUnderlyingControl<PictureBox>(sender);
|
|
|
|
if (pb == null)
|
|
|
|
return;
|
|
|
|
int index = pba.IndexOf(pb);
|
2016-08-16 03:48:02 +00:00
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
var arr = mga.Gifts[index].Data;
|
|
|
|
Array.Clear(arr, 0, arr.Length);
|
2016-08-16 03:48:02 +00:00
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
// Shuffle blank card down
|
|
|
|
int i = index;
|
|
|
|
while (i < mga.Gifts.Length - 1)
|
|
|
|
{
|
|
|
|
if (mga.Gifts[i+1].Empty)
|
|
|
|
break;
|
|
|
|
if (mga.Gifts[i+1].Type != mga.Gifts[i].Type)
|
|
|
|
break;
|
2016-08-16 03:48:02 +00:00
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
i++;
|
2016-08-16 03:48:02 +00:00
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
var mg1 = mga.Gifts[i];
|
|
|
|
var mg2 = mga.Gifts[i-1];
|
|
|
|
|
|
|
|
mga.Gifts[i-1] = mg1;
|
|
|
|
mga.Gifts[i] = mg2;
|
2014-06-28 21:22:05 +00:00
|
|
|
}
|
2022-06-18 18:04:24 +00:00
|
|
|
SetBackground(i, Drawing.PokeSprite.Properties.Resources.slotDel);
|
|
|
|
SetGiftBoxes();
|
|
|
|
}
|
2014-06-28 21:22:05 +00:00
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
// 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)
|
|
|
|
{
|
|
|
|
var value = o?.ToString();
|
|
|
|
if (value == null)
|
|
|
|
continue;
|
|
|
|
var flag = Util.ToUInt32(value);
|
|
|
|
flags[flag] = true;
|
2014-06-28 21:22:05 +00:00
|
|
|
}
|
2018-07-29 23:39:15 +00:00
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
flags.CopyTo(mga.Flags, 0);
|
|
|
|
SAV.GiftAlbum = mga;
|
2014-06-28 21:22:05 +00:00
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
Origin.CopyChangesFrom(SAV);
|
|
|
|
Close();
|
|
|
|
}
|
2016-06-20 04:22:43 +00:00
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
// Delete Received Flag
|
|
|
|
private void ClearReceivedFlag(object sender, EventArgs e)
|
|
|
|
{
|
|
|
|
if (LB_Received.SelectedIndex < 0)
|
|
|
|
return;
|
2014-06-28 21:22:05 +00:00
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
if (LB_Received.SelectedIndices.Count > 1)
|
2014-06-28 21:22:05 +00:00
|
|
|
{
|
2022-06-18 18:04:24 +00:00
|
|
|
for (int i = LB_Received.SelectedIndices.Count - 1; i >= 0; i--)
|
|
|
|
LB_Received.Items.RemoveAt(LB_Received.SelectedIndices[i]);
|
2014-06-28 21:22:05 +00:00
|
|
|
}
|
2022-06-18 18:04:24 +00:00
|
|
|
else if (LB_Received.SelectedIndices.Count == 1)
|
2014-12-10 23:24:34 +00:00
|
|
|
{
|
2022-06-18 18:04:24 +00:00
|
|
|
int lastIndex = LB_Received.SelectedIndex;
|
|
|
|
LB_Received.Items.RemoveAt(lastIndex);
|
|
|
|
if (LB_Received.Items.Count == 0)
|
2021-12-05 06:29:51 +00:00
|
|
|
return;
|
2022-06-18 18:04:24 +00:00
|
|
|
if (lastIndex == LB_Received.Items.Count)
|
|
|
|
lastIndex--;
|
|
|
|
LB_Received.SelectedIndex = lastIndex;
|
2014-12-10 23:24:34 +00:00
|
|
|
}
|
2022-06-18 18:04:24 +00:00
|
|
|
}
|
2018-07-29 23:39:15 +00:00
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
// Drag & Drop Wonder Cards
|
|
|
|
private static void Main_DragEnter(object? sender, DragEventArgs? e)
|
|
|
|
{
|
|
|
|
if (e?.Data is null)
|
|
|
|
return;
|
|
|
|
if (e.Data.GetDataPresent(DataFormats.FileDrop))
|
|
|
|
e.Effect = DragDropEffects.Copy;
|
|
|
|
}
|
2015-01-11 07:31:51 +00:00
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
private void Main_DragDrop(object? sender, DragEventArgs? e)
|
|
|
|
{
|
|
|
|
if (e?.Data?.GetData(DataFormats.FileDrop) is not string[] { Length: not 0 } files)
|
|
|
|
return;
|
|
|
|
|
|
|
|
var first = files[0];
|
|
|
|
// Check for multiple wondercards
|
|
|
|
if (Directory.Exists(first))
|
|
|
|
files = Directory.GetFiles(first, "*", SearchOption.AllDirectories);
|
2021-12-05 06:29:51 +00:00
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
if (files.Length == 1 && !Directory.Exists(files[0]))
|
|
|
|
{
|
|
|
|
string path = files[0]; // open first D&D
|
|
|
|
if (!MysteryGift.IsMysteryGift(new FileInfo(path).Length)) // arbitrary
|
2014-12-10 23:24:34 +00:00
|
|
|
{
|
2022-06-18 18:04:24 +00:00
|
|
|
WinFormsUtil.Alert(MsgMysteryGiftInvalid, path);
|
2016-06-20 04:22:43 +00:00
|
|
|
return;
|
2016-03-19 22:50:01 +00:00
|
|
|
}
|
2022-06-18 18:04:24 +00:00
|
|
|
var gift = MysteryGift.GetMysteryGift(File.ReadAllBytes(path), Path.GetExtension(path));
|
|
|
|
if (gift == null)
|
2017-07-03 04:27:22 +00:00
|
|
|
{
|
2022-06-18 18:04:24 +00:00
|
|
|
WinFormsUtil.Error(MsgMysteryGiftInvalid, path);
|
|
|
|
return;
|
2017-07-03 04:27:22 +00:00
|
|
|
}
|
2022-06-18 18:04:24 +00:00
|
|
|
ViewGiftData(gift);
|
|
|
|
return;
|
2017-06-18 01:37:19 +00:00
|
|
|
}
|
2022-06-18 18:04:24 +00:00
|
|
|
SetGiftBoxes();
|
|
|
|
}
|
2018-07-29 23:39:15 +00:00
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
private void ClickQR(object sender, EventArgs e)
|
|
|
|
{
|
|
|
|
if (ModifierKeys == Keys.Alt)
|
2017-06-18 01:37:19 +00:00
|
|
|
{
|
2022-06-18 18:04:24 +00:00
|
|
|
string url = Clipboard.GetText();
|
|
|
|
if (!string.IsNullOrWhiteSpace(url))
|
2015-03-11 04:18:35 +00:00
|
|
|
{
|
2022-06-18 18:04:24 +00:00
|
|
|
ImportQRToView(url);
|
2017-06-18 01:37:19 +00:00
|
|
|
return;
|
|
|
|
}
|
2022-06-18 18:04:24 +00:00
|
|
|
}
|
|
|
|
ExportQRFromView();
|
|
|
|
}
|
|
|
|
|
|
|
|
private void ExportQRFromView()
|
|
|
|
{
|
|
|
|
if (mg == null)
|
|
|
|
return;
|
|
|
|
if (mg.Empty)
|
|
|
|
{
|
|
|
|
WinFormsUtil.Alert(MsgMysteryGiftSlotNone);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (SAV.Generation == 6 && mg.ItemID == 726 && mg.IsItem)
|
|
|
|
{
|
|
|
|
WinFormsUtil.Alert(MsgMysteryGiftQREonTicket, MsgMysteryGiftQREonTicketAdvice);
|
|
|
|
return;
|
|
|
|
}
|
2016-06-20 04:22:43 +00:00
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
Image qr = QREncode.GenerateQRCode(mg);
|
2015-03-11 04:18:35 +00:00
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
string desc = $"({mg.Type}) {string.Join(Environment.NewLine, mg.GetDescription())}";
|
2015-03-11 04:18:35 +00:00
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
using var form = new QR(qr, PB_Preview.Image, desc + Environment.NewLine + "PKHeX Wonder Card @ ProjectPokemon.org");
|
|
|
|
form.ShowDialog();
|
|
|
|
}
|
2018-07-29 23:39:15 +00:00
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
private void ImportQRToView(string url)
|
|
|
|
{
|
|
|
|
var msg = QRDecode.GetQRData(url, out var data);
|
|
|
|
if (msg != 0)
|
2017-06-18 01:37:19 +00:00
|
|
|
{
|
2022-06-18 18:04:24 +00:00
|
|
|
WinFormsUtil.Alert(msg.ConvertMsg());
|
|
|
|
return;
|
|
|
|
}
|
2019-09-29 16:47:06 +00:00
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
if (data.Length == 0)
|
|
|
|
return;
|
2017-06-18 01:37:19 +00:00
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
string[] types = mga.Gifts.Select(g => g.Type).Distinct().ToArray();
|
|
|
|
var gift = MysteryGift.GetMysteryGift(data);
|
|
|
|
if (gift == null)
|
|
|
|
return;
|
2020-10-18 18:02:39 +00:00
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
string giftType = gift.Type;
|
2017-06-18 01:37:19 +00:00
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
if (mga.Gifts.All(card => card.Data.Length != data.Length))
|
|
|
|
WinFormsUtil.Alert(MsgMysteryGiftQRTypeLength, string.Format(MsgQRDecodeSize, $"0x{data.Length:X}"));
|
|
|
|
else if (types.All(type => type != giftType))
|
|
|
|
WinFormsUtil.Alert(MsgMysteryGiftTypeIncompatible, $"{MsgMysteryGiftQRReceived} {gift.Type}{Environment.NewLine}{MsgMysteryGiftTypeUnexpected} {string.Join(", ", types)}");
|
|
|
|
else if (!SAV.CanReceiveGift(gift))
|
|
|
|
WinFormsUtil.Alert(MsgMysteryGiftTypeDetails);
|
|
|
|
else
|
|
|
|
ViewGiftData(gift);
|
|
|
|
}
|
2015-12-18 05:15:40 +00:00
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
private async void BoxSlot_MouseDown(object? sender, MouseEventArgs e)
|
|
|
|
{
|
|
|
|
if (sender == null)
|
|
|
|
return;
|
|
|
|
switch (ModifierKeys)
|
2015-12-18 05:15:40 +00:00
|
|
|
{
|
2022-06-18 18:04:24 +00:00
|
|
|
case Keys.Control: ClickView(sender, e); return;
|
|
|
|
case Keys.Shift: ClickSet(sender, e); return;
|
|
|
|
case Keys.Alt: ClickDelete(sender, e); return;
|
|
|
|
}
|
|
|
|
var pb = sender as PictureBox;
|
|
|
|
if (pb?.Image == null)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (e.Button != MouseButtons.Left || e.Clicks != 1)
|
|
|
|
return;
|
|
|
|
|
|
|
|
int index = pba.IndexOf(pb);
|
|
|
|
var gift = mga.Gifts[index];
|
|
|
|
if (gift.Empty)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Create Temp File to Drag
|
|
|
|
wc_slot = index;
|
|
|
|
Cursor.Current = Cursors.Hand;
|
|
|
|
string newfile = Path.Combine(Path.GetTempPath(), Util.CleanFileName(gift.FileName));
|
|
|
|
try
|
|
|
|
{
|
2023-02-02 00:55:38 +00:00
|
|
|
await File.WriteAllBytesAsync(newfile, gift.Write()).ConfigureAwait(true);
|
2022-06-18 18:04:24 +00:00
|
|
|
DoDragDrop(new DataObject(DataFormats.FileDrop, new[] { newfile }), DragDropEffects.Copy | DragDropEffects.Move);
|
|
|
|
}
|
|
|
|
// Sometimes the drag-drop is canceled or ends up at a bad location. Don't bother recovering from an exception; just display a safe error message.
|
|
|
|
catch (Exception x)
|
|
|
|
{ WinFormsUtil.Error("Drag & Drop Error", x); }
|
|
|
|
wc_slot = -1;
|
|
|
|
await DeleteAsync(newfile, 20_000).ConfigureAwait(false);
|
|
|
|
}
|
2015-12-19 06:04:01 +00:00
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
private static async Task DeleteAsync(string path, int delay)
|
|
|
|
{
|
|
|
|
await Task.Delay(delay).ConfigureAwait(true);
|
|
|
|
if (!File.Exists(path))
|
|
|
|
return;
|
2015-12-19 06:04:01 +00:00
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
try { File.Delete(path); }
|
|
|
|
catch (Exception ex) { Debug.WriteLine(ex.Message); }
|
|
|
|
}
|
2022-03-26 22:52:17 +00:00
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
private void BoxSlot_DragDrop(object? sender, DragEventArgs? e)
|
|
|
|
{
|
|
|
|
if (mg == null || sender is not PictureBox pb)
|
|
|
|
return;
|
2022-03-23 06:02:46 +00:00
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
int index = pba.IndexOf(pb);
|
2022-03-23 06:02:46 +00:00
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
// Hijack to the latest unfilled slot if index creates interstitial empty slots.
|
|
|
|
int lastUnfilled = GetLastUnfilledByType(mg, mga);
|
|
|
|
if (lastUnfilled > -1 && lastUnfilled < index && mga.Gifts[lastUnfilled].Type == mga.Gifts[index].Type)
|
|
|
|
index = lastUnfilled;
|
|
|
|
if (mg is PCD { IsLockCapsule: true })
|
|
|
|
index = 11;
|
2018-07-29 23:39:15 +00:00
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
if (wc_slot == -1) // dropped
|
2015-12-18 05:15:40 +00:00
|
|
|
{
|
2022-06-18 18:04:24 +00:00
|
|
|
if (e?.Data?.GetData(DataFormats.FileDrop) is not string[] {Length: not 0} files)
|
2020-10-18 18:02:39 +00:00
|
|
|
return;
|
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
var first = files[0];
|
|
|
|
var fi = new FileInfo(first);
|
|
|
|
if (!MysteryGift.IsMysteryGift(fi.Length))
|
|
|
|
{ WinFormsUtil.Alert(MsgFileUnsupported, first); return; }
|
2015-12-19 06:04:01 +00:00
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
byte[] data = File.ReadAllBytes(first);
|
|
|
|
var gift = MysteryGift.GetMysteryGift(data, fi.Extension);
|
|
|
|
if (gift == null)
|
|
|
|
{ WinFormsUtil.Alert(MsgFileUnsupported, first); return; }
|
2018-05-12 15:13:39 +00:00
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
ref var dest = ref mga.Gifts[index];
|
|
|
|
if (gift is PCD { CanConvertToPGT: true } pcd && dest is PGT)
|
2015-12-19 06:17:01 +00:00
|
|
|
{
|
2022-06-18 18:04:24 +00:00
|
|
|
gift = pcd.Gift;
|
2015-12-19 06:17:01 +00:00
|
|
|
}
|
2022-06-18 18:04:24 +00:00
|
|
|
else if (gift.Type != dest.Type)
|
2015-12-19 06:17:01 +00:00
|
|
|
{
|
2022-06-18 18:04:24 +00:00
|
|
|
WinFormsUtil.Alert(MsgMysteryGiftSlotFail, $"{gift.Type} != {dest.Type}");
|
|
|
|
return;
|
2022-03-26 22:52:17 +00:00
|
|
|
}
|
2022-06-18 18:04:24 +00:00
|
|
|
SetBackground(index, Drawing.PokeSprite.Properties.Resources.slotSet);
|
|
|
|
dest = (DataMysteryGift)gift.Clone();
|
2016-06-20 04:22:43 +00:00
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
SetCardID(dest.CardID);
|
|
|
|
ViewGiftData(dest);
|
|
|
|
}
|
|
|
|
else // Swap Data
|
2022-03-26 22:52:17 +00:00
|
|
|
{
|
2022-06-18 18:04:24 +00:00
|
|
|
index = SwapSlots(index, wc_slot);
|
|
|
|
if (index == -1)
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
SetBackground(index, Drawing.PokeSprite.Properties.Resources.slotView);
|
|
|
|
SetGiftBoxes();
|
|
|
|
}
|
2022-03-26 22:52:17 +00:00
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
private int SwapSlots(int dest, int src)
|
|
|
|
{
|
|
|
|
var gifts = mga.Gifts;
|
|
|
|
var s1 = gifts[dest];
|
|
|
|
var s2 = gifts[src];
|
2022-03-26 22:52:17 +00:00
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
// Double check compatibility of slots
|
|
|
|
if (s1.Type != s2.Type)
|
|
|
|
{
|
|
|
|
if (s2 is PCD { CanConvertToPGT: true } && s1 is PGT)
|
2022-05-06 04:21:03 +00:00
|
|
|
{
|
2022-06-18 18:04:24 +00:00
|
|
|
// Get first empty slot
|
2022-08-24 06:11:26 +00:00
|
|
|
var firstEmpty = Array.FindIndex(gifts, static z => z.Empty);
|
2022-06-18 18:04:24 +00:00
|
|
|
if ((uint)firstEmpty < dest)
|
|
|
|
dest = firstEmpty;
|
2022-05-06 04:21:03 +00:00
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
// set the PGT to the destination PGT slot instead
|
|
|
|
ViewGiftData(s2);
|
|
|
|
ClickSet(pba[dest], EventArgs.Empty);
|
|
|
|
WinFormsUtil.Alert(string.Format(MsgMysteryGiftSlotAlternate, s2.Type, s1.Type));
|
2022-03-26 22:52:17 +00:00
|
|
|
}
|
2022-06-18 18:04:24 +00:00
|
|
|
else
|
2022-03-26 22:52:17 +00:00
|
|
|
{
|
2022-06-18 18:04:24 +00:00
|
|
|
WinFormsUtil.Alert(string.Format(MsgMysteryGiftSlotFailSwap, s2.Type, s1.Type));
|
2022-03-26 22:52:17 +00:00
|
|
|
}
|
2022-06-18 18:04:24 +00:00
|
|
|
return -1;
|
2015-12-18 05:15:40 +00:00
|
|
|
}
|
2018-07-29 23:39:15 +00:00
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
if ((s1 is PCD && dest == 11) || (s2 is PCD && src == 11))
|
2015-12-18 05:15:40 +00:00
|
|
|
{
|
2022-06-18 18:04:24 +00:00
|
|
|
WinFormsUtil.Alert(MsgMysteryGiftSlotFail, $"{GameInfo.Strings.Item[533]} swap not valid.");
|
|
|
|
return -1;
|
2015-12-18 05:15:40 +00:00
|
|
|
}
|
2018-07-29 23:39:15 +00:00
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
// If data is present in both slots, just swap.
|
|
|
|
if (!s1.Empty)
|
|
|
|
{
|
|
|
|
// Swap
|
|
|
|
(gifts[src], gifts[dest]) = (s1, s2);
|
|
|
|
return dest;
|
|
|
|
}
|
2016-10-27 01:49:40 +00:00
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
// empty slot created, bubble this slot to the end of its list
|
|
|
|
for (int i = src; i != dest; i++)
|
2016-10-27 01:49:40 +00:00
|
|
|
{
|
2022-06-18 18:04:24 +00:00
|
|
|
if (gifts[i + 1].Empty)
|
|
|
|
return i; // done bubbling
|
|
|
|
(gifts[i + 1], gifts[i]) = (gifts[i], gifts[i + 1]);
|
|
|
|
}
|
|
|
|
throw new InvalidOperationException(); // shouldn't ever hit here.
|
|
|
|
}
|
2016-10-27 01:49:40 +00:00
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
private static void BoxSlot_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;
|
|
|
|
Debug.WriteLine(e.Effect);
|
|
|
|
}
|
2016-10-27 01:49:40 +00:00
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
private int wc_slot = -1;
|
2022-05-06 04:21:03 +00:00
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
// UI Generation
|
|
|
|
private List<PictureBox> PopulateViewGiftsG4()
|
|
|
|
{
|
|
|
|
List<PictureBox> pb = new();
|
|
|
|
var spriter = SpriteUtil.Spriter;
|
2018-07-29 23:39:15 +00:00
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
// Row 1
|
|
|
|
var f1 = GetFlowLayoutPanel();
|
|
|
|
f1.Controls.Add(GetLabel($"{nameof(PGT)} 1-6"));
|
|
|
|
for (int i = 0; i < 6; i++)
|
2016-10-27 01:49:40 +00:00
|
|
|
{
|
2023-02-05 08:42:37 +00:00
|
|
|
var p = GetPictureBox(spriter.Width, spriter.Height, $"PGT {i + 1}");
|
2022-06-18 18:04:24 +00:00
|
|
|
f1.Controls.Add(p);
|
|
|
|
pb.Add(p);
|
|
|
|
}
|
|
|
|
// Row 2
|
|
|
|
var f2 = GetFlowLayoutPanel();
|
|
|
|
f2.Controls.Add(GetLabel($"{nameof(PGT)} 7-8"));
|
|
|
|
for (int i = 6; i < 8; i++)
|
|
|
|
{
|
2023-02-05 08:42:37 +00:00
|
|
|
var p = GetPictureBox(spriter.Width, spriter.Height, $"PGT {i + 1}");
|
2022-06-18 18:04:24 +00:00
|
|
|
f2.Controls.Add(p);
|
|
|
|
pb.Add(p);
|
|
|
|
}
|
|
|
|
// Row 3
|
|
|
|
var f3 = GetFlowLayoutPanel();
|
|
|
|
f3.Margin = new Padding(0, 12, 0, 0);
|
|
|
|
f3.Controls.Add(GetLabel($"{nameof(PCD)} 1-3"));
|
|
|
|
for (int i = 8; i < 11; i++)
|
|
|
|
{
|
2023-02-05 08:42:37 +00:00
|
|
|
var p = GetPictureBox(spriter.Width, spriter.Height, $"PCD {i - 7}");
|
2022-06-18 18:04:24 +00:00
|
|
|
f3.Controls.Add(p);
|
|
|
|
pb.Add(p);
|
|
|
|
}
|
2016-10-27 01:49:40 +00:00
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
FLP_Gifts.Controls.Add(f1);
|
|
|
|
FLP_Gifts.Controls.Add(f2);
|
|
|
|
FLP_Gifts.Controls.Add(f3);
|
2018-12-30 06:00:17 +00:00
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
if (mga.Gifts.Length == 12) // lock capsule
|
|
|
|
{
|
|
|
|
// Row 4
|
|
|
|
var f4 = GetFlowLayoutPanel();
|
|
|
|
f4.Controls.Add(GetLabel(GameInfo.Strings.Item[533])); // Lock Capsule
|
2016-10-27 01:49:40 +00:00
|
|
|
{
|
2023-02-05 08:42:37 +00:00
|
|
|
var p = GetPictureBox(spriter.Width, spriter.Height, "PCD Lock Capsule");
|
2022-06-18 18:04:24 +00:00
|
|
|
f4.Controls.Add(p);
|
|
|
|
pb.Add(p);
|
2016-10-27 01:49:40 +00:00
|
|
|
}
|
2022-06-18 18:04:24 +00:00
|
|
|
FLP_Gifts.Controls.Add(f4);
|
2016-10-27 01:49:40 +00:00
|
|
|
}
|
2022-06-18 18:04:24 +00:00
|
|
|
return pb;
|
|
|
|
}
|
2018-07-29 23:39:15 +00:00
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
private List<PictureBox> PopulateViewGiftsG567()
|
|
|
|
{
|
|
|
|
var pb = new List<PictureBox>();
|
2021-12-05 01:56:56 +00:00
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
const int cellsPerRow = 6;
|
|
|
|
int rows = (int)Math.Ceiling(mga.Gifts.Length / (decimal)cellsPerRow);
|
|
|
|
int countRemaining = mga.Gifts.Length;
|
|
|
|
var spriter = SpriteUtil.Spriter;
|
2017-10-01 01:25:21 +00:00
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
for (int i = 0; i < rows; i++)
|
2017-10-01 01:25:21 +00:00
|
|
|
{
|
2022-06-18 18:04:24 +00:00
|
|
|
var row = GetFlowLayoutPanel();
|
|
|
|
int count = cellsPerRow >= countRemaining ? countRemaining : cellsPerRow;
|
|
|
|
countRemaining -= count;
|
|
|
|
int start = (i * cellsPerRow) + 1;
|
|
|
|
row.Controls.Add(GetLabel($"{start}-{start + count - 1}"));
|
|
|
|
for (int j = 0; j < count; j++)
|
|
|
|
{
|
2023-02-05 08:42:37 +00:00
|
|
|
var p = GetPictureBox(spriter.Width, spriter.Height, $"Row {i} Slot {start + j}");
|
2022-06-18 18:04:24 +00:00
|
|
|
row.Controls.Add(p);
|
|
|
|
pb.Add(p);
|
|
|
|
}
|
|
|
|
FLP_Gifts.Controls.Add(row);
|
2017-10-01 01:25:21 +00:00
|
|
|
}
|
2022-06-18 18:04:24 +00:00
|
|
|
return pb;
|
|
|
|
}
|
|
|
|
|
|
|
|
private static FlowLayoutPanel GetFlowLayoutPanel() => new()
|
|
|
|
{
|
|
|
|
Width = 490,
|
|
|
|
Height = 60,
|
|
|
|
Padding = new Padding(0),
|
|
|
|
Margin = new Padding(0),
|
|
|
|
};
|
|
|
|
|
|
|
|
private static Label GetLabel(string text) => new()
|
|
|
|
{
|
|
|
|
Size = new Size(50, 60),
|
|
|
|
AutoSize = false,
|
|
|
|
TextAlign = ContentAlignment.MiddleRight,
|
|
|
|
Text = text,
|
|
|
|
Padding = new Padding(0),
|
|
|
|
Margin = new Padding(0),
|
|
|
|
};
|
|
|
|
|
2023-02-05 08:42:37 +00:00
|
|
|
private static SelectablePictureBox GetPictureBox(int width, int height, string name) => new()
|
2022-06-18 18:04:24 +00:00
|
|
|
{
|
|
|
|
Size = new Size(width + 2, height + 2), // +1 to each side for the FixedSingle border
|
|
|
|
SizeMode = PictureBoxSizeMode.CenterImage,
|
|
|
|
BorderStyle = BorderStyle.FixedSingle,
|
|
|
|
BackColor = SlotUtil.GoodDataColor,
|
|
|
|
Padding = new Padding(0),
|
|
|
|
Margin = new Padding(1),
|
2023-02-05 08:42:37 +00:00
|
|
|
Name = name,
|
|
|
|
AccessibleName = name,
|
|
|
|
AccessibleRole = AccessibleRole.Graphic,
|
2022-06-18 18:04:24 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
private void B_ModifyAll_Click(object sender, EventArgs e)
|
|
|
|
{
|
|
|
|
foreach (var g in mga.Gifts)
|
|
|
|
g.GiftUsed = sender == B_UsedAll;
|
|
|
|
SetGiftBoxes();
|
|
|
|
System.Media.SystemSounds.Asterisk.Play();
|
|
|
|
}
|
2020-01-26 19:19:58 +00:00
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
private void LB_Received_KeyDown(object sender, KeyEventArgs e)
|
|
|
|
{
|
|
|
|
if (e.KeyCode == Keys.Delete)
|
2020-01-26 19:19:58 +00:00
|
|
|
{
|
2022-06-18 18:04:24 +00:00
|
|
|
if (LB_Received.SelectedIndices.Count > 1)
|
2021-03-14 23:16:55 +00:00
|
|
|
{
|
2022-06-18 18:04:24 +00:00
|
|
|
for (int i = LB_Received.SelectedIndices.Count - 1; i >= 0; i--)
|
|
|
|
LB_Received.Items.RemoveAt(LB_Received.SelectedIndices[i]);
|
|
|
|
}
|
|
|
|
else if (LB_Received.SelectedIndices.Count == 1)
|
|
|
|
{
|
|
|
|
int lastIndex = LB_Received.SelectedIndex;
|
|
|
|
LB_Received.Items.RemoveAt(lastIndex);
|
|
|
|
if (LB_Received.Items.Count == 0)
|
|
|
|
return;
|
|
|
|
if (lastIndex == LB_Received.Items.Count)
|
|
|
|
lastIndex--;
|
|
|
|
LB_Received.SelectedIndex = lastIndex;
|
2020-01-26 19:19:58 +00:00
|
|
|
}
|
|
|
|
}
|
2016-04-22 02:16:55 +00:00
|
|
|
}
|
2022-06-18 18:04:24 +00:00
|
|
|
}
|