mirror of
https://github.com/kwsch/PKHeX.git
synced 2026-08-26 19:17:48 -05:00
ShowdownSet: handling for context-locked forms
Retconned forms like Totems and Cosplay Pikachu that only exist in a specific context now get recognized again Current-Context has shifted from Gen6->Gen7->Gen8+, so a "get form list for species" won't return these forms. Not a perfect implementation, but better for now.
This commit is contained in:
@@ -75,7 +75,10 @@ public static string GetStringFromForm(byte form, GameStrings strings, ushort sp
|
||||
return string.Empty;
|
||||
|
||||
var forms = FormConverter.GetFormList(species, strings.Types, strings.forms, genderForms, context);
|
||||
return form >= forms.Length ? string.Empty : forms[form];
|
||||
var result = form >= forms.Length ? string.Empty : forms[form];
|
||||
|
||||
// Showdown uses a non-standard representation for some forms, and uses interstitial dashes instead of spaces.
|
||||
return GetShowdownFormName(species, result);
|
||||
}
|
||||
|
||||
private const string MiniorFormName = "Meteor";
|
||||
@@ -116,13 +119,22 @@ public static string GetShowdownFormName(ushort species, string form)
|
||||
};
|
||||
}
|
||||
|
||||
public static bool IsTotemForm(ReadOnlySpan<char> formName) =>
|
||||
formName.Equals("Totem", StringComparison.OrdinalIgnoreCase) ||
|
||||
formName.Equals("Alola-Totem", StringComparison.OrdinalIgnoreCase) ||
|
||||
formName.Equals("Large", StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
|
||||
public static bool IsCosplayPikachu(ReadOnlySpan<char> formName, ReadOnlySpan<string> formNames)
|
||||
=> FormConverter.IsCosplayPikachu(formName, formNames);
|
||||
|
||||
/// <summary>
|
||||
/// Converts the Showdown form name to PKHeX's form name.
|
||||
/// </summary>
|
||||
/// <param name="species">Species ID</param>
|
||||
/// <param name="form">Showdown form name</param>
|
||||
/// <param name="ability">Showdown ability ID</param>
|
||||
public static string SetShowdownFormName(ushort species, string form, int ability)
|
||||
public static string GetFormNameFromShowdownFormName(ushort species, string form, int ability)
|
||||
{
|
||||
if (form.Length != 0)
|
||||
form = form.Replace(' ', '-'); // inconsistencies are great
|
||||
|
||||
@@ -77,7 +77,8 @@ private void LoadLines(IEnumerable<string> lines, BattleTemplateLocalization loc
|
||||
|
||||
private void SanitizeResult(BattleTemplateLocalization localization)
|
||||
{
|
||||
FormName = ShowdownParsing.SetShowdownFormName(Species, FormName, Ability);
|
||||
ReviseContextIfPastGenForm(localization.Strings);
|
||||
FormName = ShowdownParsing.GetFormNameFromShowdownFormName(Species, FormName, Ability);
|
||||
Form = ShowdownParsing.GetFormFromString(FormName, localization.Strings, Species, Context);
|
||||
|
||||
// Handle edge case with fixed-gender forms.
|
||||
@@ -85,6 +86,17 @@ private void SanitizeResult(BattleTemplateLocalization localization)
|
||||
ReviseGenderedForms();
|
||||
}
|
||||
|
||||
private void ReviseContextIfPastGenForm(GameStrings strings)
|
||||
{
|
||||
if (FormName.Length == 0)
|
||||
return; // no form name
|
||||
|
||||
if (FormInfo.HasTotemForm(Species) && ShowdownParsing.IsTotemForm(FormName))
|
||||
Context = EntityContext.Gen7;
|
||||
else if (Species is (int)Pikachu && ShowdownParsing.IsCosplayPikachu(FormName, strings.forms))
|
||||
Context = EntityContext.Gen6;
|
||||
}
|
||||
|
||||
private void ReviseGenderedForms()
|
||||
{
|
||||
if (Gender == 1) // Recognized with (F)
|
||||
@@ -115,7 +127,7 @@ private void ParseLines(SpanLineEnumerator lines, BattleTemplateLocalization loc
|
||||
bool first = true;
|
||||
foreach (var line in lines)
|
||||
{
|
||||
ReadOnlySpan<char> trim = line.Trim();
|
||||
var trim = line.Trim();
|
||||
if (IsLengthOutOfRange(trim))
|
||||
{
|
||||
// Try for other languages just in case.
|
||||
@@ -502,8 +514,7 @@ private void PushToken(BattleTemplateToken token, List<string> result, in Battle
|
||||
{
|
||||
// Core
|
||||
case BattleTemplateToken.FirstLine:
|
||||
var form = ShowdownParsing.GetShowdownFormName(Species, FormName);
|
||||
result.Add(GetStringFirstLine(form, settings));
|
||||
result.Add(GetStringFirstLine(FormName, settings));
|
||||
break;
|
||||
case BattleTemplateToken.Ability when (uint)Ability < strings.Ability.Count:
|
||||
result.Add(cfg.Push(BattleTemplateToken.Ability, strings.Ability[Ability]));
|
||||
|
||||
@@ -24,6 +24,24 @@ public static bool IsBattleOnlyForm(ushort species, byte form, byte format)
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the form is a Mega form.
|
||||
/// </summary>
|
||||
/// <param name="species">Entity species</param>
|
||||
/// <param name="form">Entity form</param>
|
||||
public static bool IsMegaForm(ushort species, byte form)
|
||||
{
|
||||
if (BattleMegas.Contains(species))
|
||||
return IsBattleMegaForm(species, form);
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the species has a Mega form.
|
||||
/// </summary>
|
||||
/// <param name="species">Entity species</param>
|
||||
public static bool HasMegaForm(ushort species) => BattleMegas.Contains(species);
|
||||
|
||||
private static bool IsBattleForm(ushort species, byte form) => species switch
|
||||
{
|
||||
// Only continue checking if the species is in the list of Battle Only forms.
|
||||
|
||||
@@ -957,7 +957,7 @@ private static void SetAlcremieFormList(IReadOnlyList<string> forms, Span<string
|
||||
SetDecorations(result, 7, forms[CaramelSwirl]);
|
||||
SetDecorations(result, 8, forms[RainbowSwirl]);
|
||||
|
||||
static void SetDecorations(Span<string> result, [ConstantExpected] byte f, string baseName)
|
||||
static void SetDecorations(Span<string> result, [ConstantExpected] byte f, ReadOnlySpan<char> baseName)
|
||||
{
|
||||
int start = f * AlcremieCountDecoration;
|
||||
var slice = result.Slice(start, AlcremieCountDecoration);
|
||||
@@ -973,4 +973,20 @@ static void SetDecorations(Span<string> result, [ConstantExpected] byte f, strin
|
||||
(int)Alcremie => Enum.GetNames<AlcremieDecoration>(),
|
||||
_ => EMPTY,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Compatibility check for past-generation form list for <see cref="Pikachu"/>.
|
||||
/// </summary>
|
||||
/// <param name="formName">Desired form name</param>
|
||||
/// <param name="formNames">List of all form names</param>
|
||||
/// <returns><c>true</c> if the form name is a cosplay Pikachu form.</returns>
|
||||
public static bool IsCosplayPikachu(ReadOnlySpan<char> formName, ReadOnlySpan<string> formNames)
|
||||
{
|
||||
for (int i = 729; i <= 734; i++)
|
||||
{
|
||||
if (formName.Equals(formNames[i], StringComparison.OrdinalIgnoreCase))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,11 +12,11 @@ public void SimulatorGetParse()
|
||||
{
|
||||
var settings = new BattleTemplateExportSettings(BattleTemplateConfig.CommunityStandard);
|
||||
|
||||
foreach (ReadOnlySpan<char> setstr in Sets)
|
||||
foreach (var setstr in Sets)
|
||||
{
|
||||
var set = new ShowdownSet(setstr).GetSetLines(settings);
|
||||
foreach (var line in set)
|
||||
setstr.Contains(line, StringComparison.Ordinal).Should().BeTrue($"Line {line} should be in the set {setstr}");
|
||||
setstr.Contains(line, StringComparison.Ordinal).Should().BeTrue($"`{line}` should be in the set: {setstr}");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -410,7 +410,7 @@ Adamant Nature
|
||||
SetMunchSnorLax,
|
||||
|
||||
"""
|
||||
Greninja @ Choice Specs
|
||||
Greninja-Ash @ Choice Specs
|
||||
Ability: Battle Bond
|
||||
EVs: 252 SpA / 4 SpD / 252 Spe
|
||||
Timid Nature
|
||||
|
||||
Reference in New Issue
Block a user