Misc updates

move encountertype datasource providing to core
fix rerolling EC not updating characteristic
remove some repeat logic calls
relocate geolocation name fetch to separate class, add tests to ensure
functionality, add languageID->country/region fetch method
This commit is contained in:
Kurt 2018-08-25 17:04:01 -07:00
parent a9f65a4617
commit 9dae7dad67
10 changed files with 236 additions and 122 deletions

View file

@ -7,7 +7,6 @@ namespace PKHeX.Core
{
private static readonly string[] ptransp = { "ポケシフター", "Poké Transfer", "Poké Fret", "Pokétrasporto", "Poképorter", "Pokétransfer", "포케시프터", "宝可传送", "寶可傳送" };
private static readonly string[] lang_val = { "ja", "en", "fr", "it", "de", "es", "ko", "zh", "zh2" };
private static readonly string[] lang_geo = { "ja", "en", "fr", "de", "it", "es", "zh", "ko" };
private const string DefaultLanguage = "en";
public static string CurrentLanguage { get; set; } = DefaultLanguage;
public static int Language(string lang = null) => Array.IndexOf(lang_val, lang ?? CurrentLanguage);
@ -17,7 +16,7 @@ namespace PKHeX.Core
// Lazy fetch implementation
private static int DefaultLanguageIndex => Array.IndexOf(lang_val, DefaultLanguage);
private static int GetLanguageIndex(string lang)
public static int GetLanguageIndex(string lang)
{
int l = Array.IndexOf(lang_val, lang);
return l < 0 ? DefaultLanguageIndex : l;
@ -63,72 +62,10 @@ namespace PKHeX.Core
public static IReadOnlyList<ComboItem> LegalMoveDataSource => Strings.LegalMoveDataSource;
public static IReadOnlyList<ComboItem> HaXMoveDataSource => Strings.HaXMoveDataSource;
public static IReadOnlyList<ComboItem> MoveDataSource => Strings.MoveDataSource;
public static IReadOnlyList<ComboItem> EncounterTypeDataSource => Strings.EncounterTypeDataSource;
public static IReadOnlyList<ComboItem> LanguageDataSource(int gen) => GameStrings.LanguageDataSource(gen);
/// <summary>
/// Gets Country and Region strings for corresponding IDs and language.
/// </summary>
/// <param name="country">Country ID</param>
/// <param name="region">Region ID</param>
/// <param name="language">Language ID</param>
/// <returns></returns>
public static Tuple<string, string> GetCountryRegionText(int country, int region, string language)
{
// Get Language we're fetching for
int lang = Array.IndexOf(lang_geo, language);
string c = GetCountryString(country, lang);
string r = GetRegionString(country, region, lang);
return new Tuple<string, string>(c, r); // country, region
}
/// <summary>
/// Gets the Country string for a given Country ID
/// </summary>
/// <param name="country">Country ID</param>
/// <param name="language">Language ID</param>
/// <returns>Country ID string</returns>
private static string GetCountryString(int country, int language)
{
var indexes = GetGlobalizedLocationIndexes("countries", language, out string[] unsortedList);
int index = Array.IndexOf(indexes, country);
if (index < 0)
return "Illegal";
return unsortedList[index];
}
/// <summary>
/// Gets the Region string for a specified country ID.
/// </summary>
/// <param name="country">Country ID</param>
/// <param name="region">Region ID</param>
/// <param name="language">Language ID</param>
/// <returns>Region ID string</returns>
private static string GetRegionString(int country, int region, int language)
{
var indexes = GetGlobalizedLocationIndexes($"sr_{country:000}", language, out string[] unsortedList);
int index = Array.IndexOf(indexes, region);
if (index < 0)
return "Illegal";
return unsortedList[index];
}
private static int[] GetGlobalizedLocationIndexes(string resource, int language, out string[] unsortedList)
{
string[] inputCSV = Util.GetStringList(resource);
// Set up our Temporary Storage
unsortedList = new string[inputCSV.Length - 1];
var indexes = new int[inputCSV.Length - 1];
// Gather our data from the input file
for (int i = 1; i < inputCSV.Length; i++)
{
string[] countryData = inputCSV[i].Split(',');
if (countryData.Length <= 1) continue;
indexes[i - 1] = Convert.ToInt32(countryData[0]);
unsortedList[i - 1] = countryData[language + 1];
}
return indexes;
}
/// <summary>
/// Gets the location names array for a specified generation.

View file

@ -296,6 +296,7 @@ namespace PKHeX.Core
public IReadOnlyList<ComboItem> LegalMoveDataSource { get; private set; }
public IReadOnlyList<ComboItem> HaXMoveDataSource { get; private set; }
public IReadOnlyList<ComboItem> MoveDataSource { get; set; }
public IReadOnlyList<ComboItem> EncounterTypeDataSource { get; private set; }
private IReadOnlyList<ComboItem> MetGen2 { get; set; }
private IReadOnlyList<ComboItem> MetGen3 { get; set; }
@ -316,6 +317,7 @@ namespace PKHeX.Core
NatureDataSource = Util.GetCBList(natures, null);
AbilityDataSource = Util.GetCBList(abilitylist, null);
VersionDataSource = GetVersionList();
EncounterTypeDataSource = Util.GetCBList(encountertypelist, new[] {0}, Legal.Gen4EncounterTypes);
HaXMoveDataSource = Util.GetCBList(movelist, null);
MoveDataSource = LegalMoveDataSource = HaXMoveDataSource.Where(m => !Legal.Z_Moves.Contains(m.Value)).ToList();

View file

@ -0,0 +1,132 @@
using System;
namespace PKHeX.Core
{
public static class GeoLocation
{
private static readonly string[][] CountryList = GetCountryList();
private static readonly string[] lang_geo = { "ja", "en", "fr", "de", "it", "es", "zh", "ko" };
private static readonly string[][][] RegionList = new string[CountryList.Length][][];
private const string INVALID = nameof(INVALID);
private static string[][] GetCountryList()
{
var input = Util.GetStringList("countries");
return UnpackList(input);
}
private static string[][] GetRegionList(int country)
{
var input = Util.GetStringList($"sr_{country:000}");
return UnpackList(input);
}
private static string[][] UnpackList(string[] input)
{
var last = GetEntry(input[input.Length - 1], out var lastIndex);
var list = new string[lastIndex+1][];
list[lastIndex] = last;
for (int i = 1; i < input.Length - 1; i++)
{
var line = input[i];
var entry = GetEntry(line, out var index);
list[index] = entry;
}
return list;
}
private static string[] GetEntry(string line, out int index)
{
var entries = line.Split(',');
index = int.Parse(entries[0]);
return entries;
}
private static string GetCountryName(int countryID, int l)
{
if (l < 0)
return INVALID;
if (countryID >= CountryList.Length)
return INVALID;
var countryNames = CountryList[countryID];
if (l < countryNames?.Length)
return countryNames[l + 1];
return INVALID;
}
private static string GetRegionName(int countryID, int regionID, int l)
{
if (l < 0)
return INVALID;
if (countryID >= RegionList.Length)
return INVALID;
var regionstrs = RegionList[countryID];
if (regionstrs == null)
{
regionstrs = RegionList[countryID] = GetRegionList(countryID);
if (regionstrs == null)
return INVALID;
}
if (regionID >= regionstrs.Length)
return INVALID;
var localized = regionstrs[regionID];
if (l < localized?.Length)
return localized[l + 1];
return INVALID;
}
/// <summary>
/// Gets the Country string for a given Country ID
/// </summary>
/// <param name="country">Country ID</param>
/// <param name="language">Language ID</param>
/// <returns>Country ID string</returns>
public static string GetCountryName(string language, int country) => GetCountryName(country, GetLanguageIndex(language));
/// <summary>
/// Gets the Region string for a specified country ID.
/// </summary>
/// <param name="country">Country ID</param>
/// <param name="region">Region ID</param>
/// <param name="language">Language ID</param>
/// <returns>Region ID string</returns>
public static string GetRegionName(string language, int country, int region) => GetRegionName(country, region, GetLanguageIndex(language));
/// <summary>
/// Gets the Country string for a given Country ID
/// </summary>
/// <param name="country">Country ID</param>
/// <param name="language">Language ID</param>
/// <returns>Country ID string</returns>
public static string GetCountryName(LanguageID language, int country) => GetCountryName(country, GetLanguageIndex(language));
/// <summary>
/// Gets the Region string for a specified country ID.
/// </summary>
/// <param name="country">Country ID</param>
/// <param name="region">Region ID</param>
/// <param name="language">Language ID</param>
/// <returns>Region ID string</returns>
public static string GetRegionName(LanguageID language, int country, int region) => GetRegionName(country, region, GetLanguageIndex(language));
/// <summary>
/// Gets Country and Region strings for corresponding IDs and language.
/// </summary>
/// <param name="country">Country ID</param>
/// <param name="region">Region ID</param>
/// <param name="language">Language ID</param>
/// <returns></returns>
public static Tuple<string, string> GetCountryRegionText(int country, int region, string language)
{
// Get Language we're fetching for
int lang = Array.IndexOf(lang_geo, language);
string c = GetCountryName(country, lang);
string r = GetRegionName(country, region, lang);
return new Tuple<string, string>(c, r); // country, region
}
private static int GetLanguageIndex(string language) => Array.IndexOf(lang_geo, language);
private static int GetLanguageIndex(LanguageID language) => GetLanguageIndex(language.GetLanguage2CharName());
}
}

View file

@ -62,4 +62,24 @@
/// </summary>
ChineseT = 10,
}
public static partial class Extensions
{
public static string GetLanguage2CharName(this LanguageID lang)
{
switch (lang)
{
default: return "en";
case LanguageID.Japanese: return "ja";
case LanguageID.French: return "fr";
case LanguageID.Italian: return "it";
case LanguageID.German: return "de";
case LanguageID.Spanish: return "es";
case LanguageID.Korean: return "ko";
case LanguageID.ChineseS:
case LanguageID.ChineseT: return "zh";
}
}
}
}

View file

@ -64,7 +64,7 @@ namespace PKHeX.Core
int favpkm = BitConverter.ToUInt16(Data, ofs + 0x9C) & 0x7FF;
string gamename = GetGameName(game);
var countryRegion = GameInfo.GetCountryRegionText(country, region, GameInfo.CurrentLanguage);
var countryRegion = GeoLocation.GetCountryRegionText(country, region, GameInfo.CurrentLanguage);
result.Add($"OT: {otname}");
result.Add($"Message: {message}");
result.Add($"Game: {gamename}");

View file

@ -661,7 +661,6 @@
this.CB_Nature.Size = new System.Drawing.Size(126, 21);
this.CB_Nature.TabIndex = 9;
this.CB_Nature.SelectedIndexChanged += new System.EventHandler(this.ValidateComboBox2);
this.CB_Nature.MouseHover += new System.EventHandler(this.UpdateNatureModification);
this.CB_Nature.Validating += new System.ComponentModel.CancelEventHandler(this.ValidateComboBox);
//
// FLP_HeldItem

View file

@ -218,6 +218,7 @@ namespace PKHeX.WinForms.Controls
Stats.UpdateIVs(null, null);
UpdatePKRSInfected(null, null);
UpdatePKRSCured(null, null);
UpdateNatureModification(null, null);
if (HaX) // Load original values from pk not pkm
{
@ -417,11 +418,8 @@ namespace PKHeX.WinForms.Controls
private static int GetSafeIndex(ComboBox cb, int index) => Math.Max(0, Math.Min(cb.Items.Count - 1, index));
private void SetIsShiny(object sender)
private void UpdateIsShiny()
{
if (sender == TB_PID)
pkm.PID = Util.GetHexValue(TB_PID.Text);
// Recalculate shininiess
bool isShiny = pkm.IsShiny;
@ -527,7 +525,7 @@ namespace PKHeX.WinForms.Controls
if (pkm.Format <= 2)
{
Stats.SetATKIVGender(newGender);
SetIsShiny(null);
UpdateIsShiny();
}
else if (pkm.Format <= 4)
{
@ -745,7 +743,7 @@ namespace PKHeX.WinForms.Controls
if (pkm.Species == 201 && !skipForm) // Unown
CB_Form.SelectedIndex = pkm.AltForm;
SetIsShiny(null);
UpdateIsShiny();
UpdateSprite();
}
@ -763,7 +761,7 @@ namespace PKHeX.WinForms.Controls
{
// Change the Level
uint EXP = Util.ToUInt32(TB_EXP.Text);
int Species = WinFormsUtil.GetIndex(CB_Species);
int Species = pkm.Species;
int Level = PKX.GetLevel(Species, EXP);
if (Level == 100)
EXP = PKX.GetEXP(100, Species);
@ -788,10 +786,10 @@ namespace PKHeX.WinForms.Controls
if (!HaX)
Level = 100;
}
if (Level > byte.MaxValue) MT_Level.Text = "255";
if (Level <= 100)
TB_EXP.Text = PKX.GetEXP(Level, WinFormsUtil.GetIndex(CB_Species)).ToString();
if (Level > byte.MaxValue)
MT_Level.Text = "255";
else if (Level <= 100)
TB_EXP.Text = PKX.GetEXP(Level, pkm.Species).ToString();
}
ChangingFields = false;
if (FieldsLoaded) // store values back
@ -820,10 +818,9 @@ namespace PKHeX.WinForms.Controls
pkm.PID = PKX.GetRandomPID(pkm.Species, pkm.Gender, pkm.Version, pkm.Nature, pkm.AltForm, (uint)(CB_Ability.SelectedIndex * 0x10001));
TB_PID.Text = pkm.PID.ToString("X8");
SetIsShiny(null);
UpdateSprite();
if (pkm.Format >= 6 && 3 <= pkm.GenNumber && pkm.GenNumber <= 5)
TB_EC.Text = TB_PID.Text;
Update_ID(TB_EC, e);
}
private void UpdateRandomEC(object sender, EventArgs e)
@ -832,14 +829,16 @@ namespace PKHeX.WinForms.Controls
return;
int wIndex = Array.IndexOf(Legal.WurmpleEvolutions, WinFormsUtil.GetIndex(CB_Species));
uint EC = wIndex < 0 ? Util.Rand32() : PKX.GetWurmpleEC(wIndex/2);
TB_EC.Text = EC.ToString("X8");
pkm.EncryptionConstant = wIndex < 0 ? Util.Rand32() : PKX.GetWurmpleEC(wIndex/2);
TB_EC.Text = pkm.EncryptionConstant.ToString("X8");
Update_ID(TB_EC, e);
UpdateLegality();
}
private void Update255_MTB(object sender, EventArgs e)
{
if (!(sender is MaskedTextBox tb)) return;
if (!(sender is MaskedTextBox tb))
return;
if (Util.ToInt32(tb.Text) > byte.MaxValue)
tb.Text = "255";
}
@ -1131,9 +1130,7 @@ namespace PKHeX.WinForms.Controls
private void UpdateNatureModification(object sender, EventArgs e)
{
if (sender != CB_Nature) return;
int nature = WinFormsUtil.GetIndex(CB_Nature);
string text = Stats.UpdateNatureModification(nature);
string text = Stats.UpdateNatureModification(pkm.Nature);
NatureTip.SetToolTip(CB_Nature, text);
}
@ -1364,7 +1361,7 @@ namespace PKHeX.WinForms.Controls
Stats.UpdateIVs(null, null);
}
SetIsShiny(null);
UpdateIsShiny();
UpdatePreviewSprite?.Invoke(this, null);
UpdateLegality();
}
@ -1382,14 +1379,16 @@ namespace PKHeX.WinForms.Controls
private void Update_ID(object sender, EventArgs e)
{
if (!FieldsLoaded)
return;
// Trim out nonhex characters
TB_PID.Text = Util.GetHexValue(TB_PID.Text).ToString("X8");
TB_EC.Text = Util.GetHexValue(TB_EC.Text).ToString("X8");
TB_PID.Text = (pkm.PID = Util.GetHexValue(TB_PID.Text)).ToString("X8");
TB_EC.Text = (pkm.EncryptionConstant = Util.GetHexValue(TB_EC.Text)).ToString("X8");
SetIsShiny(sender);
UpdateIsShiny();
UpdateSprite();
Stats.UpdateCharacteristic(); // If the EC is changed, EC%6 (Characteristic) might be changed.
if (pkm.Format <= 4 && FieldsLoaded)
if (pkm.Format <= 4)
{
FieldsLoaded = false;
pkm.PID = Util.GetHexValue(TB_PID.Text);
@ -1465,9 +1464,9 @@ namespace PKHeX.WinForms.Controls
}
else if (sender == CB_Nature)
{
pkm.Nature = CB_Nature.SelectedIndex;
if (pkm.Format <= 4)
UpdateRandomPID(sender, e);
pkm.Nature = WinFormsUtil.GetIndex(CB_Nature);
UpdateNatureModification(sender, EventArgs.Empty);
Stats.UpdateIVs(null, EventArgs.Empty); // updating Nature will trigger stats to update as well
UpdateLegality();
@ -1747,7 +1746,7 @@ namespace PKHeX.WinForms.Controls
SetCountrySubRegion(CB_Country, "countries");
CB_3DSReg.DataSource = Util.GetUnsortedCBList("regions3ds");
CB_EncounterType.DataSource = Util.GetCBList(GameInfo.Strings.encountertypelist, new[] { 0 }, Legal.Gen4EncounterTypes);
CB_EncounterType.DataSource = new BindingSource(GameInfo.EncounterTypeDataSource, null);
CB_Nature.DataSource = new BindingSource(GameInfo.NatureDataSource, null);
// Sub editors

View file

@ -185,8 +185,7 @@ namespace PKHeX.WinForms.Controls
string text = tb.Text;
if (string.IsNullOrWhiteSpace(text))
tb.Text = "0";
if (Convert.ToUInt32(text) > ushort.MaxValue)
else if (Convert.ToUInt32(text) > ushort.MaxValue)
tb.Text = "65535";
}
@ -242,20 +241,23 @@ namespace PKHeX.WinForms.Controls
private void UpdateEVTotals()
{
int evtotal = pkm.EVTotal;
if (evtotal > 510) // Background turns Red
TB_EVTotal.BackColor = EVsInvalid;
else if (evtotal == 510) // Maximum EVs
TB_EVTotal.BackColor = EVsMaxed;
else if (evtotal == 508) // Fishy EVs
TB_EVTotal.BackColor = EVsFishy;
else TB_EVTotal.BackColor = TB_IVTotal.BackColor;
var evtotal = pkm.EVTotal;
TB_EVTotal.BackColor = GetEVTotalColor(evtotal, TB_IVTotal.BackColor);
TB_EVTotal.Text = evtotal.ToString();
EVTip.SetToolTip(TB_EVTotal, $"Remaining: {510 - evtotal}");
}
private Color GetEVTotalColor(int evtotal, Color defaultColor)
{
if (evtotal > 510) // Background turns Red
return EVsInvalid;
if (evtotal == 510) // Maximum EVs
return EVsMaxed;
if (evtotal == 508) // Fishy EVs
return EVsFishy;
return defaultColor;
}
public void UpdateStats()
{
// Generate the stats.
@ -267,7 +269,6 @@ namespace PKHeX.WinForms.Controls
LoadBST(pi);
LoadPartyStats(pkm);
}
RecolorStatLabels(pkm.Nature);
}
private void LoadBST(PersonalInfo pi)
@ -299,28 +300,18 @@ namespace PKHeX.WinForms.Controls
L_Characteristic.Text = GameInfo.Strings.characteristics[characteristic];
}
private void RecolorStatLabels(int nature)
{
// Reset Label Colors
foreach (var label in L_Stats.Skip(1))
label.ResetForeColor();
// Set Colored StatLabels only if Nature isn't Neutral
if (PKX.GetNatureModification(nature, out int incr, out int decr))
return;
L_Stats[incr].ForeColor = StatIncreased;
L_Stats[decr].ForeColor = StatDecreased;
}
public string UpdateNatureModification(int nature)
{
// Reset Label Colors
foreach (var label in L_Stats.Skip(1))
label.ResetForeColor();
for (var i = 1; i < L_Stats.Length; i++)
L_Stats[i].ResetForeColor();
// Set Colored StatLabels only if Nature isn't Neutral
if (PKX.GetNatureModification(nature, out int incr, out int decr))
return "-/-";
L_Stats[incr].ForeColor = StatIncreased;
L_Stats[decr].ForeColor = StatDecreased;
return $"+{L_Stats[incr].Text} / -{L_Stats[decr].Text}".Replace(":", "");
}

View file

@ -86,6 +86,7 @@
<Compile Include="Simulator\ShowdownSetTests.cs" />
<Compile Include="Util\DataUtilTests.cs" />
<Compile Include="Util\DateUtilTests.cs" />
<Compile Include="Util\GeoLocationTests.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\PKHeX.Core\PKHeX.Core.csproj">

View file

@ -0,0 +1,33 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using PKHeX.Core;
namespace PKHeX.Tests.Util
{
[TestClass]
public class GeoLocationTests
{
private const string GeoLocationCategory = "GeoLocation Tests";
[TestMethod]
[TestCategory(GeoLocationCategory)]
public void CountryFetch()
{
string japan = GeoLocation.GetCountryName("en", 1);
Assert.AreEqual("Japan", japan);
string argentina = GeoLocation.GetCountryName(LanguageID.English, 10);
Assert.AreEqual("Argentina", argentina);
}
[TestMethod]
[TestCategory(GeoLocationCategory)]
public void RegionFetch()
{
string tokyo = GeoLocation.GetRegionName("en", 1, 2);
Assert.AreEqual("Tokyo", tokyo);
string bermuda = GeoLocation.GetRegionName(LanguageID.Korean, 186, 1);
Assert.AreEqual("버뮤다", bermuda);
}
}
}