mirror of
https://github.com/kwsch/PKHeX
synced 2024-11-13 07:47:07 +00:00
Rearrange how some memory info is checked
Split into different game contexts
This commit is contained in:
parent
b099b8d82c
commit
a631e5cb4e
16 changed files with 782 additions and 631 deletions
|
@ -28,7 +28,7 @@
|
||||||
if (pk is IMemoryOT o)
|
if (pk is IMemoryOT o)
|
||||||
{
|
{
|
||||||
o.OT_Memory = 2;
|
o.OT_Memory = 2;
|
||||||
o.OT_Feeling = Memories.GetRandomFeeling(2);
|
o.OT_Feeling = MemoryContext6.GetRandomFeeling6(2);
|
||||||
o.OT_Intensity = 1;
|
o.OT_Intensity = 1;
|
||||||
o.OT_TextVar = pk.XY ? 43 : 27; // riverside road : battling spot
|
o.OT_TextVar = pk.XY ? 43 : 27; // riverside road : battling spot
|
||||||
}
|
}
|
||||||
|
@ -45,7 +45,7 @@
|
||||||
// for lack of better randomization :)
|
// for lack of better randomization :)
|
||||||
pk.OT_Memory = 63;
|
pk.OT_Memory = 63;
|
||||||
pk.OT_Intensity = 6;
|
pk.OT_Intensity = 6;
|
||||||
pk.OT_Feeling = Memories.GetRandomFeeling(pk.OT_Memory);
|
pk.OT_Feeling = MemoryContext6.GetRandomFeeling6(pk.OT_Memory);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,490 +0,0 @@
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
namespace PKHeX.Core
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Generation 6 Memory parameters & validation
|
|
||||||
/// </summary>
|
|
||||||
public static class Memories
|
|
||||||
{
|
|
||||||
internal const int MAX_MEMORY_ID_XY = 64;
|
|
||||||
internal const int MAX_MEMORY_ID_AO = 69;
|
|
||||||
internal const int MAX_MEMORY_ID_SWSH = 89;
|
|
||||||
|
|
||||||
#region Tables
|
|
||||||
internal static readonly int[] Memory_NotXY =
|
|
||||||
{
|
|
||||||
65, // {0} was with {1} when (he/she) built a Secret Base. {4} that {3}.
|
|
||||||
66, // {0} participated in a contest with {1} and impressed many people. {4} that {3}.
|
|
||||||
67, // {0} participated in a contest with {1} and won the title. {4} that {3}.
|
|
||||||
68, // {0} soared through the sky with {1} and went to many different places. {4} that {3}.
|
|
||||||
69, // {1} asked {0} to dive. Down it went, deep into the ocean, to explore the bottom of the sea. {4} that {3}.
|
|
||||||
};
|
|
||||||
|
|
||||||
internal static readonly int[] Memory_NotAO =
|
|
||||||
{
|
|
||||||
11, // {0} went clothes shopping with {1}. {4} that {3}.
|
|
||||||
43, // {0} was impressed by the speed of the train it took with {1}. {4} that {3}.
|
|
||||||
44, // {0} encountered {2} with {1} using the Poké Radar. {4} that {3}.
|
|
||||||
56, // {0} was with {1} when (he/she) went to a boutique and tried on clothes, but (he/she) left the boutique without buying anything. {4} that {3}.
|
|
||||||
57, // {0} went to a nice restaurant with {1} and ate until it got totally full. {4} that {3}.
|
|
||||||
62, // {0} saw itself in a mirror in a mirror cave that it went to with {1}. {4} that {3}.
|
|
||||||
};
|
|
||||||
|
|
||||||
internal static readonly int[] Memory_NotSWSH =
|
|
||||||
{
|
|
||||||
// There's probably more. Send a pull request!
|
|
||||||
20, // {0} surfed across the water, carrying {1} on its back. {4} that {3}.
|
|
||||||
24, // {0} flew, carrying {1} on its back, to {2}. {4} that {3}.
|
|
||||||
35, // {0} proudly used Strength at {1}’s instruction in... {2}. {4} that {3}.
|
|
||||||
36, // {0} proudly used Cut at {1}’s instruction in... {2}. {4} that {3}.
|
|
||||||
37, // {0} shattered rocks to its heart’s content at {1}’s instruction in... {2}. {4} that {3}.
|
|
||||||
38, // {0} used Waterfall while carrying {1} on its back in... {2}. {4} that {3}.
|
|
||||||
69, // {1} asked {0} to dive. Down it went, deep into the ocean, to explore the bottom of the sea. {4} that {3}.
|
|
||||||
};
|
|
||||||
|
|
||||||
internal static readonly int[][] MoveSpecificMemories =
|
|
||||||
{
|
|
||||||
new[] {
|
|
||||||
20, // {0} surfed across the water, carrying {1} on its back. {4} that {3}.
|
|
||||||
24, // {0} flew, carrying {1} on its back, to {2}. {4} that {3}.
|
|
||||||
35, // {0} proudly used Strength at {1}’s instruction in... {2}. {4} that {3}.
|
|
||||||
36, // {0} proudly used Cut at {1}’s instruction in... {2}. {4} that {3}.
|
|
||||||
37, // {0} shattered rocks to its heart’s content at {1}’s instruction in... {2}. {4} that {3}.
|
|
||||||
38, // {0} used Waterfall while carrying {1} on its back in... {2}. {4} that {3}.
|
|
||||||
69, // {1} asked {0} to dive. Down it went, deep into the ocean, to explore the bottom of the sea. {4} that {3}.
|
|
||||||
},
|
|
||||||
new[] { 57, 19, 70, 15, 249, 127, 291}, // Move IDs
|
|
||||||
};
|
|
||||||
|
|
||||||
internal static readonly int[] LocationsWithPokeCenter_XY =
|
|
||||||
{
|
|
||||||
// Kalos locations with a PKMN CENTER
|
|
||||||
018, // Santalune City
|
|
||||||
022, // Lumiose City
|
|
||||||
030, // Camphrier Town
|
|
||||||
040, // Cyllage City
|
|
||||||
044, // Ambrette Town
|
|
||||||
052, // Geosenge Towny
|
|
||||||
058, // Shalour City
|
|
||||||
064, // Coumarine City
|
|
||||||
070, // Laverre City
|
|
||||||
076, // Dendemille Town
|
|
||||||
086, // Anistar City
|
|
||||||
090, // Couriway Town
|
|
||||||
094, // Snowbelle City
|
|
||||||
106, // Pokémon League (X/Y)
|
|
||||||
};
|
|
||||||
|
|
||||||
internal static readonly int[] LocationsWithPokeCenter_AO =
|
|
||||||
{
|
|
||||||
// Hoenn locations with a PKMN CENTER
|
|
||||||
172, // Oldale Town
|
|
||||||
174, // Dewford Town
|
|
||||||
176, // Lavaridge Town
|
|
||||||
178, // Fallarbor Town
|
|
||||||
180, // Verdanturf Town
|
|
||||||
182, // Pacifidlog Town
|
|
||||||
184, // Petalburg City
|
|
||||||
186, // Slateport City
|
|
||||||
188, // Mauville City
|
|
||||||
190, // Rustboro City
|
|
||||||
192, // Fortree City
|
|
||||||
194, // Lilycove City
|
|
||||||
196, // Mossdeep City
|
|
||||||
198, // Sootopolis City
|
|
||||||
200, // Ever Grande City
|
|
||||||
202, // Pokémon League (OR/AS)
|
|
||||||
};
|
|
||||||
|
|
||||||
private static ICollection<int> GetPokeCenterLocations(GameVersion game)
|
|
||||||
{
|
|
||||||
return GameVersion.XY.Contains(game) ? LocationsWithPokeCenter_XY : LocationsWithPokeCenter_AO;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool GetHasPokeCenterLocation(GameVersion game, int loc)
|
|
||||||
{
|
|
||||||
if (game == GameVersion.Gen6)
|
|
||||||
return GetHasPokeCenterLocation(GameVersion.X, loc) || GetHasPokeCenterLocation(GameVersion.AS, loc);
|
|
||||||
return GetPokeCenterLocations(game).Contains(loc);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static readonly byte[] MemoryMinIntensity =
|
|
||||||
{
|
|
||||||
0, 1, 1, 1, 1, 2, 2, 2, 2, 2,
|
|
||||||
2, 2, 2, 2, 3, 3, 3, 3, 4, 4,
|
|
||||||
3, 3, 3, 3, 3, 3, 3, 4, 5, 5,
|
|
||||||
5, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
|
||||||
3, 3, 1, 3, 2, 2, 4, 3, 4, 4,
|
|
||||||
4, 4, 2, 4, 2, 4, 3, 3, 4, 2,
|
|
||||||
3, 3, 3, 3, 3, 2, 3, 4, 4, 2,
|
|
||||||
};
|
|
||||||
|
|
||||||
public static int GetMemoryRarity(int memory) => (uint) memory >= MemoryRandChance.Length ? -1 : MemoryRandChance[memory];
|
|
||||||
|
|
||||||
private static readonly byte[] MemoryRandChance =
|
|
||||||
{
|
|
||||||
000, 100, 100, 100, 100, 005, 005, 005, 005, 005,
|
|
||||||
005, 005, 005, 005, 010, 020, 010, 001, 050, 030,
|
|
||||||
005, 005, 020, 005, 005, 005, 001, 050, 100, 050,
|
|
||||||
050, 002, 002, 005, 005, 005, 005, 005, 005, 002,
|
|
||||||
020, 020, 005, 010, 001, 001, 050, 030, 020, 020,
|
|
||||||
010, 010, 001, 010, 001, 050, 030, 030, 030, 002,
|
|
||||||
050, 020, 020, 020, 020, 010, 010, 050, 020, 005,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 24bits of flags allowing certain feelings for a given memory index.
|
|
||||||
/// </summary>
|
|
||||||
private static readonly uint[] MemoryFeelings =
|
|
||||||
{
|
|
||||||
0x000000, 0x04CBFD, 0x004BFD, 0x04CBFD, 0x04CBFD, 0xFFFBFB, 0x84FFF9, 0x47FFFF, 0xBF7FFA, 0x7660B0,
|
|
||||||
0x80BDF9, 0x88FB7A, 0x083F79, 0x0001FE, 0xCFEFFF, 0x84EBAF, 0xB368B0, 0x091F7E, 0x0320A0, 0x080DDD,
|
|
||||||
0x081A7B, 0x404030, 0x0FFFFF, 0x9A08BC, 0x089A7B, 0x0032AA, 0x80FF7A, 0x0FFFFF, 0x0805FD, 0x098278,
|
|
||||||
0x0B3FFF, 0x8BBFFA, 0x8BBFFE, 0x81A97C, 0x8BB97C, 0x8BBF7F, 0x8BBF7F, 0x8BBF7F, 0x8BBF7F, 0xAC3ABE,
|
|
||||||
0xBFFFFF, 0x8B837C, 0x848AFA, 0x88FFFE, 0x8B0B7C, 0xB76AB2, 0x8B1FFF, 0xBE7AB8, 0xB77EB8, 0x8C9FFD,
|
|
||||||
0xBF9BFF, 0xF408B0, 0xBCFE7A, 0x8F3F72, 0x90DB7A, 0xBCEBFF, 0xBC5838, 0x9C3FFE, 0x9CFFFF, 0x96D83A,
|
|
||||||
0xB770B0, 0x881F7A, 0x839F7A, 0x839F7A, 0x839F7A, 0x53897F, 0x41BB6F, 0x0C35FF, 0x8BBF7F, 0x8BBF7F,
|
|
||||||
};
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Tables for Gen8
|
|
||||||
|
|
||||||
public static bool IsInvalidGenLoc8(int memory, int loc, int egg, int variable)
|
|
||||||
{
|
|
||||||
if (variable > 255)
|
|
||||||
return true;
|
|
||||||
var arg = (byte)variable;
|
|
||||||
if (loc > 255) // gift
|
|
||||||
return memory != 3 || !PossibleGeneralLocations.Contains(arg);
|
|
||||||
if (memory == 2 && egg == 0)
|
|
||||||
return true;
|
|
||||||
if (loc is Encounters8Nest.SharedNest)
|
|
||||||
return !PossibleGeneralLocations.Contains(arg) || arg is 79; // dangerous place - all locations are Y-Comm locked
|
|
||||||
if (SingleGenLocAreas.TryGetValue((byte)loc, out var val))
|
|
||||||
return arg != val;
|
|
||||||
if (MultiGenLocAreas.TryGetValue((byte)loc, out var arr))
|
|
||||||
return !arr.Contains(arg);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool IsInvalidGenLoc8Other(int memory, int variable)
|
|
||||||
{
|
|
||||||
if (variable > byte.MaxValue)
|
|
||||||
return true;
|
|
||||||
var arg = (byte)variable;
|
|
||||||
return memory switch
|
|
||||||
{
|
|
||||||
_ => !PossibleGeneralLocations.Contains(arg),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// {met, values allowed}
|
|
||||||
private static readonly Dictionary<byte, byte[]> MultiGenLocAreas = new()
|
|
||||||
{
|
|
||||||
// town of Postwick
|
|
||||||
// first town, at home, friend's house
|
|
||||||
{6, new byte[] {1, 2, 3}},
|
|
||||||
|
|
||||||
// town of Wedgehurst
|
|
||||||
// someone's house, boutique, simple town, Pokémon Center
|
|
||||||
{14, new byte[] {4, 6, 8, 9}},
|
|
||||||
|
|
||||||
// Route 2
|
|
||||||
// lab, tranquil road, lakeside road
|
|
||||||
{18, new byte[] {16, 44, 71}},
|
|
||||||
|
|
||||||
// city of Motostoke
|
|
||||||
// boutique, Pokémon Center, hotel, Pokémon Gym, stylish café, hair salon, town with a mysterious air
|
|
||||||
{20, new byte[] {6, 9, 11, 20, 24, 30, 35}},
|
|
||||||
|
|
||||||
// Motostoke Stadium
|
|
||||||
// Pokémon Gym, stadium
|
|
||||||
{24, new byte[] {20, 73}},
|
|
||||||
|
|
||||||
// town of Turffield
|
|
||||||
// Pokémon Center, town with a mysterious air
|
|
||||||
{34, new byte[] {9, 12}},
|
|
||||||
|
|
||||||
// Route 5
|
|
||||||
// tranquil road, Pokémon Nursery
|
|
||||||
{40, new byte[] {44, 74}},
|
|
||||||
|
|
||||||
// town of Hulbury
|
|
||||||
// someone’s house, Pokémon Center, restaurant, seaside town
|
|
||||||
{44, new byte[] {4, 9, 31, 33}},
|
|
||||||
|
|
||||||
// city of Hammerlocke
|
|
||||||
// someone’s house, boutique, Pokémon Center, Pokémon Gym, stylish café, hair salon, town with a mysterious air
|
|
||||||
{56, new byte[] {4, 6, 9, 20, 24, 30, 35}},
|
|
||||||
|
|
||||||
// town of Stow-on-Side
|
|
||||||
// someone’s house, Pokémon Center, town in the mountains
|
|
||||||
{70, new byte[] {4, 9, 76}},
|
|
||||||
|
|
||||||
// town of Ballonlea
|
|
||||||
// someone’s house, Pokémon Center, town with a mysterious air
|
|
||||||
{78, new byte[] {4, 9, 12}},
|
|
||||||
|
|
||||||
// town of Circhester
|
|
||||||
// someone’s house, boutique, Pokémon Center, hotel, hair salon, restaurant, snowcapped town
|
|
||||||
{96, new byte[] {4, 6, 9, 11, 30, 31, 37}},
|
|
||||||
|
|
||||||
// town of Spikemuth
|
|
||||||
// Pokémon Center, run-down town
|
|
||||||
{102, new byte[] {9, 77}},
|
|
||||||
|
|
||||||
// city of Wyndon
|
|
||||||
// someone’s house, boutique, Pokémon Center, hotel, large town, stylish café, hair salon
|
|
||||||
{110, new byte[] {4, 6, 9, 11, 22, 24, 30}},
|
|
||||||
|
|
||||||
// town of Freezington
|
|
||||||
// someone’s house, snowcapped town
|
|
||||||
{206, new byte[] {04, 37}},
|
|
||||||
};
|
|
||||||
|
|
||||||
// {met, value allowed}
|
|
||||||
private static readonly Dictionary<byte, byte> SingleGenLocAreas = new()
|
|
||||||
{
|
|
||||||
{008, 41}, // Slumbering Weald, forest
|
|
||||||
{012, 44}, // Route 1, tranquil road
|
|
||||||
{016, 28}, // Wedgehurst Station, train station
|
|
||||||
{022, 28}, // Motostoke Station, train station
|
|
||||||
{028, 44}, // Route 3, tranquil road
|
|
||||||
{030, 75}, // Galar Mine, mine
|
|
||||||
{032, 44}, // Route 4, tranquil road
|
|
||||||
{036, 73}, // Turffield Stadium, stadium
|
|
||||||
{046, 28}, // Hulbury Station, train station
|
|
||||||
{048, 73}, // Hulbury Stadium, stadium
|
|
||||||
{052, 35}, // Motostoke Outskirts, town with a mysterious air
|
|
||||||
{054, 75}, // Galar Mine No. 2, mine
|
|
||||||
{058, 28}, // Hammerlocke Station, train station
|
|
||||||
{060, 73}, // Hammerlocke Stadium, stadium
|
|
||||||
{064, 79}, // Energy Plant, dangerous place
|
|
||||||
{066, 79}, // the tower summit, dangerous place
|
|
||||||
{068, 47}, // Route 6, rugged mountain pass
|
|
||||||
{072, 73}, // Stow-on-Side Stadium, stadium
|
|
||||||
{076, 41}, // Glimwood Tangle, forest
|
|
||||||
{080, 73}, // Ballonlea Stadium, stadium
|
|
||||||
{084, 44}, // Route 7, tranquil road
|
|
||||||
{086, 47}, // Route 8, rugged mountain pass
|
|
||||||
{088, 53}, // Route 8 (on Steamdrift Way), snow-swept road
|
|
||||||
{090, 53}, // Route 9, snow-swept road
|
|
||||||
{092, 53}, // Route 9 (in Circhester Bay), snow-swept road
|
|
||||||
{094, 53}, // Route 9 (in Outer Spikemuth), snow-swept road
|
|
||||||
{098, 73}, // Circhester Stadium, stadium
|
|
||||||
{104, 78}, // Route 9 Tunnel, tunnel
|
|
||||||
{106, 53}, // Route 10, snow-swept road
|
|
||||||
{108, 28}, // White Hill Station, train station
|
|
||||||
{112, 28}, // Wyndon Station, train station
|
|
||||||
{114, 38}, // Wyndon Stadium (at the Pokémon League HQ), Pokémon League
|
|
||||||
{116, 38}, // Wyndon Stadium (in a locker room), Pokémon League
|
|
||||||
{120, 44}, // Meetup Spot, tranquil road
|
|
||||||
{122, 72}, // Rolling Fields, vast field
|
|
||||||
{124, 72}, // Dappled Grove, vast field
|
|
||||||
{126, 72}, // Watchtower Ruins, vast field
|
|
||||||
{128, 72}, // East Lake Axewell, vast field
|
|
||||||
{130, 72}, // West Lake Axewell, vast field
|
|
||||||
{132, 72}, // Axew’s Eye, vast field
|
|
||||||
{134, 72}, // South Lake Miloch, vast field
|
|
||||||
{136, 72}, // near the Giant’s Seat, vast field
|
|
||||||
{138, 72}, // North Lake Miloch, vast field
|
|
||||||
{140, 72}, // Motostoke Riverbank, vast field
|
|
||||||
{142, 72}, // Bridge Field, vast field
|
|
||||||
{144, 72}, // Stony Wilderness, vast field
|
|
||||||
{146, 72}, // Dusty Bowl, vast field
|
|
||||||
{148, 72}, // around the Giant’s Mirror, vast field
|
|
||||||
{150, 72}, // the Hammerlocke Hills, vast field
|
|
||||||
{152, 72}, // near the Giant’s Cap, vast field
|
|
||||||
{154, 72}, // Lake of Outrage, vast field
|
|
||||||
{156, 28}, // Wild Area Station, train station
|
|
||||||
{158, 34}, // Battle Tower, tall building
|
|
||||||
{160, 34}, // Rose Tower, tall building
|
|
||||||
{164, 72}, // Fields of Honor, vast field
|
|
||||||
{166, 50}, // Soothing Wetlands, muddy road
|
|
||||||
{168, 41}, // Forest of Focus, forest
|
|
||||||
{170, 49}, // Challenge Beach, seaside road
|
|
||||||
{172, 40}, // Brawlers’ Cave, cave
|
|
||||||
{174, 76}, // Challenge Road, town in the mountains
|
|
||||||
{176, 40}, // Courageous Cavern, cave
|
|
||||||
{178, 49}, // Loop Lagoon, seaside road
|
|
||||||
{180, 72}, // Training Lowlands, vast field
|
|
||||||
{182, 40}, // Warm-Up Tunnel, cave
|
|
||||||
{184, 51}, // Potbottom Desert, sand-swept road
|
|
||||||
{186, 49}, // Workout Sea, seaside road
|
|
||||||
{188, 49}, // Stepping-Stone Sea, seaside road
|
|
||||||
{190, 49}, // Insular Sea, seaside road
|
|
||||||
{192, 49}, // Honeycalm Sea, seaside road
|
|
||||||
{194, 49}, // Honeycalm Island, seaside road
|
|
||||||
{196, 29}, // Master Dojo, battling spot
|
|
||||||
{198, 34}, // Tower of Darkness, tall building
|
|
||||||
{200, 34}, // Tower of Waters, tall building
|
|
||||||
{202, 28}, // Armor Station, train station
|
|
||||||
{204, 53}, // Slippery Slope, snow-swept road
|
|
||||||
{208, 53}, // Frostpoint Field, snow-swept road
|
|
||||||
{210, 72}, // Giant’s Bed, vast field
|
|
||||||
{212, 48}, // Old Cemetery, stone-lined area
|
|
||||||
{214, 53}, // Snowslide Slope, snow-swept road
|
|
||||||
{216, 40}, // Tunnel to the Top, cave
|
|
||||||
{218, 53}, // the Path to the Peak, snow-swept road
|
|
||||||
{220, 65}, // Crown Shrine, mystical place
|
|
||||||
{222, 44}, // Giant’s Foot, tranquil road
|
|
||||||
{224, 40}, // Roaring-Sea Caves, cave
|
|
||||||
{226, 49}, // Frigid Sea, seaside road
|
|
||||||
{228, 72}, // Three-Point Pass, vast field
|
|
||||||
{230, 72}, // Ballimere Lake, vast field
|
|
||||||
{232, 40}, // Lakeside Cave, cave
|
|
||||||
{234, 72}, // Dyna Tree Hill, vast field
|
|
||||||
{236, 65}, // Rock Peak Ruins, mystical place
|
|
||||||
{238, 65}, // Iceberg Ruins, mystical place
|
|
||||||
{240, 65}, // Iron Ruins, mystical place
|
|
||||||
{242, 65}, // Split-Decision Ruins, mystical place
|
|
||||||
{244, 40}, // Max Lair, cave
|
|
||||||
{246, 28}, // Crown Tundra Station, train station
|
|
||||||
};
|
|
||||||
|
|
||||||
private static readonly HashSet<byte> PossibleGeneralLocations = new()
|
|
||||||
{
|
|
||||||
01, 02, 03, 04, 06, 08, 09,
|
|
||||||
11, 12, 16,
|
|
||||||
20, 22, 24, 28, 29,
|
|
||||||
30, 31, 33, 34, 35, 37, 38,
|
|
||||||
40, 41, 44, 47, 48, 49,
|
|
||||||
50, 51, 53,
|
|
||||||
65,
|
|
||||||
71, 72, 73, 74, 75, 76, 77, 78, 79,
|
|
||||||
};
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
private static bool IsGeneralLocationMemoryMet(int memory) => memory is (1 or 2 or 3);
|
|
||||||
internal static readonly HashSet<int> MemoryGeneral = new() { 1, 2, 3, 4, 19, 24, 31, 32, 33, 35, 36, 37, 38, 39, 42, 52, 59, 70, 86 };
|
|
||||||
private static readonly HashSet<int> MemorySpecific = new() { 6 };
|
|
||||||
private static readonly HashSet<int> MemoryMove = new() { 12, 16, 48, 49, 80, 81, 89 };
|
|
||||||
private static readonly HashSet<int> MemoryItem = new() { 5, 15, 26, 34, 40, 51, 84, 88 };
|
|
||||||
private static readonly HashSet<int> MemorySpecies = new() { 7, 9, 13, 14, 17, 21, 18, 25, 29, 44, 45, 50, 60, 70, 71, 72, 75, 82, 83, 87 };
|
|
||||||
|
|
||||||
internal static readonly ushort[] KeyItemUsableObserve6 =
|
|
||||||
{
|
|
||||||
775, // Eon Flute
|
|
||||||
};
|
|
||||||
|
|
||||||
internal static readonly Dictionary<int, ushort[]> KeyItemMemoryArgsGen6 = new()
|
|
||||||
{
|
|
||||||
{(int) Species.Shaymin, new ushort[] {466}}, // Gracidea
|
|
||||||
{(int) Species.Tornadus, new ushort[] {638}}, // Reveal Glass
|
|
||||||
{(int) Species.Thundurus, new ushort[] {638}}, // Reveal Glass
|
|
||||||
{(int) Species.Landorus, new ushort[] {638}}, // Reveal Glass
|
|
||||||
{(int) Species.Kyurem, new ushort[] {628, 629}}, // DNA Splicers
|
|
||||||
{(int) Species.Hoopa, new ushort[] {765}}, // Prison Bottle
|
|
||||||
};
|
|
||||||
|
|
||||||
internal static readonly Dictionary<int, ushort[]> KeyItemMemoryArgsGen8 = new()
|
|
||||||
{
|
|
||||||
{(int) Species.Rotom, new ushort[] {1278}}, // Rotom Catalog
|
|
||||||
{(int) Species.Kyurem, new ushort[] {628, 629}}, // DNA Splicers
|
|
||||||
{(int) Species.Necrozma, new ushort[] {943, 944, 945, 946}}, // N-Lunarizer / N-Solarizer
|
|
||||||
{(int) Species.Calyrex, new ushort[] {1590, 1591}}, // Reigns of Unity
|
|
||||||
};
|
|
||||||
|
|
||||||
public static IEnumerable<ushort> KeyItemArgValues => KeyItemUsableObserve6.Concat(KeyItemMemoryArgsGen6.Values.Concat(KeyItemMemoryArgsGen8.Values).SelectMany(z => z)).Distinct();
|
|
||||||
|
|
||||||
public static MemoryArgType GetMemoryArgType(int memory, int format)
|
|
||||||
{
|
|
||||||
if (MemoryGeneral.Contains(memory)) return MemoryArgType.GeneralLocation;
|
|
||||||
if (MemorySpecific.Contains(memory) && format == 6) return MemoryArgType.SpecificLocation;
|
|
||||||
if (MemoryItem.Contains(memory)) return MemoryArgType.Item;
|
|
||||||
if (MemoryMove.Contains(memory)) return MemoryArgType.Move;
|
|
||||||
if (MemorySpecies.Contains(memory)) return MemoryArgType.Species;
|
|
||||||
|
|
||||||
return MemoryArgType.None;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool CanHaveFeeling(int memory, int feeling)
|
|
||||||
{
|
|
||||||
if (memory >= MemoryFeelings.Length)
|
|
||||||
return false;
|
|
||||||
return (MemoryFeelings[memory] & (1 << feeling)) != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool CanHaveIntensity(int memory, int intensity)
|
|
||||||
{
|
|
||||||
if (memory >= MemoryFeelings.Length)
|
|
||||||
return false;
|
|
||||||
return MemoryMinIntensity[memory] <= intensity;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int GetRandomFeeling(int memory, int max = 24)
|
|
||||||
{
|
|
||||||
var bits = MemoryFeelings[memory];
|
|
||||||
var rnd = Util.Rand;
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
int feel = rnd.Next(max);
|
|
||||||
if ((bits & (1 << feel)) != 0)
|
|
||||||
return feel;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int GetMinimumIntensity(int memory)
|
|
||||||
{
|
|
||||||
if (memory > MemoryMinIntensity.Length)
|
|
||||||
return -1;
|
|
||||||
return MemoryMinIntensity[memory];
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IEnumerable<ushort> GetMemoryItemParams(int format)
|
|
||||||
{
|
|
||||||
return format switch
|
|
||||||
{
|
|
||||||
6 or 7 => Legal.HeldItem_AO.Distinct()
|
|
||||||
.Concat(KeyItemArgValues)
|
|
||||||
.Concat(Legal.TMHM_AO.Take(100).Select(z => (ushort)z))
|
|
||||||
.Where(z => z < Legal.MaxItemID_6_AO),
|
|
||||||
8 => Legal.HeldItem_AO.Concat(Legal.HeldItems_SWSH).Distinct()
|
|
||||||
.Concat(KeyItemArgValues)
|
|
||||||
.Concat(Legal.TMHM_AO.Take(100).Select(z => (ushort)z))
|
|
||||||
.Where(z => z < Legal.MaxItemID_8_R2),
|
|
||||||
_ => System.Array.Empty<ushort>(),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public readonly struct MemoryVariableSet
|
|
||||||
{
|
|
||||||
public readonly string Handler;
|
|
||||||
|
|
||||||
public readonly int MemoryID;
|
|
||||||
public readonly int Variable;
|
|
||||||
public readonly int Intensity;
|
|
||||||
public readonly int Feeling;
|
|
||||||
|
|
||||||
private MemoryVariableSet(string handler, int m, int v, int i, int f)
|
|
||||||
{
|
|
||||||
Handler = handler;
|
|
||||||
MemoryID = m;
|
|
||||||
Variable = v;
|
|
||||||
Intensity = i;
|
|
||||||
Feeling = f;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static MemoryVariableSet Read(ITrainerMemories pkm, int handler) => handler switch
|
|
||||||
{
|
|
||||||
0 => new MemoryVariableSet(LegalityCheckStrings.L_XOT, pkm.OT_Memory, pkm.OT_TextVar, pkm.OT_Intensity, pkm.OT_Feeling), // OT
|
|
||||||
1 => new MemoryVariableSet(LegalityCheckStrings.L_XHT, pkm.HT_Memory, pkm.HT_TextVar, pkm.HT_Intensity, pkm.HT_Feeling), // HT
|
|
||||||
_ => new MemoryVariableSet(LegalityCheckStrings.L_XOT, 0, 0, 0, 0),
|
|
||||||
};
|
|
||||||
|
|
||||||
public bool Equals(MemoryVariableSet v) => v.Handler == Handler
|
|
||||||
&& v.MemoryID == MemoryID
|
|
||||||
&& v.Variable == Variable
|
|
||||||
&& v.Intensity == Intensity
|
|
||||||
&& v.Feeling == Feeling;
|
|
||||||
|
|
||||||
public override bool Equals(object obj) => obj is MemoryVariableSet v && Equals(v);
|
|
||||||
public override int GetHashCode() => -1;
|
|
||||||
public static bool operator ==(MemoryVariableSet left, MemoryVariableSet right) => left.Equals(right);
|
|
||||||
public static bool operator !=(MemoryVariableSet left, MemoryVariableSet right) => !(left == right);
|
|
||||||
}
|
|
||||||
}
|
|
38
PKHeX.Core/Legality/Restrictions/Memories/Memories.cs
Normal file
38
PKHeX.Core/Legality/Restrictions/Memories/Memories.cs
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace PKHeX.Core
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Generation 6 Memory parameters & validation
|
||||||
|
/// </summary>
|
||||||
|
public static class Memories
|
||||||
|
{
|
||||||
|
public static readonly MemoryContext6 Memory6 = new();
|
||||||
|
public static readonly MemoryContext8 Memory8 = new();
|
||||||
|
|
||||||
|
internal static readonly HashSet<int> MemoryGeneral = new() { 1, 2, 3, 4, 19, 24, 31, 32, 33, 35, 36, 37, 38, 39, 42, 52, 59, 70, 86 };
|
||||||
|
private static readonly HashSet<int> MemorySpecific = new() { 6 };
|
||||||
|
private static readonly HashSet<int> MemoryMove = new() { 12, 16, 48, 49, 80, 81, 89 };
|
||||||
|
private static readonly HashSet<int> MemoryItem = new() { 5, 15, 26, 34, 40, 51, 84, 88 };
|
||||||
|
private static readonly HashSet<int> MemorySpecies = new() { 7, 9, 13, 14, 17, 21, 18, 25, 29, 44, 45, 50, 60, 70, 71, 72, 75, 82, 83, 87 };
|
||||||
|
|
||||||
|
public static MemoryArgType GetMemoryArgType(int memory, int format)
|
||||||
|
{
|
||||||
|
if (MemoryGeneral.Contains(memory)) return MemoryArgType.GeneralLocation;
|
||||||
|
if (MemorySpecific.Contains(memory) && format == 6) return MemoryArgType.SpecificLocation;
|
||||||
|
if (MemoryItem.Contains(memory)) return MemoryArgType.Item;
|
||||||
|
if (MemoryMove.Contains(memory)) return MemoryArgType.Move;
|
||||||
|
if (MemorySpecies.Contains(memory)) return MemoryArgType.Species;
|
||||||
|
|
||||||
|
return MemoryArgType.None;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MemoryContext GetContext(int format) => format switch
|
||||||
|
{
|
||||||
|
6 or 7 => Memory6,
|
||||||
|
_ => Memory8,
|
||||||
|
};
|
||||||
|
|
||||||
|
public static IEnumerable<ushort> GetMemoryItemParams(int format) => GetContext(format).GetMemoryItemParams();
|
||||||
|
}
|
||||||
|
}
|
29
PKHeX.Core/Legality/Restrictions/Memories/MemoryContext.cs
Normal file
29
PKHeX.Core/Legality/Restrictions/Memories/MemoryContext.cs
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace PKHeX.Core
|
||||||
|
{
|
||||||
|
public abstract class MemoryContext
|
||||||
|
{
|
||||||
|
public abstract IEnumerable<ushort> GetMemoryItemParams();
|
||||||
|
public abstract IEnumerable<ushort> GetKeyItemParams();
|
||||||
|
|
||||||
|
public abstract bool CanUseItemGeneric(int item);
|
||||||
|
public abstract bool IsUsedKeyItemUnspecific(int item);
|
||||||
|
public abstract bool IsUsedKeyItemSpecific(int item, int species);
|
||||||
|
public abstract bool CanBuyItem(int item, GameVersion version);
|
||||||
|
public virtual bool CanWinRotoLoto(int item) => false;
|
||||||
|
public virtual bool CanPlantBerry(int item) => false;
|
||||||
|
public abstract bool CanHoldItem(int item);
|
||||||
|
|
||||||
|
public abstract bool CanObtainMemory(int memory);
|
||||||
|
public abstract bool CanObtainMemoryOT(GameVersion pkmVersion, int memory);
|
||||||
|
public abstract bool CanObtainMemoryHT(GameVersion pkmVersion, int memory);
|
||||||
|
|
||||||
|
public abstract bool HasPokeCenter(GameVersion version, int location);
|
||||||
|
public abstract bool IsInvalidGeneralLocationMemoryValue(int memory, int variable, IEncounterTemplate enc, PKM pk);
|
||||||
|
|
||||||
|
public abstract bool CanHaveIntensity(int memory, int intensity);
|
||||||
|
public abstract bool CanHaveFeeling(int memory, int feeling);
|
||||||
|
public abstract int GetMinimumIntensity(int memory);
|
||||||
|
}
|
||||||
|
}
|
116
PKHeX.Core/Legality/Restrictions/Memories/MemoryContext6.cs
Normal file
116
PKHeX.Core/Legality/Restrictions/Memories/MemoryContext6.cs
Normal file
|
@ -0,0 +1,116 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace PKHeX.Core
|
||||||
|
{
|
||||||
|
public sealed partial class MemoryContext6 : MemoryContext
|
||||||
|
{
|
||||||
|
private const int MAX_MEMORY_ID_XY = 64;
|
||||||
|
private const int MAX_MEMORY_ID_AO = 69;
|
||||||
|
|
||||||
|
private static ICollection<int> GetPokeCenterLocations(GameVersion game)
|
||||||
|
{
|
||||||
|
return GameVersion.XY.Contains(game) ? LocationsWithPokeCenter_XY : LocationsWithPokeCenter_AO;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool GetHasPokeCenterLocation(GameVersion game, int loc)
|
||||||
|
{
|
||||||
|
if (game == GameVersion.Any)
|
||||||
|
return GetHasPokeCenterLocation(GameVersion.X, loc) || GetHasPokeCenterLocation(GameVersion.AS, loc);
|
||||||
|
return GetPokeCenterLocations(game).Contains(loc);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int GetMemoryRarity(int memory) => (uint)memory >= MemoryRandChance.Length ? -1 : MemoryRandChance[memory];
|
||||||
|
|
||||||
|
public override IEnumerable<ushort> GetKeyItemParams() => KeyItemUsableObserve6.Concat(KeyItemMemoryArgsGen6.Values.SelectMany(z => z)).Distinct();
|
||||||
|
|
||||||
|
public override bool CanUseItemGeneric(int item)
|
||||||
|
{
|
||||||
|
// Key Item usage while in party on another species.
|
||||||
|
if (KeyItemUsableObserve6.Contains((ushort)item))
|
||||||
|
return true;
|
||||||
|
if (KeyItemMemoryArgsGen6.Values.Any(z => z.Contains((ushort)item)))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override IEnumerable<ushort> GetMemoryItemParams() => Legal.HeldItem_AO.Distinct()
|
||||||
|
.Concat(GetKeyItemParams())
|
||||||
|
.Concat(Legal.TMHM_AO.Take(100).Select(z => (ushort)z))
|
||||||
|
.Where(z => z < Legal.MaxItemID_6_AO);
|
||||||
|
|
||||||
|
public override bool IsUsedKeyItemUnspecific(int item) => KeyItemUsableObserve6.Contains((ushort)item);
|
||||||
|
public override bool IsUsedKeyItemSpecific(int item, int species) => KeyItemMemoryArgsGen6.TryGetValue(species, out var value) && value.Contains((ushort)item);
|
||||||
|
|
||||||
|
public override bool CanPlantBerry(int item) => Legal.Pouch_Berry_XY.Contains((ushort)item);
|
||||||
|
public override bool CanHoldItem(int item) => Legal.HeldItem_AO.Contains((ushort)item);
|
||||||
|
|
||||||
|
public override bool CanObtainMemoryOT(GameVersion pkmVersion, int memory) => pkmVersion switch
|
||||||
|
{
|
||||||
|
GameVersion.X or GameVersion.Y => CanObtainMemoryXY(memory),
|
||||||
|
GameVersion.OR or GameVersion.AS => CanObtainMemoryAO(memory),
|
||||||
|
_ => false,
|
||||||
|
};
|
||||||
|
|
||||||
|
public override bool CanObtainMemory(int memory) => memory <= MAX_MEMORY_ID_AO;
|
||||||
|
public override bool HasPokeCenter(GameVersion version, int location) => GetHasPokeCenterLocation(version, location);
|
||||||
|
|
||||||
|
public override bool IsInvalidGeneralLocationMemoryValue(int memory, int variable, IEncounterTemplate enc, PKM pk)
|
||||||
|
{
|
||||||
|
return false; // todo
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool CanObtainMemoryAO(int memory) => memory <= MAX_MEMORY_ID_AO && !Memory_NotAO.Contains(memory);
|
||||||
|
private static bool CanObtainMemoryXY(int memory) => memory <= MAX_MEMORY_ID_XY && !Memory_NotXY.Contains(memory);
|
||||||
|
public override bool CanObtainMemoryHT(GameVersion pkmVersion, int memory) => CanObtainMemory(memory);
|
||||||
|
|
||||||
|
public override bool CanBuyItem(int item, GameVersion version)
|
||||||
|
{
|
||||||
|
if (version is GameVersion.Any)
|
||||||
|
return PurchaseableItemAO.Contains((ushort)item) || PurchaseableItemXY.Contains((ushort)item);
|
||||||
|
if (version is GameVersion.X or GameVersion.Y)
|
||||||
|
return PurchaseableItemXY.Contains((ushort)item);
|
||||||
|
if (version is GameVersion.AS or GameVersion.OR)
|
||||||
|
return PurchaseableItemAO.Contains((ushort)item);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool CanHaveFeeling6(int memory, int feeling)
|
||||||
|
{
|
||||||
|
if (memory >= MemoryFeelings.Length)
|
||||||
|
return false;
|
||||||
|
return (MemoryFeelings[memory] & (1 << feeling)) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool CanHaveIntensity6(int memory, int intensity)
|
||||||
|
{
|
||||||
|
if (memory >= MemoryFeelings.Length)
|
||||||
|
return false;
|
||||||
|
return MemoryMinIntensity[memory] <= intensity;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int GetRandomFeeling6(int memory, int max = 24)
|
||||||
|
{
|
||||||
|
var bits = MemoryFeelings[memory];
|
||||||
|
var rnd = Util.Rand;
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
int feel = rnd.Next(max);
|
||||||
|
if ((bits & (1 << feel)) != 0)
|
||||||
|
return feel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int GetMinimumIntensity6(int memory)
|
||||||
|
{
|
||||||
|
if (memory >= MemoryMinIntensity.Length)
|
||||||
|
return -1;
|
||||||
|
return MemoryMinIntensity[memory];
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool CanHaveIntensity(int memory, int intensity) => CanHaveIntensity6(memory, intensity);
|
||||||
|
public override bool CanHaveFeeling(int memory, int feeling) => CanHaveFeeling6(memory, feeling);
|
||||||
|
public override int GetMinimumIntensity(int memory) => GetMinimumIntensity6(memory);
|
||||||
|
}
|
||||||
|
}
|
163
PKHeX.Core/Legality/Restrictions/Memories/MemoryContext6Data.cs
Normal file
163
PKHeX.Core/Legality/Restrictions/Memories/MemoryContext6Data.cs
Normal file
|
@ -0,0 +1,163 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace PKHeX.Core
|
||||||
|
{
|
||||||
|
// data tables stored separately!
|
||||||
|
public partial class MemoryContext6
|
||||||
|
{
|
||||||
|
private static readonly int[] Memory_NotXY =
|
||||||
|
{
|
||||||
|
65, // {0} was with {1} when (he/she) built a Secret Base. {4} that {3}.
|
||||||
|
66, // {0} participated in a contest with {1} and impressed many people. {4} that {3}.
|
||||||
|
67, // {0} participated in a contest with {1} and won the title. {4} that {3}.
|
||||||
|
68, // {0} soared through the sky with {1} and went to many different places. {4} that {3}.
|
||||||
|
69, // {1} asked {0} to dive. Down it went, deep into the ocean, to explore the bottom of the sea. {4} that {3}.
|
||||||
|
};
|
||||||
|
|
||||||
|
private static readonly int[] Memory_NotAO =
|
||||||
|
{
|
||||||
|
11, // {0} went clothes shopping with {1}. {4} that {3}.
|
||||||
|
43, // {0} was impressed by the speed of the train it took with {1}. {4} that {3}.
|
||||||
|
44, // {0} encountered {2} with {1} using the Poké Radar. {4} that {3}.
|
||||||
|
56, // {0} was with {1} when (he/she) went to a boutique and tried on clothes, but (he/she) left the boutique without buying anything. {4} that {3}.
|
||||||
|
57, // {0} went to a nice restaurant with {1} and ate until it got totally full. {4} that {3}.
|
||||||
|
62, // {0} saw itself in a mirror in a mirror cave that it went to with {1}. {4} that {3}.
|
||||||
|
};
|
||||||
|
|
||||||
|
internal static readonly int[][] MoveSpecificMemories =
|
||||||
|
{
|
||||||
|
new[] {
|
||||||
|
20, // {0} surfed across the water, carrying {1} on its back. {4} that {3}.
|
||||||
|
24, // {0} flew, carrying {1} on its back, to {2}. {4} that {3}.
|
||||||
|
35, // {0} proudly used Strength at {1}’s instruction in... {2}. {4} that {3}.
|
||||||
|
36, // {0} proudly used Cut at {1}’s instruction in... {2}. {4} that {3}.
|
||||||
|
37, // {0} shattered rocks to its heart’s content at {1}’s instruction in... {2}. {4} that {3}.
|
||||||
|
38, // {0} used Waterfall while carrying {1} on its back in... {2}. {4} that {3}.
|
||||||
|
69, // {1} asked {0} to dive. Down it went, deep into the ocean, to explore the bottom of the sea. {4} that {3}.
|
||||||
|
},
|
||||||
|
new[] { 57, 19, 70, 15, 249, 127, 291}, // Move IDs
|
||||||
|
};
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Kalos locations with a Pokémon Center
|
||||||
|
/// </summary>
|
||||||
|
private static readonly int[] LocationsWithPokeCenter_XY =
|
||||||
|
{
|
||||||
|
// Kalos locations with a PKMN CENTER
|
||||||
|
018, // Santalune City
|
||||||
|
022, // Lumiose City
|
||||||
|
030, // Camphrier Town
|
||||||
|
040, // Cyllage City
|
||||||
|
044, // Ambrette Town
|
||||||
|
052, // Geosenge Towny
|
||||||
|
058, // Shalour City
|
||||||
|
064, // Coumarine City
|
||||||
|
070, // Laverre City
|
||||||
|
076, // Dendemille Town
|
||||||
|
086, // Anistar City
|
||||||
|
090, // Couriway Town
|
||||||
|
094, // Snowbelle City
|
||||||
|
106, // Pokémon League (X/Y)
|
||||||
|
};
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Hoenn locations with a Pokémon Center
|
||||||
|
/// </summary>
|
||||||
|
private static readonly int[] LocationsWithPokeCenter_AO =
|
||||||
|
{
|
||||||
|
// Hoenn locations with a PKMN CENTER
|
||||||
|
172, // Oldale Town
|
||||||
|
174, // Dewford Town
|
||||||
|
176, // Lavaridge Town
|
||||||
|
178, // Fallarbor Town
|
||||||
|
180, // Verdanturf Town
|
||||||
|
182, // Pacifidlog Town
|
||||||
|
184, // Petalburg City
|
||||||
|
186, // Slateport City
|
||||||
|
188, // Mauville City
|
||||||
|
190, // Rustboro City
|
||||||
|
192, // Fortree City
|
||||||
|
194, // Lilycove City
|
||||||
|
196, // Mossdeep City
|
||||||
|
198, // Sootopolis City
|
||||||
|
200, // Ever Grande City
|
||||||
|
202, // Pokémon League (OR/AS)
|
||||||
|
};
|
||||||
|
|
||||||
|
private static readonly byte[] MemoryMinIntensity =
|
||||||
|
{
|
||||||
|
0, 1, 1, 1, 1, 2, 2, 2, 2, 2,
|
||||||
|
2, 2, 2, 2, 3, 3, 3, 3, 4, 4,
|
||||||
|
3, 3, 3, 3, 3, 3, 3, 4, 5, 5,
|
||||||
|
5, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||||
|
3, 3, 1, 3, 2, 2, 4, 3, 4, 4,
|
||||||
|
4, 4, 2, 4, 2, 4, 3, 3, 4, 2,
|
||||||
|
3, 3, 3, 3, 3, 2, 3, 4, 4, 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
private static readonly byte[] MemoryRandChance =
|
||||||
|
{
|
||||||
|
000, 100, 100, 100, 100, 005, 005, 005, 005, 005,
|
||||||
|
005, 005, 005, 005, 010, 020, 010, 001, 050, 030,
|
||||||
|
005, 005, 020, 005, 005, 005, 001, 050, 100, 050,
|
||||||
|
050, 002, 002, 005, 005, 005, 005, 005, 005, 002,
|
||||||
|
020, 020, 005, 010, 001, 001, 050, 030, 020, 020,
|
||||||
|
010, 010, 001, 010, 001, 050, 030, 030, 030, 002,
|
||||||
|
050, 020, 020, 020, 020, 010, 010, 050, 020, 005,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 24bits of flags allowing certain feelings for a given memory index.
|
||||||
|
/// </summary>
|
||||||
|
private static readonly uint[] MemoryFeelings =
|
||||||
|
{
|
||||||
|
0x000000, 0x04CBFD, 0x004BFD, 0x04CBFD, 0x04CBFD, 0xFFFBFB, 0x84FFF9, 0x47FFFF, 0xBF7FFA, 0x7660B0,
|
||||||
|
0x80BDF9, 0x88FB7A, 0x083F79, 0x0001FE, 0xCFEFFF, 0x84EBAF, 0xB368B0, 0x091F7E, 0x0320A0, 0x080DDD,
|
||||||
|
0x081A7B, 0x404030, 0x0FFFFF, 0x9A08BC, 0x089A7B, 0x0032AA, 0x80FF7A, 0x0FFFFF, 0x0805FD, 0x098278,
|
||||||
|
0x0B3FFF, 0x8BBFFA, 0x8BBFFE, 0x81A97C, 0x8BB97C, 0x8BBF7F, 0x8BBF7F, 0x8BBF7F, 0x8BBF7F, 0xAC3ABE,
|
||||||
|
0xBFFFFF, 0x8B837C, 0x848AFA, 0x88FFFE, 0x8B0B7C, 0xB76AB2, 0x8B1FFF, 0xBE7AB8, 0xB77EB8, 0x8C9FFD,
|
||||||
|
0xBF9BFF, 0xF408B0, 0xBCFE7A, 0x8F3F72, 0x90DB7A, 0xBCEBFF, 0xBC5838, 0x9C3FFE, 0x9CFFFF, 0x96D83A,
|
||||||
|
0xB770B0, 0x881F7A, 0x839F7A, 0x839F7A, 0x839F7A, 0x53897F, 0x41BB6F, 0x0C35FF, 0x8BBF7F, 0x8BBF7F,
|
||||||
|
};
|
||||||
|
|
||||||
|
private static readonly Dictionary<int, ushort[]> KeyItemMemoryArgsGen6 = new()
|
||||||
|
{
|
||||||
|
{(int) Species.Shaymin, new ushort[] {466}}, // Gracidea
|
||||||
|
{(int) Species.Tornadus, new ushort[] {638}}, // Reveal Glass
|
||||||
|
{(int) Species.Thundurus, new ushort[] {638}}, // Reveal Glass
|
||||||
|
{(int) Species.Landorus, new ushort[] {638}}, // Reveal Glass
|
||||||
|
{(int) Species.Kyurem, new ushort[] {628, 629}}, // DNA Splicers
|
||||||
|
{(int) Species.Hoopa, new ushort[] {765}}, // Prison Bottle
|
||||||
|
};
|
||||||
|
|
||||||
|
private static readonly ushort[] KeyItemUsableObserve6 =
|
||||||
|
{
|
||||||
|
775, // Eon Flute
|
||||||
|
};
|
||||||
|
|
||||||
|
private static readonly HashSet<ushort> PurchaseableItemXY = new()
|
||||||
|
{
|
||||||
|
002, 003, 004, 006, 007, 008, 009, 010, 011, 012,
|
||||||
|
013, 014, 015, 017, 018, 019, 020, 021, 022, 023,
|
||||||
|
024, 025, 026, 027, 028, 034, 035, 036, 037, 045,
|
||||||
|
046, 047, 048, 049, 052, 055, 056, 057, 058, 059,
|
||||||
|
060, 061, 062, 076, 077, 078, 079, 082, 084, 085,
|
||||||
|
254, 255, 314, 315, 316, 317, 318, 319, 320, 334,
|
||||||
|
338, 341, 342, 343, 345, 347, 352, 355, 360, 364,
|
||||||
|
365, 377, 379, 395, 402, 403, 405, 411, 618,
|
||||||
|
};
|
||||||
|
|
||||||
|
private static readonly HashSet<ushort> PurchaseableItemAO = new()
|
||||||
|
{
|
||||||
|
002, 003, 004, 006, 007, 008, 009, 010, 011, 013,
|
||||||
|
014, 015, 017, 018, 019, 020, 021, 022, 023, 024,
|
||||||
|
025, 026, 027, 028, 034, 035, 036, 037, 045, 046,
|
||||||
|
047, 048, 049, 052, 055, 056, 057, 058, 059, 060,
|
||||||
|
061, 062, 063, 064, 076, 077, 078, 079, 254, 255,
|
||||||
|
314, 315, 316, 317, 318, 319, 320, 328, 336, 341,
|
||||||
|
342, 343, 344, 347, 352, 360, 365, 367, 369, 374,
|
||||||
|
379, 384, 395, 398, 400, 403, 405, 409, 577, 692,
|
||||||
|
694,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
112
PKHeX.Core/Legality/Restrictions/Memories/MemoryContext8.cs
Normal file
112
PKHeX.Core/Legality/Restrictions/Memories/MemoryContext8.cs
Normal file
|
@ -0,0 +1,112 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace PKHeX.Core
|
||||||
|
{
|
||||||
|
public sealed partial class MemoryContext8 : MemoryContext
|
||||||
|
{
|
||||||
|
private const int MAX_MEMORY_ID_SWSH = 89;
|
||||||
|
|
||||||
|
private static ICollection<int> GetPokeCenterLocations(GameVersion game)
|
||||||
|
{
|
||||||
|
return GameVersion.SWSH.Contains(game) ? LocationsWithPokeCenter_SWSH : Array.Empty<int>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool GetHasPokeCenterLocation(GameVersion game, int loc)
|
||||||
|
{
|
||||||
|
if (game == GameVersion.Any)
|
||||||
|
return GetHasPokeCenterLocation(GameVersion.SW, loc);
|
||||||
|
return GetPokeCenterLocations(game).Contains(loc);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override IEnumerable<ushort> GetKeyItemParams() => (KeyItemMemoryArgsGen8.Values).SelectMany(z => z).Distinct();
|
||||||
|
|
||||||
|
public override IEnumerable<ushort> GetMemoryItemParams() => Legal.HeldItem_AO.Concat(Legal.HeldItems_SWSH).Distinct()
|
||||||
|
.Concat(GetKeyItemParams())
|
||||||
|
.Concat(Legal.TMHM_AO.Take(100).Select(z => (ushort)z))
|
||||||
|
.Where(z => z < Legal.MaxItemID_8_R2);
|
||||||
|
|
||||||
|
public override bool CanUseItemGeneric(int item) => true; // todo
|
||||||
|
|
||||||
|
public override bool IsUsedKeyItemUnspecific(int item) => false;
|
||||||
|
public override bool IsUsedKeyItemSpecific(int item, int species) => KeyItemMemoryArgsGen8.TryGetValue(species, out var value) && value.Contains((ushort)item);
|
||||||
|
public override bool CanHoldItem(int item) => Legal.HeldItems_SWSH.Contains((ushort)item);
|
||||||
|
|
||||||
|
public override bool CanObtainMemoryOT(GameVersion pkmVersion, int memory) => pkmVersion switch
|
||||||
|
{
|
||||||
|
GameVersion.SW or GameVersion.SH => CanObtainMemorySWSH(memory),
|
||||||
|
_ => false,
|
||||||
|
};
|
||||||
|
|
||||||
|
public override bool CanObtainMemoryHT(GameVersion pkmVersion, int memory) => CanObtainMemorySWSH(memory);
|
||||||
|
|
||||||
|
public override bool CanObtainMemory(int memory) => CanObtainMemorySWSH(memory);
|
||||||
|
public override bool HasPokeCenter(GameVersion version, int location) => GetHasPokeCenterLocation(version, location);
|
||||||
|
|
||||||
|
public override bool IsInvalidGeneralLocationMemoryValue(int memory, int variable, IEncounterTemplate enc, PKM pk)
|
||||||
|
{
|
||||||
|
if (!Memories.MemoryGeneral.Contains(memory))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (memory is 1 or 2 or 3) // Encounter only
|
||||||
|
return IsInvalidGenLoc8(memory, pk.Met_Location, pk.Egg_Location, variable, enc);
|
||||||
|
return IsInvalidGenLoc8Other(memory, variable);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool CanObtainMemorySWSH(int memory) => memory <= MAX_MEMORY_ID_SWSH && !Memory_NotSWSH.Contains(memory);
|
||||||
|
|
||||||
|
public override bool CanWinRotoLoto(int item) => true;
|
||||||
|
|
||||||
|
public override bool CanBuyItem(int item, GameVersion version)
|
||||||
|
{
|
||||||
|
if (item is 1085) // Bob's Food Tin
|
||||||
|
return version is GameVersion.SW or GameVersion.Any;
|
||||||
|
if (item is 1086) // Bach's Food Tin
|
||||||
|
return version is GameVersion.SH or GameVersion.Any;
|
||||||
|
return PurchaseableItemSWSH.Contains((ushort)item);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool IsInvalidGenLoc8(int memory, int loc, int egg, int variable, IEncounterTemplate enc)
|
||||||
|
{
|
||||||
|
if (variable > 255)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
switch (memory)
|
||||||
|
{
|
||||||
|
case 1 when enc.EggEncounter:
|
||||||
|
case 2 when !enc.EggEncounter:
|
||||||
|
case 3 when enc is not (EncounterTrade or EncounterStatic {Gift: true} or WC8 {IsHOMEGift: false}):
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
var arg = (byte)variable;
|
||||||
|
if (loc > 255) // gift
|
||||||
|
return memory != 3 || !PossibleGeneralLocations8.Contains(arg);
|
||||||
|
if (memory == 2 && egg == 0)
|
||||||
|
return true;
|
||||||
|
if (loc is Encounters8Nest.SharedNest)
|
||||||
|
return !PossibleGeneralLocations8.Contains(arg) || arg is 79; // dangerous place - all locations are Y-Comm locked
|
||||||
|
if (SingleGenLocAreas.TryGetValue((byte)loc, out var val))
|
||||||
|
return arg != val;
|
||||||
|
if (MultiGenLocAreas.TryGetValue((byte)loc, out var arr))
|
||||||
|
return !arr.Contains(arg);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool IsInvalidGenLoc8Other(int memory, int variable)
|
||||||
|
{
|
||||||
|
if (variable > byte.MaxValue)
|
||||||
|
return true;
|
||||||
|
var arg = (byte)variable;
|
||||||
|
return memory switch
|
||||||
|
{
|
||||||
|
_ => !PossibleGeneralLocations8.Contains(arg),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool CanHaveIntensity(int memory, int intensity) => true; // todo
|
||||||
|
public override bool CanHaveFeeling(int memory, int feeling) => true; // todo
|
||||||
|
public override int GetMinimumIntensity(int memory) => 3; // todo
|
||||||
|
}
|
||||||
|
}
|
230
PKHeX.Core/Legality/Restrictions/Memories/MemoryContext8Data.cs
Normal file
230
PKHeX.Core/Legality/Restrictions/Memories/MemoryContext8Data.cs
Normal file
|
@ -0,0 +1,230 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace PKHeX.Core
|
||||||
|
{
|
||||||
|
public partial class MemoryContext8
|
||||||
|
{
|
||||||
|
private static readonly int[] Memory_NotSWSH =
|
||||||
|
{
|
||||||
|
// There's probably more. Send a pull request!
|
||||||
|
20, // {0} surfed across the water, carrying {1} on its back. {4} that {3}.
|
||||||
|
24, // {0} flew, carrying {1} on its back, to {2}. {4} that {3}.
|
||||||
|
35, // {0} proudly used Strength at {1}’s instruction in... {2}. {4} that {3}.
|
||||||
|
36, // {0} proudly used Cut at {1}’s instruction in... {2}. {4} that {3}.
|
||||||
|
37, // {0} shattered rocks to its heart’s content at {1}’s instruction in... {2}. {4} that {3}.
|
||||||
|
38, // {0} used Waterfall while carrying {1} on its back in... {2}. {4} that {3}.
|
||||||
|
69, // {1} asked {0} to dive. Down it went, deep into the ocean, to explore the bottom of the sea. {4} that {3}.
|
||||||
|
};
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Galar locations with a Pokémon Center
|
||||||
|
/// </summary>
|
||||||
|
private static readonly int[] LocationsWithPokeCenter_SWSH =
|
||||||
|
{
|
||||||
|
14, 20, 34, 44, 56, 70, 78, 96, 102, 110,
|
||||||
|
};
|
||||||
|
|
||||||
|
private static readonly Dictionary<int, ushort[]> KeyItemMemoryArgsGen8 = new()
|
||||||
|
{
|
||||||
|
{(int) Species.Rotom, new ushort[] {1278}}, // Rotom Catalog
|
||||||
|
{(int) Species.Kyurem, new ushort[] {628, 629}}, // DNA Splicers
|
||||||
|
{(int) Species.Necrozma, new ushort[] {943, 944, 945, 946}}, // N-Lunarizer / N-Solarizer
|
||||||
|
{(int) Species.Calyrex, new ushort[] {1590, 1591}}, // Reigns of Unity
|
||||||
|
};
|
||||||
|
|
||||||
|
private static readonly HashSet<ushort> PurchaseableItemSWSH = new(Legal.TR_SWSH)
|
||||||
|
{
|
||||||
|
0002, 0003, 0004, 0006, 0007, 0008, 0009, 0010, 0011, 0013,
|
||||||
|
0014, 0015, 0017, 0018, 0019, 0020, 0021, 0022, 0023, 0024,
|
||||||
|
0025, 0026, 0027, 0028, 0033, 0034, 0035, 0036, 0037, 0042,
|
||||||
|
0045, 0046, 0047, 0048, 0049, 0050, 0051, 0052, 0055, 0056,
|
||||||
|
0057, 0058, 0059, 0060, 0061, 0062, 0063, 0076, 0077, 0079,
|
||||||
|
0089, 0149, 0150, 0151, 0155, 0214, 0215, 0219, 0220, 0254,
|
||||||
|
0255, 0269, 0270, 0271, 0275, 0280, 0287, 0289, 0290, 0291,
|
||||||
|
0292, 0293, 0294, 0297, 0314, 0315, 0316, 0317, 0318, 0319,
|
||||||
|
0320, 0321, 0325, 0326, 0541, 0542, 0545, 0546, 0547, 0639,
|
||||||
|
0640, 0645, 0646, 0647, 0648, 0649, 0795, 0846, 0879, 1084,
|
||||||
|
1087, 1088, 1089, 1090, 1091, 1094, 1095, 1097, 1098, 1099,
|
||||||
|
1118, 1119, 1121, 1122, 1231, 1232, 1233, 1234, 1235, 1236,
|
||||||
|
1237, 1238, 1239, 1240, 1241, 1242, 1243, 1244, 1245, 1246,
|
||||||
|
1247, 1248, 1249, 1250, 1251, 1252, 1256, 1257, 1258, 1259,
|
||||||
|
1260, 1261, 1262, 1263,
|
||||||
|
};
|
||||||
|
|
||||||
|
// {met, values allowed}
|
||||||
|
private static readonly Dictionary<byte, byte[]> MultiGenLocAreas = new()
|
||||||
|
{
|
||||||
|
// town of Postwick
|
||||||
|
// first town, at home, friend's house
|
||||||
|
{6, new byte[] {1, 2, 3}},
|
||||||
|
|
||||||
|
// town of Wedgehurst
|
||||||
|
// someone's house, boutique, simple town, Pokémon Center
|
||||||
|
{14, new byte[] {4, 6, 8, 9}},
|
||||||
|
|
||||||
|
// Route 2
|
||||||
|
// lab, tranquil road, lakeside road
|
||||||
|
{18, new byte[] {16, 44, 71}},
|
||||||
|
|
||||||
|
// city of Motostoke
|
||||||
|
// boutique, Pokémon Center, hotel, Pokémon Gym, stylish café, hair salon, town with a mysterious air
|
||||||
|
{20, new byte[] {6, 9, 11, 20, 24, 30, 35}},
|
||||||
|
|
||||||
|
// Motostoke Stadium
|
||||||
|
// Pokémon Gym, stadium
|
||||||
|
{24, new byte[] {20, 73}},
|
||||||
|
|
||||||
|
// town of Turffield
|
||||||
|
// Pokémon Center, town with a mysterious air
|
||||||
|
{34, new byte[] {9, 12}},
|
||||||
|
|
||||||
|
// Route 5
|
||||||
|
// tranquil road, Pokémon Nursery
|
||||||
|
{40, new byte[] {44, 74}},
|
||||||
|
|
||||||
|
// town of Hulbury
|
||||||
|
// someone’s house, Pokémon Center, restaurant, seaside town
|
||||||
|
{44, new byte[] {4, 9, 31, 33}},
|
||||||
|
|
||||||
|
// city of Hammerlocke
|
||||||
|
// someone’s house, boutique, Pokémon Center, Pokémon Gym, stylish café, hair salon, town with a mysterious air
|
||||||
|
{56, new byte[] {4, 6, 9, 20, 24, 30, 35}},
|
||||||
|
|
||||||
|
// town of Stow-on-Side
|
||||||
|
// someone’s house, Pokémon Center, town in the mountains
|
||||||
|
{70, new byte[] {4, 9, 76}},
|
||||||
|
|
||||||
|
// town of Ballonlea
|
||||||
|
// someone’s house, Pokémon Center, town with a mysterious air
|
||||||
|
{78, new byte[] {4, 9, 12}},
|
||||||
|
|
||||||
|
// town of Circhester
|
||||||
|
// someone’s house, boutique, Pokémon Center, hotel, hair salon, restaurant, snowcapped town
|
||||||
|
{96, new byte[] {4, 6, 9, 11, 30, 31, 37}},
|
||||||
|
|
||||||
|
// town of Spikemuth
|
||||||
|
// Pokémon Center, run-down town
|
||||||
|
{102, new byte[] {9, 77}},
|
||||||
|
|
||||||
|
// city of Wyndon
|
||||||
|
// someone’s house, boutique, Pokémon Center, hotel, large town, stylish café, hair salon
|
||||||
|
{110, new byte[] {4, 6, 9, 11, 22, 24, 30}},
|
||||||
|
|
||||||
|
// town of Freezington
|
||||||
|
// someone’s house, snowcapped town
|
||||||
|
{206, new byte[] {04, 37}},
|
||||||
|
};
|
||||||
|
|
||||||
|
// {met, value allowed}
|
||||||
|
private static readonly Dictionary<byte, byte> SingleGenLocAreas = new()
|
||||||
|
{
|
||||||
|
{008, 41}, // Slumbering Weald, forest
|
||||||
|
{012, 44}, // Route 1, tranquil road
|
||||||
|
{016, 28}, // Wedgehurst Station, train station
|
||||||
|
{022, 28}, // Motostoke Station, train station
|
||||||
|
{028, 44}, // Route 3, tranquil road
|
||||||
|
{030, 75}, // Galar Mine, mine
|
||||||
|
{032, 44}, // Route 4, tranquil road
|
||||||
|
{036, 73}, // Turffield Stadium, stadium
|
||||||
|
{046, 28}, // Hulbury Station, train station
|
||||||
|
{048, 73}, // Hulbury Stadium, stadium
|
||||||
|
{052, 35}, // Motostoke Outskirts, town with a mysterious air
|
||||||
|
{054, 75}, // Galar Mine No. 2, mine
|
||||||
|
{058, 28}, // Hammerlocke Station, train station
|
||||||
|
{060, 73}, // Hammerlocke Stadium, stadium
|
||||||
|
{064, 79}, // Energy Plant, dangerous place
|
||||||
|
{066, 79}, // the tower summit, dangerous place
|
||||||
|
{068, 47}, // Route 6, rugged mountain pass
|
||||||
|
{072, 73}, // Stow-on-Side Stadium, stadium
|
||||||
|
{076, 41}, // Glimwood Tangle, forest
|
||||||
|
{080, 73}, // Ballonlea Stadium, stadium
|
||||||
|
{084, 44}, // Route 7, tranquil road
|
||||||
|
{086, 47}, // Route 8, rugged mountain pass
|
||||||
|
{088, 53}, // Route 8 (on Steamdrift Way), snow-swept road
|
||||||
|
{090, 53}, // Route 9, snow-swept road
|
||||||
|
{092, 53}, // Route 9 (in Circhester Bay), snow-swept road
|
||||||
|
{094, 53}, // Route 9 (in Outer Spikemuth), snow-swept road
|
||||||
|
{098, 73}, // Circhester Stadium, stadium
|
||||||
|
{104, 78}, // Route 9 Tunnel, tunnel
|
||||||
|
{106, 53}, // Route 10, snow-swept road
|
||||||
|
{108, 28}, // White Hill Station, train station
|
||||||
|
{112, 28}, // Wyndon Station, train station
|
||||||
|
{114, 38}, // Wyndon Stadium (at the Pokémon League HQ), Pokémon League
|
||||||
|
{116, 38}, // Wyndon Stadium (in a locker room), Pokémon League
|
||||||
|
{120, 44}, // Meetup Spot, tranquil road
|
||||||
|
{122, 72}, // Rolling Fields, vast field
|
||||||
|
{124, 72}, // Dappled Grove, vast field
|
||||||
|
{126, 72}, // Watchtower Ruins, vast field
|
||||||
|
{128, 72}, // East Lake Axewell, vast field
|
||||||
|
{130, 72}, // West Lake Axewell, vast field
|
||||||
|
{132, 72}, // Axew’s Eye, vast field
|
||||||
|
{134, 72}, // South Lake Miloch, vast field
|
||||||
|
{136, 72}, // near the Giant’s Seat, vast field
|
||||||
|
{138, 72}, // North Lake Miloch, vast field
|
||||||
|
{140, 72}, // Motostoke Riverbank, vast field
|
||||||
|
{142, 72}, // Bridge Field, vast field
|
||||||
|
{144, 72}, // Stony Wilderness, vast field
|
||||||
|
{146, 72}, // Dusty Bowl, vast field
|
||||||
|
{148, 72}, // around the Giant’s Mirror, vast field
|
||||||
|
{150, 72}, // the Hammerlocke Hills, vast field
|
||||||
|
{152, 72}, // near the Giant’s Cap, vast field
|
||||||
|
{154, 72}, // Lake of Outrage, vast field
|
||||||
|
{156, 28}, // Wild Area Station, train station
|
||||||
|
{158, 34}, // Battle Tower, tall building
|
||||||
|
{160, 34}, // Rose Tower, tall building
|
||||||
|
{164, 72}, // Fields of Honor, vast field
|
||||||
|
{166, 50}, // Soothing Wetlands, muddy road
|
||||||
|
{168, 41}, // Forest of Focus, forest
|
||||||
|
{170, 49}, // Challenge Beach, seaside road
|
||||||
|
{172, 40}, // Brawlers’ Cave, cave
|
||||||
|
{174, 76}, // Challenge Road, town in the mountains
|
||||||
|
{176, 40}, // Courageous Cavern, cave
|
||||||
|
{178, 49}, // Loop Lagoon, seaside road
|
||||||
|
{180, 72}, // Training Lowlands, vast field
|
||||||
|
{182, 40}, // Warm-Up Tunnel, cave
|
||||||
|
{184, 51}, // Potbottom Desert, sand-swept road
|
||||||
|
{186, 49}, // Workout Sea, seaside road
|
||||||
|
{188, 49}, // Stepping-Stone Sea, seaside road
|
||||||
|
{190, 49}, // Insular Sea, seaside road
|
||||||
|
{192, 49}, // Honeycalm Sea, seaside road
|
||||||
|
{194, 49}, // Honeycalm Island, seaside road
|
||||||
|
{196, 29}, // Master Dojo, battling spot
|
||||||
|
{198, 34}, // Tower of Darkness, tall building
|
||||||
|
{200, 34}, // Tower of Waters, tall building
|
||||||
|
{202, 28}, // Armor Station, train station
|
||||||
|
{204, 53}, // Slippery Slope, snow-swept road
|
||||||
|
{208, 53}, // Frostpoint Field, snow-swept road
|
||||||
|
{210, 72}, // Giant’s Bed, vast field
|
||||||
|
{212, 48}, // Old Cemetery, stone-lined area
|
||||||
|
{214, 53}, // Snowslide Slope, snow-swept road
|
||||||
|
{216, 40}, // Tunnel to the Top, cave
|
||||||
|
{218, 53}, // the Path to the Peak, snow-swept road
|
||||||
|
{220, 65}, // Crown Shrine, mystical place
|
||||||
|
{222, 44}, // Giant’s Foot, tranquil road
|
||||||
|
{224, 40}, // Roaring-Sea Caves, cave
|
||||||
|
{226, 49}, // Frigid Sea, seaside road
|
||||||
|
{228, 72}, // Three-Point Pass, vast field
|
||||||
|
{230, 72}, // Ballimere Lake, vast field
|
||||||
|
{232, 40}, // Lakeside Cave, cave
|
||||||
|
{234, 72}, // Dyna Tree Hill, vast field
|
||||||
|
{236, 65}, // Rock Peak Ruins, mystical place
|
||||||
|
{238, 65}, // Iceberg Ruins, mystical place
|
||||||
|
{240, 65}, // Iron Ruins, mystical place
|
||||||
|
{242, 65}, // Split-Decision Ruins, mystical place
|
||||||
|
{244, 40}, // Max Lair, cave
|
||||||
|
{246, 28}, // Crown Tundra Station, train station
|
||||||
|
};
|
||||||
|
|
||||||
|
private static readonly HashSet<byte> PossibleGeneralLocations8 = new()
|
||||||
|
{
|
||||||
|
01, 02, 03, 04, 06, 08, 09,
|
||||||
|
11, 12, 16,
|
||||||
|
20, 22, 24, 28, 29,
|
||||||
|
30, 31, 33, 34, 35, 37, 38,
|
||||||
|
40, 41, 44, 47, 48, 49,
|
||||||
|
50, 51, 53,
|
||||||
|
65,
|
||||||
|
71, 72, 73, 74, 75, 76, 77, 78, 79,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
|
@ -17,30 +17,26 @@ namespace PKHeX.Core
|
||||||
|
|
||||||
public static bool CanWinRotoLoto(int generation, int item)
|
public static bool CanWinRotoLoto(int generation, int item)
|
||||||
{
|
{
|
||||||
return true; // todo
|
var context = Memories.GetContext(generation);
|
||||||
|
return context.CanWinRotoLoto(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool CanHoldItem(int generation, int item)
|
public static bool CanHoldItem(int generation, int item)
|
||||||
{
|
{
|
||||||
return true; // todo
|
var context = Memories.GetContext(generation);
|
||||||
|
return context.CanHoldItem(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool CanPlantBerry(int generation, int item)
|
public static bool CanPlantBerry(int generation, int item)
|
||||||
{
|
{
|
||||||
return true; // todo
|
var context = Memories.GetContext(generation);
|
||||||
|
return context.CanPlantBerry(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool CanUseItemGeneric(int generation, int item)
|
public static bool CanUseItemGeneric(int generation, int item)
|
||||||
{
|
{
|
||||||
if (generation == 6)
|
var context = Memories.GetContext(generation);
|
||||||
{
|
return context.CanUseItemGeneric(item);
|
||||||
// Key Item usage while in party on another species.
|
|
||||||
if (Memories.KeyItemUsableObserve6.Contains((ushort) item))
|
|
||||||
return true;
|
|
||||||
if (Memories.KeyItemMemoryArgsGen6.Values.Any(z => z.Contains((ushort) item)))
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return true; // todo
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool CanUseItem(int generation, int item, int species)
|
public static bool CanUseItem(int generation, int item, int species)
|
||||||
|
@ -52,47 +48,22 @@ namespace PKHeX.Core
|
||||||
return true; // todo
|
return true; // todo
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool IsUsedKeyItemUnspecific(int generation, int item) => generation switch
|
private static bool IsUsedKeyItemUnspecific(int generation, int item)
|
||||||
{
|
{
|
||||||
6 => Memories.KeyItemUsableObserve6.Contains((ushort)item),
|
var context = Memories.GetContext(generation);
|
||||||
_ => false,
|
return context.IsUsedKeyItemUnspecific(item);
|
||||||
};
|
}
|
||||||
|
|
||||||
private static bool IsUsedKeyItemSpecific(int generation, int item, int species) => generation switch
|
private static bool IsUsedKeyItemSpecific(int generation, int item, int species)
|
||||||
{
|
{
|
||||||
6 => Memories.KeyItemMemoryArgsGen6.TryGetValue(species, out var value) && value.Contains((ushort) item),
|
var context = Memories.GetContext(generation);
|
||||||
8 => Memories.KeyItemMemoryArgsGen8.TryGetValue(species, out var value) && value.Contains((ushort) item),
|
return context.IsUsedKeyItemSpecific(item, species);
|
||||||
_ => false,
|
}
|
||||||
};
|
|
||||||
|
|
||||||
public static bool CanBuyItem(int generation, int item, GameVersion version = GameVersion.Any)
|
public static bool CanBuyItem(int generation, int item, GameVersion version = GameVersion.Any)
|
||||||
{
|
{
|
||||||
return generation switch
|
var context = Memories.GetContext(generation);
|
||||||
{
|
return context.CanBuyItem(item, version);
|
||||||
6 => CanBuyItem6(item, version),
|
|
||||||
8 => CanBuyItem8(item, version),
|
|
||||||
_ => true, // todo
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private static bool CanBuyItem6(int item, GameVersion version)
|
|
||||||
{
|
|
||||||
if (version is GameVersion.Any)
|
|
||||||
return PurchaseableItemAO.Contains((ushort) item) || PurchaseableItemXY.Contains((ushort) item);
|
|
||||||
if (version is GameVersion.X or GameVersion.Y)
|
|
||||||
return PurchaseableItemXY.Contains((ushort)item);
|
|
||||||
if (version is GameVersion.AS or GameVersion.OR)
|
|
||||||
return PurchaseableItemAO.Contains((ushort)item);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static bool CanBuyItem8(int item, GameVersion version)
|
|
||||||
{
|
|
||||||
if (item is 1085) // Bob's Food Tin
|
|
||||||
return version is GameVersion.SW or GameVersion.Any;
|
|
||||||
if (item is 1086) // Bach's Food Tin
|
|
||||||
return version is GameVersion.SH or GameVersion.Any;
|
|
||||||
return PurchaseableItemSWSH.Contains((ushort) item);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool GetCanLearnMachineMove(PKM pkm, int move, int generation, GameVersion version = GameVersion.Any)
|
public static bool GetCanLearnMachineMove(PKM pkm, int move, int generation, GameVersion version = GameVersion.Any)
|
||||||
|
@ -261,49 +232,5 @@ namespace PKHeX.Core
|
||||||
(int)Duraludon,
|
(int)Duraludon,
|
||||||
(int)Urshifu,
|
(int)Urshifu,
|
||||||
};
|
};
|
||||||
|
|
||||||
private static readonly HashSet<ushort> PurchaseableItemXY = new()
|
|
||||||
{
|
|
||||||
002, 003, 004, 006, 007, 008, 009, 010, 011, 012,
|
|
||||||
013, 014, 015, 017, 018, 019, 020, 021, 022, 023,
|
|
||||||
024, 025, 026, 027, 028, 034, 035, 036, 037, 045,
|
|
||||||
046, 047, 048, 049, 052, 055, 056, 057, 058, 059,
|
|
||||||
060, 061, 062, 076, 077, 078, 079, 082, 084, 085,
|
|
||||||
254, 255, 314, 315, 316, 317, 318, 319, 320, 334,
|
|
||||||
338, 341, 342, 343, 345, 347, 352, 355, 360, 364,
|
|
||||||
365, 377, 379, 395, 402, 403, 405, 411, 618,
|
|
||||||
};
|
|
||||||
|
|
||||||
private static readonly HashSet<ushort> PurchaseableItemAO = new()
|
|
||||||
{
|
|
||||||
002, 003, 004, 006, 007, 008, 009, 010, 011, 013,
|
|
||||||
014, 015, 017, 018, 019, 020, 021, 022, 023, 024,
|
|
||||||
025, 026, 027, 028, 034, 035, 036, 037, 045, 046,
|
|
||||||
047, 048, 049, 052, 055, 056, 057, 058, 059, 060,
|
|
||||||
061, 062, 063, 064, 076, 077, 078, 079, 254, 255,
|
|
||||||
314, 315, 316, 317, 318, 319, 320, 328, 336, 341,
|
|
||||||
342, 343, 344, 347, 352, 360, 365, 367, 369, 374,
|
|
||||||
379, 384, 395, 398, 400, 403, 405, 409, 577, 692,
|
|
||||||
694,
|
|
||||||
};
|
|
||||||
|
|
||||||
internal static readonly HashSet<ushort> PurchaseableItemSWSH = new(Legal.TR_SWSH)
|
|
||||||
{
|
|
||||||
0002, 0003, 0004, 0006, 0007, 0008, 0009, 0010, 0011, 0013,
|
|
||||||
0014, 0015, 0017, 0018, 0019, 0020, 0021, 0022, 0023, 0024,
|
|
||||||
0025, 0026, 0027, 0028, 0033, 0034, 0035, 0036, 0037, 0042,
|
|
||||||
0045, 0046, 0047, 0048, 0049, 0050, 0051, 0052, 0055, 0056,
|
|
||||||
0057, 0058, 0059, 0060, 0061, 0062, 0063, 0076, 0077, 0079,
|
|
||||||
0089, 0149, 0150, 0151, 0155, 0214, 0215, 0219, 0220, 0254,
|
|
||||||
0255, 0269, 0270, 0271, 0275, 0280, 0287, 0289, 0290, 0291,
|
|
||||||
0292, 0293, 0294, 0297, 0314, 0315, 0316, 0317, 0318, 0319,
|
|
||||||
0320, 0321, 0325, 0326, 0541, 0542, 0545, 0546, 0547, 0639,
|
|
||||||
0640, 0645, 0646, 0647, 0648, 0649, 0795, 0846, 0879, 1084,
|
|
||||||
1087, 1088, 1089, 1090, 1091, 1094, 1095, 1097, 1098, 1099,
|
|
||||||
1118, 1119, 1121, 1122, 1231, 1232, 1233, 1234, 1235, 1236,
|
|
||||||
1237, 1238, 1239, 1240, 1241, 1242, 1243, 1244, 1245, 1246,
|
|
||||||
1247, 1248, 1249, 1250, 1251, 1252, 1256, 1257, 1258, 1259,
|
|
||||||
1260, 1261, 1262, 1263,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
namespace PKHeX.Core
|
||||||
|
{
|
||||||
|
public readonly struct MemoryVariableSet
|
||||||
|
{
|
||||||
|
public readonly string Handler;
|
||||||
|
|
||||||
|
public readonly int MemoryID;
|
||||||
|
public readonly int Variable;
|
||||||
|
public readonly int Intensity;
|
||||||
|
public readonly int Feeling;
|
||||||
|
|
||||||
|
private MemoryVariableSet(string handler, int m, int v, int i, int f)
|
||||||
|
{
|
||||||
|
Handler = handler;
|
||||||
|
MemoryID = m;
|
||||||
|
Variable = v;
|
||||||
|
Intensity = i;
|
||||||
|
Feeling = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MemoryVariableSet Read(ITrainerMemories pkm, int handler) => handler switch
|
||||||
|
{
|
||||||
|
0 => new MemoryVariableSet(LegalityCheckStrings.L_XOT, pkm.OT_Memory, pkm.OT_TextVar, pkm.OT_Intensity, pkm.OT_Feeling), // OT
|
||||||
|
1 => new MemoryVariableSet(LegalityCheckStrings.L_XHT, pkm.HT_Memory, pkm.HT_TextVar, pkm.HT_Intensity, pkm.HT_Feeling), // HT
|
||||||
|
_ => new MemoryVariableSet(LegalityCheckStrings.L_XOT, 0, 0, 0, 0),
|
||||||
|
};
|
||||||
|
|
||||||
|
public bool Equals(MemoryVariableSet v) => v.Handler == Handler
|
||||||
|
&& v.MemoryID == MemoryID
|
||||||
|
&& v.Variable == Variable
|
||||||
|
&& v.Intensity == Intensity
|
||||||
|
&& v.Feeling == Feeling;
|
||||||
|
|
||||||
|
public override bool Equals(object obj) => obj is MemoryVariableSet v && Equals(v);
|
||||||
|
public override int GetHashCode() => -1;
|
||||||
|
public static bool operator ==(MemoryVariableSet left, MemoryVariableSet right) => left.Equals(right);
|
||||||
|
public static bool operator !=(MemoryVariableSet left, MemoryVariableSet right) => !(left == right);
|
||||||
|
}
|
||||||
|
}
|
|
@ -18,27 +18,29 @@ namespace PKHeX.Core
|
||||||
VerifyHTMemory(data);
|
VerifyHTMemory(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
private CheckResult VerifyCommonMemory(PKM pkm, int handler, int gen, LegalInfo info)
|
private CheckResult VerifyCommonMemory(PKM pkm, int handler, int gen, LegalInfo info, MemoryContext context)
|
||||||
{
|
{
|
||||||
var memory = MemoryVariableSet.Read((ITrainerMemories)pkm, handler);
|
var memory = MemoryVariableSet.Read((ITrainerMemories)pkm, handler);
|
||||||
|
|
||||||
// Actionable HM moves
|
// Actionable HM moves
|
||||||
int matchingMoveMemory = Array.IndexOf(Memories.MoveSpecificMemories[0], memory.MemoryID);
|
int matchingMoveMemory = Array.IndexOf(MemoryContext6.MoveSpecificMemories[0], memory.MemoryID);
|
||||||
if (matchingMoveMemory != -1)
|
if (matchingMoveMemory != -1)
|
||||||
{
|
{
|
||||||
// Gen8 has no HMs, so this memory can never exist.
|
if (gen != 6) // Gen8 has no HMs, so this memory can never exist.
|
||||||
if (gen != 6 || (pkm.Species != (int)Species.Smeargle && !GetCanLearnMachineMove(pkm, info.EvoChainsAllGens[gen], Memories.MoveSpecificMemories[1][matchingMoveMemory], 6)))
|
|
||||||
return GetInvalid(string.Format(LMemoryArgBadMove, memory.Handler));
|
return GetInvalid(string.Format(LMemoryArgBadMove, memory.Handler));
|
||||||
|
|
||||||
|
if (pkm.Species != (int)Species.Smeargle)
|
||||||
|
{
|
||||||
|
if (!GetCanLearnMachineMove(pkm, info.EvoChainsAllGens[gen], MemoryContext6.MoveSpecificMemories[1][matchingMoveMemory], 6))
|
||||||
|
return GetInvalid(string.Format(LMemoryArgBadMove, memory.Handler));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gen == 8 && Memories.MemoryGeneral.Contains(memory.MemoryID) && Memories.IsInvalidGenLoc8Other(memory.MemoryID, memory.Variable))
|
if (context.IsInvalidGeneralLocationMemoryValue(memory.MemoryID, memory.Variable, info.EncounterMatch, pkm))
|
||||||
return GetInvalid(string.Format(LMemoryArgBadLocation, memory.Handler));
|
return GetInvalid(string.Format(LMemoryArgBadLocation, memory.Handler));
|
||||||
|
|
||||||
switch (memory.MemoryID)
|
switch (memory.MemoryID)
|
||||||
{
|
{
|
||||||
case 1 or 2 or 3 when gen == 8 && Memories.IsInvalidGenLoc8(memory.MemoryID, pkm.Met_Location, pkm.Egg_Location, memory.Variable):
|
|
||||||
return GetInvalid(string.Format(LMemoryArgBadLocation, memory.Handler));
|
|
||||||
|
|
||||||
case 19 when pkm.Species is (int)Species.Urshifu && memory.Variable is not 34: // tall building is the only location for evolving Urshifu
|
case 19 when pkm.Species is (int)Species.Urshifu && memory.Variable is not 34: // tall building is the only location for evolving Urshifu
|
||||||
case 19 when pkm.Species is (int)Species.Runerigus && memory.Variable is not 72: // vast field is the only location for evolving Runerigus
|
case 19 when pkm.Species is (int)Species.Runerigus && memory.Variable is not 72: // vast field is the only location for evolving Runerigus
|
||||||
return GetInvalid(string.Format(LMemoryArgBadLocation, memory.Handler));
|
return GetInvalid(string.Format(LMemoryArgBadLocation, memory.Handler));
|
||||||
|
@ -94,19 +96,19 @@ namespace PKHeX.Core
|
||||||
return GetInvalid(string.Format(LMemoryArgBadItem, memory.Handler));
|
return GetInvalid(string.Format(LMemoryArgBadItem, memory.Handler));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gen == 6 && !Memories.CanHaveIntensity(memory.MemoryID, memory.Intensity))
|
return VerifyCommonMemoryEtc(memory, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
private CheckResult VerifyCommonMemoryEtc(MemoryVariableSet memory, MemoryContext context)
|
||||||
|
{
|
||||||
|
if (!context.CanHaveIntensity(memory.MemoryID, memory.Intensity))
|
||||||
{
|
{
|
||||||
var encGen = info.EncounterMatch.Generation;
|
var min = context.GetMinimumIntensity(memory.MemoryID);
|
||||||
if (encGen == 6 || (encGen == 7 && memory.MemoryID != 0)) // todo: memory intensity checks for gen8
|
return GetInvalid(string.Format(LMemoryIndexIntensityMin, memory.Handler, min));
|
||||||
return GetInvalid(string.Format(LMemoryIndexIntensityMin, memory.Handler, Memories.GetMinimumIntensity(memory.MemoryID)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gen == 6 && memory.MemoryID != 4 && !Memories.CanHaveFeeling(memory.MemoryID, memory.Feeling))
|
if (!context.CanHaveFeeling(memory.MemoryID, memory.Feeling))
|
||||||
{
|
return GetInvalid(string.Format(LMemoryFeelInvalid, memory.Handler));
|
||||||
var encGen = info.EncounterMatch.Generation;
|
|
||||||
if (encGen == 6 || (encGen == 7 && memory.MemoryID != 0)) // todo: memory feeling checks for gen8
|
|
||||||
return GetInvalid(string.Format(LMemoryFeelInvalid, memory.Handler));
|
|
||||||
}
|
|
||||||
|
|
||||||
return GetValid(string.Format(LMemoryF_0_Valid, memory.Handler));
|
return GetValid(string.Format(LMemoryF_0_Valid, memory.Handler));
|
||||||
}
|
}
|
||||||
|
@ -182,14 +184,9 @@ namespace PKHeX.Core
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bounds checking
|
// Bounds checking
|
||||||
switch (memoryGen)
|
var context = Memories.GetContext(memoryGen);
|
||||||
{
|
if (!context.CanObtainMemoryOT((GameVersion)pkm.Version, memory))
|
||||||
case 6 when pkm.XY && (memory > Memories.MAX_MEMORY_ID_XY || Memories.Memory_NotXY.Contains(memory)):
|
data.AddLine(GetInvalid(string.Format(LMemoryArgBadID, L_XOT)));
|
||||||
case 6 when pkm.AO && (memory > Memories.MAX_MEMORY_ID_AO || Memories.Memory_NotAO.Contains(memory)):
|
|
||||||
case 8 when pkm.SWSH && (memory > Memories.MAX_MEMORY_ID_SWSH || Memories.Memory_NotSWSH.Contains(memory)):
|
|
||||||
data.AddLine(GetInvalid(string.Format(LMemoryArgBadID, L_XOT)));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify memory if specific to OT
|
// Verify memory if specific to OT
|
||||||
switch (memory)
|
switch (memory)
|
||||||
|
@ -211,12 +208,9 @@ namespace PKHeX.Core
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// {0} went to the Pokémon Center in {2} with {1} and had its tired body healed there. {4} that {3}.
|
// {0} went to the Pokémon Center in {2} with {1} and had its tired body healed there. {4} that {3}.
|
||||||
case 6 when memoryGen == 6 && !Memories.GetHasPokeCenterLocation((GameVersion)pkm.Version, mem.OT_TextVar):
|
case 6 when !context.HasPokeCenter((GameVersion)pkm.Version, mem.OT_TextVar):
|
||||||
data.AddLine(GetInvalid(string.Format(LMemoryArgBadLocation, L_XOT)));
|
data.AddLine(GetInvalid(string.Format(LMemoryArgBadLocation, L_XOT)));
|
||||||
return;
|
return;
|
||||||
case 6 when memoryGen == 8 && mem.OT_TextVar != 0:
|
|
||||||
data.AddLine(Get(string.Format(LMemoryArgBadLocation, L_XOT), ParseSettings.Gen8MemoryLocationTextVariable));
|
|
||||||
return;
|
|
||||||
|
|
||||||
// {0} was with {1} when {1} caught {2}. {4} that {3}.
|
// {0} was with {1} when {1} caught {2}. {4} that {3}.
|
||||||
case 14:
|
case 14:
|
||||||
|
@ -227,7 +221,7 @@ namespace PKHeX.Core
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
data.AddLine(VerifyCommonMemory(pkm, 0, Info.Generation, Info));
|
data.AddLine(VerifyCommonMemory(pkm, 0, Info.Generation, Info, context));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool CanHaveMemoryForOT(PKM pkm, int origin, int memory)
|
private static bool CanHaveMemoryForOT(PKM pkm, int origin, int memory)
|
||||||
|
@ -281,13 +275,9 @@ namespace PKHeX.Core
|
||||||
var memoryGen = pkm.Format >= 8 ? 8 : 6;
|
var memoryGen = pkm.Format >= 8 ? 8 : 6;
|
||||||
|
|
||||||
// Bounds checking
|
// Bounds checking
|
||||||
switch (memoryGen)
|
var context = Memories.GetContext(memoryGen);
|
||||||
{
|
if (!context.CanObtainMemoryHT((GameVersion)pkm.Version, memory))
|
||||||
case 6 when memory > Memories.MAX_MEMORY_ID_AO:
|
data.AddLine(GetInvalid(string.Format(LMemoryArgBadID, L_XHT)));
|
||||||
case 8 when memory > Memories.MAX_MEMORY_ID_SWSH || Memories.Memory_NotSWSH.Contains(memory):
|
|
||||||
data.AddLine(GetInvalid(string.Format(LMemoryArgBadID, L_XHT)));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify memory if specific to HT
|
// Verify memory if specific to HT
|
||||||
switch (memory)
|
switch (memory)
|
||||||
|
@ -309,12 +299,9 @@ namespace PKHeX.Core
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// {0} went to the Pokémon Center in {2} with {1} and had its tired body healed there. {4} that {3}.
|
// {0} went to the Pokémon Center in {2} with {1} and had its tired body healed there. {4} that {3}.
|
||||||
case 6 when memoryGen == 6 && !Memories.GetHasPokeCenterLocation(GameVersion.Gen6, mem.HT_TextVar):
|
case 6 when !context.HasPokeCenter(GameVersion.Any, mem.HT_TextVar):
|
||||||
data.AddLine(GetInvalid(string.Format(LMemoryArgBadLocation, L_XHT)));
|
data.AddLine(GetInvalid(string.Format(LMemoryArgBadLocation, L_XHT)));
|
||||||
return;
|
return;
|
||||||
case 6 when memoryGen == 8 && mem.HT_TextVar != 0:
|
|
||||||
data.AddLine(Get(string.Format(LMemoryArgBadLocation, L_XHT), ParseSettings.Gen8MemoryLocationTextVariable));
|
|
||||||
return;
|
|
||||||
|
|
||||||
// {0} was with {1} when {1} caught {2}. {4} that {3}.
|
// {0} was with {1} when {1} caught {2}. {4} that {3}.
|
||||||
case 14:
|
case 14:
|
||||||
|
@ -325,7 +312,7 @@ namespace PKHeX.Core
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var commonResult = VerifyCommonMemory(pkm, 1, memoryGen, Info);
|
var commonResult = VerifyCommonMemory(pkm, 1, memoryGen, Info, context);
|
||||||
data.AddLine(commonResult);
|
data.AddLine(commonResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -365,14 +365,14 @@ namespace PKHeX.Core
|
||||||
pk.OT_Memory = 3;
|
pk.OT_Memory = 3;
|
||||||
pk.OT_TextVar = 9;
|
pk.OT_TextVar = 9;
|
||||||
pk.OT_Intensity = 1;
|
pk.OT_Intensity = 1;
|
||||||
pk.OT_Feeling = Memories.GetRandomFeeling(pk.OT_Memory, 10); // 0-9
|
pk.OT_Feeling = MemoryContext6.GetRandomFeeling6(pk.OT_Memory, 10); // 0-9
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
pk.HT_Memory = 3;
|
pk.HT_Memory = 3;
|
||||||
pk.HT_TextVar = 9;
|
pk.HT_TextVar = 9;
|
||||||
pk.HT_Intensity = 1;
|
pk.HT_Intensity = 1;
|
||||||
pk.HT_Feeling = Memories.GetRandomFeeling(pk.HT_Memory, 10); // 0-9
|
pk.HT_Feeling = MemoryContext6.GetRandomFeeling6(pk.HT_Memory, 10); // 0-9
|
||||||
pk.HT_Friendship = pk.OT_Friendship;
|
pk.HT_Friendship = pk.OT_Friendship;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -446,7 +446,7 @@ namespace PKHeX.Core
|
||||||
HT_Gender = PKMConverter.OT_Gender,
|
HT_Gender = PKMConverter.OT_Gender,
|
||||||
HT_Intensity = 1,
|
HT_Intensity = 1,
|
||||||
HT_Memory = 4,
|
HT_Memory = 4,
|
||||||
HT_Feeling = Memories.GetRandomFeeling(4),
|
HT_Feeling = MemoryContext6.GetRandomFeeling6(4),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Write Transfer Location - location is dependent on 3DS system that transfers.
|
// Write Transfer Location - location is dependent on 3DS system that transfers.
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
ht.HT_Memory = 4; // Link trade to [VAR: General Location]
|
ht.HT_Memory = 4; // Link trade to [VAR: General Location]
|
||||||
ht.HT_TextVar = bank ? 0 : 9; // Somewhere (Bank) : Pokécenter (Trade)
|
ht.HT_TextVar = bank ? 0 : 9; // Somewhere (Bank) : Pokécenter (Trade)
|
||||||
ht.HT_Intensity = 1;
|
ht.HT_Intensity = 1;
|
||||||
ht.HT_Feeling = Memories.GetRandomFeeling(4, bank ? 10 : 20); // 0-9 Bank, 0-19 Trade
|
ht.HT_Feeling = MemoryContext6.GetRandomFeeling6(4, bank ? 10 : 20); // 0-9 Bank, 0-19 Trade
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
Binary file not shown.
Loading…
Reference in a new issue