Skip to content

Commit

Permalink
Differentiate Aggressive & Beta(Skittish) battle start paths (#8)
Browse files Browse the repository at this point in the history
* Beta path options

Suppose you have the following spawns: aabb
Where, a = aggressive, b = beta (skittish).
The next 2 spawns will be beta pokemon.
This step will only dismiss 2 pokemon.

By ridding of aa (not ab), the next state is bbbb, resulting in a potential 4 new entities the following step. Ridding of ab or bb will result in abbb and aabb, neither of which can be 4x advanced the next step.

If the next spawn is aa instead of bb, we get aaab or aaaa if we rid bb or ab, still both separate states. Both with different possibilities.

Mixed behaviors is more heavily skewed towards having bbbb, b stuff will be dominant. Lots of overlap, but there are potential end states that are only reachable by trying every single action.

Co-authored-by: Lusamine <[email protected]>
  • Loading branch information
kwsch and Lusamine authored Apr 15, 2022
1 parent 213853e commit e7cdced
Show file tree
Hide file tree
Showing 12 changed files with 230 additions and 165 deletions.
4 changes: 2 additions & 2 deletions PermuteMMO.ConsoleApp/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,13 @@
if (File.Exists(file))
data_mo = File.ReadAllBytes(file_mo);
else
data_mo = SpawnGenerator.SaveFile.Accessor.GetBlock(0x1E0F1BA3).Data;
data_mo = SaveFileParameter.GetMassOutbreakData();

const string file_mmo = "mmo.bin";
if (File.Exists(file_mmo))
data_mmo = File.ReadAllBytes(file_mmo);
else
data_mmo = SpawnGenerator.SaveFile.Accessor.GetBlock(0x7799EB86).Data;
data_mmo = SaveFileParameter.GetMassiveMassOutbreakData();
}

// Compute and print.
Expand Down
17 changes: 6 additions & 11 deletions PermuteMMO.Lib/ConsolePermuter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,9 @@ public static void PermuteMassiveMassOutbreak(Span<byte> data)
}

Console.WriteLine($"Spawner {j+1} at ({spawner.X:F1}, {spawner.Y:F1}, {spawner.Z}) shows {SpeciesName.GetSpeciesName(spawner.DisplaySpecies, 2)}");
Console.WriteLine($"Parameters: {spawn}");
Console.WriteLine(spawn.GetSummary("Parameters: "));
Console.WriteLine($"Seed: {seed}");
bool skittishBase = SpawnGenerator.IsSkittish(spawn.Set.Table);
bool skittishBonus = spawn.GetNextWave(out var next) && SpawnGenerator.IsSkittish(next.Set.Table);
var lines = result.GetLines(skittishBase, skittishBonus);
var lines = result.GetLines();
foreach (var line in lines)
Console.WriteLine(line);
Console.WriteLine();
Expand Down Expand Up @@ -102,10 +100,9 @@ public static void PermuteBlockMassOutbreak(Span<byte> data)
Console.WriteLine($"Found paths for {(Species)spawner.DisplaySpecies} Mass Outbreak in {areaName}:");
Console.WriteLine("==========");
Console.WriteLine($"Spawner at ({spawner.X:F1}, {spawner.Y:F1}, {spawner.Z}) shows {SpeciesName.GetSpeciesName(spawner.DisplaySpecies, 2)}");
Console.WriteLine($"Parameters: {spawn}");
Console.WriteLine(spawn.GetSummary("Parameters: "));
Console.WriteLine($"Seed: {seed}");
bool skittishBase = SpawnGenerator.IsSkittish(spawner.DisplaySpecies);
var lines = result.GetLines(skittishBase);
var lines = result.GetLines();
foreach (var line in lines)
Console.WriteLine(line);
Console.WriteLine();
Expand All @@ -121,7 +118,7 @@ public static void PermuteSingle(SpawnInfo spawn, ulong seed, ushort species)
{
Console.WriteLine($"Permuting all possible paths for {seed:X16}.");
Console.WriteLine($"Base Species: {SpeciesName.GetSpeciesName(species, 2)}");
Console.WriteLine($"Parameters: {spawn}");
Console.WriteLine(spawn.GetSummary("Parameters: "));
Console.WriteLine($"Seed: {seed}");

var result = Permuter.Permute(spawn, seed);
Expand All @@ -131,9 +128,7 @@ public static void PermuteSingle(SpawnInfo spawn, ulong seed, ushort species)
}
else
{
bool skittishBase = SpawnGenerator.IsSkittish(spawn.Set.Table);
bool skittishBonus = spawn.GetNextWave(out var next) && SpawnGenerator.IsSkittish(next.Set.Table);
var lines = result.GetLines(skittishBase, skittishBonus);
var lines = result.GetLines();
foreach (var line in lines)
Console.WriteLine(line);
}
Expand Down
3 changes: 2 additions & 1 deletion PermuteMMO.Lib/Generation/EntityResult.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,9 @@ public sealed class EntityResult
public byte Height { get; set; }
public byte Weight { get; set; }

public bool IsOblivious => BehaviorUtil.Oblivious.Contains(Species);
public bool IsSkittish => BehaviorUtil.Skittish.Contains(Species);
public bool IsAggressive => IsAlpha || !IsSkittish;
public bool IsAggressive => IsAlpha || !(IsSkittish || IsOblivious);

public string GetSummary()
{
Expand Down
58 changes: 58 additions & 0 deletions PermuteMMO.Lib/Generation/SaveFileParameter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
using PKHeX.Core;

namespace PermuteMMO.Lib;

/// <summary>
/// Fetches environment specific values necessary for spawn generation.
/// </summary>
public static class SaveFileParameter
{
#region Public Mutable - Useful for DLL consumers

public static SAV8LA SaveFile { get; set; } = GetFake();
public static PokedexSave8a Pokedex => SaveFile.PokedexSave;
public static byte[] BackingArray => SaveFile.Blocks.GetBlock(0x02168706).Data;
public static bool HasCharm { get; set; } = true;
public static bool UseSaveFileShinyRolls { get; set; }

public static byte[] GetMassOutbreakData() => SaveFile.GetMassOutbreakData();
public static byte[] GetMassiveMassOutbreakData() => SaveFile.GetMassiveMassOutbreakData();

public static byte[] GetMassOutbreakData(this SAV8LA sav) => sav.Accessor.GetBlock(0x1E0F1BA3).Data;
public static byte[] GetMassiveMassOutbreakData(this SAV8LA sav) => sav.Accessor.GetBlock(0x7799EB86).Data;

#endregion

private static SAV8LA GetFake()
{
var mainPath = AppDomain.CurrentDomain.BaseDirectory;
mainPath = Path.Combine(mainPath, "main");
if (File.Exists(mainPath))
return GetFromFile(mainPath);
return new SAV8LA();
}

private static SAV8LA GetFromFile(string mainPath)
{
var data = File.ReadAllBytes(mainPath);
var sav = new SAV8LA(data);
UseSaveFileShinyRolls = true;
HasCharm = sav.Inventory.Any(z => z.Items.Any(i => i.Index == 632 && i.Count is not 0));
return sav;
}

/// <summary>
/// Gets the count of shiny rolls the player is permitted to have when rolling an <see cref="PKM.PID"/>.
/// </summary>
/// <param name="species">Encounter species</param>
/// <param name="type">Encounter Spawn type</param>
/// <returns>[1,X] iteration of PID rolls permitted</returns>
public static int GetRerollCount(in int species, SpawnType type)
{
if (!UseSaveFileShinyRolls)
return (int)type;
bool perfect = Pokedex.IsPerfect(species);
bool complete = Pokedex.IsComplete(species);
return 1 + (complete ? 1 : 0) + (perfect ? 2 : 0) + (HasCharm ? 3 : 0) + (int)(type - 7);
}
}
43 changes: 1 addition & 42 deletions PermuteMMO.Lib/Generation/SpawnGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,38 +11,6 @@ public static class SpawnGenerator
{
public static readonly IReadOnlyDictionary<ulong, SlotDetail[]> EncounterTables = JsonDecoder.GetDictionary(Resources.mmo_es);

#region Public Mutable - Useful for DLL consumers
public static SAV8LA SaveFile { get; set; } = GetFake();
public static PokedexSave8a Pokedex => SaveFile.PokedexSave;
public static byte[] BackingArray => SaveFile.Blocks.GetBlock(0x02168706).Data;
public static bool HasCharm { get; set; } = true;
public static bool UseSaveFileShinyRolls { get; set; }
#endregion

private static SAV8LA GetFake()
{
if (File.Exists("main"))
{
var data = File.ReadAllBytes("main");
var sav = new SAV8LA(data);
UseSaveFileShinyRolls = true;
HasCharm = sav.Inventory.Any(z => z.Items.Any(i => i.Index == 632 && i.Count is not 0));
return sav;
}
return new SAV8LA();
}

/// <summary>
/// Checks if a Table (or species) is skittish.
/// </summary>
/// <param name="table">Table hash or species ID.</param>
/// <returns>True if skittish.</returns>
public static bool IsSkittish(ulong table)
{
var slots = GetSlots(table);
return slots.Any(z => z.IsSkittish);
}

/// <summary>
/// Generates an <see cref="EntityResult"/> from the input <see cref="seed"/> and <see cref="table"/>.
/// </summary>
Expand All @@ -61,7 +29,7 @@ public static EntityResult Generate(in ulong seed, in ulong table, SpawnType typ
var gt = PersonalTable.LA.GetFormEntry(slot.Species, slot.Form).Gender;

// Get roll count from save file
int shinyRolls = GetRerollCount(slot.Species, type);
int shinyRolls = SaveFileParameter.GetRerollCount(slot.Species, type);

var result = new EntityResult
{
Expand Down Expand Up @@ -109,15 +77,6 @@ private static SlotDetail[] GetFakeOutbreak(ushort species)
return Outbreaks[species] = value;
}

private static int GetRerollCount(in int species, SpawnType type)
{
if (!UseSaveFileShinyRolls)
return (int)type;
bool perfect = Pokedex.IsPerfect(species);
bool complete = Pokedex.IsComplete(species);
return 1 + (complete ? 1 : 0) + (perfect ? 2 : 0) + (HasCharm ? 3 : 0) + (int)type;
}

private static int GetLevel(SlotDetail slot, Xoroshiro128Plus slotrng)
{
var min = slot.LevelMin;
Expand Down
75 changes: 35 additions & 40 deletions PermuteMMO.Lib/Permutation/Advance.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,16 @@ public enum Advance : byte
{
CR,

A1,
A2,
A3,
A4,

G1,
G2,
G3,
// G4 is equivalent to CR

// S1 is equivalent to A1
S2,
S3,
S4,
A1, A2, A3, A4, // Aggressive
B1, B2, B3, B4, // Beta

O1, // Oblivious

// S1 is equivalent to B1
S2, S3, S4,

// G4 is equivalent to CR
G1, G2, G3,
}

public static class AdvanceExtensions
Expand All @@ -42,10 +38,17 @@ public static class AdvanceExtensions
{
CR => "Clear Remaining",

A1 => "De-spawn 1",
A2 => "Battle 2",
A3 => "Battle 3",
A4 => "Battle 4",
A1 => "1 Aggressive",
A2 => "2 Aggressive",
A3 => "3 Aggressive",
A4 => "4 Aggressive",

B1 => "1 Beta",
B2 => "1 Beta + 1 Aggressive",
B3 => "1 Beta + 2 Aggressive",
B4 => "1 Beta + 3 Aggressive",

O1 => "1 Oblivious",

G1 => "De-spawn 1 + Leave",
G2 => "De-spawn 2 + Leave",
Expand All @@ -62,48 +65,40 @@ public static class AdvanceExtensions
/// </summary>
public static int AdvanceCount(this Advance advance) => advance switch
{
A1 or G1 => 1,
A2 or S2 or G2 => 2,
A3 or S3 or G3 => 3,
A4 or S4 => 4,
A1 or B1 or G1 => 1,
A2 or B2 or S2 or G2 => 2,
A3 or B3 or S3 or G3 => 3,
A4 or B4 or S4 => 4,
_ => 0,
};

/// <summary>
/// Indicates if a multi-battle is required for this advancement.
/// </summary>
public static bool IsMulti(this Advance advance) => advance is (A2 or A3 or A4);
public static bool IsMultiAny(this Advance advance) => advance.IsMultiAggressive() || advance.IsMultiBeta() || advance.IsMultiScare();

/// <summary>
/// Indicates if a multi-battle is required for this advancement.
/// </summary>
public static bool IsScare(this Advance advance) => advance is (S2 or S3 or S4);
public static bool IsMultiAggressive(this Advance advance) => advance is (A2 or A3 or A4);

/// <summary>
/// Indicates if any advance requires a multi-battle for advancement.
/// Indicates if a multi-battle is required for this advancement.
/// </summary>
public static bool IsAnyMulti(this ReadOnlySpan<Advance> advances)
{
foreach (var adv in advances)
{
if (adv.IsMulti())
return true;
}

return false;
}
public static bool IsMultiScare(this Advance advance) => advance is (S2 or S3 or S4);

/// <summary>
/// Indicates if any advance requires a multi-scare for advancement.
/// Indicates if a multi-battle is required for this advancement.
/// </summary>
public static bool IsAnyMultiScare(this ReadOnlySpan<Advance> advances)
public static bool IsMultiBeta(this Advance advance) => advance is (B2 or B3 or B4);

public static bool IsAny<T>(this ReadOnlySpan<T> span, Func<T, bool> check)
{
foreach (var adv in advances)
foreach (var x in span)
{
if (adv.IsScare())
if (check(x))
return true;
}

return false;
}
}
12 changes: 10 additions & 2 deletions PermuteMMO.Lib/Permutation/PermuteMeta.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,17 +52,25 @@ public void AddResult(EntityResult entity, in int index)
/// <summary>
/// Calls <see cref="PermuteResult.GetLine"/> for all objects in the result list.
/// </summary>
public IEnumerable<string> GetLines(bool skittishBase, bool skittishBonus = false)
public IEnumerable<string> GetLines()
{
for (var i = 0; i < Results.Count; i++)
{
var result = Results[i];
var parent = FindNearestParentAdvanceResult(i, result.Advances);
bool isActionMultiResult = IsActionMultiResult(i, result.Advances);
yield return result.GetLine(parent, isActionMultiResult, skittishBase, skittishBonus);
bool hasChildChain = HasChildChain(i, result.Advances);
yield return result.GetLine(parent, isActionMultiResult, hasChildChain);
}
}

private bool HasChildChain(int index, Advance[] parent)
{
if (++index >= Results.Count)
return false;
return IsSubset(parent, Results[index].Advances);
}

private bool IsActionMultiResult(int index, Advance[] child)
{
int count = 0;
Expand Down
Loading

0 comments on commit e7cdced

Please sign in to comment.