mirror of
https://github.com/kwsch/PKHeX.git
synced 2026-03-21 17:48:28 -05:00
Changes for Legends: Z-A support (#4596)
Refer to pull request notes and the eventual changelog for a high-level summary. Co-authored-by: Matt <17801814+sora10pls@users.noreply.github.com> Co-authored-by: Lusamine <30205550+Lusamine@users.noreply.github.com> Co-authored-by: SciresM <8676005+SciresM@users.noreply.github.com>
This commit is contained in:
parent
ae526a5bd5
commit
fd1c538cc5
2
.github/README-de.md
vendored
2
.github/README-de.md
vendored
|
|
@ -24,7 +24,7 @@ PKHeX erwartet entschlüsselte Spielstände. Da diese konsolenspezifisch verschl
|
|||
|
||||
## Screenshots
|
||||
|
||||

|
||||

|
||||
|
||||
## Erstellen
|
||||
|
||||
|
|
|
|||
2
.github/README-es.md
vendored
2
.github/README-es.md
vendored
|
|
@ -24,7 +24,7 @@ PKHeX espera archivos de guardado que no estén cifrados con las claves específ
|
|||
|
||||
## Capturas de Pantalla
|
||||
|
||||

|
||||

|
||||
|
||||
## Building
|
||||
|
||||
|
|
|
|||
2
.github/README-fr.md
vendored
2
.github/README-fr.md
vendored
|
|
@ -23,7 +23,7 @@ PKHeX attend des fichiers de sauvegarde qui ne sont pas chiffrés avec des clés
|
|||
|
||||
## Captures d'écran
|
||||
|
||||

|
||||

|
||||
|
||||
## Construction
|
||||
|
||||
|
|
|
|||
2
.github/README-it.md
vendored
2
.github/README-it.md
vendored
|
|
@ -24,7 +24,7 @@ PKHeX si aspetta file di salvataggio non criptati con le chiavi specifiche della
|
|||
|
||||
## Screenshots
|
||||
|
||||

|
||||

|
||||
|
||||
## Building
|
||||
|
||||
|
|
|
|||
2
.github/README-ko.md
vendored
2
.github/README-ko.md
vendored
|
|
@ -24,7 +24,7 @@ PKHeX는 콘솔 전용 키로 암호화되지 않은 세이브 파일을 요구
|
|||
|
||||
## 스크린샷
|
||||
|
||||

|
||||

|
||||
|
||||
## 빌드
|
||||
|
||||
|
|
|
|||
2
.github/README-zh-Hans.md
vendored
2
.github/README-zh-Hans.md
vendored
|
|
@ -24,7 +24,7 @@ PKHeX 所读取存档文件必须是未经主机唯一密钥加密,因此请
|
|||
|
||||
## 截图
|
||||
|
||||

|
||||

|
||||
|
||||
## 构建
|
||||
|
||||
|
|
|
|||
2
.github/README-zh-Hant.md
vendored
2
.github/README-zh-Hant.md
vendored
|
|
@ -24,7 +24,7 @@ PKHeX 所讀取檔案須未經主機唯一密鑰加密,因而請使用儲存
|
|||
|
||||
## 螢幕擷取截圖
|
||||
|
||||

|
||||

|
||||
|
||||
## 構建
|
||||
|
||||
|
|
|
|||
195
PKHeX.Core/Editing/Applicators/PlusRecordApplicator.cs
Normal file
195
PKHeX.Core/Editing/Applicators/PlusRecordApplicator.cs
Normal file
|
|
@ -0,0 +1,195 @@
|
|||
using System;
|
||||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Logic for modifying the Plus Record flags of a <see cref="PA9"/>.
|
||||
/// </summary>
|
||||
public static class PlusRecordApplicator
|
||||
{
|
||||
/// <summary>
|
||||
/// Sets all the Plus Record flags for the <see cref="record"/> to the given value.
|
||||
/// </summary>
|
||||
/// <param name="record">Pokémon to modify.</param>
|
||||
/// <param name="count">Total count of flags to modify [0,x).</param>
|
||||
/// <param name="value">Value to set for each record.</param>
|
||||
public static void SetPlusFlagsAll(this IPlusRecord record, int count, bool value)
|
||||
{
|
||||
for (int i = 0; i < count; i++)
|
||||
record.SetMovePlusFlag(i, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears the Plus Record flags for the <see cref="record"/>.
|
||||
/// </summary>
|
||||
/// <param name="record">Pokémon to modify.</param>
|
||||
/// <param name="count">Total count of flags to modify [0,x).</param>
|
||||
public static void ClearPlusFlags(this IPlusRecord record, int count) => record.SetPlusFlagsAll(count, false);
|
||||
|
||||
/// <summary>
|
||||
/// Sets the Plus Record flags for the <see cref="record"/> based on the legality of learning moves.
|
||||
/// </summary>
|
||||
/// <param name="record">Pokémon to modify.</param>
|
||||
/// <param name="permit">Sanity check to retrieve plus record indexes.</param>
|
||||
/// <param name="la">Legality analysis of the Pokémon.</param>
|
||||
/// <param name="seedOfMastery">Use a Seed of Mastery to bypass the level requirement of mastering the move.</param>
|
||||
/// <param name="tm">Apply TM flags as Plus too.</param>
|
||||
public static void SetPlusFlags(this IPlusRecord record, IPermitPlus permit, LegalityAnalysis la, bool seedOfMastery, bool tm)
|
||||
{
|
||||
// Hopefully this is only called for Legends: Z-A format entities.
|
||||
var entity = la.Entity;
|
||||
var context = entity.Context;
|
||||
var evos = la.Info.EvoChainsAllGens.Get(context);
|
||||
switch (la.Entity.Context)
|
||||
{
|
||||
case EntityContext.Gen9a:
|
||||
{
|
||||
var learn = LearnSource9ZA.Instance;
|
||||
SetPlusFlagsNatural(record, permit, evos, learn, seedOfMastery);
|
||||
if (tm)
|
||||
{
|
||||
var table = PersonalTable.ZA;
|
||||
SetPlusFlagsTM<PersonalTable9ZA, PersonalInfo9ZA, LearnSource9ZA>(record, permit, evos, learn, seedOfMastery, table);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new Exception("Format not supported.");
|
||||
}
|
||||
}
|
||||
|
||||
public static void SetPlusFlagsNatural<TSource>(IPlusRecord record, IPermitPlus permit, ReadOnlySpan<EvoCriteria> evos, TSource source, bool seedOfMastery) where TSource : ILearnSourceBonus
|
||||
{
|
||||
var indexes = permit.PlusMoveIndexes;
|
||||
foreach (var evo in evos)
|
||||
{
|
||||
var (levelUp, plus) = source.GetLearnsetAndOther(evo.Species, evo.Form);
|
||||
var set = seedOfMastery ? levelUp : plus;
|
||||
var levels = set.GetAllLevels();
|
||||
var moves = set.GetAllMoves();
|
||||
for (int i = 0; i < levels.Length; i++)
|
||||
{
|
||||
if (evo.LevelMax < levels[i])
|
||||
break;
|
||||
|
||||
var move = moves[i];
|
||||
var index = indexes.IndexOf(move);
|
||||
record.SetMovePlusFlag(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void SetPlusFlagsTM<TTable, TInfo, TSource>(IPlusRecord record, IPermitPlus permit,
|
||||
ReadOnlySpan<EvoCriteria> evos,
|
||||
TSource source, bool seedOfMastery,
|
||||
TTable table)
|
||||
where TTable : IPersonalTable<TInfo>
|
||||
where TInfo : IPersonalInfo, IPersonalInfoTM
|
||||
where TSource : ILearnSourceBonus
|
||||
{
|
||||
var indexes = permit.PlusMoveIndexes;
|
||||
foreach (var evo in evos)
|
||||
{
|
||||
var pi = table[evo.Species, evo.Form];
|
||||
var (levelUp, plus) = source.GetLearnsetAndOther(evo.Species, evo.Form);
|
||||
var set = seedOfMastery ? levelUp : plus;
|
||||
for (int index = 0; index < indexes.Length; index++)
|
||||
{
|
||||
var move = indexes[index];
|
||||
var tmIndex = permit.RecordPermitIndexes.IndexOf(move);
|
||||
if (tmIndex != -1 && pi.GetIsLearnTM(tmIndex))
|
||||
record.SetMovePlusFlag(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets all moves that would be learned and naturally available as Plus based on the given level
|
||||
/// </summary>
|
||||
/// <param name="record">Record to modify</param>
|
||||
/// <param name="permit">Permit to use</param>
|
||||
/// <param name="plus">Learnset to use</param>
|
||||
/// <param name="level">Current level</param>
|
||||
/// <param name="extra">Extra moves to set as Plus</param>
|
||||
public static void SetPlusFlagsEncounter(IPlusRecord record, IPermitPlus permit, Learnset plus, byte level, params ReadOnlySpan<ushort> extra)
|
||||
{
|
||||
var indexes = permit.PlusMoveIndexes;
|
||||
var levels = plus.GetAllLevels();
|
||||
var moves = plus.GetAllMoves();
|
||||
|
||||
for (int i = 0; i < levels.Length; i++)
|
||||
{
|
||||
if (level < levels[i])
|
||||
break;
|
||||
|
||||
var move = moves[i];
|
||||
var index = indexes.IndexOf(move);
|
||||
record.SetMovePlusFlag(index);
|
||||
}
|
||||
|
||||
if (extra.Length != 0)
|
||||
SetPlusFlagsSpecific(record, permit, extra);
|
||||
}
|
||||
|
||||
public static void SetPlusFlagsSpecific(IPlusRecord record, IPermitPlus permit, ReadOnlySpan<ushort> extra)
|
||||
{
|
||||
var indexes = permit.PlusMoveIndexes;
|
||||
foreach (var move in extra)
|
||||
{
|
||||
var index = indexes.IndexOf(move);
|
||||
record.SetMovePlusFlag(index);
|
||||
}
|
||||
}
|
||||
|
||||
public static void SetPlusFlags<T>(this T pk, IPermitPlus permit, PlusRecordApplicatorOption option)
|
||||
where T : PKM, IPlusRecord
|
||||
=> SetPlusFlags(pk, pk, permit, option);
|
||||
|
||||
public static void SetPlusFlags(this IPlusRecord record, PKM pk, IPermitPlus permit, PlusRecordApplicatorOption option)
|
||||
{
|
||||
record.ClearPlusFlags(permit.PlusCountTotal);
|
||||
if (option is PlusRecordApplicatorOption.None)
|
||||
return;
|
||||
if (option is PlusRecordApplicatorOption.ForceAll)
|
||||
{
|
||||
record.SetPlusFlagsAll(permit.PlusCountUsed, true);
|
||||
return;
|
||||
}
|
||||
|
||||
var la = new LegalityAnalysis(pk);
|
||||
SetPlusFlagsInternal(record, permit, option, la);
|
||||
}
|
||||
|
||||
public static void SetPlusFlags(this IPlusRecord record, IPermitPlus permit, PlusRecordApplicatorOption option, LegalityAnalysis la)
|
||||
{
|
||||
record.ClearPlusFlags(permit.PlusCountTotal);
|
||||
if (option is PlusRecordApplicatorOption.None)
|
||||
return;
|
||||
if (option is PlusRecordApplicatorOption.ForceAll)
|
||||
{
|
||||
record.SetPlusFlagsAll(permit.PlusCountUsed, true);
|
||||
return;
|
||||
}
|
||||
|
||||
SetPlusFlagsInternal(record, permit, option, la);
|
||||
}
|
||||
|
||||
private static void SetPlusFlagsInternal(IPlusRecord record, IPermitPlus permit, PlusRecordApplicatorOption option, LegalityAnalysis la)
|
||||
{
|
||||
if (option is PlusRecordApplicatorOption.LegalCurrent)
|
||||
record.SetPlusFlags(permit, la, false, false);
|
||||
else if (option is PlusRecordApplicatorOption.LegalCurrentTM)
|
||||
record.SetPlusFlags(permit, la, false, true);
|
||||
else if (option is PlusRecordApplicatorOption.LegalSeedTM)
|
||||
record.SetPlusFlags(permit, la, true, true);
|
||||
}
|
||||
}
|
||||
|
||||
public enum PlusRecordApplicatorOption
|
||||
{
|
||||
None,
|
||||
ForceAll,
|
||||
LegalCurrent,
|
||||
LegalCurrentTM,
|
||||
LegalSeedTM,
|
||||
}
|
||||
|
|
@ -104,6 +104,8 @@ public static void SetRecordFlags(this ITechRecord pk, ReadOnlySpan<ushort> move
|
|||
{
|
||||
if (pk is PK9 pk9)
|
||||
SetRecordFlags<PersonalTable9SV, PersonalInfo9SV>(pk9, moves, evos, PersonalTable.SV);
|
||||
else if (pk is PA9 pa9)
|
||||
SetRecordFlags<PersonalTable9ZA, PersonalInfo9ZA>(pa9, moves, evos, PersonalTable.ZA);
|
||||
else if (pk is PK8 pk8)
|
||||
SetRecordFlags<PersonalTable8SWSH, PersonalInfo8SWSH>(pk8, moves, evos, PersonalTable.SWSH);
|
||||
}
|
||||
|
|
@ -113,6 +115,8 @@ public static void SetRecordFlagsAll(this ITechRecord pk, ReadOnlySpan<EvoCriter
|
|||
{
|
||||
if (pk is PK9 pk9)
|
||||
SetRecordFlagsAll<PersonalTable9SV, PersonalInfo9SV>(pk9, evos, PersonalTable.SV);
|
||||
else if (pk is PA9 pa9)
|
||||
SetRecordFlagsAll<PersonalTable9ZA, PersonalInfo9ZA>(pa9, evos, PersonalTable.ZA);
|
||||
else if (pk is PK8 pk8)
|
||||
SetRecordFlagsAll<PersonalTable8SWSH, PersonalInfo8SWSH>(pk8, evos, PersonalTable.SWSH);
|
||||
}
|
||||
|
|
@ -121,6 +125,7 @@ public static void SetRecordFlagsAll(this ITechRecord pk, ReadOnlySpan<EvoCriter
|
|||
public static bool IsRecordPermitted(this ITechRecord pk, ReadOnlySpan<EvoCriteria> evos, int index) => pk switch
|
||||
{
|
||||
PK9 => IsRecordPermitted<PersonalTable9SV, PersonalInfo9SV>(evos, PersonalTable.SV, index),
|
||||
PA9 => IsRecordPermitted<PersonalTable9ZA, PersonalInfo9ZA>(evos, PersonalTable.ZA, index),
|
||||
PK8 => IsRecordPermitted<PersonalTable8SWSH, PersonalInfo8SWSH>(evos, PersonalTable.SWSH, index),
|
||||
_ => false,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ public sealed record BattleTemplateTuple(BattleTemplateToken Token, string Text)
|
|||
public static ReadOnlySpan<char> GetMoveDisplay(MoveDisplayStyle style = MoveDisplayStyle.Fill) => style switch
|
||||
{
|
||||
MoveDisplayStyle.Fill => "----",
|
||||
MoveDisplayStyle.Directional => "↑←↓→",
|
||||
MoveDisplayStyle.Directional => "↑→←↓",
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(style), style, null),
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ private static LanguageID GetLanguage(LanguageID choice, LanguageID program)
|
|||
|
||||
private static MoveDisplayStyle GetMoveDisplayStyle(MoveDisplayStyle style, EntityContext context) => style switch
|
||||
{
|
||||
//MoveDisplayStyle.Directional when context is EntityContext.Gen9a => MoveDisplayStyle.Directional, TODO ZA
|
||||
MoveDisplayStyle.Directional when context is EntityContext.Gen9a => MoveDisplayStyle.Directional,
|
||||
_ => MoveDisplayStyle.Fill,
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -154,6 +154,9 @@ public static string GetFormNameFromShowdownFormName(ushort species, string form
|
|||
(int)Maushold when form is "Four" => "Family of Four",
|
||||
(int)Urshifu or (int)Pikachu or (int)Alcremie => form.Replace('-', ' '), // Strike and Cosplay
|
||||
|
||||
(int)Pumpkaboo or (int)Gourgeist when form is "Average" => "Medium",
|
||||
(int)Pumpkaboo or (int)Gourgeist when form is "Super" => "Jumbo",
|
||||
|
||||
_ => FormInfo.HasTotemForm(species) && form.EndsWith("Totem", StringComparison.OrdinalIgnoreCase) ? "Large" : form,
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -523,7 +523,7 @@ private static string GetSpeciesNickname(string specForm, string nickname, ushor
|
|||
{
|
||||
if (nickname.Length == 0 || nickname == specForm)
|
||||
return specForm;
|
||||
bool isNicknamed = SpeciesName.IsNicknamedAnyLanguage(species, nickname, context.Generation());
|
||||
bool isNicknamed = SpeciesName.IsNicknamedAnyLanguage(species, nickname, context);
|
||||
if (!isNicknamed)
|
||||
return specForm;
|
||||
return $"{nickname} ({specForm})";
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ public static class BatchEditing
|
|||
{
|
||||
public static readonly Type[] Types =
|
||||
[
|
||||
typeof (PK9),
|
||||
typeof (PK9), typeof (PA9),
|
||||
typeof (PK8), typeof (PA8), typeof (PB8),
|
||||
typeof (PB7),
|
||||
typeof (PK7), typeof (PK6), typeof (PK5), typeof (PK4), typeof(BK4), typeof(RK4),
|
||||
|
|
@ -30,7 +30,7 @@ public static class BatchEditing
|
|||
/// </summary>
|
||||
private static readonly string[] CustomProperties =
|
||||
[
|
||||
PROP_LEGAL, PROP_TYPENAME, PROP_RIBBONS, PROP_CONTESTSTATS, PROP_MOVEMASTERY,
|
||||
PROP_LEGAL, PROP_TYPENAME, PROP_RIBBONS, PROP_CONTESTSTATS, PROP_MOVEMASTERY, PROP_MOVEPLUS,
|
||||
PROP_TYPE1, PROP_TYPE2, PROP_TYPEEITHER,
|
||||
IdentifierContains, nameof(ISlotInfo.Slot), nameof(SlotInfoBox.Box),
|
||||
];
|
||||
|
|
@ -77,6 +77,7 @@ public static class BatchEditing
|
|||
internal const string PROP_EVS = "EVs";
|
||||
internal const string PROP_CONTESTSTATS = "ContestStats";
|
||||
internal const string PROP_MOVEMASTERY = "MoveMastery";
|
||||
internal const string PROP_MOVEPLUS = "PlusMoves";
|
||||
internal const string IdentifierContains = nameof(IdentifierContains);
|
||||
|
||||
private static string[][] GetPropArray<T>(Dictionary<string, T>.AlternateLookup<ReadOnlySpan<char>>[] types, ReadOnlySpan<string> extra)
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@ public static class BatchMods
|
|||
new ComplexSuggestion(nameof(PKM.CurrentLevel), (_, _, info) => BatchModifications.SetMinimumCurrentLevel(info)),
|
||||
new ComplexSuggestion(PROP_CONTESTSTATS, p => p is IContestStats, (_, value, info) => BatchModifications.SetContestStats(info.Entity, info.Legality, value)),
|
||||
new ComplexSuggestion(PROP_MOVEMASTERY, (_, value, info) => BatchModifications.SetSuggestedMasteryData(info, value)),
|
||||
new ComplexSuggestion(PROP_MOVEPLUS, (_, value, info) => BatchModifications.SetSuggestedMovePlusData(info, value)),
|
||||
];
|
||||
|
||||
private static DateOnly ParseDate(ReadOnlySpan<char> val) => DateOnly.ParseExact(val, "yyyyMMdd", CultureInfo.InvariantCulture);
|
||||
|
|
|
|||
|
|
@ -69,6 +69,28 @@ public static ModifyResult SetSuggestedMasteryData(BatchInfo info, ReadOnlySpan<
|
|||
return ModifyResult.Modified;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets all legal Plus Move flag data for the Entity.
|
||||
/// </summary>
|
||||
/// <remarks>Only applicable for <see cref="IPlusRecord"/>.</remarks>
|
||||
public static ModifyResult SetSuggestedMovePlusData(BatchInfo info, ReadOnlySpan<char> value)
|
||||
{
|
||||
var pk = info.Entity;
|
||||
if (pk is not IPlusRecord t || pk.PersonalInfo is not IPermitPlus p)
|
||||
return ModifyResult.Skipped;
|
||||
|
||||
PlusRecordApplicatorOption option;
|
||||
if (IsNone(value))
|
||||
option = PlusRecordApplicatorOption.None;
|
||||
else if (IsAll(value))
|
||||
option = PlusRecordApplicatorOption.LegalSeedTM;
|
||||
else
|
||||
option = PlusRecordApplicatorOption.LegalCurrent;
|
||||
|
||||
t.SetPlusFlags(p, option, info.Legality);
|
||||
return ModifyResult.Modified;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets suggested ribbon data for the Entity.
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -58,7 +58,8 @@ public static void SetAbility(this PKM pk, int abilityID)
|
|||
if (abilityID < 0)
|
||||
return;
|
||||
var index = pk.PersonalInfo.GetIndexOfAbility(abilityID);
|
||||
index = Math.Max(0, index);
|
||||
if (index < 0)
|
||||
return; // leave original value
|
||||
pk.SetAbilityIndex(index);
|
||||
}
|
||||
|
||||
|
|
@ -258,6 +259,13 @@ public static void ApplySetDetails(this PKM pk, IBattleTemplate set)
|
|||
t.ClearRecordFlags();
|
||||
t.SetRecordFlags(set.Moves, legal.Info.EvoChainsAllGens.Get(pk.Context));
|
||||
}
|
||||
|
||||
if (pk is IPlusRecord plus && pk.PersonalInfo is IPermitPlus permit)
|
||||
{
|
||||
plus.ClearPlusFlags(permit.PlusCountTotal);
|
||||
plus.SetPlusFlags(permit, legal, true, true);
|
||||
}
|
||||
|
||||
if (legal.Parsed && !MoveResult.AllValid(legal.Info.Relearn))
|
||||
pk.SetRelearnMoves(legal);
|
||||
pk.ResetPartyStats();
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ public static class Pokerus
|
|||
PA8 pa8 => HasVisitedAnother(pa8, enc),
|
||||
PB7 => false, // Does not exist in game.
|
||||
PK9 => false, // Does not exist in game, does not get copied over via HOME.
|
||||
PA9 => false, // Does not exist in game, does not get copied over via HOME.
|
||||
_ => true,
|
||||
};
|
||||
|
||||
|
|
@ -60,6 +61,7 @@ private static bool HasVisitedAnother(PA8 pk, ISpeciesForm enc)
|
|||
EntityContext.Gen7b => false,
|
||||
EntityContext.Gen8a => false,
|
||||
EntityContext.Gen9 => false,
|
||||
EntityContext.Gen9a => false,
|
||||
_ => true,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ public static PKM[] GetExtraPKM(this SaveFile sav, IReadOnlyList<SlotInfoMisc> s
|
|||
SAV8BS bs => GetExtraSlots8b(bs),
|
||||
SAV8LA la => GetExtraSlots8a(la),
|
||||
SAV9SV sv => GetExtraSlots9(sv),
|
||||
SAV9ZA za => GetExtraSlots9a(za),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
|
|
@ -240,4 +241,38 @@ private static List<SlotInfoMisc> GetExtraSlots9(SAV9SV sav)
|
|||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
private static List<SlotInfoMisc> GetExtraSlots9a(SAV9ZA sav)
|
||||
{
|
||||
var list = new List<SlotInfoMisc>();
|
||||
|
||||
var shinyCache = sav.Blocks.GetBlock(SaveBlockAccessor9ZA.KStoredShinyEntity);
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
const int size = 0x1F0;
|
||||
var ofs = (i * size) + 8;
|
||||
var entry = shinyCache.Raw.Slice(ofs, size);
|
||||
if (EntityDetection.IsPresent(entry.Span))
|
||||
list.Add(new(entry, i, true) { Type = StorageSlotType.Shiny, HideLegality = true }); // no OT info
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
var giveAway = sav.Blocks.GetBlock(SaveBlockAccessor9ZA.KStoredEventEntity);
|
||||
for (int i = 0; i < 128; i++)
|
||||
{
|
||||
const int size = 0x1A8;
|
||||
var ofs = (i * size) + 8;
|
||||
var entry = giveAway.Raw.Slice(ofs, PokeCrypto.SIZE_9PARTY);
|
||||
if (EntityDetection.IsPresent(entry.Span))
|
||||
list.Add(new(entry, i, true) { Type = StorageSlotType.Misc });
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
var block = sav.Blocks.GetBlock(SaveBlockAccessor9ZA.KFusedCalyrex);
|
||||
list.Add(new(block.Raw, 0, true) { Type = StorageSlotType.FusedCalyrex });
|
||||
|
||||
return list;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,8 @@ public enum StorageSlotType : byte
|
|||
Daycare,
|
||||
/// <summary> Global Trade Station (GTS) </summary>
|
||||
GTS,
|
||||
/// <summary> Shiny Overworld Cache </summary>
|
||||
Shiny,
|
||||
|
||||
/// <summary> Fused Legendary Storage </summary>
|
||||
FusedKyurem,
|
||||
|
|
|
|||
|
|
@ -233,6 +233,11 @@ public enum GameVersion : byte
|
|||
/// Pokémon Violet (NX)
|
||||
/// </summary>
|
||||
VL = 51,
|
||||
|
||||
/// <summary>
|
||||
/// Pokémon Legends: (Z-A) (NX)
|
||||
/// </summary>
|
||||
ZA = 52,
|
||||
#endregion
|
||||
|
||||
// The following values are not actually stored values in pk data,
|
||||
|
|
|
|||
|
|
@ -61,4 +61,9 @@ public enum LanguageID : byte
|
|||
/// Chinese Traditional (繁體中文)
|
||||
/// </summary>
|
||||
ChineseT = 10,
|
||||
|
||||
/// <summary>
|
||||
/// Spanish (LATAM)
|
||||
/// </summary>
|
||||
SpanishL = 11,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -925,5 +925,6 @@ public enum Move : ushort
|
|||
PsychicNoise,
|
||||
UpperHand,
|
||||
MalignantChain,
|
||||
NihilLight,
|
||||
MAX_COUNT,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ public FilteredGameDataSource(SaveFile sav, GameDataSource source, bool HaX = fa
|
|||
var gamelist = GameUtil.GetVersionsWithinRange(sav, sav.Generation).ToList();
|
||||
Games = Source.VersionDataSource.Where(g => gamelist.Contains((GameVersion)g.Value) || g.Value == 0).ToList();
|
||||
|
||||
Languages = Source.LanguageDataSource(sav.Generation);
|
||||
Languages = Source.LanguageDataSource(sav.Generation, sav.Context);
|
||||
Balls = Source.BallDataSource.Where(b => b.Value <= sav.MaxBallID).ToList();
|
||||
Abilities = Source.AbilityDataSource.Where(a => a.Value <= sav.MaxAbilityID).ToList();
|
||||
|
||||
|
|
@ -57,6 +57,7 @@ public FilteredGameDataSource(SaveFile sav, GameDataSource source, bool HaX = fa
|
|||
// BD/SP can be handled by <= MaxSpeciesID as it as no gaps in species availability.
|
||||
SAV8SWSH g8 => FilterUnavailable(result, g8.Personal),
|
||||
SAV9SV g9 => FilterUnavailable(result, g9.Personal),
|
||||
SAV9ZA za => FilterUnavailable(result, za.Personal),
|
||||
_ => FilterAbove(result, sav.MaxSpeciesID),
|
||||
};
|
||||
return result;
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ public sealed class GameDataSource
|
|||
(byte)LanguageID.Korean,
|
||||
(byte)LanguageID.ChineseS,
|
||||
(byte)LanguageID.ChineseT,
|
||||
(byte)LanguageID.SpanishL,
|
||||
];
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -36,11 +37,12 @@ public sealed class GameDataSource
|
|||
/// </summary>
|
||||
/// <param name="generation">Generation to get the language list for.</param>
|
||||
/// <returns>List of languages to display.</returns>
|
||||
public IReadOnlyList<ComboItem> LanguageDataSource(byte generation) => generation switch
|
||||
public IReadOnlyList<ComboItem> LanguageDataSource(byte generation, EntityContext context) => generation switch
|
||||
{
|
||||
3 => LanguageList[..6], // No Korean+
|
||||
< 7 => LanguageList[..7], // No Chinese+
|
||||
_ => [.. LanguageList],
|
||||
_ when context is EntityContext.Gen9a => [.. LanguageList],
|
||||
_ => [.. LanguageList.AsSpan(0, LanguageList.Length - 1)],
|
||||
};
|
||||
|
||||
public GameDataSource(GameStrings s)
|
||||
|
|
@ -97,6 +99,7 @@ public GameDataSource(GameStrings s)
|
|||
/// <remarks>Most recent games are at the top, loosely following Generation groups.</remarks>
|
||||
private static ReadOnlySpan<byte> OrderedVersionArray =>
|
||||
[
|
||||
52, // 9 Z-A
|
||||
50, 51, // 9 S/V
|
||||
47, // 8 PLA
|
||||
48, 49, // 8 BD/SP
|
||||
|
|
|
|||
|
|
@ -38,8 +38,8 @@ public static string GetVersionName(GameVersion version)
|
|||
return version.ToString();
|
||||
}
|
||||
|
||||
public static IReadOnlyList<ComboItem> LanguageDataSource(byte generation)
|
||||
=> Sources.LanguageDataSource(generation);
|
||||
public static IReadOnlyList<ComboItem> LanguageDataSource(byte generation, EntityContext context)
|
||||
=> Sources.LanguageDataSource(generation, context);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the location name for the specified parameters.
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ public sealed class GameStrings : IBasicStrings
|
|||
// Met Locations
|
||||
public readonly LocationSet0 Gen2, Gen3, CXD;
|
||||
public readonly LocationSet4 Gen4;
|
||||
public readonly LocationSet6 Gen5, Gen6, Gen7, Gen7b, Gen8, Gen8a, Gen8b, Gen9;
|
||||
public readonly LocationSet6 Gen5, Gen6, Gen7, Gen7b, Gen8, Gen8a, Gen8b, Gen9, Gen9a;
|
||||
|
||||
// Misc
|
||||
public readonly string[] wallpapernames, puffs, walkercourses;
|
||||
|
|
@ -143,6 +143,7 @@ internal GameStrings(string langFilePrefix)
|
|||
Gen8a = Get6("la");
|
||||
Gen8b = Get6("bdsp");
|
||||
Gen9 = Get6("sv");
|
||||
Gen9a = Get6("za");
|
||||
|
||||
Sanitize();
|
||||
|
||||
|
|
@ -282,6 +283,7 @@ private void SanitizeItemNames()
|
|||
|
||||
SanitizeItemsLA(itemlist);
|
||||
SanitizeItemsSV(itemlist);
|
||||
SanitizeItemsZA(itemlist);
|
||||
|
||||
if (Language is French)
|
||||
{
|
||||
|
|
@ -300,6 +302,26 @@ private void SanitizeItemNames()
|
|||
itemlist[1763] += " (LA)"; // Secret Medicine
|
||||
}
|
||||
|
||||
private void SanitizeItemsZA(Span<string> items)
|
||||
{
|
||||
// Seed of Mastery
|
||||
items[1622] += " (LA)";
|
||||
items[2558] += " (ZA)";
|
||||
// Canari Plushes
|
||||
Canari(items[2620..]); // Red
|
||||
Canari(items[2623..]); // Gold
|
||||
Canari(items[2626..]); // Pink
|
||||
Canari(items[2629..]); // Green
|
||||
Canari(items[2632..]); // Blue
|
||||
return;
|
||||
static void Canari(Span<string> arr)
|
||||
{
|
||||
arr[0] += " (1)";
|
||||
arr[1] += " (2)";
|
||||
arr[2] += " (3)";
|
||||
}
|
||||
}
|
||||
|
||||
private static void SanitizeItemsSV(Span<string> items)
|
||||
{
|
||||
items[2313] += " (1)"; // Academy Bottle
|
||||
|
|
@ -397,6 +419,7 @@ private void SanitizeMetLocations()
|
|||
SanitizeMetGen8a(Gen8a);
|
||||
SanitizeMetGen8b(Gen8b);
|
||||
SanitizeMetGen9(Gen9);
|
||||
SanitizeMetGen9a(Gen9a);
|
||||
|
||||
if (Language is Italian or Spanish)
|
||||
{
|
||||
|
|
@ -692,6 +715,15 @@ private void SanitizeMetGen9(LocationSet6 set)
|
|||
// set.Met3[18] += " (-)"; // Pokémon HOME -- duplicate with 40000's entry
|
||||
}
|
||||
|
||||
private static void SanitizeMetGen9a(LocationSet6 set)
|
||||
{
|
||||
// ZA: Truncated list to remove all after 235 (no encounters there).
|
||||
Deduplicate(set.Met0, 00000);
|
||||
Deduplicate(set.Met3, 30000);
|
||||
Deduplicate(set.Met4, 40000);
|
||||
Deduplicate(set.Met6, 60000);
|
||||
}
|
||||
|
||||
private static void Deduplicate(Span<string> arr, int group)
|
||||
{
|
||||
var counts = new Dictionary<string, int>();
|
||||
|
|
@ -737,6 +769,7 @@ private static void Deduplicate(Span<string> arr, int group)
|
|||
EntityContext.Gen4 => g4items, // mail names changed 4->5
|
||||
EntityContext.Gen8b => GetItemStrings8b(),
|
||||
EntityContext.Gen9 => GetItemStrings9(),
|
||||
EntityContext.Gen9a => GetItemStrings9a(),
|
||||
_ => itemlist,
|
||||
};
|
||||
|
||||
|
|
@ -778,6 +811,48 @@ static void InsertZero(Span<string> arr, string insert)
|
|||
}
|
||||
}
|
||||
|
||||
private string[] GetItemStrings9a()
|
||||
{
|
||||
// in Generation 9, TM #'s are padded to 3 digits; format them appropriately here
|
||||
var clone = (string[])itemlist.Clone();
|
||||
var span = clone.AsSpan();
|
||||
var zero = Language is Japanese or ChineseS or ChineseT ? '0' : '0';
|
||||
var prefix = span[328].AsSpan(0, 2);
|
||||
|
||||
InsertZero(prefix, span[328..420], zero, 1); // 01-92
|
||||
InsertZero(prefix, span[618..621], zero, 93); // 93-95
|
||||
InsertZero(prefix, span[690..694], zero, 96); // 96-99
|
||||
InsertZero(prefix, span[2160..2290], zero, 100); // 100-229
|
||||
return clone;
|
||||
|
||||
static void InsertZero(ReadOnlySpan<char> prefix, Span<string> arr, char zero, int start)
|
||||
{
|
||||
int i = 0;
|
||||
foreach (ref var item in arr)
|
||||
{
|
||||
var index = start + i;
|
||||
var remap = ItemConverter.RemapTechnicalMachineItemName9a;
|
||||
if (index >= remap.Length)
|
||||
break;
|
||||
index += remap[index];
|
||||
item = GetActualName(prefix, index, zero);
|
||||
i++;
|
||||
}
|
||||
arr[i..].Clear();
|
||||
}
|
||||
static string GetActualName(ReadOnlySpan<char> prefix, int value, char pad)
|
||||
{
|
||||
Span<char> buffer = stackalloc char[5];
|
||||
prefix.CopyTo(buffer);
|
||||
var arr = buffer[2..];
|
||||
arr.Fill(pad);
|
||||
arr[2] += (char)(value % 10); value /= 10;
|
||||
arr[1] += (char)(value % 10); value /= 10;
|
||||
arr[0] += (char)(value % 10);
|
||||
return new string(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
private string[] GetItemStrings3(GameVersion version)
|
||||
{
|
||||
switch (version)
|
||||
|
|
@ -869,6 +944,7 @@ private static byte GetGeneration(byte generation, bool isEggLocation, byte form
|
|||
8 when version is GameVersion.PLA => Gen8a,
|
||||
8 when GameVersion.BDSP.Contains(version) => Gen8b,
|
||||
8 => Gen8,
|
||||
9 when version is GameVersion.ZA => Gen9a,
|
||||
9 => Gen9,
|
||||
|
||||
_ => null,
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ public sealed class MetDataSource(GameStrings s)
|
|||
private readonly List<ComboItem> MetGen8a = CreateGen8a(s);
|
||||
private readonly List<ComboItem> MetGen8b = CreateGen8b(s);
|
||||
private readonly List<ComboItem> MetGen9 = CreateGen9(s);
|
||||
private readonly List<ComboItem> MetGen9a = CreateGen9a(s);
|
||||
|
||||
private IReadOnlyList<ComboItem>? MetGen4Transfer;
|
||||
private IReadOnlyList<ComboItem>? MetGen5Transfer;
|
||||
|
|
@ -150,6 +151,7 @@ private static List<ComboItem> CreateGen8(GameStrings s)
|
|||
locations.Add(new ComboItem(s.gamelist[(int)BD], LocationsHOME.SWBD));
|
||||
locations.Add(new ComboItem(s.gamelist[(int)SP], LocationsHOME.SHSP));
|
||||
locations.Add(new ComboItem(s.gamelist[(int)PLA], LocationsHOME.SWLA));
|
||||
// No backwards from ZA+
|
||||
|
||||
return locations;
|
||||
}
|
||||
|
|
@ -197,6 +199,18 @@ private static List<ComboItem> CreateGen9(GameStrings s)
|
|||
return locations;
|
||||
}
|
||||
|
||||
private static List<ComboItem> CreateGen9a(GameStrings s)
|
||||
{
|
||||
var locations = Util.GetCBList(s.Gen9a.Met0, 0);
|
||||
Util.AddCBWithOffset(locations, s.Gen9a.Met6, 60000, Locations.Daycare5);
|
||||
Util.AddCBWithOffset(locations, s.Gen9a.Met3, 30000, Locations.LinkTrade6);
|
||||
Util.AddCBWithOffset(locations, s.Gen9a.Met0, 00000, Locations9a.Met0);
|
||||
Util.AddCBWithOffset(locations, s.Gen9a.Met3, 30000, Locations9a.Met3);
|
||||
Util.AddCBWithOffset(locations, s.Gen9a.Met4, 40000, Locations9a.Met4);
|
||||
Util.AddCBWithOffset(locations, s.Gen9a.Met6, 60000, Locations9a.Met6);
|
||||
return locations;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fetches a Met Location list for a <see cref="version"/> that has been transferred away from and overwritten.
|
||||
/// </summary>
|
||||
|
|
@ -257,6 +271,7 @@ public IReadOnlyList<ComboItem> GetLocationList(GameVersion version, EntityConte
|
|||
BD or SP => Partition2(MetGen8b, IsMetLocation8BDSP),
|
||||
PLA => Partition2(MetGen8a, IsMetLocation8LA),
|
||||
SL or VL => Partition2(MetGen9, IsMetLocation9SV),
|
||||
ZA => Partition2(MetGen9a, IsMetLocation9ZA),
|
||||
_ => GetLocationListModified(version, context),
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -80,6 +80,8 @@ private static GameVersion[] GetValidGameVersions()
|
|||
|
||||
// Gen9
|
||||
SL or VL => SV,
|
||||
ZA => ZA,
|
||||
|
||||
_ => Invalid,
|
||||
};
|
||||
|
||||
|
|
@ -130,7 +132,7 @@ public static byte GetGeneration(this GameVersion version)
|
|||
RD or GN or BU or YW => 1,
|
||||
GD or SI or C => 2,
|
||||
S or R or E or FR or LG or CXD => 3,
|
||||
D or P or Pt or HG or SS => 4,
|
||||
D or P or Pt or HG or SS or BATREV => 4,
|
||||
B or W or B2 or W2 => 5,
|
||||
X or Y or AS or OR => 6,
|
||||
GP or GE => 7,
|
||||
|
|
@ -140,6 +142,7 @@ public static byte GetGeneration(this GameVersion version)
|
|||
BD or SP => 8,
|
||||
SW or SH => 8,
|
||||
SL or VL => 9,
|
||||
ZA => 9,
|
||||
_ => 0
|
||||
};
|
||||
|
||||
|
|
@ -163,6 +166,7 @@ public static byte GetGeneration(this GameVersion version)
|
|||
BD or SP => Legal.MaxSpeciesID_8b,
|
||||
SW or SH => Legal.MaxSpeciesID_8,
|
||||
SL or VL => Legal.MaxSpeciesID_9,
|
||||
ZA => Legal.MaxSpeciesID_9a,
|
||||
_ => 0
|
||||
};
|
||||
|
||||
|
|
@ -189,7 +193,7 @@ public static bool Contains(this GameVersion g1, GameVersion g2)
|
|||
public static bool IsGen7(this GameVersion version) => version is SN or MN or US or UM;
|
||||
public static bool IsGen7b(this GameVersion version) => version is GP or GE;
|
||||
public static bool IsGen8(this GameVersion version) => version is SW or SH or PLA or BD or SP;
|
||||
public static bool IsGen9(this GameVersion version) => version is SL or VL;
|
||||
public static bool IsGen9(this GameVersion version) => version is SL or VL or ZA;
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the <see cref="lump"/> version is the lump of the requested saved <see cref="version"/>.
|
||||
|
|
@ -241,7 +245,7 @@ public static bool Contains(this GameVersion g1, GameVersion g2)
|
|||
Gen8 => version is SW or SH or BD or SP or SWSH or BDSP or PLA,
|
||||
|
||||
SV => version is SL or VL,
|
||||
Gen9 => version is SL or VL or SV,
|
||||
Gen9 => version is SL or VL or SV or ZA,
|
||||
|
||||
_ => false,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -170,4 +170,5 @@ public static bool IsEggLocationBred4(ushort loc, GameVersion version)
|
|||
public static bool IsMetLocation8BDSP(ushort z) => z <= 657; // Ramanas Park (Genome Room)
|
||||
public static bool IsMetLocation8LA(ushort z) => z <= 155; // Training Grounds
|
||||
public static bool IsMetLocation9SV(ushort z) => z <= 200; // Terarium (Entry Tunnel)
|
||||
public static bool IsMetLocation9ZA(ushort z) => z <= 235; // The Sewers
|
||||
}
|
||||
|
|
|
|||
|
|
@ -76,8 +76,8 @@ public static class Locations9
|
|||
40001, 40002, 40003, 40004, 40005, 40006, 40007, 40008, 40009,
|
||||
40010, 40011, 40012, 40013, 40014, 40015, 40016, 40017, 40018, 40019,
|
||||
40020, 40021, 40022, 40024, 40024, 40025, 40026, 40027, 40028, 40029,
|
||||
40030, 40032, 40033, 40034, 40035, 40036, 40037, 40038, 40039, 40039,
|
||||
40040, 40041, 40042, 40043, 40044, 40045, 40047, 40047, 40048, 40049,
|
||||
40030, 40032, 40033, 40034, 40035, 40036, 40037, 40038, 40039,
|
||||
40040, 40041, 40042, 40043, 40044, 40045, 40046, 40047, 40048, 40049,
|
||||
40050, 40051, 40052, 40053, 40054, 40055, 40056, 40057, 40058, 40059,
|
||||
40060, 40061, 40062, 40063, 40064, 40065, 40066, 40067, 40068, 40069,
|
||||
40070, 40071, 40072, 40073, 40074, 40075, 40076, 40077, 40078,
|
||||
|
|
|
|||
69
PKHeX.Core/Game/Locations/Locations9a.cs
Normal file
69
PKHeX.Core/Game/Locations/Locations9a.cs
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
using System;
|
||||
|
||||
namespace PKHeX.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Locations for <see cref="GameVersion.ZA"/>.
|
||||
/// </summary>
|
||||
internal static class Locations9a
|
||||
{
|
||||
public static ReadOnlySpan<ushort> Met0 =>
|
||||
[
|
||||
002, 004, 006, 007, 008, 009,
|
||||
010, 011, 012, 013, 014, 015, 016, 017, 018, 019,
|
||||
020, 021, 022, 023, 024, 025, 026, 027, 028, 029,
|
||||
030, 031, 032, 033, 034, 035, 036, 037, 038, 039,
|
||||
040, 041, 042, 043, 044, 045, 046, 047, 048, 049,
|
||||
050, 051, 052, 053, 054, 055, 056, 057, 058, 059,
|
||||
060, 061, 062, 063, 064, 065, 066, 067, 068, 069,
|
||||
070, 071, 072, 073, 074, 075, 076, 077, 078, 079,
|
||||
080, 081, 082, 083, 084, 085, 086, 087, 088, 089,
|
||||
090, 091, 092, 093, 094, 095, 096, 097, 098, 099,
|
||||
100, 101, 102, 103, 104, 105, 106, 107, 108, 109,
|
||||
110, 111, 112, 113, 114, 115, 116, 117, 118, 119,
|
||||
120, 121, 122, 123, 124, 125, 126, 127, 128, 129,
|
||||
130, 131, 132, 133, 134, 135, 136, 137, 138, 139,
|
||||
140, 141, 142, 143, 144, 145, 146, 147, 148, 149,
|
||||
150, 151, 152, 153, 154, 155, 156, 157, 158, 159,
|
||||
160, 161, 162, 163, 164, 165, 166, 167, 168, 169,
|
||||
170, 171, 172, 173, 174, 175, 176, 177, 178, 179,
|
||||
180, 181, 182, 183, 184, 185, 186, 187, 188, 189,
|
||||
190, 191, 192, 193, 194, 195, 196, 197, 198, 199,
|
||||
200, 201, 202, 203, 204, 205, 206, 207, 208, 209,
|
||||
210, 211, 212, 213, 214, 215, 216, 217, 218, 219,
|
||||
220, 221, 222, 223, 224, 225, 226, 227, 228, 229,
|
||||
230, 231, 232, 233, 234, 235,
|
||||
];
|
||||
|
||||
/// <summary>
|
||||
/// Available location list for the 30000 set of location names.
|
||||
/// </summary>
|
||||
public static ReadOnlySpan<ushort> Met3 =>
|
||||
[
|
||||
30001, 30003, 30004, 30005, 30006, 30007, 30008, 30009,
|
||||
30010, 30011, 30012, 30013, 30014, 30015, 30016, 30017, 30018, 30019,
|
||||
30020, 30021, 30022, 30023, 30024, 30025, 30026, 30027, 30028, 30029,
|
||||
30030, 30031, 30032,
|
||||
];
|
||||
|
||||
/// <summary>
|
||||
/// Available location list for the 40000 set of location names.
|
||||
/// </summary>
|
||||
public static ReadOnlySpan<ushort> Met4 =>
|
||||
[
|
||||
40001, 40002, 40003, 40005, 40006, 40007, 40008, 40009,
|
||||
40010, 40011, 40012, 40014, 40015, 40016, 40017, 40018,
|
||||
40020, 40021, 40022, 40024, 40024, 40026, 40027, 40029,
|
||||
40030, 40031, 40032, 40033, 40034, 40035, 40036, 40037, 40039,
|
||||
40040, 40041, 40042, 40043, 40045, 40046, 40047, 40048, 40049,
|
||||
40051, 40052, 40053, 40054, 40055, 40056, 40057, 40058,
|
||||
40060, 40061, 40062, 40063, 40064, 40065, 40066, 40067, 40068, 40069,
|
||||
40070,
|
||||
];
|
||||
|
||||
/// <summary>
|
||||
/// Available location list for the 60000 set of location names.
|
||||
/// </summary>
|
||||
public static ReadOnlySpan<ushort> Met6 => [ /* X/Y */ 60001, 60003, /* OR/AS */ 60004, /* Z-A */ 60005];
|
||||
}
|
||||
}
|
||||
|
|
@ -172,14 +172,6 @@ public sealed class ItemStorage9SV : IItemStorage
|
|||
InventoryType.Ingredients, InventoryType.Candy,
|
||||
];
|
||||
|
||||
private static ReadOnlySpan<InventoryType> ValidHeldTypes =>
|
||||
[
|
||||
InventoryType.Items,
|
||||
InventoryType.TMHMs,
|
||||
InventoryType.Medicine, InventoryType.Berries, InventoryType.Balls, InventoryType.BattleItems,
|
||||
InventoryType.Treasure,
|
||||
];
|
||||
|
||||
public static ReadOnlySpan<ushort> Unreleased =>
|
||||
[
|
||||
0016, // Cherish Ball
|
||||
|
|
@ -240,27 +232,7 @@ public bool IsLegal(InventoryType type, int itemIndex, int itemCount)
|
|||
_ => throw new ArgumentOutOfRangeException(nameof(type)),
|
||||
};
|
||||
|
||||
public static ushort[] GetAllHeld()
|
||||
{
|
||||
var valid = ValidHeldTypes;
|
||||
var sum = 0;
|
||||
foreach (var type in valid)
|
||||
sum += GetLegal(type).Length;
|
||||
|
||||
var result = new ushort[sum];
|
||||
LoadAllHeld(valid, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
private static void LoadAllHeld(ReadOnlySpan<InventoryType> valid, Span<ushort> dest)
|
||||
{
|
||||
foreach (var type in valid)
|
||||
{
|
||||
var legal = GetLegal(type);
|
||||
legal.CopyTo(dest);
|
||||
dest = dest[legal.Length..];
|
||||
}
|
||||
}
|
||||
public static ushort[] GetAllHeld() => [..Other, ..Machine, ..Medicine, ..Berry, ..Balls, ..Battle, ..Treasure];
|
||||
|
||||
public static InventoryType GetInventoryPouch(ushort itemIndex)
|
||||
{
|
||||
|
|
|
|||
236
PKHeX.Core/Items/ItemStorage9ZA.cs
Normal file
236
PKHeX.Core/Items/ItemStorage9ZA.cs
Normal file
|
|
@ -0,0 +1,236 @@
|
|||
using System;
|
||||
using static PKHeX.Core.Species;
|
||||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
public sealed class ItemStorage9ZA : IItemStorage
|
||||
{
|
||||
public static readonly ItemStorage9ZA Instance = new();
|
||||
|
||||
public static ReadOnlySpan<ushort> Medicine => // 0
|
||||
[
|
||||
0017, 0018, 0019, 0020, 0021, 0022, 0023, 0024, 0025, 0026,
|
||||
0027, 0028, 0029, 0030, 0031, 0032, 0033, 0708,
|
||||
];
|
||||
|
||||
public static ReadOnlySpan<ushort> Balls => // 1
|
||||
[
|
||||
0001, 0002, 0003, 0004, 0005, 0006, 0007, 0008, 0009, 0010,
|
||||
0011, 0012, 0013, 0014, 0015, 0016, 0492, 0493, 0494, 0495,
|
||||
0496, 0497, 0498, 0499, 0576, 0851,
|
||||
];
|
||||
|
||||
public static ReadOnlySpan<ushort> Other => // 2 (Items)
|
||||
[
|
||||
0045, 0046, 0047, 0048, 0049, 0050, 0052, 0080, 0081, 0082,
|
||||
0083, 0084, 0085, 0103, 0107, 0108, 0109, 0214, 0217, 0218,
|
||||
0221, 0222, 0230, 0231, 0232, 0233, 0234, 0236, 0237, 0238,
|
||||
0239, 0240, 0241, 0242, 0243, 0244, 0245, 0246, 0247, 0248,
|
||||
0249, 0250, 0251, 0253, 0266, 0267, 0268, 0270, 0275, 0289,
|
||||
0290, 0291, 0292, 0293, 0294, 0296, 0538, 0540, 0564, 0565,
|
||||
0566, 0567, 0568, 0569, 0570, 0639, 0640, 0646, 0647, 0710,
|
||||
0711, 0795, 0796, 0849, 1124, 1125, 1126, 1127, 1128, 1231,
|
||||
1232, 1233, 1234, 1235, 1236, 1237, 1238, 1239, 1240, 1241,
|
||||
1242, 1243, 1244, 1245, 1246, 1247, 1248, 1249, 1250, 1251,
|
||||
1582, 1592, 2401, 2558, 2618, 2619, // Colorful Screw cannot be held.
|
||||
];
|
||||
|
||||
public static ReadOnlySpan<ushort> Treasure => // 3
|
||||
[
|
||||
0086, 0088, 0089, 0092, 0571, 0581, 0582,
|
||||
];
|
||||
|
||||
public static ReadOnlySpan<ushort> Key => // 4
|
||||
[
|
||||
0632, 0700, 0765, 0847, 2588, 2589, 2590, 2591, 2592, 2595,
|
||||
2596, 2597, 2598, 2599, 2600, 2620, 2621, 2622, 2623, 2624,
|
||||
2625, 2626, 2627, 2628, 2629, 2630, 2631, 2632, 2633, 2634,
|
||||
|
||||
];
|
||||
|
||||
public static ReadOnlySpan<ushort> Berry => // 5
|
||||
[
|
||||
0149, 0150, 0151, 0152, 0153, 0155, 0156, 0157, 0158, 0169,
|
||||
0170, 0171, 0172, 0173, 0174, 0184, 0185, 0186, 0187, 0188,
|
||||
0189, 0190, 0191, 0192, 0193, 0194, 0195, 0196, 0197, 0198,
|
||||
0199, 0200, 0686,
|
||||
];
|
||||
|
||||
public static ReadOnlySpan<ushort> TM => // 6
|
||||
[
|
||||
0328, 0329, 0330, 0331, 0332, 0333, 0334, 0335, 0336, 0337,
|
||||
0338, 0339, 0340, 0341, 0342, 0343, 0344, 0345, 0346, 0347,
|
||||
0348, 0349, 0350, 0351, 0352, 0353, 0354, 0355, 0356, 0357,
|
||||
0358, 0359, 0360, 0361, 0362, 0363, 0364, 0365, 0366, 0367,
|
||||
0368, 0369, 0370, 0371, 0372, 0373, 0374, 0375, 0376, 0377,
|
||||
0378, 0379, 0380, 0381, 0382, 0383, 0384, 0385, 0386, 0387,
|
||||
0388, 0389, 0390, 0391, 0392, 0393, 0394, 0395, 0396, 0397,
|
||||
0398, 0399, 0400, 0401, 0402, 0403, 0404, 0405, 0406, 0407,
|
||||
0408, 0409, 0410, 0411, 0412, 0413, 0414, 0415, 0416, 0417,
|
||||
0418, 0419, 0618, 0619, 0620, 0690, 0691, 0692, 0693, 2160,
|
||||
2162, 2163, 2164, 2165, 2166, 2167, 2168,
|
||||
];
|
||||
|
||||
public static ReadOnlySpan<ushort> MegaStones => // 7
|
||||
[
|
||||
0656, 0657, 0658, 0659, 0660, 0661, 0662, 0663, 0665, 0666,
|
||||
0667, 0668, 0669, 0670, 0671, 0672, 0673, 0674, 0675, 0676,
|
||||
0677, 0678, 0679, 0680, 0681, 0682, 0683, 0754, 0755, 0756,
|
||||
0757, 0758, 0759, 0760, 0761, 0762, 0763, 0764, 0767, 0768,
|
||||
0769, 0770, 2559, 2560, 2561, 2562, 2563, 2564, 2565, 2566,
|
||||
2569, 2570, 2571, 2572, 2573, 2574, 2575, 2576, 2577, 2578,
|
||||
2579, 2580, 2581, 2582, 2583, 2584, 2585, 2587,
|
||||
];
|
||||
|
||||
internal static ReadOnlySpan<InventoryType> ValidTypes =>
|
||||
[
|
||||
// Display Order
|
||||
InventoryType.Medicine,
|
||||
InventoryType.Balls,
|
||||
InventoryType.Berries,
|
||||
InventoryType.Items, // Other
|
||||
InventoryType.TMHMs,
|
||||
InventoryType.MegaStones,
|
||||
InventoryType.Treasure,
|
||||
InventoryType.KeyItems,
|
||||
];
|
||||
|
||||
public static ReadOnlySpan<ushort> Unreleased =>
|
||||
[
|
||||
0005, // Safari Ball
|
||||
0499, // Sport Ball (first Season end reward)
|
||||
|
||||
0662, // Mewtwonite X
|
||||
0663, // Mewtwonite Y
|
||||
0764, // Diancite
|
||||
|
||||
0576, // Dream Ball
|
||||
|
||||
0851, // Beast Ball
|
||||
|
||||
2575, // Chesnaughtite
|
||||
2576, // Delphoxite
|
||||
];
|
||||
|
||||
public int GetMax(InventoryType type) => type switch
|
||||
{
|
||||
InventoryType.Medicine => 999,
|
||||
InventoryType.Balls => 999,
|
||||
InventoryType.Berries => 999,
|
||||
InventoryType.Items => 999, // Other
|
||||
InventoryType.TMHMs => 1,
|
||||
InventoryType.MegaStones => 1,
|
||||
InventoryType.Treasure => 999,
|
||||
InventoryType.KeyItems => 1,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(type)),
|
||||
};
|
||||
|
||||
public bool IsLegal(InventoryType type, int itemIndex, int itemCount) => !Unreleased.Contains((ushort)itemIndex);
|
||||
|
||||
public ReadOnlySpan<ushort> GetItems(InventoryType type) => GetLegal(type);
|
||||
|
||||
public static ReadOnlySpan<ushort> GetLegal(InventoryType type) => type switch
|
||||
{
|
||||
InventoryType.Medicine => Medicine,
|
||||
InventoryType.Balls => Balls,
|
||||
InventoryType.Berries => Berry,
|
||||
InventoryType.Items => Other,
|
||||
InventoryType.TMHMs => TM,
|
||||
InventoryType.MegaStones => MegaStones,
|
||||
InventoryType.Treasure => Treasure,
|
||||
InventoryType.KeyItems => Key,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(type)),
|
||||
};
|
||||
|
||||
public static ushort[] GetAllHeld() => [..Medicine, ..Balls, ..Berry, ..MegaStones, ..Treasure, ..Other[..^1]]; // Exclude Colorful Screw
|
||||
|
||||
public static InventoryType GetInventoryPouch(ushort itemIndex)
|
||||
{
|
||||
foreach (var type in ValidTypes)
|
||||
{
|
||||
var legal = GetLegal(type);
|
||||
if (legal.Contains(itemIndex))
|
||||
return type;
|
||||
}
|
||||
return InventoryType.None;
|
||||
}
|
||||
|
||||
public static bool IsMegaStone(ushort item) => MegaStones.Contains(item);
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves the expected Mega Stone item ID for a given Pokémon species and form.
|
||||
/// </summary>
|
||||
/// <returns>0 if no item is expected for this species and form combination (in other words, not a mega form).</returns>
|
||||
public static ushort GetExpectedMegaStone(ushort species, byte form) => (Species)species switch
|
||||
{
|
||||
Gengar when form == 1 => 0656,
|
||||
Gardevoir when form == 1 => 0657,
|
||||
Ampharos when form == 1 => 0658,
|
||||
Venusaur when form == 1 => 0659,
|
||||
Charizard when form == 1 => 0660, // X
|
||||
Blastoise when form == 1 => 0661,
|
||||
Mewtwo when form == 1 => 0662, // X
|
||||
Mewtwo when form == 2 => 0663, // Y
|
||||
Medicham when form == 1 => 0665,
|
||||
Houndoom when form == 1 => 0666,
|
||||
Aggron when form == 1 => 0667,
|
||||
Banette when form == 1 => 0668,
|
||||
Tyranitar when form == 1 => 0669,
|
||||
Scizor when form == 1 => 0670,
|
||||
Pinsir when form == 1 => 0671,
|
||||
Aerodactyl when form == 1 => 0672,
|
||||
Lucario when form == 1 => 0673,
|
||||
Abomasnow when form == 1 => 0674,
|
||||
Kangaskhan when form == 1 => 0675,
|
||||
Gyarados when form == 1 => 0676,
|
||||
Absol when form == 1 => 0677,
|
||||
Charizard when form == 2 => 0678, // Y
|
||||
Alakazam when form == 1 => 0679,
|
||||
Heracross when form == 1 => 0680,
|
||||
Mawile when form == 1 => 0681,
|
||||
Manectric when form == 1 => 0682,
|
||||
Garchomp when form == 1 => 0683,
|
||||
Sableye when form == 1 => 0754,
|
||||
Altaria when form == 1 => 0755,
|
||||
Gallade when form == 1 => 0756,
|
||||
Audino when form == 1 => 0757,
|
||||
Metagross when form == 1 => 0758,
|
||||
Sharpedo when form == 1 => 0759,
|
||||
Slowbro when form == 1 => 0760,
|
||||
Steelix when form == 1 => 0761,
|
||||
Pidgeot when form == 1 => 0762,
|
||||
Glalie when form == 1 => 0763,
|
||||
Diancie when form == 1 => 0764,
|
||||
Camerupt when form == 1 => 0767,
|
||||
Lopunny when form == 1 => 0768,
|
||||
Salamence when form == 1 => 0769,
|
||||
Beedrill when form == 1 => 0770,
|
||||
Clefable when form == 1 => 2559,
|
||||
Victreebel when form == 1 => 2560,
|
||||
Starmie when form == 1 => 2561,
|
||||
Dragonite when form == 1 => 2562,
|
||||
Meganium when form == 1 => 2563,
|
||||
Feraligatr when form == 1 => 2564,
|
||||
Skarmory when form == 1 => 2565,
|
||||
Froslass when form == 1 => 2566,
|
||||
Emboar when form == 1 => 2569,
|
||||
Excadrill when form == 1 => 2570,
|
||||
Scolipede when form == 1 => 2571,
|
||||
Scrafty when form == 1 => 2572,
|
||||
Eelektross when form == 1 => 2573,
|
||||
Chandelure when form == 1 => 2574,
|
||||
Chesnaught when form == 1 => 2575,
|
||||
Delphox when form == 1 => 2576,
|
||||
Greninja when form == 3 => 2577,
|
||||
Pyroar when form == 1 => 2578,
|
||||
Floette when form == 6 => 2579,
|
||||
Malamar when form == 1 => 2580,
|
||||
Barbaracle when form == 1 => 2581,
|
||||
Dragalge when form == 1 => 2582,
|
||||
Hawlucha when form == 1 => 2583,
|
||||
Zygarde when form == 5 => 2584,
|
||||
Drampa when form == 1 => 2585,
|
||||
Falinks when form == 1 => 2587,
|
||||
_ => 0,
|
||||
};
|
||||
}
|
||||
|
|
@ -80,7 +80,7 @@ public static byte[] Write32(byte[][] data, ReadOnlySpan<byte> identifier, int p
|
|||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
// Write File Offset
|
||||
var fileOffset = (ms.Position - start) + dataOffset;
|
||||
var fileOffset = bw.BaseStream.Length - start;
|
||||
bw.Seek(start + 4 + (i * sizeof(uint)), SeekOrigin.Begin);
|
||||
bw.Write((uint)fileOffset);
|
||||
// Write File to Stream
|
||||
|
|
@ -94,8 +94,12 @@ public static byte[] Write32(byte[][] data, ReadOnlySpan<byte> identifier, int p
|
|||
}
|
||||
|
||||
// Cap the File
|
||||
bw.Seek(start + 4 + (count * sizeof(uint)), SeekOrigin.Begin);
|
||||
bw.Write((uint)((ms.Position - start) + dataOffset));
|
||||
{
|
||||
var fileOffset = bw.BaseStream.Length - start;
|
||||
bw.Seek(start + 4 + (count * sizeof(uint)), SeekOrigin.Begin);
|
||||
bw.Write((uint)fileOffset);
|
||||
}
|
||||
|
||||
// Return the byte array
|
||||
return ms.ToArray();
|
||||
}
|
||||
|
|
@ -121,7 +125,7 @@ public static byte[] Write16(byte[][] data, ReadOnlySpan<byte> identifier, int p
|
|||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
// Write File Offset
|
||||
var fileOffset = ((ms.Position - start) + dataOffset);
|
||||
var fileOffset = bw.BaseStream.Length - start;
|
||||
bw.Seek(start + 4 + (i * sizeof(ushort)), SeekOrigin.Begin);
|
||||
bw.Write((ushort)fileOffset);
|
||||
// Write File to Stream
|
||||
|
|
@ -135,8 +139,12 @@ public static byte[] Write16(byte[][] data, ReadOnlySpan<byte> identifier, int p
|
|||
}
|
||||
|
||||
// Cap the File
|
||||
bw.Seek(start + 4 + (count * sizeof(ushort)), SeekOrigin.Begin);
|
||||
bw.Write((ushort)((ms.Position - start) + dataOffset));
|
||||
{
|
||||
var fileOffset = bw.BaseStream.Length - start;
|
||||
bw.Seek(start + 4 + (count * sizeof(ushort)), SeekOrigin.Begin);
|
||||
bw.Write((ushort)fileOffset);
|
||||
}
|
||||
|
||||
// Return the byte array
|
||||
return ms.ToArray();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ public static class Breeding
|
|||
/// <summary>
|
||||
/// Checks if the species <see cref="encryptionConstant"/> is valid for the <see cref="gender"/> if originated from Gen3/4 daycare eggs.
|
||||
/// </summary>
|
||||
/// <remarks>Only applies to species that satisfy <see cref="IsGenderSpeciesDetermination"/>.</remarks>
|
||||
/// <param name="encryptionConstant">Encryption Constant</param>
|
||||
/// <param name="gender">Gender</param>
|
||||
/// <returns>True if valid</returns>
|
||||
|
|
@ -129,6 +130,8 @@ public static bool CanHatchAsEgg(ushort species, byte form, EntityContext contex
|
|||
/// <summary>
|
||||
/// Some species can have forms that cannot exist as egg (event/special forms). Same idea as <see cref="FormInfo.IsTotemForm(ushort,byte,EntityContext)"/>
|
||||
/// </summary>
|
||||
/// <param name="species">Current species</param>
|
||||
/// <param name="form">Current form, not 0.</param>
|
||||
/// <returns>True if it can be bred.</returns>
|
||||
private static bool IsBreedableForm(ushort species, byte form) => species switch
|
||||
{
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ public sealed class BulkAnalysis
|
|||
public readonly ITrainerInfo Trainer;
|
||||
public readonly List<BulkCheckResult> Parse = [];
|
||||
public readonly Dictionary<ulong, (SlotCache Slot, int Index)> Trackers = [];
|
||||
public readonly bool Valid;
|
||||
public bool Valid => Parse.Count == 0 || Parse.TrueForAll(static z => z.Result.Valid);
|
||||
|
||||
public readonly BulkAnalysisSettings Settings;
|
||||
private readonly bool[] CloneFlags;
|
||||
|
|
@ -32,6 +32,7 @@ public sealed class BulkAnalysis
|
|||
|
||||
public BulkAnalysis(SaveFile sav, BulkAnalysisSettings settings) : this(GetSlots(sav), settings, sav)
|
||||
{
|
||||
RunSaveSpecificChecks();
|
||||
}
|
||||
|
||||
public BulkAnalysis(IEnumerable<SlotCache> source, BulkAnalysisSettings settings, ITrainerInfo tr) : this(GetSlots(source), settings, tr)
|
||||
|
|
@ -47,7 +48,6 @@ private BulkAnalysis(List<SlotCache> list, BulkAnalysisSettings settings, ITrain
|
|||
CloneFlags = new bool[AllData.Count];
|
||||
|
||||
ScanAll();
|
||||
Valid = Parse.Count == 0 || Parse.TrueForAll(static z => z.Result.Valid);
|
||||
}
|
||||
|
||||
private static List<SlotCache> GetSlots(SaveFile sav)
|
||||
|
|
@ -97,6 +97,12 @@ private static bool IsEmptyData(SlotCache obj)
|
|||
new DuplicateGiftChecker(),
|
||||
];
|
||||
|
||||
private static readonly List<IBulkAnalyzer> SaveAnalyzers =
|
||||
[
|
||||
new DuplicateFusionChecker(),
|
||||
new DuplicateMegaChecker(),
|
||||
];
|
||||
|
||||
private void ScanAll()
|
||||
{
|
||||
foreach (var analyzer in Analyzers)
|
||||
|
|
@ -105,6 +111,12 @@ private void ScanAll()
|
|||
analyzer.Analyze(this);
|
||||
}
|
||||
|
||||
private void RunSaveSpecificChecks()
|
||||
{
|
||||
foreach (var analyzer in SaveAnalyzers)
|
||||
analyzer.Analyze(this);
|
||||
}
|
||||
|
||||
private static string GetSummary(SlotCache entry) => $"[{entry.Identify()}]";
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -143,6 +155,8 @@ private void ScanAll()
|
|||
Parse.Add(new(chk, line, index1, index2));
|
||||
}
|
||||
|
||||
public void AddMessage(string message, CheckResult chk, int index = BulkCheckResult.NoIndex) => Parse.Add(new(chk, message, index));
|
||||
|
||||
public void AddExternal(SlotCache first, CheckIdentifier id, int index1, ushort identity, ushort argument = 0, Severity s = Severity.Invalid)
|
||||
=> AddLine(first, id, index1, LegalityCheckResultCode.External, identity, argument, s);
|
||||
|
||||
|
|
@ -163,22 +177,27 @@ private static LegalityAnalysis[] GetIndividualAnalysis(ReadOnlySpan<SlotCache>
|
|||
public string Report(LegalityLocalizationSet localization)
|
||||
{
|
||||
var sb = new StringBuilder(1024);
|
||||
var context = LegalityLocalizationContext.Create(AllAnalysis[0], localization);
|
||||
foreach (var (chk, comment, index1, index2) in Parse)
|
||||
{
|
||||
if (sb.Length != 0)
|
||||
sb.AppendLine(); // gap for next result
|
||||
|
||||
var code = chk.Result;
|
||||
string template;
|
||||
if (code is LegalityCheckResultCode.External)
|
||||
template = ExternalBulkCheck.Localize(chk, localization, AllAnalysis, index1, index2);
|
||||
{
|
||||
var judge = localization.Description(chk.Judgement);
|
||||
var template = ExternalBulkCheck.Localize(chk, localization, AllAnalysis, index1, index2);
|
||||
sb.AppendFormat(localization.Lines.F0_1, judge, template);
|
||||
}
|
||||
else
|
||||
template = code.GetTemplate(localization.Lines);
|
||||
var judge = localization.Description(chk.Judgement);
|
||||
sb.AppendFormat(localization.Lines.F0_1, judge, template);
|
||||
{
|
||||
sb.Append(context.Humanize(chk));
|
||||
}
|
||||
sb.AppendLine();
|
||||
|
||||
sb.AppendLine(comment);
|
||||
if (comment.Length != 0)
|
||||
sb.AppendLine(comment);
|
||||
}
|
||||
if (sb.Length == 0)
|
||||
sb.AppendLine(localization.Lines.Valid);
|
||||
|
|
|
|||
108
PKHeX.Core/Legality/Bulk/SaveFile/DuplicateFusionChecker.cs
Normal file
108
PKHeX.Core/Legality/Bulk/SaveFile/DuplicateFusionChecker.cs
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
using System;
|
||||
|
||||
namespace PKHeX.Core.Bulk;
|
||||
|
||||
public sealed class DuplicateFusionChecker : IBulkAnalyzer
|
||||
{
|
||||
/// <summary>
|
||||
/// <see cref="StorageSlotType"/>
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
public void Analyze(BulkAnalysis input)
|
||||
{
|
||||
if (input.Trainer is not SaveFile sav)
|
||||
return;
|
||||
|
||||
// Rule: Only 1 Fusion of each of the stored fused species.
|
||||
Span<int> seen = stackalloc int[4]; // 0: Kyurem, 1: Necrozma-Dawn, 2: Necrozma-Dusk, 3: Calyrex-Ice/Ghost
|
||||
const int seenNotSet = -1;
|
||||
seen.Fill(seenNotSet);
|
||||
|
||||
SearchForDuplicates(input, seen, seenNotSet);
|
||||
|
||||
// Rule: The consumed species to obtain (species, form) must be present in the save file's fused storage.
|
||||
if (seen.ContainsAnyExcept(seenNotSet))
|
||||
CheckConsumedSlots(input, sav, seen, seenNotSet);
|
||||
}
|
||||
|
||||
private static void SearchForDuplicates(BulkAnalysis input, Span<int> seen, int seenNotSet)
|
||||
{
|
||||
for (var i = 0; i < input.AllData.Count; i++)
|
||||
{
|
||||
var slot = input.AllData[i];
|
||||
var pk = slot.Entity;
|
||||
|
||||
var (species, form) = (pk.Species, pk.Form);
|
||||
if (form == 0) // eager check -- fused forms always have form > 0
|
||||
continue;
|
||||
|
||||
var index = GetIndexFusedStorage(species, form);
|
||||
if (index == -1)
|
||||
continue;
|
||||
|
||||
if (seen[index] != seenNotSet) // Already given to another slot.
|
||||
{
|
||||
var other = seen[index];
|
||||
input.AddLine(slot, input.AllData[other], CheckIdentifier.Form, i, index2: other, LegalityCheckResultCode.BulkDuplicateFusionSlot, species);
|
||||
continue;
|
||||
}
|
||||
|
||||
// First time seeing this Fusion, all good.
|
||||
seen[index] = i;
|
||||
}
|
||||
}
|
||||
|
||||
private static void CheckConsumedSlots(BulkAnalysis input, SaveFile sav, Span<int> seen, int seenNotSet)
|
||||
{
|
||||
// Check that fused species is present in the fused source
|
||||
var extraSlots = sav.GetExtraSlots();
|
||||
for (int i = 0; i < seen.Length; i++)
|
||||
{
|
||||
var index = seen[i];
|
||||
if (index == seenNotSet)
|
||||
continue;
|
||||
|
||||
var extra = extraSlots.Find(z => GetIndexFusedStorage(z.Type) == i);
|
||||
if (extra is null) // uhh? shouldn't be in this save file, will be flagged by regular legality check.
|
||||
continue;
|
||||
|
||||
var exist = input.AllData[index];
|
||||
var pk = exist.Entity;
|
||||
var form = pk.Form;
|
||||
|
||||
var source = extra.Read(sav);
|
||||
if (source.Form != 0 || !IsValidStoredBaseSpecies(i, source.Species, form))
|
||||
input.AddLine(exist, CheckIdentifier.Form, i, LegalityCheckResultCode.BulkFusionSourceInvalid, source.Species, source.Form);
|
||||
}
|
||||
}
|
||||
|
||||
private static int GetIndexFusedStorage(StorageSlotType type) => type switch
|
||||
{
|
||||
StorageSlotType.FusedKyurem => 0,
|
||||
StorageSlotType.FusedNecrozmaS => 1,
|
||||
StorageSlotType.FusedNecrozmaM => 2,
|
||||
StorageSlotType.FusedCalyrex => 3,
|
||||
_ => -1,
|
||||
};
|
||||
|
||||
// The games let you fuse two separate Necrozma with the box legends (N-Solarizer and N-Lunarizer).
|
||||
private static int GetIndexFusedStorage(ushort species, byte form) => (species, form) switch
|
||||
{
|
||||
((ushort)Species.Kyurem, _) => 0, // DNA Splicers
|
||||
((ushort)Species.Necrozma, 1) => 1, // N-Solarizer
|
||||
((ushort)Species.Necrozma, 2) => 2, // N-Lunarizer
|
||||
((ushort)Species.Calyrex, _) => 3, // Reins of Unity
|
||||
_ => -1,
|
||||
};
|
||||
|
||||
private static bool IsValidStoredBaseSpecies(int index, ushort consumedSpecies, byte resultForm) => index switch
|
||||
{
|
||||
0 when resultForm == 1 => consumedSpecies is (ushort)Species.Reshiram,
|
||||
0 when resultForm == 2 => consumedSpecies is (ushort)Species.Zekrom,
|
||||
1 => consumedSpecies is (ushort)Species.Solgaleo,
|
||||
2 => consumedSpecies is (ushort)Species.Lunala,
|
||||
3 when resultForm == 1 => consumedSpecies == (ushort)Species.Glastrier,
|
||||
3 when resultForm == 2 => consumedSpecies == (ushort)Species.Spectrier,
|
||||
_ => false,
|
||||
};
|
||||
}
|
||||
80
PKHeX.Core/Legality/Bulk/SaveFile/DuplicateMegaChecker.cs
Normal file
80
PKHeX.Core/Legality/Bulk/SaveFile/DuplicateMegaChecker.cs
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using static PKHeX.Core.LegalityCheckResultCode;
|
||||
|
||||
namespace PKHeX.Core.Bulk;
|
||||
|
||||
public sealed class DuplicateMegaChecker : IBulkAnalyzer
|
||||
{
|
||||
private const CheckIdentifier Identifier = CheckIdentifier.HeldItem;
|
||||
|
||||
public void Analyze(BulkAnalysis input)
|
||||
{
|
||||
if (input.Trainer is SAV9ZA za)
|
||||
AnalyzeInventory(input, za);
|
||||
else
|
||||
AnalyzeNoInventory(input);
|
||||
}
|
||||
|
||||
private static void AnalyzeInventory(BulkAnalysis input, SAV9ZA za)
|
||||
{
|
||||
var items = za.Items;
|
||||
|
||||
// Rule: Only 1 Mega Stone of a given Item ID may be held across all Pokémon, or present in the bag.
|
||||
Dictionary<ushort, int> seenStones = []; // ushort item, int index
|
||||
for (var i = 0; i < input.AllData.Count; i++)
|
||||
{
|
||||
var slot = input.AllData[i];
|
||||
var pk = slot.Entity;
|
||||
|
||||
var stone = (ushort)pk.HeldItem;
|
||||
if (!ItemStorage9ZA.IsMegaStone(stone))
|
||||
continue;
|
||||
|
||||
var item = items.GetItem(stone);
|
||||
if (item.Count == 0) // Not acquired by the save file, thus not able to be held.
|
||||
input.AddLine(slot, Identifier, BulkCheckResult.NoIndex, BulkNotAcquiredMegaStoneInventory, stone);
|
||||
else if (!item.IsHeld) // Not marked as held, so it's still "in the bag" (not given).
|
||||
input.AddLine(slot, Identifier, BulkCheckResult.NoIndex, BulkDuplicateMegaStoneInventory, stone);
|
||||
else if (seenStones.TryGetValue(stone, out var otherIndex)) // Already given to another slot.
|
||||
input.AddLine(slot, input.AllData[otherIndex], Identifier, i, index2: otherIndex, BulkDuplicateMegaStoneSlot, stone);
|
||||
else // First time seeing this Mega Stone, all good.
|
||||
seenStones[stone] = i;
|
||||
}
|
||||
|
||||
CheckOtherUnassigned(input, items, ItemStorage9ZA.MegaStones, seenStones);
|
||||
}
|
||||
|
||||
private static void CheckOtherUnassigned(BulkAnalysis input, MyItem9a items, ReadOnlySpan<ushort> megaStones, IReadOnlyDictionary<ushort, int> seenStones)
|
||||
{
|
||||
// Check that all other un-assigned stones are not marked as assigned.
|
||||
foreach (var stone in megaStones)
|
||||
{
|
||||
if (seenStones.ContainsKey(stone))
|
||||
continue;
|
||||
var item = items.GetItem(stone);
|
||||
if (item.IsHeld)
|
||||
input.AddMessage(string.Empty, CheckResult.Get(Severity.Invalid, CheckIdentifier.HeldItem, BulkAssignedMegaStoneNotFound_0, stone));
|
||||
}
|
||||
}
|
||||
|
||||
private static void AnalyzeNoInventory(BulkAnalysis input)
|
||||
{
|
||||
// Rule: Only 1 Mega Stone of a given Item ID may be held across all Pokémon, or present in the bag.
|
||||
Dictionary<ushort, int> seenStones = []; // ushort item, int index
|
||||
for (var i = 0; i < input.AllData.Count; i++)
|
||||
{
|
||||
var slot = input.AllData[i];
|
||||
var pk = slot.Entity;
|
||||
|
||||
var stone = (ushort)pk.HeldItem;
|
||||
if (!ItemStorage9ZA.IsMegaStone(stone))
|
||||
continue;
|
||||
|
||||
if (seenStones.TryGetValue(stone, out var otherIndex)) // Already given to another slot.
|
||||
input.AddLine(slot, input.AllData[otherIndex], Identifier, i, index2: otherIndex, BulkDuplicateMegaStoneSlot, stone);
|
||||
else // First time seeing this Mega Stone, all good.
|
||||
seenStones[stone] = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -40,6 +40,9 @@ public static class EncounterEvent
|
|||
|
||||
/// <summary>Event Database for Generation 9 <see cref="EntityContext.Gen9"/></summary>
|
||||
public static readonly WC9[] MGDB_G9 = GetWC9DB(Util.GetBinaryResource("wc9.pkl"));
|
||||
|
||||
/// <summary>Event Database for Generation 9 <see cref="EntityContext.Gen9a"/></summary>
|
||||
public static readonly WA9[] MGDB_G9A = GetWA9DB(Util.GetBinaryResource("wa9.pkl"));
|
||||
#endregion
|
||||
|
||||
#region Locally Loaded Data
|
||||
|
|
@ -55,20 +58,23 @@ public static class EncounterEvent
|
|||
/// <summary>Event Database for Generation 7</summary>
|
||||
public static WC7[] EGDB_G7 { get; private set; } = [];
|
||||
|
||||
/// <summary>Event Database for Generation 7 <see cref="GameVersion.GG"/></summary>
|
||||
/// <summary>Event Database for Generation 7 <see cref="EntityContext.Gen7b"/></summary>
|
||||
public static WB7[] EGDB_G7GG { get; private set; } = [];
|
||||
|
||||
/// <summary>Event Database for Generation 8</summary>
|
||||
/// <summary>Event Database for Generation 8 <see cref="EntityContext.Gen8"/></summary>
|
||||
public static WC8[] EGDB_G8 { get; private set; } = [];
|
||||
|
||||
/// <summary>Event Database for Generation 8 <see cref="GameVersion.PLA"/></summary>
|
||||
/// <summary>Event Database for Generation 8 <see cref="EntityContext.Gen8a"/></summary>
|
||||
public static WA8[] EGDB_G8A { get; private set; } = [];
|
||||
|
||||
/// <summary>Event Database for Generation 8 <see cref="GameVersion.BDSP"/></summary>
|
||||
/// <summary>Event Database for Generation 8 <see cref="EntityContext.Gen8b"/></summary>
|
||||
public static WB8[] EGDB_G8B { get; private set; } = [];
|
||||
|
||||
/// <summary>Event Database for Generation 9 <see cref="GameVersion.SV"/></summary>
|
||||
/// <summary>Event Database for Generation 9 <see cref="EntityContext.Gen9"/></summary>
|
||||
public static WC9[] EGDB_G9 { get; private set; } = [];
|
||||
|
||||
/// <summary>Event Database for Generation 9 <see cref="EntityContext.Gen9a"/></summary>
|
||||
public static WA9[] EGDB_G9A { get; private set; } = [];
|
||||
#endregion
|
||||
|
||||
private static PCD[] GetPCDDB(Memory<byte> bin) => Get(bin, PCD.Size, static d => new PCD(d));
|
||||
|
|
@ -82,6 +88,7 @@ public static class EncounterEvent
|
|||
private static WB8[] GetWB8DB(Memory<byte> bin) => Get(bin, WB8.Size, static d => new WB8(d));
|
||||
private static WA8[] GetWA8DB(Memory<byte> bin) => Get(bin, WA8.Size, static d => new WA8(d));
|
||||
private static WC9[] GetWC9DB(Memory<byte> bin) => Get(bin, WC9.Size, static d => new WC9(d));
|
||||
private static WA9[] GetWA9DB(Memory<byte> bin) => Get(bin, WA9.Size, static d => new WA9(d));
|
||||
|
||||
private static T[] Get<T>(Memory<byte> bin, int size, Func<Memory<byte>, T> ctor)
|
||||
{
|
||||
|
|
@ -114,6 +121,7 @@ public static void RefreshMGDB(params ReadOnlySpan<string> paths)
|
|||
HashSet<WB8>? b8 = null; List<WB8>? lb8 = null;
|
||||
HashSet<WA8>? a8 = null; List<WA8>? la8 = null;
|
||||
HashSet<WC9>? g9 = null; List<WC9>? lg9 = null;
|
||||
HashSet<WA9>? a9 = null; List<WA9>? la9 = null;
|
||||
|
||||
// Load external files
|
||||
// For each file, load the gift object into the appropriate list.
|
||||
|
|
@ -135,6 +143,7 @@ public static void RefreshMGDB(params ReadOnlySpan<string> paths)
|
|||
WB8 wb8 => AddOrExpand(ref b8, ref lb8, wb8),
|
||||
WA8 wa8 => AddOrExpand(ref a8, ref la8, wa8),
|
||||
WC9 wc9 => AddOrExpand(ref g9, ref lg9, wc9),
|
||||
WA9 wa9 => AddOrExpand(ref a9, ref la9, wa9),
|
||||
_ => false,
|
||||
};
|
||||
if (!added)
|
||||
|
|
@ -165,6 +174,7 @@ static bool AddOrExpand<T>([NotNullWhen(true)] ref HashSet<T>? arr, ref List<T>?
|
|||
EGDB_G8A = SetArray(la8);
|
||||
EGDB_G8B = SetArray(lb8);
|
||||
EGDB_G9 = SetArray(lg9);
|
||||
EGDB_G9A = SetArray(la9);
|
||||
return;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
|
|
|
|||
|
|
@ -28,6 +28,12 @@ public static ReadOnlySpan<byte> Get([ConstantExpected] string resource)
|
|||
public static BinLinkerAccessor Get([ConstantExpected] string resource, [Length(2, 2)] ReadOnlySpan<byte> ident)
|
||||
=> BinLinkerAccessor.Get(Get(resource), ident);
|
||||
|
||||
/// <summary>
|
||||
/// Gets an index-able accessor for the specified resource.
|
||||
/// </summary>
|
||||
public static BinLinkerAccessor16 Get16([ConstantExpected] string resource, [Length(2, 2)] ReadOnlySpan<byte> ident)
|
||||
=> BinLinkerAccessor16.Get(Get(resource), ident);
|
||||
|
||||
/// <summary>
|
||||
/// Grabs the localized names for individual templates for all languages from the specified <see cref="index"/> of the <see cref="names"/> list.
|
||||
/// </summary>
|
||||
|
|
|
|||
91
PKHeX.Core/Legality/Encounters/Data/Gen9/Encounters9a.cs
Normal file
91
PKHeX.Core/Legality/Encounters/Data/Gen9/Encounters9a.cs
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
using static PKHeX.Core.EncounterUtil;
|
||||
using static PKHeX.Core.Shiny;
|
||||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
internal static class Encounters9a
|
||||
{
|
||||
internal static readonly EncounterArea9a[] Slots = EncounterArea9a.GetAreas(Get16("za", "za"u8));
|
||||
|
||||
internal static readonly EncounterGift9a[] Gifts =
|
||||
[
|
||||
// Z-A Starters
|
||||
new(0152,0,05,128) { Location = 30026, FlawlessIVCount = 3, Moves = new(033,039,000,000) }, // Chikorita (test_encount_init_poke_0)
|
||||
new(0498,0,05,128) { Location = 30026, FlawlessIVCount = 3, Moves = new(033,039,000,000) }, // Tepig (test_encount_init_poke_1)
|
||||
new(0158,0,05,128) { Location = 30026, FlawlessIVCount = 3, Moves = new(033,043,000,000) }, // Totodile (test_encount_init_poke_2)
|
||||
|
||||
// Kanto Starters
|
||||
new(0001,0,05,000) { Location = 30027, FlawlessIVCount = 3 }, // Bulbasaur (sub_addpoke_fushigidane)
|
||||
new(0004,0,05,000) { Location = 30027, FlawlessIVCount = 3 }, // Charmander (sub_addpoke_hitokage)
|
||||
new(0007,0,05,000) { Location = 30027, FlawlessIVCount = 3 }, // Squirtle (sub_addpoke_zenigame)
|
||||
|
||||
// Kalos Starters
|
||||
new(0650,0,14,128) { Location = 30030, Gender = 1, Nature = Nature.Impish, IVs = new(31,31,31,15,15,15) }, // Chespin (sub_addpoke_harimaron)
|
||||
new(0653,0,14,128) { Location = 30031, Gender = 1, Nature = Nature.Lonely, IVs = new(15,15,15,31,31,31) }, // Fennekin (sub_addpoke_fokko)
|
||||
new(0656,0,14,128) { Location = 00069, Gender = 0, Nature = Nature.Sassy, IVs = new(15,31,15,31,31,15) }, // Froakie (sub_addpoke_keromatsu)
|
||||
|
||||
// Side Missions
|
||||
new(0618,1,38,128) { Location = 30028, Gender = 0, FlawlessIVCount = 3, Moves = new(319,334,089,340), Trainer = TrainerGift9a.Stunfisk }, // Stunfisk-1 (sub_addpoke_gmaggyo)
|
||||
new(0665,8,09,128) { Location = 30029, Gender = 0, Nature = Nature.Naive, FlawlessIVCount = 3 }, // Spewpa-8 (sub_addpoke_kofuurai)
|
||||
|
||||
// Eternal Flower Floette
|
||||
new(0670,5,72,128) { Location = 30026, Gender = 1, Nature = Nature.Modest, FlawlessIVCount = 3, Moves = new(617,412,202,235), Trainer = TrainerGift9a.Floette }, // Floette-5 (addpoke_floette_eien)
|
||||
|
||||
// Korrina's Lucario
|
||||
new(0448,0,50,128) { Location = 30026, Gender = 0, Nature = Nature.Hardy, IVs = new(31,20,31,20,20,31), Moves = new(396,418,249,182), Trainer = TrainerGift9a.Lucario }, // Lucario (sub_addpoke_rukario)
|
||||
|
||||
// Rogue Mega Absol
|
||||
new(0359,0,30,128) { Location = 30026, FlawlessIVCount = 3, Moves = new(400,163,098,014) }, // Absol (vsmega_init_abusoru)
|
||||
|
||||
// Fossils (Tutorial Revival)
|
||||
new(0696,0,20,128) { Location = 30027, FlawlessIVCount = 3, Moves = new(046,088,204,044) }, // Tyrunt (sub_addpoke_chigoras)
|
||||
new(0698,0,20,128) { Location = 30027, FlawlessIVCount = 3, Moves = new(088,196,036,054) }, // Amaura (sub_addpoke_amarus)
|
||||
|
||||
// Fossils
|
||||
new(0142,0,20,000) { Location = 30027, Shiny = Random }, // Aerodactyl (restoration_ptera)
|
||||
new(0696,0,20,000) { Location = 30027, Shiny = Random }, // Tyrunt (restoration_chigoras)
|
||||
new(0698,0,20,000) { Location = 30027, Shiny = Random }, // Amaura (restoration_amarus)
|
||||
|
||||
// Alpha Fossils
|
||||
new(0142,0,35,255) { Location = 30027, Shiny = Random, IsAlpha = true, FlawlessIVCount = 3 }, // Aerodactyl (restoration_ptera)
|
||||
new(0696,0,35,255) { Location = 30027, Shiny = Random, IsAlpha = true, FlawlessIVCount = 3 }, // Tyrunt (restoration_chigoras)
|
||||
new(0698,0,35,255) { Location = 30027, Shiny = Random, IsAlpha = true, FlawlessIVCount = 3 }, // Amaura (restoration_amarus)
|
||||
];
|
||||
|
||||
internal static readonly EncounterStatic9a[] Static =
|
||||
[
|
||||
// Legendary and Mythical Pokémon
|
||||
new(0716,0,75,128) { Location = 00210, FlawlessIVCount = 3, Moves = new(224,585,532,601) }, // Xerneas (m10_x)
|
||||
new(0717,0,75,128) { Location = 00075, FlawlessIVCount = 3, Moves = new(542,399,094,613) }, // Yveltal (m10_y)
|
||||
new(0718,2,84,128) { Location = 00212, Nature = Nature.Quiet, IVs = new(31,31,15,19,31,28), Moves = new(687,614,615,616) }, // Zygarde-2 (ect_boss_0718_01)
|
||||
|
||||
// Main Missions / Side Missions
|
||||
new(0013,0,45,255) { Location = 00055, Gender = 0, Nature = Nature.Naive, IsAlpha = true, FlawlessIVCount = 3 }, // Weedle (sub_023_oybn)
|
||||
new(0092,0,40,128) { Location = 00231 }, // Gastly (ect_d03_01_z092_ev)
|
||||
new(0094,0,42,128) { Location = 00231 }, // Gengar (ect_d03_01_z094_ev)
|
||||
new(0302,0,10,128) { Location = 00205, Gender = 0, Nature = Nature.Naive, Moves = new(033,043,425,000) }, // Sableye (sub_003_ghost)
|
||||
new(0303,0,52,255) { Location = 00057, Gender = 1, Nature = Nature.Hardy, FlawlessIVCount = 3 }, // Mawile (sub_107_kucheat)
|
||||
new(0505,0,50,255) { Location = 00014, Gender = 0, Nature = Nature.Bold, IsAlpha = true, FlawlessIVCount = 3 }, // Watchog (sub_056_evoybn)
|
||||
new(0569,0,50,128) { Location = 00030, Gender = 0, Nature = Nature.Naughty, Moves = new(398,693,205,232) }, // Garbodor (sub_027_predator)
|
||||
new(0587,0,53,128) { Location = 00089, Gender = 1, Nature = Nature.Naive, Moves = new(113,521,403,209) }, // Emolga (sub_115_emonga)
|
||||
new(0659,0,10,255) { Location = 00079, Gender = 0, Nature = Nature.Mild, IsAlpha = true, FlawlessIVCount = 3 }, // Bunnelby (sub_002_oybn)
|
||||
new(0660,0,28,128) { Location = 00012, Gender = 0, Nature = Nature.Adamant }, // Diggersby (sub_055_evpoke)
|
||||
new(0707,0,40,128) { Location = 00235, Gender = 0, Nature = Nature.Timid, Moves = new(583,430,577,319) }, // Klefki (m05_cleffy)
|
||||
|
||||
// Side Missions EX
|
||||
// new(0150,0,70,128) { Location = 00234, FlawlessIVCount = 3, Moves = new(094,396,427,133) }, // Mewtwo (sub_120_mewtwo)
|
||||
// new(0703,0,66,128) { Location = 00063, FlawlessIVCount = 3, Moves = new(444,430,605,157) }, // Carbink (sub_119_melecie_01)
|
||||
// new(0703,0,66,128) { Location = 00063, FlawlessIVCount = 3, Moves = new(444,446,408,605) }, // Carbink (sub_119_melecie_02)
|
||||
// new(0719,0,70,128) { Location = 00063, FlawlessIVCount = 3, Moves = new(591,585,446,577) }, // Diancie (sub_119_diancie)
|
||||
];
|
||||
|
||||
private const string tradeZA = "tradeza";
|
||||
private static readonly string[][] TradeNames = Util.GetLanguageStrings11(tradeZA);
|
||||
internal static readonly EncounterTrade9a[] Trades =
|
||||
[
|
||||
new(TradeNames,0,0214,0,12) { ID32 = 797394, OTGender = 1, Gender = 0, Nature = Nature.Brave, IVs = new(31,31,15,31,15,15), Moves = new(033,043,203,042) }, // Heracross (sub_tradepoke_heracros)
|
||||
new(TradeNames,1,0447,0,25) { ID32 = 348226, OTGender = 0, Gender = 0, Nature = Nature.Rash, IVs = new(15,31,15,31,31,15), Moves = new(418,098,249,197) }, // Riolu (sub_tradepoke_riolu)
|
||||
new(TradeNames,2,0079,1,30) { ID32 = 934764, OTGender = 0, Gender = 0, FlawlessIVCount = 3, Moves = new(352,133,428,029) }, // Slowpoke-1 (sub_addpoke_gyadon)
|
||||
new(TradeNames,3,0026,1,64) { ID32 = 693489, OTGender = 1, Gender = 0, Nature = Nature.Jolly, IVs = new(20,20,20,20,20,20), Moves = new(094,087,057,583) }, // Raichu-1 (sub_addpoke_araichu)
|
||||
];
|
||||
}
|
||||
|
|
@ -21,7 +21,7 @@ public DistributionWindow(int startYear, int startMonth, int startDay, int endYe
|
|||
/// </summary>
|
||||
/// <param name="obtained">Date obtained.</param>
|
||||
/// <returns>True if the date obtained is within the date of availability for the given range.</returns>
|
||||
public bool Contains(DateOnly obtained) => (Start <= obtained && End is null) || obtained <= End;
|
||||
public bool Contains(DateOnly obtained) => Start <= obtained && !(obtained > End);
|
||||
|
||||
/// <summary>
|
||||
/// Get a valid date within the generation range.
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ public static class EncounterServerDate
|
|||
WA8 wa8 => Result(wa8.IsWithinDistributionWindow(obtained)),
|
||||
WB8 wb8 => Result(wb8.IsWithinDistributionWindow(obtained)),
|
||||
WC9 wc9 => Result(wc9.IsWithinDistributionWindow(obtained)),
|
||||
WA9 wa9 => Result(wa9.IsWithinDistributionWindow(obtained)),
|
||||
EncounterSlot7GO g7 => Result(g7.IsWithinDistributionWindow(obtained)),
|
||||
EncounterSlot8GO g8 => Result(g8.IsWithinDistributionWindow(obtained)),
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(enc)),
|
||||
|
|
@ -44,11 +45,15 @@ public static class EncounterServerDate
|
|||
/// <inheritdoc cref="IsWithinDistributionWindow(IEncounterServerDate,DateOnly)"/>
|
||||
public static bool IsWithinDistributionWindow(this WC9 card, DateOnly obtained) => card.GetDistributionWindow(out var window) && window.Contains(obtained);
|
||||
|
||||
/// <inheritdoc cref="IsWithinDistributionWindow(IEncounterServerDate,DateOnly)"/>
|
||||
public static bool IsWithinDistributionWindow(this WA9 card, DateOnly obtained) => card.GetDistributionWindow(out var window) && window.Contains(obtained);
|
||||
|
||||
public static bool GetDistributionWindow(this WB7 card, out DistributionWindow window) => WB7Gifts.TryGetValue(card.CardID, out window);
|
||||
public static bool GetDistributionWindow(this WC8 card, out DistributionWindow window) => WC8Gifts.TryGetValue(card.CardID, out window) || WC8GiftsChk.TryGetValue(card.Checksum, out window);
|
||||
public static bool GetDistributionWindow(this WA8 card, out DistributionWindow window) => WA8Gifts.TryGetValue(card.CardID, out window);
|
||||
public static bool GetDistributionWindow(this WB8 card, out DistributionWindow window) => WB8Gifts.TryGetValue(card.CardID, out window);
|
||||
public static bool GetDistributionWindow(this WC9 card, out DistributionWindow window) => WC9Gifts.TryGetValue(card.CardID, out window) || WC9GiftsChk.TryGetValue(card.Checksum, out window);
|
||||
public static bool GetDistributionWindow(this WA9 card, out DistributionWindow window) => WA9Gifts.TryGetValue(card.CardID, out window);
|
||||
|
||||
/// <summary>
|
||||
/// Initial introduction of HOME support for SW/SH; gift availability (generating) was revised in 3.0.0.
|
||||
|
|
@ -228,7 +233,7 @@ public static class EncounterServerDate
|
|||
{1548, new(2025, 09, 18, 2025, 10, 01)}, // Shiny Chi-Yu
|
||||
{0524, new(2025, 08, 14, 2025, 08, 31)}, // WCS 2025 Toedscool
|
||||
{0525, new(2025, 08, 15, 2025, 08, 23)}, // WCS 2025 Luca Ceribelli's Farigiraf
|
||||
{1540, new(2025, 09, 25, 2025, 10, 24)}, // Shiny Miraidon / Koraidon Gift
|
||||
{1540, new(2025, 09, 25, 2025, 10, 25)}, // Shiny Miraidon / Koraidon Gift
|
||||
|
||||
{9021, HOME3_ML}, // Hidden Ability Sprigatito
|
||||
{9022, HOME3_ML}, // Hidden Ability Fuecoco
|
||||
|
|
@ -236,4 +241,13 @@ public static class EncounterServerDate
|
|||
{9024, new(2024, 10, 16)}, // Shiny Meloetta
|
||||
{9025, new(2024, 11, 01)}, // PokéCenter Birthday Tandemaus
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Minimum date the gift can be received.
|
||||
/// </summary>
|
||||
private static readonly Dictionary<int, DistributionWindow> WA9Gifts = new()
|
||||
{
|
||||
{1601, new(2025, 10, 14, 2026, 3, 1, +2)}, // Ralts holding Gardevoirite
|
||||
{0102, new(2025, 10, 23, 2026, 2, 1, +2)}, // Slowpoke Poké Center Gift
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,6 +23,8 @@ public IEnumerable<IEncounterable> GetEncounters(PKM pk, LegalInfo info)
|
|||
|
||||
public IEnumerable<IEncounterable> GetPossible(PKM pk, EvoCriteria[] chain, GameVersion version, EncounterTypeGroup groups)
|
||||
{
|
||||
if (version is GameVersion.BATREV)
|
||||
yield break;
|
||||
var iterator = new EncounterPossible4(chain, groups, version, pk);
|
||||
foreach (var enc in iterator)
|
||||
yield return enc;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using static PKHeX.Core.GameVersion;
|
||||
|
|
@ -50,14 +51,14 @@ public IEnumerable<IEncounterable> GetEncounters(PKM pk, EvoCriteria[] chain, Le
|
|||
private const EntityContext Context = EntityContext.Gen9;
|
||||
private const byte EggLevel = 1;
|
||||
|
||||
public static bool TryGetEgg(PKM pk, EvoCriteria[] chain, GameVersion version, [NotNullWhen(true)] out EncounterEgg9? result)
|
||||
public static bool TryGetEgg(PKM pk, ReadOnlySpan<EvoCriteria> chain, GameVersion version, [NotNullWhen(true)] out EncounterEgg9? result)
|
||||
{
|
||||
if (version == 0 && pk.IsEgg)
|
||||
version = SL;
|
||||
return TryGetEgg(chain, version, out result);
|
||||
}
|
||||
|
||||
public static bool TryGetEgg(EvoCriteria[] chain, GameVersion version, [NotNullWhen(true)] out EncounterEgg9? result)
|
||||
public static bool TryGetEgg(ReadOnlySpan<EvoCriteria> chain, GameVersion version, [NotNullWhen(true)] out EncounterEgg9? result)
|
||||
{
|
||||
result = null;
|
||||
var devolved = chain[^1];
|
||||
|
|
|
|||
|
|
@ -0,0 +1,23 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
public sealed class EncounterGenerator9a : IEncounterGenerator
|
||||
{
|
||||
public static readonly EncounterGenerator9a Instance = new();
|
||||
public bool CanGenerateEggs => false;
|
||||
|
||||
public IEnumerable<IEncounterable> GetPossible(PKM _, EvoCriteria[] chain, GameVersion __, EncounterTypeGroup groups)
|
||||
{
|
||||
var iterator = new EncounterPossible9a(chain, groups);
|
||||
foreach (var enc in iterator)
|
||||
yield return enc;
|
||||
}
|
||||
|
||||
public IEnumerable<IEncounterable> GetEncounters(PKM pk, EvoCriteria[] chain, LegalInfo info)
|
||||
{
|
||||
var iterator = new EncounterEnumerator9a(pk, chain);
|
||||
foreach (var enc in iterator)
|
||||
yield return enc.Encounter;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
using System.Collections.Generic;
|
||||
using static PKHeX.Core.GameVersion;
|
||||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
public sealed class EncounterGenerator9X : IEncounterGenerator
|
||||
{
|
||||
public static readonly EncounterGenerator9X Instance = new();
|
||||
public bool CanGenerateEggs => false;
|
||||
|
||||
public IEnumerable<IEncounterable> GetPossible(PKM pk, EvoCriteria[] chain, GameVersion game, EncounterTypeGroup groups) => game switch
|
||||
{
|
||||
ZA => EncounterGenerator9a.Instance.GetPossible(pk, chain, game, groups),
|
||||
SL or VL => EncounterGenerator9.Instance.GetPossible(pk, chain, game, groups),
|
||||
_ => [],
|
||||
};
|
||||
|
||||
public IEnumerable<IEncounterable> GetEncounters(PKM pk, LegalInfo info)
|
||||
{
|
||||
var chain = EncounterOrigin.GetOriginChain(pk, 9, pk.Context);
|
||||
if (chain.Length == 0)
|
||||
return [];
|
||||
|
||||
return GetEncounters(pk, chain, info);
|
||||
}
|
||||
|
||||
public IEnumerable<IEncounterable> GetEncounters(PKM pk, EvoCriteria[] chain, LegalInfo info) => pk.Version switch
|
||||
{
|
||||
ZA => EncounterGenerator9a.Instance.GetEncounters(pk, chain, info),
|
||||
SL or VL => EncounterGenerator9.Instance.GetEncounters(pk, chain, info),
|
||||
_ => [],
|
||||
};
|
||||
}
|
||||
|
|
@ -553,4 +553,19 @@ public bool IsSatisfiedIVs(uint iv32)
|
|||
if (!IsSatisfiedIV(IV_SPD, (int)((iv32 >> 25) & 0x1F))) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the IV based on the specified index (visual order).
|
||||
/// </summary>
|
||||
/// <param name="index">Stat index (visual order).</param>
|
||||
public sbyte GetIV(int index) => index switch
|
||||
{
|
||||
0 => IV_HP,
|
||||
1 => IV_ATK,
|
||||
2 => IV_DEF,
|
||||
3 => IV_SPA,
|
||||
4 => IV_SPD,
|
||||
5 => IV_SPE,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(index), index, null),
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ public static class EncounterGenerator
|
|||
6 => EncounterGenerator6.Instance.GetEncounters(pk, info),
|
||||
7 => EncounterGenerator7X.Instance.GetEncounters(pk, info),
|
||||
8 => EncounterGenerator8X.Instance.GetEncounters(pk, info),
|
||||
9 => EncounterGenerator9.Instance.GetEncounters(pk, info),
|
||||
9 => EncounterGenerator9X.Instance.GetEncounters(pk, info),
|
||||
_ => EncounterGeneratorDummy.Instance.GetEncounters(pk, info),
|
||||
};
|
||||
|
||||
|
|
@ -61,7 +61,11 @@ public static class EncounterGenerator
|
|||
GameVersion.BD or GameVersion.SP => EncounterGenerator8b.Instance,
|
||||
_ => EncounterGenerator8.Instance,
|
||||
},
|
||||
9 => EncounterGenerator9.Instance,
|
||||
9 => version switch
|
||||
{
|
||||
GameVersion.ZA => EncounterGenerator9a.Instance,
|
||||
_ => EncounterGenerator9.Instance,
|
||||
},
|
||||
_ => EncounterGeneratorDummy.Instance,
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,156 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Iterates to find possible encounters for <see cref="EntityContext.Gen9a"/> encounters.
|
||||
/// </summary>
|
||||
public record struct EncounterPossible9a(EvoCriteria[] Chain, EncounterTypeGroup Flags) : IEnumerator<IEncounterable>
|
||||
{
|
||||
public IEncounterable Current { get; private set; } = null!;
|
||||
|
||||
private int Index;
|
||||
private int SubIndex;
|
||||
private YieldState State;
|
||||
readonly object IEnumerator.Current => Current;
|
||||
public readonly void Reset() => throw new NotSupportedException();
|
||||
public readonly void Dispose() { }
|
||||
public readonly IEnumerator<IEncounterable> GetEnumerator() => this;
|
||||
|
||||
private enum YieldState : byte
|
||||
{
|
||||
Start,
|
||||
|
||||
EventStart,
|
||||
Event,
|
||||
EventLocal,
|
||||
TradeStart,
|
||||
Trade,
|
||||
|
||||
StaticStart,
|
||||
|
||||
SlotStart,
|
||||
Slot,
|
||||
SlotEnd,
|
||||
|
||||
StaticCapture,
|
||||
StaticGift,
|
||||
StaticEnd,
|
||||
|
||||
End,
|
||||
}
|
||||
|
||||
public bool MoveNext()
|
||||
{
|
||||
switch (State)
|
||||
{
|
||||
case YieldState.Start:
|
||||
if (Chain.Length == 0)
|
||||
break;
|
||||
goto case YieldState.EventStart;
|
||||
|
||||
case YieldState.EventStart:
|
||||
if (!Flags.HasFlag(EncounterTypeGroup.Mystery))
|
||||
goto case YieldState.TradeStart;
|
||||
State = YieldState.Event; goto case YieldState.Event;
|
||||
case YieldState.Event:
|
||||
if (TryGetNext(EncounterEvent.MGDB_G9A))
|
||||
return true;
|
||||
Index = 0; State = YieldState.EventLocal; goto case YieldState.EventLocal;
|
||||
case YieldState.EventLocal:
|
||||
if (TryGetNext(EncounterEvent.EGDB_G9A))
|
||||
return true;
|
||||
Index = 0; goto case YieldState.TradeStart;
|
||||
|
||||
case YieldState.TradeStart:
|
||||
if (!Flags.HasFlag(EncounterTypeGroup.Trade))
|
||||
goto case YieldState.StaticStart;
|
||||
State = YieldState.Trade; goto case YieldState.Trade;
|
||||
case YieldState.Trade:
|
||||
if (TryGetNext(Encounters9a.Trades))
|
||||
return true;
|
||||
Index = 0; goto case YieldState.StaticStart;
|
||||
|
||||
case YieldState.StaticStart:
|
||||
if (!Flags.HasFlag(EncounterTypeGroup.Static))
|
||||
goto case YieldState.SlotStart;
|
||||
goto case YieldState.StaticCapture;
|
||||
case YieldState.StaticCapture:
|
||||
if (TryGetNext(Encounters9a.Static))
|
||||
return true;
|
||||
Index = 0; State = YieldState.StaticGift; goto case YieldState.StaticGift;
|
||||
case YieldState.StaticGift:
|
||||
if (TryGetNext(Encounters9a.Gifts))
|
||||
return true;
|
||||
Index = 0; goto case YieldState.StaticEnd;
|
||||
case YieldState.StaticEnd:
|
||||
goto case YieldState.SlotStart;
|
||||
|
||||
case YieldState.SlotStart:
|
||||
if (!Flags.HasFlag(EncounterTypeGroup.Slot))
|
||||
goto case YieldState.End;
|
||||
goto case YieldState.Slot;
|
||||
case YieldState.Slot:
|
||||
if (TryGetNext<EncounterArea9a, EncounterSlot9a>(Encounters9a.Slots))
|
||||
return true;
|
||||
goto case YieldState.SlotEnd;
|
||||
case YieldState.SlotEnd:
|
||||
goto case YieldState.End;
|
||||
|
||||
case YieldState.End:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool TryGetNext<TArea, TSlot>(TArea[] areas)
|
||||
where TArea : class, IEncounterArea<TSlot>
|
||||
where TSlot : class, IEncounterable, IEncounterMatch
|
||||
{
|
||||
for (; Index < areas.Length; Index++, SubIndex = 0)
|
||||
{
|
||||
var area = areas[Index];
|
||||
if (TryGetNextSub(area.Slots))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool TryGetNextSub<T>(T[] slots) where T : class, IEncounterable, IEncounterMatch
|
||||
{
|
||||
while (SubIndex < slots.Length)
|
||||
{
|
||||
var enc = slots[SubIndex++];
|
||||
foreach (var evo in Chain)
|
||||
{
|
||||
if (enc.Species != evo.Species)
|
||||
continue;
|
||||
return SetCurrent(enc);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool TryGetNext<T>(T[] db) where T : class, IEncounterable, IEncounterMatch
|
||||
{
|
||||
for (; Index < db.Length;)
|
||||
{
|
||||
var enc = db[Index++];
|
||||
foreach (var evo in Chain)
|
||||
{
|
||||
if (evo.Species != enc.Species)
|
||||
continue;
|
||||
return SetCurrent(enc);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool SetCurrent(IEncounterable match)
|
||||
{
|
||||
Current = match;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,210 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Iterates to find potentially matched encounters for <see cref="GameVersion.ZA"/>.
|
||||
/// </summary>
|
||||
public record struct EncounterEnumerator9a(PKM Entity, EvoCriteria[] Chain) : IEnumerator<MatchedEncounter<IEncounterable>>
|
||||
{
|
||||
private IEncounterable? Deferred;
|
||||
private int Index;
|
||||
private int SubIndex;
|
||||
private EncounterMatchRating Rating = EncounterMatchRating.MaxNotMatch;
|
||||
private bool Yielded;
|
||||
public MatchedEncounter<IEncounterable> Current { get; private set; }
|
||||
private YieldState State;
|
||||
private ushort met;
|
||||
private bool mustBeSlot;
|
||||
readonly object IEnumerator.Current => Current;
|
||||
|
||||
public readonly void Reset() => throw new NotSupportedException();
|
||||
public readonly void Dispose() { }
|
||||
public readonly IEnumerator<MatchedEncounter<IEncounterable>> GetEnumerator() => this;
|
||||
|
||||
private enum YieldState : byte
|
||||
{
|
||||
Start,
|
||||
|
||||
Event,
|
||||
EventLocal,
|
||||
TradeStart,
|
||||
Trade,
|
||||
|
||||
StartCaptures,
|
||||
StaticStart,
|
||||
|
||||
SlotStart,
|
||||
Slot,
|
||||
SlotEnd,
|
||||
|
||||
StaticCapture,
|
||||
StaticGift,
|
||||
StaticEnd,
|
||||
|
||||
Fallback,
|
||||
End,
|
||||
}
|
||||
|
||||
public bool MoveNext()
|
||||
{
|
||||
switch (State)
|
||||
{
|
||||
case YieldState.Start:
|
||||
if (Chain.Length == 0)
|
||||
break;
|
||||
|
||||
if (!Entity.FatefulEncounter)
|
||||
goto case YieldState.TradeStart;
|
||||
State = YieldState.Event; goto case YieldState.Event;
|
||||
|
||||
case YieldState.Event:
|
||||
if (TryGetNext(EncounterEvent.MGDB_G9A))
|
||||
return true;
|
||||
Index = 0; State = YieldState.EventLocal; goto case YieldState.EventLocal;
|
||||
case YieldState.EventLocal:
|
||||
if (TryGetNext(EncounterEvent.EGDB_G9A))
|
||||
return true;
|
||||
if (Yielded)
|
||||
break;
|
||||
Index = 0; goto case YieldState.TradeStart;
|
||||
|
||||
case YieldState.TradeStart:
|
||||
if (Entity.MetLocation != Locations.LinkTrade6NPC)
|
||||
goto case YieldState.StartCaptures;
|
||||
State = YieldState.Trade; goto case YieldState.Trade;
|
||||
case YieldState.Trade:
|
||||
if (TryGetNext(Encounters9a.Trades))
|
||||
return true;
|
||||
if (Yielded)
|
||||
break;
|
||||
Index = 0; goto case YieldState.StartCaptures;
|
||||
|
||||
case YieldState.StartCaptures:
|
||||
InitializeWildLocationInfo();
|
||||
if (mustBeSlot)
|
||||
goto case YieldState.SlotStart;
|
||||
goto case YieldState.StaticStart;
|
||||
|
||||
case YieldState.SlotStart:
|
||||
if (!EncounterStateUtil.CanBeWildEncounter(Entity))
|
||||
goto case YieldState.SlotEnd;
|
||||
State = YieldState.Slot; goto case YieldState.Slot;
|
||||
case YieldState.Slot:
|
||||
if (TryGetNext<EncounterArea9a, EncounterSlot9a>(Encounters9a.Slots))
|
||||
return true;
|
||||
Index = 0; goto case YieldState.SlotEnd;
|
||||
case YieldState.SlotEnd:
|
||||
if (!mustBeSlot)
|
||||
goto case YieldState.Fallback; // already checked everything else
|
||||
goto case YieldState.StaticStart;
|
||||
|
||||
case YieldState.StaticStart:
|
||||
State = YieldState.StaticCapture; goto case YieldState.StaticCapture;
|
||||
|
||||
case YieldState.StaticCapture:
|
||||
if (TryGetNext(Encounters9a.Static))
|
||||
return true;
|
||||
Index = 0; State = YieldState.StaticGift; goto case YieldState.StaticGift;
|
||||
case YieldState.StaticGift:
|
||||
if (TryGetNext(Encounters9a.Gifts))
|
||||
return true;
|
||||
Index = 0; State = YieldState.StaticEnd; goto case YieldState.StaticEnd;
|
||||
|
||||
case YieldState.StaticEnd:
|
||||
if (mustBeSlot)
|
||||
goto case YieldState.Fallback; // already checked everything else
|
||||
Index = 0; goto case YieldState.SlotStart;
|
||||
|
||||
case YieldState.Fallback:
|
||||
State = YieldState.End;
|
||||
if (Deferred != null)
|
||||
return SetCurrent(Deferred, Rating);
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void InitializeWildLocationInfo()
|
||||
{
|
||||
met = Entity.MetLocation;
|
||||
mustBeSlot = Entity is IRibbonIndex r && r.HasEncounterMark();
|
||||
}
|
||||
|
||||
private bool TryGetNext<TArea, TSlot>(TArea[] areas)
|
||||
where TArea : class, IEncounterArea<TSlot>, IAreaLocation
|
||||
where TSlot : class, IEncounterable, IEncounterMatch
|
||||
{
|
||||
for (; Index < areas.Length; Index++, SubIndex = 0)
|
||||
{
|
||||
var area = areas[Index];
|
||||
if (!area.IsMatchLocation(met))
|
||||
continue;
|
||||
if (TryGetNextSub(area.Slots))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool TryGetNextSub<T>(T[] slots) where T : class, IEncounterable, IEncounterMatch
|
||||
{
|
||||
while (SubIndex < slots.Length)
|
||||
{
|
||||
var enc = slots[SubIndex++];
|
||||
foreach (var evo in Chain)
|
||||
{
|
||||
if (enc.Species != evo.Species)
|
||||
continue;
|
||||
if (!enc.IsMatchExact(Entity, evo))
|
||||
break;
|
||||
|
||||
var rating = enc.GetMatchRating(Entity);
|
||||
if (rating == EncounterMatchRating.Match)
|
||||
return SetCurrent(enc);
|
||||
|
||||
if (rating < Rating)
|
||||
{
|
||||
Deferred = enc;
|
||||
Rating = rating;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool TryGetNext<T>(T[] db) where T : class, IEncounterable, IEncounterMatch
|
||||
{
|
||||
for (; Index < db.Length;)
|
||||
{
|
||||
var enc = db[Index++];
|
||||
foreach (var evo in Chain)
|
||||
{
|
||||
if (evo.Species != enc.Species)
|
||||
continue;
|
||||
if (!enc.IsMatchExact(Entity, evo))
|
||||
break;
|
||||
var rating = enc.GetMatchRating(Entity);
|
||||
if (rating == EncounterMatchRating.Match)
|
||||
return SetCurrent(enc);
|
||||
|
||||
if (rating < Rating)
|
||||
{
|
||||
Deferred = enc;
|
||||
Rating = rating;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool SetCurrent<T>(T enc, EncounterMatchRating rating = EncounterMatchRating.Match) where T : IEncounterable
|
||||
{
|
||||
Current = new MatchedEncounter<IEncounterable>(enc, rating);
|
||||
Yielded = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -89,6 +89,13 @@ private static IEnumerable<IEncounterable> GetLearnInternal(ushort species, byte
|
|||
foreach (var enc in encs)
|
||||
yield return enc;
|
||||
}
|
||||
if (PersonalTable.ZA.IsPresentInGame(species, form))
|
||||
{
|
||||
var blank = new PA9 { Species = species, Form = form };
|
||||
var encs = EncounterMovesetGenerator.GenerateEncounters(blank, moves, GameVersion.ZA);
|
||||
foreach (var enc in encs)
|
||||
yield return enc;
|
||||
}
|
||||
if (PersonalTable.LA.IsPresentInGame(species, form))
|
||||
{
|
||||
var blank = new PA8 { Species = species, Form = form };
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ public string LongName
|
|||
|
||||
public PB7 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
||||
{
|
||||
int language = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language);
|
||||
int language = (int)Language.GetSafeLanguage789((LanguageID)tr.Language);
|
||||
var rnd = Util.Rand;
|
||||
var date = this.GetRandomValidDate();
|
||||
var pk = new PB7
|
||||
|
|
|
|||
|
|
@ -113,7 +113,7 @@ public bool IsBallValid(Ball ball, ushort currentSpecies, PKM pk)
|
|||
public PKM ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
||||
{
|
||||
var pk = GetBlank();
|
||||
int language = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language);
|
||||
int language = (int)Language.GetSafeLanguage789((LanguageID)tr.Language);
|
||||
var rnd = Util.Rand;
|
||||
{
|
||||
pk.Language = language;
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ public sealed record EncounterSlot1(EncounterArea1 Parent, ushort Species, byte
|
|||
public PK1 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
||||
{
|
||||
var version = this.GetCompatibleVersion(tr.Version);
|
||||
int language = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language, version);
|
||||
int language = (int)Language.GetSafeLanguage1((LanguageID)tr.Language, version);
|
||||
var isJapanese = language == (int)LanguageID.Japanese;
|
||||
var pi = EncounterUtil.GetPersonal1(version, Species);
|
||||
var pk = new PK1(isJapanese)
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ public sealed record EncounterStatic1(ushort Species, byte Level, GameVersion Ve
|
|||
public PK1 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
||||
{
|
||||
var version = this.GetCompatibleVersion(tr.Version);
|
||||
int language = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language, version);
|
||||
int language = (int)Language.GetSafeLanguage1((LanguageID)tr.Language, version);
|
||||
var isJapanese = language == (int)LanguageID.Japanese;
|
||||
var pi = EncounterUtil.GetPersonal1(version, Species);
|
||||
var pk = new PK1(isJapanese)
|
||||
|
|
|
|||
|
|
@ -116,7 +116,7 @@ public PK1 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
|||
bool gsc = CanObtainMinGSC();
|
||||
var level = gsc ? LevelMinGSC : LevelMinRBY;
|
||||
var version = this.GetCompatibleVersion(tr.Version);
|
||||
int language = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language, version);
|
||||
int language = (int)Language.GetSafeLanguage1((LanguageID)tr.Language, version);
|
||||
var isJapanese = language == (int)LanguageID.Japanese;
|
||||
var pi = EncounterUtil.GetPersonal1(version, Species);
|
||||
var pk = new PK1(isJapanese)
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ public sealed record EncounterEgg2(ushort Species, GameVersion Version) : IEncou
|
|||
|
||||
public PK2 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
||||
{
|
||||
int language = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language, Version);
|
||||
int language = (int)Language.GetSafeLanguage2((LanguageID)tr.Language);
|
||||
var rnd = Util.Rand;
|
||||
|
||||
var pk = new PK2(language == (int)LanguageID.Japanese)
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ public bool IsTreeAvailable(ushort trainerID)
|
|||
|
||||
public PK2 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
||||
{
|
||||
int language = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language);
|
||||
int language = (int)Language.GetSafeLanguage2((LanguageID)tr.Language);
|
||||
var isJapanese = language == (int)LanguageID.Japanese;
|
||||
var pi = PersonalTable.C[Species];
|
||||
var rnd = Util.Rand;
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ public sealed record EncounterStatic2(ushort Species, byte Level, GameVersion Ve
|
|||
public PK2 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
||||
{
|
||||
var version = this.GetCompatibleVersion(tr.Version);
|
||||
int language = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language, version);
|
||||
int language = (int)Language.GetSafeLanguage2((LanguageID)tr.Language);
|
||||
var pi = PersonalTable.C[Species];
|
||||
var pk = new PK2
|
||||
{
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ public EncounterTrade2(ReadOnlySpan<string[]> names, byte index, ushort species,
|
|||
public PK2 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
||||
{
|
||||
var version = this.GetCompatibleVersion(tr.Version);
|
||||
int language = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language, version);
|
||||
int language = (int)Language.GetSafeLanguage2((LanguageID)tr.Language);
|
||||
var isJapanese = language == (int)LanguageID.Japanese;
|
||||
var pi = PersonalTable.C[Species];
|
||||
var pk = new PK2(isJapanese)
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ private int GetTemplateLanguage(ITrainerInfo tr)
|
|||
{
|
||||
if (IsJapaneseBonusDisk)
|
||||
return 1; // Japanese
|
||||
return (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language);
|
||||
return (int)Language.GetSafeLanguage3((LanguageID)tr.Language);
|
||||
}
|
||||
|
||||
private static void SetPINGA(CK3 pk, in EncounterCriteria criteria, PersonalInfo3 pi)
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ public CK3 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
|||
return pk;
|
||||
}
|
||||
|
||||
private int GetTemplateLanguage(ITrainerInfo tr) => IsEReader ? 1 : (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language);
|
||||
private int GetTemplateLanguage(ITrainerInfo tr) => IsEReader ? 1 : (int)Language.GetSafeLanguage3((LanguageID)tr.Language);
|
||||
|
||||
private void SetPINGA(CK3 pk, in EncounterCriteria criteria, PersonalInfo3 pi)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ public CK3 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
|||
return pk;
|
||||
}
|
||||
|
||||
private int GetTemplateLanguage(ITrainerInfo tr) => (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language);
|
||||
private int GetTemplateLanguage(ITrainerInfo tr) => (int)Language.GetSafeLanguage3((LanguageID)tr.Language);
|
||||
|
||||
private void SetPINGA(CK3 pk, EncounterCriteria criteria)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ public RandomCorrelationRating IsCompatible(PIDType type, PKM pk)
|
|||
|
||||
public PK3 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
||||
{
|
||||
int language = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language, Version);
|
||||
int language = (int)Language.GetSafeLanguage3((LanguageID)tr.Language);
|
||||
|
||||
var pk = new PK3
|
||||
{
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ public record EncounterSlot3(EncounterArea3 Parent, ushort Species, byte Form, b
|
|||
|
||||
public PK3 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
||||
{
|
||||
int language = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language);
|
||||
int language = (int)Language.GetSafeLanguage3((LanguageID)tr.Language);
|
||||
var version = Version switch
|
||||
{
|
||||
GameVersion.RSE => tr.Version switch
|
||||
|
|
|
|||
|
|
@ -92,7 +92,7 @@ private int GetTemplateLanguage(ITrainerInfo tr)
|
|||
if (Species is (ushort)Core.Species.Deoxys && tr.Language == 1)
|
||||
return (int)LanguageID.English;
|
||||
|
||||
return (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language);
|
||||
return (int)Language.GetSafeLanguage3((LanguageID)tr.Language);
|
||||
}
|
||||
|
||||
private void SetPINGA(PK3 pk, in EncounterCriteria criteria, PersonalInfo3 pi)
|
||||
|
|
|
|||
|
|
@ -86,7 +86,7 @@ public EncounterTrade3(ReadOnlySpan<string[]> names, byte index, GameVersion ver
|
|||
|
||||
public PK3 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
||||
{
|
||||
int language = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language);
|
||||
int language = (int)Language.GetSafeLanguage3((LanguageID)tr.Language);
|
||||
var version = this.GetCompatibleVersion(tr.Version);
|
||||
var pi = PersonalTable.E[Species];
|
||||
var pk = new PK3
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ public sealed record EncounterShadow3XD(byte Index, ushort Gauge, ReadOnlyMemory
|
|||
|
||||
public XK3 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
||||
{
|
||||
int language = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language);
|
||||
int language = (int)Language.GetSafeLanguage3((LanguageID)tr.Language);
|
||||
var pi = PersonalTable.E[Species];
|
||||
var pk = new XK3
|
||||
{
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ public sealed record EncounterSlot3XD(EncounterArea3XD Parent, ushort Species, b
|
|||
|
||||
public XK3 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
||||
{
|
||||
int language = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language);
|
||||
int language = (int)Language.GetSafeLanguage3((LanguageID)tr.Language);
|
||||
var pi = PersonalTable.E[Species];
|
||||
var pk = new XK3
|
||||
{
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ public sealed record EncounterStatic3XD(ushort Species, byte Level)
|
|||
|
||||
public XK3 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
||||
{
|
||||
int language = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language);
|
||||
int language = (int)Language.GetSafeLanguage3((LanguageID)tr.Language);
|
||||
var pi = PersonalTable.E[Species];
|
||||
var pk = new XK3
|
||||
{
|
||||
|
|
|
|||
|
|
@ -91,7 +91,7 @@ public XK3 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
|||
return pk;
|
||||
}
|
||||
|
||||
private int GetTemplateLanguage(ITrainerInfo tr) => (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language);
|
||||
private int GetTemplateLanguage(ITrainerInfo tr) => (int)Language.GetSafeLanguage3((LanguageID)tr.Language);
|
||||
|
||||
private static void SetPINGA(XK3 pk, in EncounterCriteria criteria, PersonalInfo3 pi)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ public RandomCorrelationRating IsCompatible(PIDType type, PKM pk)
|
|||
|
||||
public PK4 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
||||
{
|
||||
int language = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language, Version);
|
||||
int language = (int)Language.GetSafeLanguage456((LanguageID)tr.Language);
|
||||
var date = EncounterDate.GetDateNDS();
|
||||
|
||||
var pk = new PK4
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ private Ball GetRequiredBallValue(Ball fallback = Ball.None)
|
|||
|
||||
public PK4 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
||||
{
|
||||
int language = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language);
|
||||
int language = (int)Language.GetSafeLanguage456((LanguageID)tr.Language);
|
||||
var pi = PersonalTable.HGSS[Species];
|
||||
var pk = new PK4
|
||||
{
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ public sealed record EncounterStatic4(GameVersion Version)
|
|||
|
||||
public PK4 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
||||
{
|
||||
int language = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language);
|
||||
int language = (int)Language.GetSafeLanguage456((LanguageID)tr.Language);
|
||||
var version = this.GetCompatibleVersion(tr.Version);
|
||||
var pi = PersonalTable.HGSS[Species];
|
||||
var pk = new PK4
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ public static EncounterStatic4Pokewalker[] GetAll(ReadOnlySpan<byte> data)
|
|||
|
||||
public PK4 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
||||
{
|
||||
int language = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language);
|
||||
int language = (int)Language.GetSafeLanguage456((LanguageID)tr.Language);
|
||||
var version = this.GetCompatibleVersion(tr.Version);
|
||||
var pi = PersonalTable.HGSS[Species];
|
||||
var pk = new PK4
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ public EncounterTrade4PID(ReadOnlySpan<string[]> names, byte index, GameVersion
|
|||
|
||||
public PK4 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
||||
{
|
||||
int language = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language);
|
||||
int language = (int)Language.GetSafeLanguage456((LanguageID)tr.Language);
|
||||
var version = this.GetCompatibleVersion(tr.Version);
|
||||
var pi = PersonalTable.DP[Species];
|
||||
var pk = new PK4
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ public EncounterTrade4RanchGift(ushort species, byte met, byte level)
|
|||
|
||||
public PK4 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
||||
{
|
||||
int language = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language);
|
||||
int language = (int)Language.GetSafeLanguage456((LanguageID)tr.Language);
|
||||
var version = this.GetCompatibleVersion(tr.Version);
|
||||
var pi = PersonalTable.DP[Species];
|
||||
var pk = new PK4
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ public sealed record EncounterEgg5(ushort Species, byte Form, GameVersion Versio
|
|||
|
||||
public PK5 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
||||
{
|
||||
int language = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language, Version);
|
||||
int language = (int)Language.GetSafeLanguage456((LanguageID)tr.Language);
|
||||
var date = EncounterDate.GetDateNDS();
|
||||
|
||||
var pk = new PK5
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ public sealed record EncounterSlot5(EncounterArea5 Parent, ushort Species, byte
|
|||
|
||||
public PK5 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
||||
{
|
||||
int language = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language);
|
||||
int language = (int)Language.GetSafeLanguage456((LanguageID)tr.Language);
|
||||
var pi = PersonalTable.B2W2[Species];
|
||||
var pk = new PK5
|
||||
{
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ public sealed record EncounterStatic5(GameVersion Version)
|
|||
|
||||
public PK5 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
||||
{
|
||||
int language = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language);
|
||||
int language = (int)Language.GetSafeLanguage456((LanguageID)tr.Language);
|
||||
var version = this.GetCompatibleVersion(tr.Version);
|
||||
var pi = PersonalTable.B2W2[Species];
|
||||
var pk = new PK5
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ public EncounterStatic5Entree(GameVersion version, ushort species, byte level, b
|
|||
|
||||
public PK5 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
||||
{
|
||||
int language = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language);
|
||||
int language = (int)Language.GetSafeLanguage456((LanguageID)tr.Language);
|
||||
var version = this.GetCompatibleVersion(tr.Version);
|
||||
var pi = PersonalTable.B2W2[Species];
|
||||
var pk = new PK5
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ public sealed record EncounterStatic5N(uint PID)
|
|||
|
||||
public PK5 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
||||
{
|
||||
int language = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language);
|
||||
int language = (int)Language.GetSafeLanguage456((LanguageID)tr.Language);
|
||||
var version = this.GetCompatibleVersion(tr.Version);
|
||||
var pi = PersonalTable.B2W2[Species];
|
||||
var pk = new PK5
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ public sealed record EncounterStatic5Radar(ushort Species, byte Form, AbilityPer
|
|||
|
||||
public PK5 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
||||
{
|
||||
int language = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language);
|
||||
int language = (int)Language.GetSafeLanguage456((LanguageID)tr.Language);
|
||||
var version = this.GetCompatibleVersion(tr.Version);
|
||||
var pi = PersonalTable.B2W2[Species];
|
||||
var pk = new PK5
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ public EncounterTrade5B2W2(string[] names, GameVersion version)
|
|||
|
||||
public PK5 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
||||
{
|
||||
int language = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language);
|
||||
int language = (int)Language.GetSafeLanguage456((LanguageID)tr.Language);
|
||||
var version = this.GetCompatibleVersion(tr.Version);
|
||||
var pi = PersonalTable.B2W2[Species];
|
||||
var pk = new PK5
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ public EncounterTrade5BW(ReadOnlySpan<string[]> names, byte index, GameVersion v
|
|||
|
||||
public PK5 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
||||
{
|
||||
int language = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language);
|
||||
int language = (int)Language.GetSafeLanguage456((LanguageID)tr.Language);
|
||||
var version = this.GetCompatibleVersion(tr.Version);
|
||||
var pi = PersonalTable.BW[Species];
|
||||
var pk = new PK5
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ public sealed record EncounterEgg6(ushort Species, byte Form, GameVersion Versio
|
|||
|
||||
public PK6 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
||||
{
|
||||
int language = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language, Version);
|
||||
int language = (int)Language.GetSafeLanguage456((LanguageID)tr.Language);
|
||||
var date = EncounterDate.GetDate3DS();
|
||||
var pi = PersonalTable.AO[Species, Form];
|
||||
var rnd = Util.Rand;
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ private ReadOnlySpan<ushort> GetDexNavMoves()
|
|||
|
||||
public PK6 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
||||
{
|
||||
int language = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language);
|
||||
int language = (int)Language.GetSafeLanguage456((LanguageID)tr.Language);
|
||||
var pi = PersonalTable.AO[Species];
|
||||
var geo = tr.GetRegionOrigin(language);
|
||||
var pk = new PK6
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ public sealed record EncounterSlot6XY(EncounterArea6XY Parent, ushort Species, b
|
|||
|
||||
public PK6 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
||||
{
|
||||
int language = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language);
|
||||
int language = (int)Language.GetSafeLanguage456((LanguageID)tr.Language);
|
||||
var version = Version != GameVersion.XY ? Version : tr.Version is GameVersion.X or GameVersion.Y ? tr.Version : GameVersion.X;
|
||||
var form = GetWildForm(Form);
|
||||
var pi = PersonalTable.XY[Species, form];
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ public sealed record EncounterStatic6(GameVersion Version)
|
|||
|
||||
public PK6 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
||||
{
|
||||
int language = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language);
|
||||
int language = (int)Language.GetSafeLanguage456((LanguageID)tr.Language);
|
||||
var version = this.GetCompatibleVersion(tr.Version);
|
||||
var pi = PersonalTable.AO[Species];
|
||||
var rnd = Util.Rand;
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ public EncounterTrade6(ReadOnlySpan<string[]> names, byte index, GameVersion ver
|
|||
|
||||
public PK6 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
||||
{
|
||||
int language = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language);
|
||||
int language = (int)Language.GetSafeLanguage456((LanguageID)tr.Language);
|
||||
var version = this.GetCompatibleVersion(tr.Version);
|
||||
var pi = PersonalTable.AO[Species];
|
||||
var rnd = Util.Rand;
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ public sealed record EncounterEgg7(ushort Species, byte Form, GameVersion Versio
|
|||
|
||||
public PK7 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
||||
{
|
||||
int language = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language, Version);
|
||||
int language = (int)Language.GetSafeLanguage789((LanguageID)tr.Language);
|
||||
var date = EncounterDate.GetDate3DS();
|
||||
var pi = PersonalTable.USUM[Species, Form];
|
||||
var rnd = Util.Rand;
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ public sealed record EncounterSlot7(EncounterArea7 Parent, ushort Species, byte
|
|||
public PK7 ConvertToPKM(ITrainerInfo tr) => ConvertToPKM(tr, EncounterCriteria.Unrestricted);
|
||||
public PK7 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
||||
{
|
||||
int language = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language);
|
||||
int language = (int)Language.GetSafeLanguage789((LanguageID)tr.Language);
|
||||
var form = GetWildForm(Form);
|
||||
var pi = PersonalTable.USUM[Species, form];
|
||||
var geo = tr.GetRegionOrigin(language);
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ public sealed record EncounterStatic7(GameVersion Version)
|
|||
|
||||
public PK7 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
||||
{
|
||||
int language = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language);
|
||||
int language = (int)Language.GetSafeLanguage789((LanguageID)tr.Language);
|
||||
var version = this.GetCompatibleVersion(tr.Version);
|
||||
var pi = PersonalTable.USUM[Species, Form];
|
||||
var geo = tr.GetRegionOrigin(language);
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ public EncounterTrade7(ReadOnlySpan<string[]> names, byte index, GameVersion ver
|
|||
|
||||
public PK7 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
||||
{
|
||||
int language = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language);
|
||||
int language = (int)Language.GetSafeLanguage789((LanguageID)tr.Language);
|
||||
var version = this.GetCompatibleVersion(tr.Version);
|
||||
var pi = PersonalTable.USUM[Species, Form];
|
||||
var rnd = Util.Rand;
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ public sealed record EncounterSlot7b(EncounterArea7b Parent, ushort Species, byt
|
|||
public PB7 ConvertToPKM(ITrainerInfo tr) => ConvertToPKM(tr, EncounterCriteria.Unrestricted);
|
||||
public PB7 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
||||
{
|
||||
int language = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language);
|
||||
int language = (int)Language.GetSafeLanguage789((LanguageID)tr.Language);
|
||||
var pi = PersonalTable.GG[Species];
|
||||
var date = EncounterDate.GetDateSwitch();
|
||||
var pk = new PB7
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ public sealed record EncounterStatic7b(GameVersion Version)
|
|||
public PB7 ConvertToPKM(ITrainerInfo tr) => ConvertToPKM(tr, EncounterCriteria.Unrestricted);
|
||||
public PB7 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
||||
{
|
||||
int language = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language);
|
||||
int language = (int)Language.GetSafeLanguage789((LanguageID)tr.Language);
|
||||
var version = this.GetCompatibleVersion(tr.Version);
|
||||
var pi = PersonalTable.GG[Species, Form];
|
||||
var date = EncounterDate.GetDateSwitch();
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ public sealed record EncounterTrade7b(GameVersion Version) : IEncounterable, IEn
|
|||
|
||||
public PB7 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
||||
{
|
||||
int language = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language);
|
||||
int language = (int)Language.GetSafeLanguage789((LanguageID)tr.Language);
|
||||
var version = this.GetCompatibleVersion(tr.Version);
|
||||
var pi = PersonalTable.GG[Species, Form];
|
||||
var date = EncounterDate.GetDateSwitch();
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ public sealed record EncounterEgg8(ushort Species, byte Form, GameVersion Versio
|
|||
|
||||
public PK8 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
||||
{
|
||||
int language = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language, Version);
|
||||
int language = (int)Language.GetSafeLanguage789((LanguageID)tr.Language);
|
||||
var date = EncounterDate.GetDateSwitch();
|
||||
var pi = PersonalTable.SWSH[Species, Form];
|
||||
var rnd = Util.Rand;
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user