From 758adf2cfffe9da1c3e77221757a29d3ae649bb5 Mon Sep 17 00:00:00 2001 From: javierhimura Date: Mon, 1 May 2017 17:07:20 +0200 Subject: [PATCH] Encounter Type fix and detection of pokemon that should have evolve on trade (#1105) * Detect encounter trades that evolve on trade and have not been evolved Detect generation 1 pokemon with special catch rates : krabby trade and Pokemon Stadium Detect generation 1 pokemon that evolve on trade and have been traded but not evolved Detect pokemon with tradeback status any but with only encounters from the other GB generation, that means they are WasTradeback Detect pokemon with moves from the other GB generation, change tradebackstatus to WasTradeback * Fix dppt surfing and fishing encounter type, is is surfing because the battle background is the same as other surfingfishing encounters Fix headbutt encounter type, the encounter type depends on the battle background used when battle a pokemon, for headbutt it changes with the player tile, is the player is in a city it will be building encounter, in a grass tile tall grass, in water it is surfingfishing and cave inside a cave. Some locations have more than one possible encounter type, for example routes with trees near the grass, near the water and near non-combat tiles. Also added slot type headbutt special for the special trees, those trees are all in routes and are only adjacent to non-combat tiles * Fix encounter type for missing areas with multiple grass encounters types: Mt Coronet, Mt Silver Cave and Stark Mountain (Issue # 1095) * Fixes and typos * Check for non-japanese e-reader pokemon, is unreleased --- PKHeX.WinForms/MainWindow/Main.cs | 16 +- PKHeX/Legality/Analysis.cs | 14 +- PKHeX/Legality/Checks.cs | 71 ++++++- PKHeX/Legality/Core.cs | 190 ++++++++++++++---- PKHeX/Legality/LegalityCheckStrings.cs | 8 +- PKHeX/Legality/Structures/EncounterArea.cs | 2 +- PKHeX/Legality/Structures/EncounterStatic.cs | 3 +- PKHeX/Legality/Structures/EncounterTrade.cs | 6 + PKHeX/Legality/Structures/EncounterType.cs | 29 ++- PKHeX/Legality/Structures/SlotType.cs | 1 + PKHeX/Legality/Tables1.cs | 46 ++++- PKHeX/Legality/Tables3.cs | 6 +- PKHeX/Legality/Tables4.cs | 109 +++++++++- PKHeX/Legality/Tables7.cs | 2 +- .../text/en/LegalityCheckStrings_en.txt | 9 +- .../text/ko/LegalityCheckStrings_ko.txt | 9 +- .../text/zh/LegalityCheckStrings_zh.txt | 9 +- 17 files changed, 451 insertions(+), 79 deletions(-) diff --git a/PKHeX.WinForms/MainWindow/Main.cs b/PKHeX.WinForms/MainWindow/Main.cs index 1908f8b71..a5a4b1911 100644 --- a/PKHeX.WinForms/MainWindow/Main.cs +++ b/PKHeX.WinForms/MainWindow/Main.cs @@ -954,6 +954,18 @@ private static SAV3GCMemoryCard CheckGCMemoryCard(byte[] Data, string path) return MC; } + private void StoreLegalSaveGameData(SaveFile sav) + { + Legal.SavegameJapanese = sav.Japanese; + Legal.EReaderBerryIsEnigma = sav.eBerryIsEnigma; + Legal.EReaderBerryName = sav.eBerryName; + Legal.Savegame_Gender = sav.Gender; + Legal.Savegame_TID = sav.TID; + Legal.Savegame_SID = sav.SID; + Legal.Savegame_OT = sav.OT; + Legal.Savegame_Version = sav.Version; + } + private void openSAV(SaveFile sav, string path) { if (sav == null || sav.Version == GameVersion.Invalid) @@ -1033,9 +1045,7 @@ private void openSAV(SaveFile sav, string path) sav.Japanese = drJP == DialogResult.No; } - Legal.SavegameJapanese = sav.Japanese; - Legal.EReaderBerryIsEnigma = sav.eBerryIsEnigma; - Legal.EReaderBerryName = sav.eBerryName; + StoreLegalSaveGameData(sav); loadingSAV = true; // clean fields diff --git a/PKHeX/Legality/Analysis.cs b/PKHeX/Legality/Analysis.cs index cb5c8d6b3..a4d097eb2 100644 --- a/PKHeX/Legality/Analysis.cs +++ b/PKHeX/Legality/Analysis.cs @@ -236,8 +236,10 @@ private void updateTradebackG12() // Dragonite's Catch Rate is different than Dragonair's in Yellow, but there is no Dragonite encounter. var RGBCatchRate = Lineage.Any(s => catch_rate == PersonalTable.RB[s].CatchRate); var YCatchRate = Lineage.Any(s => s != 149 && catch_rate == PersonalTable.Y[s].CatchRate); - - bool matchAny = RGBCatchRate || YCatchRate; + // Krabby encounter trade special catch rate + var TradeCatchRate = ((pkm.Species == 098 || pkm.Species == 099) && catch_rate == 204); + var StadiumCatchRate = Legal.Stadium_GiftSpecies.Contains(pkm.Species) && Legal.Stadium_CatchRate.Contains(catch_rate); + bool matchAny = RGBCatchRate || YCatchRate || TradeCatchRate || StadiumCatchRate; // If the catch rate value has been modified, the item has either been removed or swapped in Generation 2. var HeldItemCatchRate = catch_rate == 0 || Legal.HeldItems_GSC.Any(h => h == catch_rate); @@ -250,7 +252,7 @@ private void updateTradebackG12() // Update the editing settings for the PKM to acknowledge the tradeback status if the species is changed. - ((PK1)pkm).CatchRateIsItem = !pkm.Gen1_NotTradeback && HeldItemCatchRate && matchAny; + ((PK1)pkm).CatchRateIsItem = !pkm.Gen1_NotTradeback && HeldItemCatchRate && !matchAny; } else if (pkm.Format == 2 || pkm.VC2) { @@ -276,7 +278,11 @@ private void updateTypeInfo() if (pkm.VC && pkm.Format == 7) EncounterMatch = Legal.getRBYStaticTransfer(pkm.Species); - MatchedType = Type = (EncounterOriginalGB ?? EncounterMatch ?? pkm.Species).GetType(); + if (pkm.GenNumber <= 2 && pkm.TradebackStatus == TradebackType.Any && EncountersGBMatch.All(e => e.Generation != pkm.GenNumber)) + // Example: GSC Pokemon with only possible encounters in RBY, like the legendary birds + pkm.TradebackStatus = TradebackType.WasTradeback; + + MatchedType = Type = (EncounterOriginalGB ?? EncounterMatch ?? pkm.Species)?.GetType(); var bt = Type.BaseType; if (bt != null && !(bt == typeof(Array) || bt == typeof(object) || bt.IsPrimitive)) // a parent exists Type = bt; // use base type diff --git a/PKHeX/Legality/Checks.cs b/PKHeX/Legality/Checks.cs index e9d232946..5f24ab662 100644 --- a/PKHeX/Legality/Checks.cs +++ b/PKHeX/Legality/Checks.cs @@ -500,6 +500,15 @@ private void verifyG1OT() if (tr != "GF" && tr != "ゲーフリ") // if there are more events with special OTs, may be worth refactoring AddLine(Severity.Invalid, V39, CheckIdentifier.Trainer); } + if((EncounterMatch as EncounterStatic)?.Version == GameVersion.Stadium) + { + if(tr == "STADIUM" && pkm.TID == 2000) + AddLine(Severity.Valid, V403, CheckIdentifier.Trainer); + else if (tr == "スタジアム" && pkm.TID == 1999) + AddLine(Severity.Valid, V404, CheckIdentifier.Trainer); + else + AddLine(Severity.Invalid, V402, CheckIdentifier.Trainer); + } } #endregion private void verifyHyperTraining() @@ -739,6 +748,8 @@ private CheckResult verifyEncounterStatic() switch (pkm.GenNumber) { case 3: + if ((( EncounterMatch as EncounterStaticShadow)?.EReader ?? false) && pkm.Language != 1) // Non-JP E-reader Pokemon + return new CheckResult(Severity.Invalid, V406, CheckIdentifier.Encounter); if (pkm.Species == 151 && s.Location == 201 && pkm.Language != 1) // Non-JP Mew (Old Sea Map) return new CheckResult(Severity.Invalid, V353, CheckIdentifier.Encounter); break; @@ -769,6 +780,16 @@ private CheckResult verifyEncounterStatic() } private CheckResult verifyEncounterTrade() { + var trade = (EncounterTrade)EncounterMatch; + if (trade.Species == pkm.Species && trade.EvolveOnTrade) + { + // Pokemon that evolve on trade can not be in the phase evolution after the trade + // If the trade holds an everstone EvolveOnTrade will be false for the encounter + var species = specieslist; + var unevolved = species[pkm.Species]; + var evolved = species[pkm.Species + 1]; + return new CheckResult(Severity.Invalid, string.Format(V401, unevolved, evolved), CheckIdentifier.Encounter); + } return new CheckResult(Severity.Valid, V76, CheckIdentifier.Encounter); } private CheckResult verifyEncounterG12() @@ -782,7 +803,7 @@ private CheckResult verifyEncounterG12() pkm.WasEgg = true; return verifyEncounterEgg(); } - EncounterMatch = EncounterOriginalGB = EncountersGBMatch.FirstOrDefault()?.Encounter; + EncounterMatch = EncounterOriginalGB = EncountersGBMatch?.FirstOrDefault()?.Encounter; if (EncounterMatch is EncounterSlot) return new CheckResult(Severity.Valid, V68, CheckIdentifier.Encounter); if (EncounterMatch is EncounterStatic) @@ -831,14 +852,8 @@ private void verifyEncounterType() if (EncounterMatch is EncounterStaticTyped) type = ((EncounterStaticTyped)EncounterMatch).TypeEncounter; } - if (type == EncounterType.Any) - { - // Temp analysis until all generation 4 static encounters have defined their encounter type values - AddLine(Severity.NotImplemented, V382, CheckIdentifier.Encounter); - return; - } - if (type != (EncounterType)pkm.EncounterType) + if (!type.Contains(pkm.EncounterType)) AddLine(Severity.Invalid, V381, CheckIdentifier.Encounter); else AddLine(Severity.Valid, V380, CheckIdentifier.Encounter); @@ -1126,6 +1141,20 @@ private void verifyLevel() AddLine(Severity.Fishy, V87, CheckIdentifier.Level); else AddLine(Severity.Valid, V88, CheckIdentifier.Level); + + // Machoke, Graveler, Haunter and Kadabra captured in the second phase evolution, exclude in-game trade, is already checked + if (Type != typeof(EncounterTrade) && pkm.Format <=2 && EncounterSpecies == pkm.Species && Legal.Trade_Evolution1.Contains(EncounterSpecies)) + { + var mustevolve = pkm.TradebackStatus == TradebackType.WasTradeback || (pkm.Format == 1 && Legal.IsOutsider(pkm)); + if (mustevolve) + { + // Pokemon have been traded but it is not evolved + var species = specieslist; + var unevolved = species[pkm.Species]; + var evolved = species[pkm.Species + 1]; + AddLine(Severity.Invalid, string.Format(V405, unevolved, evolved), CheckIdentifier.Level); + } + } } #region verifyMedals private void verifyMedals() @@ -2413,6 +2442,9 @@ private void verifyMiscG1() goto case TradebackType.Gen1_NotTradeback; break; case TradebackType.Gen1_NotTradeback: + if ((EncounterMatch as EncounterStatic)?.Version == GameVersion.Stadium || EncounterMatch as EncounterTradeCatchRate != null) + // Encounters detected by the catch rate, cant be invalid if match this encounters + { AddLine(Severity.Valid, V398, CheckIdentifier.Misc); } if ( ((pkm.Species == 149) && (catch_rate == PersonalTable.Y[149].CatchRate)) || (Legal.Species_NotAvailable_CatchRate.Contains(pkm.Species) && (catch_rate == PersonalTable.RB[pkm.Species].CatchRate))) { AddLine(Severity.Invalid, V396, CheckIdentifier.Misc); } @@ -2589,9 +2621,16 @@ private List GetEncounterMovesGBEra() if (pkm.WasEgg) encounters.Add(null); if (EncountersGBMatch != null) - // Add non egg encounters, start with generation 2 - // generation 1 will change valid gen 1 lvl moves for every encounter - encounters.AddRange(EncountersGBMatch.Where(t => t.Type != GBEncounterType.EggEncounter).OrderByDescending(t => t.Generation).Select(e => e.Encounter)); + { + if (EncountersGBMatch.First().Generation == 1) + // If the first encounter if from generation 1 that means encounter from generation 2 will not return any valid move that is not valid in gen1 encounter + // but it is needed to determine if pokemon could be from only one generation to check tradeback status + encounters.Add(EncountersGBMatch.First().Encounter); + else + // Add non egg encounters, start with generation 2 + // generation 1 will change valid gen 1 lvl moves for every encounter + encounters.AddRange(EncountersGBMatch.Where(t => t.Type != GBEncounterType.EggEncounter).Select(e => e.Encounter)); + } return encounters; } private CheckResult[] verifyMoves(GameVersion game = GameVersion.Any) @@ -2694,6 +2733,7 @@ private CheckResult[] parseMovesForEncounters(GameVersion game, int[] Moves) var EncounterMatchGen = EncounterMatch as IGeneration; var defaultG1LevelMoves = EncounterMoves.validLevelUpMoves[1]; + var defaultTradeback = pkm.TradebackStatus; if (EncounterMatchGen != null) // Generation 1 can have different minimum level in different encounter of the same species; update valid level moves UptateGen1LevelUpMoves(EncounterMoves, EncounterMoves.minLvlG1, EncounterMatchGen.Generation); @@ -2707,6 +2747,7 @@ private CheckResult[] parseMovesForEncounters(GameVersion game, int[] Moves) if (EncounterMatchGen?.Generation == 1) // not valid, restore generation 1 moves EncounterMoves.validLevelUpMoves[1] = defaultG1LevelMoves; + pkm.TradebackStatus = defaultTradeback; } return res; } @@ -3052,6 +3093,8 @@ private CheckResult[] parseMoves(int[] moves, List[] learn, int[] relearn, IncenseMovesLearned.Add(m); if (res[m].Valid && gen == 1) Gen1MovesLearned.Add(m); + if (res[m].Valid && gen <= 2 && pkm.TradebackStatus == TradebackType.Any && pkm.GenNumber != gen) + pkm.TradebackStatus = TradebackType.WasTradeback; } if (gen == generations.Last()) @@ -3075,6 +3118,8 @@ private CheckResult[] parseMoves(int[] moves, List[] learn, int[] relearn, else res[m] = new CheckResult(Severity.Valid, V345, CheckIdentifier.Move); LvlupEggMovesLearned.Add(m); + if (pkm.TradebackStatus == TradebackType.Any && pkm.GenNumber == 1) + pkm.TradebackStatus = TradebackType.WasTradeback; if (issplitbreed) { // Only add to split breed lists learned moves that can be from one of the egg species, ignore common moves @@ -3106,6 +3151,8 @@ private CheckResult[] parseMoves(int[] moves, List[] learn, int[] relearn, else res[m] = new CheckResult(Severity.Valid, V171, CheckIdentifier.Move) { Flag = true }; EggMovesLearned.Add(m); + if (pkm.TradebackStatus == TradebackType.Any && pkm.GenNumber == 1) + pkm.TradebackStatus = TradebackType.WasTradeback; if (issplitbreed) { // Only add to split breed lists egg moves that can be from one of the egg species, ignore common moves @@ -3128,6 +3175,8 @@ private CheckResult[] parseMoves(int[] moves, List[] learn, int[] relearn, else res[m] = new CheckResult(Severity.Valid, V333, CheckIdentifier.Move) { Flag = true }; } + if (pkm.TradebackStatus == TradebackType.Any && pkm.GenNumber == 1) + pkm.TradebackStatus = TradebackType.WasTradeback; EventEggMovesLearned.Add(m); } diff --git a/PKHeX/Legality/Core.cs b/PKHeX/Legality/Core.cs index 520b9b9e3..a83f97779 100644 --- a/PKHeX/Legality/Core.cs +++ b/PKHeX/Legality/Core.cs @@ -21,6 +21,11 @@ public static partial class Legal public static string EReaderBerryName = string.Empty; public static string EReaderBerryDisplayName => string.Format(V372, CultureInfo.CurrentCulture.TextInfo.ToTitleCase(EReaderBerryName.ToLower())); public static bool SavegameJapanese = false; + public static string Savegame_OT = string.Empty; + public static int Savegame_TID = 0; + public static int Savegame_SID = 0; + public static int Savegame_Gender = 0; + public static GameVersion Savegame_Version = GameVersion.Any; // Gen 1 private static readonly Learnset[] LevelUpRB = Learnset1.getArray(Resources.lvlmove_rb, MaxSpeciesID_1); @@ -316,17 +321,17 @@ private static EncounterType GetEncounterTypeBySlotDPPt( SlotType Type, Encounte case SlotType.Surf: case SlotType.Old_Rod: case SlotType.Good_Rod: - case SlotType.Super_Rod: return EncounterType.Surfing_Fishing; - case SlotType.Grass_Safari: + case SlotType.Super_Rod: case SlotType.Surf_Safari: case SlotType.Old_Rod_Safari: case SlotType.Good_Rod_Safari: - case SlotType.Super_Rod_Safari: return EncounterType.MarshSafari; + case SlotType.Super_Rod_Safari: return EncounterType.Surfing_Fishing; + case SlotType.Grass_Safari: return EncounterType.MarshSafari; case SlotType.HoneyTree: return EncounterType.None; } return EncounterType.None; } - private static EncounterType GetEncounterTypeBySlotHGSS(SlotType Type, EncounterType GrassType) + private static EncounterType GetEncounterTypeBySlotHGSS(SlotType Type, EncounterType GrassType, EncounterType HeadbuttType) { switch (Type) { @@ -344,41 +349,66 @@ private static EncounterType GetEncounterTypeBySlotHGSS(SlotType Type, Encounter case SlotType.Super_Rod_Safari: return EncounterType.Surfing_Fishing; case SlotType.Rock_Smash: case SlotType.Rock_Smash_Safari: return EncounterType.RockSmash; - case SlotType.Headbutt: return EncounterType.None; + case SlotType.Headbutt: return HeadbuttType; + case SlotType.Headbutt_Special: return EncounterType.None; } return EncounterType.None; } - private static void MarkDPPtEncounterTypeSlots_Route209(ref EncounterArea[] Areas) + private static void MarkDPPtEncounterTypeSlots_MultipleTypes(ref EncounterArea[] Areas, int Location, int SpecialEncounterFile, EncounterType NormalEncounterType) { - // Route 209 have two different encounter type for grass encounters - // The first area with location 24 is the proper Route 209 with tall grass encounters - // The other areas with the same location in the raw file is the lost tower, all encounters inside the tower are buildiing encounter - bool FirstArea = true; - foreach (EncounterArea Area in Areas.Where(x => x.Location == 24)) + // Area with two different encounter type for grass encounters + // SpecialEncounterFile is tall grass encounter type, the other files have the normal encounter type for this location + var numfile = 0; + foreach (EncounterArea Area in Areas.Where(x => x.Location == Location)) { - var GrassType = FirstArea ? EncounterType.TallGrass : EncounterType.Building_EnigmaStone; - if (FirstArea) - FirstArea = false; + numfile++; + var GrassType = numfile == SpecialEncounterFile ? EncounterType.TallGrass : NormalEncounterType; foreach (EncounterSlot Slot in Area.Slots) { Slot.TypeEncounter = GetEncounterTypeBySlotDPPt(Slot.Type, GrassType); } } } - private static void MarkHGSSEncounterTypeSlots_RuinsofAlph(ref EncounterArea[] Areas) + private static void MarkDPPtEncounterTypeSlots_MultipleTypes(ref EncounterArea[] Areas, int Location, int[] SpecialEncounterFiles, EncounterType NormalEncounterType) { - // Ruins of Alph have two different encounter type for grass encounters - // The first area with location 209 is the outside area of the ruins with tall grass encounters - // The other areas with the same location in the raw file is the inside of the ruins, all encounters inside are cave encounters - bool FirstArea = true; - foreach (EncounterArea Area in Areas.Where(x => x.Location == 209)) + var numfile = 0; + foreach (EncounterArea Area in Areas.Where(x => x.Location == Location)) { - var GrassType = FirstArea ? EncounterType.TallGrass : EncounterType.Cave_HallOfOrigin; - if (FirstArea) - FirstArea = false; + numfile++; + var GrassType = SpecialEncounterFiles.Contains(numfile) ? EncounterType.TallGrass : NormalEncounterType; foreach (EncounterSlot Slot in Area.Slots) { - Slot.TypeEncounter = GetEncounterTypeBySlotHGSS(Slot.Type, GrassType); + Slot.TypeEncounter = GetEncounterTypeBySlotDPPt(Slot.Type, GrassType); + } + } + } + private static void MarkHGSSEncounterTypeSlots_MultipleTypes(ref EncounterArea[] Areas, int Location, int SpecialEncounterFile, EncounterType NormalEncounterType) + { + // Area with two different encounter type for grass encounters + // SpecialEncounterFile is taall grass encounter type, the other files have the normal encounter type for this location + var HeadbuttType = getHeadbuttEncounter(Location); + var numfile = 0; + foreach (EncounterArea Area in Areas.Where(x => x.Location == Location)) + { + numfile++; + var GrassType = numfile == SpecialEncounterFile ? EncounterType.TallGrass : NormalEncounterType; + foreach (EncounterSlot Slot in Area.Slots) + { + Slot.TypeEncounter = GetEncounterTypeBySlotHGSS(Slot.Type, GrassType, HeadbuttType); + } + } + } + private static void MarkHGSSEncounterTypeSlots_MultipleTypes(ref EncounterArea[] Areas, int Location, int[] SpecialEncounterFiles, EncounterType NormalEncounterType) + { + var HeadbuttType = getHeadbuttEncounter(Location); + var numfile = 0; + foreach (EncounterArea Area in Areas.Where(x => x.Location == Location)) + { + numfile++; + var GrassType = SpecialEncounterFiles.Contains(numfile) ? EncounterType.TallGrass : NormalEncounterType; + foreach (EncounterSlot Slot in Area.Slots) + { + Slot.TypeEncounter = GetEncounterTypeBySlotHGSS(Slot.Type, GrassType, HeadbuttType); } } } @@ -386,7 +416,7 @@ private static void MarkDPPtEncounterTypeSlots(ref EncounterArea[] Areas) { foreach(EncounterArea Area in Areas) { - if (Area.Location == 24) + if (DPPt_MixInteriorExteriorLocations.Contains(Area.Location)) continue; var GrassType = (Area.Location == 70) ? EncounterType.Building_EnigmaStone :// Old Chateau DPPt_CaveLocations.Contains(Area.Location) ? EncounterType.Cave_HallOfOrigin : @@ -397,16 +427,40 @@ private static void MarkDPPtEncounterTypeSlots(ref EncounterArea[] Areas) } } } + private static EncounterType getHeadbuttEncounter(int Location) + { + // Routes with trees adjacent to water tiles + var allowsurf= HGSS_SurfingHeadbutt_Locations.Contains(Location); + // Cities + if (HGSS_CityLocations.Contains(Location)) + { + return allowsurf ? EncounterType.Headbutt_CitySurf : EncounterType.Building_EnigmaStone; + } + // Caves with no exterior zones + if (!HGSS_MixInteriorExteriorLocations.Contains(Location) && HGSS_CaveLocations.Contains(Location)) + { + return allowsurf ? EncounterType.Headbutt_CaveSurf : EncounterType.Cave_HallOfOrigin; + } + // Routes and exterior areas + // Routes with trees adjacent to grass tiles + var allowgrass = HGSS_GrassHeadbutt_Locations.Contains(Location); + return allowgrass && allowsurf ? EncounterType.Headbutt_GrassSurf : + allowgrass ? EncounterType.Headbutt_Grass : + allowsurf ? EncounterType.Headbutt_Surf : + EncounterType.None; + } + private static void MarkHGSSEncounterTypeSlots(ref EncounterArea[] Areas) { foreach (EncounterArea Area in Areas) { - if (Area.Location == 209) + if (HGSS_MixInteriorExteriorLocations.Contains(Area.Location)) continue; var GrassType = HGSS_CaveLocations.Contains(Area.Location) ? EncounterType.Cave_HallOfOrigin: EncounterType.TallGrass; + var HeadbuttType = getHeadbuttEncounter(Area.Location); foreach (EncounterSlot Slot in Area.Slots) { - Slot.TypeEncounter = GetEncounterTypeBySlotHGSS(Slot.Type, GrassType); + Slot.TypeEncounter = GetEncounterTypeBySlotHGSS(Slot.Type, GrassType, HeadbuttType); } } } @@ -655,11 +709,26 @@ private static EncounterArea[] getTables2(GameVersion Version) MarkG4AltFormSlots(ref Pt_Slots, 422, 1, Shellos_EastSeaLocation_Pt); MarkG4AltFormSlots(ref Pt_Slots, 423, 1, Gastrodon_EastSeaLocation_Pt); - MarkDPPtEncounterTypeSlots_Route209(ref D_Slots); - MarkDPPtEncounterTypeSlots_Route209(ref P_Slots); - MarkDPPtEncounterTypeSlots_Route209(ref Pt_Slots); - MarkHGSSEncounterTypeSlots_RuinsofAlph(ref HG_Slots); - MarkHGSSEncounterTypeSlots_RuinsofAlph(ref SS_Slots); + // Route 209 + MarkDPPtEncounterTypeSlots_MultipleTypes(ref D_Slots, 24, 1, EncounterType.Building_EnigmaStone); + MarkDPPtEncounterTypeSlots_MultipleTypes(ref P_Slots, 24, 1, EncounterType.Building_EnigmaStone); + MarkDPPtEncounterTypeSlots_MultipleTypes(ref Pt_Slots, 24, 1, EncounterType.Building_EnigmaStone); + + // Stark Mountain + MarkDPPtEncounterTypeSlots_MultipleTypes(ref D_Slots, 84, 1, EncounterType.Cave_HallOfOrigin); + MarkDPPtEncounterTypeSlots_MultipleTypes(ref P_Slots, 84, 1, EncounterType.Cave_HallOfOrigin); + MarkDPPtEncounterTypeSlots_MultipleTypes(ref Pt_Slots, 84, 1, EncounterType.Cave_HallOfOrigin); + // Mt Coronet + MarkDPPtEncounterTypeSlots_MultipleTypes(ref D_Slots, 50, DPPt_MtCoronetExteriorEncounters, EncounterType.Cave_HallOfOrigin); + MarkDPPtEncounterTypeSlots_MultipleTypes(ref P_Slots, 50, DPPt_MtCoronetExteriorEncounters, EncounterType.Cave_HallOfOrigin); + MarkDPPtEncounterTypeSlots_MultipleTypes(ref Pt_Slots, 50, DPPt_MtCoronetExteriorEncounters, EncounterType.Cave_HallOfOrigin); + + // Ruins of Alph + MarkHGSSEncounterTypeSlots_MultipleTypes(ref HG_Slots, 209, 1, EncounterType.Cave_HallOfOrigin); + MarkHGSSEncounterTypeSlots_MultipleTypes(ref SS_Slots, 209, 1, EncounterType.Cave_HallOfOrigin); + // Mt Silver Cave + MarkHGSSEncounterTypeSlots_MultipleTypes(ref HG_Slots, 219, HGSS_MtSilverCaveExteriorEncounters, EncounterType.Cave_HallOfOrigin); + MarkHGSSEncounterTypeSlots_MultipleTypes(ref SS_Slots, 219, HGSS_MtSilverCaveExteriorEncounters, EncounterType.Cave_HallOfOrigin); MarkG4Slots(ref D_Slots); MarkG4Slots(ref P_Slots); @@ -1338,7 +1407,7 @@ internal static EncounterSlot[] getValidWildEncounters(PKM pkm, GameVersion game if (s.Count <= 1 || pkm.Format == 7) return s.Any() ? s.ToArray() : null; - var s_EncounterTypes = s.Where(slot => slot.TypeEncounter == (EncounterType)pkm.EncounterType).ToList(); + var s_EncounterTypes = s.Where(slot => slot.TypeEncounter.Contains(pkm.EncounterType)).ToList(); if (s_EncounterTypes.Any()) return s_EncounterTypes.ToArray(); @@ -1360,12 +1429,17 @@ internal static List getValidStaticEncounter(PKM pkm, GameVersi var enc = getMatchingStaticEncounters(pkm, poss, lvl); // Filter for encounter types - if (pkm.Gen4 && pkm.Format < 7) // type is cleared on 6->7 + if (pkm.Gen4 && pkm.Format < 7 && enc.Count() > 1) // type is cleared on 6->7 { int type = pkm.EncounterType; - enc = type == 0 + var enctype = type == 0 ? enc.Where(z => !(z is EncounterStaticTyped)) // no typed encounters - : enc.Where(z => z is EncounterStaticTyped && (int) ((EncounterStaticTyped)z).TypeEncounter == type); + : enc.Where(z => z is EncounterStaticTyped && ((EncounterStaticTyped)z).TypeEncounter.Contains(type)); + + // Filter only if there are encounters that match types and encounters that do not match types, like wild encounters + // IF there is only one of the two possibilities encounter type check will detect encounter type does not match encounter + if (enctype.Any()) + enc = enctype; } var result = enc.ToList(); return result.Count == 0 ? null : result; @@ -1403,12 +1477,23 @@ private static IEnumerable getMatchingStaticEncounters(PKM pkm, if (pkm.Format == 1 && pkm.Gen1_NotTradeback) { var catch_rate = (pkm as PK1).Catch_Rate; + var japanese = (pkm as PK1).Japanese; // Pure gen 1, trades can be filter by catch rate if ((pkm.Species == 25 || pkm.Species == 26) && catch_rate == 190) // Red Blue Pikachu, is not a static encounter continue; - if (catch_rate != PersonalTable.RB[e.Species].CatchRate && catch_rate != PersonalTable.Y[e.Species].CatchRate) + if (e.Version == GameVersion.Stadium) + { + if (e.Species != 054 && !Stadium_CatchRate.Contains(catch_rate)) + continue; + // Amnesia Psyduck have different catch rate in japanese stadium and international stadium + if (e.Species == 054 && japanese && catch_rate != 167) + continue; + if (e.Species == 054 && !japanese && catch_rate != 168) + continue; + } + else if (catch_rate != PersonalTable.RB[e.Species].CatchRate && catch_rate != PersonalTable.Y[e.Species].CatchRate) continue; } @@ -1811,8 +1896,13 @@ private static EncounterTrade getValidEncounterTradeVC1(PKM pkm, DexLevel[] p, E { // Even if the in game trade use the tables with source pokemon allowing generaion 2 games, the traded pokemon could be a non-tradeback pokemon var catch_rate = (pkm as PK1).Catch_Rate; - if (catch_rate != PersonalTable.RB[z.Species].CatchRate && catch_rate != PersonalTable.Y[z.Species].CatchRate) - return null; + if (z is EncounterTradeCatchRate) + { + if (catch_rate != ((EncounterTradeCatchRate)z).Catch_Rate) + return null; + } + else if (catch_rate != PersonalTable.RB[z.Species].CatchRate && catch_rate != PersonalTable.Y[z.Species].CatchRate) + return null; } return z; } @@ -1837,6 +1927,11 @@ private static GBEncounterData getEncounter12(PKM pkm, GameVersion game) DexLevel[] vs = getValidPreEvolutions(pkm, maxspeciesorigin: maxspeciesorigin).ToArray(); var s = getValidStaticEncounter(pkm, game); + + // Valid stadium and non-stadium encounters, return only non-stadium encounters, they are less restrictive + if (s != null && game == GameVersion.RBY && s.Any(st => st.Species != 54 && st.Version == GameVersion.Stadium) && s.Any(st => st.Species != 54 && st.Version != GameVersion.Stadium)) + s = s.Where(st => st.Version != GameVersion.Stadium).ToList(); + var e = getValidWildEncounters(pkm, game); var t = getValidIngameTrade(pkm, game); @@ -1884,7 +1979,8 @@ internal static List getEncounter12(PKM pkm) // Both generations can provide an encounter. Return highest preference g1.MoveLevel = getMoveMinLevelGBEncounter(g1.Species, g1.Level, getGen1GameEncounter(pkm)); if (g1.Type > g2.Type) - return new List { g1 }; + // Return also generation 2 encounters, is only needed to determine that pokemon is not exclusive from generation 1 + return new List { g1, g2 }; if (g1.Type <= g2.Type || // Return lowest level encounter g2.MoveLevel < g1.MoveLevel) @@ -1892,7 +1988,7 @@ internal static List getEncounter12(PKM pkm) // Return also generation 1 moves, it could have different encounter moves return new List { g2, g1 }; } - return new List { g1 }; + return new List { g1, g2 }; } internal static bool getEncounterTrade1Valid(PKM pkm) { @@ -3695,5 +3791,17 @@ internal static List[] GetEmptyEggMovesList() emptyegg[0] = new List(); return emptyegg; } + + internal static bool IsOutsider(PKM pkm) + { + var Outsider = Savegame_TID != pkm.TID || Savegame_OT != pkm.OT_Name; + if (pkm.Format <= 2) + return Outsider; + Outsider |= Savegame_SID != pkm.SID; + if (pkm.Format == 3) // Generation 3 does not check ot geneder nor pokemon version + return Outsider; + Outsider |= Savegame_Gender != pkm.OT_Gender || Savegame_Version != (GameVersion) pkm.Version; + return Outsider; + } } } diff --git a/PKHeX/Legality/LegalityCheckStrings.cs b/PKHeX/Legality/LegalityCheckStrings.cs index 2324d217e..1e3dbe49f 100644 --- a/PKHeX/Legality/LegalityCheckStrings.cs +++ b/PKHeX/Legality/LegalityCheckStrings.cs @@ -72,6 +72,8 @@ public static class LegalityCheckStrings public static string V393 { get; set; } = "Valid Type B, match species type."; public static string V394 { get; set; } = "Catch rate match a valid held item from generation 2"; public static string V398 { get; set; } = "Catch Rate match a species from pokemon evolution chain."; + public static string V403 { get; set; } = "Valid International Stadium OT."; + public static string V404 { get; set; } = "Valid Japanese Stadium OT."; #endregion #region Legality Check Result Strings @@ -392,9 +394,11 @@ public static class LegalityCheckStrings public static string V396 {get; set;} = "Catch rate match species without encounters. Expected a preevolution catch rate."; public static string V397 {get; set;} = "Catch rate does not match any species from pokemon evolution chain."; public static string V399 {get; set;} = "Catch rate does not match any species from pokemon evolution chain or any generation 2 held items."; - public static string V400 {get; set;} = "Unable to match encounter conditions to a possible RNG frame."; - + public static string V401 {get; set;} = "In-game trade {0} should have evolved into {1}."; + public static string V402 {get; set;} = "Incorrect Stadium OT."; + public static string V405 {get; set;} = "Outsider {0} should have evolved into {1}."; + public static string V406 {get; set;} = "Non japanese Shadow E-reader Pokémon. Unreleased encounter."; #endregion } diff --git a/PKHeX/Legality/Structures/EncounterArea.cs b/PKHeX/Legality/Structures/EncounterArea.cs index 1fc6c22e3..7220949f4 100644 --- a/PKHeX/Legality/Structures/EncounterArea.cs +++ b/PKHeX/Legality/Structures/EncounterArea.cs @@ -586,7 +586,7 @@ private static EncounterArea getArea4HGSS_Headbutt(byte[] data) Species = Species, LevelMin = data[8 + i*4], LevelMax = data[9 + i*4], - Type = SlotType.Headbutt + Type = i <= 11 ? SlotType.Headbutt : SlotType.Headbutt_Special }); } diff --git a/PKHeX/Legality/Structures/EncounterStatic.cs b/PKHeX/Legality/Structures/EncounterStatic.cs index a88207bf3..1657d5291 100644 --- a/PKHeX/Legality/Structures/EncounterStatic.cs +++ b/PKHeX/Legality/Structures/EncounterStatic.cs @@ -125,7 +125,7 @@ public string Name public class EncounterStaticTyped : EncounterStatic { - public EncounterType TypeEncounter = EncounterType.Any; + public EncounterType TypeEncounter = EncounterType.None; protected override EncounterStatic Clone(int location) { @@ -164,6 +164,7 @@ public class EncounterStaticShadow : EncounterStatic { public EncounterLock[] Locks = new EncounterLock[0]; public int Gauge; + public bool EReader = false; protected override EncounterStatic Clone(int location) { diff --git a/PKHeX/Legality/Structures/EncounterTrade.cs b/PKHeX/Legality/Structures/EncounterTrade.cs index 7ebd9dfd6..3fd55d3d8 100644 --- a/PKHeX/Legality/Structures/EncounterTrade.cs +++ b/PKHeX/Legality/Structures/EncounterTrade.cs @@ -22,6 +22,7 @@ public class EncounterTrade : IEncounterable, IMoveset, IGeneration public int Gender = -1; public int OTGender = -1; public bool EggEncounter => false; + public bool EvolveOnTrade = false; public string Name => "In-game Trade"; @@ -35,4 +36,9 @@ public class EncounterTradePID : EncounterTrade { public uint PID; } + + public class EncounterTradeCatchRate : EncounterTrade + { + public uint Catch_Rate; + } } diff --git a/PKHeX/Legality/Structures/EncounterType.cs b/PKHeX/Legality/Structures/EncounterType.cs index b2cc13c25..c68a9154c 100644 --- a/PKHeX/Legality/Structures/EncounterType.cs +++ b/PKHeX/Legality/Structures/EncounterType.cs @@ -2,7 +2,11 @@ { public enum EncounterType { - Any = -1, + Headbutt_Grass = -1, // None or TallGrass + Headbutt_Surf = -2, // None or Surfing_Fishing + Headbutt_GrassSurf = -3, // None, TallGrass or Surfing_Fishing + Headbutt_CitySurf = -4, // Building_EnigmaStone or Surfing_Fishing + Headbutt_CaveSurf = -5, // Cave_HallOfOrigin or Surfing_Fishing None = 0, RockSmash = 1, TallGrass = 2, @@ -15,4 +19,27 @@ public enum EncounterType DistortionWorld_Pt = 23, Starter_Fossil_Gift_Pt_DPTrio = 24, } + + public static class EncounterTypeExtension + { + public static bool Contains(this EncounterType g1, int g2) + { + return g1.Contains((EncounterType)g2); + } + public static bool Contains(this EncounterType g1, EncounterType g2) + { + if (g1 == EncounterType.Headbutt_Grass) + return g2 == EncounterType.None || g2 == EncounterType.TallGrass; + if (g1 == EncounterType.Headbutt_Surf) + return g2 == EncounterType.None || g2 == EncounterType.Surfing_Fishing; + if (g1 == EncounterType.Headbutt_GrassSurf) + return EncounterType.Headbutt_Grass.Contains(g2) || g2 == EncounterType.Surfing_Fishing; + if (g1 == EncounterType.Headbutt_CitySurf) + return g2 == EncounterType.Building_EnigmaStone || g2 == EncounterType.Surfing_Fishing; + if (g1 == EncounterType.Headbutt_CaveSurf) + return g2 == EncounterType.Cave_HallOfOrigin || g2 == EncounterType.Surfing_Fishing; + + return g1 == g2; + } + } } diff --git a/PKHeX/Legality/Structures/SlotType.cs b/PKHeX/Legality/Structures/SlotType.cs index a144c49ba..e83358d3a 100644 --- a/PKHeX/Legality/Structures/SlotType.cs +++ b/PKHeX/Legality/Structures/SlotType.cs @@ -19,6 +19,7 @@ public enum SlotType SOS, Swarm, Headbutt, + Headbutt_Special, Pokeradar, HoneyTree, HiddenGrotto, diff --git a/PKHeX/Legality/Tables1.cs b/PKHeX/Legality/Tables1.cs index 967a59641..5bd4eddb4 100644 --- a/PKHeX/Legality/Tables1.cs +++ b/PKHeX/Legality/Tables1.cs @@ -110,6 +110,14 @@ public static partial class Legal // new EncounterStatic { Species = 007, Level = 10, Version = GameVersion.YW }, // Squirtle (Vermillion City) new EncounterStatic { Species = 054, Level = 15, Moves = new [] { 133, 10 }, Version = GameVersion.Stadium }, // Stadium Psyduck (Amnesia) + new EncounterStatic { Species = 001, Level = 05, Version = GameVersion.Stadium }, // Bulbasaur + new EncounterStatic { Species = 004, Level = 05, Version = GameVersion.Stadium }, // Charmander + new EncounterStatic { Species = 071, Level = 05, Version = GameVersion.Stadium }, // Squirtle + new EncounterStatic { Species = 106, Level = 20, Version = GameVersion.Stadium }, // Hitmonlee + new EncounterStatic { Species = 107, Level = 20, Version = GameVersion.Stadium }, // Hitmonchan + new EncounterStatic { Species = 133, Level = 25, Version = GameVersion.Stadium }, // Eevee + new EncounterStatic { Species = 138, Level = 20, Version = GameVersion.Stadium }, // Omanyte + new EncounterStatic { Species = 140, Level = 20, Version = GameVersion.Stadium }, // Kabuto new EncounterStatic { Species = 151, Level = 5, IVs = new [] {15,15,15,15,15,15}, Version = GameVersion.VCEvents }, // Event Mew }; internal static readonly EncounterTrade[] TradeGift_RBY_Common = @@ -140,9 +148,9 @@ public static partial class Legal new EncounterTrade { Species = 115, Generation = 1, Level = 42 }, // Kangaskhan - Evolve Rhydon (GSC: 30) new EncounterTrade { Species = 128, Generation = 1, Level = 28 }, // Tauros - Evolve Persian (GSC: 18) - new EncounterTrade { Species = 093, Generation = 1, Level = 20 }, // Haunter - Trade Machoke (GSC: 10) - new EncounterTrade { Species = 075, Generation = 1, Level = 16 }, // Graveler - Evolve Kadabra (GSC: 15) - new EncounterTrade { Species = 098, Generation = 1, Level = 15 }, // Krabby - Wild Growlithe (GSC: 5) + new EncounterTradeCatchRate { Species = 093, Generation = 1, Level = 20, Catch_Rate = 45, EvolveOnTrade = true }, // Haunter - Trade Machoke (GSC: 10) + new EncounterTradeCatchRate { Species = 075, Generation = 1, Level = 16, Catch_Rate = 45, EvolveOnTrade = true }, // Graveler - Evolve Kadabra (GSC: 15) + new EncounterTradeCatchRate { Species = 098, Generation = 1, Level = 15, Catch_Rate = 204 }, // Krabby - Wild Growlithe (GSC: 5) //new EncounterTrade { Species = 122, Generation = 1, Level = 08 }, // Mr. Mime - Wild Clefairy (GSC: 6) new EncounterTrade { Species = 067, Generation = 1, Level = 20 }, // Machoke - Wild Cubone (GSC: 10) @@ -159,9 +167,9 @@ public static partial class Legal new EncounterTrade { Species = 115, Generation = 1, Level = 30 }, // Kangaskhan - Evolve Rhydon (RBY: 42) new EncounterTrade { Species = 128, Generation = 1, Level = 18 }, // Tauros - Evolve Persian (RBY: 28) - new EncounterTrade { Species = 093, Generation = 1, Level = 10 }, // Haunter - Trade Machoke (RBY: 20) - new EncounterTrade { Species = 075, Generation = 1, Level = 15 }, // Graveler - Evolve Kadabra (RBY: 16) - new EncounterTrade { Species = 098, Generation = 1, Level = 05 }, // Krabby - Egg Growlithe (RBY: 15) + new EncounterTradeCatchRate { Species = 093, Generation = 1, Level = 10, Catch_Rate = 45, EvolveOnTrade = true }, // Haunter - Trade Machoke (RBY: 20) + new EncounterTradeCatchRate { Species = 075, Generation = 1, Level = 15, Catch_Rate = 45, EvolveOnTrade = true }, // Graveler - Evolve Kadabra (RBY: 16) + new EncounterTradeCatchRate { Species = 098, Generation = 1, Level = 05, Catch_Rate = 204 }, // Krabby - Egg Growlithe (RBY: 15) //new EncounterTrade { Species = 122, Generation = 1, Level = 08 }, // Mr. Mime - Wild Clefairy (RBY: 6) new EncounterTrade { Species = 067, Generation = 1, Level = 05 }, // Machoke - Egg Cubone (RBY: 20) @@ -196,7 +204,31 @@ public static partial class Legal }; internal static readonly int[] Species_NotAvailable_CatchRate = { - 12, 18, 31, 34, 36, 38, 45, 53, 59, 62, 65, 68, 71, 76, 78, 91, 94, 103, 121 + 12, 18, 31, 34, 36, 38, 45, 53, 59, 62, 65, 68, 71, 78, 91, 103, 121 + }; + internal static readonly int[] Stadium_CatchRate = + { + 167, // Normal Box + 168, // Gorgeous Box + }; + internal static readonly int[] Stadium_GiftSpecies = + { + 001, // Bulbasaur + 004, // Charmander + 007, // Squirtle + 054, // Psyduck (Amnesia) + 106, // Hitmonlee + 107, // Hitmonchan + 133, // Eevee + 138, // Omanyte + 140, // Kabuto + }; + internal static readonly int[] Trade_Evolution1 = + { + 064, + 067, + 075, + 093 }; } } diff --git a/PKHeX/Legality/Tables3.cs b/PKHeX/Legality/Tables3.cs index 5e58f21b6..55c7c9ba5 100644 --- a/PKHeX/Legality/Tables3.cs +++ b/PKHeX/Legality/Tables3.cs @@ -719,9 +719,9 @@ public static partial class Legal new EncounterStaticShadow { Species = 217, Level = 45, Gauge = 07000, Moves = new[] {185,313,122,163}, Location = 132 }, // Ursaring: Team Snagem Agrev @ Snagem Hideout new EncounterStaticShadow { Species = 213, Level = 45, Gauge = 07000, Moves = new[] {219,227,156,117}, Location = 125 }, // Shuckle: Deep King Agnol @ Deep Colosseum new EncounterStaticShadow { Species = 176, Level = 20, Gauge = 05000, Moves = new[] {118,204,186,281}, Location = 001 }, // Togetic: Cipher Peon Fein @ Outskirt Stand - new EncounterStaticShadow { Species = 175, Level = 20, Gauge = 00000, Moves = new[] {118,204,186,281}, IVs = new[] {0,0,0,0,0,0} }, // Togepi: Chaser ボデス @ Card e Room (Japanese games only) - new EncounterStaticShadow { Species = 179, Level = 37, Gauge = 00000, Moves = new[] {087,084,086,178}, IVs = new[] {0,0,0,0,0,0} }, // Mareep: Hunter ホル @ Card e Room (Japanese games only) - new EncounterStaticShadow { Species = 212, Level = 50, Gauge = 00000, Moves = new[] {210,232,014,163}, IVs = new[] {0,0,0,0,0,0} }, // Scizor: Bodybuilder ワーバン @ Card e Room (Japanese games only) + new EncounterStaticShadow { Species = 175, Level = 20, Gauge = 00000, Moves = new[] {118,204,186,281}, IVs = new[] {0,0,0,0,0,0}, EReader = true }, // Togepi: Chaser ボデス @ Card e Room (Japanese games only) + new EncounterStaticShadow { Species = 179, Level = 37, Gauge = 00000, Moves = new[] {087,084,086,178}, IVs = new[] {0,0,0,0,0,0}, EReader = true }, // Mareep: Hunter ホル @ Card e Room (Japanese games only) + new EncounterStaticShadow { Species = 212, Level = 50, Gauge = 00000, Moves = new[] {210,232,014,163}, IVs = new[] {0,0,0,0,0,0}, EReader = true }, // Scizor: Bodybuilder ワーバン @ Card e Room (Japanese games only) }; #endregion diff --git a/PKHeX/Legality/Tables4.cs b/PKHeX/Legality/Tables4.cs index 690549a34..413b7a727 100644 --- a/PKHeX/Legality/Tables4.cs +++ b/PKHeX/Legality/Tables4.cs @@ -220,6 +220,17 @@ public static partial class Legal 69, // Iron Island 84, // Stark Mountain }; + internal static readonly int[] DPPt_MixInteriorExteriorLocations = + { + 24, // Route 209 (Lost Tower) + 50, // Mt Coronet + 70, // Old Chateau + 84, // Stark Mountain + }; + internal static readonly int[] DPPt_MtCoronetExteriorEncounters = + { + 4, 5 + }; internal static readonly int[] HGSS_CaveLocations = { 197, // DIGLETT's Cave @@ -245,9 +256,105 @@ public static partial class Legal 228, // Cliff Cave 234, // Cliff Edge Gate }; + internal static readonly int[] HGSS_CityLocations = + { + 126, // New Bark Town + 127, // Cherrygrove City + 128, // Violet City + 129, // Azalea Town + 130, // Cianwood City + 131, // Goldenrod City + 132, // Olivine City + 133, // Ecruteak City + 134, // Mahogany Town + 136, // Blackthorn City + 138, // Pallet Town + 139, // Viridian City + 140, // Pewter City + 141, // Cerulean City + 142, // Lavender Town + 143, // Vermilion City + 144, // Celadon City + 145, // Fuchsia City + 146, // Cinnabar Island + 147, // Indigo Plateau + 148, // Saffron City + 227, // Safari Zone Gate + }; + internal static readonly int[] HGSS_SurfingHeadbutt_Locations = + { // Locations with headbutt trees adjacent to water tiles + 126, // New Bark Town + 128, // Violet City + 133, // Ecruteak City + 135, // Lake of Rage + 138, // Pallet Town + 139, // Viridian City + 160, // Route 12 + 169, // Route 21 + 170, // Route 22 + 174, // Route 26 + 175, // Route 27 + 176, // Route 28 + 178, // Route 30 + 179, // Route 31 + 180, // Route 32 + 182, // Route 34 + 183, // Route 35 + 190, // Route 42 + 191, // Route 43 + 192, // Route 44 + 214, // Ilex Forest + }; + internal static readonly int[] HGSS_GrassHeadbutt_Locations = + { // Locations with headbutt trees adjacent to tall grass tiles + 137, // Mt. Silver + 149, // Route 1 + 150, // Route 2 + 151, // Route 3 + 152, // Route 4 + 153, // Route 5 + 154, // Route 6 + 155, // Route 7 + 159, // Route 11 + 161, // Route 13 + 163, // Route 15 + 164, // Route 16 + 169, // Route 21 + 170, // Route 22 + 174, // Route 26 + 175, // Route 27 + 176, // Route 28 + 177, // Route 29 + 178, // Route 30 + 179, // Route 31 + 180, // Route 32 + 181, // Route 33 + 182, // Route 34 + 183, // Route 35 + 184, // Route 36 + 185, // Route 37 + 186, // Route 38 + 187, // Route 39 + 191, // Route 43 + 192, // Route 44 + 194, // Route 46 + 195, // Route 47 + 196, // Route 48 + 219, // Mt. Silver Cave + 224, // Viridian Forest + }; + internal static readonly int[] HGSS_MtSilverCaveExteriorEncounters = + { + 2, 3 + }; + internal static readonly int[] HGSS_MixInteriorExteriorLocations = + { + 209, // Ruins of Alph + 219, // Mt. Silver Cave + }; #endregion #region Pokéwalker Encounter - // all pkm are in Poke Ball and have a met location of "PokeWalker" + // all pkm are in Poke Ball and have a met location of "PokeWalker" internal static readonly EncounterStatic[] Encounter_PokeWalker = { // Some pkm has a pre-level move, an egg move or even a special move, it might be also available via HM/TM/Tutor diff --git a/PKHeX/Legality/Tables7.cs b/PKHeX/Legality/Tables7.cs index 67b78380d..2baa9e7dc 100644 --- a/PKHeX/Legality/Tables7.cs +++ b/PKHeX/Legality/Tables7.cs @@ -299,7 +299,7 @@ public static partial class Legal new EncounterTrade { Species = 761, Form = 0, Level = 16, Ability = 1, TID = 20683, SID = 00009, OTGender = 0, Gender = 1, Nature = Nature.Adamant, }, // Bounsweet new EncounterTrade { Species = 061, Form = 0, Level = 22, Ability = 2, TID = 01092, SID = 00009, OTGender = 1, Gender = 1, Nature = Nature.Naughty, }, // Poliwhirl new EncounterTrade { Species = 440, Form = 0, Level = 27, Ability = 2, TID = 10913, SID = 00000, OTGender = 1, Gender = 1, Nature = Nature.Calm, }, // Happiny - new EncounterTrade { Species = 075, Form = 1, Level = 32, Ability = 1, TID = 20778, SID = 00009, OTGender = 0, Gender = 0, Nature = Nature.Impish, }, // Graveler-1 + new EncounterTrade { Species = 075, Form = 1, Level = 32, Ability = 1, TID = 20778, SID = 00009, OTGender = 0, Gender = 0, Nature = Nature.Impish, EvolveOnTrade = true }, // Graveler-1 new EncounterTrade { Species = 762, Form = 0, Level = 43, Ability = 1, TID = 20679, SID = 00009, OTGender = 1, Gender = 1, Nature = Nature.Careful, }, // Steenee new EncounterTrade { Species = 663, Form = 0, Level = 59, Ability = 4, TID = 56734, SID = 00008, OTGender = 0, Gender = 0, Nature = Nature.Jolly, }, // Talonflame }; diff --git a/PKHeX/Resources/text/en/LegalityCheckStrings_en.txt b/PKHeX/Resources/text/en/LegalityCheckStrings_en.txt index 821975bed..5f57a86ac 100644 --- a/PKHeX/Resources/text/en/LegalityCheckStrings_en.txt +++ b/PKHeX/Resources/text/en/LegalityCheckStrings_en.txt @@ -40,6 +40,8 @@ V392 = Valid Type A, match species type. V393 = Valid Type B, match species type. V394 = Catch rate match a valid held item from generation 2. V398 = Catch Rate match any species from pokemon evolution chain. +V403 = Valid International Stadium OT. +V404 = Valid Japanese Stadium OT. V203 = Genderless Pokémon should not have a gender. V201 = Encryption Constant is not set. V204 = Held item is unreleased. @@ -328,4 +330,9 @@ V390 = Invalid Type B, does not match species type. V395 = Catch rate does not match a valid held item from generation 2. V396 = Catch rate match species without encounters. Expected a preevolution catch rate. V397 = Catch rate does not match any species from pokemon evolution chain. -V399 = Catch rate does not match any species from pokemon evolution chain or any generation 2 held items. \ No newline at end of file +V399 = Catch rate does not match any species from pokemon evolution chain or any generation 2 held items. +V400 = Unable to match encounter conditions to a possible RNG frame. +V401 = In-game trade {0} should have evolved into {1}. +V402 = Incorrect Stadium OT. +V405 = Outsider {0} should have evolved into {1}. +V406 = Non japanese Shadow E-reader Pokémon. Unreleased encounter. \ No newline at end of file diff --git a/PKHeX/Resources/text/ko/LegalityCheckStrings_ko.txt b/PKHeX/Resources/text/ko/LegalityCheckStrings_ko.txt index ebed5ff74..92f65f636 100644 --- a/PKHeX/Resources/text/ko/LegalityCheckStrings_ko.txt +++ b/PKHeX/Resources/text/ko/LegalityCheckStrings_ko.txt @@ -41,6 +41,8 @@ V392 = Valid Type A, match species type. V393 = Valid Type B, match species type. V394 = Catch rate match a valid held item from generation 2. V398 = Catch rate match any species from pokemon evolution chain. +V403 = Valid International Stadium OT. +V404 = Valid Japanese Stadium OT. V203 = 무성 포켓몬은 성별을 가질 수 없습니다. V201 = 암호화 상수가 설정되어 있지 않습니다. V204 = 지닌 물건이 배포되지 않은 물건입니다. @@ -329,4 +331,9 @@ V390 = Invalid Type B, does not match species type. V395 = Catch rate does not match a valid held item from generation 2. V396 = Catch rate match species without encounters. Expected a preevolution catch rate. V397 = Catch rate does not match any species from pokemon evolution chain. -V399 = Catch rate does not match any species from pokemon evolution chain or any generation 2 held items. \ No newline at end of file +V399 = Catch rate does not match any species from pokemon evolution chain or any generation 2 held items. +V400 = Unable to match encounter conditions to a possible RNG frame. +V401 = In-game trade {0} should have evolved into {1}. +V402 = Incorrect Stadium OT. +V405 = Outsider {0} should have evolved into {1}. +V406 = Non japanese Shadow E-reader Pokémon. Unreleased encounter. \ No newline at end of file diff --git a/PKHeX/Resources/text/zh/LegalityCheckStrings_zh.txt b/PKHeX/Resources/text/zh/LegalityCheckStrings_zh.txt index c483ec371..51f88f03b 100644 --- a/PKHeX/Resources/text/zh/LegalityCheckStrings_zh.txt +++ b/PKHeX/Resources/text/zh/LegalityCheckStrings_zh.txt @@ -41,6 +41,8 @@ V392 = Valid Type A, match species type. V393 = Valid Type B, match species type. V394 = Catch rate match a valid held item from generation 2 V398 = Catch rate match any species from pokemon evolution chain. +V403 = Valid International Stadium OT. +V404 = Valid Japanese Stadium OT. V203 = 无性别宝可梦不能有性别。 V201 = 未设置加密常数。 V204 = 持有物未解禁。 @@ -329,4 +331,9 @@ V390 = Invalid Type B, does not match species type. V395 = Catch rate does not match a valid held item from generation 2. V396 = Catch rate match species without encounters. Expected a preevolution catch rate. V397 = Catch rate does not match any species from pokemon evolution chain. -V399 = Catch rate does not match any species from pokemon evolution chain or any generation 2 held items. \ No newline at end of file +V399 = Catch rate does not match any species from pokemon evolution chain or any generation 2 held items. +V400 = Unable to match encounter conditions to a possible RNG frame. +V401 = In-game trade {0} should have evolved into {1}. +V402 = Incorrect Stadium OT. +V405 = Outsider {0} should have evolved into {1}. +V406 = Non japanese Shadow E-reader Pokémon. Unreleased encounter. \ No newline at end of file