mirror of
https://github.com/kwsch/PKHeX.git
synced 2026-03-21 17:48:28 -05:00
Misc legality fixes for Z-A alterations
- Evolving knowing move: relearnable additions in the evolved stage was bypassing the requirement (Sylveon can relearn Charm at any level, but Eevee cannot). Prune tree to only check if pre-evolutions could have learned move. - FormArgument requiring a minimum level to actually use the move (Primeape). Probably isn't a "complete" check, since it's implemented differently compared to Qwilfish's logic. Might be worth revising in the future to be consistent (using the same as Primeape logic? if in game, and can learn, can increase from 0). - Flag Hangry Morpeko if cannot learn Aura Wheel yet - Flag mega evo mismatches for Tatsugiri/Magearna/Meowstic - Permit mega meowstic gender in party - Remap DLC TMs (I forgot this remapping was needed; pkNX dumped it but I didn't update the table until now...)
This commit is contained in:
parent
1edfbfab0e
commit
6609dd210b
|
|
@ -99,4 +99,43 @@ public EvolutionHistory AsSingle(EntityContext context)
|
|||
single.Set(context, Get(context).ToArray());
|
||||
return single;
|
||||
}
|
||||
|
||||
public EvolutionHistory PruneKeepPreEvolutions(ushort species) => new()
|
||||
{
|
||||
Gen1 = PruneKeepPreEvolutions(Gen1, species),
|
||||
Gen2 = PruneKeepPreEvolutions(Gen2, species),
|
||||
Gen3 = PruneKeepPreEvolutions(Gen3, species),
|
||||
Gen4 = PruneKeepPreEvolutions(Gen4, species),
|
||||
Gen5 = PruneKeepPreEvolutions(Gen5, species),
|
||||
Gen6 = PruneKeepPreEvolutions(Gen6, species),
|
||||
Gen7 = PruneKeepPreEvolutions(Gen7, species),
|
||||
Gen8 = PruneKeepPreEvolutions(Gen8, species),
|
||||
Gen9 = PruneKeepPreEvolutions(Gen9, species),
|
||||
Gen7b = PruneKeepPreEvolutions(Gen7b, species),
|
||||
Gen8a = PruneKeepPreEvolutions(Gen8a, species),
|
||||
Gen8b = PruneKeepPreEvolutions(Gen8b, species),
|
||||
Gen9a = PruneKeepPreEvolutions(Gen9a, species),
|
||||
};
|
||||
|
||||
private static EvoCriteria[] PruneKeepPreEvolutions(EvoCriteria[] src, ushort species)
|
||||
{
|
||||
// Most evolved species is at the lowest index.
|
||||
// If `species` is at the current index, only keep indexes after.
|
||||
var start = GetSpeciesIndex(src, species);
|
||||
if (start == -1)
|
||||
return src;
|
||||
if (start == src.Length - 1)
|
||||
return NONE;
|
||||
return src[(start + 1)..];
|
||||
}
|
||||
|
||||
private static int GetSpeciesIndex(ReadOnlySpan<EvoCriteria> array, ushort species)
|
||||
{
|
||||
for (int i = 0; i < array.Length; i++)
|
||||
{
|
||||
if (array[i].Species == species)
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -68,6 +68,7 @@ public static bool IsFormArgEvolution(ushort species)
|
|||
[
|
||||
(int)Charm,
|
||||
(int)BabyDollEyes,
|
||||
(int)DisarmingVoice, // Z-A
|
||||
];
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -90,34 +91,23 @@ public static bool IsValidEvolutionWithMove(PKM pk, LegalInfo info)
|
|||
var move = GetSpeciesEvolutionMove(species);
|
||||
if (move is NONE)
|
||||
return true; // not a move evolution
|
||||
if (move is EEVEE)
|
||||
return IsValidEvolutionWithMoveSylveon(pk, enc, info);
|
||||
if (!IsMoveSlotAvailable(info.Moves))
|
||||
return false;
|
||||
|
||||
if (pk.HasMove(move))
|
||||
return true;
|
||||
|
||||
// Check the entire chain to see if it could have learnt it at any point.
|
||||
var head = LearnGroupUtil.GetCurrentGroup(pk);
|
||||
return MemoryPermissions.GetCanKnowMove(enc, move, info.EvoChainsAllGens, pk, head);
|
||||
var pruned = info.EvoChainsAllGens.PruneKeepPreEvolutions(species);
|
||||
if (move is EEVEE)
|
||||
return IsValidEvolutionWithMoveAny(enc, EeveeFairyMoves, pruned, pk, head);
|
||||
|
||||
return MemoryPermissions.GetCanKnowMove(enc, move, pruned, pk, head);
|
||||
}
|
||||
|
||||
private static bool IsValidEvolutionWithMoveSylveon(PKM pk, IEncounterTemplate enc, LegalInfo info)
|
||||
private static bool IsValidEvolutionWithMoveAny(IEncounterTemplate enc, ReadOnlySpan<ushort> any, EvolutionHistory history, PKM pk, ILearnGroup head)
|
||||
{
|
||||
if (!IsMoveSlotAvailable(info.Moves))
|
||||
return false;
|
||||
|
||||
foreach (var move in EeveeFairyMoves)
|
||||
foreach (var move in any)
|
||||
{
|
||||
if (pk.HasMove(move))
|
||||
return true;
|
||||
}
|
||||
|
||||
var head = LearnGroupUtil.GetCurrentGroup(pk);
|
||||
foreach (var move in EeveeFairyMoves)
|
||||
{
|
||||
if (MemoryPermissions.GetCanKnowMove(enc, move, info.EvoChainsAllGens, pk, head))
|
||||
if (MemoryPermissions.GetCanKnowMove(enc, move, history, pk, head))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -146,7 +146,6 @@ public enum LegalityCheckResultCode : ushort
|
|||
FormPikachuCosplay,
|
||||
FormPikachuCosplayInvalid,
|
||||
FormPikachuEventInvalid,
|
||||
FormInvalidExpect_0,
|
||||
FormValid,
|
||||
FormVivillon,
|
||||
FormVivillonEventPre,
|
||||
|
|
@ -398,6 +397,7 @@ public enum LegalityCheckResultCode : ushort
|
|||
EvoTradeReqOutsider_0,
|
||||
FormArgumentLEQ_0,
|
||||
FormArgumentGEQ_0,
|
||||
FormInvalidExpect_0,
|
||||
HyperTrainLevelGEQ_0, // level
|
||||
IVAllEqual_0,
|
||||
IVFlawlessCountGEQ_0, // count
|
||||
|
|
|
|||
|
|
@ -92,6 +92,9 @@ public static bool IsMegaForm(ushort species, byte form)
|
|||
(ushort)Mimikyu => (byte)(form & 2),
|
||||
(ushort)Ogerpon => (byte)(form & 3),
|
||||
(ushort)Floette => 5,
|
||||
(ushort)Tatsugiri => (byte)(form - 3), // Mega (form specific)
|
||||
(ushort)Magearna => (byte)(form - 2), // Mega (form specific)
|
||||
(ushort)Meowstic => (byte)(form - 2), // Mega (gendered)
|
||||
_ => 0,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -68,11 +68,7 @@ private CheckResult VerifyFormArgument(LegalityAnalysis data, IFormArgument f)
|
|||
> 9_999 => GetInvalid(FormArgumentLEQ_0, 9999),
|
||||
_ => arg == 0 || HasVisitedPLA(data, Stantler) ? GetValid(FormArgumentValid) : GetInvalid(FormArgumentNotAllowed),
|
||||
},
|
||||
Primeape => arg switch
|
||||
{
|
||||
> 9_999 => GetInvalid(FormArgumentLEQ_0, 9999),
|
||||
_ => arg == 0 || HasVisitedSV(data, Primeape) || HasVisitedZA(data, Primeape) ? GetValid(FormArgumentValid) : GetInvalid(FormArgumentNotAllowed),
|
||||
},
|
||||
Primeape => CheckPrimeape(data, pk, arg, enc),
|
||||
Bisharp => arg switch
|
||||
{
|
||||
> 9_999 => GetInvalid(FormArgumentLEQ_0, 9999),
|
||||
|
|
@ -123,6 +119,27 @@ private CheckResult VerifyFormArgument(LegalityAnalysis data, IFormArgument f)
|
|||
};
|
||||
}
|
||||
|
||||
private CheckResult CheckPrimeape(LegalityAnalysis data, PKM pk, uint arg, IEncounterable enc)
|
||||
{
|
||||
if (arg == 0)
|
||||
return GetValid(FormArgumentValid);
|
||||
if (arg > 9_999)
|
||||
return GetInvalid(FormArgumentLEQ_0, 9999);
|
||||
|
||||
if (HasVisitedSV(data, Primeape) || HasVisitedZA(data, Primeape))
|
||||
{
|
||||
const ushort move = (ushort)Move.RageFist;
|
||||
// Eager check
|
||||
if (pk.HasMove(move))
|
||||
return GetValid(FormArgumentValid);
|
||||
|
||||
var head = LearnGroupUtil.GetCurrentGroup(pk);
|
||||
if (MemoryPermissions.GetCanKnowMove(enc, move, data.Info.EvoChainsAllGens, pk, head))
|
||||
return GetValid(FormArgumentValid);
|
||||
}
|
||||
return GetInvalid(FormArgumentLEQ_0, 0); // Can't increase from 0.
|
||||
}
|
||||
|
||||
private CheckResult CheckFarfetchd(LegalityAnalysis data, PKM pk, uint arg)
|
||||
{
|
||||
if (arg == 0)
|
||||
|
|
|
|||
|
|
@ -143,7 +143,7 @@ private CheckResult VerifyForm(LegalityAnalysis data)
|
|||
if (enc is not EncounterGift9a)
|
||||
return GetInvalid(FormEternalInvalid);
|
||||
return GetValid(FormEternal);
|
||||
case Meowstic when form != pk.Gender:
|
||||
case Meowstic when (form & 1) != pk.Gender:
|
||||
return GetInvalid(GenderInvalidNone);
|
||||
|
||||
case Silvally:
|
||||
|
|
@ -197,7 +197,14 @@ private CheckResult VerifyBattleForms9a(LegalityAnalysis data, ushort species, b
|
|||
|
||||
// Battle forms can exist in Party.
|
||||
if (!FormInfo.IsMegaForm(species, form) && !FormInfo.IsPrimalForm(species, form))
|
||||
{
|
||||
// Morpeko-1 can exist in party, but only if it's at a level where it can know the move Aura Wheel; only learns starting at Lv. 57.
|
||||
// You can use move menu to forget Aura Wheel while it's in Hangry Mode, but the form doesn't revert, kinda like Mega Rayquaza with Dragon Ascent
|
||||
if (species is (int)Morpeko && !MemoryPermissions.GetCanKnowMove(data.EncounterMatch, (ushort)Move.AuraWheel, data.Info.EvoChainsAllGens, data.Entity, LearnGroupUtil.GetCurrentGroup(data.Entity)))
|
||||
return GetInvalid(FormInvalidExpect_0, 0);
|
||||
|
||||
return VALID;
|
||||
}
|
||||
|
||||
var megaStone = ItemStorage9ZA.GetExpectedMegaStoneOrPrimalOrb(species, form);
|
||||
if (megaStone == 0 || data.Entity.HeldItem == megaStone)
|
||||
|
|
|
|||
|
|
@ -258,5 +258,12 @@ public static ushort GetTechnicalMachineIndex9a(ushort oldTM)
|
|||
-68, +06, -68, -07, -07, -64, -71, -07, +15, -07,
|
||||
-07, -07, -07, -07, -90, -07, -07, -07, -80, -07,
|
||||
-63, 0, -08, -08, -13, -08, -71, -08, -08,
|
||||
0,
|
||||
+01, +02, +02, +03, +04, +06, +06, +06, +07, +08,
|
||||
+09, +12, +12, +13, +15, +17, +17, +29, +29, -21,
|
||||
-20, -19, -17, -16, -15, -15, -12, -11, -10, -09,
|
||||
-09, -09, -07, -06, -06, -05, -05, -03, -03, -03,
|
||||
-03, -03, -03, -03, -03, -03, -03, -03, -03, -01,
|
||||
-01, -01,
|
||||
];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -58,15 +58,24 @@ public static class TechnicalMachine9a
|
|||
public static int SetAllTechnicalMachines(SAV9ZA sav, bool collected = false)
|
||||
{
|
||||
int ctr = 0;
|
||||
var field = sav.Blocks.FieldItems;
|
||||
var inv = sav.Items;
|
||||
var finalQuantity = collected ? 1 : 0;
|
||||
foreach (var item in TechnicalMachines)
|
||||
{
|
||||
var hash = FnvHash.HashFnv1a_64(item.FieldItem);
|
||||
var index = sav.Blocks.FieldItems.GetIndex(hash);
|
||||
var index = field.GetIndex(hash);
|
||||
if (index == -1)
|
||||
continue; // Shouldn't happen. All TMs should be populated in a save file, except if it's a DLC TM (not applicable).
|
||||
sav.Blocks.FieldItems.SetValue(index, collected);
|
||||
sav.Items.SetItemQuantity(item.ItemID, collected ? 1 : 0);
|
||||
|
||||
ctr++;
|
||||
if (field.GetValue(index) != collected)
|
||||
field.SetValue(index, collected);
|
||||
else
|
||||
ctr--;
|
||||
|
||||
if (inv.GetItemQuantity(item.ItemID) != finalQuantity)
|
||||
inv.SetItemQuantity(item.ItemID, finalQuantity);
|
||||
}
|
||||
return ctr;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user