mirror of
https://github.com/kwsch/PKHeX
synced 2025-02-18 14:28:33 +00:00
We implement simple state machine iterators to iterate through every split type encounter array, and more finely control the path we iterate through. And, by using generics, we can have the compiler generate optimized code to avoid virtual calls. In addition to this, we shift away from the big-5 encounter types and not inherit from an abstract class. This allows for creating a PK* of a specific type and directly writing properties (no virtual calls). Plus we can now fine-tune each encounter type to call specific code, and not have to worry about future game encounter types bothering the generation routines.
320 lines
9.3 KiB
C#
320 lines
9.3 KiB
C#
using System;
|
|
using System.Linq;
|
|
using FluentAssertions;
|
|
using Xunit;
|
|
|
|
namespace PKHeX.Core.Tests.Simulator;
|
|
|
|
public class ShowdownSetTests
|
|
{
|
|
[Fact]
|
|
public void SimulatorGetParse()
|
|
{
|
|
foreach (ReadOnlySpan<char> setstr in Sets)
|
|
{
|
|
var set = new ShowdownSet(setstr).GetSetLines();
|
|
foreach (var line in set)
|
|
setstr.Contains(line, StringComparison.Ordinal).Should().BeTrue($"Line {line} should be in the set {setstr}");
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void SimulatorGetEncounters()
|
|
{
|
|
var set = new ShowdownSet(SetGlaceonUSUMTutor);
|
|
var pk7 = new PK7 {Species = set.Species, Form = set.Form, Moves = set.Moves};
|
|
var encounters = EncounterMovesetGenerator.GenerateEncounters(pk7, set.Moves, GameVersion.MN);
|
|
Assert.True(!encounters.Any());
|
|
pk7.HT_Name = "PKHeX";
|
|
encounters = EncounterMovesetGenerator.GenerateEncounters(pk7, set.Moves, GameVersion.MN);
|
|
var first = encounters.FirstOrDefault();
|
|
Assert.NotNull(first);
|
|
|
|
var egg = (EncounterEgg)first;
|
|
var info = new SimpleTrainerInfo(GameVersion.SN);
|
|
var pk = egg.ConvertToPKM(info);
|
|
Assert.True(pk.Species != set.Species);
|
|
|
|
var la = new LegalityAnalysis(pk);
|
|
la.Valid.Should().BeTrue($"Encounter should have generated legally: {egg} {la.Report()}");
|
|
|
|
var test = EncounterMovesetGenerator.GenerateEncounters(pk7, info, pk7.Moves).ToList();
|
|
for (var i = 0; i < test.Count; i++)
|
|
{
|
|
var t = test[i];
|
|
var convert = t.ConvertToPKM(info);
|
|
var la2 = new LegalityAnalysis(convert);
|
|
la2.Valid.Should().BeTrue($"Encounter {i} should have generated legally: {t} {la2.Report()}");
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void SimGetVivillonPostcardSV()
|
|
{
|
|
var pk9 = new PK9 { Species = (int)Species.Vivillon, Form = 1 };
|
|
var encounters = EncounterMovesetGenerator.GenerateEncounters(pk9, Array.Empty<ushort>(), GameVersion.SL);
|
|
encounters.OfType<EncounterSlot9>().Should().NotBeEmpty();
|
|
|
|
pk9 = new PK9 { Species = (int)Species.Vivillon, Form = Vivillon3DS.FancyFormID };
|
|
encounters = EncounterMovesetGenerator.GenerateEncounters(pk9, Array.Empty<ushort>(), GameVersion.SL);
|
|
encounters.OfType<EncounterSlot9>().Should().NotBeEmpty();
|
|
}
|
|
|
|
[Fact]
|
|
public void SimulatorGetWC3()
|
|
{
|
|
var set = new ShowdownSet(SetROCKSMetang);
|
|
var pk3 = new PK3 { Species = set.Species, Form = set.Form, Moves = set.Moves };
|
|
var encs = EncounterMovesetGenerator.GenerateEncounters(pk3, set.Moves, GameVersion.R);
|
|
Assert.True(encs.Any());
|
|
encs = EncounterMovesetGenerator.GenerateEncounters(pk3, set.Moves, GameVersion.R);
|
|
var first = encs.FirstOrDefault();
|
|
Assert.NotNull(first);
|
|
|
|
var wc3 = (WC3)first;
|
|
var info = new SimpleTrainerInfo(GameVersion.R);
|
|
var pk = wc3.ConvertToPKM(info);
|
|
|
|
var la = new LegalityAnalysis(pk);
|
|
Assert.True(la.Valid);
|
|
}
|
|
|
|
[Fact]
|
|
public void SimulatorGetCelebi()
|
|
{
|
|
var set = new ShowdownSet(SetCelebi);
|
|
var pk7 = new PK7 { Species = set.Species, Form = set.Form, Moves = set.Moves };
|
|
var encs = EncounterMovesetGenerator.GenerateEncounters(pk7, set.Moves, GameVersion.X);
|
|
Assert.True(encs.Any());
|
|
encs = EncounterMovesetGenerator.GenerateEncounters(pk7, set.Moves, GameVersion.X);
|
|
var first = encs.FirstOrDefault();
|
|
Assert.NotNull(first);
|
|
|
|
var info = new SimpleTrainerInfo(GameVersion.SN);
|
|
var pk = first.ConvertToPKM(info);
|
|
|
|
var la = new LegalityAnalysis(pk);
|
|
Assert.True(la.Valid);
|
|
}
|
|
|
|
[Fact]
|
|
public void SimulatorGetSplitBreed()
|
|
{
|
|
var set = new ShowdownSet(SetMunchSnorLax);
|
|
var pk7 = new PK7 { Species = set.Species, Form = set.Form, Moves = set.Moves, HT_Name = "PKHeX" }; // !! specify the HT name, we need tutors for this one
|
|
var encs = EncounterMovesetGenerator.GenerateEncounters(pk7, set.Moves, GameVersion.SN).ToList();
|
|
Assert.True(encs.Count > 0);
|
|
Assert.True(encs.All(z => z.Species > 150));
|
|
|
|
var info = new SimpleTrainerInfo(GameVersion.SN);
|
|
var enc = encs[0];
|
|
var pk = enc.ConvertToPKM(info);
|
|
|
|
var la = new LegalityAnalysis(pk);
|
|
Assert.True(la.Valid);
|
|
}
|
|
|
|
[Fact]
|
|
public void SimulatorGetVCEgg1()
|
|
{
|
|
var set = new ShowdownSet(SetSlowpoke12);
|
|
var pk7 = new PK7 { Species = set.Species, Form = set.Form, Moves = set.Moves, HT_Name = "PKHeX" };
|
|
var encs = EncounterMovesetGenerator.GenerateEncounters(pk7, set.Moves, GameVersion.GD).ToList();
|
|
Assert.True(encs.Count > 0);
|
|
|
|
var info = new SimpleTrainerInfo(GameVersion.SN);
|
|
var enc = encs[0];
|
|
var pk = enc.ConvertToPKM(info);
|
|
|
|
var la = new LegalityAnalysis(pk);
|
|
Assert.True(la.Valid);
|
|
}
|
|
|
|
[Fact]
|
|
public void SimulatorGetSmeargle()
|
|
{
|
|
var set = new ShowdownSet(SetSmeargle);
|
|
var pk7 = new PK7 { Species = set.Species, Form = set.Form, Moves = set.Moves };
|
|
var encs = EncounterMovesetGenerator.GenerateEncounters(pk7, set.Moves, GameVersion.MN);
|
|
Assert.True(encs.Any());
|
|
encs = EncounterMovesetGenerator.GenerateEncounters(pk7, set.Moves, GameVersion.MN);
|
|
var first = encs.FirstOrDefault();
|
|
Assert.NotNull(first);
|
|
|
|
var info = new SimpleTrainerInfo(GameVersion.SN);
|
|
var pk = first.ConvertToPKM(info);
|
|
|
|
var la = new LegalityAnalysis(pk);
|
|
Assert.True(la.Valid);
|
|
}
|
|
|
|
[Fact]
|
|
public void SimulatorParseMultiple()
|
|
{
|
|
var text = string.Join("\r\n\r\n", Sets);
|
|
var sets = ShowdownParsing.GetShowdownSets(text);
|
|
Assert.True(sets.Count() == Sets.Length);
|
|
|
|
sets = ShowdownParsing.GetShowdownSets(string.Empty);
|
|
Assert.True(!sets.Any());
|
|
|
|
sets = ShowdownParsing.GetShowdownSets(new [] {"", " ", " "});
|
|
Assert.True(!sets.Any());
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(SetDuplicateMoves, 3)]
|
|
public void SimulatorParseDuplicate(string text, int moveCount)
|
|
{
|
|
var set = new ShowdownSet(text);
|
|
var actual = set.Moves.Count(z => z != 0);
|
|
actual.Should().Be(moveCount);
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(LowLevelElectrode)]
|
|
public void SimulatorParseEncounter(string text)
|
|
{
|
|
var set = new ShowdownSet(text);
|
|
var pk7 = new PK3 { Species = set.Species, Form = set.Form, Moves = set.Moves, CurrentLevel = set.Level };
|
|
var encs = EncounterMovesetGenerator.GenerateEncounters(pk7, set.Moves);
|
|
var tr3 = encs.First(z => z is EncounterTrade3);
|
|
var pk3 = tr3.ConvertToPKM(new SAV3FRLG());
|
|
|
|
var la = new LegalityAnalysis(pk3);
|
|
la.Valid.Should().BeTrue(la.Report());
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(-1)]
|
|
[InlineData(256)]
|
|
public void BadFriendshipNotParsed(int value)
|
|
{
|
|
string input = $@"Eevee\nFriendship: {value}";
|
|
var set = new ShowdownSet(input);
|
|
set.Friendship.Should().NotBe(value);
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(-1)]
|
|
[InlineData(0)]
|
|
[InlineData(101)]
|
|
public void BadLevelNotParsed(int value)
|
|
{
|
|
string input = $@"Eevee\nLevel: {value}";
|
|
var set = new ShowdownSet(input);
|
|
set.Level.Should().NotBe(value);
|
|
}
|
|
|
|
private const string LowLevelElectrode =
|
|
@"BOLICHI (Electrode)
|
|
IVs: 19 HP / 16 Atk / 18 Def / 25 SpA / 19 SpD / 25 Spe
|
|
Ability: Static
|
|
Level: 3
|
|
Hasty Nature
|
|
- Charge
|
|
- Tackle
|
|
- Screech
|
|
- Sonic Boom";
|
|
|
|
private const string SetDuplicateMoves =
|
|
@"Kingler-Gmax @ Master Ball
|
|
Ability: Sheer Force
|
|
Shiny: Yes
|
|
EVs: 252 Atk / 4 SpD / 252 Spe
|
|
Jolly Nature
|
|
- Crabhammer
|
|
- Rock Slide
|
|
- Rock Slide
|
|
- X-Scissor";
|
|
|
|
private const string SetROCKSMetang =
|
|
@"Metang
|
|
IVs: 20 HP / 3 Atk / 26 Def / 1 SpA / 6 SpD / 8 Spe
|
|
Ability: Clear Body
|
|
Level: 30
|
|
Adamant Nature
|
|
- Take Down
|
|
- Confusion
|
|
- Metal Claw
|
|
- Refresh";
|
|
|
|
private const string SetGlaceonUSUMTutor =
|
|
@"Glaceon (F) @ Assault Vest
|
|
IVs: 0 Atk
|
|
EVs: 252 HP / 252 SpA / 4 SpD
|
|
Ability: Ice Body
|
|
Shiny: Yes
|
|
Modest Nature
|
|
- Blizzard
|
|
- Water Pulse
|
|
- Shadow Ball
|
|
- Hyper Voice";
|
|
|
|
private const string SetSmeargle =
|
|
@"Smeargle @ Focus Sash
|
|
Ability: Own Tempo
|
|
EVs: 248 HP / 8 Def / 252 Spe
|
|
Jolly Nature
|
|
- Sticky Web
|
|
- Nuzzle
|
|
- Taunt
|
|
- Whirlwind";
|
|
|
|
private const string SetCelebi =
|
|
@"Celebi @ Toxic Orb
|
|
Ability: Natural Cure
|
|
Jolly Nature
|
|
- Recover
|
|
- Heal Bell
|
|
- Safeguard
|
|
- Hold Back";
|
|
|
|
private const string SetNicknamedTypeNull =
|
|
@"Reliance (Type: Null) @ Eviolite
|
|
EVs: 252 HP / 4 Def / 252 SpD
|
|
Ability: Battle Armor
|
|
Careful Nature
|
|
- Facade
|
|
- Swords Dance
|
|
- Sleep Talk
|
|
- Rest";
|
|
|
|
private const string SetMunchSnorLax =
|
|
@"Snorlax @ Choice Band
|
|
Ability: Thick Fat
|
|
Level: 50
|
|
EVs: 84 HP / 228 Atk / 180 Def / 12 SpD / 4 Spe
|
|
Adamant Nature
|
|
- Double-Edge
|
|
- High Horsepower
|
|
- Self-Destruct
|
|
- Fire Punch";
|
|
|
|
private const string SetSlowpoke12 =
|
|
@"Threat (Slowpoke) @ Eviolite
|
|
Ability: Regenerator
|
|
Shiny: Yes
|
|
EVs: 248 HP / 252 Atk / 8 SpD
|
|
Adamant Nature
|
|
- Body Slam
|
|
- Earthquake
|
|
- Belly Drum
|
|
- Iron Tail";
|
|
|
|
private static readonly string[] Sets =
|
|
{
|
|
SetGlaceonUSUMTutor,
|
|
SetNicknamedTypeNull,
|
|
SetMunchSnorLax,
|
|
|
|
@"Greninja @ Choice Specs
|
|
Ability: Battle Bond
|
|
EVs: 252 SpA / 4 SpD / 252 Spe
|
|
Timid Nature
|
|
- Hydro Pump
|
|
- Spikes
|
|
- Water Shuriken
|
|
- Dark Pulse",
|
|
};
|
|
}
|