using System.Collections.Generic; using System.Linq; namespace PKHeX.Core { /// /// /// encounter area /// public abstract class EncounterAreaGB : EncounterArea { /// /// RBY Format Slot Getter from data. /// /// Byte array containing complete slot data table. /// Offset to start reading from. /// Amount of slots to read. /// Type of encounter slot. /// Slot type encounter rate. /// Array of encounter slots. protected static EncounterSlot1[] ReadSlots1(byte[] data, ref int ofs, int count, SlotType t, int rate) { EncounterSlot1[] slots = new EncounterSlot1[count]; for (int i = 0; i < count; i++) { int lvl = data[ofs++]; int spec = data[ofs++]; slots[i] = new EncounterSlot1 { LevelMax = t == SlotType.Surf ? lvl + 4 : lvl, LevelMin = lvl, Species = spec, Type = t, Rate = rate, SlotNumber = i, }; } return slots; } public override IEnumerable GetMatchingSlots(PKM pkm, IReadOnlyList vs, int minLevel = 0) { if (minLevel == 0) // any return Slots.Where(slot => vs.Any(evo => evo.Species == slot.Species)); var Gen1Version = GameVersion.RBY; bool RBDragonair = false; if (minLevel != 0 && !FilterGBSlotsCatchRate(pkm, ref vs, ref Gen1Version, ref RBDragonair)) return Enumerable.Empty(); var encounterSlots = GetMatchFromEvoLevel(pkm, vs, minLevel); return GetFilteredSlots(pkm, encounterSlots, Gen1Version, RBDragonair).OrderBy(slot => slot.LevelMin); // prefer lowest levels } private static bool FilterGBSlotsCatchRate(PKM pkm, ref IReadOnlyList vs, ref GameVersion Gen1Version, ref bool RBDragonair) { if (!(pkm is PK1 pk1) || !pkm.Gen1_NotTradeback) return true; // Pure gen 1, slots can be filter by catch rate var rate = pk1.Catch_Rate; switch (pkm.Species) { // Pikachu case (int)Species.Pikachu when rate == 163: case (int)Species.Raichu when rate == 163: return false; // Yellow Pikachu is not a wild encounter // Kadabra (YW) case (int)Species.Kadabra when rate == 96: case (int)Species.Alakazam when rate == 96: vs = vs.Where(s => s.Species == (int)Species.Kadabra).ToArray(); Gen1Version = GameVersion.YW; return true; // Kadabra (RB) case (int)Species.Kadabra when rate == 100: case (int)Species.Alakazam when rate == 100: vs = vs.Where(s => s.Species == (int)Species.Kadabra).ToArray(); Gen1Version = GameVersion.RB; return true; // Dragonair (YW) case (int)Species.Dragonair when rate == 27: case (int)Species.Dragonite when rate == 27: vs = vs.Where(s => s.Species == (int)Species.Dragonair).ToArray(); // Yellow Dragonair, ignore Dratini encounters Gen1Version = GameVersion.YW; return true; // Dragonair (RB) case (int)Species.Dragonair: case (int)Species.Dragonite: // Red blue dragonair have the same catch rate as dratini, it could also be a dratini from any game vs = vs.Where(s => rate == PersonalTable.RB[s.Species].CatchRate).ToArray(); RBDragonair = true; return true; default: vs = vs.Where(s => rate == PersonalTable.RB[s.Species].CatchRate).ToArray(); return true; } } private static IEnumerable GetFilteredSlots(PKM pkm, IEnumerable slots, GameVersion Gen1Version, bool RBDragonair) { int gen = pkm.GenNumber; switch (gen) { case 1: if (Gen1Version != GameVersion.RBY) slots = slots.Where(slot => Gen1Version.Contains(slot.Version)); // Red Blue dragonair or dratini from any gen 1 games if (RBDragonair) return slots.Where(slot => GameVersion.RB.Contains(slot.Version) || slot.Species == 147); return slots; case 2: if (pkm is PK2 pk2 && pk2.Met_TimeOfDay != 0) return slots.Where(slot => ((EncounterSlot1)slot).Time.Contains(pk2.Met_TimeOfDay)); return slots; default: return slots; } } } }