mirror of
https://github.com/kwsch/PKHeX
synced 2024-11-22 12:03:10 +00:00
Add ball deferral & met level leniency for gen3/4
Fixes some issues reported via discord
This commit is contained in:
parent
4e56a2b756
commit
3358038172
6 changed files with 115 additions and 35 deletions
|
@ -21,6 +21,29 @@ public sealed class EncounterGenerator3 : IEncounterGenerator
|
|||
return GetEncounters(pk, chain, info);
|
||||
}
|
||||
|
||||
private enum DeferralType
|
||||
{
|
||||
None,
|
||||
PIDIV,
|
||||
Tile,
|
||||
Ball,
|
||||
SlotNumber,
|
||||
}
|
||||
|
||||
private struct Deferral
|
||||
{
|
||||
public DeferralType Type;
|
||||
public IEncounterable? Encounter;
|
||||
|
||||
public void Update(DeferralType type, IEncounterable enc)
|
||||
{
|
||||
if (Type >= type)
|
||||
return;
|
||||
Type = type;
|
||||
Encounter = enc;
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<IEncounterable> GetEncounters(PKM pk, EvoCriteria[] chain, LegalInfo info)
|
||||
{
|
||||
if (chain.Length == 0)
|
||||
|
@ -29,8 +52,7 @@ public sealed class EncounterGenerator3 : IEncounterGenerator
|
|||
info.PIDIV = MethodFinder.Analyze(pk);
|
||||
var game = pk.Version;
|
||||
var iterator = new EncounterEnumerator3(pk, chain, game);
|
||||
IEncounterable? deferType = null;
|
||||
EncounterSlot3? deferSlot = null;
|
||||
Deferral defer = default;
|
||||
var leadQueue = new LeadEncounterQueue<EncounterSlot3>();
|
||||
|
||||
bool emerald = pk.E;
|
||||
|
@ -43,7 +65,12 @@ public sealed class EncounterGenerator3 : IEncounterGenerator
|
|||
var e = enc.Encounter;
|
||||
if (!IsTypeCompatible(e, pk, info.PIDIV.Type))
|
||||
{
|
||||
deferType ??= e;
|
||||
defer.Update(DeferralType.PIDIV, e);
|
||||
continue;
|
||||
}
|
||||
if (!IsBallCompatible(e, pk))
|
||||
{
|
||||
defer.Update(DeferralType.Ball, e);
|
||||
continue;
|
||||
}
|
||||
if (e is not EncounterSlot3 slot)
|
||||
|
@ -76,7 +103,7 @@ public sealed class EncounterGenerator3 : IEncounterGenerator
|
|||
var lead = LeadFinder.GetLeadInfo3(slot, info.PIDIV, evo, emerald, gender, pk.Format);
|
||||
if (!lead.IsValid())
|
||||
{
|
||||
deferSlot ??= slot;
|
||||
defer.Update(DeferralType.SlotNumber, slot);
|
||||
continue;
|
||||
}
|
||||
leadQueue.Insert(lead, slot);
|
||||
|
@ -90,19 +117,22 @@ public sealed class EncounterGenerator3 : IEncounterGenerator
|
|||
if (leadQueue.List.Count != 0)
|
||||
yield break;
|
||||
|
||||
// Error will be flagged later if this is chosen.
|
||||
if (deferSlot != null)
|
||||
{
|
||||
info.ManualFlag = EncounterYieldFlag.InvalidFrame;
|
||||
yield return deferSlot;
|
||||
}
|
||||
else if (deferType != null)
|
||||
{
|
||||
// Errors will be flagged later for those not manually handled below.
|
||||
if (defer.Encounter is not { } lastResort)
|
||||
yield break;
|
||||
if (defer.Type is DeferralType.PIDIV)
|
||||
info.ManualFlag = EncounterYieldFlag.InvalidPIDIV;
|
||||
yield return deferType;
|
||||
}
|
||||
else if (defer.Type is DeferralType.Tile)
|
||||
info.ManualFlag = EncounterYieldFlag.InvalidFrame;
|
||||
yield return lastResort;
|
||||
}
|
||||
|
||||
private static bool IsBallCompatible(IFixedBall e, PKM pk) => e.FixedBall switch
|
||||
{
|
||||
Ball.Safari when pk.Ball is (byte)Ball.Safari => true,
|
||||
_ => pk.Ball is not (byte)Ball.Safari,
|
||||
};
|
||||
|
||||
private static bool IsTypeCompatible(IEncounterTemplate enc, PKM pk, PIDType type)
|
||||
{
|
||||
if (enc is IRandomCorrelation r)
|
||||
|
|
|
@ -26,14 +26,35 @@ public sealed class EncounterGenerator4 : IEncounterGenerator
|
|||
yield return enc;
|
||||
}
|
||||
|
||||
private enum DeferralType
|
||||
{
|
||||
None,
|
||||
PIDIV,
|
||||
Tile,
|
||||
Ball,
|
||||
SlotNumber,
|
||||
}
|
||||
|
||||
private struct Deferral
|
||||
{
|
||||
public DeferralType Type;
|
||||
public IEncounterable? Encounter;
|
||||
|
||||
public void Update(DeferralType type, IEncounterable enc)
|
||||
{
|
||||
if (Type >= type)
|
||||
return;
|
||||
Type = type;
|
||||
Encounter = enc;
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<IEncounterable> GetEncounters(PKM pk, EvoCriteria[] chain, LegalInfo info)
|
||||
{
|
||||
info.PIDIV = MethodFinder.Analyze(pk);
|
||||
var game = pk.Version;
|
||||
var iterator = new EncounterEnumerator4(pk, chain, game);
|
||||
EncounterSlot4? deferSlot = null;
|
||||
IEncounterable? deferTile = null;
|
||||
IEncounterable? deferType = null;
|
||||
Deferral defer = default;
|
||||
var leadQueue = new LeadEncounterQueue<EncounterSlot4>();
|
||||
|
||||
foreach (var enc in iterator)
|
||||
|
@ -41,17 +62,25 @@ public sealed class EncounterGenerator4 : IEncounterGenerator
|
|||
var e = enc.Encounter;
|
||||
if (!IsTileCompatible(e, pk))
|
||||
{
|
||||
deferTile ??= e;
|
||||
defer.Update(DeferralType.Tile, e);
|
||||
continue;
|
||||
}
|
||||
if (!IsTypeCompatible(e, pk, info.PIDIV.Type))
|
||||
{
|
||||
deferType ??= e;
|
||||
defer.Update(DeferralType.PIDIV, e);
|
||||
continue;
|
||||
}
|
||||
if (!IsBallCompatible(e, pk))
|
||||
{
|
||||
defer.Update(DeferralType.Ball, e);
|
||||
continue;
|
||||
}
|
||||
if (e is not EncounterSlot4 slot)
|
||||
{
|
||||
yield return e;
|
||||
if (pk.Ball is (byte)Ball.Safari or (byte)Ball.Sport)
|
||||
defer.Update(DeferralType.Ball, e);
|
||||
else
|
||||
yield return e;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -59,7 +88,7 @@ public sealed class EncounterGenerator4 : IEncounterGenerator
|
|||
var lead = LeadFinder.GetLeadInfo4(pk, slot, info.PIDIV, evo);
|
||||
if (!lead.IsValid())
|
||||
{
|
||||
deferSlot ??= slot;
|
||||
defer.Update(DeferralType.SlotNumber, slot);
|
||||
continue;
|
||||
}
|
||||
leadQueue.Insert(lead, slot);
|
||||
|
@ -73,23 +102,23 @@ public sealed class EncounterGenerator4 : IEncounterGenerator
|
|||
if (leadQueue.List.Count != 0)
|
||||
yield break;
|
||||
|
||||
// Error will be flagged later if this is chosen.
|
||||
if (deferTile != null)
|
||||
{
|
||||
yield return deferTile;
|
||||
}
|
||||
else if (deferSlot != null)
|
||||
{
|
||||
info.ManualFlag = EncounterYieldFlag.InvalidFrame;
|
||||
yield return deferSlot;
|
||||
}
|
||||
else if (deferType != null)
|
||||
{
|
||||
// Errors will be flagged later for those not manually handled below.
|
||||
if (defer.Encounter is not { } lastResort)
|
||||
yield break;
|
||||
if (defer.Type is DeferralType.PIDIV)
|
||||
info.ManualFlag = EncounterYieldFlag.InvalidPIDIV;
|
||||
yield return deferType;
|
||||
}
|
||||
else if (defer.Type is DeferralType.Tile)
|
||||
info.ManualFlag = EncounterYieldFlag.InvalidFrame;
|
||||
yield return lastResort;
|
||||
}
|
||||
|
||||
private static bool IsBallCompatible(IFixedBall e, PKM pk) => e.FixedBall switch
|
||||
{
|
||||
Ball.Safari when pk.Ball is (byte)Ball.Safari => true,
|
||||
Ball.Sport when pk.Ball is (byte)Ball.Sport => true,
|
||||
_ => pk.Ball is not ((byte)Ball.Safari or (byte)Ball.Sport),
|
||||
};
|
||||
|
||||
private static bool IsTileCompatible(IEncounterTemplate enc, PKM pk)
|
||||
{
|
||||
if (pk is not IGroundTile e)
|
||||
|
|
|
@ -91,6 +91,8 @@ public static class EvolutionChain
|
|||
return [];
|
||||
|
||||
var chain = result[..count];
|
||||
if (IsMetLost(pk, enc)) // Original met level lost, need to be more permissive on evos.
|
||||
EvolutionUtil.ConditionEncounterNoMet(chain);
|
||||
return chain.ToArray();
|
||||
}
|
||||
|
||||
|
@ -121,6 +123,13 @@ public static class EvolutionChain
|
|||
return count;
|
||||
}
|
||||
|
||||
private static bool IsMetLost(PKM pk, EvolutionOrigin enc) => enc.Generation switch
|
||||
{
|
||||
>= 5 => false,
|
||||
<= 2 => pk is not ICaughtData2 { MetLevel: not 0 },
|
||||
_ => enc.Generation != pk.Format,
|
||||
};
|
||||
|
||||
private static int DevolveFrom(Span<EvoCriteria> result, PKM pk, EvolutionOrigin enc, EntityContext context, ushort encSpecies, bool discard)
|
||||
{
|
||||
var group = EvolutionGroupUtil.GetGroup(context);
|
||||
|
|
|
@ -163,4 +163,16 @@ internal static class EvolutionUtil
|
|||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
public static void ConditionEncounterNoMet(Span<EvoCriteria> chain)
|
||||
{
|
||||
// Allow for under-leveled evolutions for purposes of finding an under-leveled evolved encounter.
|
||||
// e.g. a level 5 Silcoon encounter slot (normally needs level 7).
|
||||
for (int i = 0; i < chain.Length - 1; i++)
|
||||
{
|
||||
ref var evo = ref chain[i];
|
||||
if (evo.Method.IsLevelUpRequired())
|
||||
evo = evo with { LevelMin = (byte)(chain[i + 1].LevelMin + evo.LevelUpRequired) };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Binary file not shown.
Binary file not shown.
Loading…
Reference in a new issue