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);
+ }
+ }
+}