PKHeX/PKHeX.Core/Legality/Areas/EncounterArea8.cs

485 lines
20 KiB
C#
Raw Normal View History

using System;
using System.Collections.Generic;
using System.Linq;
Enforce weather legality for SWSH (#3221) * Add weather types by location Creates a dictionary of possible weather types for each SWSH location. Unlisted locations may only have Normal weather or do not have any encounter slots. * Prune unused weather from static encounters Some encounters were too permissive with weather, e.g. Sandstorm in Fields of Honor and Challenge Beach; Snowstorm at Dyna Tree Hill. A few crossover areas that would have limited the possible weathers were marked with a "(c)". An example is Nidorina from Giant's Bed crossing to Frostpoint Field, where Raining and Thunderstorm do not occur. This additionally organizes encounters by location. * Move location-weather dictionary to EncounterArea8 * Verify weather marks on encounterslot/static encounters * Adds some static encounters available through weather bleed Weathers aren't normally available, but these static encounters are close enough to the boundary that the weather in an adjacent area can be used to spawn them. - Frostpoint Field Snorlax with Raining/Thunderstorm from Giant's Bed - Snowslide Slope Amaura with Raining/Thunderstorm from Giant's Bed - Frigid Sea Carracosta with Intense_Sun from Three-Point Pass - Frigid Sea Magmortar with Intense_Sun from Three-Point Pass - Ballimere Lake Corviknight with Snowstorm from Giant's Bed - Ballimere Lake Cryogonal with Snowstorm from Giant's Bed - Ballimere Lake Tyrunt with all weather from Giant's Bed - Lakeside Cave Ferrothorn with all weather from Ballimere Lake - Tunnel to the Top Golbat with all weather from Path to the Peak * Defer weather marks if incompatible, enforce encounterslot weather This uses the area weather to check fishing slots and tentatively adds some tables for weather bleed encounterslots. * Warm-Up Tunnel gets weather bleed from Training Lowlands * Update for base PKHeX * Handle weather bleed for SWSH encounter slots Co-authored-by: Skadiv <62726360+Skadiv@users.noreply.github.com> * Minor clean Having duplicate weather marks is illegal, so just auto-partial match them instead of checking the other marks. * Rearrange slot weather check logic * Claim reserved byte in SWSH pkl * No need for two variable names now * Valid weather marks on tree/fishing should return with main weather * Fix tree/fishing deferral and add another surf slot weather bleed * Disallow tree/fishing encounters from using bleed tables None are currently known at this time, and only hidden grass encounters have a weather bleed table * Condense bleed expression, combine tree/fish flag check * Move weather-bleed check into EncounterArea8 Makes the dictionaries private instead of internal. Co-authored-by: Skadiv <62726360+Skadiv@users.noreply.github.com>
2021-07-26 21:28:05 +00:00
using static PKHeX.Core.AreaWeather8;
using static PKHeX.Core.AreaSlotType8;
using static System.Buffers.Binary.BinaryPrimitives;
namespace PKHeX.Core
{
/// <inheritdoc cref="EncounterArea" />
/// <summary>
/// <see cref="GameVersion.SWSH"/> encounter area
/// </summary>
public sealed record EncounterArea8 : EncounterArea
{
public readonly EncounterSlot8[] Slots;
protected override IReadOnlyList<EncounterSlot> Raw => Slots;
2020-12-22 01:48:08 +00:00
/// <summary>
/// Slots from this area can cross over to another area, resulting in a different met location.
/// </summary>
2021-03-24 04:20:02 +00:00
/// <remarks>
/// Should only be true if it is a Symbol (visible) encounter.
/// </remarks>
public readonly bool PermitCrossover;
2020-12-22 01:48:08 +00:00
public override bool IsMatchLocation(int location)
{
if (Location == location)
return true;
if (!PermitCrossover)
return false;
2019-12-11 03:54:26 +00:00
// Get all other areas that the Location can bleed encounters to
if (!ConnectingArea8.TryGetValue(Location, out var others))
return false;
2019-12-11 03:54:26 +00:00
// Check if any of the other areas are the met location
return others.Contains((byte)location);
}
public override IEnumerable<EncounterSlot> GetMatchingSlots(PKM pkm, IReadOnlyList<EvoCriteria> chain)
{
2021-08-03 06:54:44 +00:00
var metLocation = pkm.Met_Location;
2020-08-22 21:12:16 +00:00
// wild area gets boosted up to level 60 post-game
var met = pkm.Met_Level;
bool isBoosted = met == BoostLevel && IsBoostedArea60(Location);
if (isBoosted)
2021-08-03 06:54:44 +00:00
return GetBoostedMatches(chain, metLocation);
return GetUnboostedMatches(chain, met, metLocation);
}
2020-08-22 21:12:16 +00:00
2021-08-03 06:54:44 +00:00
private IEnumerable<EncounterSlot8> GetUnboostedMatches(IReadOnlyList<EvoCriteria> chain, int metLevel, int metLocation)
{
foreach (var slot in Slots)
2019-11-16 01:34:18 +00:00
{
foreach (var evo in chain)
2019-11-16 01:34:18 +00:00
{
if (slot.Species != evo.Species)
continue;
2021-08-03 06:54:44 +00:00
if (!slot.IsLevelWithinRange(metLevel))
break;
2021-09-07 22:35:36 +00:00
if (slot.Form != evo.Form && slot.Species is not (int)Species.Rotom)
break;
if (slot.Weather is Heavy_Fog && IsWildArea8(Location))
break;
2021-08-03 06:54:44 +00:00
if (Location != metLocation && !CanCrossoverTo(Location, metLocation, slot.SlotType))
break;
yield return slot;
break;
}
}
}
2021-08-03 06:54:44 +00:00
private IEnumerable<EncounterSlot8> GetBoostedMatches(IReadOnlyList<EvoCriteria> chain, int metLocation)
{
foreach (var slot in Slots)
{
foreach (var evo in chain)
{
if (slot.Species != evo.Species)
continue;
// Ignore max met level comparison; we already know it is permissible to boost to level 60.
if (slot.LevelMin > BoostLevel)
break; // Can't downlevel, only boost to 60.
2021-09-07 22:35:36 +00:00
if (slot.Form != evo.Form && slot.Species is not (int)Species.Rotom)
break;
2021-08-03 06:54:44 +00:00
if (Location != metLocation && !CanCrossoverTo(Location, metLocation, slot.SlotType))
break;
yield return slot;
break;
}
}
}
2021-08-03 06:54:44 +00:00
private static bool CanCrossoverTo(int fromLocation, int toLocation, AreaSlotType8 type)
{
if (!type.CanCrossover())
return false;
return true;
}
public const int BoostLevel = 60;
public static bool IsWildArea(int location) => IsWildArea8(location) || IsWildArea8Armor(location) || IsWildArea8Crown(location);
public static bool IsBoostedArea60(int location) => IsWildArea(location);
2021-08-06 21:54:32 +00:00
public static bool IsBoostedArea60Fog(int location) => IsWildArea8(location); // IoA doesn't have fog restriction by badges, and all Crown stuff is above 60.
public static bool IsWildArea8(int location) => location is >= 122 and <= 154; // Rolling Fields -> Lake of Outrage
public static bool IsWildArea8Armor(int location) => location is >= 164 and <= 194; // Fields of Honor -> Honeycalm Island
public static bool IsWildArea8Crown(int location) => location is >= 204 and <= 234 and not 206; // Slippery Slope -> Dyna Tree Hill, skip Freezington
// Location, and areas that it can feed encounters to.
2019-11-21 01:01:34 +00:00
public static readonly IReadOnlyDictionary<int, IReadOnlyList<byte>> ConnectingArea8 = new Dictionary<int, IReadOnlyList<byte>>
{
// Route 3
// City of Motostoke
{28, new byte[] {20}},
// Rolling Fields
// Dappled Grove, East Lake Axewell, West Lake Axewell
// Also connects to South Lake Miloch but too much of a stretch
{122, new byte[] {124, 128, 130}},
// Dappled Grove
// Rolling Fields, Watchtower Ruins
{124, new byte[] {122, 126}},
// Watchtower Ruins
// Dappled Grove, West Lake Axewell
{126, new byte[] {124, 130}},
// East Lake Axewell
// Rolling Fields, West Lake Axewell, Axew's Eye, North Lake Miloch
{128, new byte[] {122, 130, 132, 138}},
// West Lake Axewell
// Rolling Fields, Watchtower Ruins, East Lake Axewell, Axew's Eye
{130, new byte[] {122, 126, 128, 132}},
// Axew's Eye
// East Lake Axewell, West Lake Axewell
{132, new byte[] {128, 130}},
// South Lake Miloch
// Giant's Seat, North Lake Miloch
{134, new byte[] {136, 138}},
// Giant's Seat
// South Lake Miloch, North Lake Miloch
{136, new byte[] {134, 138}},
// North Lake Miloch
// East Lake Axewell, South Lake Miloch, Giant's Seat
// Also connects to Motostoke Riverbank but too much of a stretch
{138, new byte[] {134, 136}},
// Motostoke Riverbank
// Bridge Field
{140, new byte[] {142}},
// Bridge Field
// Motostoke Riverbank, Stony Wilderness
{142, new byte[] {140, 144}},
// Stony Wilderness
// Bridge Field, Dusty Bowl, Giant's Mirror, Giant's Cap
{144, new byte[] {142, 146, 148, 152}},
// Dusty Bowl
// Stony Wilderness, Giant's Mirror, Hammerlocke Hills
{146, new byte[] {144, 148, 150}},
// Giant's Mirror
// Stony Wilderness, Dusty Bowl, Hammerlocke Hills
{148, new byte[] {144, 146, 148}},
// Hammerlocke Hills
// Dusty Bowl, Giant's Mirror, Giant's Cap
{150, new byte[] {146, 148, 152}},
// Giant's Cap
// Stony Wilderness, Giant's Cap
// Also connects to Lake of Outrage but too much of a stretch
{152, new byte[] {144, 150}},
// Lake of Outrage is just itself.
// Challenge Beach
// Soothing Wetlands, Courageous Cavern
{170, new byte[] {166, 176}},
// Challenge Road
// Brawler's Cave
{174, new byte[] {172}},
// Courageous Cavern
// Loop Lagoon
{176, new byte[] {178}},
// Warm-Up Tunnel
// Training Lowlands, Potbottom Desert
{182, new byte[] {180, 184}},
// Workout Sea
// Fields of Honor
{186, new byte[] {164}},
// Stepping-Stone Sea
// Fields of Honor
{188, new byte[] {170}},
// Insular Sea
// Honeycalm Sea
{190, new byte[] {192}},
// Honeycalm Sea
// Honeycalm Island
{192, new byte[] {194}},
// Frostpoint Field
// Freezington
{208, new byte[] {206}},
// Old Cemetery
// Giants Bed
{212, new byte[] {210}},
// Roaring-Sea Caves
// Giants Foot
{224, new byte[] {222}},
// Ballimere Lake
// Lakeside Cave
{230, new byte[] {232}},
};
Enforce weather legality for SWSH (#3221) * Add weather types by location Creates a dictionary of possible weather types for each SWSH location. Unlisted locations may only have Normal weather or do not have any encounter slots. * Prune unused weather from static encounters Some encounters were too permissive with weather, e.g. Sandstorm in Fields of Honor and Challenge Beach; Snowstorm at Dyna Tree Hill. A few crossover areas that would have limited the possible weathers were marked with a "(c)". An example is Nidorina from Giant's Bed crossing to Frostpoint Field, where Raining and Thunderstorm do not occur. This additionally organizes encounters by location. * Move location-weather dictionary to EncounterArea8 * Verify weather marks on encounterslot/static encounters * Adds some static encounters available through weather bleed Weathers aren't normally available, but these static encounters are close enough to the boundary that the weather in an adjacent area can be used to spawn them. - Frostpoint Field Snorlax with Raining/Thunderstorm from Giant's Bed - Snowslide Slope Amaura with Raining/Thunderstorm from Giant's Bed - Frigid Sea Carracosta with Intense_Sun from Three-Point Pass - Frigid Sea Magmortar with Intense_Sun from Three-Point Pass - Ballimere Lake Corviknight with Snowstorm from Giant's Bed - Ballimere Lake Cryogonal with Snowstorm from Giant's Bed - Ballimere Lake Tyrunt with all weather from Giant's Bed - Lakeside Cave Ferrothorn with all weather from Ballimere Lake - Tunnel to the Top Golbat with all weather from Path to the Peak * Defer weather marks if incompatible, enforce encounterslot weather This uses the area weather to check fishing slots and tentatively adds some tables for weather bleed encounterslots. * Warm-Up Tunnel gets weather bleed from Training Lowlands * Update for base PKHeX * Handle weather bleed for SWSH encounter slots Co-authored-by: Skadiv <62726360+Skadiv@users.noreply.github.com> * Minor clean Having duplicate weather marks is illegal, so just auto-partial match them instead of checking the other marks. * Rearrange slot weather check logic * Claim reserved byte in SWSH pkl * No need for two variable names now * Valid weather marks on tree/fishing should return with main weather * Fix tree/fishing deferral and add another surf slot weather bleed * Disallow tree/fishing encounters from using bleed tables None are currently known at this time, and only hidden grass encounters have a weather bleed table * Condense bleed expression, combine tree/fish flag check * Move weather-bleed check into EncounterArea8 Makes the dictionaries private instead of internal. Co-authored-by: Skadiv <62726360+Skadiv@users.noreply.github.com>
2021-07-26 21:28:05 +00:00
/// <summary>
/// Location IDs matched with possible weather types. Unlisted locations may only have Normal weather.
/// </summary>
internal static readonly Dictionary<int, AreaWeather8> WeatherbyArea = new()
{
{ 68, Intense_Sun }, // Route 6
{ 88, Snowing }, // Route 8 (Steamdrift Way)
{ 90, Snowing }, // Route 9
{ 92, Snowing }, // Route 9 (Circhester Bay)
{ 94, Overcast }, // Route 9 (Outer Spikemuth)
{ 106, Snowstorm }, // Route 10
{ 122, All }, // Rolling Fields
{ 124, All }, // Dappled Grove
{ 126, All }, // Watchtower Ruins
{ 128, All }, // East Lake Axewell
{ 130, All }, // West Lake Axewell
{ 132, All }, // Axew's Eye
{ 134, All }, // South Lake Miloch
{ 136, All }, // Giant's Seat
{ 138, All }, // North Lake Miloch
{ 140, All }, // Motostoke Riverbank
{ 142, All }, // Bridge Field
{ 144, All }, // Stony Wilderness
{ 146, All }, // Dusty Bowl
{ 148, All }, // Giant's Mirror
{ 150, All }, // Hammerlocke Hills
{ 152, All }, // Giant's Cap
{ 154, All }, // Lake of Outrage
{ 164, Normal | Overcast | Stormy | Intense_Sun | Heavy_Fog }, // Fields of Honor
{ 166, Normal | Overcast | Stormy | Intense_Sun | Heavy_Fog }, // Soothing Wetlands
{ 168, All_IoA }, // Forest of Focus
{ 170, Normal | Overcast | Stormy | Intense_Sun | Heavy_Fog }, // Challenge Beach
{ 174, All_IoA }, // Challenge Road
{ 178, Normal | Overcast | Stormy | Intense_Sun | Heavy_Fog }, // Loop Lagoon
{ 180, All_IoA }, // Training Lowlands
{ 184, Normal | Overcast | Raining | Sandstorm | Intense_Sun | Heavy_Fog }, // Potbottom Desert
{ 186, Normal | Overcast | Stormy | Intense_Sun | Heavy_Fog }, // Workout Sea
{ 188, Normal | Overcast | Stormy | Intense_Sun | Heavy_Fog }, // Stepping-Stone Sea
{ 190, Normal | Overcast | Stormy | Intense_Sun | Heavy_Fog }, // Insular Sea
{ 192, Normal | Overcast | Stormy | Intense_Sun | Heavy_Fog }, // Honeycalm Sea
{ 194, Normal | Overcast | Stormy | Intense_Sun | Heavy_Fog }, // Honeycalm Island
{ 204, Normal | Overcast | Intense_Sun | Icy | Heavy_Fog }, // Slippery Slope
{ 208, Normal | Overcast | Intense_Sun | Icy | Heavy_Fog }, // Frostpoint Field
{ 210, All_CT }, // Giant's Bed
{ 212, All_CT }, // Old Cemetery
{ 214, Normal | Overcast | Intense_Sun | Icy | Heavy_Fog }, // Snowslide Slope
{ 216, Overcast }, // Tunnel to the Top
{ 218, Normal | Overcast | Intense_Sun | Icy | Heavy_Fog }, // Path to the Peak
{ 222, All_CT }, // Giant's Foot
{ 224, Overcast }, // Roaring-Sea Caves
{ 226, No_Sun_Sand }, // Frigid Sea
{ 228, All_CT }, // Three-Point Pass
{ 230, All_Ballimere }, // Ballimere Lake
{ 232, Overcast }, // Lakeside Cave
};
/// <summary>
/// Weather types that may bleed into each location from adjacent locations for standard symbol encounter slots.
/// </summary>
internal static readonly Dictionary<int, AreaWeather8> WeatherBleedSymbol = new()
{
{ 166, All_IoA }, // Soothing Wetlands from Forest of Focus
{ 170, All_IoA }, // Challenge Beach from Forest of Focus
{ 182, All_IoA }, // Warm-Up Tunnel from Training Lowlands
{ 208, All_CT }, // Frostpoint Field from Giant's Bed
{ 216, Normal | Overcast | Intense_Sun | Icy | Heavy_Fog }, // Tunnel to the Top from Path to the Peak
{ 224, All_CT }, // Roaring-Sea Caves from Three-Point Pass
{ 232, All_Ballimere }, // Lakeside Cave from Ballimere Lake
{ 230, All_CT }, // Ballimere Lake from Giant's Bed
};
/// <summary>
/// Weather types that may bleed into each location from adjacent locations for surfing symbol encounter slots.
/// </summary>
private static readonly Dictionary<int, AreaWeather8> WeatherBleedSymbolSurfing = new()
{
{ 192, All_IoA }, // Honeycalm Sea from Training Lowlands
{ 224, All_CT }, // Roaring-Sea Caves from Giant's Foot
};
/// <summary>
/// Weather types that may bleed into each location from adjacent locations for Sharpedo symbol encounter slots.
/// </summary>
private static readonly Dictionary<int, AreaWeather8> WeatherBleedSymbolSharpedo = new()
{
{ 192, All_IoA }, // Honeycalm Sea from Training Lowlands
};
/// <summary>
/// Weather types that may bleed into each location from adjacent locations, for standard hidden grass encounter slots.
/// </summary>
private static readonly Dictionary<int, AreaWeather8> WeatherBleedHiddenGrass = new()
{
{ 166, All_IoA }, // Soothing Wetlands from Forest of Focus
{ 170, All_IoA }, // Challenge Beach from Forest of Focus
{ 208, All_CT }, // Frostpoint Field from Giant's Bed
{ 230, All_CT }, // Ballimere Lake from Giant's Bed
};
2021-08-03 06:54:44 +00:00
public static bool IsCrossoverBleedPossible(AreaSlotType8 type, int fromLocation, int toLocation) => true;
Enforce weather legality for SWSH (#3221) * Add weather types by location Creates a dictionary of possible weather types for each SWSH location. Unlisted locations may only have Normal weather or do not have any encounter slots. * Prune unused weather from static encounters Some encounters were too permissive with weather, e.g. Sandstorm in Fields of Honor and Challenge Beach; Snowstorm at Dyna Tree Hill. A few crossover areas that would have limited the possible weathers were marked with a "(c)". An example is Nidorina from Giant's Bed crossing to Frostpoint Field, where Raining and Thunderstorm do not occur. This additionally organizes encounters by location. * Move location-weather dictionary to EncounterArea8 * Verify weather marks on encounterslot/static encounters * Adds some static encounters available through weather bleed Weathers aren't normally available, but these static encounters are close enough to the boundary that the weather in an adjacent area can be used to spawn them. - Frostpoint Field Snorlax with Raining/Thunderstorm from Giant's Bed - Snowslide Slope Amaura with Raining/Thunderstorm from Giant's Bed - Frigid Sea Carracosta with Intense_Sun from Three-Point Pass - Frigid Sea Magmortar with Intense_Sun from Three-Point Pass - Ballimere Lake Corviknight with Snowstorm from Giant's Bed - Ballimere Lake Cryogonal with Snowstorm from Giant's Bed - Ballimere Lake Tyrunt with all weather from Giant's Bed - Lakeside Cave Ferrothorn with all weather from Ballimere Lake - Tunnel to the Top Golbat with all weather from Path to the Peak * Defer weather marks if incompatible, enforce encounterslot weather This uses the area weather to check fishing slots and tentatively adds some tables for weather bleed encounterslots. * Warm-Up Tunnel gets weather bleed from Training Lowlands * Update for base PKHeX * Handle weather bleed for SWSH encounter slots Co-authored-by: Skadiv <62726360+Skadiv@users.noreply.github.com> * Minor clean Having duplicate weather marks is illegal, so just auto-partial match them instead of checking the other marks. * Rearrange slot weather check logic * Claim reserved byte in SWSH pkl * No need for two variable names now * Valid weather marks on tree/fishing should return with main weather * Fix tree/fishing deferral and add another surf slot weather bleed * Disallow tree/fishing encounters from using bleed tables None are currently known at this time, and only hidden grass encounters have a weather bleed table * Condense bleed expression, combine tree/fish flag check * Move weather-bleed check into EncounterArea8 Makes the dictionaries private instead of internal. Co-authored-by: Skadiv <62726360+Skadiv@users.noreply.github.com>
2021-07-26 21:28:05 +00:00
public static bool IsWeatherBleedPossible(AreaSlotType8 type, AreaWeather8 permit, int location) => type switch
{
SymbolMain or SymbolMain2 or SymbolMain3 => WeatherBleedSymbol .TryGetValue(location, out var weather) && weather.HasFlag(permit),
HiddenMain or HiddenMain2 => WeatherBleedHiddenGrass .TryGetValue(location, out var weather) && weather.HasFlag(permit),
Enforce weather legality for SWSH (#3221) * Add weather types by location Creates a dictionary of possible weather types for each SWSH location. Unlisted locations may only have Normal weather or do not have any encounter slots. * Prune unused weather from static encounters Some encounters were too permissive with weather, e.g. Sandstorm in Fields of Honor and Challenge Beach; Snowstorm at Dyna Tree Hill. A few crossover areas that would have limited the possible weathers were marked with a "(c)". An example is Nidorina from Giant's Bed crossing to Frostpoint Field, where Raining and Thunderstorm do not occur. This additionally organizes encounters by location. * Move location-weather dictionary to EncounterArea8 * Verify weather marks on encounterslot/static encounters * Adds some static encounters available through weather bleed Weathers aren't normally available, but these static encounters are close enough to the boundary that the weather in an adjacent area can be used to spawn them. - Frostpoint Field Snorlax with Raining/Thunderstorm from Giant's Bed - Snowslide Slope Amaura with Raining/Thunderstorm from Giant's Bed - Frigid Sea Carracosta with Intense_Sun from Three-Point Pass - Frigid Sea Magmortar with Intense_Sun from Three-Point Pass - Ballimere Lake Corviknight with Snowstorm from Giant's Bed - Ballimere Lake Cryogonal with Snowstorm from Giant's Bed - Ballimere Lake Tyrunt with all weather from Giant's Bed - Lakeside Cave Ferrothorn with all weather from Ballimere Lake - Tunnel to the Top Golbat with all weather from Path to the Peak * Defer weather marks if incompatible, enforce encounterslot weather This uses the area weather to check fishing slots and tentatively adds some tables for weather bleed encounterslots. * Warm-Up Tunnel gets weather bleed from Training Lowlands * Update for base PKHeX * Handle weather bleed for SWSH encounter slots Co-authored-by: Skadiv <62726360+Skadiv@users.noreply.github.com> * Minor clean Having duplicate weather marks is illegal, so just auto-partial match them instead of checking the other marks. * Rearrange slot weather check logic * Claim reserved byte in SWSH pkl * No need for two variable names now * Valid weather marks on tree/fishing should return with main weather * Fix tree/fishing deferral and add another surf slot weather bleed * Disallow tree/fishing encounters from using bleed tables None are currently known at this time, and only hidden grass encounters have a weather bleed table * Condense bleed expression, combine tree/fish flag check * Move weather-bleed check into EncounterArea8 Makes the dictionaries private instead of internal. Co-authored-by: Skadiv <62726360+Skadiv@users.noreply.github.com>
2021-07-26 21:28:05 +00:00
Surfing => WeatherBleedSymbolSurfing .TryGetValue(location, out var weather) && weather.HasFlag(permit),
Sharpedo => WeatherBleedSymbolSharpedo.TryGetValue(location, out var weather) && weather.HasFlag(permit),
2021-08-20 20:49:20 +00:00
_ => false,
Enforce weather legality for SWSH (#3221) * Add weather types by location Creates a dictionary of possible weather types for each SWSH location. Unlisted locations may only have Normal weather or do not have any encounter slots. * Prune unused weather from static encounters Some encounters were too permissive with weather, e.g. Sandstorm in Fields of Honor and Challenge Beach; Snowstorm at Dyna Tree Hill. A few crossover areas that would have limited the possible weathers were marked with a "(c)". An example is Nidorina from Giant's Bed crossing to Frostpoint Field, where Raining and Thunderstorm do not occur. This additionally organizes encounters by location. * Move location-weather dictionary to EncounterArea8 * Verify weather marks on encounterslot/static encounters * Adds some static encounters available through weather bleed Weathers aren't normally available, but these static encounters are close enough to the boundary that the weather in an adjacent area can be used to spawn them. - Frostpoint Field Snorlax with Raining/Thunderstorm from Giant's Bed - Snowslide Slope Amaura with Raining/Thunderstorm from Giant's Bed - Frigid Sea Carracosta with Intense_Sun from Three-Point Pass - Frigid Sea Magmortar with Intense_Sun from Three-Point Pass - Ballimere Lake Corviknight with Snowstorm from Giant's Bed - Ballimere Lake Cryogonal with Snowstorm from Giant's Bed - Ballimere Lake Tyrunt with all weather from Giant's Bed - Lakeside Cave Ferrothorn with all weather from Ballimere Lake - Tunnel to the Top Golbat with all weather from Path to the Peak * Defer weather marks if incompatible, enforce encounterslot weather This uses the area weather to check fishing slots and tentatively adds some tables for weather bleed encounterslots. * Warm-Up Tunnel gets weather bleed from Training Lowlands * Update for base PKHeX * Handle weather bleed for SWSH encounter slots Co-authored-by: Skadiv <62726360+Skadiv@users.noreply.github.com> * Minor clean Having duplicate weather marks is illegal, so just auto-partial match them instead of checking the other marks. * Rearrange slot weather check logic * Claim reserved byte in SWSH pkl * No need for two variable names now * Valid weather marks on tree/fishing should return with main weather * Fix tree/fishing deferral and add another surf slot weather bleed * Disallow tree/fishing encounters from using bleed tables None are currently known at this time, and only hidden grass encounters have a weather bleed table * Condense bleed expression, combine tree/fish flag check * Move weather-bleed check into EncounterArea8 Makes the dictionaries private instead of internal. Co-authored-by: Skadiv <62726360+Skadiv@users.noreply.github.com>
2021-07-26 21:28:05 +00:00
};
public static EncounterArea8[] GetAreas(BinLinkerAccessor input, GameVersion game, bool symbol = false)
{
var result = new EncounterArea8[input.Length];
for (int i = 0; i < result.Length; i++)
2021-03-24 04:20:02 +00:00
result[i] = new EncounterArea8(input[i], symbol, game);
return result;
}
private EncounterArea8(ReadOnlySpan<byte> areaData, bool symbol, GameVersion game) : base(game)
{
2021-03-24 04:20:02 +00:00
PermitCrossover = symbol;
Location = areaData[0];
Slots = ReadSlots(areaData, areaData[1]);
}
private EncounterSlot8[] ReadSlots(ReadOnlySpan<byte> areaData, byte slotCount)
{
var slots = new EncounterSlot8[slotCount];
int ctr = 0;
int ofs = 2;
do
{
// Read area metadata
var meta = areaData.Slice(ofs, 6);
var flags = (AreaWeather8) ReadUInt16LittleEndian(meta);
var min = meta[2];
var max = meta[3];
var count = meta[4];
var slotType = (AreaSlotType8)meta[5];
ofs += 6;
// Read slots
const int bpe = 2;
for (int i = 0; i < count; i++, ctr++, ofs += bpe)
{
var entry = areaData.Slice(ofs, bpe);
var specForm = ReadUInt16LittleEndian(entry);
var species = specForm & 0x7FF;
var form = specForm >> 11;
Enforce weather legality for SWSH (#3221) * Add weather types by location Creates a dictionary of possible weather types for each SWSH location. Unlisted locations may only have Normal weather or do not have any encounter slots. * Prune unused weather from static encounters Some encounters were too permissive with weather, e.g. Sandstorm in Fields of Honor and Challenge Beach; Snowstorm at Dyna Tree Hill. A few crossover areas that would have limited the possible weathers were marked with a "(c)". An example is Nidorina from Giant's Bed crossing to Frostpoint Field, where Raining and Thunderstorm do not occur. This additionally organizes encounters by location. * Move location-weather dictionary to EncounterArea8 * Verify weather marks on encounterslot/static encounters * Adds some static encounters available through weather bleed Weathers aren't normally available, but these static encounters are close enough to the boundary that the weather in an adjacent area can be used to spawn them. - Frostpoint Field Snorlax with Raining/Thunderstorm from Giant's Bed - Snowslide Slope Amaura with Raining/Thunderstorm from Giant's Bed - Frigid Sea Carracosta with Intense_Sun from Three-Point Pass - Frigid Sea Magmortar with Intense_Sun from Three-Point Pass - Ballimere Lake Corviknight with Snowstorm from Giant's Bed - Ballimere Lake Cryogonal with Snowstorm from Giant's Bed - Ballimere Lake Tyrunt with all weather from Giant's Bed - Lakeside Cave Ferrothorn with all weather from Ballimere Lake - Tunnel to the Top Golbat with all weather from Path to the Peak * Defer weather marks if incompatible, enforce encounterslot weather This uses the area weather to check fishing slots and tentatively adds some tables for weather bleed encounterslots. * Warm-Up Tunnel gets weather bleed from Training Lowlands * Update for base PKHeX * Handle weather bleed for SWSH encounter slots Co-authored-by: Skadiv <62726360+Skadiv@users.noreply.github.com> * Minor clean Having duplicate weather marks is illegal, so just auto-partial match them instead of checking the other marks. * Rearrange slot weather check logic * Claim reserved byte in SWSH pkl * No need for two variable names now * Valid weather marks on tree/fishing should return with main weather * Fix tree/fishing deferral and add another surf slot weather bleed * Disallow tree/fishing encounters from using bleed tables None are currently known at this time, and only hidden grass encounters have a weather bleed table * Condense bleed expression, combine tree/fish flag check * Move weather-bleed check into EncounterArea8 Makes the dictionaries private instead of internal. Co-authored-by: Skadiv <62726360+Skadiv@users.noreply.github.com>
2021-07-26 21:28:05 +00:00
slots[ctr] = new EncounterSlot8(this, species, form, min, max, flags, slotType);
}
} while (ctr != slots.Length);
return slots;
}
}
/// <summary>
/// Encounter Conditions for <see cref="GameVersion.SWSH"/>
/// </summary>
Enforce weather legality for SWSH (#3221) * Add weather types by location Creates a dictionary of possible weather types for each SWSH location. Unlisted locations may only have Normal weather or do not have any encounter slots. * Prune unused weather from static encounters Some encounters were too permissive with weather, e.g. Sandstorm in Fields of Honor and Challenge Beach; Snowstorm at Dyna Tree Hill. A few crossover areas that would have limited the possible weathers were marked with a "(c)". An example is Nidorina from Giant's Bed crossing to Frostpoint Field, where Raining and Thunderstorm do not occur. This additionally organizes encounters by location. * Move location-weather dictionary to EncounterArea8 * Verify weather marks on encounterslot/static encounters * Adds some static encounters available through weather bleed Weathers aren't normally available, but these static encounters are close enough to the boundary that the weather in an adjacent area can be used to spawn them. - Frostpoint Field Snorlax with Raining/Thunderstorm from Giant's Bed - Snowslide Slope Amaura with Raining/Thunderstorm from Giant's Bed - Frigid Sea Carracosta with Intense_Sun from Three-Point Pass - Frigid Sea Magmortar with Intense_Sun from Three-Point Pass - Ballimere Lake Corviknight with Snowstorm from Giant's Bed - Ballimere Lake Cryogonal with Snowstorm from Giant's Bed - Ballimere Lake Tyrunt with all weather from Giant's Bed - Lakeside Cave Ferrothorn with all weather from Ballimere Lake - Tunnel to the Top Golbat with all weather from Path to the Peak * Defer weather marks if incompatible, enforce encounterslot weather This uses the area weather to check fishing slots and tentatively adds some tables for weather bleed encounterslots. * Warm-Up Tunnel gets weather bleed from Training Lowlands * Update for base PKHeX * Handle weather bleed for SWSH encounter slots Co-authored-by: Skadiv <62726360+Skadiv@users.noreply.github.com> * Minor clean Having duplicate weather marks is illegal, so just auto-partial match them instead of checking the other marks. * Rearrange slot weather check logic * Claim reserved byte in SWSH pkl * No need for two variable names now * Valid weather marks on tree/fishing should return with main weather * Fix tree/fishing deferral and add another surf slot weather bleed * Disallow tree/fishing encounters from using bleed tables None are currently known at this time, and only hidden grass encounters have a weather bleed table * Condense bleed expression, combine tree/fish flag check * Move weather-bleed check into EncounterArea8 Makes the dictionaries private instead of internal. Co-authored-by: Skadiv <62726360+Skadiv@users.noreply.github.com>
2021-07-26 21:28:05 +00:00
/// <remarks>Values above <see cref="AreaWeather8.All"/> are for Shaking/Fishing hidden encounters only.</remarks>
[Flags]
Enforce weather legality for SWSH (#3221) * Add weather types by location Creates a dictionary of possible weather types for each SWSH location. Unlisted locations may only have Normal weather or do not have any encounter slots. * Prune unused weather from static encounters Some encounters were too permissive with weather, e.g. Sandstorm in Fields of Honor and Challenge Beach; Snowstorm at Dyna Tree Hill. A few crossover areas that would have limited the possible weathers were marked with a "(c)". An example is Nidorina from Giant's Bed crossing to Frostpoint Field, where Raining and Thunderstorm do not occur. This additionally organizes encounters by location. * Move location-weather dictionary to EncounterArea8 * Verify weather marks on encounterslot/static encounters * Adds some static encounters available through weather bleed Weathers aren't normally available, but these static encounters are close enough to the boundary that the weather in an adjacent area can be used to spawn them. - Frostpoint Field Snorlax with Raining/Thunderstorm from Giant's Bed - Snowslide Slope Amaura with Raining/Thunderstorm from Giant's Bed - Frigid Sea Carracosta with Intense_Sun from Three-Point Pass - Frigid Sea Magmortar with Intense_Sun from Three-Point Pass - Ballimere Lake Corviknight with Snowstorm from Giant's Bed - Ballimere Lake Cryogonal with Snowstorm from Giant's Bed - Ballimere Lake Tyrunt with all weather from Giant's Bed - Lakeside Cave Ferrothorn with all weather from Ballimere Lake - Tunnel to the Top Golbat with all weather from Path to the Peak * Defer weather marks if incompatible, enforce encounterslot weather This uses the area weather to check fishing slots and tentatively adds some tables for weather bleed encounterslots. * Warm-Up Tunnel gets weather bleed from Training Lowlands * Update for base PKHeX * Handle weather bleed for SWSH encounter slots Co-authored-by: Skadiv <62726360+Skadiv@users.noreply.github.com> * Minor clean Having duplicate weather marks is illegal, so just auto-partial match them instead of checking the other marks. * Rearrange slot weather check logic * Claim reserved byte in SWSH pkl * No need for two variable names now * Valid weather marks on tree/fishing should return with main weather * Fix tree/fishing deferral and add another surf slot weather bleed * Disallow tree/fishing encounters from using bleed tables None are currently known at this time, and only hidden grass encounters have a weather bleed table * Condense bleed expression, combine tree/fish flag check * Move weather-bleed check into EncounterArea8 Makes the dictionaries private instead of internal. Co-authored-by: Skadiv <62726360+Skadiv@users.noreply.github.com>
2021-07-26 21:28:05 +00:00
public enum AreaWeather8 : ushort
{
None,
Normal = 1,
Overcast = 1 << 1,
Raining = 1 << 2,
Thunderstorm = 1 << 3,
Intense_Sun = 1 << 4,
Snowing = 1 << 5,
Snowstorm = 1 << 6,
Sandstorm = 1 << 7,
Heavy_Fog = 1 << 8,
All = Normal | Overcast | Raining | Thunderstorm | Intense_Sun | Snowing | Snowstorm | Sandstorm | Heavy_Fog,
Stormy = Raining | Thunderstorm,
Icy = Snowing | Snowstorm,
All_IoA = Normal | Overcast | Stormy | Intense_Sun | Sandstorm | Heavy_Fog, // IoA can have everything but snow
All_CT = Normal | Overcast | Stormy | Intense_Sun | Icy | Heavy_Fog, // CT can have everything but sand
No_Sun_Sand = Normal | Overcast | Stormy | Icy | Heavy_Fog, // Everything but sand and sun
All_Ballimere = Normal | Overcast | Stormy | Intense_Sun | Snowing | Heavy_Fog, // All Ballimere Lake weather
Shaking_Trees = 1 << 9,
Fishing = 1 << 10,
NotWeather = Shaking_Trees | Fishing,
}
Enforce weather legality for SWSH (#3221) * Add weather types by location Creates a dictionary of possible weather types for each SWSH location. Unlisted locations may only have Normal weather or do not have any encounter slots. * Prune unused weather from static encounters Some encounters were too permissive with weather, e.g. Sandstorm in Fields of Honor and Challenge Beach; Snowstorm at Dyna Tree Hill. A few crossover areas that would have limited the possible weathers were marked with a "(c)". An example is Nidorina from Giant's Bed crossing to Frostpoint Field, where Raining and Thunderstorm do not occur. This additionally organizes encounters by location. * Move location-weather dictionary to EncounterArea8 * Verify weather marks on encounterslot/static encounters * Adds some static encounters available through weather bleed Weathers aren't normally available, but these static encounters are close enough to the boundary that the weather in an adjacent area can be used to spawn them. - Frostpoint Field Snorlax with Raining/Thunderstorm from Giant's Bed - Snowslide Slope Amaura with Raining/Thunderstorm from Giant's Bed - Frigid Sea Carracosta with Intense_Sun from Three-Point Pass - Frigid Sea Magmortar with Intense_Sun from Three-Point Pass - Ballimere Lake Corviknight with Snowstorm from Giant's Bed - Ballimere Lake Cryogonal with Snowstorm from Giant's Bed - Ballimere Lake Tyrunt with all weather from Giant's Bed - Lakeside Cave Ferrothorn with all weather from Ballimere Lake - Tunnel to the Top Golbat with all weather from Path to the Peak * Defer weather marks if incompatible, enforce encounterslot weather This uses the area weather to check fishing slots and tentatively adds some tables for weather bleed encounterslots. * Warm-Up Tunnel gets weather bleed from Training Lowlands * Update for base PKHeX * Handle weather bleed for SWSH encounter slots Co-authored-by: Skadiv <62726360+Skadiv@users.noreply.github.com> * Minor clean Having duplicate weather marks is illegal, so just auto-partial match them instead of checking the other marks. * Rearrange slot weather check logic * Claim reserved byte in SWSH pkl * No need for two variable names now * Valid weather marks on tree/fishing should return with main weather * Fix tree/fishing deferral and add another surf slot weather bleed * Disallow tree/fishing encounters from using bleed tables None are currently known at this time, and only hidden grass encounters have a weather bleed table * Condense bleed expression, combine tree/fish flag check * Move weather-bleed check into EncounterArea8 Makes the dictionaries private instead of internal. Co-authored-by: Skadiv <62726360+Skadiv@users.noreply.github.com>
2021-07-26 21:28:05 +00:00
public static class AreaWeather8Extensions
{
public static bool IsMarkCompatible(this AreaWeather8 weather, IRibbonSetMark8 m)
{
if (m.RibbonMarkCloudy) return (weather & Overcast) != 0;
if (m.RibbonMarkRainy) return (weather & Raining) != 0;
if (m.RibbonMarkStormy) return (weather & Thunderstorm) != 0;
if (m.RibbonMarkSnowy) return (weather & Snowing) != 0;
if (m.RibbonMarkBlizzard) return (weather & Snowstorm) != 0;
if (m.RibbonMarkDry) return (weather & Intense_Sun) != 0;
if (m.RibbonMarkSandstorm) return (weather & Sandstorm) != 0;
if (m.RibbonMarkMisty) return (weather & Heavy_Fog) != 0;
return true; // no mark / etc is fine; check later.
}
}
/// <summary>
/// Encounter Slot Types for <see cref="GameVersion.SWSH"/>
/// </summary>
public enum AreaSlotType8 : byte
{
SymbolMain,
SymbolMain2,
SymbolMain3,
HiddenMain, // Both HiddenMain tables include the tree/fishing slots for the area.
Enforce weather legality for SWSH (#3221) * Add weather types by location Creates a dictionary of possible weather types for each SWSH location. Unlisted locations may only have Normal weather or do not have any encounter slots. * Prune unused weather from static encounters Some encounters were too permissive with weather, e.g. Sandstorm in Fields of Honor and Challenge Beach; Snowstorm at Dyna Tree Hill. A few crossover areas that would have limited the possible weathers were marked with a "(c)". An example is Nidorina from Giant's Bed crossing to Frostpoint Field, where Raining and Thunderstorm do not occur. This additionally organizes encounters by location. * Move location-weather dictionary to EncounterArea8 * Verify weather marks on encounterslot/static encounters * Adds some static encounters available through weather bleed Weathers aren't normally available, but these static encounters are close enough to the boundary that the weather in an adjacent area can be used to spawn them. - Frostpoint Field Snorlax with Raining/Thunderstorm from Giant's Bed - Snowslide Slope Amaura with Raining/Thunderstorm from Giant's Bed - Frigid Sea Carracosta with Intense_Sun from Three-Point Pass - Frigid Sea Magmortar with Intense_Sun from Three-Point Pass - Ballimere Lake Corviknight with Snowstorm from Giant's Bed - Ballimere Lake Cryogonal with Snowstorm from Giant's Bed - Ballimere Lake Tyrunt with all weather from Giant's Bed - Lakeside Cave Ferrothorn with all weather from Ballimere Lake - Tunnel to the Top Golbat with all weather from Path to the Peak * Defer weather marks if incompatible, enforce encounterslot weather This uses the area weather to check fishing slots and tentatively adds some tables for weather bleed encounterslots. * Warm-Up Tunnel gets weather bleed from Training Lowlands * Update for base PKHeX * Handle weather bleed for SWSH encounter slots Co-authored-by: Skadiv <62726360+Skadiv@users.noreply.github.com> * Minor clean Having duplicate weather marks is illegal, so just auto-partial match them instead of checking the other marks. * Rearrange slot weather check logic * Claim reserved byte in SWSH pkl * No need for two variable names now * Valid weather marks on tree/fishing should return with main weather * Fix tree/fishing deferral and add another surf slot weather bleed * Disallow tree/fishing encounters from using bleed tables None are currently known at this time, and only hidden grass encounters have a weather bleed table * Condense bleed expression, combine tree/fish flag check * Move weather-bleed check into EncounterArea8 Makes the dictionaries private instead of internal. Co-authored-by: Skadiv <62726360+Skadiv@users.noreply.github.com>
2021-07-26 21:28:05 +00:00
HiddenMain2,
Surfing,
Surfing2,
Sky,
Sky2,
Ground,
Ground2,
Sharpedo,
OnlyFishing, // More restricted hidden table that ignores the weather slots like grass Tentacool.
Inaccessible, // Shouldn't show up since these tables are not dumped.
Enforce weather legality for SWSH (#3221) * Add weather types by location Creates a dictionary of possible weather types for each SWSH location. Unlisted locations may only have Normal weather or do not have any encounter slots. * Prune unused weather from static encounters Some encounters were too permissive with weather, e.g. Sandstorm in Fields of Honor and Challenge Beach; Snowstorm at Dyna Tree Hill. A few crossover areas that would have limited the possible weathers were marked with a "(c)". An example is Nidorina from Giant's Bed crossing to Frostpoint Field, where Raining and Thunderstorm do not occur. This additionally organizes encounters by location. * Move location-weather dictionary to EncounterArea8 * Verify weather marks on encounterslot/static encounters * Adds some static encounters available through weather bleed Weathers aren't normally available, but these static encounters are close enough to the boundary that the weather in an adjacent area can be used to spawn them. - Frostpoint Field Snorlax with Raining/Thunderstorm from Giant's Bed - Snowslide Slope Amaura with Raining/Thunderstorm from Giant's Bed - Frigid Sea Carracosta with Intense_Sun from Three-Point Pass - Frigid Sea Magmortar with Intense_Sun from Three-Point Pass - Ballimere Lake Corviknight with Snowstorm from Giant's Bed - Ballimere Lake Cryogonal with Snowstorm from Giant's Bed - Ballimere Lake Tyrunt with all weather from Giant's Bed - Lakeside Cave Ferrothorn with all weather from Ballimere Lake - Tunnel to the Top Golbat with all weather from Path to the Peak * Defer weather marks if incompatible, enforce encounterslot weather This uses the area weather to check fishing slots and tentatively adds some tables for weather bleed encounterslots. * Warm-Up Tunnel gets weather bleed from Training Lowlands * Update for base PKHeX * Handle weather bleed for SWSH encounter slots Co-authored-by: Skadiv <62726360+Skadiv@users.noreply.github.com> * Minor clean Having duplicate weather marks is illegal, so just auto-partial match them instead of checking the other marks. * Rearrange slot weather check logic * Claim reserved byte in SWSH pkl * No need for two variable names now * Valid weather marks on tree/fishing should return with main weather * Fix tree/fishing deferral and add another surf slot weather bleed * Disallow tree/fishing encounters from using bleed tables None are currently known at this time, and only hidden grass encounters have a weather bleed table * Condense bleed expression, combine tree/fish flag check * Move weather-bleed check into EncounterArea8 Makes the dictionaries private instead of internal. Co-authored-by: Skadiv <62726360+Skadiv@users.noreply.github.com>
2021-07-26 21:28:05 +00:00
}
2021-08-03 06:54:44 +00:00
public static class AreaSlotType8Extensions
{
public static bool CanCrossover(this AreaSlotType8 type) => type is not (HiddenMain or HiddenMain2 or OnlyFishing);
public static bool CanEncounterViaFishing(this AreaSlotType8 type, AreaWeather8 weather) => type is OnlyFishing || weather.HasFlag(Fishing);
2021-08-03 06:54:44 +00:00
public static bool CanEncounterViaCurry(this AreaSlotType8 type) => type is HiddenMain or HiddenMain2;
}
}