Misc fixes/improvements

Reduce memory usage for evo method banlist (static banlist references)
Fix gen6 mega evo flag truncation
simplify QR encode/decode logic a little
Don't apply transparency if transparency is already 100% (skip the loop)
Add gen5 wild pid/tid-sid correlation check
Fix validation value reset (loading gen3-4 pkm without looking at met
tab causes the met location to get reset); fixed by prematurely
validating before setting the value
Fix gen3 pkm with gen4 contest ribbons in gen4/5 getting flagged
incorrectly
This commit is contained in:
Kurt 2017-08-13 00:21:42 -07:00
parent f3382bbd60
commit 9864d84704
7 changed files with 100 additions and 65 deletions

View file

@ -85,10 +85,14 @@ namespace PKHeX.Core
case EncounterStatic s:
if (s.Shiny != null && (bool)s.Shiny ^ pkm.IsShiny)
AddLine(Severity.Invalid, V209, CheckIdentifier.Shiny);
if (pkm.GenNumber == 5 && !s.Gift && !s.Roaming && s.Ability != 4)
VerifyG5PID_IDCorrelation();
break;
case EncounterSlot w:
if (pkm.IsShiny && w.Type == SlotType.HiddenGrotto)
AddLine(Severity.Invalid, V221, CheckIdentifier.Shiny);
if (pkm.GenNumber == 5 && pkm.AbilityNumber != 4)
VerifyG5PID_IDCorrelation();
break;
case PCD d: // fixed PID
if (d.Gift.PK.PID != 1 && pkm.EncryptionConstant != d.Gift.PK.PID)
@ -96,6 +100,13 @@ namespace PKHeX.Core
break;
}
}
private void VerifyG5PID_IDCorrelation()
{
var pid = pkm.EncryptionConstant;
var result = (pid & 1) ^ (pid >> 31) ^ (pkm.TID & 1) ^ (pkm.SID & 1);
if (result != 0)
AddLine(Severity.Invalid, V411, CheckIdentifier.PID);
}
private void VerifyECPIDWurmple()
{
uint evoVal = PKX.GetWurmpleEvoVal(pkm.EncryptionConstant);
@ -783,7 +794,7 @@ namespace PKHeX.Core
var c3 = u4.RibbonBitsContest3(); var c3n = u4.RibbonNamesContest3();
var c4 = u4.RibbonBitsContest4(); var c4n = u4.RibbonNamesContest4();
var iter3 = gen == 3 ? getMissingContestRibbons(c3, c3n) : GetRibbonMessageNone(c3, c3n);
var iter4 = gen == 4 && IsAllowedInContest4(pkm.Species) ? getMissingContestRibbons(c4, c4n) : GetRibbonMessageNone(c4, c4n);
var iter4 = (gen == 3 || gen == 4) && IsAllowedInContest4(pkm.Species) ? getMissingContestRibbons(c4, c4n) : GetRibbonMessageNone(c4, c4n);
foreach (var z in iter3.Concat(iter4))
yield return z;

View file

@ -165,15 +165,15 @@ namespace PKHeX.Core
var evo1 = raichu1.Chain[0].StageEntryMethods[0].Copy();
Lineage[26].Chain.Add(new EvolutionStage { StageEntryMethods = new List<EvolutionMethod> { evo1 } });
var evo2 = raichu1.Chain[1].StageEntryMethods[0].Copy();
evo2.Form = -1; evo2.Banlist = new[] { GameVersion.SN, GameVersion.MN };
evo2.Form = -1; evo2.Banlist = EvolutionMethod.BanSM;
Lineage[26].Chain.Add(new EvolutionStage { StageEntryMethods = new List<EvolutionMethod> { evo2 } });
var exegg = Lineage[Personal.GetFormeIndex(103, 1)].Chain[0].StageEntryMethods[0].Copy();
exegg.Form = -1; exegg.Banlist = new[] { GameVersion.SN, GameVersion.MN }; exegg.Method = 8; // No night required (doesn't matter)
exegg.Form = -1; exegg.Banlist = EvolutionMethod.BanSM; exegg.Method = 8; // No night required (doesn't matter)
Lineage[103].Chain.Add(new EvolutionStage { StageEntryMethods = new List<EvolutionMethod> { exegg } });
var marowak = Lineage[Personal.GetFormeIndex(105, 1)].Chain[0].StageEntryMethods[0].Copy();
marowak.Form = -1; marowak.Banlist = new[] {GameVersion.SN, GameVersion.MN};
marowak.Form = -1; marowak.Banlist = EvolutionMethod.BanSM;
Lineage[105].Chain.Add(new EvolutionStage { StageEntryMethods = new List<EvolutionMethod> { marowak } });
}
@ -512,8 +512,11 @@ namespace PKHeX.Core
public int Level;
public bool RequiresLevelUp;
public static readonly int[] TradeMethods = {5, 6, 7};
public GameVersion[] Banlist = new GameVersion[0];
internal static readonly int[] TradeMethods = {5, 6, 7};
private static readonly IReadOnlyCollection<GameVersion> NoBanlist = new GameVersion[0];
internal static readonly IReadOnlyCollection<GameVersion> BanSM = new[] {GameVersion.SN, GameVersion.MN};
internal IReadOnlyCollection<GameVersion> Banlist = NoBanlist;
public bool Valid(PKM pkm, int lvl, bool skipChecks)
{

View file

@ -431,8 +431,8 @@ namespace PKHeX.Core
}
public bool IsMegaEvolutionUnlocked
{
get => Data[TrainerCard + 0x14A] == 1;
set => Data[TrainerCard + 0x14A] = (byte)(value ? 1 : 0);
get => (Data[TrainerCard + 0x14A] & 0x01) != 0;
set => Data[TrainerCard + 0x14A] = (byte)((Data[TrainerCard + 0x14A] & 0xFE) | (value ? 1 : 0)); // in battle
}
public int M

View file

@ -1305,8 +1305,8 @@ namespace PKHeX.Core
}
public bool MegaUnlocked
{
get => (Data[0x1278] & 0x01) != 0;
set => Data[0x1278] = (byte)((Data[0x1278] & 0xFE) | (value ? 1 : 0)); // in battle
get => (Data[TrainerCard + 0x78] & 0x01) != 0;
set => Data[TrainerCard + 0x78] = (byte)((Data[TrainerCard + 0x78] & 0xFE) | (value ? 1 : 0)); // in battle
// Data[0x1F22] = (byte)((Data[0x1F22] & 0xFE) | (value ? 1 : 0)); // event
}

View file

@ -423,19 +423,27 @@ namespace PKHeX.WinForms.Controls
PB_MarkVC.Image = ImageUtil.ChangeOpacity(PB_MarkVC.InitialImage, getOpacity(pkm.VC));
PB_MarkHorohoro.Image = ImageUtil.ChangeOpacity(PB_MarkHorohoro.InitialImage, getOpacity(pkm.Horohoro));
var markings = pkm.Markings;
for (int i = 0; i < pba.Length; i++)
if (GetMarkingColor(markings[i], out Color c))
pba[i].Image = ImageUtil.ChangeAllColorTo(pba[i].Image, c);
}
private static bool GetMarkingColor(int markval, out Color c)
{
switch (markval)
{
switch (pkm.Markings[i])
{
case 1:
pba[i].Image = ImageUtil.ChangeAllColorTo(pba[i].Image, Color.FromArgb(000, 191, 255));
break;
case 2:
pba[i].Image = ImageUtil.ChangeAllColorTo(pba[i].Image, Color.FromArgb(255, 117, 179));
break;
}
case 1:
c = Color.FromArgb(000, 191, 255);
return true;
case 2:
c = Color.FromArgb(255, 117, 179);
return true;
default:
c = Color.Black;
return false;
}
}
private void UpdateGender()
{
int cg = PKX.GetGender(Label_Gender.Text);
@ -1281,22 +1289,26 @@ namespace PKHeX.WinForms.Controls
CB_MetLocation.ValueMember = "Value";
CB_MetLocation.DataSource = new BindingSource(met_list, null);
int metLoc = 0; // transporter or pal park for past gen pkm
switch (newTrack)
if (fieldsLoaded)
{
case GameVersion.GO: metLoc = 30012; break;
case GameVersion.RBY: metLoc = 30013; break;
int metLoc = 0; // transporter or pal park for past gen pkm
switch (newTrack)
{
case GameVersion.GO: metLoc = 30012; break;
case GameVersion.RBY: metLoc = 30013; break;
}
if (metLoc != 0)
CB_MetLocation.SelectedValue = metLoc;
else
CB_MetLocation.SelectedIndex = metLoc;
}
if (metLoc != 0)
CB_MetLocation.SelectedValue = metLoc;
else
CB_MetLocation.SelectedIndex = metLoc;
var egg_list = GameInfo.GetLocationList(Version, pkm.Format, egg: true);
CB_EggLocation.DisplayMember = "Text";
CB_EggLocation.ValueMember = "Value";
CB_EggLocation.DataSource = new BindingSource(egg_list, null);
CB_EggLocation.SelectedIndex = CHK_AsEgg.Checked ? 1 : 0; // daycare : none
if (fieldsLoaded)
CB_EggLocation.SelectedIndex = CHK_AsEgg.Checked ? 1 : 0; // daycare : none
origintrack = newTrack;
@ -1305,6 +1317,9 @@ namespace PKHeX.WinForms.Controls
if (Version == GameVersion.CXD && pkm.Format == 3)
width = 2 * width;
CB_MetLocation.DropDownWidth = width;
if (!fieldsLoaded)
ValidateChildren(); // prevent value resetting when finishing load routine
}
// Visibility logic for Gen 4 encounter type; only show for Gen 4 Pokemon.
@ -1726,7 +1741,7 @@ namespace PKHeX.WinForms.Controls
{
if (e.Index < 0) return;
var i = (ComboItem)(sender as ComboBox).Items[e.Index];
var i = (ComboItem)((ComboBox)sender).Items[e.Index];
var moves = Legality.AllSuggestedMovesAndRelearn;
bool vm = moves != null && moves.Contains(i.Value) && !HaX;

View file

@ -79,52 +79,61 @@ namespace PKHeX.WinForms
// QR Utility
private const string QR6PathBad = "null/#"; // prefix to prevent URL from loading
private const string QR6Path = @"http://lunarcookies.github.io/b1s1.html#";
private const string DecodeAPI = "http://api.qrserver.com/v1/read-qr-code/?fileurl=";
private const int QRSize = 365;
private static readonly string EncodeAPI = $"http://chart.apis.google.com/chart?chs={QRSize}x{QRSize}&cht=qr&chl=";
internal static byte[] GetQRData(string address)
{
// Fetch data from QR code...
try { if (address.Length < 4 || address.Substring(0, 3) != "htt") { WinFormsUtil.Alert("Clipboard text is not a valid URL:", address); return null; } }
try { if (address.Length < 4 || !address.StartsWith("http")) { WinFormsUtil.Alert("Clipboard text is not a valid URL:", address); return null; } }
catch { WinFormsUtil.Alert("Clipboard text is not a valid URL:", address); return null; }
string webURL = "http://api.qrserver.com/v1/read-qr-code/?fileurl=" + HttpUtility.UrlEncode(address);
string webURL = DecodeAPI + HttpUtility.UrlEncode(address);
string data;
try
{
string data = NetUtil.GetStringFromURL(webURL);
data = NetUtil.GetStringFromURL(webURL);
if (data.Contains("could not find")) { WinFormsUtil.Alert("Reader could not find QR data in the image."); return null; }
if (data.Contains("filetype not supported")) { WinFormsUtil.Alert("Input URL is not valid. Double check that it is an image (jpg/png).", address); return null; }
// Quickly convert the json response to a data string
const string cap = "\",\"error\":null}]}]";
const string intro = "[{\"type\":\"qrcode\",\"symbol\":[{\"seq\":0,\"data\":\"";
if (!data.StartsWith(intro))
throw new FormatException();
string pkstr = data.Substring(intro.Length);
if (pkstr.Contains("nQR-Code:")) // Remove multiple QR codes in same image
pkstr = pkstr.Substring(0, pkstr.IndexOf("nQR-Code:", StringComparison.Ordinal));
pkstr = pkstr.Substring(0, pkstr.IndexOf(cap, StringComparison.Ordinal)); // Trim outro
try
{
if (!pkstr.StartsWith("http") && !pkstr.StartsWith(QR6PathBad)) // G7
{
string fstr = Regex.Unescape(pkstr);
byte[] raw = Encoding.Unicode.GetBytes(fstr);
// Remove 00 interstitials and retrieve from offset 0x30, take PK7 Stored Size (always)
return raw.ToList().Where((c, i) => i % 2 == 0).Skip(0x30).Take(0xE8).ToArray();
}
// All except G7
pkstr = pkstr.Substring(pkstr.IndexOf("#", StringComparison.Ordinal) + 1); // Trim URL
pkstr = pkstr.Replace("\\", ""); // Rectify response
return Convert.FromBase64String(pkstr);
}
catch { WinFormsUtil.Alert("QR string to Data failed."); return null; }
}
catch { WinFormsUtil.Alert("Unable to connect to the internet to decode QR code."); return null; }
// Quickly convert the json response to a data string
try { return DecodeQRJson(data); }
catch (Exception e) { WinFormsUtil.Alert("QR string to Data failed.", e.Message); return null; }
}
private static byte[] DecodeQRJson(string data)
{
const string cap = "\",\"error\":null}]}]";
const string intro = "[{\"type\":\"qrcode\",\"symbol\":[{\"seq\":0,\"data\":\"";
const string qrcode = "nQR-Code:";
if (!data.StartsWith(intro))
throw new FormatException();
string pkstr = data.Substring(intro.Length);
if (pkstr.Contains(qrcode)) // Remove multiple QR codes in same image
pkstr = pkstr.Substring(0, pkstr.IndexOf(qrcode, StringComparison.Ordinal));
pkstr = pkstr.Substring(0, pkstr.IndexOf(cap, StringComparison.Ordinal)); // Trim outro
if (!pkstr.StartsWith("http") && !pkstr.StartsWith(QR6PathBad)) // G7
{
string fstr = Regex.Unescape(pkstr);
byte[] raw = Encoding.Unicode.GetBytes(fstr);
// Remove 00 interstitials and retrieve from offset 0x30, take PK7 Stored Size (always)
return raw.ToList().Where((c, i) => i % 2 == 0).Skip(0x30).Take(0xE8).ToArray();
}
// All except G7
pkstr = pkstr.Substring(pkstr.IndexOf("#", StringComparison.Ordinal) + 1); // Trim URL
pkstr = pkstr.Replace("\\", ""); // Rectify response
return Convert.FromBase64String(pkstr);
}
internal static Image GetQRImage(byte[] data, string server)
{
string qrdata = Convert.ToBase64String(data);
string message = server + qrdata;
string webURL = "http://chart.apis.google.com/chart?chs=365x365&cht=qr&chl=" + HttpUtility.UrlEncode(message);
string webURL = EncodeAPI + HttpUtility.UrlEncode(message);
try
{
@ -159,12 +168,9 @@ namespace PKHeX.WinForms
public static Image GenerateQRCode7(PK7 pk7, int box = 0, int slot = 0, int num_copies = 1)
{
byte[] data = QR7.GenerateQRData(pk7, box, slot, num_copies);
using (var generator = new QRCodeGenerator())
using (var qr_data = generator.CreateQRCode(data))
using (var qr_code = new QRCode(qr_data))
return qr_code.GetGraphic(4);
return GenerateQRCode(data, ppm: 4);
}
public static Image GenerateQRCode(byte[] data, int ppm = 4)
private static Image GenerateQRCode(byte[] data, int ppm = 4)
{
using (var generator = new QRCodeGenerator())
using (var qr_data = generator.CreateQRCode(data))

View file

@ -16,7 +16,7 @@ namespace PKHeX.WinForms
using (Graphics gr = Graphics.FromImage(img))
{
gr.DrawImage(baseLayer, new Point(0, 0));
Bitmap o = ChangeOpacity(overLayer, trans);
Image o = trans == 1f ? overLayer : ChangeOpacity(overLayer, trans);
gr.DrawImage(o, new Rectangle(x, y, overLayer.Width, overLayer.Height));
}
return img;