diff --git a/PKHeX.Core/Legality/Encounters/Data/Gen5/Encounters5B2W2.cs b/PKHeX.Core/Legality/Encounters/Data/Gen5/Encounters5B2W2.cs index eb09beeb7..9876a9cd7 100644 --- a/PKHeX.Core/Legality/Encounters/Data/Gen5/Encounters5B2W2.cs +++ b/PKHeX.Core/Legality/Encounters/Data/Gen5/Encounters5B2W2.cs @@ -1,6 +1,7 @@ using static PKHeX.Core.EncounterUtil; using static PKHeX.Core.GameVersion; using static PKHeX.Core.AbilityPermission; +using static PKHeX.Core.GlobalLinkPromotion; namespace PKHeX.Core; @@ -69,15 +70,23 @@ public static class Encounters5B2W2 new(533, 25, 067, 183, 409), // Gurdurr // PGL - new(575, 32, 243, Gender: 0), // Gothorita - new(025, 10, 029, Gender: 0), // Pikachu - new(511, 10, 437, Gender: 0), // Pansage - new(513, 10, 257, Gender: 0), // Pansear - new(515, 10, 056, Gender: 0), // Panpour - new(387, 10, 254, Gender: 0), // Turtwig - new(390, 10, 252, Gender: 0), // Chimchar - new(393, 10, 297, Gender: 0), // Piplup - new(575, 32, 286, Gender: 0), // Gothorita + new(025, 10, 029, Gender: 0, Promotion: Pikachu), + new(387, 10, 254, Gender: 0, Promotion: StartersSinnoh2), // Turtwig + new(390, 10, 252, Gender: 0, Promotion: StartersSinnoh2), // Chimchar + new(393, 10, 297, Gender: 0, Promotion: StartersSinnoh2), // Piplup + new(511, 10, 437, Gender: 0, Promotion: MonkeyUnova), // Pansage + new(513, 10, 257, Gender: 0, Promotion: MonkeyUnova), // Pansear + new(515, 10, 056, Gender: 0, Promotion: MonkeyUnova), // Panpour + new(575, 32, 243, Gender: 0, Promotion: Gothorita1), // Mirror Coat + new(575, 32, 286, Gender: 0, Promotion: Gothorita2), // Imprison + + // PGL (Both Versions) + new (149, 55, 009, Gender: 0, Promotion: Dragonite1), // JPN/KOR ThunderPunch + new (149, 55, 245, Gender: 0, Promotion: Dragonite2), // INT ExtremeSpeed + new(212, 10, 211, Gender: 0, Promotion: Scizor), // INT Steel Wing + new(248, 55, 069, Gender: 0, Promotion: Tyranitar), // INT Seismic Toss + new(376, 45, 038, Gender: 0, Promotion: Metagross), // INT Double-Edge + new(445, 48, 242, Gender: 0, Promotion: Garchomp), // INT Crunch ]); #endregion #region Static Encounter/Gift Tables diff --git a/PKHeX.Core/Legality/Encounters/Data/Gen5/Encounters5BW.cs b/PKHeX.Core/Legality/Encounters/Data/Gen5/Encounters5BW.cs index ac132959a..2809a475c 100644 --- a/PKHeX.Core/Legality/Encounters/Data/Gen5/Encounters5BW.cs +++ b/PKHeX.Core/Legality/Encounters/Data/Gen5/Encounters5BW.cs @@ -1,6 +1,7 @@ using static PKHeX.Core.EncounterUtil; using static PKHeX.Core.GameVersion; using static PKHeX.Core.AbilityPermission; +using static PKHeX.Core.GlobalLinkPromotion; namespace PKHeX.Core; @@ -88,34 +89,46 @@ public static class Encounters5BW new(336, 10, 044, 034, 401), // Seviper // PGL - new(134, 10, Gender: 0), // Vaporeon - new(135, 10, Gender: 0), // Jolteon - new(136, 10, Gender: 0), // Flareon - new(196, 10, Gender: 0), // Espeon - new(197, 10, Gender: 0), // Umbreon - new(470, 10, Gender: 0), // Leafeon - new(471, 10, Gender: 0), // Glaceon - new(001, 10, Gender: 0), // Bulbasaur - new(004, 10, Gender: 0), // Charmander - new(007, 10, Gender: 0), // Squirtle - new(453, 10, Gender: 0), // Croagunk - new(387, 10, Gender: 0), // Turtwig - new(390, 10, Gender: 0), // Chimchar - new(393, 10, Gender: 0), // Piplup - new(493, 100), // Arceus - new(252, 10, Gender: 0), // Treecko - new(255, 10, Gender: 0), // Torchic - new(258, 10, Gender: 0), // Mudkip - new(468, 10, 217, Gender: 0), // Togekiss - new(473, 34, Gender: 0), // Mamoswine - new(137, 10), // Porygon - new(384, 50), // Rayquaza - new(354, 37, 538, Gender: 1), // Banette - new(453, 10, 398, Gender: 0), // Croagunk - new(334, 35, 206, Gender: 0), // Altaria - new(242, 10), // Blissey - new(448, 10, 418, Gender: 0), // Lucario - new(189, 27, 206, Gender: 0), // Jumpluff + new(134, 10, Gender: 0, Promotion: Eeveelutions), // Vaporeon + new(135, 10, Gender: 0, Promotion: Eeveelutions), // Jolteon + new(136, 10, Gender: 0, Promotion: Eeveelutions), // Flareon + new(196, 10, Gender: 0, Promotion: Eeveelutions), // Espeon + new(197, 10, Gender: 0, Promotion: Eeveelutions), // Umbreon + new(470, 10, Gender: 0, Promotion: Eeveelutions), // Leafeon + new(471, 10, Gender: 0, Promotion: Eeveelutions), // Glaceon + new(001, 10, Gender: 0, Promotion: StartersKanto), // Bulbasaur + new(004, 10, Gender: 0, Promotion: StartersKanto), // Charmander + new(007, 10, Gender: 0, Promotion: StartersKanto), // Squirtle + new(387, 10, Gender: 0, Promotion: StartersSinnoh), // Turtwig + new(390, 10, Gender: 0, Promotion: StartersSinnoh), // Chimchar + new(393, 10, Gender: 0, Promotion: StartersSinnoh), // Piplup + new(252, 10, Gender: 0, Promotion: StartersHoenn), // Treecko + new(255, 10, Gender: 0, Promotion: StartersHoenn), // Torchic + new(258, 10, Gender: 0, Promotion: StartersHoenn), // Mudkip + new(473, 34, Gender: 0, Promotion: Mamoswine), + new(453, 10, Gender: 0, Promotion: Croagunk1), // JPN/KOR + + // PGL - Single Gender implied + new(493, 100, Promotion: Arceus), + new(137, 10, Promotion: Porygon), + new(384, 50, Promotion: Rayquaza), + new(242, 10, Promotion: Blissey), + + // PGL - Now with moves! + new(453, 10, 398, Gender: 0, Promotion: Croagunk2), // INT + new(189, 27, 206, Gender: 0, Promotion: Jumpluff), + new(334, 35, 206, Gender: 0, Promotion: Altaria), + new(354, 37, 538, Gender: 1, Promotion: Banette), + new(448, 10, 418, Gender: 0, Promotion: Lucario), + new(468, 10, 217, Gender: 0, Promotion: Togekiss), + + // PGL (Both Versions) + new (149, 55, 009, Gender: 0, Promotion: Dragonite1), // JPN/KOR ThunderPunch + new (149, 55, 245, Gender: 0, Promotion: Dragonite2), // INT ExtremeSpeed + new(212, 10, 211, Gender: 0, Promotion: Scizor), // INT Steel Wing + new(248, 55, 069, Gender: 0, Promotion: Tyranitar), // INT Seismic Toss + new(376, 45, 038, Gender: 0, Promotion: Metagross), // INT Double-Edge + new(445, 48, 242, Gender: 0, Promotion: Garchomp), // INT Crunch ]); #endregion diff --git a/PKHeX.Core/Legality/Encounters/Templates/Gen5/DreamWorldEntry.cs b/PKHeX.Core/Legality/Encounters/Templates/Gen5/DreamWorldEntry.cs index 99438399b..b07140433 100644 --- a/PKHeX.Core/Legality/Encounters/Templates/Gen5/DreamWorldEntry.cs +++ b/PKHeX.Core/Legality/Encounters/Templates/Gen5/DreamWorldEntry.cs @@ -5,7 +5,7 @@ namespace PKHeX.Core; /// /// Intermediary Representation of Dream World Data /// -public readonly record struct DreamWorldEntry(ushort Species, byte Level, ushort Move1 = 0, ushort Move2 = 0, ushort Move3 = 0, byte Form = 0, byte Gender = FixedGenderUtil.GenderRandom) +public readonly record struct DreamWorldEntry(ushort Species, byte Level, ushort Move1 = 0, ushort Move2 = 0, ushort Move3 = 0, byte Form = 0, byte Gender = FixedGenderUtil.GenderRandom, GlobalLinkPromotion Promotion = GlobalLinkPromotion.NotPromotion) { private int EntryCount => Move1 == 0 ? 1 : Move2 == 0 ? 1 : Move3 == 0 ? 2 : 3; @@ -15,17 +15,17 @@ private void AddTo(GameVersion version, Span result, ref var a = p.HasHiddenAbility ? AbilityPermission.OnlyHidden : AbilityPermission.OnlyFirst; if (Move1 == 0) { - result[ctr++] = new EncounterStatic5Entree(version, Species, Level, Form, Gender, a); + result[ctr++] = new EncounterStatic5Entree(version, Species, Level, Form, Gender, a, Promotion); return; } - result[ctr++] = new EncounterStatic5Entree(version, Species, Level, Form, Gender, a, Move1); + result[ctr++] = new EncounterStatic5Entree(version, Species, Level, Form, Gender, a, Move1, Promotion); if (Move2 == 0) return; - result[ctr++] = new EncounterStatic5Entree(version, Species, Level, Form, Gender, a, Move2); + result[ctr++] = new EncounterStatic5Entree(version, Species, Level, Form, Gender, a, Move2, Promotion); if (Move3 == 0) return; - result[ctr++] = new EncounterStatic5Entree(version, Species, Level, Form, Gender, a, Move3); + result[ctr++] = new EncounterStatic5Entree(version, Species, Level, Form, Gender, a, Move3, Promotion); } public static EncounterStatic5Entree[] GetArray(GameVersion version, ReadOnlySpan t) diff --git a/PKHeX.Core/Legality/Encounters/Templates/Gen5/EncounterStatic5Entree.cs b/PKHeX.Core/Legality/Encounters/Templates/Gen5/EncounterStatic5Entree.cs index ddac6d673..e2630496b 100644 --- a/PKHeX.Core/Legality/Encounters/Templates/Gen5/EncounterStatic5Entree.cs +++ b/PKHeX.Core/Legality/Encounters/Templates/Gen5/EncounterStatic5Entree.cs @@ -3,7 +3,7 @@ namespace PKHeX.Core; /// /// Generation 5 Entrée Forest static encounter /// -public sealed record EncounterStatic5Entree(GameVersion Version, ushort Species, byte Level, byte Form, byte Gender, AbilityPermission Ability) +public sealed record EncounterStatic5Entree(GameVersion Version, ushort Species, byte Level, byte Form, byte Gender, AbilityPermission Ability, GlobalLinkPromotion Promotion) : IEncounterable, IEncounterMatch, IEncounterConvertible, IMoveset, IFixedGender { public byte Generation => 5; @@ -21,8 +21,8 @@ public sealed record EncounterStatic5Entree(GameVersion Version, ushort Species, public Moveset Moves { get; } - public EncounterStatic5Entree(GameVersion version, ushort species, byte level, byte form, byte gender, AbilityPermission ability, ushort Move) - : this(version, species, level, form, gender, ability) => Moves = new Moveset(Move); + public EncounterStatic5Entree(GameVersion version, ushort species, byte level, byte form, byte gender, AbilityPermission ability, ushort Move, GlobalLinkPromotion promotion) + : this(version, species, level, form, gender, ability, promotion) => Moves = new Moveset(Move); #region Generating @@ -32,8 +32,9 @@ public EncounterStatic5Entree(GameVersion version, ushort species, byte level, b public PK5 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria) { - int language = (int)Language.GetSafeLanguage456((LanguageID)tr.Language); + var language = (int)Promotion.GetSafeLanguage((LanguageID)tr.Language); var version = this.GetCompatibleVersion(tr.Version); + var trainerName = EncounterUtil.GetTrainerName(tr, language); // in case it is remapped by PGL promotion restriction var pi = PersonalTable.B2W2[Species]; var pk = new PK5 { @@ -49,7 +50,7 @@ public PK5 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria) Version = version, Language = language, OriginalTrainerGender = tr.Gender, - OriginalTrainerName = tr.OT, + OriginalTrainerName = trainerName, OriginalTrainerFriendship = pi.BaseFriendship, @@ -94,6 +95,8 @@ public bool IsMatchExact(PKM pk, EvoCriteria evo) return false; if (Form != evo.Form && !FormInfo.IsFormChangeable(Species, Form, pk.Form, Context, pk.Context)) return false; + if (!Promotion.CanBeReceivedBy((LanguageID)pk.Language)) + return false; return true; } diff --git a/PKHeX.Core/Legality/Encounters/Templates/Gen5/GlobalLinkPromotion.cs b/PKHeX.Core/Legality/Encounters/Templates/Gen5/GlobalLinkPromotion.cs new file mode 100644 index 000000000..f5d7e18b3 --- /dev/null +++ b/PKHeX.Core/Legality/Encounters/Templates/Gen5/GlobalLinkPromotion.cs @@ -0,0 +1,129 @@ +using System; +using static PKHeX.Core.GlobalLinkPromotion; +using static PKHeX.Core.GlobalLinkPromotionLanguage; + +namespace PKHeX.Core; + +public enum GlobalLinkPromotion : byte +{ + // B/W + NotPromotion, + Eeveelutions, + StartersKanto, + StartersHoenn, + StartersSinnoh, // No bonus moves + Croagunk1, // No bonus moves + Croagunk2, // w/ Bonus Move Poison Jab + Arceus, + Mamoswine, + Porygon, + Rayquaza, + Blissey, + Jumpluff, + Altaria, + Banette, + Lucario, + Togekiss, + + // B2/W2 + Gothorita1, // Mirror Coat (strategy guide) + Gothorita2, // Imprison (guidebook app) + Pikachu, + MonkeyUnova, // (B2/W2) + StartersSinnoh2, // (B2/W2) w/ Bonus Moves + + // Both Games + Dragonite1, // ThunderPunch (not-international; password) + Dragonite2, // ExtremeSpeed (league events during Nimbasa Gym season) + Scizor, // Aspertia Gym + Garchomp, // Virbank Gym + Tyranitar, // Castelia Gym + Metagross, // Driftveil Gym +} + +[Flags] +public enum GlobalLinkPromotionLanguage : byte +{ + None, + Japanese = 1 << 0, + Korean = 1 << 1, + International = 1 << 2, + + NotInt = Japanese | Korean, + NotKor = Japanese | International, + All = Japanese | Korean | International, +} + +public static class GlobalLinkPromotionExtensions +{ + extension(GlobalLinkPromotion promotion) + { + public GlobalLinkPromotionLanguage GetLanguages() => promotion switch + { + StartersKanto => NotInt, + Croagunk1 => NotInt, + Croagunk2 => International, + Arceus => NotKor, + StartersHoenn => Japanese, + Rayquaza => Korean, + Blissey => NotInt, + Pikachu => NotKor, + Jumpluff => Korean, + MonkeyUnova => Japanese, + StartersSinnoh2 => International, + Gothorita2 => Japanese, + + Dragonite1 => NotInt, + Dragonite2 => International, + Scizor => International, + Garchomp => International, + Tyranitar => International, + Metagross => International, + _ => All, + }; + + public LanguageID GetSafeLanguage(LanguageID prefer) + { + if (promotion is NotPromotion) + return Language.GetSafeLanguage456(prefer); + + // Promotions can be language-locked. + var restrict = promotion.GetLanguages(); + if (restrict == All) + return Language.GetSafeLanguage456(prefer); + + // Need to restrict to the allowed languages. + if (restrict == Japanese) + return LanguageID.Japanese; + if (restrict == Korean) + return LanguageID.Korean; + if (restrict == NotKor && prefer == LanguageID.Korean) + return LanguageID.Japanese; + if (restrict == NotInt) + return (prefer == LanguageID.Korean ? prefer : LanguageID.Japanese); + + // International language only. + if (prefer is LanguageID.Japanese or LanguageID.Korean) + return LanguageID.English; + return Language.GetSafeLanguage456(prefer); + } + + public bool CanBeReceivedBy(LanguageID language) + { + if (promotion is NotPromotion) + return true; + + var restrict = promotion.GetLanguages(); + if (restrict is All) + return true; + + if (language is LanguageID.Japanese) + return restrict.HasFlag(Japanese); + if (language is LanguageID.Korean) + return restrict.HasFlag(Korean); + + // Only International languages remain. + return restrict.HasFlag(International); + } + } +}