Add better handling for specific GO transfers

No formarg or bad EC evolution peek -> search for higher species rather than from the bottom.
This commit is contained in:
Kurt
2024-01-12 18:58:23 -08:00
parent c591e9b809
commit f2209ec7fd
6 changed files with 93 additions and 12 deletions

View File

@@ -28,6 +28,12 @@ public static WurmpleEvolution GetWurmpleEvoGroup(ushort species)
return (WurmpleEvolution)(wIndex >> 1); // Silcoon, Cascoon
}
/// <summary>
/// Checks to see if the input species is a Wurmple evolution
/// </summary>
/// <returns>True if Wurmple evolution, false if not</returns>
public static bool IsWurmpleEvo(ushort species) => GetWurmpleEvoGroup(species) != WurmpleEvolution.None;
/// <summary>
/// Gets the Wurmple <see cref="PKM.EncryptionConstant"/> for a given Evolution Value
/// </summary>

View File

@@ -13,6 +13,7 @@ public record struct EncounterEnumerator8GO(PKM Entity, EvoCriteria[] Chain) : I
private int Index;
private int EvoIndex;
private int SubIndex;
private SeekMode Mode;
private EncounterMatchRating Rating = EncounterMatchRating.MaxNotMatch;
public MatchedEncounter<IEncounterable> Current { get; private set; }
private YieldState State;
@@ -26,11 +27,19 @@ private enum YieldState : byte
{
Start,
Seek,
SeekForward,
SeekReverse,
Slot,
Fallback,
End,
}
public enum SeekMode : byte
{
Forward,
Reverse,
}
public bool MoveNext()
{
switch (State)
@@ -40,12 +49,24 @@ public bool MoveNext()
break;
if (!EncounterStateUtil.CanBeWildEncounter(Entity))
break;
Mode = GetSeekMode();
if (Mode == SeekMode.Reverse)
Index = EncountersGO.SlotsGO.Length - 1;
State = YieldState.Seek; goto case YieldState.Seek;
case YieldState.Seek:
if (!SeekNextArea(EncountersGO.SlotsGO))
if (Mode == SeekMode.Forward)
{ State = YieldState.SeekForward; goto case YieldState.SeekForward; }
State = YieldState.SeekReverse; goto case YieldState.SeekReverse;
case YieldState.SeekForward:
if (!SeekForward(EncountersGO.SlotsGO))
goto case YieldState.Fallback;
State = YieldState.Slot; goto case YieldState.Slot;
case YieldState.SeekReverse:
if (!SeekReverse(EncountersGO.SlotsGO))
goto case YieldState.Fallback;
State = YieldState.Slot; goto case YieldState.Slot;
case YieldState.Slot:
var group = EncountersGO.SlotsGO[Index];
if (TryGetNext(group.Slots))
@@ -61,7 +82,7 @@ public bool MoveNext()
return false;
}
private bool SeekNextArea<TArea>(TArea[] areas)
private bool SeekForward<TArea>(TArea[] areas)
where TArea : ISpeciesForm
{
for (; Index < areas.Length; Index++, EvoIndex = 0)
@@ -77,6 +98,41 @@ private bool SeekNextArea<TArea>(TArea[] areas)
return false;
}
private bool SeekReverse<TArea>(TArea[] areas) where TArea : ISpeciesForm
{
for (; Index > 0; Index--, EvoIndex = 0) // Only difference -- search in reverse!
{
var area = areas[Index];
do
{
if (IsCompatible(area, Chain[EvoIndex]))
return true;
}
while (++EvoIndex < Chain.Length);
}
return false;
}
private readonly SeekMode GetSeekMode()
{
var species = Entity.Species;
if (species is (int)Species.Dudunsparce or (int)Species.Maushold)
{
if (!EvolutionRestrictions.GetIsExpectedEvolveFormEC100(species, Entity.Form, Entity.EncryptionConstant % 100 == 0))
return SeekMode.Reverse;
}
else if (EvolutionRestrictions.IsFormArgEvolution(species))
{
if (Entity is IFormArgument { FormArgument: 0 })
return SeekMode.Reverse;
}
else if (WurmpleUtil.IsWurmpleEvo(species) && !WurmpleUtil.IsWurmpleEvoValid(Entity))
{
return SeekMode.Reverse;
}
return SeekMode.Forward;
}
private readonly bool IsCompatible<TArea>(TArea area, EvoCriteria evo) where TArea : ISpeciesForm
{
if (area.Species != evo.Species)
@@ -108,7 +164,11 @@ private bool TryGetNext<TSlot>(TSlot[] slots)
Rating = rating;
}
}
EvoIndex = 0; SubIndex = 0; Index++;
EvoIndex = 0; SubIndex = 0;
if (Mode == SeekMode.Forward)
Index++;
else
Index--;
return false;
}

View File

@@ -36,6 +36,29 @@ internal static class EvolutionRestrictions
_ => NONE,
};
/// <summary>
/// Gets the species-form that it will evolve into.
/// </summary>
/// <exception cref="ArgumentOutOfRangeException"></exception>
public static (ushort Species, byte Form) GetEvolvedSpeciesFormEC100(ushort species, bool rare) => species switch
{
(ushort)Tandemaus => ((ushort)Maushold, (byte)(rare ? 0 : 1)),
(ushort)Dunsparce => ((ushort)Dudunsparce, (byte)(rare ? 1 : 0)),
_ => throw new ArgumentOutOfRangeException(nameof(species), species, "Incorrect EC%100 species."),
};
public static bool GetIsExpectedEvolveFormEC100(ushort species, byte form, bool rare) => species switch
{
(ushort)Maushold => form == (byte)(rare ? 0 : 1),
(ushort)Dudunsparce => form == (byte)(rare ? 1 : 0),
_ => throw new ArgumentOutOfRangeException(nameof(species), species, "Incorrect EC%100 species."),
};
public static bool IsFormArgEvolution(ushort species)
{
return species is (int)Runerigus or (int)Wyrdeer or (int)Annihilape or (int)Basculegion or (int)Kingambit or (int)Overqwil;
}
private const ushort NONE = 0;
private const ushort EEVEE = ushort.MaxValue;

View File

@@ -1,4 +1,3 @@
using System;
using static PKHeX.Core.LegalityCheckStrings;
namespace PKHeX.Core;
@@ -105,20 +104,13 @@ private static void VerifyEC100(LegalityAnalysis data, ushort encSpecies)
// Indicate the evolution for the user.
uint evoVal = pk.EncryptionConstant % 100;
bool rare = evoVal == 0;
var (species, form) = GetEvolvedSpeciesForm(encSpecies, rare);
var (species, form) = EvolutionRestrictions.GetEvolvedSpeciesFormEC100(encSpecies, rare);
var str = GameInfo.Strings;
var forms = FormConverter.GetFormList(species, str.Types, str.forms, GameInfo.GenderSymbolASCII, EntityContext.Gen9);
var msg = string.Format(L_XRareFormEvo_0_1, forms[form], rare);
data.AddLine(GetValid(msg, CheckIdentifier.EC));
}
private static (ushort, int) GetEvolvedSpeciesForm(ushort species, bool rare) => species switch
{
(int)Species.Tandemaus => ((ushort)Species.Maushold, rare ? 0 : 1),
(int)Species.Dunsparce => ((ushort)Species.Dudunsparce, rare ? 1 : 0),
_ => throw new ArgumentOutOfRangeException(nameof(species), species, "Incorrect EC%100 species."),
};
private static void VerifyEC(LegalityAnalysis data)
{
var pk = data.Entity;