public async Task Bulbasaur() { PokemonInfoTable pokeInfo = await ORASConfig.GameConfig.GetPokemonInfo(); TmsHms tmsHms = await ORASConfig.GameConfig.GetTmsHms(); PokemonInfo nullInfo = pokeInfo[0]; PokemonInfo bulbasaurInfo = pokeInfo[Species.Bulbasaur]; Assert.AreNotEqual(nullInfo, bulbasaurInfo, "Species info for Bulbasaur is the same as Null/Egg"); Assert.AreEqual(6.9, bulbasaurInfo.WeightKg, "Species weight for Bulbasaur doesn't match the Pokedex!"); Assert.AreEqual(0.7, bulbasaurInfo.HeightM, "Species height for Bulbasaur doesn't match the Pokedex!"); Assert.AreEqual(PokemonTypes.Grass, PokemonTypes.GetValueFrom(bulbasaurInfo.Types[0]), "Bulbasaur's primary type should be Grass!"); Assert.AreEqual(PokemonTypes.Poison, PokemonTypes.GetValueFrom(bulbasaurInfo.Types[1]), "Bulbasaur's secondary type should be Poison!"); TestContext.Out.WriteLine("Bulbasaur can learn the following TMs:"); foreach (var(_, tm) in bulbasaurInfo.TmHm .Select((b, i) => (b, i)) .Where(t => t.Item1)) { string type = tm >= tmsHms.TmIds.Length ? "HM" : "TM"; int num = (type == "HM") ? (tm - 100 + 1) : (tm + 1); TestContext.Out.WriteLine($"\t{type} {num}: {tmsHms.GetMove( tm ).Name}"); } }
public override async Task RandomizeLearnsets(ProgressNotifier progressNotifier, CancellationToken token) { progressNotifier?.NotifyUpdate(ProgressUpdate.StatusOnly("Randomizing learnsets...")); var config = this.ValidateAndGetConfig().Learnsets; var learnsets = (await this.Game.GetLearnsets()).ToList(); var speciesInfo = await this.Game.GetPokemonInfo(edited : true); var moves = (await this.Game.GetMoves()).ToList(); var pokeNames = (await this.Game.GetTextFile(TextNames.SpeciesNames)).Lines; for (int i = 0; i < learnsets.Count; i++) { string name = pokeNames[speciesInfo.GetSpeciesForEntry(i)]; progressNotifier?.NotifyUpdate(ProgressUpdate.Update($"Randomizing learnsets...\n{name}", i / (double)learnsets.Count)); bool preferSameType; var learnset = learnsets[i]; var species = speciesInfo[i]; var chooseFrom = moves; var chooseFromSameType = chooseFrom.Where(mv => species.HasType(PokemonTypes.GetValueFrom(mv.Type))).ToList(); Move move; for (int m = 0; m < learnset.Moves.Length; m++) { preferSameType = config.FavorSameType && this.rand.Next(2) == 0; move = (preferSameType ? chooseFromSameType : chooseFrom).GetRandom(this.rand); learnset.Moves[m] = (ushort)moves.IndexOf(move); } if (config.RandomizeLevels) { learnset.Levels = learnset.Levels .Select(_ => (ushort)this.rand.Next(1, MathUtil.Clamp(config.LearnAllMovesBy, 10, 100))) .OrderBy(l => l) .ToArray(); } if (learnset.Levels.Length > 0) { // Make sure there's always at least one move on the Pokemon learnset.Levels[0] = 1; // Pick a random STAB/Normal attack move var firstMoveChoose = moves.Where(m => m.Type == PokemonTypes.Normal.Id || species.HasType(PokemonTypes.GetValueFrom(m.Type))) .Where(m => m.Category == Move.CategoryPhysical || m.Category == Move.CategorySpecial) .ToList(); move = firstMoveChoose.GetRandom(this.rand); learnset.Moves[0] = (ushort)moves.IndexOf(move); if (config.AtLeast4Moves) { if (learnset.Levels.Length < 4) { learnset.Levels = new ushort[4]; } if (learnset.Moves.Length < 4) { learnset.Moves = new ushort[4]; } // Make sure every Pokemon has at least 4 moves at level 1 for (int m = 1; m < 4; m++) { preferSameType = config.FavorSameType && this.rand.Next(2) == 0; move = (preferSameType ? chooseFromSameType : chooseFrom).GetRandom(this.rand); learnset.Levels[m] = 1; learnset.Moves[m] = (ushort)moves.IndexOf(move); } } // Go down the list and make sure there are no duplicates for (int m = learnset.Moves.Length - 1; m >= 0; m--) { while (Array.IndexOf(learnset.Moves, learnset.Moves[m], 0, m) >= 0) { preferSameType = config.FavorSameType && this.rand.Next(2) == 0; move = (preferSameType ? chooseFromSameType : chooseFrom).GetRandom(this.rand); learnset.Moves[m] = (ushort)moves.IndexOf(move); } } } learnsets[i] = learnset; } await this.Game.SaveLearnsets(learnsets); }
public override async Task RandomizeEggMoves(Random taskRandom, ProgressNotifier progressNotifier, CancellationToken token) { var config = this.ValidateAndGetConfig().EggMoves; if (!config.RandomizeEggMoves) { return; } await this.LogAsync($"======== Beginning Egg Move randomization ========{Environment.NewLine}"); progressNotifier?.NotifyUpdate(ProgressUpdate.StatusOnly("Randomizing egg moves...")); var eggMovesList = await this.Game.GetEggMoves(); var speciesInfo = await this.Game.GetPokemonInfo(edited : true); var moves = (await this.Game.GetMoves()).ToList(); var pokeNames = (await this.Game.GetTextFile(TextNames.SpeciesNames)).Lines; var moveNames = (await this.Game.GetTextFile(TextNames.MoveNames)).Lines; for (var i = 0; i < eggMovesList.Length; i++) { var name = pokeNames[speciesInfo.GetSpeciesForEntry(i)]; var species = speciesInfo[i]; var eggMoves = eggMovesList[i]; var chooseFrom = moves.ToList(); // Clone list var chooseFromSameType = chooseFrom.Where(mv => species.HasType(PokemonTypes.GetValueFrom(mv.Type))).ToList(); var preferSameType = config.FavorSameType && taskRandom.NextDouble() < (double)config.SameTypePercentage; ushort PickRandomMove() { var move = (preferSameType ? chooseFromSameType : chooseFrom).GetRandom(taskRandom); var moveId = (ushort)moves.IndexOf(move); // We have to make sure the "-----" move is not picked because it breaks the game. Ideally // we would just exclude it from the list of considered moves, but to ensure seed-compatiblity // with the previous version of the randomizer, we need to keep the list of moves exactly // the same when we pull a random one. We then replace any "-----" choices with the first real // move. if (moveId == 0) { moveId++; } return(moveId); } if (eggMoves.Empty || eggMoves.Count == 0) { continue; } await this.LogAsync($"{name}:"); progressNotifier?.NotifyUpdate(ProgressUpdate.Update($"Randomizing egg moves...\n{name}", i / (double)eggMovesList.Length)); for (var m = 0; m < eggMoves.Count; m++) { eggMoves.Moves[m] = PickRandomMove(); await this.LogAsync($" - {moveNames[ eggMoves.Moves[ m ] ]}"); } await this.LogAsync(); eggMovesList[i] = eggMoves; } await this.Game.SaveEggMoves(eggMovesList); await this.LogAsync($"======== Finished Egg Move randomization ========{Environment.NewLine}"); }
public override async Task RandomizeLearnsets(Random taskRandom, ProgressNotifier progressNotifier, CancellationToken token) { var config = this.ValidateAndGetConfig().Learnsets; if (!config.RandomizeLearnsets) { return; } await this.LogAsync($"======== Beginning Learnset randomization ========{Environment.NewLine}"); progressNotifier?.NotifyUpdate(ProgressUpdate.StatusOnly("Randomizing learnsets...")); var learnsets = (await this.Game.GetLearnsets()).ToList(); var speciesInfo = await this.Game.GetPokemonInfo(edited : true); var moves = (await this.Game.GetMoves()).ToList(); var pokeNames = (await this.Game.GetTextFile(TextNames.SpeciesNames)).Lines; var moveNames = (await this.Game.GetTextFile(TextNames.MoveNames)).Lines; var maxMoveNameLength = moveNames.Max(n => n.Length); for (var i = 0; i < learnsets.Count; i++) { var name = pokeNames[speciesInfo.GetSpeciesForEntry(i)]; await this.LogAsync($"{name}:"); progressNotifier?.NotifyUpdate(ProgressUpdate.Update($"Randomizing learnsets...\n{name}", i / (double)learnsets.Count)); var learnset = learnsets[i]; var species = speciesInfo[i]; var chooseFrom = moves.ToList(); // Clone list var chooseFromSameType = chooseFrom.Where(mv => species.HasType(PokemonTypes.GetValueFrom(mv.Type))).ToList(); ushort PickRandomMove() { var preferSameType = config.FavorSameType && taskRandom.NextDouble() < (double)config.SameTypePercentage; var move = (preferSameType ? chooseFromSameType : chooseFrom).GetRandom(taskRandom); var moveId = (ushort)moves.IndexOf(move); // We have to make sure the "-----" move is not picked because it breaks the game. Ideally // we would just exclude it from the list of considered moves, but to ensure seed-compatiblity // with the previous version of the randomizer, we need to keep the list of moves exactly // the same when we pull a random one. We then replace any "-----" choices with the first real // move. if (moveId == 0) { moveId++; } // Same logic as above but for One-Hit KO moves if (config.NoOneHitMoves && Legality.Moves.OneHitMoves.Contains(moveId)) { moveId++; } return(moveId); } for (var m = 0; m < learnset.Moves.Length; m++) { learnset.Moves[m] = PickRandomMove(); } if (config.RandomizeLevels) { learnset.Levels = learnset.Levels .Select(_ => (ushort)taskRandom.Next(1, MathUtil.Clamp(config.LearnAllMovesBy, 10, 100))) .OrderBy(l => l) .ToArray(); } if (learnset.Levels.Length > 0) { // Make sure there's always at least one move on the Pokemon learnset.Levels[0] = 1; // Pick a random STAB/Normal attack move var firstMoveChoose = moves.Where(m => m.Type == PokemonTypes.Normal.Id || species.HasType(PokemonTypes.GetValueFrom(m.Type))) .Where(m => m.Category == Move.CategoryPhysical || m.Category == Move.CategorySpecial) .ToList(); var move = firstMoveChoose.GetRandom(taskRandom); learnset.Moves[0] = (ushort)moves.IndexOf(move); if (config.AtLeast4Moves) { if (learnset.Levels.Length < 4) { learnset.Levels = new ushort[4]; } if (learnset.Moves.Length < 4) { learnset.Moves = new ushort[4]; } // Make sure every Pokemon has at least 4 moves at level 1 for (var m = 1; m < 4; m++) { learnset.Levels[m] = 1; learnset.Moves[m] = PickRandomMove(); } } // Go down the list and make sure there are no duplicates for (var m = learnset.Moves.Length - 1; m >= 0; m--) { while (Array.IndexOf(learnset.Moves, learnset.Moves[m], 0, m) >= 0) { learnset.Moves[m] = PickRandomMove(); } } } for (var m = 0; m < learnset.Moves.Length; m++) { await this.LogAsync($" - {moveNames[ learnset.Moves[ m ] ].PadLeft( maxMoveNameLength )} @ Lv. {learnset.Levels[ m ]}"); } await this.LogAsync(); learnsets[i] = learnset; } await this.Game.SaveLearnsets(learnsets); await this.LogAsync($"======== Finished Learnset randomization ========{Environment.NewLine}"); }