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:
Kurt 2018-11-10 21:04:24 -08:00
parent 73ee5e5afd
commit 98ebf4c5cb
5 changed files with 154 additions and 27 deletions

View File

@ -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;

View File

@ -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;
}
}
}

View File

@ -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;
}

View File

@ -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;

View 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;
}
}
}
}
}