using System;
namespace PKHeX.Core;
///
/// Logic for interacting with Pokédex Form flags
///
public static class DexFormUtil
{
public static int GetDexFormIndexSM(ushort species, byte formCount, int start) => GetDexFormBitIndex(species, formCount, start, formtable_SM);
public static int GetDexFormIndexUSUM(ushort species, byte formCount, int start) => GetDexFormBitIndex(species, formCount, start, formtable_USUM);
public static int GetDexFormIndexGG(ushort species, byte formCount, int start) => GetDexFormBitIndex(species, formCount, start, formtable_GG);
public static int GetDexFormCountSM(ushort species) => GetDexFormCount(species, formtable_SM);
public static int GetDexFormCountUSUM(ushort species) => GetDexFormCount(species, formtable_USUM);
public static int GetDexFormCountGG(ushort species) => GetDexFormCount(species, formtable_GG);
private static ReadOnlySpan formtable_SM => new ushort[] // u16 species, u16 formcount
{
0x0003, 0x0002, 0x0006, 0x0003, 0x0009, 0x0002, 0x000F, 0x0002,
0x0012, 0x0002, 0x0013, 0x0002, 0x0014, 0x0003, 0x0019, 0x0007,
0x001A, 0x0002, 0x001B, 0x0002, 0x001C, 0x0002, 0x0025, 0x0002,
0x0026, 0x0002, 0x0032, 0x0002, 0x0033, 0x0002, 0x0034, 0x0002,
0x0035, 0x0002, 0x0041, 0x0002, 0x004A, 0x0002, 0x004B, 0x0002,
0x004C, 0x0002, 0x0050, 0x0002, 0x0058, 0x0002, 0x0059, 0x0002,
0x005E, 0x0002, 0x0067, 0x0002, 0x0069, 0x0002, 0x0073, 0x0002,
0x007F, 0x0002, 0x0082, 0x0002, 0x008E, 0x0002, 0x0096, 0x0003,
0x00B5, 0x0002, 0x00C9, 0x001C, 0x00D0, 0x0002, 0x00D4, 0x0002,
0x00D6, 0x0002, 0x00E5, 0x0002, 0x00F8, 0x0002, 0x00FE, 0x0002,
0x0101, 0x0002, 0x0104, 0x0002, 0x011A, 0x0002, 0x012E, 0x0002,
0x012F, 0x0002, 0x0132, 0x0002, 0x0134, 0x0002, 0x0136, 0x0002,
0x013F, 0x0002, 0x0143, 0x0002, 0x014E, 0x0002, 0x015F, 0x0004,
0x0162, 0x0002, 0x0167, 0x0002, 0x016A, 0x0002, 0x0175, 0x0002,
0x0178, 0x0002, 0x017C, 0x0002, 0x017D, 0x0002, 0x017E, 0x0002,
0x017F, 0x0002, 0x0180, 0x0002, 0x0182, 0x0004, 0x019C, 0x0003,
0x019D, 0x0003, 0x01A5, 0x0002, 0x01A6, 0x0002, 0x01A7, 0x0002,
0x01AC, 0x0002, 0x01BD, 0x0002, 0x01C0, 0x0002, 0x01CC, 0x0002,
0x01DB, 0x0002, 0x01DF, 0x0006, 0x01E7, 0x0002, 0x01EC, 0x0002,
0x01ED, 0x0012, 0x0213, 0x0002, 0x0226, 0x0002, 0x022B, 0x0002,
0x0249, 0x0004, 0x024A, 0x0004, 0x0281, 0x0002, 0x0282, 0x0002,
0x0285, 0x0002, 0x0286, 0x0003, 0x0287, 0x0002, 0x0288, 0x0002,
0x0289, 0x0005, 0x0292, 0x0003, 0x029A, 0x0014, 0x029D, 0x0005,
0x029E, 0x0006, 0x029F, 0x0005, 0x02A4, 0x000A, 0x02A6, 0x0002,
0x02A9, 0x0002, 0x02C6, 0x0004, 0x02C7, 0x0004, 0x02CC, 0x0002,
0x02CE, 0x0005, 0x02CF, 0x0002, 0x02D0, 0x0002, 0x02DF, 0x0002,
0x02E2, 0x0002, 0x02E5, 0x0004, 0x02E9, 0x0002, 0x02EA, 0x0002,
0x02F2, 0x0002, 0x02F6, 0x0002, 0x0305, 0x0012, 0x0306, 0x000E,
0x030A, 0x0004, 0x0310, 0x0002, 0x0321, 0x0002,
};
private static ReadOnlySpan formtable_USUM => new ushort[] // u16 species, u16 formcount
{
0x0003, 0x0002, 0x0006, 0x0003, 0x0009, 0x0002, 0x000F, 0x0002,
0x0012, 0x0002, 0x0013, 0x0002, 0x0014, 0x0003, 0x0019, 0x0008,
0x001A, 0x0002, 0x001B, 0x0002, 0x001C, 0x0002, 0x0025, 0x0002,
0x0026, 0x0002, 0x0032, 0x0002, 0x0033, 0x0002, 0x0034, 0x0002,
0x0035, 0x0002, 0x0041, 0x0002, 0x004A, 0x0002, 0x004B, 0x0002,
0x004C, 0x0002, 0x0050, 0x0002, 0x0058, 0x0002, 0x0059, 0x0002,
0x005E, 0x0002, 0x0067, 0x0002, 0x0069, 0x0003, 0x0073, 0x0002,
0x007F, 0x0002, 0x0082, 0x0002, 0x008E, 0x0002, 0x0096, 0x0003,
0x00B5, 0x0002, 0x00C9, 0x001C, 0x00D0, 0x0002, 0x00D4, 0x0002,
0x00D6, 0x0002, 0x00E5, 0x0002, 0x00F8, 0x0002, 0x00FE, 0x0002,
0x0101, 0x0002, 0x0104, 0x0002, 0x011A, 0x0002, 0x012E, 0x0002,
0x012F, 0x0002, 0x0132, 0x0002, 0x0134, 0x0002, 0x0136, 0x0002,
0x013F, 0x0002, 0x0143, 0x0002, 0x014E, 0x0002, 0x015F, 0x0004,
0x0162, 0x0002, 0x0167, 0x0002, 0x016A, 0x0002, 0x0175, 0x0002,
0x0178, 0x0002, 0x017C, 0x0002, 0x017D, 0x0002, 0x017E, 0x0002,
0x017F, 0x0002, 0x0180, 0x0002, 0x0182, 0x0004, 0x019C, 0x0003,
0x019D, 0x0003, 0x019E, 0x0003, 0x01A5, 0x0002, 0x01A6, 0x0002,
0x01A7, 0x0002, 0x01AC, 0x0002, 0x01BD, 0x0002, 0x01C0, 0x0002,
0x01CC, 0x0002, 0x01DB, 0x0002, 0x01DF, 0x0006, 0x01E7, 0x0002,
0x01EC, 0x0002, 0x01ED, 0x0012, 0x0213, 0x0002, 0x0226, 0x0002,
0x022B, 0x0002, 0x0249, 0x0004, 0x024A, 0x0004, 0x0281, 0x0002,
0x0282, 0x0002, 0x0285, 0x0002, 0x0286, 0x0003, 0x0287, 0x0002,
0x0288, 0x0002, 0x0289, 0x0005, 0x0292, 0x0003, 0x0298, 0x0014,
0x0299, 0x0014, 0x029A, 0x0014, 0x029D, 0x0005, 0x029E, 0x0006,
0x029F, 0x0005, 0x02A4, 0x000A, 0x02A6, 0x0002, 0x02A9, 0x0002,
0x02C6, 0x0004, 0x02C7, 0x0004, 0x02CC, 0x0002, 0x02CE, 0x0005,
0x02CF, 0x0002, 0x02D0, 0x0002, 0x02DF, 0x0002, 0x02E2, 0x0002,
0x02E5, 0x0004, 0x02E7, 0x0002, 0x02E8, 0x0002, 0x02E9, 0x0003,
0x02EA, 0x0002, 0x02F0, 0x0002, 0x02F2, 0x0002, 0x02F6, 0x0002,
0x0305, 0x0012, 0x0306, 0x000E, 0x0309, 0x0002, 0x030A, 0x0004,
0x0310, 0x0002, 0x0320, 0x0004, 0x0321, 0x0002,
};
private static ReadOnlySpan formtable_GG => new ushort[] // u16 species, u16 formcount
{
0x0003, 0x0002, 0x0006, 0x0003, 0x0009, 0x0002, 0x000F, 0x0002,
0x0012, 0x0002, 0x0013, 0x0002, 0x0014, 0x0003, 0x0019, 0x0009,
0x001A, 0x0002, 0x001B, 0x0002, 0x001C, 0x0002, 0x0025, 0x0002,
0x0026, 0x0002, 0x0032, 0x0002, 0x0033, 0x0002, 0x0034, 0x0002,
0x0035, 0x0002, 0x0041, 0x0002, 0x004A, 0x0002, 0x004B, 0x0002,
0x004C, 0x0002, 0x0050, 0x0002, 0x0058, 0x0002, 0x0059, 0x0002,
0x005E, 0x0002, 0x0067, 0x0002, 0x0069, 0x0003, 0x0073, 0x0002,
0x007F, 0x0002, 0x0082, 0x0002, 0x008E, 0x0002, 0x0096, 0x0003,
};
private static int GetDexFormBitIndex(ushort species, byte formCount, int start, ReadOnlySpan formTable)
{
int formIndex = start;
for (int i = 0; i < formTable.Length; i += 2)
{
int s = formTable[i];
int f = formTable[i + 1];
if (s == species)
return f > formCount ? -1 : formIndex;
formIndex += f - 1;
}
return -1;
}
private static int GetDexFormCount(ushort species, ReadOnlySpan formTable)
{
for (int i = 0; i < formTable.Length; i += 2)
{
if (formTable[i] == species)
return formTable[i + 1];
}
return 0;
}
public static int GetDexFormIndexBW(ushort species, byte formCount)
{
if (formCount < 1 || species > Legal.MaxSpeciesID_5)
return -1; // invalid
return species switch
{
201 => 000, // 28 Unown
386 => 028, // 4 Deoxys
492 => 032, // 2 Shaymin
487 => 034, // 2 Giratina
479 => 036, // 6 Rotom
422 => 042, // 2 Shellos
423 => 044, // 2 Gastrodon
412 => 046, // 3 Burmy
413 => 049, // 3 Wormadam
351 => 052, // 4 Castform
421 => 056, // 2 Cherrim
585 => 058, // 4 Deerling
586 => 062, // 4 Sawsbuck
648 => 066, // 2 Meloetta
555 => 068, // 2 Darmanitan
550 => 070, // 2 Basculin
_ => -1,
};
}
public static int GetDexFormIndexB2W2(ushort species, byte formCount)
{
if (formCount < 1 || species > Legal.MaxSpeciesID_5)
return -1; // invalid
return species switch
{
646 => 072, // 3 Kyurem
647 => 075, // 2 Keldeo
642 => 077, // 2 Thundurus
641 => 079, // 2 Tornadus
645 => 081, // 2 Landorus
_ => GetDexFormIndexBW(species, formCount),
};
}
public static int GetDexFormIndexXY(ushort species, byte formCount)
{
if (formCount < 1 || species > Legal.MaxSpeciesID_6)
return -1; // invalid
return species switch
{
666 => 083, // 20 Vivillion
669 => 103, // 5 Flabébé
670 => 108, // 6 Floette
671 => 114, // 5 Florges
710 => 119, // 4 Pumpkaboo
711 => 123, // 4 Gourgeist
681 => 127, // 2 Aegislash
716 => 129, // 2 Xerneas
003 => 131, // 2 Venusaur
006 => 133, // 3 Charizard
009 => 136, // 2 Blastoise
065 => 138, // 2 Alakazam
094 => 140, // 2 Gengar
115 => 142, // 2 Kangaskhan
127 => 144, // 2 Pinsir
130 => 146, // 2 Gyarados
142 => 148, // 2 Aerodactyl
150 => 150, // 3 Mewtwo
181 => 153, // 2 Ampharos
212 => 155, // 2 Scizor
214 => 157, // 2 Heracros
229 => 159, // 2 Houndoom
248 => 161, // 2 Tyranitar
257 => 163, // 2 Blaziken
282 => 165, // 2 Gardevoir
303 => 167, // 2 Mawile
306 => 169, // 2 Aggron
308 => 171, // 2 Medicham
310 => 173, // 2 Manetric
354 => 175, // 2 Banette
359 => 177, // 2 Absol
380 => 179, // 2 Latias
381 => 181, // 2 Latios
445 => 183, // 2 Garchomp
448 => 185, // 2 Lucario
460 => 187, // 2 Abomasnow
_ => GetDexFormIndexB2W2(species, formCount),
};
}
public static int GetDexFormIndexORAS(ushort species, byte formCount)
{
if (formCount < 1 || species > Legal.MaxSpeciesID_6)
return -1; // invalid
return species switch
{
025 => 189, // 7 Pikachu
720 => 196, // 2 Hoopa
015 => 198, // 2 Beedrill
018 => 200, // 2 Pidgeot
080 => 202, // 2 Slowbro
208 => 204, // 2 Steelix
254 => 206, // 2 Sceptile
260 => 208, // 2 Swampert
302 => 210, // 2 Sableye
319 => 212, // 2 Sharpedo
323 => 214, // 2 Camerupt
334 => 216, // 2 Altaria
362 => 218, // 2 Glalie
373 => 220, // 2 Salamence
376 => 222, // 2 Metagross
384 => 224, // 2 Rayquaza
428 => 226, // 2 Lopunny
475 => 228, // 2 Gallade
531 => 230, // 2 Audino
719 => 232, // 2 Diancie
382 => 234, // 2 Kyogre
383 => 236, // 2 Groudon
493 => 238, // 18 Arceus
649 => 256, // 5 Genesect
676 => 261, // 10 Furfrou
_ => GetDexFormIndexXY(species, formCount),
};
}
}