mirror of
https://github.com/kwsch/PKHeX
synced 2024-11-26 22:10:21 +00:00
Misc tweaks
Add xmldoc Simplify some casts Demote priority of Gen2 event yielding Remove old EncounterMatchUtil code Repoint DateTime.Now to console specific date provider stubs
This commit is contained in:
parent
c7aa497e73
commit
b536388d0d
71 changed files with 376 additions and 212 deletions
|
@ -30,12 +30,12 @@ public sealed class QRPK7 : IEncounterInfo
|
|||
public int Move3_PPUps => Data[0xA];
|
||||
public int Move4_PPUps => Data[0xB];
|
||||
public uint IV32 { get => ReadUInt32LittleEndian(Data.AsSpan(0xC)); set => WriteUInt32LittleEndian(Data.AsSpan(0xC), value); }
|
||||
public int IV_HP { get => (int)(IV32 >> 00) & 0x1F; set => IV32 = (uint)((IV32 & ~(0x1F << 00)) | (uint)((value > 31 ? 31 : value) << 00)); }
|
||||
public int IV_ATK { get => (int)(IV32 >> 05) & 0x1F; set => IV32 = (uint)((IV32 & ~(0x1F << 05)) | (uint)((value > 31 ? 31 : value) << 05)); }
|
||||
public int IV_DEF { get => (int)(IV32 >> 10) & 0x1F; set => IV32 = (uint)((IV32 & ~(0x1F << 10)) | (uint)((value > 31 ? 31 : value) << 10)); }
|
||||
public int IV_SPE { get => (int)(IV32 >> 15) & 0x1F; set => IV32 = (uint)((IV32 & ~(0x1F << 15)) | (uint)((value > 31 ? 31 : value) << 15)); }
|
||||
public int IV_SPA { get => (int)(IV32 >> 20) & 0x1F; set => IV32 = (uint)((IV32 & ~(0x1F << 20)) | (uint)((value > 31 ? 31 : value) << 20)); }
|
||||
public int IV_SPD { get => (int)(IV32 >> 25) & 0x1F; set => IV32 = (uint)((IV32 & ~(0x1F << 25)) | (uint)((value > 31 ? 31 : value) << 25)); }
|
||||
public int IV_HP { get => (int)(IV32 >> 00) & 0x1F; set => IV32 = (IV32 & ~(0x1Fu << 00)) | (uint)((value > 31 ? 31 : value) << 00); }
|
||||
public int IV_ATK { get => (int)(IV32 >> 05) & 0x1F; set => IV32 = (IV32 & ~(0x1Fu << 05)) | (uint)((value > 31 ? 31 : value) << 05); }
|
||||
public int IV_DEF { get => (int)(IV32 >> 10) & 0x1F; set => IV32 = (IV32 & ~(0x1Fu << 10)) | (uint)((value > 31 ? 31 : value) << 10); }
|
||||
public int IV_SPE { get => (int)(IV32 >> 15) & 0x1F; set => IV32 = (IV32 & ~(0x1Fu << 15)) | (uint)((value > 31 ? 31 : value) << 15); }
|
||||
public int IV_SPA { get => (int)(IV32 >> 20) & 0x1F; set => IV32 = (IV32 & ~(0x1Fu << 20)) | (uint)((value > 31 ? 31 : value) << 20); }
|
||||
public int IV_SPD { get => (int)(IV32 >> 25) & 0x1F; set => IV32 = (IV32 & ~(0x1Fu << 25)) | (uint)((value > 31 ? 31 : value) << 25); }
|
||||
public uint PID => ReadUInt32LittleEndian(Data.AsSpan(0x10));
|
||||
public ushort Species => ReadUInt16LittleEndian(Data.AsSpan(0x14));
|
||||
public ushort HeldItem => ReadUInt16LittleEndian(Data.AsSpan(0x16));
|
||||
|
|
|
@ -135,9 +135,9 @@ public sealed class GameDataSource
|
|||
{
|
||||
var languages = new List<ComboItem>(LanguageList);
|
||||
if (gen == 3)
|
||||
languages.RemoveAll(l => l.Value >= (int)LanguageID.Korean);
|
||||
languages.RemoveAll(static l => l.Value >= (int)LanguageID.Korean);
|
||||
else if (gen < 7)
|
||||
languages.RemoveAll(l => l.Value > (int)LanguageID.Korean);
|
||||
languages.RemoveAll(static l => l.Value > (int)LanguageID.Korean);
|
||||
return languages;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -273,22 +273,33 @@ public sealed class MetDataSource
|
|||
BD or SP => Partition2(MetGen8b, IsMetLocation8BDSP),
|
||||
PLA => Partition2(MetGen8a, IsMetLocation8LA),
|
||||
SL or VL => Partition2(MetGen9, IsMetLocation9SV),
|
||||
_ => new List<ComboItem>(GetLocationListModified(version, context)),
|
||||
_ => GetLocationListModified(version, context),
|
||||
};
|
||||
|
||||
static IReadOnlyList<ComboItem> Partition1(IReadOnlyList<ComboItem> list, Func<ushort, bool> criteria)
|
||||
static ComboItem[] Partition1(List<ComboItem> list, Func<ushort, bool> criteria)
|
||||
{
|
||||
var span = CollectionsMarshal.AsSpan(list);
|
||||
var result = new ComboItem[list.Count];
|
||||
return GetOrderedList(list, result, criteria);
|
||||
ReorderList(span, result, criteria);
|
||||
return result;
|
||||
}
|
||||
|
||||
static IReadOnlyList<ComboItem> GetOrderedList(IReadOnlyList<ComboItem> list, ComboItem[] result,
|
||||
Func<ushort, bool> criteria, int start = 0)
|
||||
static ComboItem[] Partition2(List<ComboItem> list, Func<ushort, bool> criteria, int keepFirst = 3)
|
||||
{
|
||||
var span = CollectionsMarshal.AsSpan(list);
|
||||
var result = new ComboItem[span.Length];
|
||||
for (int i = 0; i < keepFirst; i++)
|
||||
result[i] = list[i];
|
||||
ReorderList(span, result, criteria, keepFirst);
|
||||
return result;
|
||||
}
|
||||
|
||||
static void ReorderList(Span<ComboItem> list, Span<ComboItem> result, Func<ushort, bool> criteria, int start = 0)
|
||||
{
|
||||
// store values that match criteria at the next available position of the array
|
||||
// store non-matches starting at the end. reverse before returning
|
||||
int end = list.Count - 1;
|
||||
for (var index = start; index < list.Count; index++)
|
||||
int end = list.Length - 1;
|
||||
for (var index = start; index < list.Length; index++)
|
||||
{
|
||||
var item = list[index];
|
||||
if (criteria((ushort)item.Value))
|
||||
|
@ -297,18 +308,8 @@ public sealed class MetDataSource
|
|||
result[end--] = item;
|
||||
}
|
||||
|
||||
// since the non-matches are reversed in order, we swap them back since we know where they end up at.
|
||||
Array.Reverse(result, start, list.Count - start);
|
||||
return result;
|
||||
}
|
||||
|
||||
static IReadOnlyList<ComboItem> Partition2(IReadOnlyList<ComboItem> list, Func<ushort, bool> criteria,
|
||||
int keepFirst = 3)
|
||||
{
|
||||
var result = new ComboItem[list.Count];
|
||||
for (int i = 0; i < keepFirst; i++)
|
||||
result[i] = list[i];
|
||||
return GetOrderedList(list, result, criteria, keepFirst);
|
||||
// since the non-matches are reversed in order, we reverse that section.
|
||||
result[start..].Reverse();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ namespace PKHeX.Core;
|
|||
public static class LocationsHOME
|
||||
{
|
||||
// 60000 - (version - PLA)
|
||||
private const int RemapCount = 5;
|
||||
private const int RemapCount = 5; // Count of future game version IDs that can transfer back into SW/SH.
|
||||
public const ushort SHVL = 59996; // VL traded to (SW)SH
|
||||
public const ushort SWSL = 59997; // SL traded to SW(SH)
|
||||
public const ushort SHSP = 59998; // SP traded to (SW)SH
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System;
|
||||
using System.Buffers;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
|
@ -59,7 +60,13 @@ public static class BulkGenerator
|
|||
template.Form = form;
|
||||
template.Gender = template.GetSaneGender();
|
||||
|
||||
var f = EncounterMovesetGenerator.GeneratePKMs(template, tr, template.Moves).FirstOrDefault();
|
||||
var moves = ArrayPool<ushort>.Shared.Rent(4);
|
||||
var memory = moves.AsMemory(0, 4);
|
||||
var span = memory.Span;
|
||||
template.GetMoves(span);
|
||||
var f = EncounterMovesetGenerator.GeneratePKMs(template, tr, memory).FirstOrDefault();
|
||||
span.Clear();
|
||||
ArrayPool<ushort>.Shared.Return(moves);
|
||||
if (f == null)
|
||||
return null;
|
||||
|
||||
|
|
|
@ -61,7 +61,7 @@ internal static class Encounters2
|
|||
new(223, 40, GS) { Location = 039 }, // Remoraid Swarm @ Route 44 (Super Rod)
|
||||
|
||||
// Roamer
|
||||
new(245, 40, GS) { Location = 002 }, // Suicune
|
||||
new(245, 40, GS) { Location = 002 }, // Suicune
|
||||
};
|
||||
|
||||
public static readonly EncounterStatic2[] StaticGD =
|
||||
|
|
|
@ -167,23 +167,23 @@ public static class EncounterFinder
|
|||
LearnVerifier.Verify(info.Moves, pk, info.EncounterMatch, info.EvoChainsAllGens);
|
||||
}
|
||||
|
||||
private static string GetHintWhyNotFound(PKM pk, int gen)
|
||||
private static string GetHintWhyNotFound(PKM pk, int generation)
|
||||
{
|
||||
if (WasGiftEgg(pk, gen, (ushort)pk.Egg_Location))
|
||||
if (WasGiftEgg(pk, generation, (ushort)pk.Egg_Location))
|
||||
return LEncGift;
|
||||
if (WasEventEgg(pk, gen))
|
||||
if (WasEventEgg(pk, generation))
|
||||
return LEncGiftEggEvent;
|
||||
if (WasEvent(pk, gen))
|
||||
if (WasEvent(pk, generation))
|
||||
return LEncGiftNotFound;
|
||||
return LEncInvalid;
|
||||
}
|
||||
|
||||
private static bool WasGiftEgg(PKM pk, int gen, ushort loc) => !pk.FatefulEncounter && gen switch
|
||||
private static bool WasGiftEgg(PKM pk, int generation, ushort eggLocation) => !pk.FatefulEncounter && generation switch
|
||||
{
|
||||
3 => pk.IsEgg && (byte)pk.Met_Location == 253, // Gift Egg, indistinguishable from normal eggs after hatch
|
||||
4 => (uint)(loc - 2009) <= (2014 - 2009) || (pk.Format != 4 && (loc == Locations.Faraway4 && pk.HGSS)),
|
||||
5 => loc is Locations.Breeder5,
|
||||
_ => loc is Locations.Breeder6,
|
||||
4 => eggLocation - 2009u <= (2014 - 2009) || (pk.Format != 4 && (eggLocation == Locations.Faraway4 && pk.HGSS)),
|
||||
5 => eggLocation is Locations.Breeder5,
|
||||
_ => eggLocation is Locations.Breeder6,
|
||||
};
|
||||
|
||||
private static bool WasEventEgg(PKM pk, int gen) => gen switch
|
||||
|
|
|
@ -4,6 +4,9 @@ using System.Collections.Generic;
|
|||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Iterates to find possible encounters for <see cref="GameVersion.Gen1"/> encounters.
|
||||
/// </summary>
|
||||
public record struct EncounterPossible1(EvoCriteria[] Chain, EncounterTypeGroup Flags, GameVersion Version) : IEnumerator<IEncounterable>
|
||||
{
|
||||
public IEncounterable Current { get; private set; }
|
||||
|
|
|
@ -4,6 +4,9 @@ using System.Collections.Generic;
|
|||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Iterates to find possible encounters for <see cref="GameVersion.Gen2"/> encounters.
|
||||
/// </summary>
|
||||
public record struct EncounterPossible2(EvoCriteria[] Chain, EncounterTypeGroup Flags, GameVersion Version, PKM Entity) : IEnumerator<IEncounterable>
|
||||
{
|
||||
public IEncounterable Current { get; private set; }
|
||||
|
|
|
@ -4,6 +4,9 @@ using System.Collections.Generic;
|
|||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Iterates to find possible encounters for <see cref="GameVersion.Gen3"/> encounters.
|
||||
/// </summary>
|
||||
public record struct EncounterPossible3(EvoCriteria[] Chain, EncounterTypeGroup Flags, GameVersion Version) : IEnumerator<IEncounterable>
|
||||
{
|
||||
public IEncounterable Current { get; private set; }
|
||||
|
|
|
@ -4,6 +4,9 @@ using System.Collections.Generic;
|
|||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Iterates to find possible encounters for <see cref="GameVersion.CXD"/> encounters.
|
||||
/// </summary>
|
||||
public record struct EncounterPossible3GC(EvoCriteria[] Chain, EncounterTypeGroup Flags) : IEnumerator<IEncounterable>
|
||||
{
|
||||
public IEncounterable Current { get; private set; }
|
||||
|
|
|
@ -4,6 +4,9 @@ using System.Collections.Generic;
|
|||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Iterates to find possible encounters for <see cref="GameVersion.Gen4"/> encounters.
|
||||
/// </summary>
|
||||
public record struct EncounterPossible4(EvoCriteria[] Chain, EncounterTypeGroup Flags, GameVersion Version) : IEnumerator<IEncounterable>
|
||||
{
|
||||
public IEncounterable Current { get; private set; }
|
||||
|
|
|
@ -4,6 +4,9 @@ using System.Collections.Generic;
|
|||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Iterates to find possible encounters for <see cref="GameVersion.Gen5"/> encounters.
|
||||
/// </summary>
|
||||
public record struct EncounterPossible5(EvoCriteria[] Chain, EncounterTypeGroup Flags, GameVersion Version) : IEnumerator<IEncounterable>
|
||||
{
|
||||
public IEncounterable Current { get; private set; }
|
||||
|
|
|
@ -4,6 +4,9 @@ using System.Collections.Generic;
|
|||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Iterates to find possible encounters for <see cref="GameVersion.Gen6"/> encounters.
|
||||
/// </summary>
|
||||
public record struct EncounterPossible6(EvoCriteria[] Chain, EncounterTypeGroup Flags, GameVersion Version) : IEnumerator<IEncounterable>
|
||||
{
|
||||
public IEncounterable Current { get; private set; }
|
||||
|
|
|
@ -4,6 +4,9 @@ using System.Collections.Generic;
|
|||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Iterates to find possible encounters for <see cref="GameVersion.Gen7"/> encounters.
|
||||
/// </summary>
|
||||
public record struct EncounterPossible7(EvoCriteria[] Chain, EncounterTypeGroup Flags, GameVersion Version) : IEnumerator<IEncounterable>
|
||||
{
|
||||
public IEncounterable Current { get; private set; }
|
||||
|
|
|
@ -4,6 +4,9 @@ using System.Collections.Generic;
|
|||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Iterates to find possible encounters for <see cref="GameVersion.GG"/> encounters.
|
||||
/// </summary>
|
||||
public record struct EncounterPossible7GG(EvoCriteria[] Chain, EncounterTypeGroup Flags, GameVersion Version) : IEnumerator<IEncounterable>
|
||||
{
|
||||
public IEncounterable Current { get; private set; }
|
||||
|
|
|
@ -4,6 +4,9 @@ using System.Collections.Generic;
|
|||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Iterates to find possible encounters for <see cref="GameVersion.GO"/> encounters from LGP/E's GO Park.
|
||||
/// </summary>
|
||||
public record struct EncounterPossible7GO(EvoCriteria[] Chain, EncounterTypeGroup Flags) : IEnumerator<IEncounterable>
|
||||
{
|
||||
public IEncounterable Current { get; private set; }
|
||||
|
|
|
@ -4,6 +4,9 @@ using System.Collections.Generic;
|
|||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Iterates to find possible encounters for <see cref="GameVersion.SWSH"/> encounters.
|
||||
/// </summary>
|
||||
public record struct EncounterPossible8(EvoCriteria[] Chain, EncounterTypeGroup Flags, GameVersion Version) : IEnumerator<IEncounterable>
|
||||
{
|
||||
public IEncounterable Current { get; private set; }
|
||||
|
|
|
@ -4,6 +4,9 @@ using System.Collections.Generic;
|
|||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Iterates to find possible encounters for <see cref="GameVersion.GO"/> encounters.
|
||||
/// </summary>
|
||||
public record struct EncounterPossible8GO(EvoCriteria[] Chain, EncounterTypeGroup Flags) : IEnumerator<IEncounterable>
|
||||
{
|
||||
public IEncounterable Current { get; private set; }
|
||||
|
|
|
@ -4,6 +4,9 @@ using System.Collections.Generic;
|
|||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Iterates to find possible encounters for <see cref="GameVersion.PLA"/> encounters.
|
||||
/// </summary>
|
||||
public record struct EncounterPossible8a(EvoCriteria[] Chain, EncounterTypeGroup Flags) : IEnumerator<IEncounterable>
|
||||
{
|
||||
public IEncounterable Current { get; private set; }
|
||||
|
|
|
@ -4,6 +4,9 @@ using System.Collections.Generic;
|
|||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Iterates to find possible encounters for <see cref="GameVersion.BDSP"/> encounters.
|
||||
/// </summary>
|
||||
public record struct EncounterPossible8b(EvoCriteria[] Chain, EncounterTypeGroup Flags, GameVersion Version) : IEnumerator<IEncounterable>
|
||||
{
|
||||
public IEncounterable Current { get; private set; }
|
||||
|
|
|
@ -4,6 +4,9 @@ using System.Collections.Generic;
|
|||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Iterates to find possible encounters for <see cref="GameVersion.SV"/> encounters.
|
||||
/// </summary>
|
||||
public record struct EncounterPossible9(EvoCriteria[] Chain, EncounterTypeGroup Flags, GameVersion Version) : IEnumerator<IEncounterable>
|
||||
{
|
||||
public IEncounterable Current { get; private set; }
|
||||
|
|
|
@ -5,6 +5,9 @@ using System.Diagnostics;
|
|||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Iterates to find potentially matched encounters for <see cref="GameVersion.BDSP"/> encounters while in the <see cref="PK8"/> format.
|
||||
/// </summary>
|
||||
public record struct EncounterEnumerator8bSWSH(PKM Entity, EvoCriteria[] Chain, GameVersion Version) : IEnumerator<MatchedEncounter<IEncounterable>>
|
||||
{
|
||||
private IEncounterable? Deferred;
|
||||
|
|
|
@ -4,6 +4,9 @@ using System.Collections.Generic;
|
|||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Iterates to find potentially matched encounters for <see cref="GameVersion.SV"/> encounters while in the <see cref="PK8"/> format.
|
||||
/// </summary>
|
||||
public record struct EncounterEnumerator9SWSH(PKM Entity, EvoCriteria[] Chain, GameVersion Version) : IEnumerator<MatchedEncounter<IEncounterable>>
|
||||
{
|
||||
private IEncounterable? Deferred;
|
||||
|
|
|
@ -4,6 +4,9 @@ using System.Collections.Generic;
|
|||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Iterates to find potentially matched encounters for <see cref="GameVersion.Gen1"/>.
|
||||
/// </summary>
|
||||
public record struct EncounterEnumerator1(PKM Entity, EvoCriteria[] Chain) : IEnumerator<MatchedEncounter<IEncounterable>>
|
||||
{
|
||||
private IEncounterable? Deferred;
|
||||
|
|
|
@ -4,6 +4,9 @@ using System.Collections.Generic;
|
|||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Iterates to find potentially matched encounters for <see cref="GameVersion.Gen2"/>.
|
||||
/// </summary>
|
||||
public record struct EncounterEnumerator2 : IEnumerator<MatchedEncounter<IEncounterable>>
|
||||
{
|
||||
private IEncounterable? Deferred;
|
||||
|
@ -79,25 +82,7 @@ public record struct EncounterEnumerator2 : IEnumerator<MatchedEncounter<IEncoun
|
|||
case YieldState.Start:
|
||||
if (Chain.Length == 0)
|
||||
break;
|
||||
goto case YieldState.EventStart;
|
||||
|
||||
case YieldState.EventStart:
|
||||
if (Entity.Korean)
|
||||
{ State = YieldState.Trade; goto case YieldState.Trade; }
|
||||
if (ParseSettings.AllowGBVirtualConsole3DS)
|
||||
{ State = YieldState.EventVC; goto case YieldState.EventVC; }
|
||||
if (ParseSettings.AllowGBEraEvents)
|
||||
{ State = YieldState.EventGB; goto case YieldState.EventGB; }
|
||||
throw new InvalidOperationException("No events allowed");
|
||||
case YieldState.EventVC:
|
||||
State = YieldState.Trade;
|
||||
if (IsMatch(Encounters2.CelebiVC))
|
||||
return SetCurrent(Encounters2.CelebiVC);
|
||||
goto case YieldState.Trade;
|
||||
case YieldState.EventGB:
|
||||
if (TryGetNext(Encounters2GBEra.StaticEventsGB))
|
||||
return true;
|
||||
Index = 0; State = YieldState.Trade; goto case YieldState.Trade;
|
||||
State = YieldState.Trade; goto case YieldState.Trade;
|
||||
|
||||
case YieldState.Trade:
|
||||
if (TryGetNext(Encounters2.TradeGift_GSC))
|
||||
|
@ -170,7 +155,25 @@ public record struct EncounterEnumerator2 : IEnumerator<MatchedEncounter<IEncoun
|
|||
return true;
|
||||
Index = 0; goto case YieldState.SlotEnd;
|
||||
case YieldState.SlotEnd:
|
||||
goto case YieldState.EventStart;
|
||||
|
||||
case YieldState.EventStart:
|
||||
if (Entity.Korean)
|
||||
{ State = YieldState.Fallback; goto case YieldState.Fallback; }
|
||||
if (ParseSettings.AllowGBVirtualConsole3DS)
|
||||
{ State = YieldState.EventVC; goto case YieldState.EventVC; }
|
||||
if (ParseSettings.AllowGBEraEvents)
|
||||
{ State = YieldState.EventGB; goto case YieldState.EventGB; }
|
||||
throw new InvalidOperationException("No events allowed");
|
||||
case YieldState.EventVC:
|
||||
State = YieldState.Fallback;
|
||||
if (IsMatch(Encounters2.CelebiVC))
|
||||
return SetCurrent(Encounters2.CelebiVC);
|
||||
goto case YieldState.Fallback;
|
||||
case YieldState.EventGB:
|
||||
if (TryGetNext(Encounters2GBEra.StaticEventsGB))
|
||||
return true;
|
||||
State = YieldState.Fallback; goto case YieldState.Fallback;
|
||||
|
||||
case YieldState.Fallback:
|
||||
State = YieldState.End;
|
||||
|
|
|
@ -4,6 +4,9 @@ using System.Collections.Generic;
|
|||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Iterates to find potentially matched encounters for <see cref="GameVersion.Gen3"/>.
|
||||
/// </summary>
|
||||
public record struct EncounterEnumerator3(PKM Entity, EvoCriteria[] Chain, GameVersion Version) : IEnumerator<MatchedEncounter<IEncounterable>>
|
||||
{
|
||||
private IEncounterable? Deferred;
|
||||
|
|
|
@ -4,6 +4,9 @@ using System.Collections.Generic;
|
|||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Iterates to find potentially matched encounters for <see cref="GameVersion.CXD"/>.
|
||||
/// </summary>
|
||||
public record struct EncounterEnumerator3GC(PKM Entity, EvoCriteria[] Chain) : IEnumerator<MatchedEncounter<IEncounterable>>
|
||||
{
|
||||
private IEncounterable? Deferred;
|
||||
|
|
|
@ -4,6 +4,9 @@ using System.Collections.Generic;
|
|||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Iterates to find potentially matched encounters for <see cref="GameVersion.Gen4"/>.
|
||||
/// </summary>
|
||||
public record struct EncounterEnumerator4(PKM Entity, EvoCriteria[] Chain, GameVersion Version) : IEnumerator<MatchedEncounter<IEncounterable>>
|
||||
{
|
||||
private IEncounterable? Deferred;
|
||||
|
|
|
@ -4,6 +4,9 @@ using System.Collections.Generic;
|
|||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Iterates to find potentially matched encounters for <see cref="GameVersion.Gen5"/>.
|
||||
/// </summary>
|
||||
public record struct EncounterEnumerator5(PKM Entity, EvoCriteria[] Chain, GameVersion Version) : IEnumerator<MatchedEncounter<IEncounterable>>
|
||||
{
|
||||
private IEncounterable? Deferred;
|
||||
|
|
|
@ -4,6 +4,9 @@ using System.Collections.Generic;
|
|||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Iterates to find potentially matched encounters for <see cref="GameVersion.Gen6"/>.
|
||||
/// </summary>
|
||||
public record struct EncounterEnumerator6(PKM Entity, EvoCriteria[] Chain, GameVersion Version) : IEnumerator<MatchedEncounter<IEncounterable>>
|
||||
{
|
||||
private IEncounterable? Deferred;
|
||||
|
|
|
@ -4,6 +4,9 @@ using System.Collections.Generic;
|
|||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Iterates to find potentially matched encounters for <see cref="GameVersion.Gen7"/>.
|
||||
/// </summary>
|
||||
public record struct EncounterEnumerator7(PKM Entity, EvoCriteria[] Chain, GameVersion Version) : IEnumerator<MatchedEncounter<IEncounterable>>
|
||||
{
|
||||
private IEncounterable? Deferred;
|
||||
|
|
|
@ -4,6 +4,9 @@ using System.Collections.Generic;
|
|||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Iterates to find potentially matched encounters for <see cref="GameVersion.GG"/>.
|
||||
/// </summary>
|
||||
public record struct EncounterEnumerator7GG(PKM Entity, EvoCriteria[] Chain, GameVersion Version) : IEnumerator<MatchedEncounter<IEncounterable>>
|
||||
{
|
||||
private IEncounterable? Deferred;
|
||||
|
|
|
@ -4,6 +4,9 @@ using System.Collections.Generic;
|
|||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Iterates to find potentially matched encounters for <see cref="GameVersion.GG"/> encounters from GO Park.
|
||||
/// </summary>
|
||||
public record struct EncounterEnumerator7GO(PKM Entity, EvoCriteria[] Chain) : IEnumerator<MatchedEncounter<IEncounterable>>
|
||||
{
|
||||
private IEncounterable? Deferred;
|
||||
|
|
|
@ -4,6 +4,9 @@ using System.Collections.Generic;
|
|||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Iterates to find potentially matched encounters for <see cref="GameVersion.SWSH"/>.
|
||||
/// </summary>
|
||||
public record struct EncounterEnumerator8(PKM Entity, EvoCriteria[] Chain, GameVersion Version) : IEnumerator<MatchedEncounter<IEncounterable>>
|
||||
{
|
||||
private IEncounterable? Deferred;
|
||||
|
|
|
@ -4,6 +4,9 @@ using System.Collections.Generic;
|
|||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Iterates to find potentially matched encounters for <see cref="GameVersion.GO"/>.
|
||||
/// </summary>
|
||||
public record struct EncounterEnumerator8GO(PKM Entity, EvoCriteria[] Chain) : IEnumerator<MatchedEncounter<IEncounterable>>
|
||||
{
|
||||
private IEncounterable? Deferred;
|
||||
|
|
|
@ -4,6 +4,9 @@ using System.Collections.Generic;
|
|||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Iterates to find potentially matched encounters for <see cref="GameVersion.PLA"/>.
|
||||
/// </summary>
|
||||
public record struct EncounterEnumerator8a(PKM Entity, EvoCriteria[] Chain) : IEnumerator<MatchedEncounter<IEncounterable>>
|
||||
{
|
||||
private IEncounterable? Deferred;
|
||||
|
|
|
@ -5,6 +5,9 @@ using System.Diagnostics;
|
|||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Iterates to find potentially matched encounters for <see cref="GameVersion.BDSP"/>.
|
||||
/// </summary>
|
||||
public record struct EncounterEnumerator8b(PKM Entity, EvoCriteria[] Chain, GameVersion Version) : IEnumerator<MatchedEncounter<IEncounterable>>
|
||||
{
|
||||
private IEncounterable? Deferred;
|
||||
|
|
|
@ -4,6 +4,9 @@ using System.Collections.Generic;
|
|||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Iterates to find potentially matched encounters for <see cref="GameVersion.SV"/>.
|
||||
/// </summary>
|
||||
public record struct EncounterEnumerator9(PKM Entity, EvoCriteria[] Chain, GameVersion Version) : IEnumerator<MatchedEncounter<IEncounterable>>
|
||||
{
|
||||
private IEncounterable? Deferred;
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
namespace PKHeX.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Tuple of matched encounter info.
|
||||
/// </summary>
|
||||
public readonly record struct MatchedEncounter<T>(T Encounter, EncounterMatchRating Rating);
|
|
@ -1,6 +1,3 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
/// <summary>
|
||||
|
@ -23,58 +20,3 @@ public enum EncounterMatchRating : ushort
|
|||
/// <summary> Unused -- only used as an initial "max" value that anything else will be more suitable of a match. </summary>
|
||||
MaxNotMatch,
|
||||
}
|
||||
|
||||
public readonly record struct MatchedEncounter<T>(T Encounter, EncounterMatchRating Rating);
|
||||
|
||||
public static class EncounterMatchUtil
|
||||
{
|
||||
public static EncounterEnumerator<T> Enumerate<T>(this IReadOnlyList<T> encounters, EvoCriteria[] chain, PKM pk)
|
||||
where T : IEncounterMatch, IEncounterable
|
||||
{
|
||||
return new EncounterEnumerator<T>(encounters, chain, pk);
|
||||
}
|
||||
|
||||
public struct EncounterEnumerator<T> : IEnumerator<MatchedEncounter<T>> where T : IEncounterMatch, IEncounterable
|
||||
{
|
||||
private readonly IReadOnlyList<T> _encounters;
|
||||
private readonly EvoCriteria[] _chain;
|
||||
private int _index = 0;
|
||||
private readonly PKM _pk;
|
||||
|
||||
public EncounterEnumerator(IReadOnlyList<T> encounters, EvoCriteria[] chain, PKM pk)
|
||||
{
|
||||
_encounters = encounters;
|
||||
_chain = chain;
|
||||
_pk = pk;
|
||||
}
|
||||
|
||||
public MatchedEncounter<T> Current { get; private set; } = default!;
|
||||
readonly object IEnumerator.Current => Current;
|
||||
|
||||
public bool MoveNext()
|
||||
{
|
||||
for (; _index < _encounters.Count;)
|
||||
{
|
||||
var enc = _encounters[_index++];
|
||||
foreach (var evo in _chain)
|
||||
{
|
||||
if (enc.Species != evo.Species)
|
||||
continue;
|
||||
|
||||
var exact = enc.IsMatchExact(_pk, evo);
|
||||
if (!exact)
|
||||
break;
|
||||
|
||||
Current = new(enc, enc.GetMatchRating(_pk));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void Reset() => _index = 0;
|
||||
public readonly void Dispose() { }
|
||||
public readonly IEnumerator<MatchedEncounter<T>> GetEnumerator() => this;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,7 +20,14 @@ public interface IMagnetStatic
|
|||
/// <summary> Count of slots in the parent area that can be yielded by <see cref="Ability.MagnetPull"/> </summary>
|
||||
byte MagnetPullCount { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Indicates if the slot can be yielded by <see cref="Ability.Static"/>.
|
||||
/// </summary>
|
||||
bool IsStaticSlot => StaticCount != 0 && StaticIndex != byte.MaxValue;
|
||||
|
||||
/// <summary>
|
||||
/// Indicates if the slot can be yielded by <see cref="Ability.MagnetPull"/>.
|
||||
/// </summary>
|
||||
bool IsMagnetSlot => MagnetPullCount != 0 && MagnetPullIndex != byte.MaxValue;
|
||||
|
||||
bool IsMatchStatic(int index, int count) => index == StaticIndex && count == StaticCount;
|
||||
|
|
|
@ -12,7 +12,7 @@ public static class EggHatchLocation5
|
|||
|
||||
public static bool IsValidMet5(int location, GameVersion game)
|
||||
{
|
||||
var shift = (uint)((int)game - (int)W);
|
||||
var shift = (uint)(game - W);
|
||||
if (shift >= 4)
|
||||
return false;
|
||||
|
||||
|
|
|
@ -24,8 +24,12 @@ public static class MoveBreed4
|
|||
if (count == -1)
|
||||
count = moves.Length;
|
||||
|
||||
var learn = GameData.GetLearnSource(version);
|
||||
var learnset = learn.GetLearnset(species, 0);
|
||||
var learnset = version switch
|
||||
{
|
||||
HG or SS => LearnSource4HGSS.Instance.GetLearnset(species, 0),
|
||||
D or P => LearnSource4DP.Instance.GetLearnset(species, 0),
|
||||
_ => LearnSource4Pt.Instance.GetLearnset(species, 0),
|
||||
};
|
||||
var table = version switch
|
||||
{
|
||||
HG or SS => PersonalTable.HGSS,
|
||||
|
|
|
@ -22,8 +22,11 @@ public static class MoveBreed5
|
|||
if (count == -1)
|
||||
count = moves.Length;
|
||||
|
||||
var learn = GameData.GetLearnSource(version);
|
||||
var learnset = learn.GetLearnset(species, 0);
|
||||
var learnset = version switch
|
||||
{
|
||||
GameVersion.B or GameVersion.W => LearnSource5BW.Instance.GetLearnset(species, 0),
|
||||
_ => LearnSource5B2W2.Instance.GetLearnset(species, 0),
|
||||
};
|
||||
IPersonalInfoTM pi = version switch
|
||||
{
|
||||
GameVersion.B or GameVersion.W => PersonalTable.BW[species],
|
||||
|
|
|
@ -9,6 +9,16 @@ public static class Tera9RNG
|
|||
{
|
||||
private const uint TeraTypeCount = 18;
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the <see cref="ITeraType.TeraTypeOriginal"/> matches the specification of the <see cref="gem"/> value.
|
||||
/// </summary>
|
||||
/// <param name="seed">Seed used to generate the Tera Type</param>
|
||||
/// <param name="gem">Encounter specified Gem Type</param>
|
||||
/// <param name="species">Encounter Species</param>
|
||||
/// <param name="form">Encounter Form</param>
|
||||
/// <param name="original">Original Tera Type from the Entity</param>
|
||||
/// <returns>True if the Tera Type matches the RNG and specification</returns>
|
||||
/// <exception cref="ArgumentOutOfRangeException"></exception>
|
||||
public static bool IsMatchTeraType(in uint seed, in GemType gem, in ushort species, in byte form, in byte original)
|
||||
{
|
||||
if (gem.IsSpecified(out var type))
|
||||
|
@ -43,6 +53,14 @@ public static class Tera9RNG
|
|||
throw new ArgumentOutOfRangeException(nameof(gem), gem, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the expected Tera Type from the Personal Info and RNG seed.
|
||||
/// </summary>
|
||||
/// <param name="seed">Seed used to generate the Tera Type</param>
|
||||
/// <param name="gem">Encounter specified Gem Type</param>
|
||||
/// <param name="species">Encounter Species</param>
|
||||
/// <param name="form">Encounter Form</param>
|
||||
/// <exception cref="ArgumentOutOfRangeException"></exception>
|
||||
public static byte GetTeraType(in ulong seed, GemType gem, in ushort species, in byte form)
|
||||
{
|
||||
if (gem.IsSpecified(out var type))
|
||||
|
@ -61,6 +79,9 @@ public static class Tera9RNG
|
|||
throw new ArgumentOutOfRangeException(nameof(gem), gem, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the original Tera Type matches either of the Personal Info types.
|
||||
/// </summary>
|
||||
private static bool IsMatchType(IPersonalType pi, in byte original) => original == pi.Type1 || original == pi.Type2;
|
||||
|
||||
public static bool IsMatchTeraTypePersonalEgg(in ushort species, in byte form, in byte original) =>
|
||||
|
@ -68,7 +89,16 @@ public static class Tera9RNG
|
|||
? IsMatchTeraTypePersonalAnyForm(species, original)
|
||||
: IsMatchTeraTypePersonal(species, form, original);
|
||||
|
||||
/// <inheritdoc cref="IsMatchType"/>
|
||||
public static bool IsMatchTeraTypePersonal(in ushort species, in byte form, in byte original) => IsMatchType(PersonalTable.SV[species, form], original);
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the original Tera Type matches any of the Personal Info types for any form it may change into.
|
||||
/// </summary>
|
||||
/// <remarks>Only enter this method if it is permitted to change into all forms.</remarks>
|
||||
/// <param name="species">Encounter Species</param>
|
||||
/// <param name="original">Entity's original Tera Type</param>
|
||||
/// <returns>True if the Tera Type matches any of the Personal Info types</returns>
|
||||
public static bool IsMatchTeraTypePersonalAnyForm(in ushort species, in byte original)
|
||||
{
|
||||
var pt = PersonalTable.SV;
|
||||
|
@ -85,18 +115,27 @@ public static class Tera9RNG
|
|||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the original Tera Type matches the Personal Info type for the specified form.
|
||||
/// </summary>
|
||||
/// <remarks>Used for HOME imports into <see cref="GameVersion.SV"/>.</remarks>
|
||||
/// <param name="pi">Arrival Personal Info</param>
|
||||
/// <param name="original">Entity's original Tera Type</param>
|
||||
/// <returns>True if the Tera Type matches the expected Personal Info type</returns>
|
||||
private static bool IsMatchTeraTypeImport(PersonalInfo9SV pi, in byte original)
|
||||
{
|
||||
var import = TeraTypeUtil.GetTeraTypeImport(pi.Type1, pi.Type2);
|
||||
return (MoveType)original == import;
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="IsMatchTeraTypeImport"/>
|
||||
public static bool IsMatchTeraTypePersonalImport(in ushort species, in byte form, in byte original)
|
||||
{
|
||||
var pi = PersonalTable.SV[species, form];
|
||||
return IsMatchTeraTypeImport(pi, original);
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="IsMatchTeraTypeImport"/>
|
||||
public static bool IsMatchTeraTypePersonalAnyFormImport(in ushort species, in byte original)
|
||||
{
|
||||
var pt = PersonalTable.SV;
|
||||
|
@ -113,12 +152,29 @@ public static class Tera9RNG
|
|||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the expected Tera Type from the Personal Info and pivot.
|
||||
/// </summary>
|
||||
/// <param name="species">Encounter Species</param>
|
||||
/// <param name="form">Encounter Form</param>
|
||||
/// <param name="pivot">Random pivot to determine which Personal Info type to use</param>
|
||||
/// <returns>Expected Tera Type</returns>
|
||||
public static byte GetTeraTypeFromPersonal(in ushort species, in byte form, in ulong pivot)
|
||||
{
|
||||
var pi = PersonalTable.SV[species, form];
|
||||
return pivot == 0 ? pi.Type1 : pi.Type2;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compares the Raid Seed to the possible raid bounds to see if the encounter can originate from that seed.
|
||||
/// </summary>
|
||||
/// <remarks>A given raid seed might yield a different encounter or star count, hence why we need to check.</remarks>
|
||||
/// <param name="seed">Random seed used to generate the raid.</param>
|
||||
/// <param name="stars">Difficulty rating.</param>
|
||||
/// <param name="raidRate">Random weight of the raid to be used in the comparison with the game specific min rates.</param>
|
||||
/// <param name="randRateMinScarlet">Total weight of all Scarlet raids prior to this encounter.</param>
|
||||
/// <param name="randRateMinViolet">Total weight of all Violet raids prior to this encounter.</param>
|
||||
/// <returns>True if the raid seed can generate the encounter.</returns>
|
||||
public static bool IsMatchStarChoice(in uint seed, in byte stars, in byte raidRate, in short randRateMinScarlet, in short randRateMinViolet)
|
||||
{
|
||||
// When determining a raid, the game takes the u32 seed and does two rand calls.
|
||||
|
|
|
@ -77,13 +77,14 @@ public sealed class LegalInfo : IGeneration
|
|||
StoreMetadata(pk.Generation);
|
||||
}
|
||||
|
||||
internal void StoreMetadata(int gen)
|
||||
/// <summary>
|
||||
/// We can call this method at the start for any Gen3+ encounter iteration.
|
||||
/// Additionally, We need to call this for each Gen1/2 encounter as Version is not stored for those origins.
|
||||
/// </summary>
|
||||
/// <param name="generation">Encounter generation</param>
|
||||
internal void StoreMetadata(int generation) => Generation = generation switch
|
||||
{
|
||||
// We can call this method at the start for any Gen3+ encounter iteration.
|
||||
// We need to call this for each Gen1/2 encounter as Version is not stored for those origins.
|
||||
Generation = gen;
|
||||
|
||||
if (gen == -1 && Entity is PK9 { IsUnhatchedEgg: true })
|
||||
Generation = 9;
|
||||
}
|
||||
-1 when Entity is PK9 { IsUnhatchedEgg: true } => 9,
|
||||
_ => generation,
|
||||
};
|
||||
}
|
||||
|
|
|
@ -185,7 +185,7 @@ public sealed class PGF : DataMysteryGift, IRibbonSetEvent3, IRibbonSetEvent4, I
|
|||
|
||||
var rnd = Util.Rand;
|
||||
|
||||
var dt = DateTime.Now;
|
||||
var dt = EncounterDate.GetDateNDS();
|
||||
if (Day == 0)
|
||||
{
|
||||
Day = (byte)dt.Day;
|
||||
|
@ -202,7 +202,7 @@ public sealed class PGF : DataMysteryGift, IRibbonSetEvent3, IRibbonSetEvent4, I
|
|||
Met_Level = currentLevel,
|
||||
Nature = Nature != -1 ? Nature : rnd.Next(25),
|
||||
Form = Form,
|
||||
Version = OriginGame == 0 ? tr.Game : OriginGame,
|
||||
Version = GetVersion(tr, rnd),
|
||||
Language = Language == 0 ? tr.Language : Language,
|
||||
Ball = Ball,
|
||||
Move1 = Move1,
|
||||
|
@ -241,8 +241,6 @@ public sealed class PGF : DataMysteryGift, IRibbonSetEvent3, IRibbonSetEvent4, I
|
|||
|
||||
FatefulEncounter = true,
|
||||
};
|
||||
if (tr.Generation > 5 && OriginGame == 0) // Gen6+, give random gen5 game
|
||||
pk.Version = (int)GameVersion.W + rnd.Next(4);
|
||||
|
||||
if (Move1 == 0) // No moves defined
|
||||
{
|
||||
|
@ -285,6 +283,23 @@ public sealed class PGF : DataMysteryGift, IRibbonSetEvent3, IRibbonSetEvent4, I
|
|||
return pk;
|
||||
}
|
||||
|
||||
private int GetVersion(ITrainerInfo tr, Random rnd)
|
||||
{
|
||||
if (OriginGame != 0)
|
||||
return OriginGame;
|
||||
if (tr.Generation <= 5)
|
||||
return tr.Game;
|
||||
// Gen6+, give random gen5 game
|
||||
var bias = rnd.Next(4);
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
var ver = (int)GameVersion.W + ((bias + i) % 4);
|
||||
if (CanBeReceivedByVersion(ver))
|
||||
return ver;
|
||||
}
|
||||
return (int)GameVersion.W; // should never hit this for any distributed card
|
||||
}
|
||||
|
||||
private void SetEggMetDetails(PK5 pk)
|
||||
{
|
||||
pk.IsEgg = true;
|
||||
|
|
|
@ -17,7 +17,7 @@ public sealed class WC6Full
|
|||
Data = data;
|
||||
var wc6 = data.AsSpan(GiftStart).ToArray();
|
||||
Gift = new WC6(wc6);
|
||||
var now = DateTime.Now;
|
||||
var now = EncounterDate.GetDate3DS();
|
||||
Gift.RawDate = WC6.SetDate((uint)now.Year, (uint)now.Month, (uint)now.Day);
|
||||
|
||||
Gift.RestrictVersion = RestrictVersion;
|
||||
|
@ -30,7 +30,7 @@ public sealed class WC6Full
|
|||
var countgift = data.Length / WC6.Size;
|
||||
var result = new WC6[countfull + countgift];
|
||||
|
||||
var now = DateTime.Now;
|
||||
var now = EncounterDate.GetDate3DS();
|
||||
for (int i = 0; i < countfull; i++)
|
||||
result[i] = ReadWC6(WC6Full, i * Size, now);
|
||||
for (int i = 0; i < countgift; i++)
|
||||
|
@ -39,7 +39,7 @@ public sealed class WC6Full
|
|||
return result;
|
||||
}
|
||||
|
||||
private static WC6 ReadWC6(ReadOnlySpan<byte> data, int ofs, DateTime date)
|
||||
private static WC6 ReadWC6(ReadOnlySpan<byte> data, int ofs, DateOnly date)
|
||||
{
|
||||
var slice = data.Slice(ofs + GiftStart, WC6.Size).ToArray();
|
||||
return new WC6(slice)
|
||||
|
|
|
@ -17,7 +17,7 @@ public sealed class WC7Full
|
|||
Data = data;
|
||||
var wc7 = data.AsSpan(GiftStart).ToArray();
|
||||
Gift = new WC7(wc7);
|
||||
var now = DateTime.Now;
|
||||
var now = EncounterDate.GetDate3DS();
|
||||
Gift.RawDate = WC7.SetDate((uint)now.Year, (uint)now.Month, (uint)now.Day);
|
||||
|
||||
Gift.RestrictVersion = RestrictVersion;
|
||||
|
@ -30,7 +30,7 @@ public sealed class WC7Full
|
|||
var countgift = data.Length / WC7.Size;
|
||||
var result = new WC7[countfull + countgift];
|
||||
|
||||
var now = DateTime.Now;
|
||||
var now = EncounterDate.GetDate3DS();
|
||||
for (int i = 0; i < countfull; i++)
|
||||
result[i] = ReadWC7(wc7Full, i * Size, now);
|
||||
for (int i = 0; i < countgift; i++)
|
||||
|
@ -39,7 +39,7 @@ public sealed class WC7Full
|
|||
return result;
|
||||
}
|
||||
|
||||
private static WC7 ReadWC7(ReadOnlySpan<byte> data, int ofs, DateTime date)
|
||||
private static WC7 ReadWC7(ReadOnlySpan<byte> data, int ofs, DateOnly date)
|
||||
{
|
||||
var slice = data.Slice(ofs + GiftStart, WC7.Size).ToArray();
|
||||
return new WC7(slice)
|
||||
|
|
|
@ -7,12 +7,22 @@ namespace PKHeX.Core;
|
|||
/// </summary>
|
||||
public interface ITrainerID32 : ITrainerID16
|
||||
{
|
||||
/// <summary>
|
||||
/// 32-bit Trainer ID (0-4294967295)
|
||||
/// </summary>
|
||||
uint ID32 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 16-bit Secret ID (0-65535)
|
||||
/// </summary>
|
||||
ushort SID16 { get; set; }
|
||||
}
|
||||
|
||||
public interface ITrainerID16 : ITrainerID
|
||||
{
|
||||
/// <summary>
|
||||
/// 16-bit Trainer ID (0-65535)
|
||||
/// </summary>
|
||||
ushort TID16 { get; set; }
|
||||
}
|
||||
|
||||
|
@ -28,10 +38,13 @@ public static class ITrainerID32Extensions
|
|||
public static bool IsShiny(this ITrainerID32 tr, uint pid, int gen = 7)
|
||||
{
|
||||
var xor = GetShinyXor(tr, pid);
|
||||
var threshold = (gen >= 7 ? 16 : 8);
|
||||
var threshold = (gen >= 7 ? ShinyXorThreshold7 : ShinyXorThreshold36);
|
||||
return xor < threshold;
|
||||
}
|
||||
|
||||
private const int ShinyXorThreshold36 = 8; // 1:8192
|
||||
private const int ShinyXorThreshold7 = 16; // 1:4096
|
||||
|
||||
/// <summary>
|
||||
/// Calculates the <see cref="pid"/> and <see cref="ITrainerID32.ID32"/> xor.
|
||||
/// </summary>
|
||||
|
|
|
@ -455,7 +455,7 @@ public abstract class PKM : ISpeciesForm, ITrainerID32, IGeneration, IShiny, ILa
|
|||
Move2 = value.Move2;
|
||||
Move3 = value.Move3;
|
||||
Move4 = value.Move4;
|
||||
this.SetMaximumPPCurrent(Moves);
|
||||
this.SetMaximumPPCurrent(value);
|
||||
}
|
||||
|
||||
public void SetMoves(ReadOnlySpan<ushort> value)
|
||||
|
@ -464,7 +464,7 @@ public abstract class PKM : ISpeciesForm, ITrainerID32, IGeneration, IShiny, ILa
|
|||
Move2 = value.Length > 1 ? value[1] : default;
|
||||
Move3 = value.Length > 2 ? value[2] : default;
|
||||
Move4 = value.Length > 3 ? value[3] : default;
|
||||
this.SetMaximumPPCurrent(Moves);
|
||||
this.SetMaximumPPCurrent(value);
|
||||
}
|
||||
|
||||
public ushort[] RelearnMoves
|
||||
|
|
|
@ -275,8 +275,8 @@ public abstract class SAV4 : SaveFile, IEventFlag37
|
|||
{
|
||||
var pk4 = (PK4)pk;
|
||||
// Apply to this Save File
|
||||
DateTime Date = DateTime.Now;
|
||||
if (pk4.Trade(OT, ID32, Gender, Date.Day, Date.Month, Date.Year))
|
||||
var now = EncounterDate.GetDateNDS();
|
||||
if (pk4.Trade(OT, ID32, Gender, now.Day, now.Month, now.Year))
|
||||
pk.RefreshChecksum();
|
||||
}
|
||||
|
||||
|
|
|
@ -244,8 +244,8 @@ public sealed class SAV4BR : SaveFile
|
|||
{
|
||||
var pk4 = (BK4)pk;
|
||||
// Apply to this Save File
|
||||
DateTime Date = DateTime.Now;
|
||||
if (pk4.Trade(OT, ID32, Gender, Date.Day, Date.Month, Date.Year))
|
||||
var now = EncounterDate.GetDateNDS();
|
||||
if (pk4.Trade(OT, ID32, Gender, now.Day, now.Month, now.Year))
|
||||
pk.RefreshChecksum();
|
||||
}
|
||||
|
||||
|
|
|
@ -115,8 +115,8 @@ public abstract class SAV5 : SaveFile, ISaveBlock5BW, IEventFlag37
|
|||
{
|
||||
var pk5 = (PK5)pk;
|
||||
// Apply to this Save File
|
||||
DateTime Date = DateTime.Now;
|
||||
if (pk5.Trade(OT, ID32, Gender, Date.Day, Date.Month, Date.Year))
|
||||
var now = EncounterDate.GetDateNDS();
|
||||
if (pk5.Trade(OT, ID32, Gender, now.Day, now.Month, now.Year))
|
||||
pk.RefreshChecksum();
|
||||
}
|
||||
|
||||
|
|
|
@ -111,8 +111,8 @@ public abstract class SAV6 : SAV_BEEF, ITrainerStatRecord, ISaveBlock6Core, IReg
|
|||
PK6 pk6 = (PK6)pk;
|
||||
// Apply to this Save File
|
||||
int CT = pk6.CurrentHandler;
|
||||
DateTime Date = DateTime.Now;
|
||||
pk6.Trade(this, Date.Day, Date.Month, Date.Year);
|
||||
var now = EncounterDate.GetDate3DS();
|
||||
pk6.Trade(this, now.Day, now.Month, now.Year);
|
||||
if (CT != pk6.CurrentHandler) // Logic updated Friendship
|
||||
{
|
||||
// Copy over the Friendship Value only under certain circumstances
|
||||
|
|
|
@ -175,8 +175,8 @@ public abstract class SAV7 : SAV_BEEF, ITrainerStatRecord, ISaveBlock7Main, IReg
|
|||
PK7 pk7 = (PK7)pk;
|
||||
// Apply to this Save File
|
||||
int CT = pk7.CurrentHandler;
|
||||
DateTime Date = DateTime.Now;
|
||||
pk7.Trade(this, Date.Day, Date.Month, Date.Year);
|
||||
var now = EncounterDate.GetDate3DS();
|
||||
pk7.Trade(this, now.Day, now.Month, now.Year);
|
||||
if (CT != pk7.CurrentHandler) // Logic updated Friendship
|
||||
{
|
||||
// Copy over the Friendship Value only under certain circumstances
|
||||
|
|
|
@ -93,8 +93,8 @@ public sealed class SAV7b : SAV_BEEF, ISaveBlock7b, IGameSync, IEventFlagArray
|
|||
{
|
||||
var pb7 = (PB7)pk;
|
||||
// Apply to this Save File
|
||||
var Date = DateTime.Now;
|
||||
pb7.Trade(this, Date.Day, Date.Month, Date.Year);
|
||||
var now = EncounterDate.GetDateSwitch();
|
||||
pb7.Trade(this, now.Day, now.Month, now.Year);
|
||||
pb7.RefreshChecksum();
|
||||
}
|
||||
|
||||
|
|
|
@ -309,8 +309,8 @@ public sealed class SAV8BS : SaveFile, ISaveFileRevision, ITrainerStatRecord, IE
|
|||
{
|
||||
var pb8 = (PB8)pk;
|
||||
// Apply to this Save File
|
||||
DateTime Date = DateTime.Now;
|
||||
pb8.Trade(this, Date.Day, Date.Month, Date.Year);
|
||||
var now = EncounterDate.GetDateSwitch();
|
||||
pb8.Trade(this, now.Day, now.Month, now.Year);
|
||||
|
||||
pb8.RefreshChecksum();
|
||||
AddCountAcquired(pb8);
|
||||
|
|
|
@ -195,8 +195,8 @@ public sealed class SAV8SWSH : SaveFile, ISaveBlock8SWSH, ITrainerStatRecord, IS
|
|||
{
|
||||
PK8 pk8 = (PK8)pk;
|
||||
// Apply to this Save File
|
||||
DateTime Date = DateTime.Now;
|
||||
pk8.Trade(this, Date.Day, Date.Month, Date.Year);
|
||||
var now = EncounterDate.GetDateSwitch();
|
||||
pk8.Trade(this, now.Day, now.Month, now.Year);
|
||||
|
||||
if (FormArgumentUtil.IsFormArgumentTypeDatePair(pk8.Species, pk8.Form))
|
||||
{
|
||||
|
|
|
@ -164,8 +164,8 @@ public sealed class SAV9SV : SaveFile, ISaveBlock9Main, ISCBlockArray, ISaveFile
|
|||
{
|
||||
PK9 pk9 = (PK9)pk;
|
||||
// Apply to this Save File
|
||||
DateTime Date = DateTime.Now;
|
||||
pk9.Trade(this, Date.Day, Date.Month, Date.Year);
|
||||
var now = EncounterDate.GetDateSwitch();
|
||||
pk9.Trade(this, now.Day, now.Month, now.Year);
|
||||
|
||||
if (FormArgumentUtil.IsFormArgumentTypeDatePair(pk9.Species, pk9.Form))
|
||||
{
|
||||
|
|
|
@ -63,12 +63,12 @@ public sealed class Roamer3 : IContestStats
|
|||
public bool Active { get => Data[Offset + 0x13] == 1; set => Data[Offset + 0x13] = value ? (byte)1 : (byte)0; }
|
||||
|
||||
// Derived Properties
|
||||
private int IV_HP { get => (int)(IV32 >> 00) & 0x1F; set => IV32 = (uint)((IV32 & ~(0x1F << 00)) | (uint)((value > 31 ? 31 : value) << 00)); }
|
||||
private int IV_ATK { get => (int)(IV32 >> 05) & 0x1F; set => IV32 = (uint)((IV32 & ~(0x1F << 05)) | (uint)((value > 31 ? 31 : value) << 05)); }
|
||||
private int IV_DEF { get => (int)(IV32 >> 10) & 0x1F; set => IV32 = (uint)((IV32 & ~(0x1F << 10)) | (uint)((value > 31 ? 31 : value) << 10)); }
|
||||
private int IV_SPE { get => (int)(IV32 >> 15) & 0x1F; set => IV32 = (uint)((IV32 & ~(0x1F << 15)) | (uint)((value > 31 ? 31 : value) << 15)); }
|
||||
private int IV_SPA { get => (int)(IV32 >> 20) & 0x1F; set => IV32 = (uint)((IV32 & ~(0x1F << 20)) | (uint)((value > 31 ? 31 : value) << 20)); }
|
||||
private int IV_SPD { get => (int)(IV32 >> 25) & 0x1F; set => IV32 = (uint)((IV32 & ~(0x1F << 25)) | (uint)((value > 31 ? 31 : value) << 25)); }
|
||||
private int IV_HP { get => (int)(IV32 >> 00) & 0x1F; set => IV32 = (IV32 & ~(0x1Fu << 00)) | (uint)((value > 31 ? 31 : value) << 00); }
|
||||
private int IV_ATK { get => (int)(IV32 >> 05) & 0x1F; set => IV32 = (IV32 & ~(0x1Fu << 05)) | (uint)((value > 31 ? 31 : value) << 05); }
|
||||
private int IV_DEF { get => (int)(IV32 >> 10) & 0x1F; set => IV32 = (IV32 & ~(0x1Fu << 10)) | (uint)((value > 31 ? 31 : value) << 10); }
|
||||
private int IV_SPE { get => (int)(IV32 >> 15) & 0x1F; set => IV32 = (IV32 & ~(0x1Fu << 15)) | (uint)((value > 31 ? 31 : value) << 15); }
|
||||
private int IV_SPA { get => (int)(IV32 >> 20) & 0x1F; set => IV32 = (IV32 & ~(0x1Fu << 20)) | (uint)((value > 31 ? 31 : value) << 20); }
|
||||
private int IV_SPD { get => (int)(IV32 >> 25) & 0x1F; set => IV32 = (IV32 & ~(0x1Fu << 25)) | (uint)((value > 31 ? 31 : value) << 25); }
|
||||
|
||||
/// <summary>
|
||||
/// Roamer's IVs.
|
||||
|
|
|
@ -28,12 +28,12 @@ public sealed class Roamer4
|
|||
// 0x13 alignment, unused
|
||||
|
||||
// Derived Properties
|
||||
private int IV_HP { get => (int)(IV32 >> 00) & 0x1F; set => IV32 = (uint)((IV32 & ~(0x1F << 00)) | (uint)((value > 31 ? 31 : value) << 00)); }
|
||||
private int IV_ATK { get => (int)(IV32 >> 05) & 0x1F; set => IV32 = (uint)((IV32 & ~(0x1F << 05)) | (uint)((value > 31 ? 31 : value) << 05)); }
|
||||
private int IV_DEF { get => (int)(IV32 >> 10) & 0x1F; set => IV32 = (uint)((IV32 & ~(0x1F << 10)) | (uint)((value > 31 ? 31 : value) << 10)); }
|
||||
private int IV_SPE { get => (int)(IV32 >> 15) & 0x1F; set => IV32 = (uint)((IV32 & ~(0x1F << 15)) | (uint)((value > 31 ? 31 : value) << 15)); }
|
||||
private int IV_SPA { get => (int)(IV32 >> 20) & 0x1F; set => IV32 = (uint)((IV32 & ~(0x1F << 20)) | (uint)((value > 31 ? 31 : value) << 20)); }
|
||||
private int IV_SPD { get => (int)(IV32 >> 25) & 0x1F; set => IV32 = (uint)((IV32 & ~(0x1F << 25)) | (uint)((value > 31 ? 31 : value) << 25)); }
|
||||
private int IV_HP { get => (int)(IV32 >> 00) & 0x1F; set => IV32 = (IV32 & ~(0x1Fu << 00)) | (uint)((value > 31 ? 31 : value) << 00); }
|
||||
private int IV_ATK { get => (int)(IV32 >> 05) & 0x1F; set => IV32 = (IV32 & ~(0x1Fu << 05)) | (uint)((value > 31 ? 31 : value) << 05); }
|
||||
private int IV_DEF { get => (int)(IV32 >> 10) & 0x1F; set => IV32 = (IV32 & ~(0x1Fu << 10)) | (uint)((value > 31 ? 31 : value) << 10); }
|
||||
private int IV_SPE { get => (int)(IV32 >> 15) & 0x1F; set => IV32 = (IV32 & ~(0x1Fu << 15)) | (uint)((value > 31 ? 31 : value) << 15); }
|
||||
private int IV_SPA { get => (int)(IV32 >> 20) & 0x1F; set => IV32 = (IV32 & ~(0x1Fu << 20)) | (uint)((value > 31 ? 31 : value) << 20); }
|
||||
private int IV_SPD { get => (int)(IV32 >> 25) & 0x1F; set => IV32 = (IV32 & ~(0x1Fu << 25)) | (uint)((value > 31 ? 31 : value) << 25); }
|
||||
|
||||
/// <summary>
|
||||
/// Roamer's IVs.
|
||||
|
|
|
@ -39,7 +39,7 @@ public sealed class Daycare5 : SaveBlock<SAV5>
|
|||
private int GetDaycareEXPOffset(int slot) => GetDaycareSlotOffset(slot) + 4 + PokeCrypto.SIZE_5PARTY;
|
||||
|
||||
public bool? IsOccupied(int slot) => ReadUInt32LittleEndian(Data.AsSpan(GetDaycareSlotOffset(slot))) == 1;
|
||||
public void SetOccupied(int slot, bool occupied) => WriteUInt32LittleEndian(Data.AsSpan(GetDaycareSlotOffset(slot)), (uint)(occupied ? 1 : 0));
|
||||
public void SetOccupied(int slot, bool occupied) => WriteUInt32LittleEndian(Data.AsSpan(GetDaycareSlotOffset(slot)), occupied ? 1u : 0);
|
||||
|
||||
public uint? GetEXP(int slot) => ReadUInt32LittleEndian(Data.AsSpan(GetDaycareEXPOffset(slot)));
|
||||
public void SetEXP(int slot, uint EXP) => WriteUInt32LittleEndian(Data.AsSpan(GetDaycareEXPOffset(slot)), EXP);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using System;
|
||||
using System;
|
||||
using static System.Buffers.Binary.BinaryPrimitives;
|
||||
|
||||
namespace PKHeX.Core;
|
||||
|
@ -50,7 +50,7 @@ public sealed class EntreeForest
|
|||
{
|
||||
var slots = new EntreeSlot[TotalSlots];
|
||||
for (int i = 0; i < slots.Length; i++)
|
||||
slots[i] = new EntreeSlot(Data, i * 4) { Area = GetSlotArea(i) };
|
||||
slots[i] = new EntreeSlot(Data.AsMemory(i * EntreeSlot.SIZE, EntreeSlot.SIZE)) { Area = GetSlotArea(i) };
|
||||
return slots;
|
||||
}
|
||||
}
|
||||
|
@ -116,6 +116,6 @@ public sealed class EntreeForest
|
|||
0 => EntreeForestArea.Center,
|
||||
1 => EntreeForestArea.Left,
|
||||
2 => EntreeForestArea.Right,
|
||||
_ => throw new ArgumentOutOfRangeException(),
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(index)),
|
||||
};
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ public sealed class EntreeSlot : ISpeciesForm
|
|||
public ushort Species // bits 0-10
|
||||
{
|
||||
get => (ushort)((RawValue & 0x3FF) >> 0);
|
||||
set => RawValue = (RawValue & 0xFFFF_F800) | ((uint)(value & 0x3FF) << 0);
|
||||
set => RawValue = (RawValue & 0xFFFF_F800) | ((value & 0x3FFu) << 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -23,7 +23,7 @@ public sealed class EntreeSlot : ISpeciesForm
|
|||
public ushort Move // bits 11-20
|
||||
{
|
||||
get => (ushort)((RawValue & 0x001F_F800) >> 11);
|
||||
set => RawValue = (RawValue & 0xFFE0_07FF) | ((uint)(value & 0x3FF) << 11);
|
||||
set => RawValue = (RawValue & 0xFFE0_07FF) | ((value & 0x3FFu) << 11);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -41,7 +41,7 @@ public sealed class EntreeSlot : ISpeciesForm
|
|||
public byte Form // bits 23-27
|
||||
{
|
||||
get => (byte)((RawValue & 0x0F80_0000) >> 23);
|
||||
set => RawValue = (RawValue & 0xF07F_FFFF) | ((uint)(value & 0x1F) << 23);
|
||||
set => RawValue = (RawValue & 0xF07F_FFFF) | ((value & 0x1Fu) << 23);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -62,25 +62,29 @@ public sealed class EntreeSlot : ISpeciesForm
|
|||
set => RawValue = ((RawValue << 3) >> 3) | (uint)((value & 0x7) << 29);
|
||||
}
|
||||
|
||||
private readonly byte[] Data;
|
||||
private readonly int Offset;
|
||||
private Memory<byte> Data { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Raw Data Value
|
||||
/// </summary>
|
||||
public uint RawValue
|
||||
{
|
||||
get => ReadUInt32LittleEndian(Data.AsSpan(Offset));
|
||||
set => WriteUInt32LittleEndian(Data.AsSpan(Offset), value);
|
||||
get => ReadUInt32LittleEndian(Data.Span);
|
||||
set => WriteUInt32LittleEndian(Data.Span, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets the raw data value to 0.
|
||||
/// </summary>
|
||||
public void Delete() => RawValue = 0;
|
||||
|
||||
public const int SIZE = 4;
|
||||
|
||||
/// <summary>
|
||||
/// Indicates which area the slot data originated from.
|
||||
/// Extra metadata for the slot which is not stored in the raw data.
|
||||
/// </summary>
|
||||
public EntreeForestArea Area { get; init; }
|
||||
|
||||
public EntreeSlot(byte[] data, int ofs)
|
||||
{
|
||||
Data = data;
|
||||
Offset = ofs;
|
||||
}
|
||||
public EntreeSlot(Memory<byte> data) => Data = data;
|
||||
}
|
||||
|
|
|
@ -29,12 +29,12 @@ public sealed class Roamer5
|
|||
public byte Unk13 { get => Data[0x13]; set => Data[0x13] = value; } // likely just alignment
|
||||
|
||||
// Derived Properties
|
||||
private int IV_HP { get => (int)(IV32 >> 00) & 0x1F; set => IV32 = (uint)((IV32 & ~(0x1F << 00)) | (uint)((value > 31 ? 31 : value) << 00)); }
|
||||
private int IV_ATK { get => (int)(IV32 >> 05) & 0x1F; set => IV32 = (uint)((IV32 & ~(0x1F << 05)) | (uint)((value > 31 ? 31 : value) << 05)); }
|
||||
private int IV_DEF { get => (int)(IV32 >> 10) & 0x1F; set => IV32 = (uint)((IV32 & ~(0x1F << 10)) | (uint)((value > 31 ? 31 : value) << 10)); }
|
||||
private int IV_SPE { get => (int)(IV32 >> 15) & 0x1F; set => IV32 = (uint)((IV32 & ~(0x1F << 15)) | (uint)((value > 31 ? 31 : value) << 15)); }
|
||||
private int IV_SPA { get => (int)(IV32 >> 20) & 0x1F; set => IV32 = (uint)((IV32 & ~(0x1F << 20)) | (uint)((value > 31 ? 31 : value) << 20)); }
|
||||
private int IV_SPD { get => (int)(IV32 >> 25) & 0x1F; set => IV32 = (uint)((IV32 & ~(0x1F << 25)) | (uint)((value > 31 ? 31 : value) << 25)); }
|
||||
private int IV_HP { get => (int)(IV32 >> 00) & 0x1F; set => IV32 = (IV32 & ~(0x1Fu << 00)) | (uint)((value > 31 ? 31 : value) << 00); }
|
||||
private int IV_ATK { get => (int)(IV32 >> 05) & 0x1F; set => IV32 = (IV32 & ~(0x1Fu << 05)) | (uint)((value > 31 ? 31 : value) << 05); }
|
||||
private int IV_DEF { get => (int)(IV32 >> 10) & 0x1F; set => IV32 = (IV32 & ~(0x1Fu << 10)) | (uint)((value > 31 ? 31 : value) << 10); }
|
||||
private int IV_SPE { get => (int)(IV32 >> 15) & 0x1F; set => IV32 = (IV32 & ~(0x1Fu << 15)) | (uint)((value > 31 ? 31 : value) << 15); }
|
||||
private int IV_SPA { get => (int)(IV32 >> 20) & 0x1F; set => IV32 = (IV32 & ~(0x1Fu << 20)) | (uint)((value > 31 ? 31 : value) << 20); }
|
||||
private int IV_SPD { get => (int)(IV32 >> 25) & 0x1F; set => IV32 = (IV32 & ~(0x1Fu << 25)) | (uint)((value > 31 ? 31 : value) << 25); }
|
||||
|
||||
/// <summary>
|
||||
/// Roamer's IVs.
|
||||
|
|
|
@ -5,7 +5,7 @@ namespace PKHeX.Core;
|
|||
|
||||
public sealed class Puff6 : SaveBlock<SAV6>
|
||||
{
|
||||
private const int MaxPuffID = 26; // Supreme Winter Poké Puff
|
||||
private const byte MaxPuffID = 26; // Supreme Winter Poké Puff
|
||||
private const int PuffSlots = 100;
|
||||
|
||||
public Puff6(SAV6 SAV, int offset) : base(SAV) => Offset = offset;
|
||||
|
@ -21,37 +21,41 @@ public sealed class Puff6 : SaveBlock<SAV6>
|
|||
|
||||
public void Reset()
|
||||
{
|
||||
Array.Clear(Data, Offset, PuffSlots);
|
||||
var puffs = GetPuffs();
|
||||
puffs.Clear();
|
||||
// Set the first few default Puffs
|
||||
Data[Offset + 0] = 1;
|
||||
Data[Offset + 1] = 2;
|
||||
Data[Offset + 2] = 3;
|
||||
Data[Offset + 3] = 4;
|
||||
Data[Offset + 4] = 5;
|
||||
puffs[0] = 1;
|
||||
puffs[1] = 2;
|
||||
puffs[2] = 3;
|
||||
puffs[3] = 4;
|
||||
puffs[4] = 5;
|
||||
PuffCount = 5;
|
||||
}
|
||||
|
||||
public void MaxCheat(bool special = false)
|
||||
{
|
||||
var rnd = Util.Rand;
|
||||
var puffs = GetPuffs();
|
||||
if (special)
|
||||
{
|
||||
for (int i = 0; i < PuffSlots; i++)
|
||||
Data[Offset + i] = (byte)(21 + rnd.Next(2)); // Supreme Wish or Honor
|
||||
foreach (ref var puff in puffs)
|
||||
puff = (byte)(21 + rnd.Next(2)); // Supreme Wish or Honor
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < PuffSlots; i++)
|
||||
Data[Offset + i] = (byte)((i % MaxPuffID) + 1);
|
||||
rnd.Shuffle(Data.AsSpan(Offset, PuffSlots));
|
||||
int i = 0;
|
||||
foreach (ref var puff in puffs)
|
||||
puff = (byte)((i++ % MaxPuffID) + 1);
|
||||
rnd.Shuffle(puffs);
|
||||
}
|
||||
PuffCount = PuffSlots;
|
||||
}
|
||||
|
||||
public void Sort(bool reverse = false)
|
||||
{
|
||||
Array.Sort(Data, Offset, PuffCount);
|
||||
var puffs = GetPuffs();
|
||||
puffs.Sort();
|
||||
if (reverse)
|
||||
Array.Reverse(Data, Offset, PuffCount);
|
||||
puffs.Reverse();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1121,16 +1121,19 @@ public sealed class PokedexSave8a
|
|||
if (hash == 0xCBF29CE484222645)
|
||||
return 0;
|
||||
|
||||
return (int)(uint)SaveFile.Accessor.GetBlockValue((uint)(hash & 0xFFFFFFFF));
|
||||
return (int)(uint)SaveFile.Accessor.GetBlockValue(GetSaveBlockKey(hash));
|
||||
}
|
||||
|
||||
private static uint GetSaveBlockKey(ulong hash) => (uint)hash; // truncate to 32-bit
|
||||
|
||||
private int GetSpeciesQuestState(ulong hash)
|
||||
{
|
||||
if (hash is 0xC0EA47549AB5F3D9 or 0xCBF29CE484222645)
|
||||
return 0;
|
||||
|
||||
// These are single-byte blocks, but type is "object"...
|
||||
return SaveFile.Accessor.GetBlock((uint)(hash & 0xFFFFFFFF)).Data[0];
|
||||
var key = GetSaveBlockKey(hash);
|
||||
return SaveFile.Accessor.GetBlock(key).Data[0];
|
||||
}
|
||||
|
||||
public static bool IsAnyTaskTriggered(ushort species, PokedexResearchTaskType8a which, MoveType moveType, int move, PokedexTimeOfDay8a timeOfDay)
|
||||
|
|
|
@ -40,8 +40,8 @@ public sealed class PokedexSaveData
|
|||
public bool IsPokedexCompleted(PokedexType8a which) => (GlobalData.Flags & (which < PokedexType8a.Count ? (1 << (int)which) : 1)) != 0;
|
||||
public bool IsPokedexPerfect(PokedexType8a which) => (GlobalData.Flags & ((which < PokedexType8a.Count ? (1 << (int)which) : 1) << 6)) != 0;
|
||||
|
||||
public void SetPokedexCompleted(PokedexType8a which) => GlobalData.Flags |= (uint)(which < PokedexType8a.Count ? (1 << (int)which) : 1);
|
||||
public void SetPokedexPerfect(PokedexType8a which) => GlobalData.Flags |= (uint)((which < PokedexType8a.Count ? (1 << (int)which) : 1) << 6);
|
||||
public void SetPokedexCompleted(PokedexType8a which) => GlobalData.Flags |= which < PokedexType8a.Count ? (1u << (int)which) : 1;
|
||||
public void SetPokedexPerfect(PokedexType8a which) => GlobalData.Flags |= (which < PokedexType8a.Count ? (1u << (int)which) : 1) << 6;
|
||||
|
||||
public PokedexSaveResearchEntry GetResearchEntry(ushort species) => ResearchEntries[species];
|
||||
|
||||
|
|
|
@ -86,7 +86,9 @@ public sealed class Zukan4 : ZukanBase<SAV4>
|
|||
const int brSize = 0x40;
|
||||
if (species == (int)Species.Deoxys)
|
||||
{
|
||||
uint val = (uint)(Data[0x4 + (1 * brSize) - 1] | (Data[0x4 + (2 * brSize) - 1] << 8));
|
||||
var br1 = Data[0x4 + (1 * brSize) - 1];
|
||||
var br2 = Data[0x4 + (2 * brSize) - 1];
|
||||
uint val = (uint)(br1 | (br2 << 8));
|
||||
return GetDexFormValues(val, 4, 4);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue