using System; namespace PKHeX.Core; /// /// Modifications using legality. /// internal static class BatchModifications { private static bool IsAll(ReadOnlySpan p) => p.EndsWith("All", StringComparison.OrdinalIgnoreCase); private static bool IsNone(ReadOnlySpan p) => p.EndsWith("None", StringComparison.OrdinalIgnoreCase); /// /// Sets a suggested legal moveset for the Entity. /// public static ModifyResult SetSuggestedMoveset(BatchInfo info, bool random = false) { Span moves = stackalloc ushort[4]; info.Legality.GetMoveSet(moves, random); return SetMoves(info.Entity, moves); } /// /// Sets a suggested legal relearn moveset for the Entity. /// public static ModifyResult SetSuggestedRelearnData(BatchInfo info, ReadOnlySpan propValue) { var pk = info.Entity; if (pk is ITechRecord t) { if (IsNone(propValue)) t.SetRecordFlags(pk, TechnicalRecordApplicatorOption.None); else if (IsAll(propValue)) t.SetRecordFlags(pk, TechnicalRecordApplicatorOption.LegalAll, info.Legality); else t.SetRecordFlags(pk, TechnicalRecordApplicatorOption.LegalCurrent, info.Legality); } pk.SetRelearnMoves(info.Legality); return ModifyResult.Modified; } /// /// Sets all legal Move Mastery flag data for the Entity. /// /// Only applicable for . public static ModifyResult SetSuggestedMasteryData(BatchInfo info, ReadOnlySpan propValue) { var pk = info.Entity; if (pk is not IMoveShop8Mastery t) return ModifyResult.Skipped; t.ClearMoveShopFlags(); if (IsNone(propValue)) return ModifyResult.Modified; var enc = info.Legality.EncounterMatch; if (enc is IMasteryInitialMoveShop8 shop) shop.SetInitialMastery(pk, enc); if (IsAll(propValue)) { t.SetPurchasedFlagsAll(pk); t.SetMoveShopFlagsAll(pk); } else { t.SetMoveShopFlags(pk); } return ModifyResult.Modified; } /// /// Sets all legal Plus Move flag data for the Entity. /// /// Only applicable for . public static ModifyResult SetSuggestedMovePlusData(BatchInfo info, ReadOnlySpan value) { var pk = info.Entity; if (pk is not IPlusRecord t || pk.PersonalInfo is not IPermitPlus p) return ModifyResult.Skipped; PlusRecordApplicatorOption option; if (IsNone(value)) option = PlusRecordApplicatorOption.None; else if (IsAll(value)) option = PlusRecordApplicatorOption.LegalSeedTM; else option = PlusRecordApplicatorOption.LegalCurrent; t.SetPlusFlags(p, option, info.Legality); return ModifyResult.Modified; } /// /// Sets suggested ribbon data for the Entity. /// /// If None, removes all ribbons possible. public static ModifyResult SetSuggestedRibbons(BatchInfo info, ReadOnlySpan value) { if (IsNone(value)) RibbonApplicator.RemoveAllValidRibbons(info.Legality); else if (IsAll(value)) RibbonApplicator.SetAllValidRibbons(info.Legality); else // Only for current context RibbonApplicator.SetAllValidRibbons(info.Entity, info.Legality.EncounterMatch, info.Legality.Info.EvoChainsAllGens.AsSingle(info.Entity.Context)); return ModifyResult.Modified; } /// /// Sets suggested met data for the Entity. /// public static ModifyResult SetSuggestedMetData(BatchInfo info) { var pk = info.Entity; var encounter = EncounterSuggestion.GetSuggestedMetInfo(pk); if (encounter is null) return ModifyResult.Error; var location = encounter.Location; var level = encounter.LevelMin; var minimumLevel = EncounterSuggestion.GetLowestLevel(pk, level); var current = Math.Max(minimumLevel, level); if (pk.MetLevel == level && pk.MetLocation == location && pk.CurrentLevel == current) return ModifyResult.Skipped; pk.MetLevel = level; pk.MetLocation = location; pk.CurrentLevel = current; return ModifyResult.Modified; } /// /// Sets the lowest current level for the Entity. /// public static ModifyResult SetMinimumCurrentLevel(BatchInfo info) { var result = EncounterSuggestion.IterateMinimumCurrentLevel(info.Entity, info.Legal); return result ? ModifyResult.Modified : ModifyResult.Skipped; } /// /// Sets the provided moves in a random order. /// /// Pokémon to modify. /// Moves to apply. public static ModifyResult SetMoves(PKM pk, ReadOnlySpan moves) { Span current = stackalloc ushort[4]; pk.GetMoves(current); if (current.SequenceEqual(moves)) return ModifyResult.Skipped; pk.SetMoves(moves); return ModifyResult.Modified; } public static ModifyResult SetEVs(PKM pk) { Span evs = stackalloc int[6]; EffortValues.SetMax(evs, pk); Span current = stackalloc int[6]; pk.GetEVs(current); if (current.SequenceEqual(evs)) return ModifyResult.Skipped; pk.SetEVs(evs); return ModifyResult.Modified; } /// /// Sets the contests stats as requested. /// /// Pokémon to modify. /// Legality Information matched to. /// Option to apply with public static ModifyResult SetContestStats(PKM pk, LegalityAnalysis la, ReadOnlySpan option) { if (option.Length != 0 && option[EntityBatchEditor.CONST_SUGGEST.Length..] is not "0") pk.SetMaxContestStats(la.EncounterMatch, la.Info.EvoChainsAllGens); else pk.SetSuggestedContestStats(la.EncounterMatch, la.Info.EvoChainsAllGens); return ModifyResult.Modified; } public static ModifyResult SetSuggestedCurrentFriendship(BatchInfo info) { var pk = info.Entity; var value = HistoryVerifier.GetSuggestedFriendshipCurrent(pk, info.Legality.EncounterMatch); if (pk.CurrentFriendship == value) return ModifyResult.Skipped; pk.CurrentFriendship = value; return ModifyResult.Modified; } public static ModifyResult SetSuggestedOriginalTrainerFriendship(BatchInfo info) { var pk = info.Entity; var value = HistoryVerifier.GetSuggestedFriendshipOT(pk, info.Legality.EncounterMatch); if (pk.OriginalTrainerFriendship == value) return ModifyResult.Skipped; pk.OriginalTrainerFriendship = value; return ModifyResult.Modified; } public static ModifyResult SetSuggestedHandlingTrainerFriendship(BatchInfo info) { var pk = info.Entity; var value = HistoryVerifier.GetSuggestedFriendshipHT(pk); if (pk.HandlingTrainerFriendship == value) return ModifyResult.Skipped; pk.HandlingTrainerFriendship = value; return ModifyResult.Modified; } }