mirror of
https://github.com/kwsch/PKHeX
synced 2024-11-10 06:34:19 +00:00
Misc tweaks
Add xmldoc, simplify some expressions
This commit is contained in:
parent
ec45ca1a83
commit
538d651aef
9 changed files with 91 additions and 30 deletions
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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}",
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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 { } }
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue