Refactoring: Move Source (Legality) (#3560)
Rewrites a good amount of legality APIs pertaining to:
* Legal moves that can be learned
* Evolution chains & cross-generation paths
* Memory validation with forgotten moves
In generation 8, there are 3 separate contexts an entity can exist in: SW/SH, BD/SP, and LA. Not every entity can cross between them, and not every entity from generation 7 can exist in generation 8 (Gogoat, etc). By creating class models representing the restrictions to cross each boundary, we are able to better track and validate data.
The old implementation of validating moves was greedy: it would iterate for all generations and evolutions, and build a full list of every move that can be learned, storing it on the heap. Now, we check one game group at a time to see if the entity can learn a move that hasn't yet been validated. End result is an algorithm that requires 0 allocation, and a smaller/quicker search space.
The old implementation of storing move parses was inefficient; for each move that was parsed, a new object is created and adjusted depending on the parse. Now, move parse results are `struct` and store the move parse contiguously in memory. End result is faster parsing and 0 memory allocation.
* `PersonalTable` objects have been improved with new API methods to check if a species+form can exist in the game.
* `IEncounterTemplate` objects have been improved to indicate the `EntityContext` they originate in (similar to `Generation`).
* Some APIs have been extended to accept `Span<T>` instead of Array/IEnumerable
2022-08-03 23:15:27 +00:00
|
|
|
|
using System;
|
2018-05-19 04:35:57 +00:00
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
|
namespace PKHeX.Core;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Repository of localized game strings for a given <see cref="LanguageID"/>.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public sealed class GameStrings : IBasicStrings
|
2018-05-19 04:35:57 +00:00
|
|
|
|
{
|
2022-06-18 18:04:24 +00:00
|
|
|
|
// PKM Info
|
|
|
|
|
public readonly string[] specieslist, movelist, itemlist, abilitylist, types, natures, forms,
|
|
|
|
|
memories, genloc, feeling6, feeling8, intensity,
|
|
|
|
|
trainingbags, trainingstage, characteristics,
|
|
|
|
|
groundtiletypes, balllist, gamelist, pokeblocks, ribbons;
|
|
|
|
|
|
|
|
|
|
private readonly string[] g4items, g3coloitems, g3xditems, g3items, g2items, g1items;
|
|
|
|
|
|
|
|
|
|
// Met Locations
|
2022-11-25 01:42:17 +00:00
|
|
|
|
public readonly LocationSet0 Gen2, Gen3, CXD;
|
|
|
|
|
public readonly LocationSet4 Gen4;
|
|
|
|
|
public readonly LocationSet6 Gen5, Gen6, Gen7, Gen7b, Gen8, Gen8a, Gen8b, Gen9;
|
2022-06-18 18:04:24 +00:00
|
|
|
|
|
|
|
|
|
// Misc
|
|
|
|
|
public readonly string[] wallpapernames, puffs, walkercourses;
|
|
|
|
|
public readonly string[] uggoods, ugspheres, ugtraps, ugtreasures;
|
|
|
|
|
private readonly string lang;
|
|
|
|
|
private readonly int LanguageIndex;
|
|
|
|
|
|
|
|
|
|
public string EggName { get; }
|
|
|
|
|
public IReadOnlyList<string> Species => specieslist;
|
|
|
|
|
public IReadOnlyList<string> Item => itemlist;
|
|
|
|
|
public IReadOnlyList<string> Move => movelist;
|
|
|
|
|
public IReadOnlyList<string> Ability => abilitylist;
|
|
|
|
|
public IReadOnlyList<string> Types => types;
|
|
|
|
|
public IReadOnlyList<string> Natures => natures;
|
|
|
|
|
|
|
|
|
|
private string[] Get(string ident) => GameLanguage.GetStrings(ident, lang);
|
|
|
|
|
private const string NPC = "NPC";
|
2022-08-25 03:32:40 +00:00
|
|
|
|
private const string EmptyIndex = "---";
|
2022-06-18 18:04:24 +00:00
|
|
|
|
|
2019-09-23 23:56:47 +00:00
|
|
|
|
/// <summary>
|
2022-06-18 18:04:24 +00:00
|
|
|
|
/// Item IDs that correspond to the <see cref="Ball"/> value.
|
2019-09-23 23:56:47 +00:00
|
|
|
|
/// </summary>
|
2023-03-26 00:55:55 +00:00
|
|
|
|
private static ReadOnlySpan<ushort> Items_Ball => new ushort[]
|
2018-05-19 04:35:57 +00:00
|
|
|
|
{
|
2022-06-18 18:04:24 +00:00
|
|
|
|
0000, 0001, 0002, 0003, 0004, 0005, 0006, 0007, 0008, 0009,
|
|
|
|
|
0010, 0011, 0012, 0013, 0014, 0015, 0016, 0492, 0493, 0494,
|
|
|
|
|
0495, 0496, 0497, 0498, 0499, 0576, 0851,
|
|
|
|
|
1785, 1710, 1711,
|
|
|
|
|
1712, 1713, 1746, 1747, 1748, 1749, 1750, 1771,
|
|
|
|
|
};
|
|
|
|
|
|
2022-11-25 01:42:17 +00:00
|
|
|
|
internal GameStrings(string l)
|
2022-06-18 18:04:24 +00:00
|
|
|
|
{
|
|
|
|
|
lang = l;
|
|
|
|
|
LanguageIndex = GameLanguage.GetLanguageIndex(l);
|
|
|
|
|
ribbons = Get("ribbons");
|
|
|
|
|
|
|
|
|
|
// Past Generation strings
|
|
|
|
|
g3items = Get("ItemsG3");
|
|
|
|
|
g3coloitems = GetG3CXD(g3items, "ItemsG3Colosseum");
|
|
|
|
|
g3xditems = GetG3CXD(g3items, "ItemsG3XD");
|
|
|
|
|
|
|
|
|
|
g2items = Get("ItemsG2");
|
|
|
|
|
g1items = Get("ItemsG1");
|
2022-11-25 01:42:17 +00:00
|
|
|
|
Gen2 = new(Get("gsc_00000"));
|
|
|
|
|
Gen3 = new(Get("rsefrlg_00000"));
|
|
|
|
|
CXD = new(Get("cxd_00000"));
|
|
|
|
|
SanitizeMetStringsCXD(CXD.Met0);
|
2022-06-18 18:04:24 +00:00
|
|
|
|
|
|
|
|
|
// Current Generation strings
|
|
|
|
|
natures = Util.GetNaturesList(l);
|
|
|
|
|
types = Get("types");
|
|
|
|
|
abilitylist = Get("abilities");
|
|
|
|
|
|
|
|
|
|
movelist = Get("moves");
|
2022-08-25 03:32:40 +00:00
|
|
|
|
// Differentiate Physical/Special Z-Moves
|
2022-06-18 18:04:24 +00:00
|
|
|
|
for (int i = 622; i < 658; i++)
|
2022-08-25 03:32:40 +00:00
|
|
|
|
{
|
|
|
|
|
const string p = " (P)";
|
|
|
|
|
const string s = " (S)";
|
|
|
|
|
bool isPhysicalZMove = (i & 1) == 0;
|
|
|
|
|
movelist[i] += isPhysicalZMove ? p : s;
|
|
|
|
|
}
|
2022-06-18 18:04:24 +00:00
|
|
|
|
|
|
|
|
|
itemlist = Get("items");
|
|
|
|
|
characteristics = Get("character");
|
|
|
|
|
specieslist = Get("species");
|
|
|
|
|
wallpapernames = Get("wallpaper");
|
|
|
|
|
groundtiletypes = Get("groundtile");
|
|
|
|
|
gamelist = Get("games");
|
|
|
|
|
|
2023-03-26 00:55:55 +00:00
|
|
|
|
var balls = Items_Ball;
|
|
|
|
|
balllist = new string[balls.Length];
|
2022-06-18 18:04:24 +00:00
|
|
|
|
for (int i = 0; i < balllist.Length; i++)
|
2023-03-26 00:55:55 +00:00
|
|
|
|
balllist[i] = itemlist[balls[i]];
|
2022-06-18 18:04:24 +00:00
|
|
|
|
|
|
|
|
|
pokeblocks = Get("pokeblock");
|
|
|
|
|
forms = Get("forms");
|
|
|
|
|
memories = Get("memories");
|
|
|
|
|
feeling6 = Get("feeling6");
|
|
|
|
|
feeling8 = Get("feeling");
|
|
|
|
|
intensity = Get("intensity");
|
|
|
|
|
genloc = Get("genloc");
|
|
|
|
|
trainingbags = Get("trainingbag");
|
|
|
|
|
trainingstage = Get("supertraining");
|
|
|
|
|
puffs = Get("puff");
|
|
|
|
|
|
|
|
|
|
walkercourses = Get("hgss_walkercourses");
|
|
|
|
|
|
|
|
|
|
uggoods = Get("dppt_uggoods");
|
|
|
|
|
ugspheres = Get("dppt_ugspheres");
|
|
|
|
|
ugtraps = Get("dppt_ugtraps");
|
|
|
|
|
ugtreasures = Get("dppt_ugtreasures");
|
|
|
|
|
|
|
|
|
|
EggName = specieslist[0];
|
2022-11-25 01:42:17 +00:00
|
|
|
|
Gen4 = Get4("hgss");
|
|
|
|
|
Gen5 = Get6("bw2");
|
|
|
|
|
Gen6 = Get6("xy");
|
|
|
|
|
Gen7 = Get6("sm");
|
|
|
|
|
|
|
|
|
|
Gen7b = Get6("gg", Gen7.Met3, Gen7.Met6);
|
|
|
|
|
Gen8 = Get6("swsh");
|
|
|
|
|
Gen8a = Get6("la");
|
|
|
|
|
Gen8b = Get6("bdsp");
|
|
|
|
|
Gen9 = Get6("sv");
|
2022-06-18 18:04:24 +00:00
|
|
|
|
|
|
|
|
|
Sanitize();
|
|
|
|
|
|
|
|
|
|
g4items = (string[])itemlist.Clone();
|
|
|
|
|
Get("mail4").CopyTo(g4items, 137);
|
|
|
|
|
}
|
2018-05-19 04:35:57 +00:00
|
|
|
|
|
2022-11-25 01:42:17 +00:00
|
|
|
|
private LocationSet4 Get4(string ident)
|
|
|
|
|
{
|
|
|
|
|
var met0 = Get($"{ident}_00000");
|
|
|
|
|
var met2 = Get($"{ident}_02000");
|
|
|
|
|
var met3 = Get($"{ident}_03000");
|
|
|
|
|
return new LocationSet4(met0, met2, met3);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private LocationSet6 Get6(string ident)
|
|
|
|
|
{
|
|
|
|
|
var met0 = Get($"{ident}_00000");
|
|
|
|
|
var met3 = Get($"{ident}_30000");
|
|
|
|
|
var met4 = Get($"{ident}_40000");
|
|
|
|
|
var met6 = Get($"{ident}_60000");
|
|
|
|
|
return new LocationSet6(met0,met3, met4, met6);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private LocationSet6 Get6(string ident, string[] met3, string[] met6)
|
|
|
|
|
{
|
|
|
|
|
var met0 = Get($"{ident}_00000");
|
|
|
|
|
var met4 = Get($"{ident}_40000");
|
|
|
|
|
return new LocationSet6(met0, met3, met4, met6);
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
|
private string[] GetG3CXD(string[] arr, string fileName)
|
|
|
|
|
{
|
2022-08-25 03:32:40 +00:00
|
|
|
|
// Concatenate the Gen3 Item list with the CXD item array; CXD items starting at index 500.
|
2022-11-25 01:42:17 +00:00
|
|
|
|
var item500 = Get(fileName);
|
2022-06-18 18:04:24 +00:00
|
|
|
|
var result = new string[500 + item500.Length];
|
|
|
|
|
for (int i = arr.Length; i < result.Length; i++)
|
2023-01-22 04:02:33 +00:00
|
|
|
|
result[i] = string.Empty;
|
2022-06-18 18:04:24 +00:00
|
|
|
|
arr.CopyTo(result, 0);
|
|
|
|
|
item500.CopyTo(result, 500);
|
|
|
|
|
return result;
|
|
|
|
|
}
|
2021-06-03 19:04:19 +00:00
|
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
|
private static void SanitizeMetStringsCXD(string[] cxd)
|
|
|
|
|
{
|
2023-01-22 04:02:33 +00:00
|
|
|
|
// Less than 10% of location values are unique.
|
2022-06-18 18:04:24 +00:00
|
|
|
|
// Just mark them with the ID if they aren't empty.
|
|
|
|
|
for (int i = 0; i < 227; i++)
|
2018-08-03 03:11:42 +00:00
|
|
|
|
{
|
2022-11-25 01:42:17 +00:00
|
|
|
|
ref var str = ref cxd[i];
|
2022-06-18 18:04:24 +00:00
|
|
|
|
if (str.Length != 0)
|
2022-11-25 01:42:17 +00:00
|
|
|
|
str = $"{str} [{i:000}]";
|
2018-08-03 03:11:42 +00:00
|
|
|
|
}
|
2022-06-18 18:04:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void Sanitize()
|
|
|
|
|
{
|
|
|
|
|
SanitizeItemNames();
|
|
|
|
|
SanitizeMetLocations();
|
|
|
|
|
|
|
|
|
|
// De-duplicate the Calyrex ability names
|
|
|
|
|
abilitylist[(int)Core.Ability.AsOneI] += $" ({specieslist[(int)Core.Species.Glastrier]})";
|
|
|
|
|
abilitylist[(int)Core.Ability.AsOneG] += $" ({specieslist[(int)Core.Species.Spectrier]})";
|
2023-09-16 06:36:21 +00:00
|
|
|
|
// De-duplicate the Ogerpon ability names
|
|
|
|
|
abilitylist[(int)Core.Ability.EmbodyAspect0] += $" ({forms[FormConverter.MaskTeal]})";
|
2023-09-16 19:40:09 +00:00
|
|
|
|
abilitylist[(int)Core.Ability.EmbodyAspect1] += $" ({forms[FormConverter.MaskHearthflame]})";
|
|
|
|
|
abilitylist[(int)Core.Ability.EmbodyAspect2] += $" ({forms[FormConverter.MaskWellspring]})";
|
2023-09-16 06:36:21 +00:00
|
|
|
|
abilitylist[(int)Core.Ability.EmbodyAspect3] += $" ({forms[FormConverter.MaskCornerstone]})";
|
2022-06-18 18:04:24 +00:00
|
|
|
|
|
|
|
|
|
// Replace the Egg Name with ---; egg name already stored to eggname
|
2022-08-25 03:32:40 +00:00
|
|
|
|
specieslist[0] = EmptyIndex;
|
2022-06-18 18:04:24 +00:00
|
|
|
|
// Fix (None) tags
|
|
|
|
|
var none = $"({itemlist[0]})";
|
2022-11-25 01:42:17 +00:00
|
|
|
|
abilitylist[0] = itemlist[0] = movelist[0] = Gen6.Met0[0] = Gen5.Met0[0] = Gen4.Met0[0] = CXD.Met0[0] = puffs[0] = none;
|
2022-06-18 18:04:24 +00:00
|
|
|
|
}
|
2018-08-03 03:11:42 +00:00
|
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
|
private void SanitizeItemNames()
|
|
|
|
|
{
|
|
|
|
|
// Fix Item Names (Duplicate entries)
|
|
|
|
|
var HM06 = itemlist[425];
|
|
|
|
|
var HM0 = HM06[..^1]; // language ambiguous!
|
|
|
|
|
itemlist[426] = $"{HM0}7 (G4)";
|
|
|
|
|
itemlist[427] = $"{HM0}8 (G4)";
|
|
|
|
|
itemlist[456] += " (HG/SS)"; // S.S. Ticket
|
|
|
|
|
itemlist[736] += " (OR/AS)"; // S.S. Ticket
|
|
|
|
|
itemlist[463] += " (DPPt)"; // Storage Key
|
|
|
|
|
itemlist[734] += " (OR/AS)"; // Storage Key
|
|
|
|
|
itemlist[476] += " (HG/SS)"; // Basement Key
|
|
|
|
|
itemlist[723] += " (OR/AS)"; // Basement Key
|
|
|
|
|
itemlist[621] += " (M)"; // Xtransceiver
|
|
|
|
|
itemlist[626] += " (F)"; // Xtransceiver
|
|
|
|
|
itemlist[629] += " (2)"; // DNA Splicers
|
|
|
|
|
itemlist[637] += " (2)"; // Dropped Item
|
|
|
|
|
itemlist[707] += " (2)"; // Travel Trunk
|
|
|
|
|
itemlist[713] += " (2)"; // Alt Bike
|
|
|
|
|
itemlist[714] += " (2)"; // Holo Caster
|
|
|
|
|
itemlist[729] += " (1)"; // Meteorite
|
|
|
|
|
itemlist[740] += " (2)"; // Contest Costume
|
|
|
|
|
itemlist[751] += " (2)"; // Meteorite
|
|
|
|
|
itemlist[771] += " (3)"; // Meteorite
|
|
|
|
|
itemlist[772] += " (4)"; // Meteorite
|
|
|
|
|
itemlist[842] += " (SM)"; // Fishing Rod
|
|
|
|
|
itemlist[945] += " (2)"; // Used Solarizer
|
|
|
|
|
itemlist[946] += " (2)"; // Used Lunarizer
|
|
|
|
|
|
|
|
|
|
itemlist[873] += " (GP/GE)"; // S.S. Ticket
|
|
|
|
|
itemlist[459] += " (HG/SS)"; // Parcel
|
|
|
|
|
itemlist[467] += " (Pt)"; // Secret Key
|
|
|
|
|
itemlist[475] += " (HG/SS)"; // Card Key
|
|
|
|
|
itemlist[894] += " (GP)"; // Leaf Letter
|
|
|
|
|
itemlist[895] += " (GE)"; // Leaf Letter
|
|
|
|
|
|
|
|
|
|
// some languages have same names for other items!
|
|
|
|
|
itemlist[878] += " (GP/GE)"; // Lift Key (Elevator Key=700)
|
|
|
|
|
itemlist[479] += " (HG/SS)"; // Lost Item (Dropped Item=636)
|
|
|
|
|
|
2023-04-16 19:58:07 +00:00
|
|
|
|
// Append Z-Crystal Key Item differentiator
|
|
|
|
|
foreach (var i in ItemStorage7USUM.Pouch_ZCrystal_USUM)
|
2022-06-18 18:04:24 +00:00
|
|
|
|
itemlist[i] += " [Z]";
|
|
|
|
|
|
|
|
|
|
itemlist[0121] += " (1)"; // Pokémon Box Link
|
|
|
|
|
itemlist[1075] += " (2)"; // Pokémon Box Link
|
|
|
|
|
|
|
|
|
|
itemlist[1080] += " (SW/SH)"; // Fishing Rod
|
|
|
|
|
|
|
|
|
|
itemlist[1081] += " (1)"; // Rotom Bike
|
|
|
|
|
itemlist[1266] += " (2)"; // Rotom Bike
|
|
|
|
|
itemlist[1585] += " (3)"; // Rotom Bike
|
|
|
|
|
itemlist[1586] += " (4)"; // Rotom Bike
|
|
|
|
|
|
|
|
|
|
itemlist[1590] += " (1)"; // Reins of Unity
|
|
|
|
|
itemlist[1591] += " (2)"; // Reins of Unity
|
|
|
|
|
itemlist[1607] += " (3)"; // Reins of Unity
|
|
|
|
|
|
|
|
|
|
for (int i = 12; i <= 29; i++) // Differentiate DNA Samples
|
|
|
|
|
g3coloitems[500 + i] += $" ({i - 11:00})";
|
|
|
|
|
// differentiate G3 Card Key from Colo
|
|
|
|
|
g3coloitems[500 + 10] += " (COLO)";
|
|
|
|
|
|
|
|
|
|
SanitizeItemsLA(itemlist);
|
2022-11-25 01:42:17 +00:00
|
|
|
|
SanitizeItemsSV(itemlist);
|
2022-06-18 18:04:24 +00:00
|
|
|
|
|
|
|
|
|
if (lang is "fr")
|
2018-05-19 04:35:57 +00:00
|
|
|
|
{
|
2022-06-18 18:04:24 +00:00
|
|
|
|
itemlist[1681] += " (LA)"; // Galet Noir dup with 617 (Dark Stone | Black Tumblestone)
|
2022-11-25 01:42:17 +00:00
|
|
|
|
itemlist[1262] += " (G8)"; // Nouilles dup with 1934 (Instant Noodles | Rice)
|
|
|
|
|
itemlist[1263] += " (G8)"; // Steak Haché dup with 1925 (Precooked Burger | Herbed Sausage)
|
2018-05-19 04:35:57 +00:00
|
|
|
|
}
|
2022-06-18 18:04:24 +00:00
|
|
|
|
else if (lang is "ja")
|
2018-05-19 04:35:57 +00:00
|
|
|
|
{
|
2022-06-18 18:04:24 +00:00
|
|
|
|
itemlist[1693] += " (LA)"; // むしよけスプレー dup with 79 (Repel)
|
|
|
|
|
itemlist[1716] += " (LA)"; // ビビリだま dup with 847 (Adrenaline Orb | Scatter Bang)
|
|
|
|
|
itemlist[1717] += " (LA)"; // けむりだま dup with 228 (Smoke Ball | Smoke Bomb)
|
2022-02-05 01:35:15 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
|
itemlist[464] += " (G4)"; // Secret Medicine
|
|
|
|
|
itemlist[1763] += " (LA)"; // Secret Medicine
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-25 01:42:17 +00:00
|
|
|
|
private static void SanitizeItemsSV(string[] items)
|
|
|
|
|
{
|
|
|
|
|
items[2313] += " (1)"; // Academy Bottle
|
|
|
|
|
items[2314] += " (2)"; // Academy Bottle
|
|
|
|
|
items[2318] += " (1)"; // Academy Cup
|
|
|
|
|
items[2319] += " (2)"; // Academy Cup
|
|
|
|
|
items[2323] += " (1)"; // Academy Tablecloth
|
|
|
|
|
items[2324] += " (2)"; // Academy Tablecloth
|
|
|
|
|
items[2329] += " (1)"; // Academy Ball
|
|
|
|
|
items[2330] += " (2)"; // Academy Ball
|
|
|
|
|
items[0694] += " (G6-8)"; // TM100, not held.
|
2023-09-16 06:36:21 +00:00
|
|
|
|
|
|
|
|
|
items[2418] += " (SL)"; // Academy Chairs
|
|
|
|
|
items[2419] += " (VL)"; // Academy Chairs
|
2022-11-25 01:42:17 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
|
private static void SanitizeItemsLA(string[] items)
|
|
|
|
|
{
|
|
|
|
|
// Recipes
|
|
|
|
|
items[1784] += " (~)"; // Gigaton Ball
|
|
|
|
|
items[1783] += " (~)"; // Leaden Ball
|
|
|
|
|
items[1753] += " (~)"; // Heavy Ball
|
|
|
|
|
items[1752] += " (~)"; // Jet Ball
|
|
|
|
|
items[1751] += " (~)"; // Wing Ball
|
|
|
|
|
items[1731] += " (~)"; // Twice-Spiced Radish
|
|
|
|
|
items[1730] += " (~)"; // Choice Dumpling
|
|
|
|
|
items[1729] += " (~)"; // Swap Snack
|
|
|
|
|
items[1677] += " (~)"; // Aux Powerguard
|
|
|
|
|
items[1676] += " (~)"; // Aux Evasion
|
|
|
|
|
items[1675] += " (~)"; // Dire Hit
|
|
|
|
|
items[1674] += " (~)"; // Aux Guard
|
|
|
|
|
items[1673] += " (~)"; // Aux Power
|
|
|
|
|
items[1671] += " (~)"; // Stealth Spray
|
|
|
|
|
items[1670] += " (~)"; // Max Elixir
|
|
|
|
|
items[1669] += " (~)"; // Max Ether
|
|
|
|
|
items[1668] += " (~)"; // Max Revive
|
|
|
|
|
items[1667] += " (~)"; // Revive
|
|
|
|
|
items[1666] += " (~)"; // Full Heal
|
|
|
|
|
items[1665] += " (~)"; // Jubilife Muffin
|
|
|
|
|
items[1664] += " (~)"; // Old Gateau
|
|
|
|
|
items[1663] += " (~)"; // Superb Remedy
|
|
|
|
|
items[1662] += " (~)"; // Fine Remedy
|
|
|
|
|
items[1661] += " (~)"; // Remedy
|
|
|
|
|
items[1660] += " (~)"; // Full Restore
|
|
|
|
|
items[1659] += " (~)"; // Max Potion
|
|
|
|
|
items[1658] += " (~)"; // Hyper Potion
|
|
|
|
|
items[1657] += " (~)"; // Super Potion
|
|
|
|
|
items[1656] += " (~)"; // Potion
|
|
|
|
|
items[1655] += " (~)"; // Salt Cake
|
|
|
|
|
items[1654] += " (~)"; // Bean Cake
|
|
|
|
|
items[1653] += " (~)"; // Grain Cake
|
|
|
|
|
items[1652] += " (~)"; // Honey Cake
|
|
|
|
|
items[1650] += " (~)"; // Mushroom Cake
|
|
|
|
|
items[1649] += " (~)"; // Star Piece
|
|
|
|
|
items[1648] += " (~)"; // Sticky Glob
|
|
|
|
|
items[1647] += " (~)"; // Scatter Bang
|
|
|
|
|
items[1646] += " (~)"; // Smoke Bomb
|
|
|
|
|
items[1644] += " (~)"; // Pokéshi Doll
|
|
|
|
|
items[1643] += " (~)"; // Feather Ball
|
|
|
|
|
items[1642] += " (~)"; // Ultra Ball
|
|
|
|
|
items[1641] += " (~)"; // Great Ball
|
|
|
|
|
items[1640] += " (~)"; // Poké Ball
|
|
|
|
|
|
|
|
|
|
// Items
|
|
|
|
|
items[1616] += " (LA)"; // Dire Hit
|
|
|
|
|
items[1689] += " (LA)"; // Snowball
|
|
|
|
|
items[1710] += " (LA)"; // Poké Ball
|
|
|
|
|
items[1711] += " (LA)"; // Great Ball
|
|
|
|
|
items[1712] += " (LA)"; // Ultra Ball
|
|
|
|
|
items[1748] += " (LA)"; // Heavy Ball
|
|
|
|
|
|
|
|
|
|
// Key Items
|
|
|
|
|
items[1622] += " (-)"; // Poké Ball
|
|
|
|
|
items[1765] += " (1)"; // Lost Satchel
|
|
|
|
|
items[1766] += " (2)"; // Lost Satchel
|
|
|
|
|
items[1767] += " (3)"; // Lost Satchel
|
|
|
|
|
items[1768] += " (4)"; // Lost Satchel
|
|
|
|
|
items[1769] += " (5)"; // Lost Satchel
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void SanitizeMetLocations()
|
|
|
|
|
{
|
|
|
|
|
// Fix up some of the Location strings to make them more descriptive
|
2022-11-25 01:42:17 +00:00
|
|
|
|
SanitizeMetGen4(Gen4);
|
|
|
|
|
SanitizeMetGen5(Gen5);
|
|
|
|
|
SanitizeMetGen6(Gen6);
|
|
|
|
|
SanitizeMetGen7(Gen7);
|
|
|
|
|
SanitizeMetGen7b(Gen7b);
|
|
|
|
|
SanitizeMetGen8(Gen8);
|
|
|
|
|
SanitizeMetGen8a(Gen8a);
|
|
|
|
|
SanitizeMetGen8b(Gen8b);
|
|
|
|
|
SanitizeMetGen9(Gen9);
|
2022-06-18 18:04:24 +00:00
|
|
|
|
|
|
|
|
|
if (lang is "es" or "it")
|
2022-02-05 01:35:15 +00:00
|
|
|
|
{
|
2022-06-18 18:04:24 +00:00
|
|
|
|
// Campeonato Mundial duplicates
|
|
|
|
|
for (int i = 28; i < 35; i++)
|
2022-11-25 01:42:17 +00:00
|
|
|
|
Gen6.Met4[i] += " (-)";
|
2022-06-18 18:04:24 +00:00
|
|
|
|
|
|
|
|
|
// Evento de Videojuegos -- first as duplicate
|
2022-11-25 01:42:17 +00:00
|
|
|
|
Gen6.Met4[35] += " (-)";
|
|
|
|
|
Gen7.Met4[38] += " (-)";
|
|
|
|
|
Gen7b.Met4[27] += " (-)";
|
2018-05-19 04:35:57 +00:00
|
|
|
|
}
|
2018-08-03 03:11:42 +00:00
|
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
|
if (lang == "ko")
|
2018-05-19 04:35:57 +00:00
|
|
|
|
{
|
2022-06-18 18:04:24 +00:00
|
|
|
|
// Pokémon Ranger duplicate (should be Ranger Union)
|
2022-11-25 01:42:17 +00:00
|
|
|
|
Gen5.Met4[71] += " (-)";
|
2018-05-19 04:35:57 +00:00
|
|
|
|
}
|
2022-06-18 18:04:24 +00:00
|
|
|
|
}
|
2018-08-03 03:11:42 +00:00
|
|
|
|
|
2022-11-25 01:42:17 +00:00
|
|
|
|
private void SanitizeMetGen4(LocationSet4 set)
|
2022-06-18 18:04:24 +00:00
|
|
|
|
{
|
2022-11-25 01:42:17 +00:00
|
|
|
|
set.Met0[054] += " (DP/Pt)"; // Victory Road
|
|
|
|
|
set.Met0[221] += " (HG/SS)"; // Victory Road
|
2019-07-09 05:05:59 +00:00
|
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
|
// German language duplicate; handle for all since it can be confused.
|
2022-11-25 01:42:17 +00:00
|
|
|
|
set.Met0[104] += " (DP/Pt)"; // Vista Lighthouse
|
|
|
|
|
set.Met0[212] += " (HG/SS)"; // Lighthouse
|
2019-07-09 05:05:59 +00:00
|
|
|
|
|
2022-11-25 01:42:17 +00:00
|
|
|
|
set.Met2[1] += $" ({NPC})"; // Anything from an NPC
|
|
|
|
|
set.Met2[2] += $" ({EggName})"; // Egg From Link Trade
|
2022-06-18 18:04:24 +00:00
|
|
|
|
}
|
2019-07-09 05:05:59 +00:00
|
|
|
|
|
2022-11-25 01:42:17 +00:00
|
|
|
|
private void SanitizeMetGen5(LocationSet6 set)
|
2022-06-18 18:04:24 +00:00
|
|
|
|
{
|
2022-11-25 01:42:17 +00:00
|
|
|
|
set.Met0[36] = $"{set.Met0[84]}/{set.Met0[36]}"; // Cold Storage in BW = PWT in BW2
|
|
|
|
|
set.Met0[40] += " (B/W)"; // Victory Road in BW
|
|
|
|
|
set.Met0[134] += " (B2/W2)"; // Victory Road in B2W2
|
2022-06-18 18:04:24 +00:00
|
|
|
|
// BW2 Entries from 76 to 105 are for Entralink in BW
|
|
|
|
|
for (int i = 76; i < 106; i++)
|
2022-11-25 01:42:17 +00:00
|
|
|
|
set.Met0[i] += "●";
|
2022-06-18 18:04:24 +00:00
|
|
|
|
|
|
|
|
|
// Collision between 40002 (legal) and 00002 (illegal) "Faraway place"
|
2022-11-25 01:42:17 +00:00
|
|
|
|
if (set.Met0[2] == set.Met4[2])
|
|
|
|
|
set.Met0[2] += " (2)";
|
2022-06-18 18:04:24 +00:00
|
|
|
|
|
|
|
|
|
for (int i = 97; i < 109; i++)
|
2022-11-25 01:42:17 +00:00
|
|
|
|
set.Met4[i] += $" ({i - 97})";
|
2022-06-18 18:04:24 +00:00
|
|
|
|
|
|
|
|
|
// Localize the Poketransfer to the language (30001)
|
2022-11-25 01:42:17 +00:00
|
|
|
|
set.Met3[1] = GameLanguage.GetTransporterName(LanguageIndex);
|
|
|
|
|
set.Met3[2] += $" ({NPC})"; // Anything from an NPC
|
|
|
|
|
set.Met3[3] += $" ({EggName})"; // Link Trade (Egg)
|
2022-06-18 18:04:24 +00:00
|
|
|
|
|
|
|
|
|
// Zorua/Zoroark events
|
2022-11-25 01:42:17 +00:00
|
|
|
|
set.Met3[10] = $"{specieslist[251]} ({specieslist[570]} 1)"; // Celebi's Zorua Event
|
|
|
|
|
set.Met3[11] = $"{specieslist[251]} ({specieslist[570]} 2)"; // Celebi's Zorua Event
|
|
|
|
|
set.Met3[12] = $"{specieslist[571]} (1)"; // Zoroark
|
|
|
|
|
set.Met3[13] = $"{specieslist[571]} (2)"; // Zoroark
|
2022-06-18 18:04:24 +00:00
|
|
|
|
|
2022-11-25 01:42:17 +00:00
|
|
|
|
set.Met6[3] += $" ({EggName})"; // Egg Treasure Hunter/Breeder, whatever...
|
2022-06-18 18:04:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-11-25 01:42:17 +00:00
|
|
|
|
private void SanitizeMetGen6(LocationSet6 set)
|
2022-06-18 18:04:24 +00:00
|
|
|
|
{
|
2022-09-27 16:58:00 +00:00
|
|
|
|
// Add in the sub-location if available.
|
|
|
|
|
for (int i = 8; i <= 136; i += 2)
|
|
|
|
|
{
|
2022-11-25 01:42:17 +00:00
|
|
|
|
var nextLoc = set.Met0[i + 1];
|
2022-09-27 16:58:00 +00:00
|
|
|
|
if (nextLoc.Length == 0)
|
|
|
|
|
continue;
|
2022-11-25 01:42:17 +00:00
|
|
|
|
set.Met0[i + 1] = string.Empty;
|
|
|
|
|
set.Met0[i] += $" ({nextLoc})";
|
2022-09-27 16:58:00 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-11-25 01:42:17 +00:00
|
|
|
|
set.Met0[104] += " (X/Y)"; // Victory Road
|
|
|
|
|
set.Met0[106] += " (X/Y)"; // Pokémon League
|
|
|
|
|
set.Met0[202] += " (OR/AS)"; // Pokémon League
|
|
|
|
|
set.Met0[298] += " (OR/AS)"; // Victory Road
|
|
|
|
|
set.Met3[1] += $" ({NPC})"; // Anything from an NPC
|
|
|
|
|
set.Met3[2] += $" ({EggName})"; // Egg From Link Trade
|
2022-06-18 18:04:24 +00:00
|
|
|
|
|
|
|
|
|
for (int i = 63; i <= 69; i++)
|
2022-11-25 01:42:17 +00:00
|
|
|
|
set.Met4[i] += $" ({i - 62})";
|
2022-06-18 18:04:24 +00:00
|
|
|
|
}
|
2018-08-03 03:11:42 +00:00
|
|
|
|
|
2022-11-25 01:42:17 +00:00
|
|
|
|
private void SanitizeMetGen7(LocationSet6 set)
|
2022-06-18 18:04:24 +00:00
|
|
|
|
{
|
|
|
|
|
// Sun/Moon duplicates -- elaborate!
|
2022-11-25 01:42:17 +00:00
|
|
|
|
for (int i = 6; i < set.Met0.Length; i += 2)
|
2018-05-19 04:35:57 +00:00
|
|
|
|
{
|
2022-06-18 18:04:24 +00:00
|
|
|
|
if (i is >= 194 and < 198)
|
|
|
|
|
continue; // Skip Island Names (unused)
|
2022-11-25 01:42:17 +00:00
|
|
|
|
var nextLoc = set.Met0[i + 1];
|
2022-06-18 18:04:24 +00:00
|
|
|
|
if (nextLoc.Length == 0)
|
|
|
|
|
continue;
|
2022-11-25 01:42:17 +00:00
|
|
|
|
set.Met0[i + 1] = string.Empty;
|
|
|
|
|
set.Met0[i] += $" ({nextLoc})";
|
2018-05-19 04:35:57 +00:00
|
|
|
|
}
|
2022-11-25 01:42:17 +00:00
|
|
|
|
set.Met0[32] += " (2)";
|
|
|
|
|
set.Met0[102] += " (2)";
|
2022-06-18 18:04:24 +00:00
|
|
|
|
|
2022-11-25 01:42:17 +00:00
|
|
|
|
set.Met3[1] += $" ({NPC})"; // Anything from an NPC
|
|
|
|
|
set.Met3[2] += $" ({EggName})"; // Egg From Link Trade
|
2022-06-18 18:04:24 +00:00
|
|
|
|
for (int i = 3; i <= 6; i++) // distinguish first set of regions (unused) from second (used)
|
2022-11-25 01:42:17 +00:00
|
|
|
|
set.Met3[i] += " (-)";
|
2022-06-18 18:04:24 +00:00
|
|
|
|
|
|
|
|
|
for (int i = 59; i < 66; i++) // distinguish Event year duplicates
|
2022-11-25 01:42:17 +00:00
|
|
|
|
set.Met4[i] += " (-)";
|
|
|
|
|
}
|
2018-08-03 03:11:42 +00:00
|
|
|
|
|
2023-01-22 04:02:33 +00:00
|
|
|
|
private static void SanitizeMetGen7b(LocationSet6 set)
|
2022-11-25 01:42:17 +00:00
|
|
|
|
{
|
2022-06-18 18:04:24 +00:00
|
|
|
|
for (int i = 48; i < 55; i++) // distinguish Event year duplicates
|
2022-11-25 01:42:17 +00:00
|
|
|
|
set.Met4[i] += " (-)";
|
2022-06-18 18:04:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-11-25 01:42:17 +00:00
|
|
|
|
private void SanitizeMetGen8(LocationSet6 set)
|
2022-06-18 18:04:24 +00:00
|
|
|
|
{
|
|
|
|
|
// SW/SH duplicates -- elaborate!
|
2022-11-25 01:42:17 +00:00
|
|
|
|
for (int i = 88; i < set.Met0.Length; i += 2)
|
2018-05-19 04:35:57 +00:00
|
|
|
|
{
|
2022-11-25 01:42:17 +00:00
|
|
|
|
var nextLoc = set.Met0[i + 1];
|
2022-06-18 18:04:24 +00:00
|
|
|
|
if (nextLoc.Length == 0)
|
|
|
|
|
continue;
|
2022-11-25 01:42:17 +00:00
|
|
|
|
set.Met0[i + 1] = string.Empty;
|
|
|
|
|
set.Met0[i] += $" ({nextLoc})";
|
2018-05-19 04:35:57 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-11-25 01:42:17 +00:00
|
|
|
|
set.Met3[1] += $" ({NPC})"; // Anything from an NPC
|
|
|
|
|
set.Met3[2] += $" ({EggName})"; // Egg From Link Trade
|
2022-06-18 18:04:24 +00:00
|
|
|
|
for (int i = 3; i <= 6; i++) // distinguish first set of regions (unused) from second (used)
|
2022-11-25 01:42:17 +00:00
|
|
|
|
set.Met3[i] += " (-)";
|
|
|
|
|
set.Met3[19] += " (?)"; // Kanto for the third time
|
2022-06-18 18:04:24 +00:00
|
|
|
|
|
|
|
|
|
for (int i = 55; i < 61; i++) // distinguish Event year duplicates
|
2022-11-25 01:42:17 +00:00
|
|
|
|
set.Met4[i] += " (-)";
|
|
|
|
|
set.Met4[30] += " (-)"; // a Video game Event (in spanish etc) -- duplicate with line 39
|
|
|
|
|
set.Met4[53] += " (-)"; // a Pokémon event -- duplicate with line 37
|
|
|
|
|
|
|
|
|
|
set.Met4[81] += " (-)"; // Pokémon GO -- duplicate with 30000's entry
|
|
|
|
|
set.Met4[86] += " (-)"; // Pokémon HOME -- duplicate with 30000's entry
|
|
|
|
|
// set.Met3[12] += " (-)"; // Pokémon GO -- duplicate with 40000's entry
|
|
|
|
|
// set.Met3[18] += " (-)"; // Pokémon HOME -- duplicate with 40000's entry
|
2022-06-18 18:04:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-11-25 01:42:17 +00:00
|
|
|
|
private void SanitizeMetGen8b(LocationSet6 set)
|
2022-06-18 18:04:24 +00:00
|
|
|
|
{
|
2022-11-25 01:42:17 +00:00
|
|
|
|
set.Met3[1] += $" ({NPC})"; // Anything from an NPC
|
|
|
|
|
set.Met3[2] += $" ({EggName})"; // Egg From Link Trade
|
2022-06-18 18:04:24 +00:00
|
|
|
|
|
2022-11-25 01:42:17 +00:00
|
|
|
|
Deduplicate(set.Met0, 00000);
|
|
|
|
|
Deduplicate(set.Met3, 30000);
|
|
|
|
|
Deduplicate(set.Met4, 40000);
|
|
|
|
|
Deduplicate(set.Met6, 60000);
|
2022-06-18 18:04:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-11-25 01:42:17 +00:00
|
|
|
|
private void SanitizeMetGen8a(LocationSet6 set)
|
2022-06-18 18:04:24 +00:00
|
|
|
|
{
|
2022-11-25 01:42:17 +00:00
|
|
|
|
set.Met0[31] += " (2)"; // in Floaro Gardens
|
|
|
|
|
set.Met3[1] += $" ({NPC})"; // Anything from an NPC
|
|
|
|
|
set.Met3[2] += $" ({EggName})"; // Egg From Link Trade
|
2022-06-18 18:04:24 +00:00
|
|
|
|
for (int i = 3; i <= 6; i++) // distinguish first set of regions (unused) from second (used)
|
2022-11-25 01:42:17 +00:00
|
|
|
|
set.Met3[i] += " (-)";
|
|
|
|
|
set.Met3[19] += " (?)"; // Kanto for the third time
|
2022-06-18 18:04:24 +00:00
|
|
|
|
|
2022-11-25 01:42:17 +00:00
|
|
|
|
set.Met4[30] += " (-)"; // a Video game Event (in spanish etc) -- duplicate with line 39
|
|
|
|
|
set.Met4[53] += " (-)"; // a Pokémon event -- duplicate with line 37
|
2022-06-18 18:04:24 +00:00
|
|
|
|
|
2022-11-25 01:42:17 +00:00
|
|
|
|
set.Met4[81] += " (-)"; // Pokémon GO -- duplicate with 30000's entry
|
|
|
|
|
set.Met4[86] += " (-)"; // Pokémon HOME -- duplicate with 30000's entry
|
|
|
|
|
// set.Met3[12] += " (-)"; // Pokémon GO -- duplicate with 40000's entry
|
|
|
|
|
// set.Met3[18] += " (-)"; // Pokémon HOME -- duplicate with 40000's entry
|
2022-06-18 18:04:24 +00:00
|
|
|
|
|
|
|
|
|
for (int i = 55; i <= 60; i++) // distinguish second set of YYYY Event from the first
|
2022-11-25 01:42:17 +00:00
|
|
|
|
set.Met4[i] += " (-)";
|
2022-06-18 18:04:24 +00:00
|
|
|
|
|
2022-11-25 01:42:17 +00:00
|
|
|
|
if (lang is "en" or "es" or "de" or "it" or "fr")
|
2022-02-05 01:35:15 +00:00
|
|
|
|
{
|
2022-06-18 18:04:24 +00:00
|
|
|
|
// Final four locations are not nouns, rather the same location reference (at the...) as prior entries.
|
2022-11-25 01:42:17 +00:00
|
|
|
|
set.Met0[152] += " (152)"; // Galaxy Hall
|
|
|
|
|
set.Met0[153] += " (153)"; // Front Gate
|
|
|
|
|
set.Met0[154] += " (154)"; // Farm
|
|
|
|
|
set.Met0[155] += " (155)"; // Training Grounds
|
2022-02-05 01:35:15 +00:00
|
|
|
|
}
|
2022-06-18 18:04:24 +00:00
|
|
|
|
}
|
2022-02-05 01:35:15 +00:00
|
|
|
|
|
2022-11-25 01:42:17 +00:00
|
|
|
|
private void SanitizeMetGen9(LocationSet6 set)
|
|
|
|
|
{
|
|
|
|
|
var m = set.Met0;
|
|
|
|
|
m[110] += " (1)"; // Area Zero
|
|
|
|
|
m[112] += " (2)"; // Area Zero
|
|
|
|
|
m[114] += " (3)"; // Area Zero
|
|
|
|
|
m[116] += " (4)"; // Area Zero
|
|
|
|
|
m[124] += " (5)"; // Area Zero
|
|
|
|
|
m[126] += " (6)"; // Area Zero
|
|
|
|
|
m[128] += " (7)"; // Area Zero
|
|
|
|
|
|
|
|
|
|
m[040] += " (1)"; // Casseroya Lake
|
|
|
|
|
m[108] += " (2)"; // Casseroya Lake
|
|
|
|
|
m[034] += " (1)"; // East Province (Area One)
|
|
|
|
|
m[104] += " (2)"; // East Province (Area One)
|
|
|
|
|
m[038] += " (1)"; // Glaseado Mountain
|
|
|
|
|
m[042] += " (2)"; // Glaseado Mountain
|
|
|
|
|
m[068] += " (3)"; // Glaseado Mountain
|
|
|
|
|
m[008] += " (1)"; // Mesagoza
|
|
|
|
|
m[072] += " (2)"; // Mesagoza
|
|
|
|
|
m[074] += " (3)"; // Mesagoza
|
|
|
|
|
m[044] += " (1)"; // North Province (Area Three)
|
|
|
|
|
m[102] += " (2)"; // North Province (Area Three)
|
|
|
|
|
m[047] += " (1)"; // North Province (Area Two)
|
|
|
|
|
m[098] += " (2)"; // North Province (Area Two)
|
|
|
|
|
m[016] += " (1)"; // South Province (Area Six)
|
|
|
|
|
m[066] += " (2)"; // South Province (Area Six)
|
|
|
|
|
m[030] += " (1)"; // Tagtree Thicket
|
|
|
|
|
m[106] += " (2)"; // Tagtree Thicket
|
|
|
|
|
m[022] += " (1)"; // West Province (Area One)
|
|
|
|
|
m[100] += " (2)"; // West Province (Area One)
|
|
|
|
|
m[052] += " (1)"; // Zero Gate
|
|
|
|
|
m[054] += " (2)"; // Zero Gate
|
|
|
|
|
m[118] += " (1)"; // Zero Lab
|
|
|
|
|
m[120] += " (2)"; // Zero Lab
|
|
|
|
|
m[122] += " (3)"; // Zero Lab
|
|
|
|
|
|
2023-09-16 06:36:21 +00:00
|
|
|
|
m[144] += " (1)"; // Oni Mountain
|
|
|
|
|
m[147] += " (2)"; // Oni Mountain
|
|
|
|
|
m[149] += " (3)"; // Oni Mountain
|
|
|
|
|
m[150] += " (4)"; // Oni Mountain
|
|
|
|
|
m[169] += " (5)"; // Oni Mountain
|
|
|
|
|
|
|
|
|
|
m[152] += " (1)"; // Crystal Pool
|
|
|
|
|
m[154] += " (2)"; // Crystal Pool
|
|
|
|
|
m[153] += " (1)"; // Oni Mountain Summit
|
|
|
|
|
m[155] += " (2)"; // Oni Mountain Summit
|
|
|
|
|
m[164] += " (1)"; // Kitakami Wilds
|
|
|
|
|
m[167] += " (2)"; // Kitakami Wilds
|
|
|
|
|
|
2022-11-25 01:42:17 +00:00
|
|
|
|
set.Met3[1] += $" ({NPC})"; // Anything from an NPC
|
|
|
|
|
set.Met3[2] += $" ({EggName})"; // Egg From Link Trade
|
|
|
|
|
for (int i = 3; i <= 6; i++) // distinguish first set of regions (unused) from second (used)
|
|
|
|
|
set.Met3[i] += " (-)";
|
|
|
|
|
set.Met3[19] += " (?)"; // Kanto for the third time
|
|
|
|
|
|
|
|
|
|
for (int i = 49; i <= 54; i++) // distinguish Event year duplicates
|
|
|
|
|
set.Met4[i] += " (-)";
|
|
|
|
|
|
|
|
|
|
set.Met4[27] += " (-)"; // a Video game Event (in spanish etc) -- duplicate with line 36
|
|
|
|
|
set.Met4[48] += " (-)"; // a Pokémon event -- duplicate with line 34
|
|
|
|
|
|
|
|
|
|
set.Met4[73] += " (-)"; // Pokémon GO -- duplicate with 30000's entry
|
|
|
|
|
set.Met4[78] += " (-)"; // Pokémon HOME -- duplicate with 30000's entry
|
|
|
|
|
// set.Met3[12] += " (-)"; // Pokémon GO -- duplicate with 40000's entry
|
|
|
|
|
// set.Met3[18] += " (-)"; // Pokémon HOME -- duplicate with 40000's entry
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
|
private static void Deduplicate(string[] arr, int group)
|
|
|
|
|
{
|
|
|
|
|
var counts = new Dictionary<string, int>();
|
2021-11-20 02:23:49 +00:00
|
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
|
foreach (var s in arr)
|
|
|
|
|
{
|
|
|
|
|
counts.TryGetValue(s, out var value);
|
|
|
|
|
counts[s] = value + 1;
|
|
|
|
|
}
|
2021-11-20 02:23:49 +00:00
|
|
|
|
|
|
|
|
|
#if !DEBUG
|
2022-11-25 01:42:17 +00:00
|
|
|
|
var maxCounts = new Dictionary<string, int>(counts);
|
2021-11-20 02:23:49 +00:00
|
|
|
|
#endif
|
2022-06-18 18:04:24 +00:00
|
|
|
|
for (var i = arr.Length - 1; i >= 0; i--)
|
|
|
|
|
{
|
2021-11-20 02:23:49 +00:00
|
|
|
|
#if DEBUG
|
2022-06-18 18:04:24 +00:00
|
|
|
|
arr[i] += $" ({group + i:00000})";
|
2021-11-20 02:23:49 +00:00
|
|
|
|
#else
|
2022-11-25 01:42:17 +00:00
|
|
|
|
var s = arr[i];
|
|
|
|
|
var count = counts[s]--;
|
|
|
|
|
if (count == 1)
|
|
|
|
|
continue;
|
|
|
|
|
var format = maxCounts[s] switch
|
|
|
|
|
{
|
|
|
|
|
>= 100 => " ({0:000})",
|
|
|
|
|
>= 10 => " ({0:00})",
|
|
|
|
|
_ => " ({0})",
|
|
|
|
|
};
|
|
|
|
|
arr[i] += string.Format(format, count);
|
2021-11-20 02:23:49 +00:00
|
|
|
|
#endif
|
|
|
|
|
}
|
2022-06-18 18:04:24 +00:00
|
|
|
|
}
|
2021-11-20 02:23:49 +00:00
|
|
|
|
|
Refactoring: Move Source (Legality) (#3560)
Rewrites a good amount of legality APIs pertaining to:
* Legal moves that can be learned
* Evolution chains & cross-generation paths
* Memory validation with forgotten moves
In generation 8, there are 3 separate contexts an entity can exist in: SW/SH, BD/SP, and LA. Not every entity can cross between them, and not every entity from generation 7 can exist in generation 8 (Gogoat, etc). By creating class models representing the restrictions to cross each boundary, we are able to better track and validate data.
The old implementation of validating moves was greedy: it would iterate for all generations and evolutions, and build a full list of every move that can be learned, storing it on the heap. Now, we check one game group at a time to see if the entity can learn a move that hasn't yet been validated. End result is an algorithm that requires 0 allocation, and a smaller/quicker search space.
The old implementation of storing move parses was inefficient; for each move that was parsed, a new object is created and adjusted depending on the parse. Now, move parse results are `struct` and store the move parse contiguously in memory. End result is faster parsing and 0 memory allocation.
* `PersonalTable` objects have been improved with new API methods to check if a species+form can exist in the game.
* `IEncounterTemplate` objects have been improved to indicate the `EntityContext` they originate in (similar to `Generation`).
* Some APIs have been extended to accept `Span<T>` instead of Array/IEnumerable
2022-08-03 23:15:27 +00:00
|
|
|
|
public string[] GetItemStrings(EntityContext context, GameVersion game = GameVersion.Any) => context switch
|
2022-06-18 18:04:24 +00:00
|
|
|
|
{
|
2022-11-25 01:42:17 +00:00
|
|
|
|
EntityContext.Gen1 => g1items,
|
|
|
|
|
EntityContext.Gen2 => g2items,
|
|
|
|
|
EntityContext.Gen3 => GetItemStrings3(game),
|
|
|
|
|
EntityContext.Gen4 => g4items, // mail names changed 4->5
|
Refactoring: Move Source (Legality) (#3560)
Rewrites a good amount of legality APIs pertaining to:
* Legal moves that can be learned
* Evolution chains & cross-generation paths
* Memory validation with forgotten moves
In generation 8, there are 3 separate contexts an entity can exist in: SW/SH, BD/SP, and LA. Not every entity can cross between them, and not every entity from generation 7 can exist in generation 8 (Gogoat, etc). By creating class models representing the restrictions to cross each boundary, we are able to better track and validate data.
The old implementation of validating moves was greedy: it would iterate for all generations and evolutions, and build a full list of every move that can be learned, storing it on the heap. Now, we check one game group at a time to see if the entity can learn a move that hasn't yet been validated. End result is an algorithm that requires 0 allocation, and a smaller/quicker search space.
The old implementation of storing move parses was inefficient; for each move that was parsed, a new object is created and adjusted depending on the parse. Now, move parse results are `struct` and store the move parse contiguously in memory. End result is faster parsing and 0 memory allocation.
* `PersonalTable` objects have been improved with new API methods to check if a species+form can exist in the game.
* `IEncounterTemplate` objects have been improved to indicate the `EntityContext` they originate in (similar to `Generation`).
* Some APIs have been extended to accept `Span<T>` instead of Array/IEnumerable
2022-08-03 23:15:27 +00:00
|
|
|
|
EntityContext.Gen8b => GetItemStrings8b(),
|
2022-11-25 01:42:17 +00:00
|
|
|
|
EntityContext.Gen9 => GetItemStrings9(),
|
|
|
|
|
_ => itemlist,
|
2022-06-18 18:04:24 +00:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
private string[] GetItemStrings8b()
|
|
|
|
|
{
|
|
|
|
|
// Item Indexes
|
|
|
|
|
var clone = (string[])itemlist.Clone();
|
|
|
|
|
var tm = clone[419][..2];
|
|
|
|
|
for (int i = 420; i <= 427; i++)
|
|
|
|
|
clone[i] = $"{tm}{i - 420 + 93}";
|
|
|
|
|
|
|
|
|
|
clone[618] += "(-)"; // TM93
|
|
|
|
|
clone[619] += "(-)"; // TM94
|
|
|
|
|
clone[620] += "(-)"; // TM95
|
|
|
|
|
clone[690] += "(-)"; // TM96
|
|
|
|
|
clone[691] += "(-)"; // TM97
|
|
|
|
|
clone[692] += "(-)"; // TM98
|
|
|
|
|
clone[693] += "(-)"; // TM99
|
|
|
|
|
clone[694] += "(-)"; // TM100
|
|
|
|
|
return clone;
|
|
|
|
|
}
|
2021-11-20 02:23:49 +00:00
|
|
|
|
|
2022-11-25 01:42:17 +00:00
|
|
|
|
private string[] GetItemStrings9()
|
|
|
|
|
{
|
|
|
|
|
// in Generation 9, TMs are padded to 3 digits; format them appropriately here
|
|
|
|
|
var clone = (string[])itemlist.Clone();
|
|
|
|
|
var zero = lang is "ja" or "zh" or "zh2" ? "0" : "0";
|
|
|
|
|
|
|
|
|
|
for (int i = 328; i <= 419; i++)
|
|
|
|
|
clone[i] = clone[i].Insert(clone[i].Length - 2, zero);
|
|
|
|
|
for (int i = 618; i <= 620; i++)
|
|
|
|
|
clone[i] = clone[i].Insert(clone[i].Length - 2, zero);
|
|
|
|
|
for (int i = 690; i <= 693; i++)
|
|
|
|
|
clone[i] = clone[i].Insert(clone[i].Length - 2, zero);
|
|
|
|
|
|
|
|
|
|
return clone;
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
|
private string[] GetItemStrings3(GameVersion game)
|
|
|
|
|
{
|
|
|
|
|
switch (game)
|
2018-05-19 04:35:57 +00:00
|
|
|
|
{
|
2022-06-18 18:04:24 +00:00
|
|
|
|
case GameVersion.COLO:
|
|
|
|
|
return g3coloitems;
|
|
|
|
|
case GameVersion.XD:
|
|
|
|
|
return g3xditems;
|
|
|
|
|
default:
|
|
|
|
|
if (EReaderBerrySettings.IsEnigma)
|
|
|
|
|
return g3items;
|
|
|
|
|
|
|
|
|
|
var g3ItemsWithEBerry = (string[])g3items.Clone();
|
|
|
|
|
g3ItemsWithEBerry[175] = EReaderBerrySettings.DisplayName;
|
|
|
|
|
return g3ItemsWithEBerry;
|
2018-05-19 04:35:57 +00:00
|
|
|
|
}
|
2022-06-18 18:04:24 +00:00
|
|
|
|
}
|
2018-05-19 04:35:57 +00:00
|
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Gets the location name for the specified parameters.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="isEggLocation">Location is from the <see cref="PKM.Egg_Location"/></param>
|
|
|
|
|
/// <param name="location">Location value</param>
|
|
|
|
|
/// <param name="format">Current <see cref="PKM.Format"/></param>
|
|
|
|
|
/// <param name="generation"><see cref="PKM.Generation"/> of origin</param>
|
|
|
|
|
/// <param name="version">Current GameVersion (only applicable for <see cref="GameVersion.Gen7b"/> differentiation)</param>
|
|
|
|
|
/// <returns>Location name. May be an empty string if no location name is known for that location value.</returns>
|
|
|
|
|
public string GetLocationName(bool isEggLocation, int location, int format, int generation, GameVersion version)
|
|
|
|
|
{
|
|
|
|
|
if (format == 1)
|
2018-06-30 16:59:48 +00:00
|
|
|
|
{
|
2022-11-25 01:42:17 +00:00
|
|
|
|
// Legality binaries have Location IDs that were manually remapped to Gen3 location IDs.
|
2022-06-18 18:04:24 +00:00
|
|
|
|
if (location == 0)
|
2019-06-22 17:50:32 +00:00
|
|
|
|
return string.Empty;
|
2022-11-25 01:42:17 +00:00
|
|
|
|
return Gen3.GetLocationName(location);
|
2018-05-19 04:35:57 +00:00
|
|
|
|
}
|
2018-08-03 03:11:42 +00:00
|
|
|
|
|
2022-11-25 01:42:17 +00:00
|
|
|
|
generation = GetGeneration(generation, isEggLocation, format);
|
|
|
|
|
var set = GetLocations(generation, version);
|
|
|
|
|
if (set is null)
|
2022-06-18 18:04:24 +00:00
|
|
|
|
return string.Empty;
|
2022-11-25 01:42:17 +00:00
|
|
|
|
return set.GetLocationName(location);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static int GetGeneration(int generation, bool isEggLocation, int format)
|
|
|
|
|
{
|
|
|
|
|
if (format == 2)
|
|
|
|
|
return 2;
|
|
|
|
|
if (format == 3)
|
|
|
|
|
return 3;
|
|
|
|
|
if (generation == 4 && (isEggLocation || format == 4))
|
|
|
|
|
return 4;
|
|
|
|
|
if (generation >= 5)
|
|
|
|
|
return generation;
|
|
|
|
|
if (format >= 5)
|
|
|
|
|
return format;
|
|
|
|
|
return -1; // Nonsensical inputs.
|
2018-05-19 04:35:57 +00:00
|
|
|
|
}
|
2022-06-18 18:04:24 +00:00
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Gets the location names array for a specified generation.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="gen">Generation to get location names for.</param>
|
|
|
|
|
/// <param name="version">Version of origin</param>
|
|
|
|
|
/// <returns>List of location names.</returns>
|
2022-11-25 01:42:17 +00:00
|
|
|
|
public ILocationSet? GetLocations(int gen, GameVersion version) => gen switch
|
2022-06-18 18:04:24 +00:00
|
|
|
|
{
|
2022-11-25 01:42:17 +00:00
|
|
|
|
2 => Gen2,
|
|
|
|
|
3 => GameVersion.CXD.Contains(version) ? CXD : Gen3,
|
|
|
|
|
4 => Gen4,
|
|
|
|
|
5 => Gen5,
|
|
|
|
|
6 => Gen6,
|
|
|
|
|
7 => GameVersion.Gen7b.Contains(version) ? Gen7b : Gen7,
|
|
|
|
|
|
2023-06-20 17:36:28 +00:00
|
|
|
|
8 when version is GameVersion.PLA => Gen8a,
|
2022-11-25 01:42:17 +00:00
|
|
|
|
8 when GameVersion.BDSP.Contains(version) => Gen8b,
|
|
|
|
|
8 => Gen8,
|
|
|
|
|
9 => Gen9,
|
|
|
|
|
|
|
|
|
|
_ => null,
|
2022-06-18 18:04:24 +00:00
|
|
|
|
};
|
|
|
|
|
|
2022-11-25 01:42:17 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Gets the location names array for a specified generation.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="gen">Generation to get location names for.</param>
|
|
|
|
|
/// <param name="version">Version of origin</param>
|
|
|
|
|
/// <param name="bankID">BankID used to choose the text bank.</param>
|
|
|
|
|
/// <returns>List of location names.</returns>
|
|
|
|
|
public ReadOnlySpan<string> GetLocationNames(int gen, GameVersion version, int bankID = 0)
|
2022-06-18 18:04:24 +00:00
|
|
|
|
{
|
2022-11-25 01:42:17 +00:00
|
|
|
|
var set = GetLocations(gen, version);
|
|
|
|
|
if (set is null)
|
|
|
|
|
return Array.Empty<string>();
|
|
|
|
|
return set.GetLocationNames(bankID);
|
|
|
|
|
}
|
2020-03-16 19:05:33 +00:00
|
|
|
|
}
|