mirror of
https://github.com/kwsch/PKHeX.git
synced 2026-08-20 09:44:28 -05:00
Gen5: fix basculin-blue reckless ability handling
Closes #2058 so many spots needing updating: - ability verifier (legality check) - encounter template=>pk5 (generating) - editor load abilities (show the ability in list) - editor save ability (acknowledge ability index)
This commit is contained in:
@@ -135,10 +135,18 @@ private static void LoadAbilityList(IPersonalAbility pi, Span<ComboItem> list, R
|
||||
for (int i = 0; i < list.Length; i++)
|
||||
{
|
||||
var value = pi.GetAbilityAtIndex(i);
|
||||
var name = names[value];
|
||||
char suffix = i == 2 ? HiddenAbilitySuffix : (char)(AbilityIndexSuffix + i);
|
||||
var display = $"{name} ({suffix})";
|
||||
list[i] = new ComboItem(display, value);
|
||||
var item = GetAbilityItem(names, value, suffix);
|
||||
list[i] = item;
|
||||
}
|
||||
}
|
||||
|
||||
public static ComboItem GetAbilityItem(ReadOnlySpan<string> names, int value, char suffix)
|
||||
=> GetAbilityItem(names[value], suffix, value);
|
||||
|
||||
public static ComboItem GetAbilityItem(string name, char suffix, int value)
|
||||
{
|
||||
var display = $"{name} ({suffix})";
|
||||
return new ComboItem(display, value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,6 +83,6 @@ public static EncounterMutation GetSuggested(EntityContext targetContext, byte l
|
||||
_ => false,
|
||||
},
|
||||
OnlyHidden => end.CanBeHidden() || mutation.HasFlag(CanAbilityPatch),
|
||||
_ => false,
|
||||
_ => true,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -77,6 +77,8 @@ public PK5 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
||||
pk.PID = pid;
|
||||
pk.Gender = gender;
|
||||
pk.RefreshAbility(ability);
|
||||
if (ability == 0 && this is { Species: (int)Core.Species.Basculin, Form: 1 })
|
||||
pk.Ability = (int)Core.Ability.Reckless;
|
||||
|
||||
return pk;
|
||||
}
|
||||
|
||||
@@ -90,6 +90,8 @@ private void SetPINGA(PK5 pk, in EncounterCriteria criteria, PersonalInfo5B2W2 p
|
||||
var abilityIndex = Ability == AbilityPermission.OnlyHidden ? 2 : (int)((pk.PID >> 16) & 1);
|
||||
pk.RefreshAbility(abilityIndex);
|
||||
criteria.SetRandomIVs(pk);
|
||||
if (abilityIndex == 0 && this is { Species: (int)Core.Species.Basculin, Form: 1, Version: GameVersion.B or GameVersion.W })
|
||||
pk.Ability = (int)Core.Ability.Reckless;
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
@@ -30,6 +30,8 @@ private CheckResult VerifyAbility(LegalityAnalysis data)
|
||||
var pk = data.Entity;
|
||||
if (pk is PA9 pa9)
|
||||
return VerifyBirthAbility(data, pa9);
|
||||
if (pk is PK5 pk5 && IsEdgeCaseBasculin(data, pk5, out var basc))
|
||||
return basc;
|
||||
|
||||
var abilities = (IPersonalAbility12)data.PersonalInfo;
|
||||
|
||||
@@ -95,6 +97,42 @@ private CheckResult VerifyAbility(LegalityAnalysis data)
|
||||
return VerifyAbility(data, abilities, abilIndex);
|
||||
}
|
||||
|
||||
private bool IsEdgeCaseBasculin(LegalityAnalysis data, PK5 pk5, out CheckResult result)
|
||||
{
|
||||
result = default;
|
||||
// Gen5 Only Edge Case issue:
|
||||
// - Basculin-Blue (form 1) *should* have Rock Head.
|
||||
// In B/W, Blue-Striped Basculin have Reckless as its Ability (incorrect) due to referencing the wrong Personal Info.
|
||||
// - However, the in-game trade Blue-Striped Basculin in White that has Rock Head (correct).
|
||||
// In B2/W2, wild Blue-Striped Basculin have Rock Head (correct), but bred Blue-Striped Basculin have Reckless (incorrect).
|
||||
// - When transferred to Pokémon Bank, any Blue-Striped Basculin with Reckless have their Ability changed to Rock Head (fixed).
|
||||
// Impacted encounter types: Egg|Wild (B/W), Egg (B2/W2)
|
||||
|
||||
if (pk5 is not { Species: (int)Species.Basculin, Form: 1, HiddenAbility: false, Ability: not (int)Ability.Adaptability })
|
||||
return false; // check abilities as usual.
|
||||
|
||||
var expect = (int)Ability.RockHead; // correct.
|
||||
if (pk5.Version is GameVersion.B2 or GameVersion.W2)
|
||||
{
|
||||
var enc = data.EncounterMatch;
|
||||
if (enc is EncounterEgg5)
|
||||
expect = (int)Ability.Reckless; // incorrect
|
||||
}
|
||||
else if (pk5.Version is GameVersion.B or GameVersion.W)
|
||||
{
|
||||
var enc = data.EncounterMatch;
|
||||
if (enc is not EncounterTrade5BW)
|
||||
expect = (int)Ability.Reckless; // incorrect
|
||||
}
|
||||
|
||||
var current = pk5.Ability;
|
||||
if (current == expect)
|
||||
result = VALID;
|
||||
else
|
||||
result = GetInvalid(AbilityUnexpected);
|
||||
return true; // tell the analyzer to use this result
|
||||
}
|
||||
|
||||
public static bool IsValidAbilityBits(int bitNum) => bitNum is 1 or 2 or 4;
|
||||
|
||||
private CheckResult VerifyAbility(LegalityAnalysis data, IPersonalAbility12 abilities, int abilIndex)
|
||||
|
||||
@@ -508,6 +508,13 @@ public PK6 ConvertToPK6()
|
||||
StringConverter345.TransferGlyphs56(pk6.NicknameTrash);
|
||||
StringConverter345.TransferString56(OriginalTrainerTrash, pk6.OriginalTrainerTrash);
|
||||
|
||||
// Fix Basculin-Blue
|
||||
if (Species is (ushort)Core.Species.Basculin && Form == 1 && Ability == (int)Core.Ability.Reckless)
|
||||
{
|
||||
pk6.Ability = (int)Core.Ability.RockHead;
|
||||
pk6.AbilityNumber = 1;
|
||||
}
|
||||
|
||||
// Fix Checksum
|
||||
pk6.RefreshChecksum();
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ private void PopulateFieldsPK5()
|
||||
if (HaX)
|
||||
DEV_Ability.SelectedValue = pk5.Ability;
|
||||
else if (pk5.HiddenAbility)
|
||||
CB_Ability.SelectedIndex = CB_Ability.Items.Count - 1;
|
||||
CB_Ability.SelectedIndex = 2;
|
||||
else
|
||||
LoadAbility4(pk5);
|
||||
|
||||
@@ -45,7 +45,7 @@ private PK5 PreparePK5()
|
||||
pk5.PokeStarFame = (byte)NUD_PokeStarFame.Value;
|
||||
if (!HaX)
|
||||
{
|
||||
pk5.HiddenAbility = CB_Ability.SelectedIndex is not (0 or 1);
|
||||
pk5.HiddenAbility = CB_Ability.SelectedIndex is 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -398,11 +398,16 @@ private void LoadAbility4(PKM pk)
|
||||
private static int GetAbilityIndex4(PKM pk)
|
||||
{
|
||||
var pi = pk.PersonalInfo;
|
||||
int abilityIndex = pi.GetIndexOfAbility(pk.Ability);
|
||||
if (abilityIndex < 0)
|
||||
return 0;
|
||||
var ability = pk.Ability;
|
||||
int abilityIndex = pi.GetIndexOfAbility(ability);
|
||||
if (abilityIndex >= 2)
|
||||
return 2;
|
||||
if (abilityIndex < 0)
|
||||
{
|
||||
if (ability == (int)Ability.Reckless && pk is { Context: EntityContext.Gen5, Species: (ushort)Species.Basculin, Form: 1 })
|
||||
return 3; // manually appended "extra" bug case for Gen5 Basculin-Blue.
|
||||
return 0; // fall back to first ability.
|
||||
}
|
||||
|
||||
var abils = (IPersonalAbility12)pi;
|
||||
if (abils.IsAbility12Same)
|
||||
|
||||
@@ -513,6 +513,8 @@ private void SetAbilityList()
|
||||
bool tmp = FieldsLoaded;
|
||||
FieldsLoaded = false;
|
||||
var items = GameInfo.FilteredSources.GetAbilityList(Entity.PersonalInfo);
|
||||
if (Entity is { Context: EntityContext.Gen5, Species: (ushort)Species.Basculin, Form: 1 })
|
||||
items = [..items, FilteredGameDataSource.GetAbilityItem(GameInfo.Strings.abilitylist, (int)Ability.Reckless, '*')];
|
||||
CB_Ability.DataSource = items;
|
||||
CB_Ability.SelectedIndex = Math.Clamp(ability, 0, items.Count - 1); // restore original index if available
|
||||
FieldsLoaded = tmp;
|
||||
|
||||
Binary file not shown.
Reference in New Issue
Block a user