public static void ShuffleTMs(Random random, ItemShufflerSettings settings, ExtractedGame extractedGame) { if (settings.RandomizeTMs) { Logger.Log("=============================== TMs ===============================\n\n"); var tms = extractedGame.TMs; // use set to avoid dupes var newTMSet = new HashSet <ushort>(); var validMoves = extractedGame.ValidMoves; if (settings.TMForceGoodDamagingMove) { // determine what percent of TMs should be good var count = (int)Math.Round(settings.TMGoodDamagingMovePercent * tms.Length); // keep picking until it's not a dupe // this could probably be done smarterly var goodDamagingMoves = extractedGame.GoodDamagingMoves; while (newTMSet.Count < count) { var newMove = goodDamagingMoves[random.Next(0, goodDamagingMoves.Length)]; newTMSet.Add((ushort)newMove.MoveIndex); } } // keep picking while we haven't picked enough TMs while (newTMSet.Count < tms.Length) { newTMSet.Add((ushort)validMoves[random.Next(0, validMoves.Length)].MoveIndex); } // set them to the actual TM item for (int i = 0; i < tms.Length; i++) { var tm = tms[i]; tm.Move = newTMSet.ElementAt(i); Logger.Log($"TM{tm.TMIndex}: {extractedGame.MoveList[tm.Move].Name}\n"); } Logger.Log($"\n\n"); } }
public static void ShufflePokeSpots(Random random, PokeSpotShufflerSettings settings, PokeSpotPokemon[] pokeSpotPokemon, ExtractedGame extractedGame) { var validPokemon = extractedGame.ValidPokemon; var validItems = settings.BanBadHeldItems ? extractedGame.GoodItems : extractedGame.NonKeyItems; Logger.Log("=============================== Poke Spots ===============================\n\n"); foreach (var pokeSpotPoke in pokeSpotPokemon) { Logger.Log($"PokeSpot Type: {pokeSpotPoke.PokeSpot.PokeSpotType}\n\n"); var pokemon = extractedGame.PokemonList[pokeSpotPoke.Pokemon]; if (pokeSpotPoke.Pokemon == RandomizerConstants.BonslyIndex) { // I don't know if this'll work or not... pokeSpotPoke.EncounterPercentage = settings.EasyBonsly ? 100 : pokeSpotPoke.EncounterPercentage; Logger.Log("Bonsly damnit stop running away!\n"); continue; } if (settings.RandomizePokeSpotPokemon) { var newPokemon = validPokemon[random.Next(0, validPokemon.Length)]; Logger.Log($"Pokemon {pokemon.Name} -> {newPokemon.Name}\n"); pokeSpotPoke.Pokemon = (ushort)newPokemon.Index; pokemon = newPokemon; } if (settings.RandomizeHeldItems) { var newItem = validItems[random.Next(0, validItems.Length)]; Logger.Log($"Pokemon {pokemon.HeldItem} -> {newItem.Name}\n"); pokemon.HeldItem = (ushort)newItem.Index; } if (settings.BoostPokeSpotLevel) { var maxLevel = pokeSpotPoke.MaxLevel; var minLevel = pokeSpotPoke.MinLevel; var maxLevelIncrease = (byte)Math.Clamp(maxLevel + maxLevel * settings.BoostPokeSpotLevelPercent, 1, 100); var minLevelIncrease = (byte)Math.Clamp(minLevel + minLevel * settings.BoostPokeSpotLevelPercent, 1, 100); Logger.Log($"Max Level {maxLevel} -> {maxLevelIncrease}\n"); Logger.Log($"Min Level {minLevel} -> {minLevelIncrease}\n"); pokeSpotPoke.MaxLevel = maxLevelIncrease; pokeSpotPoke.MinLevel = minLevelIncrease; } if (settings.SetMinimumCatchRate) { var catchRate = Math.Max(pokemon.CatchRate, settings.MinimumCatchRate); var catchRateIncrease = (byte)Math.Clamp(catchRate, 0, byte.MaxValue); Logger.Log($"Catch Rate {pokemon.CatchRate} -> {catchRateIncrease}\n"); pokemon.CatchRate = catchRateIncrease; } } }
public static ushort[] GetNewMoveset(Random random, RandomMoveSetOptions options, ushort pokemon, ushort level, ExtractedGame extractedGame) { var poke = extractedGame.PokemonList[pokemon]; var moveSet = new HashSet <ushort>(); var moveFilter = options.BanShadowMoves ? extractedGame.ValidMoves.Where(m => !m.IsShadowMove) : extractedGame.ValidMoves; if (options.BanEarlyDragonRage) { moveFilter = moveFilter.Where(m => !(m.MoveIndex == RandomizerConstants.DragonRageIndex && level < RandomizerConstants.BanDragonRageUnderLevel)); } var typeFilter = moveFilter; if (options.PreferType) { // allow 20% chance for move to not be same type typeFilter = typeFilter.Where(m => m.Type == poke.Type1 || m.Type == poke.Type2 || random.Next(0, 10) >= 8).ToArray(); if (!moveFilter.Any()) { typeFilter = moveFilter; } } var potentialMoves = typeFilter.ToArray(); if (options.UseLevelUpMoves || !options.RandomizeMovesets) { // not randomizing moves? pick level up moves then var levelUpMoves = extractedGame.PokemonList[pokemon].CurrentLevelMoves(level++); // this *could* happen so increase the level until there's at least one move for them while (!levelUpMoves.Any() && level <= 100) { levelUpMoves = extractedGame.PokemonList[pokemon].CurrentLevelMoves(level++); } // still nothing, add a random move if (!levelUpMoves.Any()) { var newMove = potentialMoves[random.Next(0, potentialMoves.Length)]; moveSet.Add((ushort)newMove.MoveIndex); } else { foreach (var levelUpMove in levelUpMoves) { moveSet.Add(levelUpMove.Move); } } } else if (options.MinimumGoodMoves > 0) { var goodMoves = potentialMoves.Where(m => m.BasePower >= Configuration.GoodDamagingMovePower).ToArray(); while (moveSet.Count < options.MinimumGoodMoves) { var newMove = goodMoves[random.Next(0, goodMoves.Length)]; moveSet.Add((ushort)newMove.MoveIndex); } } if (options.RandomizeMovesets || options.ForceFourMoves) { while (moveSet.Count < Constants.NumberOfPokemonMoves) { var newMove = potentialMoves[random.Next(0, potentialMoves.Length)]; moveSet.Add((ushort)newMove.MoveIndex); } } return(moveSet.ToArray()); }
public static void RandomizeMoves(Random random, MoveShufflerSettings settings, ExtractedGame extractedGame) { Logger.Log("=============================== Moves ===============================\n\n"); foreach (var move in extractedGame.ValidMoves) { Logger.Log($"{move.Name}: \n"); if (settings.RandomMovePower && move.BasePower > 0) { // sample move power with the power of math!! // basically moves will average at 80 power but can be from 10 to 150 move.BasePower = (byte)random.Sample(80, 70); } Logger.Log($"Power: {move.BasePower}\n"); if (settings.RandomMoveAcc && move.Accuracy > 0) { // randomize accuracy, repick if the moves is OHKO and 100% accurate cause that's a yikes byte acc; do { acc = (byte)Math.Min(100, random.Sample(80, 30)); } while (acc == 100 && move.EffectType == MoveEffectTypes.OHKO); move.Accuracy = acc; } Logger.Log($"Accuracy: {move.Accuracy}\n"); if (settings.RandomMovePP) { // pick from 1, 8, multiply by 5 to get the 5 - 40 range for PP move.PP = (byte)Math.Max(5, Math.Round(random.Sample(4, 4)) * 5); } Logger.Log($"PP: {move.PP}\n"); if (settings.RandomMoveTypes && move.Type != PokemonTypes.None) { var typesCount = Enum.GetValues <PokemonTypes>(); PokemonTypes newType; // pick new move type but not the none type do { newType = typesCount[random.Next(0, typesCount.Length)]; }while (newType == PokemonTypes.None); move.Type = newType; } Logger.Log($"Type: {move.Type}\n"); // I don't know if this will work for colo, probably not if (settings.RandomMoveCategory && move.Category != MoveCategories.None) { var newCategory = (MoveCategories)random.Next(1, 3); move.Category = newCategory; } Logger.Log($"Category: {move.Category}\n\n"); } }
public static void RandomizeColoStatics(Random random, StaticPokemonShufflerSettings settings, IGiftPokemon[] starters, ExtractedGame extractedGame) { }
public static void RandomizeXDStatics(Random random, StaticPokemonShufflerSettings settings, XDStarterPokemon starter, ISO iso, ExtractedGame extractedGame) { int index = 0; Evolution secondStage; bool condition = false; Logger.Log("=============================== Statics ===============================\n\n"); // pick starters // basically set a condition based on the setting, keep looping till you meet it switch (settings.Starter) { case StarterRandomSetting.Custom: { index = extractedGame.PokemonList.FirstOrDefault(p => p.Name.ToLower() == settings.Starter1.ToLower())?.Index ?? starter.Pokemon; } break; case StarterRandomSetting.Random: { while (index == 0 || RandomizerConstants.SpecialPokemon.Contains(index)) { index = random.Next(1, extractedGame.PokemonList.Length); } } break; case StarterRandomSetting.RandomThreeStage: while (!condition) { var newStarter = extractedGame.PokemonList[random.Next(0, extractedGame.ValidPokemon.Length)]; index = newStarter.Index; secondStage = extractedGame.PokemonList[index].Evolutions[0]; condition = !PokemonTraitShuffler.CheckForSplitOrEndEvolution(newStarter, out int _) && !PokemonTraitShuffler.CheckForSplitOrEndEvolution(extractedGame.PokemonList[secondStage.EvolvesInto], out int _) // check if any pokemon evolve into this one, less likely for three stages but probably good to check anyway && !extractedGame.ValidPokemon.Any(p => { for (int i = 0; i < p.Evolutions.Length; i++) { if (p.Evolutions[i].EvolvesInto == index) { return(true); } } return(false); }); } break; case StarterRandomSetting.RandomTwoStage: while (!condition) { var newStarter = extractedGame.PokemonList[random.Next(0, extractedGame.ValidPokemon.Length)]; index = newStarter.Index; secondStage = extractedGame.PokemonList[index].Evolutions[0]; condition = !PokemonTraitShuffler.CheckForSplitOrEndEvolution(newStarter, out int _) && PokemonTraitShuffler.CheckForSplitOrEndEvolution(extractedGame.PokemonList[secondStage.EvolvesInto], out int count) && count == 0 // check if any pokemon evolve into this one && !extractedGame.ValidPokemon.Any(p => { for (int i = 0; i < p.Evolutions.Length; i++) { if (p.Evolutions[i].EvolvesInto == index) { return(true); } } return(false); }); } break; case StarterRandomSetting.RandomSingleStage: while (!condition) { var newStarter = extractedGame.PokemonList[random.Next(0, extractedGame.ValidPokemon.Length)]; index = newStarter.Index; condition = PokemonTraitShuffler.CheckForSplitOrEndEvolution(newStarter, out int count) && count == 0 // check if any pokemon evolve into this one && !extractedGame.ValidPokemon.Any(p => { for (int i = 0; i < p.Evolutions.Length; i++) { if (p.Evolutions[i].EvolvesInto == index) { return(true); } } return(false); }); } break; default: case StarterRandomSetting.Unchanged: index = starter.Pokemon; break; } starter.Pokemon = (ushort)index; Logger.Log($"Your new starter is {extractedGame.PokemonList[index].Name}\n"); // instance pokemon have separate movesets than the pool // i.e. if you don't update the moveset than your starter will have Eevee's move set ushort[] moves; if (settings.MoveSetOptions.RandomizeMovesets || settings.Starter != StarterRandomSetting.Unchanged) { Logger.Log($"It knows:\n"); moves = MoveShuffler.GetNewMoveset(random, settings.MoveSetOptions, starter.Pokemon, starter.Level, extractedGame); for (int i = 0; i < moves.Length; i++) { var move = moves[i]; Logger.Log($"{extractedGame.MoveList[move].Name}\n"); starter.SetMove(i, move); } } List <Pokemon> newRequestedPokemon = new List <Pokemon>(); List <Pokemon> newGivenPokemon = new List <Pokemon>(); var pokemon = extractedGame.ValidPokemon; // set given switch (settings.Trade) { default: case TradeRandomSetting.Unchanged: Logger.Log("Unchanged\n\n"); return; case TradeRandomSetting.Given: case TradeRandomSetting.Both: for (int i = 0; i < extractedGame.GiftPokemonList.Length; i++) { var giftPoke = extractedGame.GiftPokemonList[i]; var newPoke = pokemon[random.Next(0, pokemon.Length)]; giftPoke.Pokemon = (ushort)newPoke.Index; if (giftPoke.GiftType.Contains("Duking")) { newGivenPokemon.Add(newPoke); } ushort[] newMoveSet = MoveShuffler.GetNewMoveset(random, settings.MoveSetOptions, giftPoke.Pokemon, extractedGame.GiftPokemonList[i].Level, extractedGame); for (int j = 0; j < newMoveSet.Length; j++) { extractedGame.GiftPokemonList[i].SetMove(j, newMoveSet[j]); } } break; case TradeRandomSetting.Requested: for (int i = 0; i < 3; i++) { newGivenPokemon.Add(extractedGame.PokemonList[new XDTradePokemon((byte)(i + 2), iso).Pokemon]); } break; } // set requested for (int i = 0; i < 3; i++) { var pokeSpot = new PokeSpotPokemon(2, (PokeSpotType)i, iso); var newRequestedPoke = settings.UsePokeSpotPokemonInTrade || settings.Trade == TradeRandomSetting.Requested || settings.Trade == TradeRandomSetting.Both ? extractedGame.PokemonList[pokeSpot.Pokemon] : pokemon[random.Next(0, pokemon.Length)]; newRequestedPokemon.Add(newRequestedPoke); } Logger.Log($"Requested Pokemon: {string.Join(", ", newRequestedPokemon.Select(p => p.Name))}\n"); Logger.Log($"Given Pokemon: {string.Join(", ", newGivenPokemon.Select(p => p.Name))}\n"); XDTradePokemon.UpdateTrades(iso, newRequestedPokemon.ToArray(), newGivenPokemon.ToArray()); }
public static void ShuffleOverworldItems(Random random, ItemShufflerSettings settings, ExtractedGame extractedGame) { // there are a lot of battle cds, so only add them to one location and then // block that same cd from being put in another location (only if they haven't banned cds entirely) var battleCDsUsed = new List <int>(); var potentialItems = settings.BanBadItems ? extractedGame.GoodItems : extractedGame.NonKeyItems; if (settings.BanBattleCDs) { potentialItems = potentialItems.Where(i => !RandomizerConstants.BattleCDList.Contains(i.Index)).ToArray(); } Logger.Log("=============================== Overworld Items ===============================\n\n"); foreach (var item in extractedGame.OverworldItemList) { // i'm *assuming* the devs didn't place any invalid items on the overworld if (item.Item > extractedGame.ItemList.Length || extractedGame.ItemList[item.Item].BagSlot == BagSlots.KeyItems) { continue; } if (settings.RandomizeItems) { ushort newItem = 0; while (newItem == 0 || battleCDsUsed.Contains(newItem)) { newItem = (ushort)potentialItems[random.Next(0, potentialItems.Length)].Index; } if (RandomizerConstants.BattleCDList.Contains(newItem)) { battleCDsUsed.Add(newItem); } Logger.Log($"{extractedGame.ItemList[item.Item].Name} -> "); item.Item = newItem; Logger.Log($"{extractedGame.ItemList[newItem].Name}\n\n"); } if (settings.RandomizeItemQuantity) { Logger.Log($"Quantity: {item.Quantity} -> "); item.Quantity = (byte)random.Next(1, 6); Logger.Log($"{item.Quantity}\n\n"); } } }
public static void ShuffleTutorMoves(Random random, ItemShufflerSettings settings, TutorMove[] tutorMoves, ExtractedGame extractedGame) { if (settings.RandomizeTutorMoves) { Logger.Log("=============================== Tutor Moves ===============================\n\n"); var newTutorMoveSet = new HashSet <ushort>(); var validMoves = extractedGame.ValidMoves; if (settings.TutorForceGoodDamagingMove) { // determine what percent of TMs should be good var count = (int)Math.Round(settings.TutorGoodDamagingMovePercent * tutorMoves.Length); // filter the move list by moves that are deemed good var goodDamagingMoves = extractedGame.GoodDamagingMoves; while (newTutorMoveSet.Count < count) { var newMove = goodDamagingMoves[random.Next(0, goodDamagingMoves.Length)]; newTutorMoveSet.Add((ushort)newMove.MoveIndex); } } // keep picking while we haven't picked enough TMs or we picked a dupe while (newTutorMoveSet.Count < tutorMoves.Length) { newTutorMoveSet.Add((ushort)validMoves[random.Next(0, validMoves.Length)].MoveIndex); } // set them to the actual TM item for (int i = 0; i < tutorMoves.Length; i++) { tutorMoves[i].Move = newTutorMoveSet.ElementAt(i); Logger.Log($"Tutor Move {i + 1}: {extractedGame.MoveList[tutorMoves[i].Move].Name}\n"); } Logger.Log($"\n\n"); } }
public static void UpdatePokemarts(Random random, ItemShufflerSettings settings, ExtractedGame extractedGame) { if (settings.RandomizeMarts) { Logger.Log("=============================== Mart Items ===============================\n\n"); var potentialItems = settings.BanBadItems ? extractedGame.NonKeyItems : extractedGame.GoodItems; potentialItems = potentialItems.Where(i => !RandomizerConstants.BattleCDList.Contains(i.Index)).ToArray(); foreach (var mart in extractedGame.Pokemarts) { Logger.Log($"Mart {mart.Index}:\n"); for (int i = 0; i < mart.Items.Count; i++) { var item = mart.Items[i]; if (item < extractedGame.ItemList.Length) { Logger.Log($"{extractedGame.ItemList[item].Name} -> "); } else { Logger.Log($"{item} -> "); } mart.Items[i] = (ushort)potentialItems[random.Next(0, potentialItems.Length)].Index; Logger.Log($"{extractedGame.ItemList[mart.Items[i]].Name}\n"); } mart.SaveItems(); Logger.Log($"\n"); } Logger.Log($"\n"); } if (settings.MartsSellEvoStones) { Logger.Log($"Adding Evolution Stones to Agate Village Mart.\n\n"); foreach (var agateMartIndex in RandomizerConstants.AgateVillageMartIndices) { var agateMart = extractedGame.Pokemarts[agateMartIndex]; agateMart.Items.AddRange(RandomizerConstants.EvoStoneItemList); for (int i = agateMartIndex + 1; i < extractedGame.Pokemarts.Length; i++) { extractedGame.Pokemarts[i].FirstItemIndex += (ushort)(RandomizerConstants.EvoStoneItemList.Length); } agateMart.SaveItems(); } } }
private static void ChangeCompatibility(Random random, MoveCompatibility moveCompatibility, Pokemon pokemon, ExtractedGame extractedGame, bool tms) { switch (moveCompatibility) { case MoveCompatibility.Full: { if (tms) { Logger.Log($"TM Compatibility: Full\n"); for (int i = 0; i < pokemon.LearnableTMs.Length; i++) { pokemon.SetLearnableTMS(i, true); } } else { Logger.Log($"Tutor Move Compatibility: Full\n"); for (int i = 0; i < pokemon.TutorMoves.Length; i++) { pokemon.SetTutorMoves(i, true); } } } break; case MoveCompatibility.Random: { if (tms) { Logger.Log($"TM Compatibility:\n"); for (int i = 0; i < pokemon.LearnableTMs.Length; i++) { var compatible = random.Next(0, 2) == 0; pokemon.SetLearnableTMS(i, compatible); Logger.Log($"TM{extractedGame.TMs[i].TMIndex} - {compatible}\n"); } } else { Logger.Log($"Tutor Move Compatibility:\n"); for (int i = 0; i < pokemon.TutorMoves.Length; i++) { var compatible = random.Next(0, 2) == 0; pokemon.SetTutorMoves(i, compatible); Logger.Log($"{i + 1} - {compatible}\n"); } } Logger.Log($"\n"); } break; case MoveCompatibility.RandomPreferType: { if (tms) { Logger.Log($"TM Compatibility:\n"); var tmMoves = extractedGame.TMs.Select(t => extractedGame.MoveList[t.Move]).ToArray(); for (int i = 0; i < pokemon.LearnableTMs.Length; i++) { var isCompatible = tmMoves[i].Type == pokemon.Type1 || tmMoves[i].Type == pokemon.Type2 || random.Next(0, 10) >= 8; pokemon.SetLearnableTMS(i, isCompatible); Logger.Log($"TM{extractedGame.TMs[i].TMIndex} - {isCompatible}\n"); } } else { Logger.Log($"Tutor Move Compatibility:\n"); var tutorMoves = extractedGame.TutorMoves.Select(t => extractedGame.MoveList[t.Move]).ToArray(); for (int i = 0; i < pokemon.TutorMoves.Length; i++) { var isCompatible = tutorMoves[i].Type == pokemon.Type1 || tutorMoves[i].Type == pokemon.Type2 || random.Next(0, 10) >= 8; pokemon.SetTutorMoves(i, isCompatible); Logger.Log($"{i + 1} - {isCompatible}\n"); } } Logger.Log($"\n"); } break; default: case MoveCompatibility.Unchanged: break; } }
public static void RandomizePokemonTraits(Random random, PokemonTraitShufflerSettings settings, ExtractedGame extractedGame) { // store pokemon we've randomized already in a list, for follows evolution var pokeBaseStatsRandomized = new List <string>(); var pokeAbilitiesRandomized = new List <string>(); var pokeTypesRandomized = new List <string>(); var pokeEvosRandomized = new List <int>(); var easyEvolutions = new List <string>(); Logger.Log("=============================== Pokemon ===============================\n\n"); // set up filtered lists here to avoid recalculating it every loop IEnumerable <Move> movefilter = extractedGame.ValidMoves; if (settings.MoveSetOptions.BanShadowMoves) { movefilter = movefilter.Where(m => !m.IsShadowMove); } IEnumerable <Ability> abilitiesFilter = extractedGame.Abilities; if (!settings.AllowWonderGuard) { abilitiesFilter = abilitiesFilter.Where(a => a.Index != RandomizerConstants.WonderGuardIndex); } if (settings.BanNegativeAbilities) { abilitiesFilter = abilitiesFilter.Where(a => !RandomizerConstants.BadAbilityList.Contains(a.Index)); } // do this first for "follow evolution" checks if (settings.RandomizeEvolutions) { Logger.Log($"Setting New Evolutions\n\n"); foreach (var poke in extractedGame.PokemonList) { // prevent loops and multiple pokemon evolving into the same pokemon pokeEvosRandomized.Add(poke.Index); var pokeFilter = extractedGame.PokemonList.Where(p => !pokeEvosRandomized.Contains(p.Index)); if (settings.EvolutionHasSameType) { pokeFilter = pokeFilter.Where(p => p.Type1 == poke.Type1 || p.Type2 == poke.Type2 || p.Type1 == poke.Type2); } for (int i = 0; i < poke.Evolutions.Length; i++) { var evolution = poke.Evolutions[i]; if (evolution.EvolutionMethod == EvolutionMethods.None) { continue; } if (settings.EvolutionHasSimilarStrength) { var count = 1; var similarStrengths = pokeFilter.Where(p => p.BST >= poke.BST - BSTRange && p.BST <= poke.BST + BSTRange); while (!similarStrengths.Any() && count < 3) { // anybody? hello? count++; similarStrengths = pokeFilter.Where(p => p.BST >= poke.BST - (count * BSTRange) && p.BST <= poke.BST + (count * BSTRange)); } pokeFilter = similarStrengths; } var potentialPokes = pokeFilter.ToArray(); if (potentialPokes.Length == 0) { // null it out Logger.Log($"End of the line for {poke.Name}.\n"); poke.SetEvolution(i, 0, 0, 0); } else { var newPoke = potentialPokes[random.Next(0, potentialPokes.Length)]; // same evolution, just evolves into something else Logger.Log($"{poke.Name} evolves into {newPoke.Name} instead of {extractedGame.PokemonList[evolution.EvolvesInto].Name}.\n"); poke.SetEvolution(i, (byte)evolution.EvolutionMethod, evolution.EvolutionCondition, (ushort)newPoke.Index); pokeEvosRandomized.Add(newPoke.Index); } Logger.Log($"\n"); } } } foreach (var poke in extractedGame.PokemonList) { if (RandomizerConstants.SpecialPokemon.Contains(poke.Index)) { continue; } Logger.Log($"{poke.Name}'s Traits:\n\n"); ChangeCompatibility(random, settings.TMCompatibility, poke, extractedGame, true); if (extractedGame.TutorMoves.Length > 0) { ChangeCompatibility(random, settings.TutorCompatibility, poke, extractedGame, false); } // todo: use enum for bst option // and follow evolution if (settings.RandomizeBaseStats > 0) // || (settings.BaseStatsFollowEvolution && !pokeBaseStatsRandomized.Contains(poke.Name))) { IList <byte> newBsts; if (settings.RandomizeBaseStats == 1) { // shuffle newBsts = new List <byte> { poke.HP, poke.Attack, poke.Defense, poke.SpecialAttack, poke.SpecialDefense, poke.Speed }; // everyone do the the fisher-yates shuffle for (int i = newBsts.Count; i > 0; i--) { var j = random.Next(0, i + 1); // apparently xor swapping is slower than using a temp variable // take that john mcaffee var temp = newBsts[j]; newBsts[j] = newBsts[i]; newBsts[i] = temp; } } else { // random within total var pokeBst = poke.BST; var randomBsts = new byte[6]; newBsts = new byte[6]; random.NextBytes(randomBsts); var randomSum = randomBsts.Sum(b => b); for (int i = 0; i < newBsts.Count; i++) { newBsts[i] = (byte)(((float)randomBsts[i] / randomSum) * pokeBst); } } poke.HP = newBsts[0]; poke.Attack = newBsts[1]; poke.Defense = newBsts[2]; poke.SpecialAttack = newBsts[3]; poke.SpecialDefense = newBsts[4]; poke.Speed = newBsts[5]; Logger.Log($"Setting BSTs: H {newBsts[0]}/A {newBsts[1]}/D {newBsts[2]}/SpA {newBsts[3]}/SpD {newBsts[4]}/S {newBsts[5]}.\n"); if (settings.BaseStatsFollowEvolution) { pokeBaseStatsRandomized.Add(poke.Name); } } if (settings.UpdateBaseStats) { // todo // need some way of loading them without doing something... regrettable } if (settings.StandardizeEXPCurves) { poke.LevelUpRate = RandomizerConstants.Legendaries.Contains(poke.Index) ? ExpRate.Slow : ExpRate.Fast; Logger.Log($"Setting EXP rate to {poke.LevelUpRate}.\n"); } if (settings.RandomizeAbilities && !pokeAbilitiesRandomized.Contains(poke.Name)) { var abilities = abilitiesFilter.ToArray(); RandomizeAbility(random, abilities, poke); if (settings.AbilitiesFollowEvolution) { var endOrSplitEvolution = false; Pokemon currentPoke = poke; pokeAbilitiesRandomized.Add(currentPoke.Name); while (!endOrSplitEvolution) { endOrSplitEvolution = CheckForSplitOrEndEvolution(currentPoke, out var _); if (!endOrSplitEvolution) { var evoPoke = extractedGame.PokemonList[currentPoke.Evolutions[0].EvolvesInto]; evoPoke.Ability1 = poke.Ability1; evoPoke.Ability2 = poke.Ability2; Logger.Log($"Setting {evoPoke.Name}'s Ability to match {poke.Name}.\n"); pokeAbilitiesRandomized.Add(evoPoke.Name); currentPoke = evoPoke; } } } } if (settings.RandomizeTypes && !pokeTypesRandomized.Contains(poke.Name)) { RandomizeTypes(random, poke); if (settings.TypesFollowEvolution) { var endOrSplitEvolution = false; Pokemon currentPoke = poke; pokeTypesRandomized.Add(currentPoke.Name); while (!endOrSplitEvolution) { endOrSplitEvolution = CheckForSplitOrEndEvolution(currentPoke, out var _); if (!endOrSplitEvolution) { var evoPoke = extractedGame.PokemonList[currentPoke.Evolutions[0].EvolvesInto]; evoPoke.Type1 = currentPoke.Type1; evoPoke.Type2 = currentPoke.Type2; Logger.Log($"Setting {evoPoke.Name}'s Type to match {poke.Name}.\n"); pokeTypesRandomized.Add(evoPoke.Name); currentPoke = evoPoke; } } } } if (settings.FixImpossibleEvolutions || settings.EasyEvolutions) { for (int i = 0; i < poke.Evolutions.Length; i++) { if (settings.FixImpossibleEvolutions) { var method = poke.Evolutions[i].EvolutionMethod; if (method == EvolutionMethods.TradeWithItem || method == EvolutionMethods.Trade || method == EvolutionMethods.HappinessDay || method == EvolutionMethods.HappinessNight) { poke.SetEvolution(i, (byte)EvolutionMethods.LevelUp, (ushort)Configuration.TradePokemonEvolutionLevel, poke.Evolutions[i].EvolvesInto); Logger.Log($"Setting to evolve via level up at level {Configuration.TradePokemonEvolutionLevel}\n"); break; } } if (settings.EasyEvolutions) { if (!CheckForSplitOrEndEvolution(poke, out int _)) { var evolution = poke.Evolutions[0]; var evoPoke = extractedGame.PokemonList[evolution.EvolvesInto]; // check if we evolve into something else // i.e. if three stage if (!CheckForSplitOrEndEvolution(evoPoke, out int count)) { var evoPokeEvolution = evoPoke.Evolutions[0]; if (evoPokeEvolution.EvolutionMethod == EvolutionMethods.LevelUp && evoPokeEvolution.EvolutionCondition > 40) { // make a bold assumption that if the second stage evolves by level up then the first does too evoPoke.SetEvolution(0, (byte)evoPokeEvolution.EvolutionMethod, 40, evoPokeEvolution.EvolvesInto); poke.SetEvolution(0, (byte)evolution.EvolutionMethod, 30, evolution.EvolvesInto); Logger.Log($"Setting {poke.Name} to evolve at level 30.\n"); Logger.Log($"Setting {evoPoke.Name} to evolve at level 40.\n"); } } else if (count == 0 && evolution.EvolutionMethod == EvolutionMethods.LevelUp && evolution.EvolutionCondition > 40) { // this is the last stage poke.SetEvolution(0, (byte)evolution.EvolutionMethod, 40, evolution.EvolvesInto); Logger.Log($"Setting to evolve at level 40.\n"); } } } } Logger.Log($"\n"); } // so I heard you like a challenge... if (settings.NoEXP) { poke.BaseExp = 0; } // randomize level up moves if (settings.MoveSetOptions.RandomizeMovesets) { var typeFilter = movefilter; if (settings.MoveSetOptions.PreferType) { // allow 20% chance for move to not be same type typeFilter = typeFilter.Where(m => m.Type == poke.Type1 || m.Type == poke.Type2 || random.Next(0, 10) >= 8).ToArray(); if (!typeFilter.Any()) { typeFilter = movefilter; } } var potentialMoves = typeFilter.ToArray(); for (int i = 0; i < poke.LevelUpMoves.Length; i++) { var move = poke.LevelUpMoves[i]; if (move.Level == 0) { continue; } var newMove = settings.MoveSetOptions.MetronomeOnly ? extractedGame.MoveList[RandomizerConstants.MetronomeIndex] : potentialMoves[random.Next(0, potentialMoves.Length)]; poke.SetLevelUpMove(i, move.Level, (ushort)newMove.MoveIndex); Logger.Log($"Level Up Move at level {move.Level}: {newMove.Name}\n"); } } Logger.Log($"\n"); } }
public static void ShuffleCards(Random random, BingoCardShufflerSettings settings, BattleBingoCard[] bingoCards, ExtractedGame extractedGame) { Logger.Log("=============================== Bingo Cards ===============================\n\n"); var potentialPokes = extractedGame.PokemonList; if (settings.RandomizeBattleBingoPokemon && settings.ForceStrongPokemon) { potentialPokes = potentialPokes.Where(p => p.BST >= Configuration.StrongPokemonBST).ToArray(); } var potentialMoves = extractedGame.MoveList.Where(m => m.BasePower > 0); if (settings.RandomizeBattleBingoMoveSets) { if (settings.ForceGoodDamagingMove) { potentialMoves = potentialMoves.Where(m => m.BasePower >= Configuration.GoodDamagingMovePower); } if (settings.BanShadowMoves) { potentialMoves = potentialMoves.Where(m => !m.IsShadowMove); } } foreach (var card in bingoCards) { for (int i = 0; i <= card.Panels.Length; i++) { BattleBingoPokemon battleBingoPokemon; Pokemon newPoke; if (i == card.Panels.Length) { // randomize starter battleBingoPokemon = card.StartingPokemon; Logger.Log($"Starter: {extractedGame.PokemonList[battleBingoPokemon.Pokemon].Name} -> "); } else { var panel = card.Panels[i]; if (panel.PanelType != BattleBingoPanelType.Pokemon) { continue; } battleBingoPokemon = panel.BingoPokemon; Logger.Log($"Panel Pokemon: {extractedGame.PokemonList[battleBingoPokemon.Pokemon].Name} -> "); } newPoke = extractedGame.PokemonList[battleBingoPokemon.Pokemon]; if (settings.RandomizeBattleBingoPokemon) { newPoke = potentialPokes[random.Next(0, potentialPokes.Length)]; battleBingoPokemon.Pokemon = (ushort)newPoke.Index; } Logger.Log($"{extractedGame.PokemonList[battleBingoPokemon.Pokemon].Name}\n"); if (settings.RandomizeBattleBingoMoveSets) { // filter again by stab moves var movePool = potentialMoves; if (settings.ForceSTABMove) { var stabMoves = potentialMoves.Where(m => m.Type == newPoke.Type1 || m.Type == newPoke.Type2); // don't use stab moves if there aren't any that match if (stabMoves.Any()) { movePool = stabMoves; } } // pick good moves battleBingoPokemon.Move = (ushort)movePool.ElementAt(random.Next(0, movePool.Count())).MoveIndex; } Logger.Log($"Move: {extractedGame.MoveList[battleBingoPokemon.Move].Name}\n\n"); } // if you shuffle the panels do you have to write back the offset? } }
public static void ShuffleTeams(Random random, TeamShufflerSettings settings, ExtractedGame extractedGame) { var potentialItems = settings.BanBadItems ? extractedGame.GoodItems : extractedGame.NonKeyItems; var potentialMoves = extractedGame.MoveList; if (settings.MoveSetOptions.RandomizeMovesets && settings.MoveSetOptions.ForceGoodMoves) { potentialMoves = potentialMoves.Where(m => m.BasePower >= Configuration.GoodDamagingMovePower).ToArray(); } Logger.Log("=============================== Trainers ===============================\n\n"); // yikes foreach (var pool in extractedGame.TrainerPools) { if (pool.TeamType == TrainerPoolType.DarkPokemon) { continue; } foreach (var trainer in pool.AllTrainers) { if (!trainer.IsSet) { continue; } Logger.Log($"Trainer {trainer.Name}\nWith:\n"); foreach (var pokemon in trainer.Pokemon) { if (pokemon.Pokemon == 0) { continue; } RandomizePokemon(random, settings, pokemon, extractedGame.PokemonList); Logger.Log($"{extractedGame.PokemonList[pokemon.Pokemon].Name}\n"); Logger.Log($"Is a shadow Pokemon: {pokemon.IsShadow}\n"); if (settings.RandomizeHeldItems) { var item = potentialItems[random.Next(0, potentialItems.Length)]; pokemon.Item = (ushort)item.Index; Logger.Log($"Holding a(n) {item.Name}\n"); } if (settings.SetMinimumShadowCatchRate && pokemon.IsShadow) { if (pokemon.ShadowCatchRate == 0) { pokemon.ShadowCatchRate = extractedGame.PokemonList[pokemon.Pokemon].CatchRate; } var catchRate = Math.Max(pokemon.ShadowCatchRate, settings.ShadowCatchRateMinimum); var catchRateIncrease = (byte)Math.Clamp(catchRate, 0, byte.MaxValue); Logger.Log($"Setting catch rate to {catchRateIncrease}\n"); pokemon.ShadowCatchRate = catchRateIncrease; } if (settings.BoostTrainerLevel) { var level = pokemon.Level; var levelIncrease = (byte)Math.Clamp(level + level * settings.BoostTrainerLevelPercent, 1, 100); Logger.Log($"Boosting level from {pokemon.Level} to {levelIncrease}\n"); pokemon.Level = levelIncrease; } RandomizeMoveSet(random, settings, pokemon, extractedGame); Logger.Log($"\n"); } Logger.Log($"\n"); } Logger.Log($"\n"); } }
public static void RandomizeMoveSet(Random random, TeamShufflerSettings settings, ITrainerPokemon pokemon, ExtractedGame extractedGame) { ushort[] moveSet = null; if (settings.MoveSetOptions.MetronomeOnly) { moveSet = Enumerable.Repeat(RandomizerConstants.MetronomeIndex, Constants.NumberOfPokemonMoves).ToArray(); } else if (settings.MoveSetOptions.RandomizeMovesets || settings.RandomizePokemon) { moveSet = MoveShuffler.GetNewMoveset(random, settings.MoveSetOptions, pokemon.Pokemon, pokemon.Level, extractedGame); } if (moveSet != null) { Logger.Log($"It knows:\n"); for (int i = 0; i < moveSet.Length; i++) { var move = moveSet[i]; Logger.Log($"{extractedGame.MoveList[move].Name}\n"); pokemon.SetMove(i, move); } } }