PKHeX/PKHeX.Core/Legality/Structures/TreesArea.cs
javierhimura 461fb70f90 Generation 1/2 Legal improvements (#1310)
* Added location to encounter slot to make verification againts the location of the encounter when the pokemon has lost met location, like generation 2 heabutt tree, jhoto surfing in route 45 and in the future generation 4 munchlax tree

Added version to generation 1 and 2 encounter locations to filter by catch rate based of the version of the encounter and check initial moves of the encounter only for the game that match the encounter

Filter generation 2 pokemon for crystal who have met location based of the time of day when it was captured

Completed version to static and traded encounters for gen 1 pokemon, to avoid check a red encounter with yellow initial moves, if an encounter is possible in both games with diferent moves it is duplicated (like eevee), if it is possible in both games with the same moves is left as RBY, the encounter will only use red/blue moveset

Verify some invalid gen 2 encounters. Crystall heabutt encounters based on the TID, using the tree selection algorithm of the game to determine if the encounter is possible for the TID (implemented base on https://bulbapedia.bulbagarden.net/wiki/Headbutt_tree#Mechanics). Coordinates of Crystal trees obtained with the programa G2Map

Added checks for fishing encounters for unreacheable water tiles in gen 2, route 14, national park and the beta safari zone.

* Fix gen 1 static encounters and trade encounters filter by version

* Missing strings
2017-07-06 16:03:41 -07:00

146 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;
}
}
}
}