PKHeX/PKHeX.Core/Legality/Encounters/EncounterTrade/EncounterTrade1.cs
Kurt ccf87242c1 Eliminate boxing on encounter search (criteria)
struct implementing interface is boxed when passed to method that accepts interface (not generic method).
Removes IDexLevel (no other inheritors but EvoCriteria) and uses the primitive the data is stored (array, not IReadOnlyList) for slightly better perf.
2022-05-07 18:29:36 -07:00

138 lines
4.4 KiB
C#

using System.Linq;
namespace PKHeX.Core
{
/// <summary>
/// Trade Encounter data with a fixed Catch Rate
/// </summary>
/// <remarks>
/// Generation 1 specific value used in detecting unmodified/un-traded Generation 1 Trade Encounter data.
/// Species &amp; Minimum level (legal) possible to acquire at.
/// </remarks>
public sealed record EncounterTrade1 : EncounterTradeGB
{
public override int Generation => 1;
public override byte LevelMin => CanObtainMinGSC() ? LevelMinGSC : LevelMinRBY;
private readonly byte LevelMinRBY;
private readonly byte LevelMinGSC;
public override int Location => 0;
public override Shiny Shiny => Shiny.Random;
public EncounterTrade1(int species, GameVersion game, byte rby, byte gsc) : base(species, gsc, game)
{
TrainerNames = StringConverter12.G1TradeOTName;
LevelMinRBY = rby;
LevelMinGSC = gsc;
}
public EncounterTrade1(int species, GameVersion game, byte rby) : this(species, game, rby, rby) { }
public byte GetInitialCatchRate()
{
var pt = Version == GameVersion.YW ? PersonalTable.Y : PersonalTable.RB;
return (byte)pt[Species].CatchRate;
}
protected override void ApplyDetails(ITrainerInfo sav, EncounterCriteria criteria, PKM pk)
{
base.ApplyDetails(sav, criteria, pk);
var pk1 = (PK1)pk;
pk1.Catch_Rate = GetInitialCatchRate();
}
internal bool IsNicknameValid(PKM pkm)
{
var nick = pkm.Nickname;
if (pkm.Format <= 2)
return Nicknames.Contains(nick);
// Converted string 1/2->7 to language specific value
// Nicknames can be from any of the languages it can trade between.
int lang = pkm.Language;
if (lang == 1)
{
// Special consideration for Hiragana strings that are transferred
if (Version == GameVersion.YW && Species == (int)Core.Species.Dugtrio)
return nick == "ぐりお";
return nick == Nicknames[1];
}
return GetNicknameIndex(nick) >= 2;
}
internal bool IsTrainerNameValid(PKM pkm)
{
string ot = pkm.OT_Name;
if (pkm.Format <= 2)
return ot == StringConverter12.G1TradeOTStr;
// Converted string 1/2->7 to language specific value
int lang = pkm.Language;
var tr = GetOT(lang);
return ot == tr;
}
private int GetNicknameIndex(string nickname)
{
var nn = Nicknames;
for (int i = 0; i < nn.Count; i++)
{
if (nn[i] == nickname)
return i;
}
return -1;
}
private bool CanObtainMinGSC()
{
if (!ParseSettings.AllowGen1Tradeback)
return false;
if (Version == GameVersion.BU && EvolveOnTrade)
return ParseSettings.AllowGBCartEra;
return true;
}
private bool IsMatchLevel(PKM pkm, int lvl)
{
if (pkm is not PK1)
return lvl >= LevelMinGSC;
return lvl >= LevelMin;
}
public override bool IsMatchExact(PKM pkm, EvoCriteria evo)
{
if (!IsMatchLevel(pkm, pkm.CurrentLevel)) // minimum required level
return false;
if (Version == GameVersion.BU)
{
// Encounters with this version have to originate from the Japanese Blue game.
if (!pkm.Japanese)
return false;
// Stadium 2 can transfer from GSC->RBY without a "Trade", thus allowing un-evolved outsiders
if (EvolveOnTrade && !ParseSettings.AllowGBCartEra && pkm.CurrentLevel < LevelMinRBY)
return false;
}
return true;
}
protected override bool IsMatchPartial(PKM pkm)
{
if (!IsTrainerNameValid(pkm))
return true;
if (!IsNicknameValid(pkm))
return true;
if (ParseSettings.AllowGen1Tradeback)
return false;
if (pkm is not PK1 pk1)
return false;
var req = GetInitialCatchRate();
return req != pk1.Catch_Rate;
}
}
}