mirror of
https://github.com/kwsch/PKHeX.git
synced 2026-05-06 05:27:14 -05:00
Add sort pointer repointing
LGPE uses a list of pkm for boxes, and has pointers indicating where each party member is at need some logic for handling the sorting. Had suspected this a while back so this pre-work came in handy (untested tho) make eventflags offset ptr virtual, I might end up doing things differently for event flags
This commit is contained in:
parent
73ee5e5afd
commit
98ebf4c5cb
|
|
@ -141,6 +141,8 @@ public static int GetMaxSpeciesID(this GameVersion game)
|
|||
return Legal.MaxSpeciesID_7;
|
||||
if (USUM.Contains(game))
|
||||
return Legal.MaxSpeciesID_7_USUM;
|
||||
if (GG.Contains(game))
|
||||
return Legal.MaxSpeciesID_7b;
|
||||
return Legal.MaxSpeciesID_7_USUM;
|
||||
}
|
||||
return -1;
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ public class SearchSettings
|
|||
{
|
||||
public int Format { private get; set; }
|
||||
public int Generation { private get; set; }
|
||||
public int Species { private get; set; } = -1;
|
||||
public int Species { get; set; } = -1;
|
||||
public int Ability { private get; set; } = -1;
|
||||
public int Nature { private get; set; } = -1;
|
||||
public int Item { private get; set; } = -1;
|
||||
|
|
@ -23,7 +23,7 @@ public class SearchSettings
|
|||
|
||||
public bool? SearchShiny { private get; set; }
|
||||
public bool? SearchLegal { private get; set; }
|
||||
public bool? SearchEgg { private get; set; }
|
||||
public bool? SearchEgg { get; set; }
|
||||
public int? ESV { private get; set; }
|
||||
public int? Level { private get; set; }
|
||||
|
||||
|
|
@ -33,7 +33,7 @@ public class SearchSettings
|
|||
public CloneDetectionMethod SearchClones { private get; set; }
|
||||
public IList<string> BatchInstructions { private get; set; }
|
||||
|
||||
private readonly List<int> Moves = new List<int>();
|
||||
public readonly List<int> Moves = new List<int>();
|
||||
|
||||
// ReSharper disable once CollectionNeverUpdated.Global
|
||||
/// <summary>
|
||||
|
|
@ -134,5 +134,19 @@ private IEnumerable<PKM> FilterResultEgg(IEnumerable<PKM> res)
|
|||
return res.Where(pk => pk.IsEgg && pk.PSV == ESV);
|
||||
return res.Where(pk => pk.IsEgg);
|
||||
}
|
||||
|
||||
public GameVersion[] GetVersions(SaveFile SAV, GameVersion fallback)
|
||||
{
|
||||
if (Version > 0)
|
||||
return new[] {(GameVersion) Version};
|
||||
if (Generation != 0)
|
||||
{
|
||||
return fallback.GetGeneration() == Generation
|
||||
? GameUtil.GetVersionsWithinRange(SAV, Generation).ToArray()
|
||||
: GameUtil.GameVersions;
|
||||
}
|
||||
|
||||
return GameUtil.GameVersions;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -489,8 +489,9 @@ public static uint GetRandomPID(int species, int cg, int origin, int nature, int
|
|||
// Data Requests
|
||||
public static string GetResourceStringBall(int ball) => $"_ball{ball}";
|
||||
private const string ResourceSeparator = "_";
|
||||
private const string ResourcePikachuCosplay = "c";
|
||||
private const string ResourceShiny = "s";
|
||||
private const string ResourcePikachuCosplay = "c"; // osplay
|
||||
private const string ResourceShiny = "s"; // hiny
|
||||
private const string ResourceGGStarter = "p"; //artner
|
||||
public static bool AllowShinySprite { get; set; }
|
||||
|
||||
public static string GetResourceStringSprite(int species, int form, int gender, int generation = Generation, bool shiny = false)
|
||||
|
|
@ -507,6 +508,9 @@ public static string GetResourceStringSprite(int species, int form, int gender,
|
|||
|
||||
if (species == 25 && form > 0 && generation == 6) // Cosplay Pikachu
|
||||
sb.Append(ResourcePikachuCosplay);
|
||||
else if (GameVersion.GG.Contains(PKMConverter.Trainer.Game) && (species == 25 || species == 133) && form != 0)
|
||||
sb.Append(ResourceGGStarter);
|
||||
|
||||
if (shiny && AllowShinySprite)
|
||||
sb.Append(ResourceShiny);
|
||||
return sb.ToString();
|
||||
|
|
@ -783,9 +787,10 @@ public static string GetLocationString(this PKM pk, bool eggmet)
|
|||
/// <param name="list">Source list to copy from</param>
|
||||
/// <param name="dest">Destination list/array</param>
|
||||
/// <param name="sav">Context for checking slot write protection</param>
|
||||
/// <param name="skip">Criteria for skipping a slot</param>
|
||||
/// <param name="start">Starting point to copy to</param>
|
||||
/// <returns>Count of <see cref="PKM"/> copied.</returns>
|
||||
public static int CopyTo(this IEnumerable<PKM> list, IList<PKM> dest, SaveFile sav, int start = 0)
|
||||
public static int CopyTo(this IEnumerable<PKM> list, IList<PKM> dest, SaveFile sav, Func<int, int, bool> skip, int start = 0)
|
||||
{
|
||||
int ctr = start;
|
||||
foreach (var z in list)
|
||||
|
|
@ -793,7 +798,7 @@ public static int CopyTo(this IEnumerable<PKM> list, IList<PKM> dest, SaveFile s
|
|||
if (dest.Count <= ctr)
|
||||
break;
|
||||
var exist = dest[ctr];
|
||||
if (exist != null && sav.IsSlotOverwriteProtected(exist.Box, exist.Slot))
|
||||
if (exist != null && skip(exist.Box, exist.Slot))
|
||||
continue;
|
||||
dest[ctr++] = z;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -117,7 +117,7 @@ protected virtual byte[] Write(bool DSV)
|
|||
public virtual bool HasBoxWallpapers => GetBoxWallpaperOffset(0) > -1;
|
||||
public virtual bool HasNamableBoxes => HasBoxWallpapers;
|
||||
public bool HasPokeBlock => ORAS && !ORASDEMO;
|
||||
public bool HasEvents => EventFlags != null;
|
||||
public virtual bool HasEvents => EventFlags != null;
|
||||
public bool HasLink => (ORAS && !ORASDEMO) || XY;
|
||||
|
||||
// Counts
|
||||
|
|
@ -454,6 +454,7 @@ public bool IsPartyAllEggs(params int[] except)
|
|||
public virtual int CurrentBox { get => 0; set { } }
|
||||
protected int[] LockedSlots = Array.Empty<int>();
|
||||
protected int[] TeamSlots = Array.Empty<int>();
|
||||
protected virtual IList<int>[] SlotPointers => new[] {LockedSlots,TeamSlots};
|
||||
|
||||
public bool MoveBox(int box, int insertBeforeBox)
|
||||
{
|
||||
|
|
@ -491,6 +492,8 @@ public bool MoveBox(int box, int insertBeforeBox)
|
|||
SetBoxName(b, boxNames[i]);
|
||||
SetBoxWallpaper(b, boxWallpapers[i]);
|
||||
}
|
||||
SlotPointerUtil.UpdateMove(box, insertBeforeBox, BoxSlotCount, SlotPointers);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -522,6 +525,10 @@ public bool SwapBox(int box1, int box2)
|
|||
int b1w = GetBoxWallpaper(box1);
|
||||
SetBoxWallpaper(box1, GetBoxWallpaper(box2));
|
||||
SetBoxWallpaper(box2, b1w);
|
||||
|
||||
// Pointers
|
||||
SlotPointerUtil.UpdateSwap(box1, box2, BoxSlotCount, SlotPointers);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -657,21 +664,23 @@ public void DeletePartySlot(int slot)
|
|||
|
||||
public virtual bool IsSlotLocked(int box, int slot) => false;
|
||||
public virtual bool IsSlotInBattleTeam(int box, int slot) => false;
|
||||
|
||||
public bool IsSlotOverwriteProtected(int box, int slot) => IsSlotLocked(box, slot) || IsSlotInBattleTeam(box, slot);
|
||||
protected virtual bool IsSlotOverwriteProtected(int box, int slot) => IsSlotLocked(box, slot) || IsSlotInBattleTeam(box, slot);
|
||||
protected virtual bool IsSlotSwapProtected(int box, int slot) => false;
|
||||
|
||||
private bool IsRegionOverwriteProtected(int min, int max)
|
||||
{
|
||||
if (LockedSlots.Any(slot => min <= slot && slot < max)) // locked slot within box
|
||||
if (LockedSlots.Any(slot => WithinRange(slot, min, max))) // locked slot within box
|
||||
return true;
|
||||
if (TeamSlots.Any(slot => min <= slot && slot < max)) // team slot within box
|
||||
if (TeamSlots.Any(slot => WithinRange(slot, min, max))) // team slot within box
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool WithinRange(int slot, int min, int max) => min <= slot && slot < max;
|
||||
|
||||
public bool IsAnySlotLockedInBox(int BoxStart, int BoxEnd)
|
||||
{
|
||||
return LockedSlots.Any(slot => BoxStart*BoxSlotCount <= slot && slot < (BoxEnd + 1)*BoxSlotCount);
|
||||
return LockedSlots.Any(slot => WithinRange(slot, BoxStart*BoxSlotCount, (BoxEnd + 1)*BoxSlotCount));
|
||||
}
|
||||
|
||||
public void SortBoxes(int BoxStart = 0, int BoxEnd = -1, Func<IEnumerable<PKM>, IEnumerable<PKM>> sortMethod = null, bool reverse = false)
|
||||
|
|
@ -682,13 +691,19 @@ public void SortBoxes(int BoxStart = 0, int BoxEnd = -1, Func<IEnumerable<PKM>,
|
|||
if (BoxEnd >= BoxStart)
|
||||
Section = Section.Take(BoxSlotCount * (BoxEnd - BoxStart + 1));
|
||||
|
||||
Section = Section.Where(z => !IsSlotOverwriteProtected(z.Box, z.Slot));
|
||||
Func<int, int, bool> skip = IsSlotSwapProtected;
|
||||
Section = Section.Where(z => !skip(z.Box, z.Slot));
|
||||
var Sorted = (sortMethod ?? PKMSorting.OrderBySpecies)(Section);
|
||||
if (reverse)
|
||||
Sorted = Sorted.ReverseSort();
|
||||
|
||||
Sorted.CopyTo(BD, this, start);
|
||||
BoxData = BD;
|
||||
var result = Sorted.ToArray();
|
||||
var boxclone = new PKM[BD.Count];
|
||||
BD.CopyTo(boxclone, 0);
|
||||
result.CopyTo(boxclone, this, skip, start);
|
||||
|
||||
SlotPointerUtil.UpdateRepointFrom(boxclone, BD, 0, SlotPointers);
|
||||
BoxData = boxclone;
|
||||
}
|
||||
|
||||
public void ClearBoxes(int BoxStart = 0, int BoxEnd = -1, Func<PKM, bool> deleteCriteria = null)
|
||||
|
|
@ -751,7 +766,7 @@ public bool SetPCBinary(byte[] data)
|
|||
|
||||
var BD = BoxData;
|
||||
var pkdata = PKX.GetPKMDataFromConcatenatedBinary(data, BlankPKM.EncryptedBoxData.Length);
|
||||
pkdata.Select(z => GetPKM(DecryptPKM(z))).CopyTo(BD, this);
|
||||
pkdata.Select(z => GetPKM(DecryptPKM(z))).CopyTo(BD, this, IsSlotOverwriteProtected);
|
||||
BoxData = BD;
|
||||
return true;
|
||||
}
|
||||
|
|
@ -767,7 +782,7 @@ public bool SetBoxBinary(byte[] data, int box)
|
|||
|
||||
var BD = BoxData;
|
||||
var pkdata = PKX.GetPKMDataFromConcatenatedBinary(data, BlankPKM.EncryptedBoxData.Length);
|
||||
pkdata.Select(z => GetPKM(DecryptPKM(z))).CopyTo(BD, this, start);
|
||||
pkdata.Select(z => GetPKM(DecryptPKM(z))).CopyTo(BD, this, IsSlotOverwriteProtected, start);
|
||||
BoxData = BD;
|
||||
return true;
|
||||
}
|
||||
|
|
@ -832,7 +847,7 @@ public bool IsRangeAll(int Offset, int Length, int value)
|
|||
/// <param name="storedCount">Count of actual <see cref="PKM"/> stored.</param>
|
||||
/// <param name="slotPointers">Important slot pointers that need to be repointed if a slot moves.</param>
|
||||
/// <returns>True if <see cref="BoxData"/> was updated, false if no update done.</returns>
|
||||
public bool CompressStorage(out int storedCount, params ushort[][] slotPointers)
|
||||
public bool CompressStorage(out int storedCount, params IList<int>[] slotPointers)
|
||||
{
|
||||
// keep track of empty slots, and only write them at the end if slots were shifted (no need otherwise).
|
||||
var empty = new List<byte[]>();
|
||||
|
|
@ -850,14 +865,7 @@ public bool CompressStorage(out int storedCount, params ushort[][] slotPointers)
|
|||
{
|
||||
shiftedSlots = true; // appending empty slots afterwards is now required since a rewrite was done
|
||||
Buffer.BlockCopy(Data, offset, Data, Box + (ctr * size), size);
|
||||
foreach (var ptrSet in slotPointers)
|
||||
{
|
||||
for (int j = 0; j < ptrSet.Length; j++) // update ptr
|
||||
{
|
||||
if (ptrSet[j] == i)
|
||||
ptrSet[j] = ctr;
|
||||
}
|
||||
}
|
||||
SlotPointerUtil.UpdateRepointFrom(ctr, i, slotPointers);
|
||||
}
|
||||
ctr++;
|
||||
continue;
|
||||
|
|
|
|||
98
PKHeX.Core/Saves/Storage/SlotPointerUtil.cs
Normal file
98
PKHeX.Core/Saves/Storage/SlotPointerUtil.cs
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace PKHeX.Core
|
||||
{
|
||||
public static class SlotPointerUtil
|
||||
{
|
||||
private static bool WithinRange(int slot, int min, int max) => min <= slot && slot < max;
|
||||
|
||||
public static void UpdateSwap(int b1, int b2, int slotsPerBox, params IList<int>[] ptrset)
|
||||
{
|
||||
int diff = (b1 - b2) * slotsPerBox;
|
||||
|
||||
int b1s = b1 * slotsPerBox;
|
||||
int b1e = b1s + slotsPerBox;
|
||||
int b12 = b1 > b2 ? -diff : diff;
|
||||
|
||||
int b2s = b2 * slotsPerBox;
|
||||
int b2e = b2s + slotsPerBox;
|
||||
int b21 = b2 > b1 ? -diff : diff;
|
||||
foreach (var list in ptrset)
|
||||
{
|
||||
for (int s = 0; s < list.Count; s++)
|
||||
{
|
||||
if (WithinRange(b1s, b1e, list[s]))
|
||||
list[s] += b12;
|
||||
else if (WithinRange(b2s, b2e, list[s]))
|
||||
list[s] += b21;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void UpdateRepointFrom(IList<PKM> result, IList<PKM> bd, int start, params IList<int>[] slotPointers)
|
||||
{
|
||||
foreach (var p in slotPointers)
|
||||
{
|
||||
for (int i = 0; i < p.Count; i++)
|
||||
{
|
||||
var index = p[i];
|
||||
if (index >= bd.Count)
|
||||
continue;
|
||||
var pk = bd[index];
|
||||
var newIndex = result.IndexOf(pk);
|
||||
if (newIndex < 0)
|
||||
continue;
|
||||
|
||||
Debug.WriteLine($"Repointing {pk.Nickname} from ({pk.Box}|{pk.Slot}) to {newIndex}");
|
||||
Debug.WriteLine($"{result[newIndex]}");
|
||||
p[i] = start + newIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void UpdateRepointFrom(int newIndex, int oldIndex, params IList<int>[] slotPointers)
|
||||
{
|
||||
foreach (var p in slotPointers)
|
||||
{
|
||||
for (int s = 0; s < p.Count; s++)
|
||||
{
|
||||
if (p[s] != oldIndex)
|
||||
continue;
|
||||
p[s] = newIndex;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void UpdateMove(int bMove, int cMove, int slotsPerBox, params IList<int>[] ptrset)
|
||||
{
|
||||
int bStart = bMove * slotsPerBox;
|
||||
int cStart = cMove * slotsPerBox;
|
||||
int bEnd = bStart + slotsPerBox;
|
||||
int cEnd = cStart + slotsPerBox;
|
||||
int cShift;
|
||||
int bShift;
|
||||
if (bMove < cMove) // shift chunk down, shift box up
|
||||
{
|
||||
cShift = -slotsPerBox;
|
||||
bShift = (cStart - bStart);
|
||||
}
|
||||
else // shift box down, shift chunk up
|
||||
{
|
||||
cShift = slotsPerBox;
|
||||
bShift = -(bStart - cStart);
|
||||
}
|
||||
foreach (var list in ptrset)
|
||||
{
|
||||
for (int s = 0; s < list.Count; s++)
|
||||
{
|
||||
if (WithinRange(cStart, cEnd, list[s]))
|
||||
list[s] += cShift;
|
||||
if (WithinRange(bStart, bEnd, list[s]))
|
||||
list[s] += bShift;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user