Tuck event ribbons behind interface

Reduces amount of reflection per legality check (faster checks!), can be
expressed a little clearer now with a bool array loop comparison.

Closes #1061
This commit is contained in:
Kurt 2017-04-15 01:20:29 -07:00
parent 18fb42e86d
commit e8aaf71b4d
11 changed files with 115 additions and 65 deletions

View File

@ -1125,69 +1125,47 @@ private void verifyRibbons()
}
// Check Event Ribbons
var RibbonData = ReflectUtil.getPropertiesStartWithPrefix(pkm.GetType(), "Ribbon");
MysteryGift MatchedGift = EncounterMatch as MysteryGift;
string[] EventRib =
var encounterContent = (EncounterMatch as MysteryGift)?.Content ?? EncounterMatch;
var set1 = pkm as IRibbonSet1;
if (set1 != null)
{
nameof(PK6.RibbonCountry), nameof(PK6.RibbonNational), nameof(PK6.RibbonEarth), nameof(PK6.RibbonWorld), nameof(PK6.RibbonClassic),
nameof(PK6.RibbonPremier), nameof(PK6.RibbonEvent), nameof(PK6.RibbonBirthday), nameof(PK6.RibbonSpecial), nameof(PK6.RibbonSouvenir),
nameof(PK6.RibbonWishing), nameof(PK6.RibbonChampionBattle), nameof(PK6.RibbonChampionRegional), nameof(PK6.RibbonChampionNational), nameof(PK6.RibbonChampionWorld)
};
if (MatchedGift != null) // Wonder Card
{
var mgRibbons = MatchedGift.Format == 4 ? EventRib : ReflectUtil.getPropertiesStartWithPrefix(MatchedGift.Content.GetType(), "Ribbon");
var commonRibbons = mgRibbons.Intersect(RibbonData).ToArray();
var sb = RibbonSetHelper.getRibbonBits(set1);
var enc1 = encounterContent as IRibbonSet1;
var eb = RibbonSetHelper.getRibbonBits(enc1);
foreach (string r in commonRibbons)
if (pkm.Gen3)
eb[0] = sb[0]; // permit Earth Ribbon
if (pkm.Version == 15)
eb[1] = true; // require National Ribbon TODO: shadow pkm only
for (int i = 0; i < sb.Length; i++)
{
bool? pk = ReflectUtil.getBooleanState(pkm, r);
bool? mg = ReflectUtil.getBooleanState(MatchedGift.Content, r);
if (pk != mg) // Mismatch
{
if (pk ?? false)
missingRibbons.Add(r);
else
invalidRibbons.Add(r);
}
}
}
else if (EncounterType == typeof(EncounterLink))
{
// No Event Ribbons except Classic (unless otherwise specified, ie not for Demo)
for (int i = 0; i < EventRib.Length; i++)
{
if (i == 4)
if (sb[i] == eb[i]) // valid
continue;
if (ReflectUtil.getBooleanState(pkm, EventRib[i]) == true)
invalidRibbons.Add(EventRibName[i]);
var list = eb[i] ? missingRibbons : invalidRibbons;
list.Add(RibbonSetHelper.getRibbonNames(set1, i));
}
bool classic = ReflectUtil.getBooleanState(pkm, EventRib[4]) == true;
if (classic ^ ((EncounterLink)EncounterMatch).Classic)
(classic ? invalidRibbons : missingRibbons).Add(EventRibName[4]);
}
else if (EncounterType == typeof(EncounterStatic))
var set2 = pkm as IRibbonSet2;
if (set2 != null)
{
// No Event Ribbons except Wishing (which is only for Magearna)
for (int i = 0; i < EventRib.Length; i++)
var sb = RibbonSetHelper.getRibbonBits(set2);
var enc2 = encounterContent as IRibbonSet2;
var eb = RibbonSetHelper.getRibbonBits(enc2);
if (EncounterMatch is EncounterLink)
eb[0] = true; // require Classic Ribbon
if ((EncounterMatch as EncounterStatic)?.RibbonWishing ?? false)
eb[1] = true; // require Wishing Ribbon
for (int i = 0; i < sb.Length; i++)
{
if (i == 10)
if (sb[i] == eb[i]) // valid
continue;
if (ReflectUtil.getBooleanState(pkm, EventRib[i]) == true)
invalidRibbons.Add(EventRibName[i]);
var list = eb[i] ? missingRibbons : invalidRibbons;
list.Add(RibbonSetHelper.getRibbonNames(set2, i));
}
bool wishing = ReflectUtil.getBooleanState(pkm, EventRib[10]) == true;
if (wishing ^ ((EncounterStatic)EncounterMatch).RibbonWishing)
(wishing ? invalidRibbons : missingRibbons).Add(EventRibName[10]);
}
else // No ribbons
{
for (int i = 0; i < EventRib.Length; i++)
if (ReflectUtil.getBooleanState(pkm, EventRib[i]) == true)
invalidRibbons.Add(EventRibName[i]);
}
// Unobtainable ribbons for Gen Origin
@ -1197,8 +1175,6 @@ private void verifyRibbons()
invalidRibbons.Add(V96); // RSE HoF
if (ReflectUtil.getBooleanState(pkm, nameof(PK3.RibbonArtist)) == true)
invalidRibbons.Add(V97); // RSE Master Rank Portrait
if (ReflectUtil.getBooleanState(pkm, nameof(PK3.RibbonNational)) == true && pkm.Version != (int)GameVersion.CXD)
invalidRibbons.Add(V98); // RSE HoF
}
if (pkm.GenNumber > 4)
{
@ -1225,9 +1201,9 @@ private void verifyRibbons()
string[] result = new string[2];
if (missingRibbons.Count > 0)
result[0] = string.Format(V101, string.Join(", ", missingRibbons));
result[0] = string.Format(V101, string.Join(", ", missingRibbons.Select(z => z.Replace("Ribbon", ""))));
if (invalidRibbons.Count > 0)
result[1] = string.Format(V102, string.Join(", ", invalidRibbons));
result[1] = string.Format(V102, string.Join(", ", invalidRibbons.Select(z => z.Replace("Ribbon", ""))));
AddLine(Severity.Invalid, string.Join(Environment.NewLine, result.Where(s => !string.IsNullOrEmpty(s))), CheckIdentifier.Ribbon);
}
private void verifyAbility()

View File

@ -0,0 +1,73 @@
namespace PKHeX.Core
{
internal interface IRibbonSet1 // Gen3+
{
bool RibbonEarth { get; set; }
bool RibbonNational { get; set; }
bool RibbonCountry { get; set; }
bool RibbonChampionBattle { get; set; }
bool RibbonChampionRegional { get; set; }
bool RibbonChampionNational { get; set; }
}
internal interface IRibbonSet2 // Gen4+
{
bool RibbonClassic { get; set; }
bool RibbonWishing { get; set; }
bool RibbonPremier { get; set; }
bool RibbonEvent { get; set; }
bool RibbonBirthday { get; set; }
bool RibbonSpecial { get; set; }
bool RibbonWorld { get; set; }
bool RibbonChampionWorld { get; set; }
bool RibbonSouvenir { get; set; }
}
internal static class RibbonSetHelper
{
public static readonly string[] RibbonNames1 =
{
nameof(IRibbonSet1.RibbonEarth), nameof(IRibbonSet1.RibbonNational), nameof(IRibbonSet1.RibbonCountry),
nameof(IRibbonSet1.RibbonChampionBattle), nameof(IRibbonSet1.RibbonChampionRegional), nameof(IRibbonSet1.RibbonChampionNational)
};
public static bool[] getRibbonBits(IRibbonSet1 set)
{
if (set == null)
return new bool[6];
return new[]
{
set.RibbonEarth,
set.RibbonNational,
set.RibbonCountry,
set.RibbonChampionBattle,
set.RibbonChampionRegional,
set.RibbonChampionNational,
};
}
public static readonly string[] RibbonNames2 =
{
nameof(IRibbonSet2.RibbonClassic), nameof(IRibbonSet2.RibbonWishing), nameof(IRibbonSet2.RibbonPremier),
nameof(IRibbonSet2.RibbonEvent), nameof(IRibbonSet2.RibbonBirthday), nameof(IRibbonSet2.RibbonSpecial),
nameof(IRibbonSet2.RibbonWorld), nameof(IRibbonSet2.RibbonChampionWorld), nameof(IRibbonSet2.RibbonSouvenir)
};
public static bool[] getRibbonBits(IRibbonSet2 set)
{
if (set == null)
return new bool[9];
return new[]
{
set.RibbonClassic,
set.RibbonWishing,
set.RibbonPremier,
set.RibbonEvent,
set.RibbonBirthday,
set.RibbonSpecial,
set.RibbonWorld,
set.RibbonChampionWorld,
set.RibbonSouvenir,
};
}
public static string getRibbonNames(IRibbonSet1 set, int index) => RibbonNames1[index];
public static string getRibbonNames(IRibbonSet2 set, int index) => RibbonNames2[index];
}
}

View File

@ -3,7 +3,7 @@
namespace PKHeX.Core
{
public sealed class PGF : MysteryGift
public sealed class PGF : MysteryGift, IRibbonSet1, IRibbonSet2
{
public const int Size = 0xCC;
public override int Format => 5;

View File

@ -4,7 +4,7 @@
namespace PKHeX.Core
{
public sealed class WC6 : MysteryGift
public sealed class WC6 : MysteryGift, IRibbonSet1, IRibbonSet2
{
public const int Size = 0x108;
public const int SizeFull = 0x310;

View File

@ -4,7 +4,7 @@
namespace PKHeX.Core
{
public sealed class WC7 : MysteryGift
public sealed class WC7 : MysteryGift, IRibbonSet1, IRibbonSet2
{
public const int Size = 0x108;
public const int SizeFull = 0x310;

View File

@ -167,6 +167,7 @@
<Compile Include="Legality\Structures\EvolutionTree.cs" />
<Compile Include="Legality\Structures\IGeneration.cs" />
<Compile Include="Legality\Structures\IMoveset.cs" />
<Compile Include="Legality\Structures\IRibbonSet.cs" />
<Compile Include="Legality\Structures\Learnset.cs" />
<Compile Include="Legality\Structures\Nature.cs" />
<Compile Include="Legality\Structures\SlotType.cs" />

View File

@ -3,7 +3,7 @@
namespace PKHeX.Core
{
public class PK3 : PKM // 3rd Generation PKM File
public class PK3 : PKM, IRibbonSet1
{
public static readonly byte[] ExtraBytes =
{

View File

@ -3,7 +3,7 @@
namespace PKHeX.Core
{
public class PK4 : PKM // 4th Generation PKM File
public class PK4 : PKM, IRibbonSet1, IRibbonSet2
{
public static readonly byte[] ExtraBytes =
{

View File

@ -3,7 +3,7 @@
namespace PKHeX.Core
{
public class PK5 : PKM // 5th Generation PKM File
public class PK5 : PKM, IRibbonSet1, IRibbonSet2
{
public static readonly byte[] ExtraBytes =
{

View File

@ -3,7 +3,7 @@
namespace PKHeX.Core
{
public class PK6 : PKM
public class PK6 : PKM, IRibbonSet1, IRibbonSet2
{
public static readonly byte[] ExtraBytes =
{

View File

@ -3,7 +3,7 @@
namespace PKHeX.Core
{
public class PK7 : PKM
public class PK7 : PKM, IRibbonSet1, IRibbonSet2
{
public static readonly byte[] ExtraBytes =
{