mirror of
https://github.com/kwsch/pkNX.git
synced 2026-04-04 00:15:06 -05:00
428 lines
14 KiB
C#
428 lines
14 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
|
|
using pkNX.Structures;
|
|
|
|
namespace pkNX.Randomization
|
|
{
|
|
public class PersonalRandomizer : Randomizer
|
|
{
|
|
private const int tmcount = 100;
|
|
private const int eggGroupCount = 16;
|
|
private const int TypeCount = 18;
|
|
|
|
private readonly GameInfo Game;
|
|
private readonly PersonalTable Table;
|
|
private readonly EvolutionSet[] Evolutions;
|
|
|
|
public PersonalRandSettings Settings { get; set; }
|
|
|
|
public PersonalRandomizer(PersonalTable table, GameInfo game, EvolutionSet[] evolutions)
|
|
{
|
|
Game = game;
|
|
Table = table;
|
|
Evolutions = evolutions;
|
|
if (File.Exists("bannedabilites.txt"))
|
|
{
|
|
var data = File.ReadAllLines("bannedabilities.txt");
|
|
var list = new List<int>(BannedAbilities);
|
|
list.AddRange(data.Select(z => Convert.ToInt32(z)));
|
|
BannedAbilities = list;
|
|
}
|
|
}
|
|
|
|
public override void Execute()
|
|
{
|
|
if (Settings.ModifyByEvolutions)
|
|
RandomizeChains();
|
|
else
|
|
RandomizeAllSpecies();
|
|
}
|
|
|
|
private void RandomizeAllSpecies()
|
|
{
|
|
for (var species = 0; species <= Game.MaxSpeciesID; species++)
|
|
RandomizeSpecies(species);
|
|
}
|
|
|
|
private bool[] processed;
|
|
|
|
private void RandomizeChains()
|
|
{
|
|
processed = new bool[Table.TableLength];
|
|
for (var species = 0; species <= Game.MaxSpeciesID; species++)
|
|
{
|
|
for (int f = 0; f <= Table[species].FormeCount; f++)
|
|
RandomizeChain(species, f);
|
|
}
|
|
}
|
|
|
|
private bool AlreadyProcessed(int index)
|
|
{
|
|
if (processed[index])
|
|
return true;
|
|
processed[index] = true;
|
|
return false;
|
|
}
|
|
|
|
private void RandomizeChain(int species, int forme)
|
|
{
|
|
var index = Table.GetFormeIndex(species, forme);
|
|
if (AlreadyProcessed(index))
|
|
return;
|
|
processed[index] = true;
|
|
|
|
var entry = Table[index];
|
|
Randomize(entry, species);
|
|
ProcessEvolutions(species, forme, index);
|
|
}
|
|
|
|
private void ProcessEvolutions(int species, int forme, int devolvedIndex)
|
|
{
|
|
var evoindex = GetEvolutionEntry(species, forme);
|
|
var evos = Evolutions[evoindex];
|
|
|
|
if (evos.PossibleEvolutions.Length == 1)
|
|
{
|
|
var evo = evos.PossibleEvolutions[0];
|
|
var ei = Table.GetFormeIndex(evo.Species, evo.Form);
|
|
|
|
if (AlreadyProcessed(evoindex))
|
|
return;
|
|
RandomizeSingleChain(evo, devolvedIndex);
|
|
ProcessEvolutions(evo.Species, evo.Form, ei);
|
|
}
|
|
else
|
|
{
|
|
foreach (var evo in evos.PossibleEvolutions)
|
|
{
|
|
var ei = Table.GetFormeIndex(evo.Species, evo.Form);
|
|
if (AlreadyProcessed(evoindex))
|
|
return;
|
|
RandomizeSplitChain(evo, devolvedIndex);
|
|
ProcessEvolutions(evo.Species, evo.Form, ei);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void RandomizeSingleChain(EvolutionMethod evo, int devolvedIndex)
|
|
{
|
|
var child = Table[devolvedIndex];
|
|
var z = Table.GetFormeEntry(evo.Species, evo.Form);
|
|
RandomizeFrom(z, child, evo.Species);
|
|
}
|
|
|
|
private void RandomizeSplitChain(EvolutionMethod evo, int devolvedIndex)
|
|
{
|
|
var child = Table[devolvedIndex];
|
|
var z = Table.GetFormeEntry(evo.Species, evo.Form);
|
|
RandomizeFrom(z, child, evo.Species);
|
|
}
|
|
|
|
private int GetEvolutionEntry(int species, int form)
|
|
{
|
|
if (Game.Generation < 7)
|
|
return species;
|
|
return Table.GetFormeIndex(species, form);
|
|
}
|
|
|
|
private void RandomizeSpecies(int species)
|
|
{
|
|
var entry = Table[species];
|
|
Randomize(entry, species);
|
|
var formeCount = entry.FormeCount;
|
|
for (int forme = 1; forme <= formeCount; forme++)
|
|
{
|
|
entry = Table.GetFormeEntry(species, forme);
|
|
Randomize(entry, species);
|
|
}
|
|
}
|
|
|
|
public void RandomizeFrom(PersonalInfo z, PersonalInfo child, int species)
|
|
{
|
|
if (Settings.ModifyStats)
|
|
RandomizeStats(z);
|
|
if (Settings.ShuffleStats)
|
|
RandomShuffledStats(z);
|
|
|
|
if (Settings.ModifyTypes)
|
|
{
|
|
if (Settings.InheritType && Settings.InheritTypeSetting != ModifyState.All)
|
|
{
|
|
var types = child.Types;
|
|
switch (Settings.InheritTypeSetting)
|
|
{
|
|
case ModifyState.Two when Rand.Next(100) < Settings.InheritTypeNeitherChance:
|
|
types = new[] { GetRandomType(), GetRandomType() };
|
|
break;
|
|
case ModifyState.Two when Rand.Next(100) < Settings.InheritTypeOnlyOneChance:
|
|
case ModifyState.One when Rand.Next(100) < Settings.InheritTypeOnlyOneChance:
|
|
types[Rand.Next(2)] = GetRandomType();
|
|
break;
|
|
}
|
|
if (Rand.Next(0, 100) < Settings.SameTypeChance)
|
|
{
|
|
int index = Rand.Next(2);
|
|
types[index ^ 1] = types[index];
|
|
}
|
|
z.Types = types;
|
|
}
|
|
else
|
|
{
|
|
RandomizeTypes(z);
|
|
}
|
|
}
|
|
|
|
if (Settings.ModifyAbility)
|
|
{
|
|
if (Settings.InheritAbility)
|
|
{
|
|
var abils = child.Abilities;
|
|
GetRandomAbilities(abils, Settings.InheritAbilitySetting);
|
|
z.Abilities = abils;
|
|
}
|
|
else
|
|
{
|
|
RandomizeAbilities(z);
|
|
}
|
|
}
|
|
|
|
if (Settings.ModifyLearnsetTM || Settings.ModifyLearnsetHM)
|
|
{
|
|
if (Settings.InheritChildTM)
|
|
z.TMHM = child.TMHM;
|
|
else
|
|
RandomizeTMHM(z);
|
|
}
|
|
|
|
if (Settings.ModifyLearnsetTypeTutors)
|
|
{
|
|
if (Settings.InheritChildSpecial)
|
|
z.TypeTutors = child.TypeTutors;
|
|
else
|
|
RandomizeTypeTutors(z, species);
|
|
}
|
|
|
|
if (Settings.ModifyLearnsetMoveTutors)
|
|
{
|
|
if (Settings.InheritChildTutor)
|
|
z.SpecialTutors = child.SpecialTutors;
|
|
else
|
|
RandomizeSpecialTutors(z);
|
|
}
|
|
|
|
if (Settings.ModifyEgg)
|
|
z.EggGroups = child.EggGroups;
|
|
|
|
if (Settings.ModifyHeldItems)
|
|
{
|
|
if (Settings.InheritHeldItem)
|
|
z.Items = child.Items;
|
|
else
|
|
RandomizeHeldItems(z);
|
|
}
|
|
|
|
ExecuteCatchRate(z);
|
|
}
|
|
|
|
private void GetRandomAbilities(int[] abils, ModifyState setting)
|
|
{
|
|
switch (setting)
|
|
{
|
|
case ModifyState.All:
|
|
GetRandomAbilities(abils);
|
|
break;
|
|
case ModifyState.Two when Rand.Next(100) < Settings.InheritAbilityNeitherChance:
|
|
GetRandomAbilities(abils, 1);
|
|
break;
|
|
case ModifyState.Two when Rand.Next(100) < Settings.InheritAbilityOnlyOneChance:
|
|
case ModifyState.One when Rand.Next(100) < Settings.InheritAbilityOnlyOneChance:
|
|
GetRandomAbilities(abils, 2);
|
|
break;
|
|
}
|
|
if (Rand.Next(100) < Settings.SameAbilityChance)
|
|
{
|
|
int index = Rand.Next(2);
|
|
abils[index^1] = abils[index];
|
|
}
|
|
}
|
|
|
|
public void Randomize(PersonalInfo z, int species)
|
|
{
|
|
if (Settings.ModifyStats)
|
|
RandomizeStats(z);
|
|
if (Settings.ShuffleStats)
|
|
RandomShuffledStats(z);
|
|
|
|
if (Settings.ModifyTypes)
|
|
RandomizeTypes(z);
|
|
|
|
if (Settings.ModifyAbility)
|
|
RandomizeAbilities(z);
|
|
|
|
if (Settings.ModifyLearnsetTM || Settings.ModifyLearnsetHM)
|
|
RandomizeTMHM(z);
|
|
|
|
if (Settings.ModifyLearnsetTypeTutors)
|
|
RandomizeTypeTutors(z, species);
|
|
|
|
if (Settings.ModifyLearnsetMoveTutors)
|
|
RandomizeSpecialTutors(z);
|
|
|
|
if (Settings.ModifyEgg)
|
|
RandomizeEggGroups(z);
|
|
|
|
if (Settings.ModifyHeldItems)
|
|
RandomizeHeldItems(z);
|
|
|
|
ExecuteCatchRate(z);
|
|
}
|
|
|
|
private void ExecuteCatchRate(PersonalInfo z)
|
|
{
|
|
if (Settings.CatchRate == CatchRate.Random)
|
|
z.CatchRate = Rand.Next(3, 251); // Random Catch Rate between 3 and 250.
|
|
else if (Settings.CatchRate == CatchRate.BSTScaled)
|
|
z.CatchRate = GetBSTCatchRate(z.BST);
|
|
}
|
|
|
|
private static int GetBSTCatchRate(int BST)
|
|
{
|
|
var c = 11 * (Math.Sqrt(Math.Max(0, 600 - BST)));
|
|
|
|
const int min = 3;
|
|
return (int)Math.Min(255, min + c);
|
|
}
|
|
|
|
private void RandomizeTMHM(PersonalInfo z)
|
|
{
|
|
var tms = z.TMHM;
|
|
|
|
if (Settings.ModifyLearnsetTM)
|
|
{
|
|
for (int j = 0; j < tmcount; j++)
|
|
tms[j] = Rand.Next(100) < Settings.LearnTMPercent;
|
|
}
|
|
|
|
if (Settings.ModifyLearnsetHM)
|
|
{
|
|
for (int j = tmcount; j < tms.Length; j++)
|
|
tms[j] = Rand.Next(100) < Settings.LearnTMPercent;
|
|
}
|
|
|
|
z.TMHM = tms;
|
|
}
|
|
|
|
private void RandomizeTypeTutors(PersonalInfo z, int species)
|
|
{
|
|
var t = z.TypeTutors;
|
|
for (int i = 0; i < t.Length; i++)
|
|
t[i] = Rand.Next(100) < Settings.LearnTypeTutorPercent;
|
|
|
|
// Make sure Rayquaza can learn Dragon Ascent.
|
|
if (!Game.XY && species == 384)
|
|
t[7] = true;
|
|
|
|
z.TypeTutors = t;
|
|
}
|
|
|
|
private void RandomizeSpecialTutors(PersonalInfo z)
|
|
{
|
|
var tutors = z.SpecialTutors;
|
|
foreach (bool[] tutor in tutors)
|
|
{
|
|
for (int i = 0; i < tutor.Length; i++)
|
|
tutor[i] = Rand.Next(100) < Settings.LearnMoveTutorPercent;
|
|
}
|
|
|
|
z.SpecialTutors = tutors;
|
|
}
|
|
|
|
private void RandomizeAbilities(PersonalInfo z)
|
|
{
|
|
var abils = z.Abilities;
|
|
GetRandomAbilities(abils, Settings.Ability);
|
|
z.Abilities = abils;
|
|
}
|
|
|
|
private void GetRandomAbilities(int[] abils, int skip = 0)
|
|
{
|
|
for (int i = 0; i < abils.Length - skip; i++)
|
|
abils[i] = GetRandomAbility();
|
|
}
|
|
|
|
private void RandomizeEggGroups(PersonalInfo z)
|
|
{
|
|
var egg = z.EggGroups;
|
|
egg[0] = GetRandomEggGroup();
|
|
egg[1] = Rand.Next(100) < Settings.SameEggGroupChance ? egg[0] : GetRandomEggGroup();
|
|
z.EggGroups = egg;
|
|
}
|
|
|
|
private void RandomizeHeldItems(PersonalInfo z)
|
|
{
|
|
var item = z.Items;
|
|
for (int j = 0; j < item.Length; j++)
|
|
item[j] = GetRandomHeldItem();
|
|
z.Items = item;
|
|
}
|
|
|
|
private void RandomizeTypes(PersonalInfo z)
|
|
{
|
|
var t = z.Types;
|
|
t[0] = GetRandomType();
|
|
t[1] = Rand.Next(0, 100) < Settings.SameTypeChance ? t[0] : GetRandomType();
|
|
z.Types = t;
|
|
}
|
|
|
|
private void RandomizeStats(PersonalInfo z)
|
|
{
|
|
// Fiddle with Base Stats, don't muck with Shedinja.
|
|
var stats = z.Stats;
|
|
if (stats[0] == 1)
|
|
return;
|
|
int RandDeviation() => Rand.Next(Settings.StatDeviationMin, Settings.StatDeviationMax);
|
|
for (int i = 0; i < stats.Length; i++)
|
|
{
|
|
if (!Settings.StatsToRandomize[i])
|
|
continue;
|
|
|
|
var val = stats[i] * RandDeviation() / 100;
|
|
stats[i] = Math.Max(1, Math.Min(255, val));
|
|
}
|
|
z.Stats = stats;
|
|
}
|
|
|
|
private void RandomShuffledStats(PersonalInfo z)
|
|
{
|
|
// Fiddle with Base Stats, don't muck with Shedinja.
|
|
var stats = z.Stats;
|
|
if (stats[0] == 1)
|
|
return;
|
|
Util.Shuffle(stats);
|
|
z.Stats = stats;
|
|
}
|
|
|
|
private int GetRandomType() => Rand.Next(0, TypeCount);
|
|
private int GetRandomEggGroup() => Rand.Next(1, eggGroupCount);
|
|
private int GetRandomHeldItem() => Game.HeldItems.Length > 1 ? Game.HeldItems[Rand.Next(1, Game.HeldItems.Length)] : 0;
|
|
private readonly IList<int> BannedAbilities = Array.Empty<int>();
|
|
|
|
private int GetRandomAbility()
|
|
{
|
|
const int WonderGuard = 25;
|
|
while (true)
|
|
{
|
|
int newabil = Rand.Next(1, Game.MaxAbilityID + 1);
|
|
if (newabil == WonderGuard && Settings.WonderGuard == Permissive.No)
|
|
continue;
|
|
if (BannedAbilities.Contains(newabil))
|
|
continue;
|
|
return newabil;
|
|
}
|
|
}
|
|
}
|
|
}
|