Misc fixes

Ignore slot match for Swarm3
Honey Tree only yield possible slots via TID/SID
Pick min level for EncounterTrade1
Set nickname for CXD Elekid trade
Set held item for Pt Giratina
Set egg location for Ranch gift hatched egg
Set hidden ability flag for N's Darmanitan
Set XY Vivillon form based on generated geolocation
Force evolve Trade species if encounter requires it
Correctly recognize pikachu-colored-pichu Gen4 gift PID type
Set hatched manaphy egg's met location & date
This commit is contained in:
Kurt 2023-09-11 00:54:40 -07:00
parent b536388d0d
commit e3f8091971
19 changed files with 78 additions and 37 deletions

View file

@ -60,7 +60,7 @@ public sealed class EncounterGenerator3 : IEncounterGenerator
foreach (var enc in iterator)
{
var e = enc.Encounter;
if (e is not EncounterSlot3 s3)
if (e is not EncounterSlot3 s3 || s3 is EncounterSlot3Swarm)
{
yield return e;
continue;

View file

@ -20,9 +20,9 @@ public sealed class EncounterGenerator4 : IEncounterGenerator
return GetEncounters(pk, chain, info);
}
public IEnumerable<IEncounterable> GetPossible(PKM _, EvoCriteria[] chain, GameVersion game, EncounterTypeGroup groups)
public IEnumerable<IEncounterable> GetPossible(PKM pk, EvoCriteria[] chain, GameVersion game, EncounterTypeGroup groups)
{
var iterator = new EncounterPossible4(chain, groups, game);
var iterator = new EncounterPossible4(chain, groups, game, pk);
foreach (var enc in iterator)
yield return enc;
}

View file

@ -8,9 +8,9 @@ public sealed class EncounterGenerator8b : IEncounterGenerator
{
public static readonly EncounterGenerator8b Instance = new();
public IEnumerable<IEncounterable> GetPossible(PKM _, EvoCriteria[] chain, GameVersion game, EncounterTypeGroup groups)
public IEnumerable<IEncounterable> GetPossible(PKM pk, EvoCriteria[] chain, GameVersion game, EncounterTypeGroup groups)
{
var iterator = new EncounterPossible8b(chain, groups, game);
var iterator = new EncounterPossible8b(chain, groups, game, pk);
foreach (var enc in iterator)
yield return enc;
}

View file

@ -84,9 +84,9 @@ public static class EncounterMovesetGenerator
/// </summary>
/// <param name="pk">Rough Pokémon data which contains the requested species, gender, and form.</param>
/// <param name="info">Trainer information of the receiver.</param>
public static void OptimizeCriteria(PKM pk, ITrainerID16 info)
public static void OptimizeCriteria(PKM pk, ITrainerID32 info)
{
pk.TID16 = info.TID16; // Necessary for Gen2 Headbutt encounters.
pk.ID32 = info.ID32; // Necessary for Gen2 Headbutt encounters and Honey Tree encounters
var htTrash = pk.HT_Trash;
if (htTrash.Length != 0)
htTrash[0] = 1; // Fake Trash to indicate trading.

View file

@ -7,7 +7,7 @@ namespace PKHeX.Core;
/// <summary>
/// Iterates to find possible encounters for <see cref="GameVersion.Gen4"/> encounters.
/// </summary>
public record struct EncounterPossible4(EvoCriteria[] Chain, EncounterTypeGroup Flags, GameVersion Version) : IEnumerator<IEncounterable>
public record struct EncounterPossible4(EvoCriteria[] Chain, EncounterTypeGroup Flags, GameVersion Version, PKM Entity) : IEnumerator<IEncounterable>
{
public IEncounterable Current { get; private set; }
@ -181,23 +181,23 @@ public record struct EncounterPossible4(EvoCriteria[] Chain, EncounterTypeGroup
{ State = YieldState.SlotSS; goto case YieldState.SlotSS; }
throw new ArgumentOutOfRangeException(nameof(Version));
case YieldState.SlotHG:
if (TryGetNext<EncounterArea4, EncounterSlot4>(Encounters4HGSS.SlotsHG))
if (TryGetNext(Encounters4HGSS.SlotsHG))
return true;
goto case YieldState.SlotEnd;
case YieldState.SlotSS:
if (TryGetNext<EncounterArea4, EncounterSlot4>(Encounters4HGSS.SlotsSS))
if (TryGetNext(Encounters4HGSS.SlotsSS))
return true;
goto case YieldState.SlotEnd;
case YieldState.SlotD:
if (TryGetNext<EncounterArea4, EncounterSlot4>(Encounters4DPPt.SlotsD))
if (TryGetNext(Encounters4DPPt.SlotsD))
return true;
goto case YieldState.SlotEnd;
case YieldState.SlotP:
if (TryGetNext<EncounterArea4, EncounterSlot4>(Encounters4DPPt.SlotsP))
if (TryGetNext(Encounters4DPPt.SlotsP))
return true;
goto case YieldState.SlotEnd;
case YieldState.SlotPt:
if (TryGetNext<EncounterArea4, EncounterSlot4>(Encounters4DPPt.SlotsPt))
if (TryGetNext(Encounters4DPPt.SlotsPt))
return true;
goto case YieldState.SlotEnd;
case YieldState.SlotEnd:
@ -206,9 +206,7 @@ public record struct EncounterPossible4(EvoCriteria[] Chain, EncounterTypeGroup
return false;
}
private bool TryGetNext<TArea, TSlot>(TArea[] areas)
where TArea : class, IEncounterArea<TSlot>
where TSlot : class, IEncounterable, IEncounterMatch
private bool TryGetNext(EncounterArea4[] areas)
{
for (; Index < areas.Length; Index++, SubIndex = 0)
{
@ -236,7 +234,7 @@ public record struct EncounterPossible4(EvoCriteria[] Chain, EncounterTypeGroup
return false;
}
private bool TryGetNextSub<T>(T[] slots) where T : class, IEncounterable, IEncounterMatch
private bool TryGetNextSub(EncounterSlot4[] slots)
{
while (SubIndex < slots.Length)
{
@ -245,6 +243,8 @@ public record struct EncounterPossible4(EvoCriteria[] Chain, EncounterTypeGroup
{
if (enc.Species != evo.Species)
continue;
if (enc.IsInvalidMunchlaxTree(Entity))
continue;
return SetCurrent(enc);
}
}

View file

@ -7,7 +7,7 @@ namespace PKHeX.Core;
/// <summary>
/// Iterates to find possible encounters for <see cref="GameVersion.BDSP"/> encounters.
/// </summary>
public record struct EncounterPossible8b(EvoCriteria[] Chain, EncounterTypeGroup Flags, GameVersion Version) : IEnumerator<IEncounterable>
public record struct EncounterPossible8b(EvoCriteria[] Chain, EncounterTypeGroup Flags, GameVersion Version, PKM Entity) : IEnumerator<IEncounterable>
{
public IEncounterable Current { get; private set; }
@ -119,11 +119,11 @@ public record struct EncounterPossible8b(EvoCriteria[] Chain, EncounterTypeGroup
{ State = YieldState.SlotSP; goto case YieldState.SlotSP; }
throw new ArgumentOutOfRangeException(nameof(Version));
case YieldState.SlotBD:
if (TryGetNext<EncounterArea8b, EncounterSlot8b>(Encounters8b.SlotsBD))
if (TryGetNext(Encounters8b.SlotsBD))
return true;
goto case YieldState.SlotEnd;
case YieldState.SlotSP:
if (TryGetNext<EncounterArea8b, EncounterSlot8b>(Encounters8b.SlotsSP))
if (TryGetNext(Encounters8b.SlotsSP))
return true;
goto case YieldState.SlotEnd;
case YieldState.SlotEnd:
@ -132,9 +132,7 @@ public record struct EncounterPossible8b(EvoCriteria[] Chain, EncounterTypeGroup
return false;
}
private bool TryGetNext<TArea, TSlot>(TArea[] areas)
where TArea : class, IEncounterArea<TSlot>
where TSlot : class, IEncounterable, IEncounterMatch
private bool TryGetNext(EncounterArea8b[] areas)
{
for (; Index < areas.Length; Index++, SubIndex = 0)
{
@ -145,7 +143,7 @@ public record struct EncounterPossible8b(EvoCriteria[] Chain, EncounterTypeGroup
return false;
}
private bool TryGetNextSub<T>(T[] slots) where T : class, IEncounterable, IEncounterMatch
private bool TryGetNextSub(EncounterSlot8b[] slots)
{
while (SubIndex < slots.Length)
{
@ -154,6 +152,8 @@ public record struct EncounterPossible8b(EvoCriteria[] Chain, EncounterTypeGroup
{
if (enc.Species != evo.Species)
continue;
if (enc.IsInvalidMunchlaxTree(Entity))
continue;
return SetCurrent(enc);
}
}

View file

@ -112,7 +112,8 @@ public sealed record EncounterTrade1 : IEncounterable, IEncounterMatch, IFixedTr
public PK1 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
{
var level = ParseSettings.AllowGen1Tradeback ? LevelMinGSC : LevelMinRBY;
bool gsc = CanObtainMinGSC();
var level = gsc ? LevelMinGSC : LevelMinRBY;
int lang = (int)Language.GetSafeLanguage(Generation, (LanguageID)tr.Language, Version);
var isJapanese = lang == (int)LanguageID.Japanese;
var pi = EncounterUtil1.GetPersonal1(Version, Species);
@ -131,6 +132,8 @@ public sealed record EncounterTrade1 : IEncounterable, IEncounterMatch, IFixedTr
pk.OT_Trash[0] = StringConverter12.G1TradeOTCode;
EncounterUtil1.SetEncounterMoves(pk, Version, level);
if (EvolveOnTrade)
pk.Species++;
pk.ResetPartyStats();
@ -170,7 +173,7 @@ public sealed record EncounterTrade1 : IEncounterable, IEncounterMatch, IFixedTr
private bool IsMatchLevel(PKM pk, int lvl)
{
if (pk is not PK1)
if (pk is not PK1 || CanObtainMinGSC())
return lvl >= LevelMinGSC;
return lvl >= LevelMin;
}

View file

@ -9,9 +9,5 @@ namespace PKHeX.Core;
internal sealed record EncounterSlot3Swarm(EncounterArea3 Parent, ushort Species, byte LevelMin, byte LevelMax, byte SlotNumber, Moveset Moves)
: EncounterSlot3(Parent, Species, 0, LevelMin, LevelMax, SlotNumber, 0, 0, 0, 0), IMoveset
{
protected override void SetEncounterMoves(PKM pk)
{
pk.SetMoves(Moves);
pk.SetMaximumPPCurrent(Moves);
}
protected override void SetEncounterMoves(PKM pk) => pk.SetMoves(Moves);
}

View file

@ -76,7 +76,7 @@ public sealed record EncounterTrade3XD : IEncounterable, IEncounterMatch, IEncou
OT_Gender = 0,
TID16 = TID16,
SID16 = tr.SID16,
Nickname = SpeciesName.GetSpeciesNameGeneration(Species, lang, Generation),
Nickname = IsFixedNickname ? GetNickname(lang) : SpeciesName.GetSpeciesNameGeneration(Species, lang, Generation),
};
SetPINGA(pk, criteria, pi);

View file

@ -122,12 +122,19 @@ public sealed record EncounterSlot4(EncounterArea4 Parent, ushort Species, byte
// A/B/C tables, only Munchlax is a 'C' encounter, and A/B are accessible from any tree.
// C table encounters are only available from 4 trees, which are determined by TID16/SID16 of the save file.
if (Type is SlotType.HoneyTree && Species == (int)Core.Species.Munchlax && !Parent.IsMunchlaxTree(pk))
if (IsInvalidMunchlaxTree(pk))
return false;
return true;
}
public bool IsInvalidMunchlaxTree(PKM pk)
{
if (Type is not SlotType.HoneyTree)
return false;
return Species == (int)Core.Species.Munchlax && !Parent.IsMunchlaxTree(pk);
}
public EncounterMatchRating GetMatchRating(PKM pk)
{
if ((pk.Ball == (int)Ball.Safari) != Locations.IsSafariZoneLocation4(Location))

View file

@ -83,6 +83,10 @@ public sealed record EncounterStatic4(GameVersion Version)
pk.Egg_Location = EggLocation;
pk.EggMetDate = pk.MetDate;
}
else if (Species == (int)Core.Species.Giratina && Form == 1)
{
pk.HeldItem = 0112; // Griseous Orb
}
SetPINGA(pk, criteria, pi);
if (Moves.HasMoves)

View file

@ -105,6 +105,12 @@ public sealed record EncounterTrade4RanchGift
HT_Gender = tr.Gender,
};
if (EggLocation != 0)
{
pk.Egg_Location = EggLocation;
pk.EggMetDate = pk.MetDate;
}
if (Moves.HasMoves)
pk.SetMoves(Moves);
else

View file

@ -81,6 +81,7 @@ public sealed record EncounterStatic5N(uint PID)
AbilityPermission.OnlySecond => pi.Ability2,
_ => pi.AbilityH,
},
HiddenAbility = Ability == AbilityPermission.OnlyHidden,
};
EncounterUtil1.SetEncounterMoves(pk, version, LevelMin);

View file

@ -76,6 +76,9 @@ public sealed record EncounterSlot6XY(EncounterArea6XY Parent, ushort Species, b
else
pk.SetDefaultRegionOrigins(lang);
if (IsRandomUnspecificForm && Form == EncounterUtil1.FormVivillon)
pk.Form = Vivillon3DS.GetPattern(pk.Country, pk.Region);
SetPINGA(pk, criteria);
EncounterUtil1.SetEncounterMoves(pk, Version, LevelMin);
pk.SetRandomMemory6();
@ -85,8 +88,11 @@ public sealed record EncounterSlot6XY(EncounterArea6XY Parent, ushort Species, b
private byte GetWildForm(byte form)
{
if (form != EncounterUtil1.FormRandom)
if (form < EncounterUtil1.FormDynamic)
return form;
if (form == EncounterUtil1.FormVivillon)
return 0; // rectify later
// flagged as totally random
return (byte)Util.Rand.Next(PersonalTable.XY[Species].FormCount);
}

View file

@ -107,6 +107,9 @@ public sealed record EncounterTrade7 : IEncounterable, IEncounterMatch, IFixedTr
if (pk.IsShiny)
pk.PID ^= 0x1000_0000;
criteria.SetRandomIVs(pk, IVs);
if (EvolveOnTrade)
pk.Species++;
pk.RefreshAbility(criteria.GetAbilityFromNumber(Ability));
pk.ResetPartyStats();

View file

@ -137,12 +137,19 @@ public sealed record EncounterSlot8b(EncounterArea8b Parent, ushort Species, byt
// A/B/C tables, only Munchlax is a 'C' encounter, and A/B are accessible from any tree.
// C table encounters are only available from 4 trees, which are determined by TID16/SID16 of the save file.
if (Type is SlotType.HoneyTree && Species == (int)Core.Species.Munchlax && !Parent.IsMunchlaxTree(pk))
if (IsInvalidMunchlaxTree(pk))
return false;
return true;
}
public bool IsInvalidMunchlaxTree(PKM pk)
{
if (Type is not SlotType.HoneyTree)
return false;
return Species == (int)Core.Species.Munchlax && !Parent.IsMunchlaxTree(pk);
}
public EncounterMatchRating GetMatchRating(PKM pk)
{
bool isHidden = pk.AbilityNumber == 4;
@ -175,5 +182,4 @@ public sealed record EncounterSlot8b(EncounterArea8b Parent, ushort Species, byt
return baseEgg.Contains(move);
}
#endregion
}

View file

@ -102,6 +102,8 @@ public sealed record EncounterTrade9
EncounterUtil1.SetEncounterMoves(pk, version, Level);
SetPINGA(pk, criteria, pi);
if (EvolveOnTrade)
pk.Species++;
pk.ResetPartyStats();

View file

@ -12,7 +12,7 @@ namespace PKHeX.Core;
/// https://projectpokemon.org/home/forums/topic/5870-pok%C3%A9mon-mystery-gift-editor-v143-now-with-bw-support/
/// See also: http://tccphreak.shiny-clique.net/debugger/pcdfiles.htm
/// </remarks>
public sealed class PCD : DataMysteryGift, IRibbonSetEvent3, IRibbonSetEvent4, IRestrictVersion
public sealed class PCD : DataMysteryGift, IRibbonSetEvent3, IRibbonSetEvent4, IRestrictVersion, IRandomCorrelation
{
public const int Size = 0x358; // 856
public override int Generation => 4;
@ -100,6 +100,9 @@ public sealed class PCD : DataMysteryGift, IRibbonSetEvent3, IRibbonSetEvent4, I
public override int Location { get => IsEgg ? 0 : Gift.EggLocation + 3000; set { } }
public override int EggLocation { get => IsEgg ? Gift.EggLocation + 3000 : 0; set { } }
public bool IsCompatible(PIDType val, PKM pk) => Gift.IsCompatible(val, pk);
public PIDType GetSuggestedCorrelation() => Gift.GetSuggestedCorrelation();
public bool GiftEquals(PGT pgt)
{
// Skip over the PGT's "Corresponding PCD Slot" @ 0x02

View file

@ -196,6 +196,8 @@ public sealed class PGT : DataMysteryGift, IRibbonSetEvent3, IRibbonSetEvent4, I
pk4.Language = lang;
pk4.Egg_Location = 1; // Ranger (will be +3000 later)
pk4.Nickname = SpeciesName.GetSpeciesNameGeneration((int)Core.Species.Manaphy, lang, 4);
pk4.Met_Location = pk4.Version is (int)GameVersion.HG or (int)GameVersion.SS ? Locations.HatchLocationHGSS : Locations.HatchLocationDPPt;
pk4.MetDate = EncounterDate.GetDateNDS();
}
private void SetPINGA(PK4 pk4, EncounterCriteria criteria)
@ -306,6 +308,8 @@ public sealed class PGT : DataMysteryGift, IRibbonSetEvent3, IRibbonSetEvent4, I
{
if (IsManaphyEgg)
return IsG4ManaphyPIDValid(val, pk);
if (PK.PID != 1 && val == PIDType.G5MGShiny)
return true;
return val == PIDType.None;
}