Refactoring

Move logic closer to where it is used rather than in larger static classes

EncounterStatic(7): move VC transfer template creation to class, simplify some sanity checks
EvoChain: g==2 case is never hit as the generation check at the top of the loop already skips
This commit is contained in:
Kurt 2020-09-05 12:11:43 -07:00
parent cf67d156ad
commit c1adab9703
18 changed files with 151 additions and 130 deletions

View file

@ -154,7 +154,10 @@ namespace PKHeX.Core
Parsed = true;
}
#if SUPPRESS
// We want to swallow any error from malformed input data from the user. The Valid state is all that we really need.
#pragma warning disable CA1031 // Do not catch general exception types
catch (Exception e)
#pragma warning restore CA1031 // Do not catch general exception types
{
System.Diagnostics.Debug.WriteLine(e.Message);
Info = new LegalInfo(pkm);
@ -284,11 +287,10 @@ namespace PKHeX.Core
var enc = (Info.EncounterOriginalGB = EncounterMatch);
if (enc is EncounterInvalid)
return;
var updated = Info.EncounterMatch = EncounterStaticGenerator.GetVCStaticTransferEncounter(pkm, enc);
if (!(updated is EncounterStatic7 s) || !EncounterStaticGenerator.IsVCStaticTransferEncounterValid(pkm, s))
{ AddLine(Severity.Invalid, LEncInvalid, CheckIdentifier.Encounter); return; }
var vc = EncounterStaticGenerator.GetVCStaticTransferEncounter(pkm, enc);
Info.EncounterMatch = vc;
foreach (var z in Transfer.VerifyVCEncounter(pkm, enc, s, Info.Moves))
foreach (var z in Transfer.VerifyVCEncounter(pkm, enc, vc, Info.Moves))
AddLine(z);
Transfer.VerifyTransferLegalityG12(this);

View file

@ -26,5 +26,38 @@
{
return true;
}
public override bool IsMatchDeferred(PKM pkm)
{
if (pkm is PK1 pk1 && pk1.Gen1_NotTradeback && !IsCatchRateValid(pk1))
return true;
return !ParseSettings.AllowGBCartEra && GameVersion.GBCartEraOnly.Contains(Version);
}
private bool IsCatchRateValid(PK1 pk1)
{
var catch_rate = pk1.Catch_Rate;
if (Species == (int)Core.Species.Pikachu)
{
if (catch_rate == 190) // Red Blue Pikachu is not a static encounter
return false;
if (catch_rate == 163 && Level == 5) // Light Ball (Yellow) starter
return true;
}
if (Version == GameVersion.Stadium)
{
// Amnesia Psyduck has different catch rates depending on language
if (Species == (int)Core.Species.Psyduck)
return catch_rate == (pk1.Japanese ? 167 : 168);
return catch_rate == 167 || catch_rate == 168;
}
// Encounters can have different Catch Rates (RBG vs Y)
var table = Version == GameVersion.Y ? PersonalTable.Y : PersonalTable.RB;
var rate = table[Species].CatchRate;
return catch_rate == rate;
}
}
}

View file

@ -72,6 +72,11 @@ namespace PKHeX.Core
return Location == pkm.Met_Location;
return true;
}
public override bool IsMatchDeferred(PKM pkm)
{
return !ParseSettings.AllowGBCartEra && GameVersion.GBCartEraOnly.Contains(Version);
}
}
public sealed class EncounterStatic2Odd : EncounterStatic2

View file

@ -28,5 +28,40 @@ namespace PKHeX.Core
return Form == evo.Form || Legal.IsFormChangeable(Species, Form, pkm.Format);
}
public static EncounterStatic7 GetVC1(int species, int metLevel)
{
bool mew = species == (int)Core.Species.Mew;
return new EncounterStatic7
{
Species = species,
Gift = true, // Forces Poké Ball
Ability = Legal.TransferSpeciesDefaultAbility_1.Contains(species) ? 1 : 4, // Hidden by default, else first
Shiny = mew ? Shiny.Never : Shiny.Random,
Fateful = mew,
Location = Locations.Transfer1,
Level = metLevel,
Version = GameVersion.RBY,
FlawlessIVCount = mew ? 5 : 3,
};
}
public static EncounterStatic7 GetVC2(int species, int metLevel)
{
bool mew = species == (int)Core.Species.Mew;
bool fateful = mew || species == (int)Core.Species.Celebi;
return new EncounterStatic7
{
Species = species,
Gift = true, // Forces Poké Ball
Ability = Legal.TransferSpeciesDefaultAbility_2.Contains(species) ? 1 : 4, // Hidden by default, else first
Shiny = mew ? Shiny.Never : Shiny.Random,
Fateful = fateful,
Location = Locations.Transfer2,
Level = metLevel,
Version = GameVersion.GSC,
FlawlessIVCount = fateful ? 5 : 3
};
}
}
}
}

View file

@ -1,4 +1,5 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Linq;
using static PKHeX.Core.Legal;
@ -43,7 +44,7 @@ namespace PKHeX.Core
{
foreach (var dl in evos)
{
if (!GetIsMatchStatic(pkm, e, dl))
if (!e.IsMatch(pkm, dl))
continue;
if (e.IsMatchDeferred(pkm))
@ -57,20 +58,6 @@ namespace PKHeX.Core
yield return e;
}
private static bool GetIsMatchStatic(PKM pkm, EncounterStatic e, DexLevel evo)
{
if (!e.IsMatch(pkm, evo))
return false;
if (pkm is PK1 pk1 && pk1.Gen1_NotTradeback && !IsValidCatchRatePK1(e, pk1))
return false;
if (!ParseSettings.AllowGBCartEra && GameVersion.GBCartEraOnly.Contains(e.Version))
return false;
return true;
}
private static IEnumerable<EncounterStatic> GetStaticEncounters(PKM pkm, IReadOnlyList<DexLevel> dl, GameVersion gameSource = GameVersion.Any)
{
if (gameSource == GameVersion.Any)
@ -80,48 +67,17 @@ namespace PKHeX.Core
return table.Where(e => dl.Any(d => d.Species == e.Species));
}
internal static IEncounterable GetVCStaticTransferEncounter(PKM pkm, IEncounterable enc)
internal static EncounterStatic7 GetVCStaticTransferEncounter(PKM pkm, IEncounterable enc)
{
var species = pkm.Species;
var met = pkm.Met_Level;
if (pkm.VC1)
return GetRBYStaticTransfer(pkm.Species > MaxSpeciesID_1 ? enc.Species : pkm.Species, pkm.Met_Level);
return EncounterStatic7.GetVC1(species > MaxSpeciesID_1 ? enc.Species : species, met);
if (pkm.VC2)
return GetGSStaticTransfer(pkm.Species > MaxSpeciesID_2 ? enc.Species : pkm.Species, pkm.Met_Level);
return new EncounterInvalid(pkm);
}
return EncounterStatic7.GetVC2(species > MaxSpeciesID_2 ? enc.Species : species, met);
private static EncounterStatic7 GetRBYStaticTransfer(int species, int pkmMetLevel)
{
bool mew = species == (int)Species.Mew;
return new EncounterStatic7
{
Species = species,
Gift = true, // Forces Poké Ball
Ability = TransferSpeciesDefaultAbility_1.Contains(species) ? 1 : 4, // Hidden by default, else first
Shiny = mew ? Shiny.Never : Shiny.Random,
Fateful = mew,
Location = Transfer1,
Level = pkmMetLevel,
Version = GameVersion.RBY,
FlawlessIVCount = mew ? 5 : 3,
};
}
private static EncounterStatic7 GetGSStaticTransfer(int species, int pkmMetLevel)
{
bool mew = species == (int) Species.Mew;
bool fateful = mew || species == (int) Species.Celebi;
return new EncounterStatic7
{
Species = species,
Gift = true, // Forces Poké Ball
Ability = TransferSpeciesDefaultAbility_2.Contains(species) ? 1 : 4, // Hidden by default, else first
Shiny = mew ? Shiny.Never : Shiny.Random,
Fateful = fateful,
Location = Transfer2,
Level = pkmMetLevel,
Version = GameVersion.GSC,
FlawlessIVCount = fateful ? 5 : 3
};
// Should never reach here.
throw new ArgumentException(nameof(pkm.Version));
}
internal static EncounterStatic? GetStaticLocation(PKM pkm, int species = -1)
@ -129,46 +85,15 @@ namespace PKHeX.Core
switch (pkm.GenNumber)
{
case 1:
return GetRBYStaticTransfer(species, pkm.Met_Level);
return EncounterStatic7.GetVC1(species, pkm.Met_Level);
case 2:
return GetGSStaticTransfer(species, pkm.Met_Level);
return EncounterStatic7.GetVC2(species, pkm.Met_Level);
default:
var dl = EvolutionChain.GetValidPreEvolutions(pkm, maxLevel: 100, skipChecks: true);
return GetPossible(pkm, dl).FirstOrDefault();
}
}
internal static bool IsVCStaticTransferEncounterValid(PKM pkm, EncounterStatic e)
{
return pkm.Met_Location == e.Location && pkm.Egg_Location == e.EggLocation;
}
private static bool IsValidCatchRatePK1(EncounterStatic e, PK1 pk1)
{
var catch_rate = pk1.Catch_Rate;
// Pure gen 1, trades can be filter by catch rate
if (pk1.Species == (int)Species.Pikachu || pk1.Species == (int)Species.Raichu)
{
if (catch_rate == 190) // Red Blue Pikachu, is not a static encounter
return false;
if (catch_rate == 163 && e.Level == 5) // Light Ball (Yellow) starter
return true;
}
if (e.Version == GameVersion.Stadium)
{
// Amnesia Psyduck has different catch rates depending on language
if (e.Species == (int)Species.Psyduck)
return catch_rate == (pk1.Japanese ? 167 : 168);
return GBRestrictions.Stadium_CatchRate.Contains(catch_rate);
}
// Encounters can have different Catch Rates (RBG vs Y)
var table = e.Version == GameVersion.Y ? PersonalTable.Y : PersonalTable.RB;
var rate = table[e.Species].CatchRate;
return catch_rate == rate;
}
// Generation Specific Fetching
private static IEnumerable<EncounterStatic> GetEncounterStaticTable(PKM pkm, GameVersion gameSource = GameVersion.Any)
{

View file

@ -132,7 +132,7 @@ namespace PKHeX.Core
case GameVersion.C:
case GameVersion.GSC:
case GameVersion.RBY:
return pkm.Format > 2 ? Legal.Transfer2 : pkm.Met_Level == 0 ? 0 : Locations.HatchLocationC;
return pkm.Format > 2 ? Locations.Transfer2 : pkm.Met_Level == 0 ? 0 : Locations.HatchLocationC;
}
return -1;
}
@ -151,9 +151,9 @@ namespace PKHeX.Core
if (pkm.Version == (int) GameVersion.GO)
return 30012;
if (pkm.VC1)
return Legal.Transfer1;
return Locations.Transfer1;
if (pkm.VC2)
return Legal.Transfer2;
return Locations.Transfer2;
if (pkm.Format == 4) // Pal Park
return Locations.Transfer3;

View file

@ -243,7 +243,7 @@ namespace PKHeX.Core
{
var res = new CheckMoveResult[4];
bool AllParsed() => res.All(z => z != null);
var required = pkm.Format != 1 ? 1 : GBRestrictions.GetRequiredMoveCount(pkm, source.CurrentMoves, info, source.Base);
var required = !(pkm is PK1 pk1) ? 1 : GBRestrictions.GetRequiredMoveCount(pk1, source.CurrentMoves, info, source.Base);
// Special considerations!
int reset = 0;

View file

@ -122,10 +122,6 @@ namespace PKHeX.Core
int minlvl = GetMinLevelGeneration(pkm, g);
GensEvoChains[g].RemoveAll(e => e.Level < minlvl);
}
else if (g == 2 && pkm.TradebackStatus == TradebackType.Gen1_NotTradeback)
{
GensEvoChains[2] = NONE;
}
else if (g == 1)
{
// Remove Gen2 post-evolutions (Scizor, Blissey...)

View file

@ -156,7 +156,7 @@ namespace PKHeX
previousspecies = 0;
}
internal static int GetRequiredMoveCount(PKM pk, IReadOnlyList<int> moves, LegalInfo info, IReadOnlyList<int> initialmoves)
internal static int GetRequiredMoveCount(PK1 pk, IReadOnlyList<int> moves, LegalInfo info, IReadOnlyList<int> initialmoves)
{
if (!pk.Gen1_NotTradeback) // No Move Deleter in Gen 1
return 1; // Move Deleter exits, slots from 2 onwards can always be empty

View file

@ -53,6 +53,12 @@
/// <summary> Route 5 in <see cref="GameVersion.SWSH"/> </summary>
public const int HatchLocation8 = 40;
/// <summary> Generation 1 -> Generation 7 Transfer Location (Kanto) </summary>
public const int Transfer1 = 30013;
/// <summary> Generation 2 -> Generation 7 Transfer Location (Johto) </summary>
public const int Transfer2 = 30017;
/// <summary> Generation 3 -> Generation 4 Transfer Location (Pal Park) </summary>
public const int Transfer3 = 0x37;

View file

@ -9,11 +9,6 @@ namespace PKHeX.Core
internal const int MaxItemID_1 = 255;
internal const int MaxAbilityID_1 = 0;
/// <summary>
/// Generation 1 -> Generation 7 Transfer Location (Kanto)
/// </summary>
public const int Transfer1 = 30013;
internal static readonly ushort[] Pouch_Items_RBY =
{
000,001,002,003,004,005,006, 010,011,012,013,014,015,

View file

@ -10,11 +10,6 @@ namespace PKHeX.Core
internal const int MaxItemID_2 = 255;
internal const int MaxAbilityID_2 = 0;
/// <summary>
/// Generation 2 -> Generation 7 Transfer Location (Johto)
/// </summary>
public const int Transfer2 = 30017;
internal static readonly ushort[] Pouch_Items_GSC = {
3, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 46, 47, 48, 49, 51, 52, 53, 57, 60, 62, 63, 64, 65, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 91, 92, 93, 94, 95, 96, 97, 98, 99, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 117, 118, 119, 121, 122, 123, 124, 125, 126, 131, 132, 138, 139, 140, 143, 144, 146, 150, 151, 152, 156, 158, 163, 167, 168, 169, 170, 172, 173, 174, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189
};

View file

@ -267,11 +267,11 @@ namespace PKHeX.Core
2000, 2002, 2009, 2010, 2011, 2013, 2014
};
internal static int GetTransfer45MetLocation(PKM pk5)
internal static int GetTransfer45MetLocation(PKM pkm)
{
if (pk5.Gen4 && pk5.FatefulEncounter)
if (pkm.Gen4 && pkm.FatefulEncounter)
{
var spec = pk5.Species;
var spec = pkm.Species;
if (spec == 251) // Celebi
return Locations.Transfer4_CelebiUnused;
if (243 <= spec && spec <= 245) // Beast

View file

@ -111,7 +111,7 @@ namespace PKHeX.Core
// Dream ball not usable in wild
};
internal static readonly HashSet<int> DreamWorldBalls = new HashSet<int> (WildPokeBalls5.Concat(new[] { 25 }));
internal static readonly HashSet<int> DreamWorldBalls = new HashSet<int>(WildPokeBalls5) {(int)Ball.Dream};
internal static readonly int[] FutureEvolutionsGen5 =
{

View file

@ -143,9 +143,6 @@ namespace PKHeX.Core
public IEnumerable<CheckResult> VerifyVCEncounter(PKM pkm, IEncounterable encounter, ILocation transfer, IList<CheckMoveResult> Moves)
{
// Check existing EncounterMatch
if (encounter is EncounterInvalid)
yield break; // Avoid duplicate invalid message
if (encounter is EncounterStatic v && (GameVersion.GBCartEraOnly.Contains(v.Version) || v.Version == GameVersion.VCEvents))
{
bool exceptions = false;

View file

@ -146,7 +146,7 @@ namespace PKHeX.Core
Move2_PPUps = Move2_PPUps,
Move3_PPUps = Move3_PPUps,
Move4_PPUps = Move4_PPUps,
Met_Location = Legal.Transfer1, // "Kanto region", hardcoded.
Met_Location = Locations.Transfer1, // "Kanto region", hardcoded.
Gender = Gender,
OT_Name = StringConverter12.GetG1ConvertedString(otname, Japanese),
IsNicknamed = false,
@ -170,7 +170,7 @@ namespace PKHeX.Core
int flawless = Species == (int)Core.Species.Mew ? 5 : 3;
var rnd = Util.Rand;
for (var i = 0; i < new_ivs.Length; i++)
new_ivs[i] = rnd.Next(pk7.MaxIV + 1);
new_ivs[i] = rnd.Next(32);
for (var i = 0; i < flawless; i++)
new_ivs[i] = 31;
Util.Shuffle(new_ivs);

View file

@ -145,7 +145,7 @@ namespace PKHeX.Core
Move2_PPUps = Move2_PPUps,
Move3_PPUps = Move3_PPUps,
Move4_PPUps = Move4_PPUps,
Met_Location = Legal.Transfer2, // "Johto region", hardcoded.
Met_Location = Locations.Transfer2, // "Johto region", hardcoded.
Gender = Gender,
IsNicknamed = false,
AltForm = AltForm,
@ -170,7 +170,7 @@ namespace PKHeX.Core
int flawless = special ? 5 : 3;
var rnd = Util.Rand;
for (var i = 0; i < new_ivs.Length; i++)
new_ivs[i] = rnd.Next(pk7.MaxIV + 1);
new_ivs[i] = rnd.Next(32);
for (var i = 0; i < flawless; i++)
new_ivs[i] = 31;
Util.Shuffle(new_ivs);
@ -191,23 +191,19 @@ namespace PKHeX.Core
else if (IsNicknamedBank)
{
pk7.IsNicknamed = true;
pk7.Nickname = Korean ? Nickname
: StringConverter12.GetG1ConvertedString(nick, Japanese);
pk7.Nickname = Korean ? Nickname : StringConverter12.GetG1ConvertedString(nick, Japanese);
}
pk7.OT_Name = Korean ? OT_Name
: StringConverter12.GetG1ConvertedString(otname, Japanese);
pk7.OT_Name = Korean ? OT_Name : StringConverter12.GetG1ConvertedString(otname, Japanese);
pk7.OT_Gender = OT_Gender; // Crystal
pk7.SetTradeMemoryHT(bank: true); // oh no, memories on gen7 pkm
// Dizzy Punch cannot be transferred
{
var moves = pk7.Moves;
var index = Array.IndexOf(moves, 146); // Dizzy Punch
var index = pk7.GetMoveIndex(146); // Dizzy Punch
if (index != -1)
{
moves[index] = 0;
pk7.Moves = moves;
pk7.SetMove(index, 0);
pk7.FixMoves();
}
}

View file

@ -1083,6 +1083,42 @@ namespace PKHeX.Core
/// </summary>
public bool HasMove(int move) => Move1 == move || Move2 == move || Move3 == move || Move4 == move;
public int GetMoveIndex(int move) => Move1 == move ? 0 : Move2 == move ? 1 : Move3 == move ? 2 : Move4 == move ? 3 : -1;
public int GetMove(int index)
{
switch (index)
{
case 0: return Move1;
case 1: return Move2;
case 2: return Move3;
case 3: return Move4;
default:
throw new IndexOutOfRangeException(nameof(index));
}
}
public void SetMove(int index, int value)
{
switch (index)
{
case 0:
Move1 = value;
return;
case 1:
Move2 = value;
return;
case 2:
Move3 = value;
return;
case 3:
Move4 = value;
return;
default:
throw new IndexOutOfRangeException(nameof(index));
}
}
/// <summary>
/// Clears moves that a <see cref="PKM"/> may have, possibly from a future generation.
/// </summary>