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
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[]
{
298, // Flame Plate

View file

@ -63,14 +63,14 @@ namespace PKHeX.Core
{
var pouches = new[]
{
MakePouch(InventoryType.Items),
MakePouch(InventoryType.Items, IsHeldItemLegal),
MakePouch(InventoryType.KeyItems),
MakePouch(InventoryType.TMHMs),
MakePouch(InventoryType.Medicine),
MakePouch(InventoryType.Berries),
MakePouch(InventoryType.Balls),
MakePouch(InventoryType.BattleItems),
MakePouch(InventoryType.Treasure),
MakePouch(InventoryType.TMHMs, IsHeldItemLegal),
MakePouch(InventoryType.Medicine, IsHeldItemLegal),
MakePouch(InventoryType.Berries, IsHeldItemLegal),
MakePouch(InventoryType.Balls, IsHeldItemLegal),
MakePouch(InventoryType.BattleItems, IsHeldItemLegal),
MakePouch(InventoryType.Treasure, IsHeldItemLegal),
};
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);
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
{
InventoryType.Items => 999,

View file

@ -1,4 +1,5 @@
using System.Collections.Generic;
using System.Linq;
namespace PKHeX.Core
{
@ -22,14 +23,14 @@ namespace PKHeX.Core
{
var pouch = new InventoryPouch[]
{
new InventoryPouch8(InventoryType.Medicine, Legal.Pouch_Medicine_SWSH, 999, Medicine, PouchSize8.Medicine),
new InventoryPouch8(InventoryType.Balls, Legal.Pouch_Ball_SWSH, 999, Balls, PouchSize8.Balls),
new InventoryPouch8(InventoryType.BattleItems, Legal.Pouch_Battle_SWSH, 999, Battle, PouchSize8.Battle),
new InventoryPouch8(InventoryType.Berries, Legal.Pouch_Berries_SWSH, 999, Berries, PouchSize8.Berries),
new InventoryPouch8(InventoryType.Items, Legal.Pouch_Regular_SWSH, 999, Items, PouchSize8.Items),
new InventoryPouch8(InventoryType.TMHMs, Legal.Pouch_TMHM_SWSH, 999, TMs, PouchSize8.TMs),
new InventoryPouch8(InventoryType.MailItems, Legal.Pouch_Treasure_SWSH, 999, Treasures, PouchSize8.Treasures),
new InventoryPouch8(InventoryType.Candy, Legal.Pouch_Ingredients_SWSH, 999, Ingredients, PouchSize8.Ingredients),
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, IsItemLegal),
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, IsItemLegal),
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, IsItemLegal),
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, IsItemLegal),
new InventoryPouch8(InventoryType.KeyItems, Legal.Pouch_Key_SWSH, 1, Key, PouchSize8.Key),
};
return pouch.LoadAll(Data);
@ -41,5 +42,14 @@ namespace PKHeX.Core
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>
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>
public readonly int MaxCount;
@ -31,7 +33,7 @@ namespace PKHeX.Core
/// <summary> Size of the backing byte array that represents the pouch. </summary>
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>();
Type = type;
@ -39,6 +41,7 @@ namespace PKHeX.Core
MaxCount = maxCount;
Offset = offset;
PouchDataSize = size > -1 ? size : legal.Length;
IsItemLegal = isLegal;
}
/// <summary> Reads the pouch from the backing <see cref="data"/>. </summary>
@ -178,13 +181,13 @@ namespace PKHeX.Core
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);
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);
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);
private void GiveAllItems(IReadOnlyList<ushort> newItems, int count = -1)
private void GiveAllItems(ReadOnlySpan<ushort> newItems, int count = -1)
{
if (count < 0)
count = MaxCount;
var current = (InventoryItem[]) Items.Clone();
var itemEnd = Math.Min(Items.Length, newItems.Count);
for (int i = 0; i < itemEnd; i++)
{
var item = Items[i] = GetEmpty();
item.Index = newItems[i];
var itemEnd = Math.Min(Items.Length, newItems.Length);
var iterate = newItems[..itemEnd];
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)
{
item.SetNewDetails(count);
@ -214,6 +221,9 @@ namespace PKHeX.Core
// load old values
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)
@ -257,7 +267,7 @@ namespace PKHeX.Core
return Math.Min(MaxCount, requestVal);
}
public abstract InventoryItem GetEmpty();
public abstract InventoryItem GetEmpty(int itemID = 0, int count = 0);
}
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)
{

View file

@ -16,7 +16,7 @@ namespace PKHeX.Core
// u16 id
// 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)
{

View file

@ -12,7 +12,7 @@ namespace PKHeX.Core
public InventoryPouch7(InventoryType type, ushort[] legal, int maxCount, int 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)
{

View file

@ -11,7 +11,7 @@ namespace PKHeX.Core
public bool SetNew { get; set; }
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)
: base(type, legal, maxCount, offset, size) { }

View file

@ -11,10 +11,10 @@ namespace PKHeX.Core
public bool SetNew { get; set; }
private InventoryItem8[] OriginalItems = Array.Empty<InventoryItem8>();
public InventoryPouch8(InventoryType type, ushort[] legal, int maxCount, int offset, int size)
: base(type, legal, maxCount, offset, size) { }
public InventoryPouch8(InventoryType type, ushort[] legal, int maxCount, int offset, int size, Func<ushort, bool>? isLegal = null)
: 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)
{

View file

@ -10,10 +10,11 @@ namespace PKHeX.Core
public bool SetNew { get; set; }
public InventoryPouch8b(InventoryType type, ushort[] legal, int maxCount, int offset)
: base(type, legal, maxCount, offset) { }
public InventoryPouch8b(InventoryType type, ushort[] legal, int maxCount, int 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)
{

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)
{

View file

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