mirror of
https://github.com/kwsch/pkNX.git
synced 2026-04-25 23:36:55 -05:00
Add trainer randomizer beginnings
This commit is contained in:
parent
d89d2f8cd5
commit
7582c5d307
11
pkNX.Randomization/Randomizers/MoveRandType.cs
Normal file
11
pkNX.Randomization/Randomizers/MoveRandType.cs
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
namespace pkNX.Randomization
|
||||
{
|
||||
public enum MoveRandType
|
||||
{
|
||||
None,
|
||||
Random,
|
||||
CurrentMoves,
|
||||
HighPowered,
|
||||
MetronomeOnly,
|
||||
}
|
||||
}
|
||||
58
pkNX.Randomization/Randomizers/TrainerRandSettings.cs
Normal file
58
pkNX.Randomization/Randomizers/TrainerRandSettings.cs
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
using System.ComponentModel;
|
||||
|
||||
namespace pkNX.Randomization
|
||||
{
|
||||
public class TrainerRandSettings
|
||||
{
|
||||
private const string General = nameof(General);
|
||||
private const string Classes = nameof(Classes);
|
||||
private const string Misc = nameof(Misc);
|
||||
private const string Pokémon = nameof(Pokémon);
|
||||
private const string Stats = nameof(Stats);
|
||||
private const string Moves = nameof(Moves);
|
||||
|
||||
[Category(General), Description("")]
|
||||
public int TeamCountMin { get; set; }
|
||||
[Category(General), Description("")]
|
||||
public int TeamCountMax { get; set; }
|
||||
[Category(General), Description("")]
|
||||
public bool TeamTypeThemed { get; set; }
|
||||
[Category(General), Description("")]
|
||||
public bool TrainerMaxAI { get; set; }
|
||||
[Category(General), Description("")]
|
||||
public bool ForceSpecialTeamCount6 { get; set; }
|
||||
|
||||
[Category(Classes), Description("")]
|
||||
public bool SkipSpecialClasses { get; set; }
|
||||
[Category(Classes), Description("")]
|
||||
public bool RandomTrainerClass { get; set; }
|
||||
|
||||
[Category(Pokémon), Description("")]
|
||||
public bool RandomizeTeam { get; set; }
|
||||
[Category(Pokémon), Description("")]
|
||||
public bool ForceFullyEvolved { get; set; }
|
||||
[Category(Pokémon), Description("")]
|
||||
public int ForceFullyEvolvedAtLevel { get; set; }
|
||||
|
||||
[Category(Pokémon), Description("")]
|
||||
public bool BoostLevel { get; set; }
|
||||
[Category(Pokémon), Description("")]
|
||||
public decimal LevelBoostRatio { get; set; }
|
||||
|
||||
[Category(Stats), Description("")]
|
||||
public bool RandomShinies { get; set; }
|
||||
[Category(Stats), Description("")]
|
||||
public decimal ShinyChance { get; set; }
|
||||
[Category(Stats), Description("")]
|
||||
public bool MaxIVs { get; set; }
|
||||
[Category(Stats), Description("")]
|
||||
public bool RandomAbilities { get; set; }
|
||||
[Category(Misc), Description("")]
|
||||
public bool AllowRandomMegaForms { get; set; }
|
||||
|
||||
[Category(Moves), Description("")]
|
||||
public bool BanFixedDamageMoves { get; set; }
|
||||
[Category(Moves), Description("")]
|
||||
public MoveRandType MoveRandType { get; set; }
|
||||
}
|
||||
}
|
||||
233
pkNX.Randomization/Randomizers/TrainerRandomizer.cs
Normal file
233
pkNX.Randomization/Randomizers/TrainerRandomizer.cs
Normal file
|
|
@ -0,0 +1,233 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using pkNX.Structures;
|
||||
|
||||
namespace pkNX.Randomization
|
||||
{
|
||||
public class TrainerRandomizer : Randomizer
|
||||
{
|
||||
private readonly GameInfo Info;
|
||||
private readonly PersonalTable Personal;
|
||||
private readonly VsTrainer[] Trainers;
|
||||
private readonly int[] PossibleHeldItems;
|
||||
private readonly Dictionary<int, int[]> MegaDictionary;
|
||||
private readonly Dictionary<int, int> IndexFixedCount;
|
||||
private readonly IList<int> SpecialClasses;
|
||||
|
||||
public LearnsetRandomizer Learn { get; set; }
|
||||
public SpeciesRandomizer RandSpec { get; set; }
|
||||
public MoveRandomizer RandMove { get; set; }
|
||||
public int ClassCount { get; set; }
|
||||
public IList<int> BannedMoves { get; set; }
|
||||
public static Func<TrainerPoke> GetBlank { get; set; }
|
||||
public IList<int> FinalEvo { get; set; } = Array.Empty<int>();
|
||||
|
||||
private TrainerRandSettings Settings;
|
||||
|
||||
public TrainerRandomizer(GameInfo info, PersonalTable t, VsTrainer[] trainers)
|
||||
{
|
||||
Trainers = trainers;
|
||||
Info = info;
|
||||
Personal = t;
|
||||
|
||||
PossibleHeldItems = Legal.GetRandomItemList(Info.Game);
|
||||
MegaDictionary = Legal.GetMegaDictionary(Info.Game);
|
||||
IndexFixedCount = GetFixedCountIndexes(Info.Game);
|
||||
SpecialClasses = GetSpecialClasses(Info.Game);
|
||||
}
|
||||
|
||||
public void Initialize(TrainerRandSettings settings) => Settings = settings;
|
||||
|
||||
public void SetBannedMoves(int[] moves)
|
||||
{
|
||||
var list = new List<int>(moves);
|
||||
list.AddRange(new[] { 165, 621, 464 }.Concat(Legal.Z_Moves)); // Struggle, Hyperspace Fury, Dark Void
|
||||
if (Settings.BanFixedDamageMoves)
|
||||
list.AddRange(MoveRandomizer.FixedDamageMoves);
|
||||
BannedMoves = list;
|
||||
}
|
||||
|
||||
public override void Execute()
|
||||
{
|
||||
foreach (var tr in Trainers)
|
||||
{
|
||||
if (tr.Team.Count == 0)
|
||||
continue;
|
||||
|
||||
// Trainer
|
||||
if (Settings.RandomTrainerClass)
|
||||
SetRandomClass(tr);
|
||||
SetupTeamCount(tr);
|
||||
if (Settings.TrainerMaxAI)
|
||||
tr.Self.AI |= 7;
|
||||
|
||||
// Team
|
||||
foreach (var pk in tr.Team)
|
||||
{
|
||||
DetermineSpecies(pk);
|
||||
UpdatePKMFromSettings(pk);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void SetupTeamCount(VsTrainer tr)
|
||||
{
|
||||
bool special = IndexFixedCount.TryGetValue(tr.ID, out var count);
|
||||
int min = special ? count : Settings.TeamCountMin;
|
||||
int max = special ? count : Settings.TeamCountMax;
|
||||
|
||||
var avgBST = (int)tr.Team.Average(pk => Personal[pk.Species].BST);
|
||||
int avgLevel = (int)tr.Team.Average(pk => pk.Level);
|
||||
var pinfo = Personal.Table.OrderBy(pk => Math.Abs(avgBST - pk.BST)).First();
|
||||
int avgSpec = Array.IndexOf(Personal.Table, pinfo);
|
||||
|
||||
if (Settings.ForceSpecialTeamCount6 && special && count == 6)
|
||||
{
|
||||
for (int g = tr.Team.Count; g < 6; g++)
|
||||
tr.Team.Add(GetBlankPKM(avgLevel, avgSpec));
|
||||
}
|
||||
else if (tr.Team.Count < min)
|
||||
{
|
||||
for (int p = tr.Team.Count; p < min; p++)
|
||||
tr.Team.Add(GetBlankPKM(avgLevel, avgSpec));
|
||||
}
|
||||
else if (tr.Team.Count > max)
|
||||
{
|
||||
tr.Team.RemoveRange(max, tr.Team.Count - max);
|
||||
}
|
||||
}
|
||||
|
||||
private void SetRandomClass(VsTrainer tr)
|
||||
{
|
||||
// ignore special classes
|
||||
if (Settings.SkipSpecialClasses && !SpecialClasses.Contains(tr.Self.Class))
|
||||
{
|
||||
int randClass() => Util.Random.Next(ClassCount);
|
||||
int rv;
|
||||
do
|
||||
{
|
||||
rv = randClass();
|
||||
} while (SpecialClasses.Contains(rv)); // don't allow disallowed classes
|
||||
tr.Self.Class = rv;
|
||||
}
|
||||
|
||||
// all classes
|
||||
else if (!Settings.SkipSpecialClasses)
|
||||
{
|
||||
int randClass() => Util.Random.Next(ClassCount);
|
||||
int rv;
|
||||
do
|
||||
{
|
||||
rv = randClass();
|
||||
} while (rv == 082); // Lusamine 2 can crash multi battles, skip
|
||||
tr.Self.Class = rv;
|
||||
}
|
||||
}
|
||||
|
||||
private void DetermineSpecies(IPokeData pk)
|
||||
{
|
||||
if (Settings.RandomizeTeam)
|
||||
{
|
||||
int Type = Settings.TeamTypeThemed ? Util.Random.Next(17) : -1;
|
||||
|
||||
// replaces Megas with another Mega (Dexio and Lysandre in USUM)
|
||||
if (MegaDictionary.Any(z => z.Value.Contains(pk.HeldItem)))
|
||||
{
|
||||
int[] mega = GetRandomMega(MegaDictionary, out int species);
|
||||
pk.Species = species;
|
||||
pk.HeldItem = mega[Util.Random.Next(mega.Length)];
|
||||
pk.Form = 0; // allow it to Mega Evolve naturally
|
||||
}
|
||||
|
||||
// every other pkm
|
||||
else
|
||||
{
|
||||
pk.Species = RandSpec.GetRandomSpeciesType(pk.Species, Type);
|
||||
pk.HeldItem = PossibleHeldItems[Util.Random.Next(PossibleHeldItems.Length)];
|
||||
pk.Form = Legal.GetRandomForme(pk.Species, Settings.AllowRandomMegaForms, true, Personal.Table);
|
||||
}
|
||||
|
||||
pk.Gender = 0; // random
|
||||
pk.Nature = Util.Random.Next(25); // random
|
||||
}
|
||||
|
||||
if (Settings.ForceFullyEvolved && pk.Level >= Settings.ForceFullyEvolvedAtLevel && !FinalEvo.Contains(pk.Species))
|
||||
{
|
||||
int randFinalEvo() => Util.Random.Next(FinalEvo.Count);
|
||||
pk.Species = FinalEvo[randFinalEvo()];
|
||||
pk.Form = Legal.GetRandomForme(pk.Species, Settings.AllowRandomMegaForms, true, Personal.Table);
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdatePKMFromSettings(TrainerPoke pk)
|
||||
{
|
||||
if (Settings.BoostLevel)
|
||||
pk.Level = Legal.GetModifiedLevel(pk.Level, Settings.LevelBoostRatio);
|
||||
if (Settings.RandomShinies)
|
||||
pk.Shiny = Util.Random.Next(0, 100 + 1) < Settings.ShinyChance;
|
||||
if (Settings.RandomAbilities)
|
||||
pk.Ability = (int)Util.Rand32() % 4;
|
||||
if (Settings.MaxIVs)
|
||||
pk.IVs = new[] { 31, 31, 31, 31, 31, 31 };
|
||||
|
||||
RandomizeEntryMoves(pk);
|
||||
}
|
||||
|
||||
private void RandomizeEntryMoves(TrainerPoke pk)
|
||||
{
|
||||
switch (Settings.MoveRandType)
|
||||
{
|
||||
case MoveRandType.Random: // Random
|
||||
pk.Moves = RandMove.GetRandomMoveset(pk.Species);
|
||||
break;
|
||||
case MoveRandType.CurrentMoves:
|
||||
pk.Moves = Learn.GetCurrentMoves(pk.Species, pk.Form, pk.Level);
|
||||
break;
|
||||
case MoveRandType.HighPowered:
|
||||
pk.Moves = Learn.GetHighPoweredMoves(pk.Species, pk.Form);
|
||||
break;
|
||||
case MoveRandType.MetronomeOnly: // Metronome
|
||||
pk.Moves = new[] { 118, 0, 0, 0 };
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
// sanitize moves
|
||||
var moves = pk.Moves;
|
||||
if (RandMove.SanitizeMovesetForBannedMoves(moves, pk.Species))
|
||||
pk.Moves = moves;
|
||||
}
|
||||
|
||||
private TrainerPoke GetBlankPKM(int avgLevel, int avgSpec)
|
||||
{
|
||||
var pk = GetBlank();
|
||||
pk.Species = RandSpec.GetRandomSpecies(avgSpec);
|
||||
pk.Level = avgLevel;
|
||||
return pk;
|
||||
}
|
||||
|
||||
private static int[] GetRandomMega(Dictionary<int, int[]> megas, out int species)
|
||||
{
|
||||
int rnd = Util.Random.Next(megas.Count);
|
||||
species = megas.Keys.ElementAt(rnd);
|
||||
return megas.Values.ElementAt(rnd);
|
||||
}
|
||||
|
||||
private static readonly int[] royal = { 081, 082, 083, 084, 185 };
|
||||
private static readonly Dictionary<int, int> FixedSM = royal.ToDictionary(z => z, _ => 1);
|
||||
|
||||
private static Dictionary<int, int> GetFixedCountIndexes(GameVersion game)
|
||||
{
|
||||
if (GameVersion.SM.Contains(game) || GameVersion.USUM.Contains(game))
|
||||
return FixedSM;
|
||||
return new Dictionary<int, int>();
|
||||
}
|
||||
|
||||
private static int[] GetSpecialClasses(GameVersion game)
|
||||
{
|
||||
return Array.Empty<int>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,10 +1,11 @@
|
|||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace pkNX.Structures
|
||||
{
|
||||
public static partial class Legal
|
||||
{
|
||||
internal static int GetRandomForme(int species, bool mega, bool alola, PersonalInfo[] stats = null)
|
||||
public static int GetRandomForme(int species, bool mega, bool alola, PersonalInfo[] stats = null)
|
||||
{
|
||||
if (stats == null)
|
||||
return 0;
|
||||
|
|
@ -31,7 +32,7 @@ internal static int GetRandomForme(int species, bool mega, bool alola, PersonalI
|
|||
/// <param name="level">Current Level.</param>
|
||||
/// <param name="factor">Modification factor.</param>
|
||||
/// <returns>Boosted (or reduced) level.</returns>
|
||||
internal static int GetModifiedLevel(int level, decimal factor)
|
||||
public static int GetModifiedLevel(int level, decimal factor)
|
||||
{
|
||||
int newlvl = (int)(level * factor);
|
||||
if (newlvl < 1)
|
||||
|
|
@ -41,7 +42,7 @@ internal static int GetModifiedLevel(int level, decimal factor)
|
|||
return newlvl;
|
||||
}
|
||||
|
||||
internal static int[] GetRandomItemList(GameVersion game)
|
||||
public static int[] GetRandomItemList(GameVersion game)
|
||||
{
|
||||
if (GameVersion.ORAS.Contains(game) || game == GameVersion.ORASDEMO)
|
||||
return Items_HeldAO.Concat(Items_Ball).Where(i => i != 0).ToArray();
|
||||
|
|
@ -54,5 +55,114 @@ internal static int[] GetRandomItemList(GameVersion game)
|
|||
|
||||
return new int[1];
|
||||
}
|
||||
|
||||
public static Dictionary<int, int[]> GetMegaDictionary(GameVersion game)
|
||||
{
|
||||
if (GameVersion.XY.Contains(game))
|
||||
return MegaDictionaryXY;
|
||||
if (GameVersion.GG.Contains(game))
|
||||
return MegaDictionaryGG;
|
||||
return MegaDictionaryAO;
|
||||
}
|
||||
|
||||
private static readonly Dictionary<int, int[]> MegaDictionaryXY = new Dictionary<int, int[]>
|
||||
{
|
||||
{003, new[] {659}}, // Venusaur @ Venusaurite
|
||||
{006, new[] {660, 678}}, // Charizard @ Charizardite X/Y
|
||||
{009, new[] {661}}, // Blastoise @ Blastoisinite
|
||||
{065, new[] {679}}, // Alakazam @ Alakazite
|
||||
{094, new[] {656}}, // Gengar @ Gengarite
|
||||
{115, new[] {675}}, // Kangaskhan @ Kangaskhanite
|
||||
{127, new[] {671}}, // Pinsir @ Pinsirite
|
||||
{130, new[] {676}}, // Gyarados @ Gyaradosite
|
||||
{142, new[] {672}}, // Aerodactyl @ Aerodactylite
|
||||
{150, new[] {662, 663}}, // Mewtwo @ Mewtwonite X/Y
|
||||
{181, new[] {658}}, // Ampharos @ Ampharosite
|
||||
{212, new[] {670}}, // Scizor @ Scizorite
|
||||
{214, new[] {680}}, // Heracross @ Heracronite
|
||||
{229, new[] {666}}, // Houndoom @ Houndoominite
|
||||
{248, new[] {669}}, // Tyranitar @ Tyranitarite
|
||||
{257, new[] {664}}, // Blaziken @ Blazikenite
|
||||
{282, new[] {657}}, // Gardevoir @ Gardevoirite
|
||||
{303, new[] {681}}, // Mawile @ Mawilite
|
||||
{306, new[] {667}}, // Aggron @ Aggronite
|
||||
{308, new[] {665}}, // Medicham @ Medichamite
|
||||
{310, new[] {682}}, // Manectric @ Manectite
|
||||
{354, new[] {668}}, // Banette @ Banettite
|
||||
{359, new[] {677}}, // Absol @ Absolite
|
||||
{380, new[] {684}}, // Latias @ Latiasite
|
||||
{381, new[] {685}}, // Latios @ Latiosite
|
||||
{445, new[] {683}}, // Garchomp @ Garchompite
|
||||
{448, new[] {673}}, // Lucario @ Lucarionite
|
||||
{460, new[] {674}}, // Abomasnow @ Abomasite
|
||||
};
|
||||
|
||||
private static readonly Dictionary<int, int[]> MegaDictionaryAO = new Dictionary<int, int[]>
|
||||
{
|
||||
{003, new[] {659}}, // Venusaur @ Venusaurite
|
||||
{006, new[] {660, 678}}, // Charizard @ Charizardite X/Y
|
||||
{009, new[] {661}}, // Blastoise @ Blastoisinite
|
||||
{065, new[] {679}}, // Alakazam @ Alakazite
|
||||
{094, new[] {656}}, // Gengar @ Gengarite
|
||||
{115, new[] {675}}, // Kangaskhan @ Kangaskhanite
|
||||
{127, new[] {671}}, // Pinsir @ Pinsirite
|
||||
{130, new[] {676}}, // Gyarados @ Gyaradosite
|
||||
{142, new[] {672}}, // Aerodactyl @ Aerodactylite
|
||||
{150, new[] {662, 663}}, // Mewtwo @ Mewtwonite X/Y
|
||||
{181, new[] {658}}, // Ampharos @ Ampharosite
|
||||
{212, new[] {670}}, // Scizor @ Scizorite
|
||||
{214, new[] {680}}, // Heracross @ Heracronite
|
||||
{229, new[] {666}}, // Houndoom @ Houndoominite
|
||||
{248, new[] {669}}, // Tyranitar @ Tyranitarite
|
||||
{257, new[] {664}}, // Blaziken @ Blazikenite
|
||||
{282, new[] {657}}, // Gardevoir @ Gardevoirite
|
||||
{303, new[] {681}}, // Mawile @ Mawilite
|
||||
{306, new[] {667}}, // Aggron @ Aggronite
|
||||
{308, new[] {665}}, // Medicham @ Medichamite
|
||||
{310, new[] {682}}, // Manectric @ Manectite
|
||||
{354, new[] {668}}, // Banette @ Banettite
|
||||
{359, new[] {677}}, // Absol @ Absolite
|
||||
{380, new[] {684}}, // Latias @ Latiasite
|
||||
{381, new[] {685}}, // Latios @ Latiosite
|
||||
{445, new[] {683}}, // Garchomp @ Garchompite
|
||||
{448, new[] {673}}, // Lucario @ Lucarionite
|
||||
{460, new[] {674}}, // Abomasnow @ Abomasite
|
||||
|
||||
{015, new[] {770}}, // Beedrill @ Beedrillite
|
||||
{018, new[] {762}}, // Pidgeot @ Pidgeotite
|
||||
{080, new[] {760}}, // Slowbro @ Slowbronite
|
||||
{208, new[] {761}}, // Steelix @ Steelixite
|
||||
{254, new[] {753}}, // Sceptile @ Sceptilite
|
||||
{260, new[] {752}}, // Swampert @ Swampertite
|
||||
{302, new[] {754}}, // Sableye @ Sablenite
|
||||
{319, new[] {759}}, // Sharpedo @ Sharpedonite
|
||||
{323, new[] {767}}, // Camerupt @ Cameruptite
|
||||
{334, new[] {755}}, // Altaria @ Altarianite
|
||||
{362, new[] {763}}, // Glalie @ Glalitite
|
||||
{373, new[] {769}}, // Salamence @ Salamencite
|
||||
{376, new[] {758}}, // Metagross @ Metagrossite
|
||||
{428, new[] {768}}, // Lopunny @ Lopunnite
|
||||
{475, new[] {756}}, // Gallade @ Galladite
|
||||
{531, new[] {757}}, // Audino @ Audinite
|
||||
{719, new[] {764}}, // Diancie @ Diancite
|
||||
};
|
||||
|
||||
private static readonly Dictionary<int, int[]> MegaDictionaryGG = new Dictionary<int, int[]>
|
||||
{
|
||||
{003, new[] {659}}, // Venusaur @ Venusaurite
|
||||
{006, new[] {660, 678}}, // Charizard @ Charizardite X/Y
|
||||
{009, new[] {661}}, // Blastoise @ Blastoisinite
|
||||
{065, new[] {679}}, // Alakazam @ Alakazite
|
||||
{094, new[] {656}}, // Gengar @ Gengarite
|
||||
{115, new[] {675}}, // Kangaskhan @ Kangaskhanite
|
||||
{127, new[] {671}}, // Pinsir @ Pinsirite
|
||||
{130, new[] {676}}, // Gyarados @ Gyaradosite
|
||||
{142, new[] {672}}, // Aerodactyl @ Aerodactylite
|
||||
{150, new[] {662, 663}}, // Mewtwo @ Mewtwonite X/Y
|
||||
|
||||
{015, new[] {770}}, // Beedrill @ Beedrillite
|
||||
{018, new[] {762}}, // Pidgeot @ Pidgeotite
|
||||
{080, new[] {760}}, // Slowbro @ Slowbronite
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user