mirror of
https://github.com/kwsch/PKHeX
synced 2024-11-16 09:08:02 +00:00
147 lines
6.2 KiB
C#
147 lines
6.2 KiB
C#
|
using System.Linq;
|
|||
|
|
|||
|
namespace PKHeX.Core
|
|||
|
{
|
|||
|
// Pokemon Crystal Headbutt tree encounters by trainer id, base on mechanics described in
|
|||
|
// https://bulbapedia.bulbagarden.net/wiki/Headbutt_tree#Mechanics
|
|||
|
|
|||
|
public enum TreeEncounterAvailable
|
|||
|
{
|
|||
|
ValidTree, // Encounter is possible a reacheable tree
|
|||
|
InvalidTree, // Encounter is only possible a tree reacheable only with walk-trought walls cheats
|
|||
|
Impossible // Encounter is not possible in any tree
|
|||
|
}
|
|||
|
|
|||
|
public class TreeCoordinates
|
|||
|
{
|
|||
|
internal int X { get; set; }
|
|||
|
internal int Y { get; set; }
|
|||
|
internal int Index => ((X * Y + X + Y) / 5) % 10;
|
|||
|
}
|
|||
|
|
|||
|
public class TreesArea
|
|||
|
{
|
|||
|
public int Location { get; private set; }
|
|||
|
public TreeEncounterAvailable[] TrainerModerateEncounterTree { get; private set; }
|
|||
|
public TreeEncounterAvailable[] TrainerLowEncounterTree { get; private set; }
|
|||
|
|
|||
|
private int[] ValidTreeIndex { get; set; }
|
|||
|
private int[] InvalidTreeIndex { get; set; }
|
|||
|
|
|||
|
private TreeCoordinates[] ValidTrees { get; set; }
|
|||
|
private TreeCoordinates[] InvalidTrees { get; set; }
|
|||
|
private static int[][] TrainerModerateTreeIndex { get; set; }
|
|||
|
|
|||
|
internal static TreesArea[] GetArray(byte[][] entries)
|
|||
|
{
|
|||
|
if (entries == null)
|
|||
|
return null;
|
|||
|
TrainerModerateTreeIndex = GenerateTrainersTreeIndex();
|
|||
|
var Areas = new TreesArea[entries.Length];
|
|||
|
for(int i = 0; i < entries.Length; i++)
|
|||
|
{
|
|||
|
Areas[i] = GetArea(entries[i]);
|
|||
|
}
|
|||
|
return Areas;
|
|||
|
}
|
|||
|
|
|||
|
private static int[][] GenerateTrainersTreeIndex()
|
|||
|
{
|
|||
|
// A tree have a low encounter or moderate encounter base on the TID Pivot Index ( TID % 10)
|
|||
|
// Calculate for every Trainer Pivot Index the 5 tree index for low encounters
|
|||
|
int[][] TrainersIndex = new int[10][];
|
|||
|
for (int pivotindex = 0; pivotindex < 10; pivotindex++)
|
|||
|
{
|
|||
|
int[] ModerateEncounterTreeIndex = new int[5];
|
|||
|
for(int index = 0; index <= 4; index++)
|
|||
|
ModerateEncounterTreeIndex[index] = (pivotindex + index) % 10;
|
|||
|
TrainersIndex[pivotindex] = ModerateEncounterTreeIndex.OrderBy(x => x).ToArray();
|
|||
|
}
|
|||
|
return TrainersIndex;
|
|||
|
}
|
|||
|
|
|||
|
private static TreesArea GetArea(byte[] entrie)
|
|||
|
{
|
|||
|
var Area = new TreesArea();
|
|||
|
|
|||
|
Area.ReadAreaRawData(entrie);
|
|||
|
Area.GenerateAreaTreeIndex();
|
|||
|
Area.GenerateAreaTrainerEncounters();
|
|||
|
return Area;
|
|||
|
}
|
|||
|
|
|||
|
private void ReadAreaRawData(byte[] entrie)
|
|||
|
{
|
|||
|
// Coordinates of trees for every are obtained with programa G2Map
|
|||
|
// ValidTrees are those accesible from the player
|
|||
|
// Invalid tress are trees that the player can not reach without cheating devices, like a tree beyond other trees
|
|||
|
Location = entrie[0];
|
|||
|
ValidTrees = new TreeCoordinates[entrie[1]];
|
|||
|
|
|||
|
var ofs = 2;
|
|||
|
for (int i = 0; i < ValidTrees.Length; i++)
|
|||
|
{
|
|||
|
ValidTrees[i] = new TreeCoordinates()
|
|||
|
{
|
|||
|
X = entrie[ofs],
|
|||
|
Y = entrie[ofs + 1]
|
|||
|
};
|
|||
|
ofs += 2;
|
|||
|
}
|
|||
|
InvalidTrees = new TreeCoordinates[entrie[ofs]];
|
|||
|
ofs += 1;
|
|||
|
for (int i = 0; i < InvalidTrees.Length; i++)
|
|||
|
{
|
|||
|
InvalidTrees[i] = new TreeCoordinates()
|
|||
|
{
|
|||
|
X = entrie[ofs],
|
|||
|
Y = entrie[ofs + 1]
|
|||
|
};
|
|||
|
ofs += 2;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
private void GenerateAreaTreeIndex()
|
|||
|
{
|
|||
|
// For legallity purpose only the tree index is needed, group the trees data by their index, trees with the same index are indistinguible
|
|||
|
ValidTreeIndex = ValidTrees.Select(t => t.Index).Distinct().OrderBy(i => i).ToArray();
|
|||
|
InvalidTreeIndex = InvalidTrees.Select(t => t.Index).Distinct().OrderBy(i => i).Except(ValidTreeIndex).ToArray();
|
|||
|
}
|
|||
|
|
|||
|
private void GenerateAreaTrainerEncounters()
|
|||
|
{
|
|||
|
// Check for every trainer pivot index if there is trees with low encounter and moderate encounter available in the area
|
|||
|
TrainerModerateEncounterTree = new TreeEncounterAvailable[10];
|
|||
|
TrainerLowEncounterTree = new TreeEncounterAvailable[10];
|
|||
|
for (int pivotindex = 0; pivotindex < 10; pivotindex++)
|
|||
|
{
|
|||
|
var TrainerModerateTrees = TrainerModerateTreeIndex[pivotindex];
|
|||
|
|
|||
|
var ModerateValid = ValidTreeIndex.Any(t => TrainerModerateTrees.Contains(t));
|
|||
|
var ModerateInvalid = InvalidTreeIndex.Any(t => TrainerModerateTrees.Contains(t));
|
|||
|
if (ModerateValid)
|
|||
|
// There is a valid tree with an index for moderate encounters
|
|||
|
TrainerModerateEncounterTree[pivotindex] = TreeEncounterAvailable.ValidTree;
|
|||
|
else if (ModerateInvalid)
|
|||
|
// There is a tree with an index for moderate encounters but is invalid
|
|||
|
TrainerModerateEncounterTree[pivotindex] = TreeEncounterAvailable.InvalidTree;
|
|||
|
else
|
|||
|
// No trees for moderate encounters
|
|||
|
TrainerModerateEncounterTree[pivotindex] = TreeEncounterAvailable.Impossible;
|
|||
|
|
|||
|
var LowValid = ValidTreeIndex.Except(TrainerModerateTrees).Any();
|
|||
|
var LowInvalid = InvalidTreeIndex.Except(TrainerModerateTrees).Any();
|
|||
|
if (LowValid)
|
|||
|
// There is a valid tree with an index for low encounters
|
|||
|
TrainerLowEncounterTree[pivotindex] = TreeEncounterAvailable.ValidTree;
|
|||
|
else if (LowInvalid)
|
|||
|
// There is a tree with an index for low encounters but is invalid
|
|||
|
TrainerLowEncounterTree[pivotindex] = TreeEncounterAvailable.InvalidTree;
|
|||
|
else
|
|||
|
// No trees for low encounters
|
|||
|
TrainerLowEncounterTree[pivotindex] = TreeEncounterAvailable.Impossible;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|