mirror of
https://github.com/kwsch/PKHeX
synced 2024-11-26 22:10:21 +00:00
Add HoneyTree API
This commit is contained in:
parent
963eaaaa40
commit
96e74a05d0
18 changed files with 214 additions and 66 deletions
|
@ -4,6 +4,9 @@ namespace PKHeX.Core;
|
|||
|
||||
internal static class Locations8b
|
||||
{
|
||||
public static bool IsUnderground(ushort location) => location is (>= 508 and <= 617);
|
||||
public static bool IsMarsh(ushort location) => location is (>= 219 and <= 224);
|
||||
|
||||
public static ReadOnlySpan<ushort> Met0 => new ushort[]
|
||||
{
|
||||
000, 001, 002, 003, 004, 005, 006, 007, 008, 009,
|
||||
|
|
|
@ -194,14 +194,17 @@ public sealed record EncounterCriteria : IFixedNature, IFixedGender, IFixedAbili
|
|||
/// Applies random IVs without any correlation.
|
||||
/// </summary>
|
||||
/// <param name="pk">Entity to mutate.</param>
|
||||
public void SetRandomIVs(PKM pk)
|
||||
public void SetRandomIVs(PKM pk) => SetRandomIVs(pk, Util.Rand);
|
||||
|
||||
/// <inheritdoc cref="SetRandomIVs(PKM)"/>
|
||||
public void SetRandomIVs(PKM pk, Random rnd)
|
||||
{
|
||||
pk.IV_HP = IV_HP != RandomIV ? IV_HP : Util.Rand.Next(32);
|
||||
pk.IV_ATK = IV_ATK != RandomIV ? IV_ATK : Util.Rand.Next(32);
|
||||
pk.IV_DEF = IV_DEF != RandomIV ? IV_DEF : Util.Rand.Next(32);
|
||||
pk.IV_SPA = IV_SPA != RandomIV ? IV_SPA : Util.Rand.Next(32);
|
||||
pk.IV_SPD = IV_SPD != RandomIV ? IV_SPD : Util.Rand.Next(32);
|
||||
pk.IV_SPE = IV_SPE != RandomIV ? IV_SPE : Util.Rand.Next(32);
|
||||
pk.IV_HP = IV_HP != RandomIV ? IV_HP : rnd.Next(32);
|
||||
pk.IV_ATK = IV_ATK != RandomIV ? IV_ATK : rnd.Next(32);
|
||||
pk.IV_DEF = IV_DEF != RandomIV ? IV_DEF : rnd.Next(32);
|
||||
pk.IV_SPA = IV_SPA != RandomIV ? IV_SPA : rnd.Next(32);
|
||||
pk.IV_SPD = IV_SPD != RandomIV ? IV_SPD : rnd.Next(32);
|
||||
pk.IV_SPE = IV_SPE != RandomIV ? IV_SPE : rnd.Next(32);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -73,16 +73,17 @@ public sealed record EncounterArea4 : IEncounterArea<EncounterSlot4>, ISlotRNGTy
|
|||
{
|
||||
// We didn't encode the honey tree index to the encounter slot resource.
|
||||
// Check if any of the slot's location doesn't match any of the groupC trees' area location ID.
|
||||
var trees = SAV4Sinnoh.CalculateMunchlaxTrees(pk.TID16, pk.SID16);
|
||||
Span<byte> trees = stackalloc byte[4];
|
||||
HoneyTreeUtil.CalculateMunchlaxTrees(pk.ID32, trees);
|
||||
return IsMunchlaxTree(trees, location);
|
||||
}
|
||||
|
||||
private static bool IsMunchlaxTree(in MunchlaxTreeSet4 trees, ushort location)
|
||||
private static bool IsMunchlaxTree(ReadOnlySpan<byte> trees, ushort location)
|
||||
{
|
||||
return LocationID_HoneyTree[trees.Tree1] == location
|
||||
|| LocationID_HoneyTree[trees.Tree2] == location
|
||||
|| LocationID_HoneyTree[trees.Tree3] == location
|
||||
|| LocationID_HoneyTree[trees.Tree4] == location;
|
||||
return LocationID_HoneyTree[trees[0]] == location
|
||||
|| LocationID_HoneyTree[trees[1]] == location
|
||||
|| LocationID_HoneyTree[trees[2]] == location
|
||||
|| LocationID_HoneyTree[trees[3]] == location;
|
||||
}
|
||||
|
||||
private static ReadOnlySpan<byte> LocationID_HoneyTree => new byte[]
|
||||
|
|
|
@ -142,7 +142,7 @@ public abstract record EncounterStatic8Nest<T>(GameVersion Version)
|
|||
|
||||
if (pk is IRibbonSetMark8 { HasMarkEncounter8: true })
|
||||
return false;
|
||||
if (pk.Species == (int)Core.Species.Shedinja && pk is IRibbonSetAffixed { AffixedRibbon: >= (int)RibbonIndex.MarkLunchtime })
|
||||
if (pk.Species == (int)Core.Species.Shedinja && pk is IRibbonSetAffixed { AffixedRibbon: >= (int)RibbonIndex.MarkLunchtime and <= (int)RibbonIndex.MarkSlump })
|
||||
return false;
|
||||
|
||||
if (!IsMatchEggLocation(pk))
|
||||
|
|
|
@ -88,16 +88,17 @@ public sealed record EncounterArea8b : IEncounterArea<EncounterSlot8b>, IAreaLoc
|
|||
{
|
||||
// We didn't encode the honey tree index to the encounter slot resource.
|
||||
// Check if any of the slot's location doesn't match any of the groupC trees' area location ID.
|
||||
var trees = SAV4Sinnoh.CalculateMunchlaxTrees(pk.TID16, pk.SID16);
|
||||
Span<byte> trees = stackalloc byte[4];
|
||||
HoneyTreeUtil.CalculateMunchlaxTrees(pk.ID32, trees);
|
||||
return IsMunchlaxTree(trees, location);
|
||||
}
|
||||
|
||||
private static bool IsMunchlaxTree(in MunchlaxTreeSet4 trees, ushort location)
|
||||
private static bool IsMunchlaxTree(ReadOnlySpan<byte> trees, ushort location)
|
||||
{
|
||||
return LocationID_HoneyTree[trees.Tree1] == location
|
||||
|| LocationID_HoneyTree[trees.Tree2] == location
|
||||
|| LocationID_HoneyTree[trees.Tree3] == location
|
||||
|| LocationID_HoneyTree[trees.Tree4] == location;
|
||||
return LocationID_HoneyTree[trees[0]] == location
|
||||
|| LocationID_HoneyTree[trees[1]] == location
|
||||
|| LocationID_HoneyTree[trees[2]] == location
|
||||
|| LocationID_HoneyTree[trees[3]] == location;
|
||||
}
|
||||
|
||||
private static ReadOnlySpan<ushort> LocationID_HoneyTree => new ushort[]
|
||||
|
|
|
@ -14,8 +14,8 @@ public sealed record EncounterSlot8b(EncounterArea8b Parent, ushort Species, byt
|
|||
public Shiny Shiny => Shiny.Random;
|
||||
public bool IsShiny => false;
|
||||
public int EggLocation => 0;
|
||||
public bool IsUnderground => Parent.Location is (>= 508 and <= 617);
|
||||
public bool IsMarsh => Parent.Location is (>= 219 and <= 224);
|
||||
public bool IsUnderground => Locations8b.IsUnderground(Parent.Location);
|
||||
public bool IsMarsh => Locations8b.IsMarsh(Parent.Location);
|
||||
public Ball FixedBall => GetRequiredBall();
|
||||
private Ball GetRequiredBall(Ball fallback = Ball.None) => IsMarsh ? Ball.Safari : fallback;
|
||||
|
||||
|
|
|
@ -84,6 +84,17 @@ public static class LCRNG
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint Prev8(uint seed) => (seed * rMult8) + rAdd8;
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint Prev9(uint seed) => (seed * rMult9) + rAdd9;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the next 16 bits of the next RNG seed.
|
||||
/// </summary>
|
||||
/// <param name="seed">Seed to advance one step.</param>
|
||||
/// <param name="result">Next seed, top 16 bits.</param>
|
||||
public static void Next16(ref uint seed, out int result)
|
||||
{
|
||||
seed = Next(seed);
|
||||
result = (int)(seed >> 16);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Advances the RNG seed to the next state value a specified amount of times.
|
||||
/// </summary>
|
||||
|
|
|
@ -16,7 +16,7 @@ public sealed class MarkVerifier : Verifier
|
|||
if (pk is not IRibbonIndex m)
|
||||
return;
|
||||
|
||||
if (!MarkRules.IsEncounterMarkAllowed(data)) // Shedinja doesn't copy Ribbons or Marks
|
||||
if (!MarkRules.IsEncounterMarkAllowed(data.EncounterOriginal, data.Entity)) // Shedinja doesn't copy Ribbons or Marks
|
||||
VerifyNoMarksPresent(data, m);
|
||||
else
|
||||
VerifyMarksPresent(data, m);
|
||||
|
@ -93,7 +93,7 @@ public sealed class MarkVerifier : Verifier
|
|||
if (m is not PKM pk)
|
||||
return;
|
||||
|
||||
if (MarkRules.IsEncounterMarkLost(data))
|
||||
if (MarkRules.IsEncounterMarkLost(data.EncounterOriginal, data.Entity))
|
||||
{
|
||||
VerifyShedinjaAffixed(data, affix, pk, m);
|
||||
return;
|
||||
|
|
|
@ -11,20 +11,20 @@ public static class MarkRules
|
|||
/// <summary>
|
||||
/// Checks if an encounter-only mark is possible to obtain for the encounter, if not lost via data manipulation.
|
||||
/// </summary>
|
||||
public static bool IsEncounterMarkAllowed(LegalityAnalysis data)
|
||||
public static bool IsEncounterMarkAllowed(IEncounterTemplate enc, PKM pk)
|
||||
{
|
||||
if (IsEncounterMarkLost(data))
|
||||
if (IsEncounterMarkLost(enc, pk))
|
||||
return false;
|
||||
return data.Info.EncounterOriginal.Context is EntityContext.Gen8 or EntityContext.Gen9;
|
||||
return enc.Context is EntityContext.Gen8 or EntityContext.Gen9;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if original marks and ribbons are lost via data manipulation.
|
||||
/// </summary>
|
||||
public static bool IsEncounterMarkLost(LegalityAnalysis data)
|
||||
public static bool IsEncounterMarkLost(IEncounterTemplate enc, PKM pk)
|
||||
{
|
||||
// Nincada -> Shedinja loses all ribbons and marks, but does not purge any Affixed Ribbon value.
|
||||
return data.EncounterOriginal.Species is (int)Species.Nincada && data.Entity.Species == (int)Species.Shedinja;
|
||||
return enc.Species is (int)Species.Nincada && pk.Species == (int)Species.Shedinja;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -3,7 +3,7 @@ using static PKHeX.Core.RibbonIndex;
|
|||
namespace PKHeX.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Parsing logic for <see cref="IRibbonSetCommon8"/>.
|
||||
/// Parsing logic for <see cref="IRibbonSetMark9"/>.
|
||||
/// </summary>
|
||||
public static class RibbonVerifierMark9
|
||||
{
|
||||
|
|
|
@ -224,7 +224,7 @@ public sealed class PKH : PKM, IHandlerLanguage, IFormArgument, IHomeTrack, IBat
|
|||
#region Maximums
|
||||
|
||||
public override int MaxIV => 31;
|
||||
public override int MaxEV => 252;
|
||||
public override int MaxEV => EffortValues.Max252;
|
||||
public override int MaxStringLengthOT => 12;
|
||||
public override int MaxStringLengthNickname => 12;
|
||||
public override ushort MaxMoveID => Legal.MaxMoveID_8a;
|
||||
|
|
|
@ -21,7 +21,7 @@ public abstract class G3PKM : PKM, IRibbonSetEvent3, IRibbonSetCommon3, IRibbonS
|
|||
public sealed override int MaxBallID => Legal.MaxBallID_3;
|
||||
public sealed override int MaxGameID => Legal.MaxGameID_3;
|
||||
public sealed override int MaxIV => 31;
|
||||
public sealed override int MaxEV => 255;
|
||||
public sealed override int MaxEV => EffortValues.Max255;
|
||||
public sealed override int MaxStringLengthOT => 7;
|
||||
public sealed override int MaxStringLengthNickname => 10;
|
||||
|
||||
|
|
|
@ -100,7 +100,7 @@ public abstract class G6PKM : PKM, ISanityChecksum
|
|||
|
||||
// Maximums
|
||||
public sealed override int MaxIV => 31;
|
||||
public sealed override int MaxEV => 252;
|
||||
public sealed override int MaxEV => EffortValues.Max252;
|
||||
public sealed override int MaxStringLengthOT => 12;
|
||||
public sealed override int MaxStringLengthNickname => 12;
|
||||
}
|
||||
|
|
152
PKHeX.Core/Saves/HoneyTreeUtil.cs
Normal file
152
PKHeX.Core/Saves/HoneyTreeUtil.cs
Normal file
|
@ -0,0 +1,152 @@
|
|||
using System;
|
||||
using static System.Buffers.Binary.BinaryPrimitives;
|
||||
using static PKHeX.Core.HoneyTreeSlotGroup;
|
||||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Utility class for calculating honey trees for <see cref="GameVersion.DPPt"/> and <see cref="GameVersion.BDSP"/>.
|
||||
/// </summary>
|
||||
public static class HoneyTreeUtil
|
||||
{
|
||||
/// <summary>
|
||||
/// Number of possible honey trees that exist in the game.
|
||||
/// </summary>
|
||||
private const byte HoneyTreeCount = 21;
|
||||
|
||||
/// <summary>
|
||||
/// Populates the given span with the 4 possible honey trees for the given ID.
|
||||
/// </summary>
|
||||
/// <param name="id">The 32-bit Trainer ID to calculate the trees for.</param>
|
||||
/// <param name="result">Result span that will be populated with the 4 possible trees.</param>
|
||||
/// <exception cref="ArgumentOutOfRangeException"></exception>
|
||||
public static void CalculateMunchlaxTrees(uint id, Span<byte> result)
|
||||
{
|
||||
if (result.Length != sizeof(uint))
|
||||
throw new ArgumentOutOfRangeException(nameof(result));
|
||||
WriteUInt32BigEndian(result, id);
|
||||
foreach (ref var b in result)
|
||||
b %= HoneyTreeCount;
|
||||
|
||||
AdjustOverlap(result);
|
||||
}
|
||||
|
||||
private static void AdjustOverlap(Span<byte> result)
|
||||
{
|
||||
// If a tree is the same as any previous one, increment it and reset to 0 if it overflows the max.
|
||||
// Yields 3-4 unique trees per ID. 1935328924d => {10,6,9,10}
|
||||
// The original intent was likely to have 4 rare trees per save file; if so, the implementation was flawed.
|
||||
// (the inner loop should have restarted if it detected a duplicate, instead of continuing to the next tree)
|
||||
for (int i = 1; i < result.Length; i++)
|
||||
{
|
||||
ref var b = ref result[i];
|
||||
for (int j = 0; j < i; j++)
|
||||
{
|
||||
if (b != result[j])
|
||||
continue;
|
||||
b++;
|
||||
if (b >= HoneyTreeCount)
|
||||
b = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// There aren't any RNG considerations for Munchlax/etc encounter slot legality.
|
||||
// The RNG calls for populating the tree are disjointed from the RNG calls for generating the Entity upon encounter.
|
||||
// Group -> Slot -> Shakes
|
||||
|
||||
/// <summary>
|
||||
/// Calculates the honey tree result for the given seed when the tree elapses.
|
||||
/// </summary>
|
||||
/// <param name="seed">Current RNG state seed of the game.</param>
|
||||
/// <param name="isMunchlaxTree">If the tree is a "rare" tree based on <see cref="CalculateMunchlaxTrees"/>.</param>"/>
|
||||
public static (HoneyTreeSlotGroup Group, int Slot, int Shakes) GetHoneyTreeResult(uint seed, bool isMunchlaxTree)
|
||||
{
|
||||
LCRNG.Next16(ref seed, out var randGroup);
|
||||
LCRNG.Next16(ref seed, out var randSlot);
|
||||
LCRNG.Next16(ref seed, out var randShakes);
|
||||
|
||||
var group = GetHoneyTreeGroup(randGroup, isMunchlaxTree);
|
||||
var slot = GetHoneyTreeSlotIndex(randSlot);
|
||||
var shakes = GetShakeCount(randShakes, group);
|
||||
|
||||
return (group, slot, shakes);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates which slot group rarity inhabits a honey tree.
|
||||
/// </summary>
|
||||
public static HoneyTreeSlotGroup GetHoneyTreeGroup(int rnd, bool isMunchlaxTree) => isMunchlaxTree switch
|
||||
{
|
||||
true => rnd switch
|
||||
{
|
||||
0 => Munchlax, // 1%
|
||||
< 10 => None, // 9% fail
|
||||
< 30 => Common, // 20%
|
||||
_ => Rare, // 70%
|
||||
},
|
||||
_ => rnd switch
|
||||
{
|
||||
< 10 => None, // 10% fail
|
||||
< 30 => Rare, // 20%
|
||||
_ => Common, // 70%
|
||||
},
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Indicates which slot index of the group inhabits in the honey tree.
|
||||
/// </summary>
|
||||
public static int GetHoneyTreeSlotIndex(int rnd) => rnd switch
|
||||
{
|
||||
< 05 => 5, // 5%
|
||||
< 10 => 4, // 5%
|
||||
< 20 => 3, // 10%
|
||||
< 40 => 2, // 20%
|
||||
< 60 => 1, // 20%
|
||||
_ => 0, // 20%
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Indicates how many times the tree shakes before the encounter.
|
||||
/// </summary>
|
||||
public static int GetShakeCount(int rnd, HoneyTreeSlotGroup group) => group switch
|
||||
{
|
||||
Common => rnd switch
|
||||
{
|
||||
< 19 => 2, // 19%
|
||||
< 79 => 1, // 60%
|
||||
< 99 => 0, // 20%
|
||||
_ => 3, // 1%
|
||||
},
|
||||
Rare => rnd switch
|
||||
{
|
||||
< 75 => 2, // 75%
|
||||
< 95 => 1, // 20%
|
||||
95 => 0, // 1%
|
||||
_ => 3, // 4%
|
||||
},
|
||||
Munchlax => rnd switch
|
||||
{
|
||||
< 5 => 2, // 5%
|
||||
5 => 1, // 1%
|
||||
6 => 0, // 1%
|
||||
_ => 3, // 93%
|
||||
},
|
||||
_ => 0,
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates which slot group rarity inhabits a honey tree.
|
||||
/// </summary>
|
||||
public enum HoneyTreeSlotGroup : byte
|
||||
{
|
||||
/// <summary> No species inhabits the tree. </summary>
|
||||
None,
|
||||
/// <summary> Common species inhabit the tree. </summary>
|
||||
Common,
|
||||
/// <summary> Rare species inhabit the tree. </summary>
|
||||
Rare,
|
||||
/// <summary> Munchlax inhabits the tree. </summary>
|
||||
Munchlax,
|
||||
}
|
|
@ -12,7 +12,7 @@ public sealed class SAV2Stadium : SAV_STADIUM
|
|||
public override string SaveRevisionString => Japanese ? "J" : "U";
|
||||
|
||||
public override PersonalTable2 Personal => PersonalTable.C;
|
||||
public override int MaxEV => ushort.MaxValue;
|
||||
public override int MaxEV => EffortValues.Max12;
|
||||
public override ReadOnlySpan<ushort> HeldItems => Legal.HeldItems_GSC;
|
||||
public override GameVersion Version { get; protected set; } = GameVersion.Stadium2;
|
||||
|
||||
|
|
|
@ -77,7 +77,7 @@ public abstract class SAV4 : SaveFile, IEventFlag37
|
|||
public sealed override Type PKMType => typeof(PK4);
|
||||
|
||||
public sealed override int BoxCount => 18;
|
||||
public sealed override int MaxEV => 255;
|
||||
public sealed override int MaxEV => EffortValues.Max255;
|
||||
public sealed override int Generation => 4;
|
||||
public override EntityContext Context => EntityContext.Gen4;
|
||||
public int EventFlagCount => 0xB60; // 2912
|
||||
|
|
|
@ -125,25 +125,6 @@ public abstract class SAV4Sinnoh : SAV4
|
|||
public HoneyTreeValue GetHoneyTree(int index) => new(GetHoneyTreeSpan(index).ToArray());
|
||||
public void SetHoneyTree(HoneyTreeValue tree, int index) => SetData(GetHoneyTreeSpan(index), tree.Data);
|
||||
|
||||
public MunchlaxTreeSet4 GetMunchlaxTrees() => CalculateMunchlaxTrees(TID16, SID16);
|
||||
|
||||
public static MunchlaxTreeSet4 CalculateMunchlaxTrees(ushort tid, ushort sid)
|
||||
{
|
||||
int A = (tid >> 8) % 21;
|
||||
int B = (tid & 0x00FF) % 21;
|
||||
int C = (sid >> 8) % 21;
|
||||
int D = (sid & 0x00FF) % 21;
|
||||
|
||||
if (A == B) B = (B + 1) % 21;
|
||||
if (A == C) C = (C + 1) % 21;
|
||||
if (B == C) C = (C + 1) % 21;
|
||||
if (A == D) D = (D + 1) % 21;
|
||||
if (B == D) D = (D + 1) % 21;
|
||||
if (C == D) D = (D + 1) % 21;
|
||||
|
||||
return new(A, B, C, D);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public int OFS_PoffinCase { get; protected set; }
|
||||
|
@ -227,8 +208,3 @@ public enum PoketchApp
|
|||
Stopwatch,
|
||||
Alarm_Clock,
|
||||
}
|
||||
|
||||
public readonly record struct MunchlaxTreeSet4(int Tree1, int Tree2, int Tree3, int Tree4)
|
||||
{
|
||||
public bool Contains(int tree) => tree == Tree1 || tree == Tree2 || tree == Tree3 || tree == Tree4;
|
||||
}
|
||||
|
|
|
@ -16,20 +16,21 @@ public partial class SAV_HoneyTree : Form
|
|||
SAV = (SAV4Sinnoh)(Origin = sav).Clone();
|
||||
|
||||
// Get Munchlax tree for this savegame in screen
|
||||
MunchlaxTrees = SAV.GetMunchlaxTrees();
|
||||
MunchlaxTrees = new byte[4];
|
||||
HoneyTreeUtil.CalculateMunchlaxTrees(SAV.ID32, MunchlaxTrees);
|
||||
|
||||
const string sep = "- ";
|
||||
var names = CB_TreeList.Items;
|
||||
L_Tree0.Text = string.Join(Environment.NewLine,
|
||||
sep + names[MunchlaxTrees.Tree1],
|
||||
sep + names[MunchlaxTrees.Tree2],
|
||||
sep + names[MunchlaxTrees.Tree3],
|
||||
sep + names[MunchlaxTrees.Tree4]);
|
||||
sep + names[MunchlaxTrees[0]],
|
||||
sep + names[MunchlaxTrees[1]],
|
||||
sep + names[MunchlaxTrees[2]],
|
||||
sep + names[MunchlaxTrees[3]]);
|
||||
|
||||
CB_TreeList.SelectedIndex = 0;
|
||||
}
|
||||
|
||||
private readonly MunchlaxTreeSet4 MunchlaxTrees;
|
||||
private readonly byte[] MunchlaxTrees;
|
||||
private int entry;
|
||||
private bool loading;
|
||||
private HoneyTreeValue? Tree;
|
||||
|
@ -45,7 +46,7 @@ public partial class SAV_HoneyTree : Form
|
|||
if (loading)
|
||||
return;
|
||||
|
||||
if (species == (int)Species.Munchlax && !MunchlaxTrees.Contains(CB_TreeList.SelectedIndex))
|
||||
if (species == (int)Species.Munchlax && !MunchlaxTrees.AsSpan().Contains((byte)CB_TreeList.SelectedIndex))
|
||||
WinFormsUtil.Alert("Catching Munchlax in this tree will make it illegal for this savegame's TID16/SID16 combination.");
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue