mirror of
https://github.com/kwsch/PKHeX
synced 2024-11-10 14:44:24 +00:00
Handle "random" AV gains from level up
This commit is contained in:
parent
45af203a26
commit
3dbf46be92
8 changed files with 127 additions and 49 deletions
|
@ -15,8 +15,8 @@ public static class BatchMods
|
|||
new TypeSuggestion<IScaledSizeValue>(nameof(IScaledSizeValue.WeightAbsolute), p => p.ResetWeight()),
|
||||
new TypeSuggestion<IHyperTrain>(nameof(Extensions.HyperTrainClear), p => p.HyperTrainClear()),
|
||||
new TypeSuggestion<IGeoTrack>(nameof(Extensions.ClearGeoLocationData), p => p.ClearGeoLocationData()),
|
||||
new TypeSuggestion<IAwakened>(nameof(Extensions.AwakeningClear), p => p.AwakeningClear()),
|
||||
new TypeSuggestion<IAwakened>(nameof(Extensions.AwakeningMax), p => p.AwakeningMax()),
|
||||
new TypeSuggestion<IAwakened>(nameof(AwakeningUtil.AwakeningClear), p => p.AwakeningClear()),
|
||||
new TypeSuggestion<IAwakened>(nameof(AwakeningUtil.AwakeningMax), p => p.AwakeningMax()),
|
||||
new TypeSuggestion<IGanbaru>(nameof(GanbaruExtensions.ClearGanbaruValues), p => p.ClearGanbaruValues()),
|
||||
new TypeSuggestion<IGanbaru>(nameof(GanbaruExtensions.SetSuggestedGanbaruValues), p => p.SetSuggestedGanbaruValues((PKM)p)),
|
||||
|
||||
|
|
|
@ -153,4 +153,9 @@ public enum CheckIdentifier : byte
|
|||
/// The <see cref="CheckResult"/> pertains to <see cref="PKM.MarkValue"/> values.
|
||||
/// </summary>
|
||||
Marking,
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="CheckResult"/> pertains to the <see cref="PKM"/> <see cref="IAwakened"/> values.
|
||||
/// </summary>
|
||||
AVs,
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#define SUPPRESS
|
||||
#define SUPPRESS
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
@ -229,6 +229,8 @@ public sealed class LegalityAnalysis
|
|||
UpdateChecks();
|
||||
if (Entity.Format >= 8)
|
||||
Transfer.VerifyTransferLegalityG8(this);
|
||||
else if (Entity is PB7)
|
||||
Awakening.Verify(this);
|
||||
}
|
||||
|
||||
private void ParsePK8()
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
namespace PKHeX.Core;
|
||||
namespace PKHeX.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Collection of analyzers that are used for parsing secondary details.
|
||||
|
@ -34,4 +34,5 @@ internal static class LegalityAnalyzers
|
|||
public static readonly TransferVerifier Transfer = new();
|
||||
public static readonly MarkVerifier Mark = new();
|
||||
public static readonly LegendsArceusVerifier Arceus = new();
|
||||
public static readonly AwakenedValueVerifier Awakening = new();
|
||||
}
|
||||
|
|
42
PKHeX.Core/Legality/Verifiers/AwakenedValueVerifier.cs
Normal file
42
PKHeX.Core/Legality/Verifiers/AwakenedValueVerifier.cs
Normal file
|
@ -0,0 +1,42 @@
|
|||
using System;
|
||||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
public sealed class AwakenedValueVerifier : Verifier
|
||||
{
|
||||
protected override CheckIdentifier Identifier => CheckIdentifier.AVs;
|
||||
|
||||
public override void Verify(LegalityAnalysis data)
|
||||
{
|
||||
if (data.Entity is not PB7 pb7)
|
||||
return;
|
||||
|
||||
int sum = pb7.EVTotal;
|
||||
if (sum != 0)
|
||||
data.AddLine(GetInvalid(LegalityCheckStrings.LEffortShouldBeZero));
|
||||
|
||||
if (!pb7.AwakeningAllValid())
|
||||
data.AddLine(GetInvalid(LegalityCheckStrings.LAwakenedCap));
|
||||
|
||||
Span<byte> required = stackalloc byte[6];
|
||||
AwakeningUtil.GetExpectedMinimumAVs(required, pb7);
|
||||
ReadOnlySpan<byte> current = stackalloc byte[6]
|
||||
{
|
||||
pb7.GetAV(0),
|
||||
pb7.GetAV(1),
|
||||
pb7.GetAV(2),
|
||||
pb7.GetAV(4),
|
||||
pb7.GetAV(5),
|
||||
pb7.GetAV(3), // Speed last!
|
||||
};
|
||||
|
||||
for (int i = 0; i < required.Length; i++)
|
||||
{
|
||||
if (current[i] >= required[i])
|
||||
continue;
|
||||
|
||||
data.AddLine(GetInvalid(string.Format(LegalityCheckStrings.LAwakenedShouldBeValue, required[i])));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -13,11 +13,6 @@ public sealed class EffortValueVerifier : Verifier
|
|||
public override void Verify(LegalityAnalysis data)
|
||||
{
|
||||
var pk = data.Entity;
|
||||
if (pk is IAwakened a)
|
||||
{
|
||||
VerifyAwakenedValues(data, a);
|
||||
return;
|
||||
}
|
||||
var enc = data.EncounterMatch;
|
||||
if (pk.IsEgg)
|
||||
{
|
||||
|
@ -65,36 +60,4 @@ public sealed class EffortValueVerifier : Verifier
|
|||
else if (evs[0] != 0 && evs.Count(evs[0]) == evs.Length)
|
||||
data.AddLine(Get(LEffortAllEqual, Severity.Fishy));
|
||||
}
|
||||
|
||||
private void VerifyAwakenedValues(LegalityAnalysis data, IAwakened awakened)
|
||||
{
|
||||
var pk = data.Entity;
|
||||
int sum = pk.EVTotal;
|
||||
if (sum != 0)
|
||||
data.AddLine(GetInvalid(LEffortShouldBeZero));
|
||||
|
||||
if (!awakened.AwakeningAllValid())
|
||||
data.AddLine(GetInvalid(LAwakenedCap));
|
||||
|
||||
var enc = data.EncounterMatch;
|
||||
|
||||
// go park transfers have 2 AVs for all stats.
|
||||
if (enc is EncounterSlot7GO)
|
||||
{
|
||||
Span<byte> avs = stackalloc byte[6];
|
||||
awakened.GetAVs(avs);
|
||||
foreach (var av in avs)
|
||||
{
|
||||
if (av >= 2)
|
||||
continue;
|
||||
|
||||
data.AddLine(GetInvalid(string.Format(LAwakenedShouldBeValue, 2)));
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (awakened.AwakeningSum() == 0 && !enc.IsWithinEncounterRange(pk))
|
||||
data.AddLine(Get(LAwakenedEXPIncreased, Severity.Fishy));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using System;
|
||||
using System;
|
||||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
|
@ -12,7 +12,7 @@ public interface IAwakened
|
|||
byte AV_SPD { get; set; }
|
||||
}
|
||||
|
||||
public static partial class Extensions
|
||||
public static class AwakeningUtil
|
||||
{
|
||||
/// <summary>
|
||||
/// Sums all values.
|
||||
|
@ -47,10 +47,26 @@ public static partial class Extensions
|
|||
/// <param name="max">Maximum value to set</param>
|
||||
public static void AwakeningSetRandom(this IAwakened pk, byte min = 0, int max = Legal.AwakeningMax)
|
||||
{
|
||||
if (pk is not PB7 pb7)
|
||||
return;
|
||||
Span<byte> result = stackalloc byte[6];
|
||||
GetExpectedMinimumAVs(result, pb7);
|
||||
|
||||
var rnd = Util.Rand;
|
||||
int randClamp = max + 1;
|
||||
for (int index = 0; index < 6; index++)
|
||||
pk.SetAV(index, (byte)rnd.Next(min, randClamp));
|
||||
for (int i = 0; i < 6; i++)
|
||||
result[i] = (byte)rnd.Next(result[i], randClamp);
|
||||
AwakeningSetVisual(pb7, result);
|
||||
}
|
||||
|
||||
public static void AwakeningSetVisual(IAwakened pk, Span<byte> result)
|
||||
{
|
||||
pk.AV_HP = result[0];
|
||||
pk.AV_ATK = result[1];
|
||||
pk.AV_DEF = result[2];
|
||||
pk.AV_SPA = result[3];
|
||||
pk.AV_SPD = result[4];
|
||||
pk.AV_SPE = result[5];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -96,7 +112,7 @@ public static partial class Extensions
|
|||
/// </summary>
|
||||
/// <param name="pk">Pokémon to check.</param>
|
||||
/// <param name="index">Index to get</param>
|
||||
public static int GetAV(this IAwakened pk, int index) => index switch
|
||||
public static byte GetAV(this IAwakened pk, int index) => index switch
|
||||
{
|
||||
0 => pk.AV_HP,
|
||||
1 => pk.AV_ATK,
|
||||
|
@ -129,12 +145,14 @@ public static partial class Extensions
|
|||
/// <param name="pk">Retriever for IVs</param>
|
||||
public static void SetSuggestedAwakenedValues(this IAwakened a, PKM pk)
|
||||
{
|
||||
Span<byte> result = stackalloc byte[6];
|
||||
GetExpectedMinimumAVs(result, (PB7)a);
|
||||
a.AV_HP = Legal.AwakeningMax;
|
||||
a.AV_ATK = pk.IV_ATK == 0 ? (byte)0 : Legal.AwakeningMax;
|
||||
a.AV_ATK = pk.IV_ATK == 0 ? result[1] : Legal.AwakeningMax;
|
||||
a.AV_DEF = Legal.AwakeningMax;
|
||||
a.AV_SPE = pk.IV_SPE == 0 ? (byte)0 : Legal.AwakeningMax;
|
||||
a.AV_SPA = Legal.AwakeningMax;
|
||||
a.AV_SPD = Legal.AwakeningMax;
|
||||
a.AV_SPE = pk.IV_SPE == 0 ? result[5] : Legal.AwakeningMax;
|
||||
}
|
||||
|
||||
public static bool IsAwakeningBelow(this IAwakened current, IAwakened initial) => !current.IsAwakeningAboveOrEqual(initial);
|
||||
|
@ -155,4 +173,26 @@ public static partial class Extensions
|
|||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void GetExpectedMinimumAVs(Span<byte> result, PB7 pk)
|
||||
{
|
||||
// go park transfers have 2 AVs for all stats.
|
||||
// leveling up in-game applies 1 AV to a "random" index.
|
||||
if (pk.Version == (int)GameVersion.GO)
|
||||
result.Fill(2);
|
||||
|
||||
var nature = pk.Nature;
|
||||
var character = pk.Characteristic;
|
||||
var ec = pk.EncryptionConstant;
|
||||
var start = pk.Met_Level;
|
||||
var end = pk.CurrentLevel;
|
||||
|
||||
for (int i = start + 1; i <= end; i++)
|
||||
{
|
||||
var lm10 = i % 10;
|
||||
var bits = (ec >> (3 * lm10)) & 7;
|
||||
var index = PB7.GetRandomIndex((int)bits, character, nature);
|
||||
++result[index];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
using static System.Buffers.Binary.BinaryPrimitives;
|
||||
|
@ -585,6 +585,31 @@ public sealed class PB7 : G6PKM, IHyperTrain, IAwakened, IScaledSizeValue, IComb
|
|||
return (byte)Math.Min(255, unsigned);
|
||||
}
|
||||
|
||||
public static int GetRandomIndex(int bits, int characterIndex, int nature)
|
||||
{
|
||||
if (bits is 6 or 7)
|
||||
return GetRandomIndex(characterIndex);
|
||||
if (bits is 0)
|
||||
return 0;
|
||||
Span<sbyte> amps = NatureAmpTable.AsSpan(5 * nature, 5);
|
||||
if (amps[bits - 1] != -1) // not a negative stat
|
||||
return bits;
|
||||
|
||||
// remap a negative stat to positive
|
||||
return 1 + amps.IndexOf((sbyte)1);
|
||||
}
|
||||
|
||||
private static int GetRandomIndex(int characterIndex) => (characterIndex / 5) switch
|
||||
{
|
||||
0 => 0,
|
||||
1 => 1,
|
||||
2 => 2,
|
||||
3 => 5,
|
||||
4 => 3,
|
||||
5 => 4,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(characterIndex)), // never happens, characteristic is always 0-29
|
||||
};
|
||||
|
||||
public PK8 ConvertToPK8()
|
||||
{
|
||||
var pk8 = new PK8
|
||||
|
|
Loading…
Reference in a new issue