2016-11-08 16:43:57 +00:00
|
|
|
|
using System;
|
2017-02-27 02:23:29 +00:00
|
|
|
|
using System.Collections.Generic;
|
2017-02-12 17:52:26 +00:00
|
|
|
|
using System.Linq;
|
2016-11-08 16:43:57 +00:00
|
|
|
|
|
2017-01-08 07:54:09 +00:00
|
|
|
|
namespace PKHeX.Core
|
2016-11-08 16:43:57 +00:00
|
|
|
|
{
|
2017-10-24 06:12:58 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Represents an Area where <see cref="PKM"/> can be encountered, which contains a Location ID and <see cref="EncounterSlot"/> data.
|
|
|
|
|
/// </summary>
|
2016-11-08 16:43:57 +00:00
|
|
|
|
public class EncounterArea
|
|
|
|
|
{
|
|
|
|
|
public int Location;
|
|
|
|
|
public EncounterSlot[] Slots;
|
2017-10-24 06:12:58 +00:00
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Creates an empty encounter area ready for initialization.
|
|
|
|
|
/// </summary>
|
2016-11-08 16:43:57 +00:00
|
|
|
|
public EncounterArea() { }
|
|
|
|
|
|
2017-10-24 06:12:58 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Creates an array of encounter data with a specified location ID.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="data">Encounter data</param>
|
|
|
|
|
/// <remarks>
|
|
|
|
|
/// Encounter Data is stored in the following format: (u16 Location, n*[u16 Species/Form, u8 Min, u8 Max])
|
|
|
|
|
/// </remarks>
|
2016-11-08 16:43:57 +00:00
|
|
|
|
private EncounterArea(byte[] data)
|
|
|
|
|
{
|
|
|
|
|
Location = BitConverter.ToUInt16(data, 0);
|
|
|
|
|
Slots = new EncounterSlot[(data.Length - 2) / 4];
|
|
|
|
|
for (int i = 0; i < Slots.Length; i++)
|
|
|
|
|
{
|
|
|
|
|
ushort SpecForm = BitConverter.ToUInt16(data, 2 + i * 4);
|
|
|
|
|
Slots[i] = new EncounterSlot
|
|
|
|
|
{
|
|
|
|
|
Species = SpecForm & 0x7FF,
|
|
|
|
|
Form = SpecForm >> 11,
|
|
|
|
|
LevelMin = data[4 + i * 4],
|
|
|
|
|
LevelMax = data[5 + i * 4],
|
|
|
|
|
};
|
|
|
|
|
}
|
2017-11-26 02:16:50 +00:00
|
|
|
|
foreach (var slot in Slots)
|
|
|
|
|
slot.Area = this;
|
2016-11-08 16:43:57 +00:00
|
|
|
|
}
|
2017-02-12 17:52:26 +00:00
|
|
|
|
|
2017-03-19 15:44:36 +00:00
|
|
|
|
public EncounterArea Clone(int location)
|
|
|
|
|
{
|
2017-11-26 02:16:50 +00:00
|
|
|
|
EncounterArea Area = new EncounterArea
|
2017-03-19 19:27:58 +00:00
|
|
|
|
{
|
|
|
|
|
Location = location,
|
|
|
|
|
Slots = new EncounterSlot[Slots.Length]
|
|
|
|
|
};
|
2017-03-19 15:44:36 +00:00
|
|
|
|
for (int i = 0; i < Slots.Length; i++)
|
|
|
|
|
{
|
2017-11-26 02:16:50 +00:00
|
|
|
|
Area.Slots[i] = Slots[i].Clone();
|
|
|
|
|
Area.Slots[i].Area = Area;
|
2017-03-19 15:44:36 +00:00
|
|
|
|
}
|
2017-11-26 02:16:50 +00:00
|
|
|
|
return Area;
|
2017-03-19 15:44:36 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public EncounterArea[] Clone(int[] locations)
|
|
|
|
|
{
|
|
|
|
|
EncounterArea[] Areas = new EncounterArea[locations.Length];
|
2017-03-19 19:27:58 +00:00
|
|
|
|
for (int i = 0; i < locations.Length; i++)
|
|
|
|
|
Areas[i] = Clone(locations[i]);
|
2017-03-19 15:44:36 +00:00
|
|
|
|
return Areas;
|
|
|
|
|
}
|
|
|
|
|
|
2017-10-24 06:12:58 +00:00
|
|
|
|
private static IEnumerable<EncounterSlot1> GetSlots1_GW(byte[] data, ref int ofs, SlotType t)
|
2017-02-12 17:52:26 +00:00
|
|
|
|
{
|
|
|
|
|
int rate = data[ofs++];
|
2017-10-24 06:12:58 +00:00
|
|
|
|
return rate == 0 ? Enumerable.Empty<EncounterSlot1>() : ReadSlots(data, ref ofs, 10, t, rate);
|
2017-02-12 17:52:26 +00:00
|
|
|
|
}
|
2017-06-18 01:37:19 +00:00
|
|
|
|
private static EncounterSlot1[] GetSlots1_F(byte[] data, ref int ofs)
|
2017-02-12 17:52:26 +00:00
|
|
|
|
{
|
|
|
|
|
int count = data[ofs++];
|
2017-06-18 01:37:19 +00:00
|
|
|
|
return ReadSlots(data, ref ofs, count, SlotType.Super_Rod, -1);
|
2017-02-12 17:52:26 +00:00
|
|
|
|
}
|
2017-02-27 02:23:29 +00:00
|
|
|
|
|
2017-06-18 01:37:19 +00:00
|
|
|
|
private static EncounterSlot1[] GetSlots2_GW(byte[] data, ref int ofs, SlotType t, int slotSets, int slotCount)
|
2017-02-27 02:23:29 +00:00
|
|
|
|
{
|
|
|
|
|
byte[] rates = new byte[slotSets];
|
|
|
|
|
for (int i = 0; i < rates.Length; i++)
|
|
|
|
|
rates[i] = data[ofs++];
|
|
|
|
|
|
2017-06-18 01:37:19 +00:00
|
|
|
|
var slots = ReadSlots(data, ref ofs, slotSets * slotCount, t, rates[0]);
|
2017-07-06 23:03:41 +00:00
|
|
|
|
for (int i = 0; i < slotCount; i++)
|
|
|
|
|
{
|
|
|
|
|
slots[i].Time = EncounterTime.Morning;
|
|
|
|
|
}
|
2017-02-27 02:23:29 +00:00
|
|
|
|
for (int r = 1; r < slotSets; r++)
|
|
|
|
|
{
|
|
|
|
|
for (int i = 0; i < slotCount; i++)
|
|
|
|
|
{
|
|
|
|
|
int index = i + r*slotCount;
|
|
|
|
|
slots[index].Rate = rates[r];
|
|
|
|
|
slots[index].SlotNumber = i;
|
2017-07-07 11:53:21 +00:00
|
|
|
|
slots[index].Time = r == 1 ? EncounterTime.Day : EncounterTime.Night;
|
2017-02-27 02:23:29 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return slots;
|
|
|
|
|
}
|
|
|
|
|
|
2017-10-24 06:12:58 +00:00
|
|
|
|
private static List<EncounterSlot1> GetSlots2_F(byte[] data, ref int ofs, SlotType t)
|
2017-02-27 05:46:00 +00:00
|
|
|
|
{
|
|
|
|
|
// slot set ends in 0xFF 0x** 0x**
|
|
|
|
|
var slots = new List<EncounterSlot1>();
|
2017-06-16 05:21:02 +00:00
|
|
|
|
int ctr = 0;
|
2017-02-27 05:46:00 +00:00
|
|
|
|
while (true)
|
|
|
|
|
{
|
|
|
|
|
int rate = data[ofs++];
|
|
|
|
|
int species = data[ofs++];
|
|
|
|
|
int level = data[ofs++];
|
|
|
|
|
|
|
|
|
|
slots.Add(new EncounterSlot1
|
|
|
|
|
{
|
|
|
|
|
Rate = rate,
|
|
|
|
|
Species = species,
|
|
|
|
|
LevelMin = level,
|
|
|
|
|
LevelMax = level,
|
2017-06-16 05:21:02 +00:00
|
|
|
|
SlotNumber = ctr++,
|
2017-02-27 05:46:00 +00:00
|
|
|
|
Type = species == 0 ? SlotType.Special : t // day/night specific
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (rate == 0xFF)
|
|
|
|
|
break;
|
|
|
|
|
}
|
2017-10-24 06:12:58 +00:00
|
|
|
|
return slots;
|
2017-02-27 05:46:00 +00:00
|
|
|
|
}
|
2017-06-18 01:37:19 +00:00
|
|
|
|
private static EncounterSlot1[] GetSlots2_H(byte[] data, ref int ofs, SlotType t)
|
2017-03-03 02:24:50 +00:00
|
|
|
|
{
|
|
|
|
|
// slot set ends in 0xFF
|
|
|
|
|
var slots = new List<EncounterSlot1>();
|
|
|
|
|
int tableCount = t == SlotType.Headbutt ? 2 : 1;
|
2017-07-06 23:03:41 +00:00
|
|
|
|
SlotType slottype = t;
|
2017-03-03 02:24:50 +00:00
|
|
|
|
while (tableCount != 0)
|
|
|
|
|
{
|
2017-07-06 23:03:41 +00:00
|
|
|
|
if (t == SlotType.Headbutt)
|
|
|
|
|
slottype = tableCount == 2 ? SlotType.Headbutt_Special : SlotType.Headbutt;
|
2017-03-03 02:24:50 +00:00
|
|
|
|
int rate = data[ofs++];
|
|
|
|
|
if (rate == 0xFF) // end of table
|
|
|
|
|
{
|
|
|
|
|
tableCount--;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int species = data[ofs++];
|
|
|
|
|
int level = data[ofs++];
|
|
|
|
|
|
|
|
|
|
slots.Add(new EncounterSlot1
|
|
|
|
|
{
|
|
|
|
|
Rate = rate,
|
|
|
|
|
Species = species,
|
|
|
|
|
LevelMin = level,
|
|
|
|
|
LevelMax = level,
|
2017-07-06 23:03:41 +00:00
|
|
|
|
Type = slottype
|
2017-03-03 02:24:50 +00:00
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
return slots.ToArray();
|
|
|
|
|
}
|
2017-02-27 05:46:00 +00:00
|
|
|
|
|
2017-06-18 01:37:19 +00:00
|
|
|
|
private static IEnumerable<EncounterArea> GetAreas2(byte[] data, ref int ofs, SlotType t, int slotSets, int slotCount)
|
2017-02-27 02:23:29 +00:00
|
|
|
|
{
|
|
|
|
|
var areas = new List<EncounterArea>();
|
|
|
|
|
while (data[ofs] != 0xFF) // end
|
|
|
|
|
{
|
2017-11-26 02:16:50 +00:00
|
|
|
|
var location = data[ofs++] << 8 | data[ofs++];
|
|
|
|
|
var slots = GetSlots2_GW(data, ref ofs, t, slotSets, slotCount);
|
|
|
|
|
var area = new EncounterArea
|
2017-02-27 02:23:29 +00:00
|
|
|
|
{
|
2017-11-26 02:16:50 +00:00
|
|
|
|
Location = location,
|
|
|
|
|
Slots = slots,
|
|
|
|
|
};
|
|
|
|
|
foreach (var slot in slots)
|
|
|
|
|
slot.Area = area;
|
|
|
|
|
areas.Add(area);
|
2017-02-27 02:23:29 +00:00
|
|
|
|
}
|
2017-03-08 07:13:46 +00:00
|
|
|
|
ofs++;
|
2017-02-27 02:23:29 +00:00
|
|
|
|
return areas;
|
|
|
|
|
}
|
2017-06-18 01:37:19 +00:00
|
|
|
|
private static List<EncounterArea> GetAreas2_F(byte[] data, ref int ofs)
|
2017-02-27 05:46:00 +00:00
|
|
|
|
{
|
|
|
|
|
var areas = new List<EncounterArea>();
|
|
|
|
|
var types = new[] {SlotType.Old_Rod, SlotType.Good_Rod, SlotType.Super_Rod};
|
2017-06-12 23:54:39 +00:00
|
|
|
|
while (ofs != 0x18C)
|
2017-02-27 05:46:00 +00:00
|
|
|
|
{
|
2017-06-12 23:54:39 +00:00
|
|
|
|
areas.Add(new EncounterArea {
|
2017-06-18 01:37:19 +00:00
|
|
|
|
Slots = GetSlots2_F(data, ref ofs, types[0])
|
|
|
|
|
.Concat(GetSlots2_F(data, ref ofs, types[1]))
|
|
|
|
|
.Concat(GetSlots2_F(data, ref ofs, types[2])).ToArray() });
|
2017-02-27 05:46:00 +00:00
|
|
|
|
}
|
2017-06-12 23:54:39 +00:00
|
|
|
|
|
2017-02-27 05:46:00 +00:00
|
|
|
|
// Read TimeFishGroups
|
|
|
|
|
var dl = new List<DexLevel>();
|
2017-06-12 23:54:39 +00:00
|
|
|
|
while (ofs < data.Length)
|
2017-02-27 05:46:00 +00:00
|
|
|
|
dl.Add(new DexLevel {Species = data[ofs++], Level = data[ofs++]});
|
|
|
|
|
|
|
|
|
|
// Add TimeSlots
|
|
|
|
|
foreach (var area in areas)
|
|
|
|
|
{
|
|
|
|
|
var slots = area.Slots;
|
|
|
|
|
for (int i = 0; i < slots.Length; i++)
|
|
|
|
|
{
|
|
|
|
|
var slot = slots[i];
|
|
|
|
|
if (slot.Type != SlotType.Special)
|
|
|
|
|
continue;
|
|
|
|
|
Array.Resize(ref slots, slots.Length + 1);
|
2017-06-12 23:54:39 +00:00
|
|
|
|
Array.Copy(slots, i, slots, i+1, slots.Length - i - 1); // shift slots down
|
2017-02-27 05:46:00 +00:00
|
|
|
|
slots[i+1] = slot.Clone(); // differentiate copied slot
|
|
|
|
|
|
|
|
|
|
int index = slot.LevelMin*2;
|
|
|
|
|
for (int j = 0; j < 2; j++) // load special slot info
|
|
|
|
|
{
|
2017-12-12 00:01:24 +00:00
|
|
|
|
var s = (EncounterSlot1)slots[i + j];
|
2017-02-27 05:46:00 +00:00
|
|
|
|
s.Species = dl[index + j].Species;
|
2017-06-16 05:21:02 +00:00
|
|
|
|
s.LevelMin = s.LevelMax = dl[index + j].Level;
|
|
|
|
|
s.Type = slots[i - 1].Type; // special slots are never first in a set, so copy previous type
|
2017-07-06 23:03:41 +00:00
|
|
|
|
s.Time = j == 0 ? EncounterTime.MorningDay : EncounterTime.Night;
|
2017-02-27 05:46:00 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2017-06-16 05:21:02 +00:00
|
|
|
|
area.Slots = slots;
|
2017-02-27 05:46:00 +00:00
|
|
|
|
}
|
|
|
|
|
return areas;
|
|
|
|
|
}
|
2017-06-18 01:37:19 +00:00
|
|
|
|
private static IEnumerable<EncounterArea> GetAreas2_H(byte[] data, ref int ofs)
|
2017-03-03 02:24:50 +00:00
|
|
|
|
{
|
|
|
|
|
// Read Location Table
|
|
|
|
|
var head = new List<EncounterArea>();
|
|
|
|
|
var headID = new List<int>();
|
|
|
|
|
while (data[ofs] != 0xFF)
|
|
|
|
|
{
|
|
|
|
|
head.Add(new EncounterArea
|
|
|
|
|
{
|
|
|
|
|
Location = (data[ofs++] << 8) | data[ofs++],
|
|
|
|
|
Slots = null, // later
|
|
|
|
|
});
|
|
|
|
|
headID.Add(data[ofs++]);
|
|
|
|
|
}
|
|
|
|
|
ofs++;
|
|
|
|
|
|
|
|
|
|
var rock = new List<EncounterArea>();
|
|
|
|
|
var rockID = new List<int>();
|
|
|
|
|
while (data[ofs] != 0xFF)
|
|
|
|
|
{
|
|
|
|
|
rock.Add(new EncounterArea
|
|
|
|
|
{
|
|
|
|
|
Location = (data[ofs++] << 8) | data[ofs++],
|
|
|
|
|
Slots = null, // later
|
|
|
|
|
});
|
|
|
|
|
rockID.Add(data[ofs++]);
|
|
|
|
|
}
|
|
|
|
|
ofs++;
|
|
|
|
|
ofs += 0x16; // jump over GetTreeMons
|
|
|
|
|
|
|
|
|
|
// Read ptr table
|
|
|
|
|
int[] ptr = new int[data.Length == 0x109 ? 6 : 9]; // GS : C
|
|
|
|
|
for (int i = 0; i < ptr.Length; i++)
|
|
|
|
|
ptr[i] = data[ofs++] | (data[ofs++] << 8);
|
|
|
|
|
|
|
|
|
|
int baseOffset = ptr.Min() - ofs;
|
|
|
|
|
|
|
|
|
|
// Read Tables
|
|
|
|
|
for (int i = 0; i < head.Count; i++)
|
|
|
|
|
{
|
|
|
|
|
int o = ptr[headID[i]] - baseOffset;
|
2017-06-18 01:37:19 +00:00
|
|
|
|
head[i].Slots = GetSlots2_H(data, ref o, SlotType.Headbutt);
|
2017-03-03 02:24:50 +00:00
|
|
|
|
}
|
|
|
|
|
for (int i = 0; i < rock.Count; i++)
|
|
|
|
|
{
|
|
|
|
|
int o = ptr[rockID[i]] - baseOffset;
|
2017-06-18 01:37:19 +00:00
|
|
|
|
rock[i].Slots = GetSlots2_H(data, ref o, SlotType.Rock_Smash);
|
2017-03-03 02:24:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return head.Concat(rock);
|
|
|
|
|
}
|
2017-02-12 17:52:26 +00:00
|
|
|
|
|
2017-06-18 01:37:19 +00:00
|
|
|
|
private static IEnumerable<EncounterSlot> GetSlots3(byte[] data, ref int ofs, int numslots, SlotType t)
|
2017-03-19 12:19:45 +00:00
|
|
|
|
{
|
|
|
|
|
var slots = new List<EncounterSlot>();
|
|
|
|
|
int Ratio = data[ofs];
|
|
|
|
|
//1 byte padding
|
|
|
|
|
if (Ratio > 0)
|
|
|
|
|
{
|
|
|
|
|
for (int i = 0; i < numslots; i++)
|
|
|
|
|
{
|
2017-03-19 19:44:59 +00:00
|
|
|
|
int Species = BitConverter.ToInt16(data, ofs + 4 + i * 4);
|
2017-03-19 19:27:58 +00:00
|
|
|
|
if (Species <= 0)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
slots.Add(new EncounterSlot
|
|
|
|
|
{
|
|
|
|
|
LevelMin = data[ofs + 2 + i * 4],
|
|
|
|
|
LevelMax = data[ofs + 3 + i * 4],
|
|
|
|
|
Species = Species,
|
|
|
|
|
SlotNumber = i,
|
|
|
|
|
Type = t
|
|
|
|
|
});
|
2017-03-19 12:19:45 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
ofs += 2 + numslots * 4;
|
|
|
|
|
return slots;
|
|
|
|
|
}
|
2017-06-18 01:37:19 +00:00
|
|
|
|
private static IEnumerable<EncounterSlot> GetSlots3_F(byte[] data, ref int ofs, int numslots)
|
2017-03-19 12:19:45 +00:00
|
|
|
|
{
|
|
|
|
|
var slots = new List<EncounterSlot>();
|
|
|
|
|
int Ratio = data[ofs];
|
|
|
|
|
//1 byte padding
|
|
|
|
|
if (Ratio > 0)
|
|
|
|
|
{
|
|
|
|
|
for (int i = 0; i < numslots; i++)
|
|
|
|
|
{
|
2017-03-19 19:44:59 +00:00
|
|
|
|
int Species = BitConverter.ToInt16(data, ofs + 4 + i * 4);
|
2017-03-19 19:27:58 +00:00
|
|
|
|
if (Species <= 0)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
var slot = new EncounterSlot
|
|
|
|
|
{
|
|
|
|
|
LevelMin = data[ofs + 2 + i*4],
|
|
|
|
|
LevelMax = data[ofs + 3 + i*4],
|
|
|
|
|
Species = Species,
|
|
|
|
|
};
|
|
|
|
|
if (i < 2)
|
|
|
|
|
{
|
|
|
|
|
slot.Type = SlotType.Old_Rod;
|
|
|
|
|
slot.SlotNumber = i; // 0,1
|
|
|
|
|
}
|
|
|
|
|
else if (i < 5)
|
|
|
|
|
{
|
|
|
|
|
slot.Type = SlotType.Good_Rod;
|
|
|
|
|
slot.SlotNumber = i - 2; // 0,1,2
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
slot.Type = SlotType.Super_Rod;
|
|
|
|
|
slot.SlotNumber = i - 5; // 0,1,2,3,4
|
|
|
|
|
}
|
|
|
|
|
slots.Add(slot);
|
2017-03-19 12:19:45 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
ofs += 2 + numslots * 4;
|
|
|
|
|
return slots;
|
|
|
|
|
}
|
|
|
|
|
|
2017-06-18 01:37:19 +00:00
|
|
|
|
private static EncounterSlot[] GetSlots4_DPPt_G(byte[] data, int ofs, int numslots, SlotType t)
|
2017-03-19 12:19:45 +00:00
|
|
|
|
{
|
|
|
|
|
var slots = new EncounterSlot[numslots];
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < numslots; i++)
|
|
|
|
|
{
|
2017-03-26 05:23:36 +00:00
|
|
|
|
int level = data[ofs + i*8];
|
|
|
|
|
int species = BitConverter.ToInt32(data, ofs + i*8 + 4);
|
2017-03-19 17:44:46 +00:00
|
|
|
|
slots[i] = new EncounterSlot
|
2017-03-19 12:19:45 +00:00
|
|
|
|
{
|
|
|
|
|
LevelMax = level,
|
|
|
|
|
LevelMin = level,
|
|
|
|
|
Species = species,
|
2017-03-19 19:27:58 +00:00
|
|
|
|
SlotNumber = i,
|
2017-03-19 14:10:28 +00:00
|
|
|
|
Type = t
|
2017-03-19 12:19:45 +00:00
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
return slots;
|
|
|
|
|
}
|
2017-06-18 01:37:19 +00:00
|
|
|
|
private static EncounterSlot[] GetSlots4_HGSS_G(byte[] data, int ofs, int numslots, SlotType t)
|
2017-03-19 12:19:45 +00:00
|
|
|
|
{
|
|
|
|
|
var slots = new EncounterSlot[numslots * 3];
|
|
|
|
|
// First 36 slots are morning, day and night grass slots
|
|
|
|
|
// The order is 12 level values, 12 morning species, 12 day species and 12 night species
|
|
|
|
|
for (int i = 0; i < numslots; i++)
|
|
|
|
|
{
|
|
|
|
|
int level = data[ofs + i];
|
2017-05-28 04:17:53 +00:00
|
|
|
|
int species = BitConverter.ToUInt16(data, ofs + numslots + i * 2);
|
2017-03-19 17:44:46 +00:00
|
|
|
|
slots[i] = new EncounterSlot
|
2017-03-19 12:19:45 +00:00
|
|
|
|
{
|
|
|
|
|
LevelMin = level,
|
|
|
|
|
LevelMax = level,
|
|
|
|
|
Species = species,
|
2017-03-19 19:27:58 +00:00
|
|
|
|
SlotNumber = i,
|
2017-03-19 14:10:28 +00:00
|
|
|
|
Type = t
|
2017-03-19 12:19:45 +00:00
|
|
|
|
};
|
|
|
|
|
slots[numslots + i] = slots[i].Clone();
|
2017-03-19 17:44:46 +00:00
|
|
|
|
slots[numslots + i].Species = BitConverter.ToUInt16(data, ofs + numslots * 3 + i * 2);
|
2017-03-19 14:10:28 +00:00
|
|
|
|
slots[numslots + i].Type = t;
|
2017-03-19 12:19:45 +00:00
|
|
|
|
slots[numslots * 2 + i] = slots[i].Clone();
|
2017-03-19 17:44:46 +00:00
|
|
|
|
slots[numslots * 2 + i].Species = BitConverter.ToUInt16(data, ofs + numslots * 5 + i * 2);
|
2017-03-19 14:10:28 +00:00
|
|
|
|
slots[numslots * 2 + i].Type = t;
|
2017-03-19 12:19:45 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return slots;
|
|
|
|
|
}
|
2017-12-03 20:20:49 +00:00
|
|
|
|
private static List<EncounterSlot> GetSlots4_G_Replace(byte[] data, int ofs, int slotSize, EncounterSlot[] ReplacedSlots, int[] slotnums, SlotType t = SlotType.Grass)
|
2017-03-19 12:19:45 +00:00
|
|
|
|
{
|
2017-03-20 14:49:05 +00:00
|
|
|
|
//Special slots like GBA Dual Slot. Those slot only contain the info of species id, the level is copied from one of the first grass slots
|
2017-03-26 11:14:00 +00:00
|
|
|
|
//for dppt slotSize = 4, for hgss slotSize = 2
|
2017-03-19 12:19:45 +00:00
|
|
|
|
var slots = new List<EncounterSlot>();
|
|
|
|
|
|
2017-03-19 19:27:58 +00:00
|
|
|
|
int numslots = slotnums.Length;
|
2017-03-19 12:19:45 +00:00
|
|
|
|
for (int i = 0; i < numslots; i++)
|
|
|
|
|
{
|
2017-03-19 19:27:58 +00:00
|
|
|
|
var baseSlot = ReplacedSlots[slotnums[i]];
|
|
|
|
|
if (baseSlot.LevelMin <= 0)
|
|
|
|
|
continue;
|
2017-03-19 12:19:45 +00:00
|
|
|
|
|
2017-03-26 11:14:00 +00:00
|
|
|
|
int species = BitConverter.ToUInt16(data, ofs + i / (4 / slotSize) * slotSize);
|
2017-04-07 04:18:02 +00:00
|
|
|
|
if (species <= 0 || baseSlot.Species == species) // Empty or duplicate
|
2017-03-19 19:27:58 +00:00
|
|
|
|
continue;
|
2017-03-19 13:38:30 +00:00
|
|
|
|
|
2017-03-19 19:27:58 +00:00
|
|
|
|
var slot = baseSlot.Clone();
|
|
|
|
|
slot.Species = species;
|
|
|
|
|
slot.Type = t;
|
2017-11-30 07:20:49 +00:00
|
|
|
|
slot.SlotNumber = i;
|
2017-03-19 19:27:58 +00:00
|
|
|
|
slots.Add(slot);
|
2017-03-19 13:38:30 +00:00
|
|
|
|
}
|
|
|
|
|
return slots;
|
|
|
|
|
}
|
2017-06-18 01:37:19 +00:00
|
|
|
|
private static IEnumerable<EncounterSlot> GetSlots4DPPt_WFR(byte[] data, int ofs, int numslots, SlotType t)
|
2017-03-19 12:19:45 +00:00
|
|
|
|
{
|
|
|
|
|
var slots = new List<EncounterSlot>();
|
|
|
|
|
for (int i = 0; i < numslots; i++)
|
|
|
|
|
{
|
2017-03-30 00:43:17 +00:00
|
|
|
|
// max, min, unused, unused, [32bit species]
|
2017-03-19 19:27:58 +00:00
|
|
|
|
int Species = BitConverter.ToInt32(data, ofs + 4 + i * 8);
|
|
|
|
|
if (Species <= 0)
|
|
|
|
|
continue;
|
2017-03-20 14:49:05 +00:00
|
|
|
|
// fishing and surf slots with species = 0 are not added
|
|
|
|
|
// DPPt does not have fishing or surf swarms
|
2017-03-19 19:27:58 +00:00
|
|
|
|
slots.Add(new EncounterSlot
|
|
|
|
|
{
|
2017-03-30 00:43:17 +00:00
|
|
|
|
LevelMax = data[ofs + 0 + i * 8],
|
|
|
|
|
LevelMin = data[ofs + 1 + i * 8],
|
2017-03-19 19:27:58 +00:00
|
|
|
|
Species = Species,
|
2017-11-30 07:20:49 +00:00
|
|
|
|
SlotNumber = i,
|
2017-03-19 19:27:58 +00:00
|
|
|
|
Type = t
|
|
|
|
|
});
|
2017-03-19 12:19:45 +00:00
|
|
|
|
}
|
2017-12-03 20:20:49 +00:00
|
|
|
|
EncounterUtil.MarkEncountersStaticMagnetPull(slots, PersonalTable.HGSS);
|
2017-03-19 12:19:45 +00:00
|
|
|
|
return slots;
|
|
|
|
|
}
|
2017-06-18 01:37:19 +00:00
|
|
|
|
private static IEnumerable<EncounterSlot> GetSlots4HGSS_WFR(byte[] data, int ofs, int numslots, SlotType t)
|
2017-03-19 13:38:30 +00:00
|
|
|
|
{
|
|
|
|
|
var slots = new List<EncounterSlot>();
|
|
|
|
|
for (int i = 0; i < numslots; i++)
|
|
|
|
|
{
|
2017-03-19 19:27:58 +00:00
|
|
|
|
// min, max, [16bit species]
|
|
|
|
|
int Species = BitConverter.ToInt16(data, ofs + 2 + i * 4);
|
2017-03-20 14:49:05 +00:00
|
|
|
|
if (t == SlotType.Rock_Smash && Species <= 0)
|
2017-03-19 19:27:58 +00:00
|
|
|
|
continue;
|
2017-03-20 14:49:05 +00:00
|
|
|
|
// fishing and surf slots with species = 0 are added too, it is needed for the swarm encounters,
|
|
|
|
|
// it will be deleted after add swarm slots
|
2017-03-19 13:38:30 +00:00
|
|
|
|
|
2017-03-19 19:27:58 +00:00
|
|
|
|
slots.Add(new EncounterSlot
|
|
|
|
|
{
|
|
|
|
|
LevelMin = data[ofs + 0 + i * 4],
|
|
|
|
|
LevelMax = data[ofs + 1 + i * 4],
|
|
|
|
|
Species = Species,
|
2017-11-30 07:20:49 +00:00
|
|
|
|
SlotNumber = i,
|
2017-03-19 19:27:58 +00:00
|
|
|
|
Type = t
|
|
|
|
|
});
|
2017-03-19 13:38:30 +00:00
|
|
|
|
}
|
2017-12-03 20:20:49 +00:00
|
|
|
|
EncounterUtil.MarkEncountersStaticMagnetPull(slots, PersonalTable.HGSS);
|
2017-03-19 13:38:30 +00:00
|
|
|
|
return slots;
|
|
|
|
|
}
|
2017-03-19 12:19:45 +00:00
|
|
|
|
|
2017-06-18 01:37:19 +00:00
|
|
|
|
private static EncounterArea GetArea3(byte[] data)
|
2017-03-19 12:19:45 +00:00
|
|
|
|
{
|
2017-03-19 17:44:46 +00:00
|
|
|
|
var HaveGrassSlots = data[1] == 1;
|
|
|
|
|
var HaveSurfSlots = data[2] == 1;
|
|
|
|
|
var HaveRockSmashSlots = data[3] == 1;
|
|
|
|
|
var HaveFishingSlots = data[4] == 1;
|
2017-03-19 12:19:45 +00:00
|
|
|
|
|
|
|
|
|
int offset = 5;
|
|
|
|
|
var slots = new List<EncounterSlot>();
|
|
|
|
|
if (HaveGrassSlots)
|
2017-06-18 01:37:19 +00:00
|
|
|
|
slots.AddRange(GetSlots3(data, ref offset, 12, SlotType.Grass));
|
2017-03-19 12:19:45 +00:00
|
|
|
|
if (HaveSurfSlots)
|
2017-06-18 01:37:19 +00:00
|
|
|
|
slots.AddRange(GetSlots3(data, ref offset, 5, SlotType.Surf));
|
2017-03-19 12:19:45 +00:00
|
|
|
|
if (HaveRockSmashSlots)
|
2017-06-18 01:37:19 +00:00
|
|
|
|
slots.AddRange(GetSlots3(data, ref offset, 5, SlotType.Rock_Smash));
|
2017-03-19 12:19:45 +00:00
|
|
|
|
if (HaveFishingSlots)
|
2017-06-18 01:37:19 +00:00
|
|
|
|
slots.AddRange(GetSlots3_F(data, ref offset, 10));
|
2017-11-26 02:16:50 +00:00
|
|
|
|
|
|
|
|
|
EncounterArea Area3 = new EncounterArea
|
|
|
|
|
{
|
|
|
|
|
Location = data[0],
|
|
|
|
|
Slots = slots.ToArray()
|
|
|
|
|
};
|
|
|
|
|
foreach (var slot in Area3.Slots)
|
|
|
|
|
slot.Area = Area3;
|
|
|
|
|
|
2017-03-19 12:19:45 +00:00
|
|
|
|
return Area3;
|
|
|
|
|
}
|
|
|
|
|
|
2017-12-03 20:20:49 +00:00
|
|
|
|
private static EncounterArea GetArea4DPPt(byte[] data, bool pt = false)
|
2017-03-19 12:19:45 +00:00
|
|
|
|
{
|
|
|
|
|
var Slots = new List<EncounterSlot>();
|
|
|
|
|
|
2017-12-03 20:20:49 +00:00
|
|
|
|
int location = BitConverter.ToUInt16(data, 0x00);
|
2017-04-07 04:18:02 +00:00
|
|
|
|
var GrassRatio = BitConverter.ToInt32(data, 0x02);
|
2017-03-19 12:19:45 +00:00
|
|
|
|
if (GrassRatio > 0)
|
|
|
|
|
{
|
2017-06-18 01:37:19 +00:00
|
|
|
|
EncounterSlot[] GrassSlots = GetSlots4_DPPt_G(data, 0x06, 12, SlotType.Grass);
|
2017-04-07 04:18:02 +00:00
|
|
|
|
//Swarming slots replace slots 0 and 1
|
2017-12-03 20:20:49 +00:00
|
|
|
|
var swarm = GetSlots4_G_Replace(data, 0x66, 4, GrassSlots, Legal.Slot4_Swarm, SlotType.Swarm);
|
2017-04-07 04:18:02 +00:00
|
|
|
|
//Morning and Night slots replace slots 2 and 3
|
2017-12-03 20:20:49 +00:00
|
|
|
|
var morning = GetSlots4_G_Replace(data, 0x6E, 4, GrassSlots, Legal.Slot4_Time); // Morning
|
|
|
|
|
var night = GetSlots4_G_Replace(data, 0x76, 4, GrassSlots, Legal.Slot4_Time); // Night
|
2017-04-07 04:18:02 +00:00
|
|
|
|
//Pokéradar slots replace slots 4,5,10 and 11
|
2017-03-20 14:49:05 +00:00
|
|
|
|
//Pokéradar is marked with different slot type because it have different PID-IV generationn
|
2017-12-03 20:20:49 +00:00
|
|
|
|
var radar = GetSlots4_G_Replace(data, 0x7E, 4, GrassSlots, Legal.Slot4_Radar, SlotType.Pokeradar);
|
|
|
|
|
|
2017-04-07 04:18:02 +00:00
|
|
|
|
//24 bytes padding
|
2017-12-03 20:20:49 +00:00
|
|
|
|
|
2017-03-19 12:19:45 +00:00
|
|
|
|
//Dual Slots replace slots 8 and 9
|
2017-12-03 20:20:49 +00:00
|
|
|
|
var ruby = GetSlots4_G_Replace(data, 0xA6, 4, GrassSlots, Legal.Slot4_Dual); // Ruby
|
|
|
|
|
var sapphire = GetSlots4_G_Replace(data, 0xAE, 4, GrassSlots, Legal.Slot4_Dual); // Sapphire
|
|
|
|
|
var emerald = GetSlots4_G_Replace(data, 0xB6, 4, GrassSlots, Legal.Slot4_Dual); // Emerald
|
|
|
|
|
var firered = GetSlots4_G_Replace(data, 0xBE, 4, GrassSlots, Legal.Slot4_Dual); // FireRed
|
|
|
|
|
var leafgreen = GetSlots4_G_Replace(data, 0xC6, 4, GrassSlots, Legal.Slot4_Dual); // LeafGreen
|
|
|
|
|
|
|
|
|
|
Slots.AddRange(GrassSlots);
|
|
|
|
|
Slots.AddRange(swarm);
|
|
|
|
|
Slots.AddRange(morning);
|
|
|
|
|
Slots.AddRange(night);
|
|
|
|
|
Slots.AddRange(radar);
|
|
|
|
|
Slots.AddRange(ruby);
|
|
|
|
|
Slots.AddRange(sapphire);
|
|
|
|
|
Slots.AddRange(emerald);
|
|
|
|
|
Slots.AddRange(firered);
|
|
|
|
|
Slots.AddRange(leafgreen);
|
|
|
|
|
|
|
|
|
|
// Permute Static-Magnet Pull combinations
|
|
|
|
|
// [None/Swarm]-[None/Morning/Night]-[None/Radar]-[None/R/S/E/F/L] [None/TrophyGarden]
|
|
|
|
|
// 2 * 3 * 2 * 6 = 72 different combinations of slots (more with trophy garden)
|
|
|
|
|
var regular = new List<List<EncounterSlot>> {GrassSlots.Where(z => z.SlotNumber == 6 || z.SlotNumber == 7).ToList()}; // every other slot is in the product
|
|
|
|
|
var pair0 = new List<List<EncounterSlot>> {GrassSlots.Where(z => Legal.Slot4_Swarm.Contains(z.SlotNumber)).ToList()};
|
|
|
|
|
var pair1 = new List<List<EncounterSlot>> {GrassSlots.Where(z => Legal.Slot4_Time.Contains(z.SlotNumber)).ToList()};
|
|
|
|
|
var pair2 = new List<List<EncounterSlot>> {GrassSlots.Where(z => Legal.Slot4_Radar.Contains(z.SlotNumber)).ToList()};
|
|
|
|
|
var pair3 = new List<List<EncounterSlot>> {GrassSlots.Where(z => Legal.Slot4_Dual.Contains(z.SlotNumber)).ToList()};
|
|
|
|
|
if (swarm.Count != 0) pair0.Add(swarm);
|
|
|
|
|
if (morning.Count != 0) pair1.Add(morning); if (night.Count != 0) pair1.Add(night);
|
|
|
|
|
if (radar.Count != 0) pair2.Add(radar);
|
|
|
|
|
if (ruby.Count != 0) pair3.Add(ruby); if (sapphire.Count != 0) pair3.Add(sapphire); if (emerald.Count != 0) pair3.Add(emerald);
|
|
|
|
|
if (firered.Count != 0) pair3.Add(firered); if (leafgreen.Count != 0) pair3.Add(leafgreen);
|
|
|
|
|
if (location == 68) // Trophy Garden
|
|
|
|
|
{
|
|
|
|
|
// Occupy Slots 6 & 7
|
|
|
|
|
var species = pt ? Encounters4.TrophyPt : Encounters4.TrophyDP;
|
|
|
|
|
var slots = new List<EncounterSlot>();
|
|
|
|
|
foreach (var s in species)
|
|
|
|
|
{
|
|
|
|
|
var slot = regular[0][0].Clone();
|
|
|
|
|
slot.Species = s;
|
|
|
|
|
slots.Add(slot);
|
|
|
|
|
|
|
|
|
|
slot = regular[0][1].Clone();
|
|
|
|
|
slot.Species = s;
|
|
|
|
|
slots.Add(slot);
|
|
|
|
|
}
|
|
|
|
|
Slots.AddRange(slots);
|
|
|
|
|
// get all permutations of trophy inhabitants
|
|
|
|
|
var trophy = regular[0].Concat(slots).ToArray();
|
|
|
|
|
for (int i = 0; i < trophy.Length; i++)
|
|
|
|
|
for (int j = i + 1; j < trophy.Length; j++)
|
|
|
|
|
regular.Add(new List<EncounterSlot>{trophy[i], trophy[j]});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var set = new[] { regular, pair0, pair1, pair2, pair3 };
|
|
|
|
|
var product = set.CartesianProduct();
|
|
|
|
|
var extra = MarkStaticMagnetExtras(product);
|
|
|
|
|
Slots.AddRange(extra);
|
2017-03-19 12:19:45 +00:00
|
|
|
|
}
|
|
|
|
|
|
2017-04-07 04:18:02 +00:00
|
|
|
|
var SurfRatio = BitConverter.ToInt32(data, 0xCE);
|
2017-03-19 12:19:45 +00:00
|
|
|
|
if (SurfRatio > 0)
|
2017-06-18 01:37:19 +00:00
|
|
|
|
Slots.AddRange(GetSlots4DPPt_WFR(data, 0xD2, 5, SlotType.Surf));
|
2017-04-07 04:18:02 +00:00
|
|
|
|
|
|
|
|
|
//44 bytes padding
|
2017-03-19 12:19:45 +00:00
|
|
|
|
|
2017-04-07 04:18:02 +00:00
|
|
|
|
var OldRodRatio = BitConverter.ToInt32(data, 0x126);
|
2017-03-19 12:19:45 +00:00
|
|
|
|
if (OldRodRatio > 0)
|
2017-06-18 01:37:19 +00:00
|
|
|
|
Slots.AddRange(GetSlots4DPPt_WFR(data, 0x12A, 5, SlotType.Old_Rod));
|
2017-03-19 12:19:45 +00:00
|
|
|
|
|
2017-04-07 04:18:02 +00:00
|
|
|
|
var GoodRodRatio = BitConverter.ToInt32(data, 0x152);
|
2017-03-19 12:19:45 +00:00
|
|
|
|
if (GoodRodRatio > 0)
|
2017-06-18 01:37:19 +00:00
|
|
|
|
Slots.AddRange(GetSlots4DPPt_WFR(data, 0x156, 5, SlotType.Good_Rod));
|
2017-03-19 12:19:45 +00:00
|
|
|
|
|
2017-04-07 04:18:02 +00:00
|
|
|
|
var SuperRodRatio = BitConverter.ToInt32(data, 0x17E);
|
2017-03-19 12:19:45 +00:00
|
|
|
|
if (SuperRodRatio > 0)
|
2017-06-18 01:37:19 +00:00
|
|
|
|
Slots.AddRange(GetSlots4DPPt_WFR(data, 0x182, 5, SlotType.Super_Rod));
|
2017-03-19 12:19:45 +00:00
|
|
|
|
|
2017-11-26 02:16:50 +00:00
|
|
|
|
EncounterArea Area4 = new EncounterArea
|
|
|
|
|
{
|
2017-12-03 20:20:49 +00:00
|
|
|
|
Location = location,
|
2017-11-26 02:16:50 +00:00
|
|
|
|
Slots = Slots.ToArray()
|
|
|
|
|
};
|
|
|
|
|
foreach (var slot in Area4.Slots)
|
|
|
|
|
slot.Area = Area4;
|
|
|
|
|
|
2017-03-19 12:19:45 +00:00
|
|
|
|
return Area4;
|
|
|
|
|
}
|
2017-12-03 20:20:49 +00:00
|
|
|
|
private static IEnumerable<EncounterSlot> MarkStaticMagnetExtras(IEnumerable<IEnumerable<List<EncounterSlot>>> product)
|
|
|
|
|
{
|
|
|
|
|
var trackPermute = new List<EncounterSlot>();
|
|
|
|
|
foreach (var p in product)
|
|
|
|
|
MarkStaticMagnetPermute(p.SelectMany(z => z), trackPermute);
|
|
|
|
|
return trackPermute;
|
|
|
|
|
}
|
|
|
|
|
private static void MarkStaticMagnetPermute(IEnumerable<EncounterSlot> grp, List<EncounterSlot> trackPermute)
|
|
|
|
|
{
|
|
|
|
|
EncounterUtil.MarkEncountersStaticMagnetPullPermutation(grp, PersonalTable.HGSS, trackPermute);
|
|
|
|
|
}
|
2017-03-19 12:19:45 +00:00
|
|
|
|
|
2017-06-18 01:37:19 +00:00
|
|
|
|
private static EncounterArea GetArea4HGSS(byte[] data)
|
2017-03-19 12:19:45 +00:00
|
|
|
|
{
|
|
|
|
|
var Slots = new List<EncounterSlot>();
|
2017-04-07 04:18:02 +00:00
|
|
|
|
|
|
|
|
|
var GrassRatio = data[0x02];
|
|
|
|
|
var SurfRatio = data[0x03];
|
|
|
|
|
var RockSmashRatio = data[0x04];
|
|
|
|
|
var OldRodRatio = data[0x05];
|
|
|
|
|
var GoodRodRatio = data[0x06];
|
|
|
|
|
var SuperRodRatio = data[0x07];
|
2017-03-19 12:19:45 +00:00
|
|
|
|
// 2 bytes padding
|
|
|
|
|
|
|
|
|
|
if (GrassRatio > 0)
|
|
|
|
|
{
|
|
|
|
|
// First 36 slots are morning, day and night grass slots
|
|
|
|
|
// The order is 12 level values, 12 morning species, 12 day species and 12 night species
|
2017-06-18 01:37:19 +00:00
|
|
|
|
var GrassSlots = GetSlots4_HGSS_G(data, 0x0A, 12, SlotType.Grass);
|
2017-12-03 20:20:49 +00:00
|
|
|
|
//Grass slots with species = 0 are added too, it is needed for the swarm encounters, it will be deleted after swarms are added
|
2017-03-19 19:27:58 +00:00
|
|
|
|
|
|
|
|
|
// Hoenn Sound and Sinnoh Sound replace slots 4 and 5
|
2017-12-03 20:20:49 +00:00
|
|
|
|
var hoenn = GetSlots4_G_Replace(data, 0x5E, 2, GrassSlots, Legal.Slot4_Sound); // Hoenn
|
|
|
|
|
var sinnoh = GetSlots4_G_Replace(data, 0x62, 2, GrassSlots, Legal.Slot4_Sound); // Sinnoh
|
|
|
|
|
|
|
|
|
|
Slots.AddRange(GrassSlots);
|
|
|
|
|
Slots.AddRange(hoenn);
|
|
|
|
|
Slots.AddRange(sinnoh);
|
|
|
|
|
|
|
|
|
|
// Static / Magnet Pull
|
|
|
|
|
var grass1 = GrassSlots.Take(12).ToList();
|
|
|
|
|
var grass2 = GrassSlots.Skip(12).Take(12).ToList();
|
|
|
|
|
var grass3 = GrassSlots.Skip(24).ToList();
|
|
|
|
|
// Swarm slots do not displace electric/steel types, with exception of SoulSilver Mawile (which doesn't displace) -- handle separately
|
|
|
|
|
|
|
|
|
|
foreach (var time in new[] {grass1, grass2, grass3})
|
|
|
|
|
{
|
|
|
|
|
// non radio
|
|
|
|
|
var regular = time.Where(z => !Legal.Slot4_Sound.Contains(z.SlotNumber)).ToList(); // every other slot is in the product
|
|
|
|
|
var radio = new List<List<EncounterSlot>> {time.Where(z => Legal.Slot4_Sound.Contains(z.SlotNumber)).ToList()};
|
|
|
|
|
if (hoenn.Count > 0) radio.Add(hoenn); if (sinnoh.Count > 0) radio.Add(sinnoh);
|
|
|
|
|
|
|
|
|
|
var extra = new List<EncounterSlot>();
|
|
|
|
|
foreach (var t in radio)
|
|
|
|
|
MarkStaticMagnetPermute(regular.Concat(t), extra);
|
|
|
|
|
Slots.AddRange(extra);
|
|
|
|
|
}
|
2017-03-19 12:19:45 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (SurfRatio > 0)
|
2017-06-18 01:37:19 +00:00
|
|
|
|
Slots.AddRange(GetSlots4HGSS_WFR(data, 0x66, 5, SlotType.Surf));
|
2017-03-19 12:19:45 +00:00
|
|
|
|
|
|
|
|
|
if (RockSmashRatio > 0)
|
2017-06-18 01:37:19 +00:00
|
|
|
|
Slots.AddRange(GetSlots4HGSS_WFR(data, 0x7A, 2, SlotType.Rock_Smash));
|
2017-03-19 12:19:45 +00:00
|
|
|
|
|
|
|
|
|
if (OldRodRatio > 0)
|
2017-06-18 01:37:19 +00:00
|
|
|
|
Slots.AddRange(GetSlots4HGSS_WFR(data, 0x82, 5, SlotType.Old_Rod));
|
2017-03-19 12:19:45 +00:00
|
|
|
|
|
|
|
|
|
if (GoodRodRatio > 0)
|
2017-06-18 01:37:19 +00:00
|
|
|
|
Slots.AddRange(GetSlots4HGSS_WFR(data, 0x96, 5, SlotType.Good_Rod));
|
2017-03-19 12:19:45 +00:00
|
|
|
|
|
|
|
|
|
if (SuperRodRatio > 0)
|
2017-06-18 01:37:19 +00:00
|
|
|
|
Slots.AddRange(GetSlots4HGSS_WFR(data, 0xAA, 5, SlotType.Super_Rod));
|
2017-03-19 13:38:30 +00:00
|
|
|
|
|
2017-04-07 04:18:02 +00:00
|
|
|
|
// Last 6 bytes only have species ID info
|
|
|
|
|
if (data[0xC2] == 120) // Location = 182, 127, 130, 132, 167, 188, 210
|
2017-04-04 03:02:40 +00:00
|
|
|
|
Slots.AddRange(SlotsHGSS_Staryu);
|
|
|
|
|
|
2017-11-26 02:16:50 +00:00
|
|
|
|
EncounterArea Area4 = new EncounterArea
|
|
|
|
|
{
|
|
|
|
|
Location = BitConverter.ToUInt16(data, 0x00),
|
|
|
|
|
Slots = Slots.ToArray()
|
|
|
|
|
};
|
|
|
|
|
foreach (var slot in Area4.Slots)
|
|
|
|
|
slot.Area = Area4;
|
2017-03-19 12:19:45 +00:00
|
|
|
|
return Area4;
|
|
|
|
|
}
|
2017-04-04 03:02:40 +00:00
|
|
|
|
private static readonly EncounterSlot[] SlotsHGSS_Staryu =
|
|
|
|
|
{
|
|
|
|
|
new EncounterSlot { Species = 120, LevelMin = 20, LevelMax = 20, Type = SlotType.Good_Rod },
|
|
|
|
|
new EncounterSlot { Species = 120, LevelMin = 40, LevelMax = 40, Type = SlotType.Super_Rod },
|
|
|
|
|
};
|
2017-03-19 12:19:45 +00:00
|
|
|
|
|
2017-06-18 01:37:19 +00:00
|
|
|
|
private static EncounterArea GetArea4HGSS_Headbutt(byte[] data)
|
2017-03-19 15:23:46 +00:00
|
|
|
|
{
|
|
|
|
|
if (data.Length < 78)
|
2017-03-19 19:27:58 +00:00
|
|
|
|
return new EncounterArea(); // bad data
|
|
|
|
|
|
|
|
|
|
//2 byte location ID (defer to end)
|
2017-03-19 15:23:46 +00:00
|
|
|
|
//4 bytes padding
|
|
|
|
|
var Slots = new List<EncounterSlot>();
|
|
|
|
|
|
|
|
|
|
// 00-11 Normal trees
|
|
|
|
|
// 12-17 Special trees
|
|
|
|
|
for (int i = 0; i < 18; i++)
|
|
|
|
|
{
|
2017-03-19 19:27:58 +00:00
|
|
|
|
int Species = BitConverter.ToInt16(data, 6 + i*4);
|
|
|
|
|
if (Species <= 0)
|
|
|
|
|
continue;
|
|
|
|
|
Slots.Add(new EncounterSlot
|
2017-03-19 15:23:46 +00:00
|
|
|
|
{
|
2017-03-19 19:27:58 +00:00
|
|
|
|
Species = Species,
|
|
|
|
|
LevelMin = data[8 + i*4],
|
|
|
|
|
LevelMax = data[9 + i*4],
|
Encounter Type fix and detection of pokemon that should have evolve on trade (#1105)
* Detect encounter trades that evolve on trade and have not been evolved
Detect generation 1 pokemon with special catch rates : krabby trade and Pokemon Stadium
Detect generation 1 pokemon that evolve on trade and have been traded but not evolved
Detect pokemon with tradeback status any but with only encounters from the other GB generation, that means they are WasTradeback
Detect pokemon with moves from the other GB generation, change tradebackstatus to WasTradeback
* Fix dppt surfing and fishing encounter type, is is surfing because the battle background is the same as other surfingfishing encounters
Fix headbutt encounter type, the encounter type depends on the battle background used when battle a pokemon, for headbutt it changes with the player tile, is the player is in a city it will be building encounter, in a grass tile tall grass, in water it is surfingfishing and cave inside a cave. Some locations have more than one possible encounter type, for example routes with trees near the grass, near the water and near non-combat tiles.
Also added slot type headbutt special for the special trees, those trees are all in routes and are only adjacent to non-combat tiles
* Fix encounter type for missing areas with multiple grass encounters types: Mt Coronet, Mt Silver Cave and Stark Mountain (Issue # 1095)
* Fixes and typos
* Check for non-japanese e-reader pokemon, is unreleased
2017-05-01 15:07:20 +00:00
|
|
|
|
Type = i <= 11 ? SlotType.Headbutt : SlotType.Headbutt_Special
|
2017-03-19 19:27:58 +00:00
|
|
|
|
});
|
2017-03-19 15:23:46 +00:00
|
|
|
|
}
|
2017-03-19 19:27:58 +00:00
|
|
|
|
|
2017-11-26 02:16:50 +00:00
|
|
|
|
var Area = new EncounterArea
|
2017-03-19 19:27:58 +00:00
|
|
|
|
{
|
|
|
|
|
Location = BitConverter.ToUInt16(data, 0),
|
|
|
|
|
Slots = Slots.ToArray()
|
|
|
|
|
};
|
2017-11-26 02:16:50 +00:00
|
|
|
|
foreach (var slot in Area.Slots)
|
|
|
|
|
slot.Area = Area;
|
|
|
|
|
return Area;
|
2017-03-19 15:23:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
2017-02-12 17:52:26 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// RBY Format Slot Getter from data.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="data">Byte array containing complete slot data table.</param>
|
|
|
|
|
/// <param name="ofs">Offset to start reading from.</param>
|
|
|
|
|
/// <param name="count">Amount of slots to read.</param>
|
|
|
|
|
/// <param name="t">Type of encounter slot.</param>
|
|
|
|
|
/// <param name="rate">Slot type encounter rate.</param>
|
|
|
|
|
/// <returns>Array of encounter slots.</returns>
|
2017-06-18 01:37:19 +00:00
|
|
|
|
private static EncounterSlot1[] ReadSlots(byte[] data, ref int ofs, int count, SlotType t, int rate)
|
2017-02-12 17:52:26 +00:00
|
|
|
|
{
|
|
|
|
|
EncounterSlot1[] slots = new EncounterSlot1[count];
|
|
|
|
|
for (int i = 0; i < count; i++)
|
|
|
|
|
{
|
|
|
|
|
int lvl = data[ofs++];
|
|
|
|
|
int spec = data[ofs++];
|
|
|
|
|
|
|
|
|
|
slots[i] = new EncounterSlot1
|
|
|
|
|
{
|
2017-06-16 05:42:43 +00:00
|
|
|
|
LevelMax = t == SlotType.Surf ? lvl + 4 : lvl,
|
2017-02-12 17:52:26 +00:00
|
|
|
|
LevelMin = lvl,
|
|
|
|
|
Species = spec,
|
|
|
|
|
Type = t,
|
|
|
|
|
Rate = rate,
|
2017-02-27 02:23:29 +00:00
|
|
|
|
SlotNumber = i,
|
2017-02-12 17:52:26 +00:00
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
return slots;
|
|
|
|
|
}
|
2017-02-27 02:23:29 +00:00
|
|
|
|
|
2017-06-18 01:37:19 +00:00
|
|
|
|
private static EncounterSlot1[] ReadSlots_FY(byte[] data, ref int ofs, int count, SlotType t, int rate)
|
2017-04-10 08:02:40 +00:00
|
|
|
|
{
|
|
|
|
|
// Convert byte to actual number
|
|
|
|
|
int[] Levelbytelist = { 0xFF, 0x15, 0x67, 0x1D, 0x3B, 0x5C, 0x72, 0x16, 0x71, 0x18, 0x00, 0x6D, 0x80, };
|
|
|
|
|
int[] dexbytelist = { 0x47, 0x6E, 0x18, 0x9B, 0x17, 0x4E, 0x8A, 0x5C, 0x5D, 0x9D, 0x9E, 0x1B, 0x85, 0x16, 0x58, 0x59, };
|
|
|
|
|
int[] specieslist = { 060, 061, 072, 073, 090, 098, 099, 116, 117, 118, 119, 120, 129, 130, 147, 148, };
|
|
|
|
|
|
|
|
|
|
EncounterSlot1[] slots = new EncounterSlot1[count];
|
|
|
|
|
for (int i = 0; i < count; i++)
|
|
|
|
|
{
|
|
|
|
|
int spec = specieslist[Array.IndexOf(dexbytelist, data[ofs++])];
|
|
|
|
|
int lvl = Array.IndexOf(Levelbytelist, data[ofs++]) * 5;
|
|
|
|
|
|
|
|
|
|
slots[i] = new EncounterSlot1
|
|
|
|
|
{
|
|
|
|
|
LevelMax = lvl,
|
|
|
|
|
LevelMin = lvl,
|
|
|
|
|
Species = spec,
|
|
|
|
|
Type = t,
|
|
|
|
|
Rate = rate,
|
|
|
|
|
SlotNumber = i,
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
return slots;
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-27 02:23:29 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Gets the encounter areas with <see cref="EncounterSlot"/> information from Generation 1 Grass/Water data.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="data">Input raw data.</param>
|
|
|
|
|
/// <returns>Array of encounter areas.</returns>
|
2017-06-18 01:37:19 +00:00
|
|
|
|
public static EncounterArea[] GetArray1_GW(byte[] data)
|
2017-02-12 17:52:26 +00:00
|
|
|
|
{
|
|
|
|
|
// RBY Format
|
|
|
|
|
var ptr = new int[255];
|
|
|
|
|
int count = 0;
|
|
|
|
|
for (int i = 0; i < ptr.Length; i++)
|
|
|
|
|
{
|
|
|
|
|
ptr[i] = BitConverter.ToInt16(data, i*2);
|
|
|
|
|
if (ptr[i] != -1)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
count = i;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
EncounterArea[] areas = new EncounterArea[count];
|
|
|
|
|
for (int i = 0; i < areas.Length; i++)
|
|
|
|
|
{
|
2017-06-18 01:37:19 +00:00
|
|
|
|
var grass = GetSlots1_GW(data, ref ptr[i], SlotType.Grass);
|
|
|
|
|
var water = GetSlots1_GW(data, ref ptr[i], SlotType.Surf);
|
2017-02-12 17:52:26 +00:00
|
|
|
|
areas[i] = new EncounterArea
|
|
|
|
|
{
|
|
|
|
|
Location = i,
|
|
|
|
|
Slots = grass.Concat(water).ToArray()
|
|
|
|
|
};
|
|
|
|
|
}
|
2017-12-05 04:16:54 +00:00
|
|
|
|
return areas.Where(area => area.Slots.Length != 0).ToArray();
|
2017-02-12 17:52:26 +00:00
|
|
|
|
}
|
2017-02-27 02:23:29 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Gets the encounter areas with <see cref="EncounterSlot"/> information from Pokémon Yellow (Generation 1) Fishing data.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="data">Input raw data.</param>
|
|
|
|
|
/// <returns>Array of encounter areas.</returns>
|
2017-06-18 01:37:19 +00:00
|
|
|
|
public static EncounterArea[] GetArray1_FY(byte[] data)
|
2017-02-12 17:52:26 +00:00
|
|
|
|
{
|
|
|
|
|
const int size = 9;
|
|
|
|
|
int count = data.Length/size;
|
|
|
|
|
EncounterArea[] areas = new EncounterArea[count];
|
|
|
|
|
for (int i = 0; i < count; i++)
|
|
|
|
|
{
|
|
|
|
|
int ofs = i*size + 1;
|
|
|
|
|
areas[i] = new EncounterArea
|
|
|
|
|
{
|
|
|
|
|
Location = data[i*size + 0],
|
2017-06-18 01:37:19 +00:00
|
|
|
|
Slots = ReadSlots_FY(data, ref ofs, 4, SlotType.Super_Rod, -1)
|
2017-02-12 17:52:26 +00:00
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
return areas;
|
|
|
|
|
}
|
2017-02-27 02:23:29 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Gets the encounter areas with <see cref="EncounterSlot"/> information from Generation 1 Fishing data.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="data">Input raw data.</param>
|
|
|
|
|
/// <returns>Array of encounter areas.</returns>
|
2017-06-18 01:37:19 +00:00
|
|
|
|
public static EncounterArea[] GetArray1_F(byte[] data)
|
2017-02-12 17:52:26 +00:00
|
|
|
|
{
|
|
|
|
|
var ptr = new int[255];
|
|
|
|
|
var map = new int[255];
|
|
|
|
|
int count = 0;
|
|
|
|
|
for (int i = 0; i < ptr.Length; i++)
|
|
|
|
|
{
|
|
|
|
|
map[i] = data[i*3 + 0];
|
|
|
|
|
if (map[i] == 0xFF)
|
|
|
|
|
{
|
|
|
|
|
count = i;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
ptr[i] = BitConverter.ToInt16(data, i * 3 + 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
EncounterArea[] areas = new EncounterArea[count];
|
|
|
|
|
for (int i = 0; i < areas.Length; i++)
|
|
|
|
|
{
|
|
|
|
|
areas[i] = new EncounterArea
|
|
|
|
|
{
|
|
|
|
|
Location = map[i],
|
2017-06-18 01:37:19 +00:00
|
|
|
|
Slots = GetSlots1_F(data, ref ptr[i])
|
2017-02-12 17:52:26 +00:00
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
return areas;
|
|
|
|
|
}
|
2017-02-27 02:23:29 +00:00
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Gets the encounter areas with <see cref="EncounterSlot"/> information from Generation 2 Grass/Water data.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="data">Input raw data.</param>
|
|
|
|
|
/// <returns>Array of encounter areas.</returns>
|
2017-06-18 01:37:19 +00:00
|
|
|
|
public static EncounterArea[] GetArray2_GW(byte[] data)
|
2017-02-27 02:23:29 +00:00
|
|
|
|
{
|
|
|
|
|
int ofs = 0;
|
|
|
|
|
var areas = new List<EncounterArea>();
|
2017-06-18 01:37:19 +00:00
|
|
|
|
areas.AddRange(GetAreas2(data, ref ofs, SlotType.Grass, 3, 7)); // Johto Grass
|
|
|
|
|
areas.AddRange(GetAreas2(data, ref ofs, SlotType.Surf, 1, 3)); // Johto Water
|
|
|
|
|
areas.AddRange(GetAreas2(data, ref ofs, SlotType.Grass, 3, 7)); // Kanto Grass
|
|
|
|
|
areas.AddRange(GetAreas2(data, ref ofs, SlotType.Surf, 1, 3)); // Kanto Water
|
|
|
|
|
areas.AddRange(GetAreas2(data, ref ofs, SlotType.Swarm, 3, 7)); // Swarm
|
|
|
|
|
areas.AddRange(GetAreas2(data, ref ofs, SlotType.Special, 1, 3)); // Union Cave
|
2017-02-27 02:23:29 +00:00
|
|
|
|
return areas.ToArray();
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-27 05:46:00 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Gets the encounter areas with <see cref="EncounterSlot"/> information from Generation 2 Grass/Water data.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="data">Input raw data.</param>
|
|
|
|
|
/// <returns>Array of encounter areas.</returns>
|
2017-06-18 01:37:19 +00:00
|
|
|
|
public static EncounterArea[] GetArray2_F(byte[] data)
|
2017-02-27 05:46:00 +00:00
|
|
|
|
{
|
|
|
|
|
int ofs = 0;
|
2017-06-18 01:37:19 +00:00
|
|
|
|
var f = GetAreas2_F(data, ref ofs);
|
2017-06-12 23:54:39 +00:00
|
|
|
|
|
|
|
|
|
// Fishing Tables are not associated to a single map; a map picks a table to use.
|
|
|
|
|
// For all maps that use a table, create a new EncounterArea with reference to the table's slots.
|
|
|
|
|
sbyte[] convMapIDtoFishLocationID =
|
|
|
|
|
{
|
|
|
|
|
-1, 1, -1, 0, 3, 3, 3, -1, 10, 3, 2, -1, -1, 2, 3, 0,
|
|
|
|
|
-1, -1, 3, -1, -1, -1, 3, -1, -1, -1, -1, 0, -1, -1, 0, 9,
|
|
|
|
|
1, 0, 2, 2, -1, 3, 7, 3, -1, 3, 4, 8, 2, -1, 2, 1,
|
|
|
|
|
-1, 3, -1, -1, -1, -1, -1, 0, 2, 2, -1, -1, 3, 1, -1, -1,
|
|
|
|
|
-1, 2, -1, 2, -1, -1, -1, -1, -1, -1, 11, 11, 0, -1, -1, -1,
|
|
|
|
|
-1, 7, 0, 1, -1, 1, 1, 3, -1, -1, -1, 1, 1, 2, 3, -1,
|
|
|
|
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
|
|
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
|
|
|
};
|
|
|
|
|
var areas = new List<EncounterArea>();
|
|
|
|
|
for (int i = 0; i < convMapIDtoFishLocationID.Length; i++)
|
|
|
|
|
{
|
|
|
|
|
var loc = convMapIDtoFishLocationID[i];
|
|
|
|
|
if (convMapIDtoFishLocationID[i] == -1) // no table for map
|
|
|
|
|
continue;
|
|
|
|
|
areas.Add(new EncounterArea { Location = i, Slots = f[loc].Slots });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Some maps have two tables. Fortunately, there's only two. Add the second table.
|
|
|
|
|
areas.Add(new EncounterArea { Location = 0x1B, Slots = f[1].Slots }); // Olivine City (0: Harbor, 1: City)
|
|
|
|
|
areas.Add(new EncounterArea { Location = 0x2E, Slots = f[3].Slots }); // Silver Cave (2: Inside, 3: Outside)
|
|
|
|
|
return areas.ToArray();
|
2017-03-03 02:24:50 +00:00
|
|
|
|
}
|
2017-06-18 01:37:19 +00:00
|
|
|
|
public static EncounterArea[] GetArray2_H(byte[] data)
|
2017-03-03 02:24:50 +00:00
|
|
|
|
{
|
|
|
|
|
int ofs = 0;
|
2017-06-18 01:37:19 +00:00
|
|
|
|
return GetAreas2_H(data, ref ofs).ToArray();
|
2017-02-27 05:46:00 +00:00
|
|
|
|
}
|
|
|
|
|
|
2017-03-19 12:19:45 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Gets the encounter areas with <see cref="EncounterSlot"/> information from Generation 3 data.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="entries">Raw data, one byte array per encounter area</param>
|
|
|
|
|
/// <returns>Array of encounter areas.</returns>
|
2017-06-18 01:37:19 +00:00
|
|
|
|
public static EncounterArea[] GetArray3(byte[][] entries)
|
2017-03-19 12:19:45 +00:00
|
|
|
|
{
|
|
|
|
|
if (entries == null)
|
|
|
|
|
return null;
|
|
|
|
|
|
|
|
|
|
var Areas = new List<EncounterArea>();
|
2017-03-19 17:44:46 +00:00
|
|
|
|
foreach (byte[] t in entries)
|
2017-03-19 12:19:45 +00:00
|
|
|
|
{
|
2017-06-18 01:37:19 +00:00
|
|
|
|
EncounterArea Area = GetArea3(t);
|
2017-12-05 04:16:54 +00:00
|
|
|
|
if (Area.Slots.Length != 0)
|
2017-03-19 12:19:45 +00:00
|
|
|
|
Areas.Add(Area);
|
|
|
|
|
}
|
|
|
|
|
return Areas.ToArray();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Gets the encounter areas with <see cref="EncounterSlot"/> information from Generation 4 Diamond, Pearl and Platinum data.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="entries">Raw data, one byte array per encounter area</param>
|
2017-12-03 20:20:49 +00:00
|
|
|
|
/// <param name="pt">Platinum flag (for Trophy Garden slot insertion)</param>
|
2017-03-19 12:19:45 +00:00
|
|
|
|
/// <returns>Array of encounter areas.</returns>
|
2017-12-03 20:20:49 +00:00
|
|
|
|
public static EncounterArea[] GetArray4DPPt(byte[][] entries, bool pt = false)
|
2017-03-19 12:19:45 +00:00
|
|
|
|
{
|
2017-12-03 20:20:49 +00:00
|
|
|
|
return entries?.Select(z => GetArea4DPPt(z, pt)).Where(Area => Area.Slots.Length != 0).ToArray();
|
2017-03-19 12:19:45 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Gets the encounter areas with <see cref="EncounterSlot"/> information from Generation 4 Hearth Gold and Soul Silver data.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="entries">Raw data, one byte array per encounter area</param>
|
|
|
|
|
/// <returns>Array of encounter areas.</returns>
|
2017-06-18 01:37:19 +00:00
|
|
|
|
public static EncounterArea[] GetArray4HGSS(byte[][] entries)
|
2017-03-19 12:19:45 +00:00
|
|
|
|
{
|
2017-11-26 02:16:50 +00:00
|
|
|
|
return entries?.Select(GetArea4HGSS).Where(Area => Area.Slots.Length != 0).ToArray();
|
2017-03-19 12:19:45 +00:00
|
|
|
|
}
|
|
|
|
|
|
2017-03-19 15:23:46 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Gets the encounter areas with <see cref="EncounterSlot"/> information from Generation 4 Hearth Gold and Soul Silver Headbutt tree data.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="entries">Raw data, one byte array per encounter area</param>
|
|
|
|
|
/// <returns>Array of encounter areas.</returns>
|
2017-06-18 01:37:19 +00:00
|
|
|
|
public static EncounterArea[] GetArray4HGSS_Headbutt(byte[][] entries)
|
2017-03-19 15:23:46 +00:00
|
|
|
|
{
|
2017-11-26 02:16:50 +00:00
|
|
|
|
return entries?.Select(GetArea4HGSS_Headbutt).Where(Area => Area.Slots.Length != 0).ToArray();
|
2017-03-19 15:23:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
2017-03-27 03:23:45 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Gets the encounter areas for species with same level range and same slottype at same location
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="species">List of species that exist in the Area.</param>
|
|
|
|
|
/// <param name="lvls">Paired LevelMins and LevelMaxs of the encounter slots.</param>
|
|
|
|
|
/// <param name="location">Location index of the encounter area.</param>
|
|
|
|
|
/// <param name="t">Encounter slot type of the encounter area.</param>
|
|
|
|
|
/// <returns></returns>
|
2017-06-18 01:37:19 +00:00
|
|
|
|
public static EncounterArea[] GetSimpleEncounterArea(IEnumerable<int> species, int[] lvls, int location, SlotType t)
|
2017-03-27 03:23:45 +00:00
|
|
|
|
{
|
|
|
|
|
var l = new List<EncounterSlot>();
|
|
|
|
|
// levels data not paired
|
|
|
|
|
if ((lvls.Length & 1) == 1)
|
|
|
|
|
return new[] { new EncounterArea { Location = location, Slots = l.ToArray() } };
|
|
|
|
|
|
|
|
|
|
foreach (var s in species)
|
|
|
|
|
{
|
|
|
|
|
for (int i = 0; i < lvls.Length;)
|
|
|
|
|
{
|
|
|
|
|
l.Add(new EncounterSlot
|
|
|
|
|
{
|
|
|
|
|
LevelMin = lvls[i++],
|
|
|
|
|
LevelMax = lvls[i++],
|
|
|
|
|
Species = s,
|
|
|
|
|
Type = t
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return new[] { new EncounterArea { Location = location, Slots = l.ToArray() } };
|
|
|
|
|
}
|
|
|
|
|
|
2017-10-24 06:12:58 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Gets an array of areas from an array of raw area data
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="entries">Simplified raw format of an Area</param>
|
|
|
|
|
/// <returns>Array of areas</returns>
|
2017-06-18 01:37:19 +00:00
|
|
|
|
public static EncounterArea[] GetArray(byte[][] entries)
|
2016-11-08 16:43:57 +00:00
|
|
|
|
{
|
|
|
|
|
if (entries == null)
|
|
|
|
|
return null;
|
|
|
|
|
|
|
|
|
|
EncounterArea[] data = new EncounterArea[entries.Length];
|
|
|
|
|
for (int i = 0; i < data.Length; i++)
|
|
|
|
|
data[i] = new EncounterArea(entries[i]);
|
|
|
|
|
return data;
|
|
|
|
|
}
|
|
|
|
|
}
|
2017-12-03 20:20:49 +00:00
|
|
|
|
|
|
|
|
|
public partial class Extensions
|
|
|
|
|
{
|
|
|
|
|
public static IEnumerable<IEnumerable<T>> CartesianProduct<T>(this IEnumerable<IEnumerable<T>> sequences)
|
|
|
|
|
{
|
|
|
|
|
IEnumerable<IEnumerable<T>> emptyProduct = new[] { Enumerable.Empty<T>() };
|
|
|
|
|
return sequences.Aggregate(
|
|
|
|
|
emptyProduct,
|
|
|
|
|
(accumulator, sequence) =>
|
|
|
|
|
from accseq in accumulator
|
|
|
|
|
from item in sequence
|
|
|
|
|
select accseq.Concat(new[] { item }));
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-11-08 16:43:57 +00:00
|
|
|
|
}
|