Add shedinja dropped ribbons/marking considerations

Nice bug ya got there, gamefreak.

Coulda cleared the AffixedRibbon value instead of copying it on Shedinja creation, and it would have made this unnecessary.

Please ditch the Affixed Ribbon gimmick for future games, thanks!
This commit is contained in:
Kurt 2021-04-21 15:20:16 -07:00
parent 25565e6f07
commit 2aed4c3118
6 changed files with 90 additions and 16 deletions

View file

@ -95,8 +95,8 @@ namespace PKHeX.Core
} }
var encounter = EncounterSuggestion.GetSuggestedMetInfo(legal.pkm); var encounter = EncounterSuggestion.GetSuggestedMetInfo(legal.pkm);
if (encounter is IRelearn {Relearn: {Count: > 0}} r) if (encounter is IRelearn {Relearn: {Count: > 0} r})
return r.Relearn; return r;
return m; return m;
} }

View file

@ -9,7 +9,7 @@ namespace PKHeX.Core
public sealed record EncounterSlot8 : EncounterSlot, IOverworldCorrelation8 public sealed record EncounterSlot8 : EncounterSlot, IOverworldCorrelation8
{ {
public readonly AreaWeather8 Weather; public readonly AreaWeather8 Weather;
public override string LongName => Weather == AreaWeather8.All ? wild : $"{wild} [{(((EncounterArea8)Area).PermitCrossover ? "Symbol" : "Hidden")}] - {Weather.ToString().Replace("_", string.Empty)}"; public override string LongName => $"{wild} [{(((EncounterArea8)Area).PermitCrossover ? "Symbol" : "Hidden")}] - {Weather.ToString().Replace("_", string.Empty)}";
public override int Generation => 8; public override int Generation => 8;
public EncounterSlot8(EncounterArea8 area, int species, int form, int min, int max, AreaWeather8 weather) : base(area, species, form, min, max) public EncounterSlot8(EncounterArea8 area, int species, int form, int min, int max, AreaWeather8 weather) : base(area, species, form, min, max)
@ -36,7 +36,7 @@ namespace PKHeX.Core
if (((EncounterArea8)Area).PermitCrossover) if (((EncounterArea8)Area).PermitCrossover)
return MustHave; // symbol walking overworld return MustHave; // symbol walking overworld
bool curry = pk is IRibbonSetMark8 {RibbonMarkCurry: true}; bool curry = pk is IRibbonSetMark8 {RibbonMarkCurry: true} || pk.Species == (int)Core.Species.Shedinja && pk is PK8 {AffixedRibbon:(int)RibbonIndex.MarkCurry};
if (curry) if (curry)
return MustNotHave; return MustNotHave;

View file

@ -84,6 +84,17 @@ namespace PKHeX.Core
return EncounterMatchRating.Deferred; return EncounterMatchRating.Deferred;
// Only encounter slots can have these marks; defer for collisions. // Only encounter slots can have these marks; defer for collisions.
if (pkm.Species == (int) Core.Species.Shedinja)
{
// Loses Mark on evolution to Shedinja, but not affixed ribbon value.
return pkm switch
{
IRibbonSetMark8 {RibbonMarkCurry: true} => EncounterMatchRating.Deferred,
PK8 {AffixedRibbon: (int) RibbonIndex.MarkCurry} => EncounterMatchRating.Deferred,
_ => EncounterMatchRating.Match
};
}
if (pkm is IRibbonSetMark8 m && (m.RibbonMarkCurry || m.RibbonMarkFishing)) if (pkm is IRibbonSetMark8 m && (m.RibbonMarkCurry || m.RibbonMarkFishing))
return EncounterMatchRating.Deferred; return EncounterMatchRating.Deferred;

View file

@ -36,6 +36,8 @@ namespace PKHeX.Core
if (pkm is IRibbonSetMark8 m8 && m8.HasMark()) if (pkm is IRibbonSetMark8 m8 && m8.HasMark())
return false; return false;
if (pkm.Species == (int)Core.Species.Shedinja && pkm is PK8 { AffixedRibbon: >= (int)RibbonIndex.MarkLunchtime })
return false;
return base.IsMatchExact(pkm, evo); return base.IsMatchExact(pkm, evo);
} }

View file

@ -1,4 +1,5 @@
using static PKHeX.Core.LegalityCheckStrings; using System.Linq;
using static PKHeX.Core.LegalityCheckStrings;
namespace PKHeX.Core namespace PKHeX.Core
{ {
@ -15,7 +16,7 @@ namespace PKHeX.Core
if (pkm is not IRibbonIndex m) if (pkm is not IRibbonIndex m)
return; return;
if (data.Info.Generation != 8) if (data.Info.Generation != 8 || (pkm.Species == (int)Species.Shedinja && data.EncounterOriginal.Species is not (int)Species.Shedinja)) // Shedinja doesn't copy Ribbons or Marks
VerifyNoMarksPresent(data, m); VerifyNoMarksPresent(data, m);
else else
VerifyMarksPresent(data, m); VerifyMarksPresent(data, m);
@ -126,9 +127,68 @@ namespace PKHeX.Core
return; return;
if ((byte)affix > (int)RibbonIndex.MarkSlump) if ((byte)affix > (int)RibbonIndex.MarkSlump)
{
data.AddLine(GetInvalid(string.Format(LRibbonMarkingAffixedF_0, affix))); data.AddLine(GetInvalid(string.Format(LRibbonMarkingAffixedF_0, affix)));
else if (!pk8.GetRibbonIndex((RibbonIndex)affix)) return;
data.AddLine(GetInvalid(string.Format(LRibbonMarkingAffixedF_0, (RibbonIndex)affix))); }
if (pk8.Species == (int)Species.Shedinja && data.EncounterOriginal.Species is not (int)Species.Shedinja)
{
VerifyShedinjaAffixed(data, affix, pk8);
return;
}
EnsureHasRibbon(data, pk8, affix);
}
private void VerifyShedinjaAffixed(LegalityAnalysis data, sbyte affix, PK8 pk8)
{
// Does not copy ribbons or marks, but retains the Affixed Ribbon value.
// Try re-verifying to see if it could have had the Ribbon/Mark.
if ((byte) affix >= (int) RibbonIndex.MarkLunchtime)
{
if (data.EncounterOriginal.Generation != 8)
data.AddLine(GetInvalid(string.Format(LRibbonMarkingAffixedF_0, (RibbonIndex) affix)));
return;
}
var enc = data.EncounterOriginal;
if (enc.Generation <= 4 && (pk8.Ball != (int)Ball.Poke || IsMoveSetEvolvedShedinja(pk8)))
{
// Evolved in a prior generation.
EnsureHasRibbon(data, pk8, affix);
return;
}
var clone = pk8.Clone();
clone.Species = (int) Species.Nincada;
((IRibbonIndex) clone).SetRibbon(affix);
var parse = RibbonVerifier.GetRibbonResults(clone, data.EncounterOriginal);
var expect = $"Ribbon{(RibbonIndex) affix}";
var name = RibbonStrings.GetName(expect);
bool invalid = parse.FirstOrDefault(z => z.Name == name)?.Invalid == true;
var severity = invalid ? Severity.Invalid : Severity.Fishy;
data.AddLine(Get(string.Format(LRibbonMarkingAffixedF_0, affix), severity));
}
private static bool IsMoveSetEvolvedShedinja(PK8 pk8)
{
if (pk8.HasMove((int) Move.Screech))
return true;
if (pk8.HasMove((int) Move.SwordsDance))
return true;
if (pk8.HasMove((int) Move.Slash))
return true;
if (pk8.HasMove((int) Move.BatonPass))
return true;
return pk8.HasMove((int)Move.Agility) && !pk8.GetMoveRecordFlag(12);
}
private void EnsureHasRibbon(LegalityAnalysis data, PK8 pk8, sbyte affix)
{
var hasRibbon = pk8.GetRibbonIndex((RibbonIndex) affix);
if (!hasRibbon)
data.AddLine(GetInvalid(string.Format(LRibbonMarkingAffixedF_0, (RibbonIndex) affix)));
} }
} }
} }

View file

@ -14,6 +14,7 @@ namespace PKHeX.Core
public override void Verify(LegalityAnalysis data) public override void Verify(LegalityAnalysis data)
{ {
// Flag VC (Gen1/2) ribbons using Gen7 origin rules.
var enc = data.EncounterMatch; var enc = data.EncounterMatch;
var pkm = data.pkm; var pkm = data.pkm;
@ -25,8 +26,7 @@ namespace PKHeX.Core
return; return;
} }
int gen = enc.Generation; // Flag VC (Gen1/2) ribbons using Gen7 origin rules. var result = GetIncorrectRibbons(pkm, enc);
var result = GetIncorrectRibbons(pkm, enc, gen);
if (result.Count != 0) if (result.Count != 0)
{ {
var msg = string.Join(Environment.NewLine, result); var msg = string.Join(Environment.NewLine, result);
@ -38,11 +38,11 @@ namespace PKHeX.Core
} }
} }
private static List<string> GetIncorrectRibbons(PKM pkm, IEncounterable enc, int gen) private static List<string> GetIncorrectRibbons(PKM pkm, IEncounterable enc)
{ {
List<string> missingRibbons = new(); List<string> missingRibbons = new();
List<string> invalidRibbons = new(); List<string> invalidRibbons = new();
var ribs = GetRibbonResults(pkm, enc, gen); var ribs = GetRibbonResults(pkm, enc);
foreach (var bad in ribs) foreach (var bad in ribs)
(bad.Invalid ? invalidRibbons : missingRibbons).Add(bad.Name); (bad.Invalid ? invalidRibbons : missingRibbons).Add(bad.Name);
@ -75,14 +75,14 @@ namespace PKHeX.Core
return false; return false;
} }
private static IEnumerable<RibbonResult> GetRibbonResults(PKM pkm, IEncounterable enc, int gen) internal static IEnumerable<RibbonResult> GetRibbonResults(PKM pkm, IEncounterable enc)
{ {
return GetInvalidRibbons(pkm, enc, gen) return GetInvalidRibbons(pkm, enc)
.Concat(GetInvalidRibbonsEvent1(pkm, enc)) .Concat(GetInvalidRibbonsEvent1(pkm, enc))
.Concat(GetInvalidRibbonsEvent2(pkm, enc)); .Concat(GetInvalidRibbonsEvent2(pkm, enc));
} }
private static IEnumerable<RibbonResult> GetInvalidRibbons(PKM pkm, IEncounterable enc, int gen) private static IEnumerable<RibbonResult> GetInvalidRibbons(PKM pkm, IEncounterable enc)
{ {
if (pkm is IRibbonSetOnly3 o3) if (pkm is IRibbonSetOnly3 o3)
{ {
@ -91,7 +91,7 @@ namespace PKHeX.Core
} }
if (pkm is IRibbonSetUnique3 u3) if (pkm is IRibbonSetUnique3 u3)
{ {
if (gen != 3) if (enc.Generation != 3)
{ {
if (u3.RibbonWinning) if (u3.RibbonWinning)
yield return new RibbonResult(nameof(u3.RibbonWinning)); yield return new RibbonResult(nameof(u3.RibbonWinning));
@ -107,6 +107,7 @@ namespace PKHeX.Core
} }
} }
int gen = enc.Generation;
if (pkm is IRibbonSetUnique4 u4) if (pkm is IRibbonSetUnique4 u4)
{ {
if (!IsAllowedBattleFrontier(pkm.Species, pkm.Form, 4) || gen > 4) if (!IsAllowedBattleFrontier(pkm.Species, pkm.Form, 4) || gen > 4)