mirror of
https://github.com/kwsch/PKHeX
synced 2025-02-17 05:48:44 +00:00
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:
parent
65e19e7f8b
commit
251dc9c46a
7 changed files with 144 additions and 22 deletions
|
@ -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)
|
||||
|
|
|
@ -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 |
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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))
|
||||
{
|
||||
|
|
Loading…
Add table
Reference in a new issue