Misc tweaks

Add xmldoc, simplify some expressions
This commit is contained in:
Kurt 2022-08-05 11:23:28 -07:00
parent ec45ca1a83
commit 538d651aef
9 changed files with 91 additions and 30 deletions

View file

@ -117,10 +117,10 @@ public readonly record struct EvolutionMethod(EvolutionType Method, ushort Speci
1 or 2 => true,
// Pal Park / PokeTransfer updates Met Level
3 or 4 => pk.Format > origin || pk.Met_Level < lvl,
3 or 4 => pk.Format > origin || lvl > pk.Met_Level,
// 5=>6 and later transfers keep current level
>=5 => lvl >= Level && (!pk.IsNative || pk.Met_Level < lvl),
>=5 => lvl >= Level && (!pk.IsNative || lvl > pk.Met_Level),
_ => false,
};

View file

@ -2,17 +2,27 @@ using System;
namespace PKHeX.Core;
/// <summary>
/// Evolution Reversal logic
/// </summary>
public static class EvolutionReversal
{
/// <summary>
/// Reverses from current state to see what evolutions the <see cref="pk"/> may have existed as.
/// </summary>
/// <param name="lineage">Evolution Method lineage reversal object</param>
/// <param name="species">Species to devolve from</param>
/// <param name="form">Form to devolve from</param>
/// <param name="pk">Entity reference to sanity check evolutions with</param>
/// <param name="levelMin">Minimum level the entity may exist as</param>
/// <param name="levelMax">Maximum the entity may exist as</param>
/// <param name="maxSpeciesID">Maximum species ID that may exist</param>
/// <param name="skipChecks">Option to bypass some evolution criteria</param>
/// <param name="stopSpecies">Species ID that should be the last node, if at all.</param>
/// <returns>Reversed evolution lineage, with the lowest index being the current species-form.</returns>
public static EvoCriteria[] Reverse(this IEvolutionLookup lineage, ushort species, byte form, PKM pk, byte levelMin, byte levelMax, int maxSpeciesID, bool skipChecks, int stopSpecies)
{
var lvl = levelMax;
var first = new EvoCriteria { Species = species, Form = form, LevelMax = lvl };
const int maxEvolutions = 3;
Span<EvoCriteria> evos = stackalloc EvoCriteria[maxEvolutions];
evos[0] = first;
// Sometimes we have to sanitize the inputs.
switch (species)
{
case (int)Species.Silvally:
@ -20,9 +30,16 @@ public static class EvolutionReversal
break;
}
// Store our results -- trim at the end when we place it on the heap.
const int maxEvolutions = 3;
Span<EvoCriteria> evos = stackalloc EvoCriteria[maxEvolutions];
var lvl = levelMax; // highest level, any level-up method will decrease.
evos[0] = new EvoCriteria { Species = species, Form = form, LevelMax = lvl }; // current species-form
// There aren't any circular evolution paths, and all lineages have at most 3 evolutions total.
// There aren't any convergent evolution paths, so only yield the first connection.
int ctr = 1;
int ctr = 1; // count in the 'evos' span
while (species != stopSpecies)
{
var key = EvolutionTree.GetLookupKey(species, form);

View file

@ -7,19 +7,30 @@ namespace PKHeX.Core;
/// </summary>
public struct EvolutionNode
{
internal EvolutionLink First;
/// <summary> First reverse evolution in the node. </summary>
public EvolutionLink First;
/// <summary> Second reverse evolution in the node. Often empty. </summary>
public EvolutionLink Second;
/// <summary>
/// Registers an evolution link into the next empty slot in the node.
/// </summary>
/// <param name="link">Link to register</param>
/// <exception cref="InvalidOperationException"> is thrown if the node is full.</exception>
public void Add(EvolutionLink link)
{
if (First.Species == 0)
if (First.IsEmpty)
First = link;
else if (Second.Species == 0)
else if (Second.IsEmpty)
Second = link;
else
throw new InvalidOperationException($"{nameof(EvolutionNode)} already has two links.");
}
/// <summary>
/// Registers a function that disallows the reverse evolution link from being valid if the <see cref="func"/> is not satisfied.
/// </summary>
/// <param name="func">Function that checks if the link should be allowed as an evolution path.</param>
public void Ban(Func<PKM, bool> func)
{
ref var first = ref First;

View file

@ -45,6 +45,9 @@ public sealed class LegalityAnalysis
/// </remarks>
public IEncounterable EncounterOriginal => Info.EncounterOriginal;
/// <summary>
/// Indicates where the <see cref="Entity"/> originated.
/// </summary>
public readonly SlotOrigin SlotOrigin;
/// <summary>

View file

@ -26,10 +26,10 @@ public abstract class PKM : ISpeciesForm, ITrainerID, IGeneration, IShiny, ILang
protected PKM(byte[] data) => Data = data;
protected PKM(int size) => Data = new byte[size];
public virtual byte[] EncryptedPartyData => Encrypt().AsSpan()[..SIZE_PARTY].ToArray();
public virtual byte[] EncryptedBoxData => Encrypt().AsSpan()[..SIZE_STORED].ToArray();
public virtual byte[] DecryptedPartyData => Write().AsSpan()[..SIZE_PARTY].ToArray();
public virtual byte[] DecryptedBoxData => Write().AsSpan()[..SIZE_STORED].ToArray();
public virtual byte[] EncryptedPartyData => Encrypt().AsSpan(0, SIZE_PARTY).ToArray();
public virtual byte[] EncryptedBoxData => Encrypt().AsSpan(0, SIZE_STORED).ToArray();
public virtual byte[] DecryptedPartyData => Write().AsSpan(0, SIZE_PARTY).ToArray();
public virtual byte[] DecryptedBoxData => Write().AsSpan(0, SIZE_STORED).ToArray();
/// <summary>
/// Rough indication if the data is junk or not.
@ -242,7 +242,6 @@ public abstract class PKM : ISpeciesForm, ITrainerID, IGeneration, IShiny, ILang
public abstract int NickLength { get; }
// Derived
public int SpecForm { get => Species + (Form << 11); set { Species = value & 0x7FF; Form = value >> 11; } }
public virtual int SpriteItem => HeldItem;
public virtual bool IsShiny => TSV == PSV;
public int TrainerID7 { get => (int)((uint)(TID | (SID << 16)) % 1000000); set => SetID7(TrainerSID7, value); }
@ -434,7 +433,7 @@ public abstract class PKM : ISpeciesForm, ITrainerID, IGeneration, IShiny, ILang
public int[] Moves
{
get => new[] { Move1, Move2, Move3, Move4 };
set => SetMoves(value.AsSpan());
set => SetMoves(value);
}
public void PushMove(int move)

View file

@ -61,7 +61,7 @@ public static class SearchUtil
_ => true,
};
public static bool SatisfiesFilterMoves(PKM pk, IEnumerable<int> requiredMoves)
public static bool SatisfiesFilterMoves(PKM pk, IReadOnlyList<int> requiredMoves)
{
foreach (var m in requiredMoves)
{
@ -86,9 +86,12 @@ public static class SearchUtil
{
1 => $"{pk.Species:000}{((PK1) pk).DV16:X4}",
2 => $"{pk.Species:000}{((PK2) pk).DV16:X4}",
_ => $"{pk.Species:000}{pk.PID:X8}{string.Join(" ", pk.IVs)}{pk.Form:00}",
_ => $"{pk.Species:000}{pk.PID:X8}{GetIVString(pk)}{pk.Form:00}",
};
// use a space so we don't merge single digit IVs and potentially get incorrect collisions
private static string GetIVString(PKM pk) => $"{pk.IV_HP} {pk.IV_ATK} {pk.IV_DEF} {pk.IV_SPE} {pk.IV_SPA} {pk.IV_SPD}";
public static string HashByPID(PKM pk) => pk.Format switch
{
1 => $"{((PK1) pk).DV16:X4}",

View file

@ -2,12 +2,15 @@ using System;
namespace PKHeX.Core;
/// <summary>
/// Logic for working with Effort Values
/// </summary>
public static class EffortValues
{
/// <summary>
/// Gets randomized EVs for a given generation format
/// </summary>
/// <param name="evs">Array containing randomized EVs (H/A/B/S/C/D)</param>
/// <param name="evs">Array to store the resulting EVs</param>
/// <param name="generation">Generation specific formatting option</param>
public static void SetRandom(Span<int> evs, int generation)
{
@ -20,23 +23,44 @@ public static class EffortValues
private static void SetRandom252(Span<int> evs, Random rnd)
{
do
// Set random EVs (max 252 per stat) until we run out of EVs.
// The last stat index receives the remaining EVs
const int maxTotal = 510;
const int maxStat = 252;
const int maxStatPlusBias = 300; // weight more towards the high end of received EVs
while (true) // loop until we get a valid set of 6 stats
{
int max = 510;
int remain = maxTotal;
for (int i = 0; i < evs.Length - 1; i++)
max -= evs[i] = (byte)Math.Min(rnd.Next(Math.Min(300, max)), 252);
evs[5] = max;
} while (evs[5] > 252);
{
var max = Math.Min(maxStatPlusBias, remain);
var amount = rnd.Next(0, max);
if (amount > maxStat)
amount = maxStat;
remain -= (evs[i] = (byte)amount);
}
if (remain > maxStat)
continue; // try again! must have had really low rand rolls.
evs[5] = remain;
break; // done!
}
Util.Shuffle(evs, 0, evs.Length, rnd);
}
private static void SetRandom12(Span<int> evs, Random rnd)
{
// In generation 1/2, EVs can be 0-65535.
for (int i = 0; i < evs.Length; i++)
evs[i] = rnd.Next(ushort.MaxValue + 1);
}
/// <summary>
/// Sets the Effort Values to a reasonable max value.
/// </summary>
/// <param name="evs">Array to store the resulting EVs</param>
/// <param name="entity">Entity that will eventually receive the EVs</param>
public static void SetMax(Span<int> evs, PKM entity)
{
if (entity.Format < 3)
@ -63,5 +87,9 @@ public static class EffortValues
evs[i] = ushort.MaxValue;
}
public static void Clear(Span<int> values) => values.Clear();
/// <summary>
/// Sets all the EVs to zero.
/// </summary>
/// <param name="evs">Array to store the resulting EVs</param>
public static void Clear(Span<int> evs) => evs.Clear();
}

View file

@ -53,7 +53,7 @@ public sealed class PersonalInfo2 : PersonalInfo
}
}
// EV Yields are just aliases for base stats in Gen I
// EV Yields are just aliases for base stats in Gen II
public override int EV_HP { get => HP; set { } }
public override int EV_ATK { get => ATK; set { } }
public override int EV_DEF { get => DEF; set { } }

View file

@ -71,7 +71,7 @@ public static class SpriteUtil
{
const int Lugia = (int)Species.Lugia;
if (pk.Species == Lugia) // show XD shadow sprite
img = Spriter.GetSprite(Spriter.ShadowLugia, Lugia, pk.HeldItem, pk.IsEgg, shiny, pk.Format, tweak);
img = Spriter.GetSprite(Spriter.ShadowLugia, Lugia, pk.SpriteItem, pk.IsEgg, shiny, pk.Format, tweak);
GetSpriteGlow(pk, 75, 0, 130, out var pixels, out var baseSprite, true);
var glowImg = ImageUtil.GetBitmap(pixels, baseSprite.Width, baseSprite.Height, baseSprite.PixelFormat);