PKHeX/PKHeX.Core/Legality/Encounters/Data/Encounters3.cs

192 lines
14 KiB
C#
Raw Normal View History

Offload EncounterSlot loading logic to reduce complexity (#2980) * Rework gen1 slot loading Slot templates are precomputed from ROM data and just loaded straight in, with tight coupling to the encounter area (grouped by slot types). * Revise fuzzy met check for underleveled wild evos Example: Level 23 poliwhirl in RBY as a level 50 poliwhirl, will assume the chain is 25-50 for poliwhirl (as poliwag evolves at 25). Instead of revising the origin chain, just ignore the evo min level in the comparison. Previous commit fixed it for gen1. * Rework gen2-4 slot loading Gen4 not finished, Type Encounter data and some edge encounters not recognizing yet... * Add feebas slots for old/good encounters * Begin moving properties Great news! Gen5-7 need to be de-dumbed like Gen1-4. Then I can remove the bang (!) on the Area accessor and ensure that it's never null! * Split off XD pokespot slot encounter table type * Set area in constructor * Deduplicate g3 roaming encounters * Deduplicate xd encounter locations (rebattle) Only difference is met location; no need to create 500 extra encounter objects. A simple contains check is ok (rarely in gen3 format). * Make all slots have a readonly reference to their parent area * Minor clean * Remove "Safari" slot type flag Can be determined via other means (generation-location), allows us to reduce the size of SlotType member to a byte Output of slot binaries didn't preserve the Safari flag anyway. * Update SlotType.cs * Handle type encounters correctly * Merge safari area into regular xy area * Merge dexnav accessor logic * fix some logic so that tests pass again rearrange g5 dw init to be done outside of static constructor (initializer instead) PIDGenerator: friend safari slots now generate with required flawless IV count * Add cianwood tentacool gift encounter * Remove unnecessary abstractions Fake area just returned a slot; since Slots have a non-null reference to the area, we can just return the slot and use the API to grab a list of possible slots for the chain. Increase restrictiveness of location/type get-set operations * Minor tweaks, pass parameters DexNav observed state isn't necessary to use, only need to see if it's possible to dexnav. Now that we have metadata for slots, we can. * Remove unused legality tables
2020-08-30 17:23:22 +00:00
using static PKHeX.Core.EncounterUtil;
using static PKHeX.Core.GameVersion;
namespace PKHeX.Core
{
/// <summary>
/// Generation 3 Encounters
/// </summary>
internal static class Encounters3
{
2020-10-13 22:37:18 +00:00
private static readonly EncounterArea3[] SlotsSwarmRSE = GetSwarm("rse_swarm", "rs", RSE);
internal static readonly EncounterArea3[] SlotsR = ArrayUtil.ConcatAll(Get("r", "ru", R), SlotsSwarmRSE);
internal static readonly EncounterArea3[] SlotsS = ArrayUtil.ConcatAll(Get("s", "sa", S), SlotsSwarmRSE);
internal static readonly EncounterArea3[] SlotsE = ArrayUtil.ConcatAll(Get("e", "em", E), SlotsSwarmRSE);
internal static readonly EncounterArea3[] SlotsFR = Get("fr", "fr", FR);
internal static readonly EncounterArea3[] SlotsLG = Get("lg", "lg", LG);
2020-10-13 22:37:18 +00:00
private static byte[][] ReadUnpack(string resource, string ident) => BinLinker.Unpack(Util.GetBinaryResource($"encounter_{resource}.pkl"), ident);
private static EncounterArea3[] Get(string resource, string ident, GameVersion game) => EncounterArea3.GetAreas(ReadUnpack(resource, ident), game);
private static EncounterArea3[] GetSwarm(string resource, string ident, GameVersion game) => EncounterArea3.GetAreasSwarm(ReadUnpack(resource, ident), game);
static Encounters3()
{
MarkEncounterTradeStrings(TradeGift_RSE, TradeRSE);
MarkEncounterTradeStrings(TradeGift_FRLG, TradeFRLG);
}
private static readonly EncounterStatic3[] Encounter_RSE_Roam =
{
2020-12-22 01:17:56 +00:00
new(380, 40, S) { Roaming = true, Location = 016 }, // Latias
new(380, 40, E) { Roaming = true, Location = 016 }, // Latias
new(381, 40, R) { Roaming = true, Location = 016 }, // Latios
new(381, 40, E) { Roaming = true, Location = 016 }, // Latios
};
private static readonly EncounterStatic3[] Encounter_RSE_Regular =
{
// Starters
2021-12-10 03:10:50 +00:00
new(152, 05, E ) { Gift = true, Location = 000 }, // Chikorita @ Littleroot Town
new(155, 05, E ) { Gift = true, Location = 000 }, // Cyndaquil
new(158, 05, E ) { Gift = true, Location = 000 }, // Totodile
new(252, 05, RSE) { Gift = true, Location = 016 }, // Treecko @ Route 101
new(255, 05, RSE) { Gift = true, Location = 016 }, // Torchic
new(258, 05, RSE) { Gift = true, Location = 016 }, // Mudkip
// Fossil @ Rustboro City
2021-12-10 03:10:50 +00:00
new(345, 20, RSE) { Gift = true, Location = 010 }, // Lileep
new(347, 20, RSE) { Gift = true, Location = 010 }, // Anorith
// Gift
2021-12-10 03:10:50 +00:00
new(351, 25, RSE) { Gift = true, Location = 034 }, // Castform @ Weather Institute
new(374, 05, RSE) { Gift = true, Location = 013 }, // Beldum @ Mossdeep City
new(360, 05, RSE) { Gift = true, EggLocation = 253 }, // Wynaut Egg
// Stationary
2020-12-22 01:17:56 +00:00
new(352, 30, RSE) { Location = 034 }, // Kecleon @ Route 119
new(352, 30, RSE) { Location = 035 }, // Kecleon @ Route 120
new(101, 30, RS ) { Location = 066 }, // Electrode @ Hideout (R:Magma Hideout/S:Aqua Hideout)
new(101, 30, E ) { Location = 197 }, // Electrode @ Aqua Hideout
new(185, 40, E ) { Location = 058 }, // Sudowoodo @ Battle Frontier
// Stationary Lengendary
2021-12-10 03:10:50 +00:00
new(377, 40, RSE) { Location = 082 }, // Regirock @ Desert Ruins
new(378, 40, RSE) { Location = 081 }, // Regice @ Island Cave
new(379, 40, RSE) { Location = 083 }, // Registeel @ Ancient Tomb
new(380, 50, R ) { Location = 073 }, // Latias @ Southern Island
2020-12-22 01:17:56 +00:00
new(380, 50, E) { Location = 073, Fateful = true }, // Latias @ Southern Island
2021-12-10 03:10:50 +00:00
new(381, 50, S ) { Location = 073 }, // Latios @ Southern Island
2020-12-22 01:17:56 +00:00
new(381, 50, E) { Location = 073, Fateful = true }, // Latios @ Southern Island
2021-12-10 03:10:50 +00:00
new(382, 45, S ) { Location = 072 }, // Kyogre @ Cave of Origin
new(382, 70, E) { Location = 203 }, // Kyogre @ Marine Cave
new(383, 45, R ) { Location = 072 }, // Groudon @ Cave of Origin
new(383, 70, E) { Location = 205 }, // Groudon @ Terra Cave
new(384, 70, RSE) { Location = 085 }, // Rayquaza @ Sky Pillar
// Event
2020-12-22 01:17:56 +00:00
new(151, 30, E) { Location = 201, Fateful = true }, // Mew @ Faraway Island (Unreleased outside of Japan)
new(249, 70, E) { Location = 211, Fateful = true }, // Lugia @ Navel Rock
new(250, 70, E) { Location = 211, Fateful = true }, // Ho-Oh @ Navel Rock
new(386, 30, E) { Location = 200, Fateful = true, Form = 3 }, // Deoxys @ Birth Island
};
private static readonly EncounterStatic3[] Encounter_FRLG_Roam =
{
2020-12-22 01:17:56 +00:00
new(243, 50, FRLG) { Roaming = true, Location = 16 }, // Raikou
new(244, 50, FRLG) { Roaming = true, Location = 16 }, // Entei
new(245, 50, FRLG) { Roaming = true, Location = 16 }, // Suicune
};
private static readonly EncounterStatic3[] Encounter_FRLG_Stationary =
{
// Starters @ Pallet Town
2021-12-10 03:10:50 +00:00
new(001, 05, FRLG) { Gift = true, Location = 088 }, // Bulbasaur
new(004, 05, FRLG) { Gift = true, Location = 088 }, // Charmander
new(007, 05, FRLG) { Gift = true, Location = 088 }, // Squirtle
// Fossil @ Cinnabar Island
2021-12-10 03:10:50 +00:00
new(138, 05, FRLG) { Gift = true, Location = 096 }, // Omanyte
new(140, 05, FRLG) { Gift = true, Location = 096 }, // Kabuto
new(142, 05, FRLG) { Gift = true, Location = 096 }, // Aerodactyl
// Gift
2021-12-10 03:10:50 +00:00
new(106, 25, FRLG) { Gift = true, Location = 098 }, // Hitmonlee @ Saffron City
new(107, 25, FRLG) { Gift = true, Location = 098 }, // Hitmonchan @ Saffron City
new(129, 05, FRLG) { Gift = true, Location = 099 }, // Magikarp @ Route 4
new(131, 25, FRLG) { Gift = true, Location = 134 }, // Lapras @ Silph Co.
new(133, 25, FRLG) { Gift = true, Location = 094 }, // Eevee @ Celadon City
2020-12-22 01:17:56 +00:00
new(175, 05, FRLG) { Gift = true, EggLocation = 253 }, // Togepi Egg
2018-05-12 15:13:39 +00:00
// Celadon City Game Corner
2020-12-22 01:17:56 +00:00
new(063, 09, FR) { Gift = true, Location = 94 }, // Abra
new(035, 08, FR) { Gift = true, Location = 94 }, // Clefairy
new(123, 25, FR) { Gift = true, Location = 94 }, // Scyther
new(147, 18, FR) { Gift = true, Location = 94 }, // Dratini
new(137, 26, FR) { Gift = true, Location = 94 }, // Porygon
new(063, 07, LG) { Gift = true, Location = 94 }, // Abra
new(035, 12, LG) { Gift = true, Location = 94 }, // Clefairy
new(127, 18, LG) { Gift = true, Location = 94 }, // Pinsir
new(147, 24, LG) { Gift = true, Location = 94 }, // Dratini
new(137, 18, LG) { Gift = true, Location = 94 }, // Porygon
// Stationary
2021-12-10 03:10:50 +00:00
new(143, 30, FRLG) { Location = 112 }, // Snorlax @ Route 12
new(143, 30, FRLG) { Location = 116 }, // Snorlax @ Route 16
new(101, 34, FRLG) { Location = 142 }, // Electrode @ Power Plant
new(097, 30, FRLG) { Location = 176 }, // Hypno @ Berry Forest
// Stationary Legendary
2021-12-10 03:10:50 +00:00
new(144, 50, FRLG) { Location = 139 }, // Articuno @ Seafoam Islands
new(145, 50, FRLG) { Location = 142 }, // Zapdos @ Power Plant
new(146, 50, FRLG) { Location = 175 }, // Moltres @ Mt. Ember.
new(150, 70, FRLG) { Location = 141 }, // Mewtwo @ Cerulean Cave
// Event
2020-12-22 01:17:56 +00:00
new(249, 70, FRLG) { Location = 174, Fateful = true }, // Lugia @ Navel Rock
new(250, 70, FRLG) { Location = 174, Fateful = true }, // Ho-Oh @ Navel Rock
2021-12-10 03:10:50 +00:00
new(386, 30, FR ) { Location = 187, Fateful = true, Form = 1 }, // Deoxys @ Birth Island
new(386, 30, LG) { Location = 187, Fateful = true, Form = 2 }, // Deoxys @ Birth Island
};
Offload EncounterSlot loading logic to reduce complexity (#2980) * Rework gen1 slot loading Slot templates are precomputed from ROM data and just loaded straight in, with tight coupling to the encounter area (grouped by slot types). * Revise fuzzy met check for underleveled wild evos Example: Level 23 poliwhirl in RBY as a level 50 poliwhirl, will assume the chain is 25-50 for poliwhirl (as poliwag evolves at 25). Instead of revising the origin chain, just ignore the evo min level in the comparison. Previous commit fixed it for gen1. * Rework gen2-4 slot loading Gen4 not finished, Type Encounter data and some edge encounters not recognizing yet... * Add feebas slots for old/good encounters * Begin moving properties Great news! Gen5-7 need to be de-dumbed like Gen1-4. Then I can remove the bang (!) on the Area accessor and ensure that it's never null! * Split off XD pokespot slot encounter table type * Set area in constructor * Deduplicate g3 roaming encounters * Deduplicate xd encounter locations (rebattle) Only difference is met location; no need to create 500 extra encounter objects. A simple contains check is ok (rarely in gen3 format). * Make all slots have a readonly reference to their parent area * Minor clean * Remove "Safari" slot type flag Can be determined via other means (generation-location), allows us to reduce the size of SlotType member to a byte Output of slot binaries didn't preserve the Safari flag anyway. * Update SlotType.cs * Handle type encounters correctly * Merge safari area into regular xy area * Merge dexnav accessor logic * fix some logic so that tests pass again rearrange g5 dw init to be done outside of static constructor (initializer instead) PIDGenerator: friend safari slots now generate with required flawless IV count * Add cianwood tentacool gift encounter * Remove unnecessary abstractions Fake area just returned a slot; since Slots have a non-null reference to the area, we can just return the slot and use the API to grab a list of possible slots for the chain. Increase restrictiveness of location/type get-set operations * Minor tweaks, pass parameters DexNav observed state isn't necessary to use, only need to see if it's possible to dexnav. Now that we have metadata for slots, we can. * Remove unused legality tables
2020-08-30 17:23:22 +00:00
private static readonly EncounterStatic3[] Encounter_RSE = ArrayUtil.ConcatAll(Encounter_RSE_Roam, Encounter_RSE_Regular);
private static readonly EncounterStatic3[] Encounter_FRLG = ArrayUtil.ConcatAll(Encounter_FRLG_Roam, Encounter_FRLG_Stationary);
private static readonly byte[] TradeContest_Cool = { 30, 05, 05, 05, 05, 10 };
private static readonly byte[] TradeContest_Beauty = { 05, 30, 05, 05, 05, 10 };
private static readonly byte[] TradeContest_Cute = { 05, 05, 30, 05, 05, 10 };
private static readonly byte[] TradeContest_Clever = { 05, 05, 05, 30, 05, 10 };
private static readonly byte[] TradeContest_Tough = { 05, 05, 05, 05, 30, 10 };
internal static readonly EncounterTrade3[] TradeGift_RSE =
{
new(RS, 0x00009C40, 296, 05) { Ability = 2, TID = 49562, SID = 00000, OTGender = 0, Gender = 0, IVs = new[] {5,5,4,4,4,4}, Contest = TradeContest_Tough }, // Slakoth (Level 5 Breeding) -> Makuhita
new(RS, 0x498A2E17, 300, 03) { Ability = 1, TID = 02259, SID = 00000, OTGender = 1, Gender = 1, IVs = new[] {5,4,4,5,4,4}, Contest = TradeContest_Cute }, // Pikachu (Level 3 Viridian Forest) -> Skitty
new(RS, 0x4C970B7F, 222, 21) { Ability = 2, TID = 50183, SID = 00000, OTGender = 1, Gender = 1, IVs = new[] {4,4,5,4,4,5}, Contest = TradeContest_Beauty }, // Bellossom (Level 21 Oddish -> Gloom -> Bellossom) -> Corsola
new(E , 0x00000084, 273, 04) { Ability = 2, TID = 38726, SID = 00000, OTGender = 0, Gender = 0, IVs = new[] {5,4,5,4,4,4}, Contest = TradeContest_Cool }, // Ralts (Level 4 Route 102) -> Seedot
new(E , 0x0000006F, 311, 05) { Ability = 1, TID = 08460, SID = 00001, OTGender = 0, Gender = 1, IVs = new[] {4,4,4,5,5,4}, Contest = TradeContest_Cute }, // Volbeat (Level 5 Breeding) -> Plusle
new(E , 0x0000007F, 116, 05) { Ability = 1, TID = 46285, SID = 00000, OTGender = 0, Gender = 0, IVs = new[] {5,4,4,4,5,4}, Contest = TradeContest_Tough }, // Bagon (Level 5 Breeding) -> Horsea*
new(E , 0x0000008B, 052, 03) { Ability = 1, TID = 25945, SID = 00001, OTGender = 1, Gender = 0, IVs = new[] {4,5,4,5,4,4}, Contest = TradeContest_Clever }, // Skitty (Level 3 Trade)-> Meowth*
// If Pokémon with * is evolved in a Generation IV or V game, its Ability will become its second Ability.
};
internal static readonly EncounterTrade3[] TradeGift_FRLG =
{
new(FRLG, 0x00009CAE, 122, 05) { Ability = 1, TID = 01985, SID = 00000, OTGender = 0, Gender = 0, IVs = new[] {20,15,17,24,23,22}, Contest = TradeContest_Clever }, // Abra (Level 5 Breeding) -> Mr. Mime
new(FR , 0x4C970B89, 029, 05) { Ability = 1, TID = 63184, SID = 00000, OTGender = 1, Gender = 1, IVs = new[] {22,18,25,19,15,22}, Contest = TradeContest_Tough }, // Nidoran♀
new( LG, 0x4C970B9E, 032, 05) { Ability = 1, TID = 63184, SID = 00000, OTGender = 1, Gender = 0, IVs = new[] {19,25,18,22,22,15}, Contest = TradeContest_Cool }, // Nidoran♂ *
new(FR , 0x00EECA15, 030, 16) { Ability = 1, TID = 13637, SID = 00000, OTGender = 0, Gender = 1, IVs = new[] {22,25,18,19,22,15}, Contest = TradeContest_Cute }, // Nidorina *
new( LG, 0x00EECA19, 033, 16) { Ability = 1, TID = 13637, SID = 00000, OTGender = 0, Gender = 0, IVs = new[] {19,18,25,22,15,22}, Contest = TradeContest_Tough }, // Nidorino *
new(FR , 0x451308AB, 108, 25) { Ability = 1, TID = 01239, SID = 00000, OTGender = 0, Gender = 0, IVs = new[] {24,19,21,15,23,21}, Contest = TradeContest_Tough }, // Golduck (Level 25) -> Lickitung *
new( LG, 0x451308AB, 108, 25) { Ability = 1, TID = 01239, SID = 00000, OTGender = 0, Gender = 0, IVs = new[] {24,19,21,15,23,21}, Contest = TradeContest_Tough }, // Slowbro (Level 25) -> Lickitung *
new(FRLG, 0x498A2E1D, 124, 20) { Ability = 1, TID = 36728, SID = 00000, OTGender = 0, Gender = 1, IVs = new[] {18,17,18,22,25,21}, Contest = TradeContest_Beauty }, // Poliwhirl (Level 20) -> Jynx
new(FRLG, 0x151943D7, 083, 03) { Ability = 1, TID = 08810, SID = 00000, OTGender = 0, Gender = 0, IVs = new[] {20,25,21,24,15,20}, Contest = TradeContest_Cool }, // Spearow (Level 3 Capture) -> Farfetch'd
new(FRLG, 0x06341016, 101, 03) { Ability = 2, TID = 50298, SID = 00000, OTGender = 0, Gender = 2, IVs = new[] {19,16,18,25,25,19}, Contest = TradeContest_Cool }, // Raichu (Level 3) -> Electrode
new(FRLG, 0x5C77ECFA, 114, 05) { Ability = 1, TID = 60042, SID = 00000, OTGender = 1, Gender = 0, IVs = new[] {22,17,25,16,23,20}, Contest = TradeContest_Cute }, // Venonat (Level 5 Breeding) -> Tangela
new(FRLG, 0x482CAC89, 086, 05) { Ability = 1, TID = 09853, SID = 00000, OTGender = 0, Gender = 0, IVs = new[] {24,15,22,16,23,22}, Contest = TradeContest_Tough }, // Ponyta (Level 5 Breeding) -> Seel *
// If Pokémon with * is evolved in a Generation IV or V game, its Ability will become its second Ability.
};
private const string tradeRSE = "traderse";
private const string tradeFRLG = "tradefrlg";
private static readonly string[][] TradeRSE = Util.GetLanguageStrings7(tradeRSE);
private static readonly string[][] TradeFRLG = Util.GetLanguageStrings7(tradeFRLG);
internal static readonly EncounterStatic3[] StaticR = GetEncounters(Encounter_RSE, R);
internal static readonly EncounterStatic3[] StaticS = GetEncounters(Encounter_RSE, S);
internal static readonly EncounterStatic3[] StaticE = GetEncounters(Encounter_RSE, E);
internal static readonly EncounterStatic3[] StaticFR = GetEncounters(Encounter_FRLG, FR);
internal static readonly EncounterStatic3[] StaticLG = GetEncounters(Encounter_FRLG, LG);
}
}