Add locked slot indication and write protection

Reinterpreted #637, now utilizing the lock symbol (cropped to 30px
vertical height) to indicate strongly that the slot is locked (which can
only be viewed).
This commit is contained in:
Kurt 2016-12-15 23:17:17 -08:00
parent 65e19e7f8b
commit 251dc9c46a
7 changed files with 144 additions and 22 deletions

View file

@ -711,10 +711,30 @@ namespace PKHeX
#region PC/Box Data
else if (BitConverter.ToUInt16(input, 4) == 0 && BitConverter.ToUInt32(input, 8) > 0 && PKX.getIsPKM(input.Length / SAV.BoxSlotCount / SAV.BoxCount) || PKX.getIsPKM(input.Length / SAV.BoxSlotCount))
{
if (SAV.setPCBin(input))
Util.Alert("PC Binary loaded.");
else if (SAV.setBoxBin(input, CB_BoxSelect.SelectedIndex))
Util.Alert("Box Binary loaded.");
if (SAV.getPCBin().Length == input.Length)
{
if (SAV.getBoxHasLockedSlot(0, SAV.BoxCount - 1))
Util.Alert("Battle Box slots prevent loading of PC data.");
else if (SAV.setPCBin(input))
Util.Alert("PC Binary loaded.");
else
{
Util.Alert("Binary is not compatible with save file.", "Current SAV Generation: " + SAV.Generation);
return;
}
}
else if (SAV.getBoxBin(CB_BoxSelect.SelectedIndex).Length == input.Length)
{
if (SAV.getBoxHasLockedSlot(CB_BoxSelect.SelectedIndex, CB_BoxSelect.SelectedIndex))
Util.Alert("Battle Box slots in box prevent loading of box data.");
else if (SAV.setBoxBin(input, CB_BoxSelect.SelectedIndex))
Util.Alert("Box Binary loaded.");
else
{
Util.Alert("Binary is not compatible with save file.", "Current SAV Generation: " + SAV.Generation);
return;
}
}
else
{
Util.Alert("Binary is not compatible with save file.", "Current SAV Generation: " + SAV.Generation);
@ -737,8 +757,16 @@ namespace PKHeX
bool? noSetb = getPKMSetOverride();
PKM[] data = b.BattlePKMs;
int offset = SAV.getBoxOffset(CB_BoxSelect.SelectedIndex);
int slotSkipped = 0;
for (int i = 0; i < 24; i++)
{
if (SAV.getIsSlotLocked(CB_BoxSelect.SelectedIndex, i))
{ slotSkipped++; continue; }
SAV.setStoredSlot(data[i], offset + i*SAV.SIZE_STORED, noSetb);
}
if (slotSkipped > 0)
Util.Alert($"Skipped {slotSkipped} locked slot{(slotSkipped > 1 ? "s" : "")}.");
setPKXBoxes();
updateBoxViewers();
@ -3124,23 +3152,31 @@ namespace PKHeX
bool all = false;
if (ModifierKeys == (Keys.Alt | Keys.Shift) && DialogResult.Yes == Util.Prompt(MessageBoxButtons.YesNo, "Clear ALL Boxes?!"))
{
if (SAV.getBoxHasLockedSlot(0, SAV.BoxCount - 1))
{ Util.Alert("Battle Box slots prevent the clearing of all boxes."); return; }
SAV.resetBoxes();
modified = "Boxes cleared!";
all = true;
}
else if (ModifierKeys == Keys.Alt && DialogResult.Yes == Util.Prompt(MessageBoxButtons.YesNo, "Clear Current Box?"))
{
if (SAV.getBoxHasLockedSlot(CB_BoxSelect.SelectedIndex, CB_BoxSelect.SelectedIndex))
{ Util.Alert("Battle Box slots prevent the clearing of box."); return; }
SAV.resetBoxes(CB_BoxSelect.SelectedIndex, CB_BoxSelect.SelectedIndex + 1);
modified = "Current Box cleared!";
}
else if (ModifierKeys == (Keys.Control | Keys.Shift) && DialogResult.Yes == Util.Prompt(MessageBoxButtons.YesNo, "Sort ALL Boxes?!"))
{
if (SAV.getBoxHasLockedSlot(0, SAV.BoxCount - 1))
{ Util.Alert("Battle Box slots prevent the sorting of all boxes."); return; }
SAV.sortBoxes();
modified = "Boxes sorted!";
all = true;
}
else if (ModifierKeys == Keys.Control && DialogResult.Yes == Util.Prompt(MessageBoxButtons.YesNo, "Sort Current Box?"))
{
if (SAV.getBoxHasLockedSlot(CB_BoxSelect.SelectedIndex, CB_BoxSelect.SelectedIndex))
{ Util.Alert("Battle Box slots prevent the sorting of box."); return; }
SAV.sortBoxes(CB_BoxSelect.SelectedIndex, CB_BoxSelect.SelectedIndex + 1);
modified = "Current Box sorted!";
}
@ -3231,6 +3267,8 @@ namespace PKHeX
int slot = getSlot(sender);
if (slot == 30 && (CB_Species.SelectedIndex == 0 || CHK_IsEgg.Checked))
{ Util.Alert("Can't have empty/egg first slot."); return; }
if (SAV.getIsSlotLocked(CB_BoxSelect.SelectedIndex, slot))
{ Util.Alert("Can't set to locked slot."); return; }
int offset = getPKXOffset(slot);
if (offset < 0)
@ -3279,7 +3317,10 @@ namespace PKHeX
private void clickDelete(object sender, EventArgs e)
{
int slot = getSlot(sender);
if (slot == 30 && SAV.PartyCount == 1 && !HaX) { Util.Alert("Can't delete first slot."); return; }
if (slot == 30 && SAV.PartyCount == 1 && !HaX)
{ Util.Alert("Can't delete first slot."); return; }
if (SAV.getIsSlotLocked(CB_BoxSelect.SelectedIndex, slot))
{ Util.Alert("Can't delete locked slot."); return; }
int offset = getPKXOffset(slot);
if (offset < 0)
@ -3382,11 +3423,18 @@ namespace PKHeX
PKM pk = preparePKM();
int slotSkipped = 0;
for (int i = 0; i < 30; i++) // set to every slot in box
{
if (SAV.getIsSlotLocked(CB_BoxSelect.SelectedIndex, i))
{ slotSkipped++; continue; }
SAV.setStoredSlot(pk, getPKXOffset(i));
getQuickFiller(SlotPictureBoxes[i], pk);
}
if (slotSkipped > 0)
Util.Alert($"Skipped {slotSkipped} locked slot{(slotSkipped > 1 ? "s" : "")}.");
updateBoxViewers();
}
private void clickLegality(object sender, EventArgs e)
@ -3709,7 +3757,13 @@ namespace PKHeX
pk = pk ?? preparePKM(false); // don't perform control loss click
if (pb == dragout) mnuLQR.Enabled = pk.Species != 0; // Species
pb.Image = pk.Species != 0 ? pk.Sprite : null;
var sprite = pk.Species != 0 ? pk.Sprite : null;
int slot = getSlot(pb);
bool locked = slot < 30 && SAV.getIsSlotLocked(CB_BoxSelect.SelectedIndex, slot);
if (locked)
sprite = Util.LayerImage(sprite, Properties.Resources.locked, 5, 0, 1);
pb.Image = sprite;
if (pb.BackColor == Color.Red)
pb.BackColor = Color.Transparent;
}
@ -3733,7 +3787,13 @@ namespace PKHeX
return;
}
// Something stored in slot. Only display if species is valid.
pb.Image = p.Species == 0 ? null : p.Sprite;
var sprite = p.Species != 0 ? p.Sprite : null;
int slot = getSlot(pb);
bool locked = slot < 30 && SAV.getIsSlotLocked(CB_BoxSelect.SelectedIndex, slot);
if (locked)
sprite = Util.LayerImage(sprite, Properties.Resources.locked, 5, 0, 1);
pb.Image = sprite;
pb.BackColor = Color.Transparent;
pb.Visible = true;
}
@ -4089,17 +4149,21 @@ namespace PKHeX
if (pb.Image == null)
return;
int slot = getSlot(pb);
int box = slot >= 30 ? -1 : CB_BoxSelect.SelectedIndex;
if (SAV.getIsSlotLocked(box, slot))
return;
// Set flag to prevent re-entering.
DragInfo.slotDragDropInProgress = true;
DragInfo.slotSource = this;
DragInfo.slotSourceSlotNumber = getSlot(pb);
int offset = getPKXOffset(DragInfo.slotSourceSlotNumber);
DragInfo.slotSourceSlotNumber = slot;
DragInfo.slotSourceBoxNumber = box;
DragInfo.slotSourceOffset = getPKXOffset(DragInfo.slotSourceSlotNumber);
// Prepare Data
DragInfo.slotPkmSource = SAV.getData(offset, SAV.SIZE_STORED);
DragInfo.slotSourceOffset = offset;
DragInfo.slotSourceBoxNumber = DragInfo.slotSourceSlotNumber >= 30 ? -1 : CB_BoxSelect.SelectedIndex;
DragInfo.slotPkmSource = SAV.getData(DragInfo.slotSourceOffset, SAV.SIZE_STORED);
// Make a new file name based off the PID
bool encrypt = ModifierKeys == Keys.Control;
@ -4161,6 +4225,12 @@ namespace PKHeX
// Check for In-Dropped files (PKX,SAV,ETC)
string[] files = (string[])e.Data.GetData(DataFormats.FileDrop);
if (Directory.Exists(files[0])) { loadBoxesFromDB(files[0]); return; }
if (SAV.getIsSlotLocked(DragInfo.slotDestinationBoxNumber, DragInfo.slotDestinationSlotNumber))
{
DragInfo.slotDestinationSlotNumber = -1; // Invalidate
Util.Alert("Unable to set to locked slot.");
return;
}
if (DragInfo.slotSourceOffset < 0) // file
{
if (files.Length <= 0)

View file

@ -258,6 +258,7 @@ namespace PKHeX
// Derived
public virtual int SpriteItem => HeldItem;
public virtual bool IsShiny => TSV == PSV;
public virtual bool Locked { get { return false; } set { } }
public int TrainerID7 => (int)((uint)(TID | (SID << 16)) % 1000000);
public bool Gen7 => Version >= 30 && Version <= 31;
public bool Gen6 => Version >= 24 && Version <= 29;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View file

@ -25,11 +25,19 @@ namespace PKHeX
if (!Exportable)
resetBoxes();
var demo = new byte[0x4C4].SequenceEqual(Data.Skip(PCLayout).Take(0x4C4));
var demo = new byte[0x4C4].SequenceEqual(Data.Skip(PCLayout).Take(0x4C4)); // up to Battle Box values
if (demo)
{
PokeDex = -1; // Disabled
}
int lockedCount = 0;
for (int i = 0; i < LockedSlots.Length; i++)
{
short val = BitConverter.ToInt16(Data, BattleBoxFlags + i * 2);
if (val >= 0)
LockedSlots[lockedCount++] = (val & 0xFF + BoxSlotCount*(val >> 8)) & 0xFFFF;
}
Array.Resize(ref LockedSlots, lockedCount);
}
// Configuration
@ -219,11 +227,13 @@ namespace PKHeX
PokeDexLanguageFlags = PokeDex + 0x550;
WondercardData = WondercardFlags + 0x100;
BattleBoxFlags = PCLayout + 0x4C4;
PCBackgrounds = PCLayout + 0x5C0;
LastViewedBox = PCLayout + 0x5E3;
PCFlags = PCLayout + 0x5E0;
FashionLength = 0x1A08;
LockedSlots = new int[36];
}
else // Empty input
{
@ -245,6 +255,7 @@ namespace PKHeX
private int JoinFestaData { get; set; } = int.MinValue;
private int PokeFinderSave { get; set; } = int.MinValue;
private int BattleTree { get; set; } = int.MinValue;
private int BattleBoxFlags { get; set; } = int.MinValue;
// Accessible as SAV7
public int TrainerCard { get; private set; } = 0x14000;
@ -863,6 +874,14 @@ namespace PKHeX
protected set { Data[Party + 6 * SIZE_PARTY] = (byte)value; }
}
public override int BoxesUnlocked { get { return Data[PCFlags + 1]; } set { Data[PCFlags + 1] = (byte)value; } }
public override bool getIsSlotLocked(int box, int slot)
{
if (slot >= 30 || box > BoxCount)
return true;
int slotIndex = slot + BoxSlotCount*box;
return LockedSlots.Any(s => s == slotIndex);
}
public override int DaycareSeedSize => 32; // 128 bits
public override int getDaycareSlotOffset(int loc, int slot)

View file

@ -206,6 +206,7 @@ namespace PKHeX
for (int i = 0; i < data.Length; i++)
{
data[i] = getStoredSlot(BattleBox + SIZE_STORED * i);
data[i].Locked = BattleBoxLocked;
if (data[i].Species == 0)
return data.Take(i).ToArray();
}
@ -352,6 +353,7 @@ namespace PKHeX
public virtual int BoxesUnlocked { get { return -1; } set { } }
public virtual byte[] BoxFlags { get { return null; } set { } }
public virtual int CurrentBox { get { return 0; } set { } }
protected int[] LockedSlots = new int[0];
protected virtual int getBoxWallpaperOffset(int box) { return -1; }
public int getBoxWallpaper(int box)
@ -451,6 +453,11 @@ namespace PKHeX
setStoredSlot(BlankPKM, getPartyOffset(5), false, false);
PartyCount -= 1;
}
public virtual bool getIsSlotLocked(int box, int slot) { return false; }
public bool getBoxHasLockedSlot(int BoxStart, int BoxEnd)
{
return LockedSlots.Any(slot => BoxStart*BoxSlotCount <= slot && slot < (BoxEnd + 1)*BoxSlotCount);
}
public void sortBoxes(int BoxStart = 0, int BoxEnd = -1)
{
@ -485,6 +492,8 @@ namespace PKHeX
public byte[] getBoxBin(int box) { return BoxData.Skip(box*BoxSlotCount).Take(BoxSlotCount).SelectMany(pk => pk.EncryptedBoxData).ToArray(); }
public bool setPCBin(byte[] data)
{
if (LockedSlots.Any())
return false;
if (data.Length != getPCBin().Length)
return false;
@ -506,6 +515,8 @@ namespace PKHeX
}
public bool setBoxBin(byte[] data, int box)
{
if (LockedSlots.Any(slot => box * BoxSlotCount <= slot && slot < (box + 1) * BoxSlotCount))
return false;
if (data.Length != getBoxBin(box).Length)
return false;
@ -553,6 +564,6 @@ namespace PKHeX
Edited = true;
}
public virtual bool RequiresMemeCrypto { get { return false; } }
public virtual bool RequiresMemeCrypto => false;
}
}

View file

@ -112,12 +112,22 @@ namespace PKHeX
return;
}
// Something stored in slot. Only display if species is valid.
pb.Image = p.Species == 0 ? null : p.Sprite;
var sprite = p.Species != 0 ? p.Sprite : null;
int slot = getSlot(pb);
bool locked = slot < 30 && SAV.getIsSlotLocked(CB_BoxSelect.SelectedIndex, slot);
if (locked)
sprite = Util.LayerImage(sprite, Properties.Resources.locked, 5, 0, 1);
pb.Image = sprite;
pb.BackColor = Color.Transparent;
}
private void getQuickFiller(PictureBox pb, PKM pk)
{
pb.Image = pk.Species == 0 ? null : pk.Sprite;
var sprite = pk.Species != 0 ? pk.Sprite : null;
int slot = getSlot(pb);
bool locked = slot < 30 && SAV.getIsSlotLocked(CB_BoxSelect.SelectedIndex, slot);
if (locked)
sprite = Util.LayerImage(sprite, Properties.Resources.locked, 5, 0, 1);
pb.Image = sprite;
if (pb.BackColor == Color.Red)
pb.BackColor = Color.Transparent;
}
@ -157,18 +167,21 @@ namespace PKHeX
if (pb.Image == null)
return;
int slot = getSlot(pb);
int box = slot >= 30 ? -1 : CB_BoxSelect.SelectedIndex;
if (SAV.getIsSlotLocked(box, slot))
return;
// Set flag to prevent re-entering.
DragInfo.slotDragDropInProgress = true;
DragInfo.slotSource = this;
DragInfo.slotSourceSlotNumber = getSlot(pb);
int offset = getPKXOffset(DragInfo.slotSourceSlotNumber);
DragInfo.slotSourceSlotNumber = slot;
DragInfo.slotSourceBoxNumber = box;
DragInfo.slotSourceOffset = getPKXOffset(DragInfo.slotSourceSlotNumber);
// Prepare Data
DragInfo.slotPkmSource = SAV.getData(offset, SAV.SIZE_STORED);
DragInfo.slotSourceOffset = offset;
DragInfo.slotSourceBoxNumber = CB_BoxSelect.SelectedIndex;
DragInfo.slotSource = this;
DragInfo.slotPkmSource = SAV.getData(DragInfo.slotSourceOffset, SAV.SIZE_STORED);
// Make a new file name based off the PID
byte[] dragdata = SAV.decryptPKM(DragInfo.slotPkmSource);
@ -225,6 +238,12 @@ namespace PKHeX
// Check for In-Dropped files (PKX,SAV,ETC)
string[] files = (string[])e.Data.GetData(DataFormats.FileDrop);
if (Directory.Exists(files[0])) { return; }
if (SAV.getIsSlotLocked(DragInfo.slotDestinationBoxNumber, DragInfo.slotDestinationSlotNumber))
{
DragInfo.slotDestinationSlotNumber = -1; // Invalidate
Util.Alert("Unable to set to locked slot.");
return;
}
if (DragInfo.slotSourceOffset < 0) // file
{
if (files.Length <= 0)

View file

@ -10,6 +10,8 @@ namespace PKHeX
// Image Layering/Blending Utility
internal static Bitmap LayerImage(Image baseLayer, Image overLayer, int x, int y, double trans)
{
if (baseLayer == null)
return overLayer as Bitmap;
Bitmap img = new Bitmap(baseLayer.Width, baseLayer.Height);
using (Graphics gr = Graphics.FromImage(img))
{