Entree5: add language restrictions for pgl promos

Fixes #4836 wrt language mismatch
This commit is contained in:
Kurt
2026-07-14 22:40:08 -05:00
parent 1db56ce169
commit 572b4e26fd
5 changed files with 201 additions and 47 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -5,7 +5,7 @@ namespace PKHeX.Core;
/// <summary>
/// Intermediary Representation of Dream World Data
/// </summary>
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<EncounterStatic5Entree> 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<DreamWorldEntry> t)

View File

@@ -3,7 +3,7 @@ namespace PKHeX.Core;
/// <summary>
/// Generation 5 Entrée Forest static encounter
/// </summary>
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<PK5>, 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;
}

View File

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