Add simple legal item filtering for giveall

Closes #3318

Gen8: if held item, only give if can be legally held; if dmax crystal, only give if available.
Gen8b: if held item, only give if can be legally held
Others: unimplemented; pull requests accepted.
This commit is contained in:
Kurt 2021-12-04 12:24:32 -08:00
parent 4cb80b5463
commit 9a1b2719ec
13 changed files with 73 additions and 45 deletions

View file

@ -344,6 +344,13 @@ namespace PKHeX.Core
}; };
#region Unreleased Items #region Unreleased Items
private const int DMAX_START = 1279;
private const int DMAX_END = 1578;
private const int DMAX_LEGAL_END = 1290; // ★Sgr7194 (Eevee)
public static bool IsDynamaxCrystal(ushort item) => item is >= DMAX_START and <= DMAX_END;
public static bool IsDynamaxCrystalAvailable(ushort item) => item is >= DMAX_START and <= DMAX_LEGAL_END;
internal static readonly bool[] ReleasedHeldItems_8 = GetPermitList(MaxItemID_8, HeldItems_SWSH, new ushort[] internal static readonly bool[] ReleasedHeldItems_8 = GetPermitList(MaxItemID_8, HeldItems_SWSH, new ushort[]
{ {
298, // Flame Plate 298, // Flame Plate

View file

@ -63,14 +63,14 @@ namespace PKHeX.Core
{ {
var pouches = new[] var pouches = new[]
{ {
MakePouch(InventoryType.Items), MakePouch(InventoryType.Items, IsHeldItemLegal),
MakePouch(InventoryType.KeyItems), MakePouch(InventoryType.KeyItems),
MakePouch(InventoryType.TMHMs), MakePouch(InventoryType.TMHMs, IsHeldItemLegal),
MakePouch(InventoryType.Medicine), MakePouch(InventoryType.Medicine, IsHeldItemLegal),
MakePouch(InventoryType.Berries), MakePouch(InventoryType.Berries, IsHeldItemLegal),
MakePouch(InventoryType.Balls), MakePouch(InventoryType.Balls, IsHeldItemLegal),
MakePouch(InventoryType.BattleItems), MakePouch(InventoryType.BattleItems, IsHeldItemLegal),
MakePouch(InventoryType.Treasure), MakePouch(InventoryType.Treasure, IsHeldItemLegal),
}; };
return pouches.LoadAll(Data); return pouches.LoadAll(Data);
} }
@ -103,13 +103,15 @@ namespace PKHeX.Core
} }
} }
private InventoryPouch8b MakePouch(InventoryType type) private InventoryPouch8b MakePouch(InventoryType type, Func<ushort, bool>? isLegal = null)
{ {
ushort[] legal = GetLegal(type); ushort[] legal = GetLegal(type);
var max = GetMax(type); var max = GetMax(type);
return new InventoryPouch8b(type, legal, max, Offset); return new InventoryPouch8b(type, legal, max, Offset, isLegal);
} }
public static bool IsHeldItemLegal(ushort item) => !Legal.HeldItems_BS.Contains(item) || Legal.ReleasedHeldItems_8b[item];
private static int GetMax(InventoryType type) => type switch private static int GetMax(InventoryType type) => type switch
{ {
InventoryType.Items => 999, InventoryType.Items => 999,

View file

@ -1,4 +1,5 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
namespace PKHeX.Core namespace PKHeX.Core
{ {
@ -22,14 +23,14 @@ namespace PKHeX.Core
{ {
var pouch = new InventoryPouch[] var pouch = new InventoryPouch[]
{ {
new InventoryPouch8(InventoryType.Medicine, Legal.Pouch_Medicine_SWSH, 999, Medicine, PouchSize8.Medicine), new InventoryPouch8(InventoryType.Medicine, Legal.Pouch_Medicine_SWSH, 999, Medicine, PouchSize8.Medicine, IsItemLegal),
new InventoryPouch8(InventoryType.Balls, Legal.Pouch_Ball_SWSH, 999, Balls, PouchSize8.Balls), new InventoryPouch8(InventoryType.Balls, Legal.Pouch_Ball_SWSH, 999, Balls, PouchSize8.Balls, IsItemLegal),
new InventoryPouch8(InventoryType.BattleItems, Legal.Pouch_Battle_SWSH, 999, Battle, PouchSize8.Battle), new InventoryPouch8(InventoryType.BattleItems, Legal.Pouch_Battle_SWSH, 999, Battle, PouchSize8.Battle, IsItemLegal),
new InventoryPouch8(InventoryType.Berries, Legal.Pouch_Berries_SWSH, 999, Berries, PouchSize8.Berries), new InventoryPouch8(InventoryType.Berries, Legal.Pouch_Berries_SWSH, 999, Berries, PouchSize8.Berries, IsItemLegal),
new InventoryPouch8(InventoryType.Items, Legal.Pouch_Regular_SWSH, 999, Items, PouchSize8.Items), new InventoryPouch8(InventoryType.Items, Legal.Pouch_Regular_SWSH, 999, Items, PouchSize8.Items, IsItemLegal),
new InventoryPouch8(InventoryType.TMHMs, Legal.Pouch_TMHM_SWSH, 999, TMs, PouchSize8.TMs), new InventoryPouch8(InventoryType.TMHMs, Legal.Pouch_TMHM_SWSH, 999, TMs, PouchSize8.TMs, IsItemLegal),
new InventoryPouch8(InventoryType.MailItems, Legal.Pouch_Treasure_SWSH, 999, Treasures, PouchSize8.Treasures), new InventoryPouch8(InventoryType.MailItems, Legal.Pouch_Treasure_SWSH, 999, Treasures, PouchSize8.Treasures, IsItemLegal),
new InventoryPouch8(InventoryType.Candy, Legal.Pouch_Ingredients_SWSH, 999, Ingredients, PouchSize8.Ingredients), new InventoryPouch8(InventoryType.Candy, Legal.Pouch_Ingredients_SWSH, 999, Ingredients, PouchSize8.Ingredients, IsItemLegal),
new InventoryPouch8(InventoryType.KeyItems, Legal.Pouch_Key_SWSH, 1, Key, PouchSize8.Key), new InventoryPouch8(InventoryType.KeyItems, Legal.Pouch_Key_SWSH, 1, Key, PouchSize8.Key),
}; };
return pouch.LoadAll(Data); return pouch.LoadAll(Data);
@ -41,5 +42,14 @@ namespace PKHeX.Core
value.SaveAll(Data); value.SaveAll(Data);
} }
} }
public static bool IsItemLegal(ushort item)
{
if (Legal.IsDynamaxCrystal(item))
return Legal.IsDynamaxCrystalAvailable(item);
if (!Legal.HeldItems_SWSH.Contains(item))
return true;
return Legal.ReleasedHeldItems_8[item];
}
} }
} }

View file

@ -15,6 +15,8 @@ namespace PKHeX.Core
/// <summary> Valid item IDs that may be stored in the pouch. </summary> /// <summary> Valid item IDs that may be stored in the pouch. </summary>
public readonly ushort[] LegalItems; public readonly ushort[] LegalItems;
public readonly Func<ushort, bool>? IsItemLegal;
/// <summary> Max quantity for a given item that can be stored in the pouch. </summary> /// <summary> Max quantity for a given item that can be stored in the pouch. </summary>
public readonly int MaxCount; public readonly int MaxCount;
@ -31,7 +33,7 @@ namespace PKHeX.Core
/// <summary> Size of the backing byte array that represents the pouch. </summary> /// <summary> Size of the backing byte array that represents the pouch. </summary>
protected readonly int PouchDataSize; protected readonly int PouchDataSize;
protected InventoryPouch(InventoryType type, ushort[] legal, int maxCount, int offset, int size = -1) protected InventoryPouch(InventoryType type, ushort[] legal, int maxCount, int offset, int size = -1, Func<ushort, bool>? isLegal = null)
{ {
Items = Array.Empty<InventoryItem>(); Items = Array.Empty<InventoryItem>();
Type = type; Type = type;
@ -39,6 +41,7 @@ namespace PKHeX.Core
MaxCount = maxCount; MaxCount = maxCount;
Offset = offset; Offset = offset;
PouchDataSize = size > -1 ? size : legal.Length; PouchDataSize = size > -1 ? size : legal.Length;
IsItemLegal = isLegal;
} }
/// <summary> Reads the pouch from the backing <see cref="data"/>. </summary> /// <summary> Reads the pouch from the backing <see cref="data"/>. </summary>
@ -178,13 +181,13 @@ namespace PKHeX.Core
item.Count = modification(item); item.Count = modification(item);
} }
public void GiveAllItems(IReadOnlyList<ushort> newItems, Func<InventoryItem, int> getSuggestedItemCount, int count = -1) public void GiveAllItems(ReadOnlySpan<ushort> newItems, Func<InventoryItem, int> getSuggestedItemCount, int count = -1)
{ {
GiveAllItems(newItems, count); GiveAllItems(newItems, count);
ModifyAllCount(getSuggestedItemCount); ModifyAllCount(getSuggestedItemCount);
} }
public void GiveAllItems(SaveFile sav, IReadOnlyList<ushort> items, int count = -1) public void GiveAllItems(SaveFile sav, ReadOnlySpan<ushort> items, int count = -1)
{ {
GiveAllItems(items, count); GiveAllItems(items, count);
ModifyAllCount(item => GetSuggestedItemCount(sav, item.Index, count)); ModifyAllCount(item => GetSuggestedItemCount(sav, item.Index, count));
@ -192,19 +195,23 @@ namespace PKHeX.Core
public void GiveAllItems(SaveFile sav, int count = -1) => GiveAllItems(sav, LegalItems, count); public void GiveAllItems(SaveFile sav, int count = -1) => GiveAllItems(sav, LegalItems, count);
private void GiveAllItems(IReadOnlyList<ushort> newItems, int count = -1) private void GiveAllItems(ReadOnlySpan<ushort> newItems, int count = -1)
{ {
if (count < 0) if (count < 0)
count = MaxCount; count = MaxCount;
var current = (InventoryItem[]) Items.Clone(); var current = (InventoryItem[]) Items.Clone();
var itemEnd = Math.Min(Items.Length, newItems.Count); var itemEnd = Math.Min(Items.Length, newItems.Length);
for (int i = 0; i < itemEnd; i++) var iterate = newItems[..itemEnd];
{
var item = Items[i] = GetEmpty();
item.Index = newItems[i];
var match = Array.Find(current, z => z.Index == newItems[i]); int ctr = 0;
foreach (var newItemID in iterate)
{
if (IsItemLegal?.Invoke(newItemID) == false)
continue;
var item = Items[ctr++] = GetEmpty(newItemID);
var match = Array.Find(current, z => z.Index == newItemID);
if (match == null) if (match == null)
{ {
item.SetNewDetails(count); item.SetNewDetails(count);
@ -214,6 +221,9 @@ namespace PKHeX.Core
// load old values // load old values
item.MergeOverwrite(match); item.MergeOverwrite(match);
} }
for (int i = ctr; i < Items.Length; i++)
Items[i] = GetEmpty();
} }
public bool IsValidItemAndCount(ITrainerInfo sav, int item, bool HasNew, bool HaX, ref int count) public bool IsValidItemAndCount(ITrainerInfo sav, int item, bool HasNew, bool HaX, ref int count)
@ -257,7 +267,7 @@ namespace PKHeX.Core
return Math.Min(MaxCount, requestVal); return Math.Min(MaxCount, requestVal);
} }
public abstract InventoryItem GetEmpty(); public abstract InventoryItem GetEmpty(int itemID = 0, int count = 0);
} }
public static class InventoryPouchExtensions public static class InventoryPouchExtensions

View file

@ -37,6 +37,6 @@ namespace PKHeX.Core
} }
} }
public override InventoryItem GetEmpty() => new(); public override InventoryItem GetEmpty(int itemID = 0, int count = 0) => new() { Index = itemID, Count = count };
} }
} }

View file

@ -9,7 +9,7 @@ namespace PKHeX.Core
{ {
} }
public override InventoryItem GetEmpty() => new(); public override InventoryItem GetEmpty(int itemID = 0, int count = 0) => new() { Index = itemID, Count = count };
public override void GetPouch(byte[] data) public override void GetPouch(byte[] data)
{ {

View file

@ -16,7 +16,7 @@ namespace PKHeX.Core
// u16 id // u16 id
// u16 count // u16 count
public override InventoryItem GetEmpty() => new(); public override InventoryItem GetEmpty(int itemID = 0, int count = 0) => new() { Index = itemID, Count = count };
public override void GetPouch(byte[] data) public override void GetPouch(byte[] data)
{ {

View file

@ -12,7 +12,7 @@ namespace PKHeX.Core
public InventoryPouch7(InventoryType type, ushort[] legal, int maxCount, int offset) public InventoryPouch7(InventoryType type, ushort[] legal, int maxCount, int offset)
: base(type, legal, maxCount, offset) { } : base(type, legal, maxCount, offset) { }
public override InventoryItem GetEmpty() => new InventoryItem7(); public override InventoryItem GetEmpty(int itemID = 0, int count = 0) => new InventoryItem7 { Index = itemID, Count = count };
public override void GetPouch(byte[] data) public override void GetPouch(byte[] data)
{ {

View file

@ -11,7 +11,7 @@ namespace PKHeX.Core
public bool SetNew { get; set; } public bool SetNew { get; set; }
private InventoryItem7b[] OriginalItems = Array.Empty<InventoryItem7b>(); private InventoryItem7b[] OriginalItems = Array.Empty<InventoryItem7b>();
public override InventoryItem GetEmpty() => new InventoryItem7b(); public override InventoryItem GetEmpty(int itemID = 0, int count = 0) => new InventoryItem7b { Index = itemID, Count = count };
public InventoryPouch7b(InventoryType type, ushort[] legal, int maxCount, int offset, int size) public InventoryPouch7b(InventoryType type, ushort[] legal, int maxCount, int offset, int size)
: base(type, legal, maxCount, offset, size) { } : base(type, legal, maxCount, offset, size) { }

View file

@ -11,10 +11,10 @@ namespace PKHeX.Core
public bool SetNew { get; set; } public bool SetNew { get; set; }
private InventoryItem8[] OriginalItems = Array.Empty<InventoryItem8>(); private InventoryItem8[] OriginalItems = Array.Empty<InventoryItem8>();
public InventoryPouch8(InventoryType type, ushort[] legal, int maxCount, int offset, int size) public InventoryPouch8(InventoryType type, ushort[] legal, int maxCount, int offset, int size, Func<ushort, bool>? isLegal = null)
: base(type, legal, maxCount, offset, size) { } : base(type, legal, maxCount, offset, size, isLegal) { }
public override InventoryItem GetEmpty() => new InventoryItem8(); public override InventoryItem GetEmpty(int itemID = 0, int count = 0) => new InventoryItem8 { Index = itemID, Count = count };
public override void GetPouch(byte[] data) public override void GetPouch(byte[] data)
{ {

View file

@ -10,10 +10,11 @@ namespace PKHeX.Core
public bool SetNew { get; set; } public bool SetNew { get; set; }
public InventoryPouch8b(InventoryType type, ushort[] legal, int maxCount, int offset) public InventoryPouch8b(InventoryType type, ushort[] legal, int maxCount, int offset,
: base(type, legal, maxCount, offset) { } Func<ushort, bool>? isLegal)
: base(type, legal, maxCount, offset, isLegal: isLegal) { }
public override InventoryItem GetEmpty() => new InventoryItem8b { IsNew = true }; public override InventoryItem GetEmpty(int itemID = 0, int count = 0) => new InventoryItem8b { Index = itemID, Count = count, IsNew = true };
public override void GetPouch(byte[] data) public override void GetPouch(byte[] data)
{ {

View file

@ -9,7 +9,7 @@ namespace PKHeX.Core
{ {
} }
public override InventoryItem GetEmpty() => new(); public override InventoryItem GetEmpty(int itemID = 0, int count = 0) => new() { Index = itemID, Count = count };
public override void GetPouch(byte[] data) public override void GetPouch(byte[] data)
{ {

View file

@ -227,9 +227,7 @@ namespace PKHeX.WinForms
continue; // ignore item continue; // ignore item
// create clean item data when saving // create clean item data when saving
var item = pouch.GetEmpty(); var item = pouch.GetEmpty(itemindex, itemcnt);
item.Index = itemindex;
item.Count = itemcnt;
if (item is IItemFreeSpace f) if (item is IItemFreeSpace f)
f.IsFreeSpace = (bool)cells[ColumnFreeSpace].Value; f.IsFreeSpace = (bool)cells[ColumnFreeSpace].Value;
if (item is IItemFavorite v) if (item is IItemFavorite v)