2016-08-27 08:52:34 +00:00
|
|
|
|
using System;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
|
2017-01-08 07:54:09 +00:00
|
|
|
|
namespace PKHeX.Core
|
2016-08-27 08:52:34 +00:00
|
|
|
|
{
|
2016-08-31 05:58:39 +00:00
|
|
|
|
public class PK1 : PKM
|
2016-08-27 08:52:34 +00:00
|
|
|
|
{
|
|
|
|
|
// Internal use only
|
2016-08-29 05:21:55 +00:00
|
|
|
|
protected internal byte[] otname;
|
|
|
|
|
protected internal byte[] nick;
|
2017-02-13 06:31:31 +00:00
|
|
|
|
public override PersonalInfo PersonalInfo => PersonalTable.Y[Species];
|
2016-08-27 08:52:34 +00:00
|
|
|
|
|
2016-08-28 10:18:22 +00:00
|
|
|
|
public byte[] OT_Name_Raw => (byte[])otname.Clone();
|
|
|
|
|
public byte[] Nickname_Raw => (byte[])nick.Clone();
|
2016-09-15 05:04:22 +00:00
|
|
|
|
public override bool Valid => Species <= 151 && (Data[0] == 0 || Species != 0);
|
2016-08-28 10:18:22 +00:00
|
|
|
|
|
2016-08-27 08:52:34 +00:00
|
|
|
|
public sealed override int SIZE_PARTY => PKX.SIZE_1PARTY;
|
|
|
|
|
public override int SIZE_STORED => PKX.SIZE_1STORED;
|
|
|
|
|
internal const int STRLEN_J = 6;
|
|
|
|
|
internal const int STRLEN_U = 11;
|
|
|
|
|
private int StringLength => Japanese ? STRLEN_J : STRLEN_U;
|
|
|
|
|
|
2017-04-09 21:06:50 +00:00
|
|
|
|
public override string getString(int Offset, int Count) => PKX.getString1(Data, Offset, Count, Japanese);
|
|
|
|
|
public override byte[] setString(string value, int maxLength) => PKX.setString1(value, maxLength, Japanese);
|
|
|
|
|
|
|
|
|
|
// Trash Bytes
|
2017-05-13 03:32:36 +00:00
|
|
|
|
public override byte[] Nickname_Trash { get => nick; set { if (value?.Length == nick.Length) nick = value; } }
|
|
|
|
|
public override byte[] OT_Trash { get => otname; set { if (value?.Length == otname.Length) otname = value; } }
|
2017-04-09 21:06:50 +00:00
|
|
|
|
|
2016-08-27 08:52:34 +00:00
|
|
|
|
public override int Format => 1;
|
|
|
|
|
|
|
|
|
|
public bool Japanese => otname.Length == STRLEN_J;
|
|
|
|
|
|
2016-12-08 06:57:08 +00:00
|
|
|
|
public override string FileName => $"{Species:000} - {Nickname} - {SaveUtil.ccitt16(Encrypt()):X4}.{Extension}";
|
2016-08-29 05:21:55 +00:00
|
|
|
|
|
2016-08-27 08:52:34 +00:00
|
|
|
|
public PK1(byte[] decryptedData = null, string ident = null, bool jp = false)
|
|
|
|
|
{
|
|
|
|
|
Data = (byte[])(decryptedData ?? new byte[SIZE_PARTY]).Clone();
|
|
|
|
|
Identifier = ident;
|
|
|
|
|
if (Data.Length != SIZE_PARTY)
|
|
|
|
|
Array.Resize(ref Data, SIZE_PARTY);
|
2016-09-04 06:54:11 +00:00
|
|
|
|
int strLen = jp ? STRLEN_J : STRLEN_U;
|
2016-08-27 08:52:34 +00:00
|
|
|
|
otname = Enumerable.Repeat((byte) 0x50, strLen).ToArray();
|
|
|
|
|
nick = Enumerable.Repeat((byte) 0x50, strLen).ToArray();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override PKM Clone()
|
|
|
|
|
{
|
2016-08-29 05:21:55 +00:00
|
|
|
|
PK1 new_pk1 = new PK1(Data, Identifier, Japanese);
|
2016-08-27 08:52:34 +00:00
|
|
|
|
Array.Copy(otname, 0, new_pk1.otname, 0, otname.Length);
|
|
|
|
|
Array.Copy(nick, 0, new_pk1.nick, 0, nick.Length);
|
|
|
|
|
return new_pk1;
|
|
|
|
|
}
|
|
|
|
|
public override string Nickname
|
|
|
|
|
{
|
2017-05-13 03:32:36 +00:00
|
|
|
|
get => PKX.getString1(nick, 0, nick.Length, Japanese);
|
2016-08-27 08:52:34 +00:00
|
|
|
|
set
|
|
|
|
|
{
|
2017-04-09 21:06:50 +00:00
|
|
|
|
byte[] strdata = setString(value, StringLength);
|
2016-08-29 05:21:55 +00:00
|
|
|
|
if (nick.Any(b => b == 0) && nick[StringLength - 1] == 0x50 && Array.FindIndex(nick, b => b == 0) == strdata.Length - 1) // Handle JP Mew event with grace
|
|
|
|
|
{
|
|
|
|
|
int firstInd = Array.FindIndex(nick, b => b == 0);
|
|
|
|
|
for (int i = firstInd; i < StringLength - 1; i++)
|
|
|
|
|
if (nick[i] != 0)
|
|
|
|
|
break;
|
|
|
|
|
strdata = strdata.Take(strdata.Length - 1).ToArray();
|
|
|
|
|
}
|
2016-08-27 08:52:34 +00:00
|
|
|
|
strdata.CopyTo(nick, 0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override string OT_Name
|
|
|
|
|
{
|
2017-05-13 03:32:36 +00:00
|
|
|
|
get => PKX.getString1(otname, 0, otname.Length, Japanese);
|
2016-08-27 08:52:34 +00:00
|
|
|
|
set
|
|
|
|
|
{
|
2017-04-09 21:06:50 +00:00
|
|
|
|
byte[] strdata = setString(value, StringLength);
|
2016-08-29 05:21:55 +00:00
|
|
|
|
if (otname.Any(b => b == 0) && otname[StringLength - 1] == 0x50 && Array.FindIndex(otname, b => b == 0) == strdata.Length - 1) // Handle JP Mew event with grace
|
|
|
|
|
{
|
|
|
|
|
int firstInd = Array.FindIndex(otname, b => b == 0);
|
|
|
|
|
for (int i = firstInd; i < StringLength - 1; i++)
|
|
|
|
|
if (otname[i] != 0)
|
|
|
|
|
break;
|
|
|
|
|
strdata = strdata.Take(strdata.Length - 1).ToArray();
|
|
|
|
|
}
|
2016-08-27 08:52:34 +00:00
|
|
|
|
strdata.CopyTo(otname, 0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-05-13 03:32:36 +00:00
|
|
|
|
public override byte[] Encrypt() => new PokemonList1(this).GetBytes();
|
2016-08-28 10:18:22 +00:00
|
|
|
|
public override byte[] EncryptedPartyData => Encrypt().ToArray();
|
|
|
|
|
public override byte[] EncryptedBoxData => Encrypt().ToArray();
|
2016-08-29 05:21:55 +00:00
|
|
|
|
public override byte[] DecryptedBoxData => Encrypt().ToArray();
|
|
|
|
|
public override byte[] DecryptedPartyData => Encrypt().ToArray();
|
2016-08-28 10:18:22 +00:00
|
|
|
|
|
2016-08-29 20:27:17 +00:00
|
|
|
|
public override bool IsNicknamed
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
2017-03-05 01:19:57 +00:00
|
|
|
|
string spName = PKX.getSpeciesNameGeneration(Species, Japanese ? 1 : 2, Format);
|
2017-04-09 21:06:50 +00:00
|
|
|
|
return !nick.SequenceEqual(setString(spName, StringLength)
|
2016-09-11 23:22:05 +00:00
|
|
|
|
.Concat(Enumerable.Repeat((byte) 0x50, StringLength - spName.Length - 1))
|
|
|
|
|
.Select(b => (byte)(b == 0xF2 ? 0xE8 : b)));
|
2016-08-29 20:27:17 +00:00
|
|
|
|
}
|
2017-03-05 01:19:57 +00:00
|
|
|
|
set
|
|
|
|
|
{
|
|
|
|
|
if (!value)
|
|
|
|
|
setNotNicknamed();
|
|
|
|
|
}
|
2016-08-29 20:27:17 +00:00
|
|
|
|
}
|
|
|
|
|
|
2017-01-25 11:29:38 +00:00
|
|
|
|
public bool IsNicknamedBank
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
2017-03-05 01:19:57 +00:00
|
|
|
|
var spName = PKX.getSpeciesNameGeneration(Species, Japanese ? 1 : 2, Format);
|
2017-01-25 11:29:38 +00:00
|
|
|
|
return Nickname != spName;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-29 20:27:17 +00:00
|
|
|
|
public void setNotNicknamed()
|
|
|
|
|
{
|
2017-03-05 01:19:57 +00:00
|
|
|
|
string spName = PKX.getSpeciesNameGeneration(Species, Japanese ? 1 : 2, Format);
|
2017-04-09 21:06:50 +00:00
|
|
|
|
nick = setString(spName, StringLength)
|
2016-09-11 23:22:05 +00:00
|
|
|
|
.Concat(Enumerable.Repeat((byte)0x50, StringLength - spName.Length - 1))
|
|
|
|
|
.Select(b => (byte)(b == 0xF2 ? 0xE8 : b)) // Decimal point<->period fix
|
|
|
|
|
.ToArray();
|
2016-08-29 20:27:17 +00:00
|
|
|
|
}
|
|
|
|
|
|
2016-08-27 08:52:34 +00:00
|
|
|
|
|
|
|
|
|
#region Stored Attributes
|
2016-08-27 09:56:15 +00:00
|
|
|
|
public override int Species
|
|
|
|
|
{
|
2017-05-13 03:32:36 +00:00
|
|
|
|
get => PKX.getG1Species(Data[0]);
|
2016-08-27 09:56:15 +00:00
|
|
|
|
set
|
|
|
|
|
{
|
|
|
|
|
Data[0] = (byte)PKX.setG1Species(value);
|
2016-10-29 16:39:11 +00:00
|
|
|
|
|
|
|
|
|
// Before updating catch rate, check if non-standard
|
Generation 1 and 2 legal Improvements (#1099)
* Refactor parseMovesForEncounter to gather valid moves for species encounter, some Pokemon can have valid encounters with different source species from the encounter, the valid moves change if the encounter species change because some preevolutions moves are illegal if pokemon caught already evolved.
Example, generation 1 Pikachu that can have a RBY Pikachu encounter and GSC Pichu encounter, the valid moves for the first encounters should not have any Pichu exclusive evolution moves
Also assign the encounter match from gb when parsing moves like the variable Encounter Match, to store the encounter that is valid for the pokemon moves instead the first encounter.
Store the species encounter, this will be needed to check if the evolution is valid for species that evolve leveling with a given learned move
* Add Tradeback Status to the pokemon, this variable for generations 1 and 2 use data like the catch rate to determine if trade between generations 1 and 2 was possible.
If analysis is for VC games tradeback have value NotTradeback for every gen 1 pokemon, but for cart saves some pokemon can be determine that have not been tradeback, if catch rate match species catch rate but do not match a valid generation 2 held item that means the pokemon habe been never traded to generation 2 games, that allow to discart encounters and moves from generation 2.
Also if is not tradeback catch rate is used to filter encounters, catch rate determine in what species was captured the pokemon discarting some preevolutions moves
Also add option for generation 1 cart save analysis to check legal status not allowing generation 2 games, like VC games but with Stadium allowed, like the generation 1 non tradeback rules from Smogon
Also change evolution chains to included generation 2 preevolutions for gen 1 pokemon if tradeback was possible, it is needed to avoid parsemoves to check illegal pokemon like Hitmonchan with Tyrogue level up moves
* Check legal values of generation 1 type and catch rate
Replace pokemon catch rate after changind pokemon species always if pokemon was not tradeback from generation 2, the catch rate will keep unchanged only if it can be a held item and do not match species catch rate (default item)
Also if catch rate is changed use base species catch rate to avoid legal errors if the catch rate of the evolution species if is not possible with the current moves
* Filter ingame trades and static encounters with catch rate for generation 1 non tradeback
* Fix min moves for generation 1 metapod encounter
* Clean up
* Fix encounter level for generation 1, valid moves are those with one level after the encounter level, pokemon can not learn a new move until level up
Clean up type validation
Fix generation 3 fatefull encounter eggs, the pokemon lost the fatefull mark when it hatch
* Clean-up
* Use new variable EncounterSpecies when it is needed to detect the species of the encounter, the old code wont work if the encounter is a wild slots array
* Fix generation 1 evolution chains and catch rate as default held item
* Fix Generation 1 Yellow Pikachu and Kadabra catch rates
2017-04-27 04:27:59 +00:00
|
|
|
|
if (!CatchRateIsItem)
|
2017-05-28 20:19:48 +00:00
|
|
|
|
{
|
|
|
|
|
int baseSpecies = Legal.getBaseSpecies(this);
|
|
|
|
|
int Rate = Catch_Rate;
|
|
|
|
|
if (Enumerable.Range(baseSpecies, value).All(z => Rate != PersonalTable.RB[z].CatchRate))
|
|
|
|
|
Catch_Rate = PersonalTable.RB[value].CatchRate;
|
|
|
|
|
}
|
2016-10-29 16:39:11 +00:00
|
|
|
|
Type_A = PersonalInfo.Types[0];
|
|
|
|
|
Type_B = PersonalInfo.Types[1];
|
2016-08-27 09:56:15 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2016-08-27 08:52:34 +00:00
|
|
|
|
|
2017-05-13 03:32:36 +00:00
|
|
|
|
public override int Stat_HPCurrent { get => BigEndian.ToUInt16(Data, 0x1); set => BigEndian.GetBytes((ushort)value).CopyTo(Data, 0x1); }
|
|
|
|
|
public int Status_Condition { get => Data[4]; set => Data[4] = (byte)value; }
|
|
|
|
|
public int Type_A { get => Data[5]; set => Data[5] = (byte)value; }
|
|
|
|
|
public int Type_B { get => Data[6]; set => Data[6] = (byte)value; }
|
|
|
|
|
public int Catch_Rate { get => Data[7]; set => Data[7] = (byte)value; }
|
|
|
|
|
public override int Move1 { get => Data[8]; set => Data[8] = (byte)value; }
|
|
|
|
|
public override int Move2 { get => Data[9]; set => Data[9] = (byte)value; }
|
|
|
|
|
public override int Move3 { get => Data[10]; set => Data[10] = (byte)value; }
|
|
|
|
|
public override int Move4 { get => Data[11]; set => Data[11] = (byte)value; }
|
|
|
|
|
public override int TID { get => BigEndian.ToUInt16(Data, 0xC); set => BigEndian.GetBytes((ushort)value).CopyTo(Data, 0xC); }
|
2016-08-27 08:52:34 +00:00
|
|
|
|
public override uint EXP
|
|
|
|
|
{
|
2017-05-13 03:32:36 +00:00
|
|
|
|
get => (BigEndian.ToUInt32(Data, 0xE) >> 8) & 0x00FFFFFF;
|
|
|
|
|
set => Array.Copy(BigEndian.GetBytes((value << 8) & 0xFFFFFF00), 0, Data, 0xE, 3);
|
2016-08-27 08:52:34 +00:00
|
|
|
|
}
|
2017-05-13 03:32:36 +00:00
|
|
|
|
public override int EV_HP { get => BigEndian.ToUInt16(Data, 0x11); set => BigEndian.GetBytes((ushort)value).CopyTo(Data, 0x11); }
|
|
|
|
|
public override int EV_ATK { get => BigEndian.ToUInt16(Data, 0x13); set => BigEndian.GetBytes((ushort)value).CopyTo(Data, 0x13); }
|
|
|
|
|
public override int EV_DEF { get => BigEndian.ToUInt16(Data, 0x15); set => BigEndian.GetBytes((ushort)value).CopyTo(Data, 0x15); }
|
|
|
|
|
public override int EV_SPE { get => BigEndian.ToUInt16(Data, 0x17); set => BigEndian.GetBytes((ushort)value).CopyTo(Data, 0x17); }
|
|
|
|
|
public int EV_SPC { get => BigEndian.ToUInt16(Data, 0x19); set => BigEndian.GetBytes((ushort)value).CopyTo(Data, 0x19); }
|
|
|
|
|
public override int EV_SPA { get => EV_SPC; set => EV_SPC = value; }
|
|
|
|
|
public override int EV_SPD { get => EV_SPC; set { } }
|
|
|
|
|
public ushort DV16 { get => BigEndian.ToUInt16(Data, 0x1B); set => BigEndian.GetBytes(value).CopyTo(Data, 0x1B); }
|
|
|
|
|
public override int IV_HP { get => ((IV_ATK & 1) << 3) | ((IV_DEF & 1) << 2) | ((IV_SPE & 1) << 1) | ((IV_SPC & 1) << 0); set { } }
|
|
|
|
|
public override int IV_ATK { get => (DV16 >> 12) & 0xF; set => DV16 = (ushort)((DV16 & ~(0xF << 12)) | (ushort)((value > 0xF ? 0xF : value) << 12)); }
|
|
|
|
|
public override int IV_DEF { get => (DV16 >> 8) & 0xF; set => DV16 = (ushort)((DV16 & ~(0xF << 8)) | (ushort)((value > 0xF ? 0xF : value) << 8)); }
|
|
|
|
|
public override int IV_SPE { get => (DV16 >> 4) & 0xF; set => DV16 = (ushort)((DV16 & ~(0xF << 4)) | (ushort)((value > 0xF ? 0xF : value) << 4)); }
|
|
|
|
|
public int IV_SPC { get => (DV16 >> 0) & 0xF; set => DV16 = (ushort)((DV16 & ~(0xF << 0)) | (ushort)((value > 0xF ? 0xF : value) << 0)); }
|
|
|
|
|
public override int IV_SPA { get => IV_SPC; set => IV_SPC = value; }
|
|
|
|
|
public override int IV_SPD { get => IV_SPC; set { } }
|
2017-05-19 16:22:12 +00:00
|
|
|
|
public override int Move1_PP { get => Data[0x1D] & 0x3F; set => Data[0x1D] = (byte)((Data[0x1D] & 0xC0) | Math.Min(63, value)); }
|
|
|
|
|
public override int Move2_PP { get => Data[0x1E] & 0x3F; set => Data[0x1E] = (byte)((Data[0x1E] & 0xC0) | Math.Min(63, value)); }
|
|
|
|
|
public override int Move3_PP { get => Data[0x1F] & 0x3F; set => Data[0x1F] = (byte)((Data[0x1F] & 0xC0) | Math.Min(63, value)); }
|
|
|
|
|
public override int Move4_PP { get => Data[0x20] & 0x3F; set => Data[0x20] = (byte)((Data[0x20] & 0xC0) | Math.Min(63, value)); }
|
2017-05-13 03:32:36 +00:00
|
|
|
|
public override int Move1_PPUps { get => (Data[0x1D] & 0xC0) >> 6; set => Data[0x1D] = (byte)((Data[0x1D] & 0x3F) | ((value & 0x3) << 6)); }
|
|
|
|
|
public override int Move2_PPUps { get => (Data[0x1E] & 0xC0) >> 6; set => Data[0x1E] = (byte)((Data[0x1E] & 0x3F) | ((value & 0x3) << 6)); }
|
|
|
|
|
public override int Move3_PPUps { get => (Data[0x1F] & 0xC0) >> 6; set => Data[0x1F] = (byte)((Data[0x1F] & 0x3F) | ((value & 0x3) << 6)); }
|
|
|
|
|
public override int Move4_PPUps { get => (Data[0x20] & 0xC0) >> 6; set => Data[0x20] = (byte)((Data[0x20] & 0x3F) | ((value & 0x3) << 6)); }
|
2016-08-27 08:52:34 +00:00
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region Party Attributes
|
|
|
|
|
public override int Stat_Level
|
|
|
|
|
{
|
2017-05-13 03:32:36 +00:00
|
|
|
|
get => Data[0x21];
|
2016-08-27 08:52:34 +00:00
|
|
|
|
set { Data[0x21] = (byte)value; Data[0x3] = (byte)value; }
|
|
|
|
|
}
|
2017-05-13 03:32:36 +00:00
|
|
|
|
public override int Stat_HPMax { get => BigEndian.ToUInt16(Data, 0x22); set => BigEndian.GetBytes((ushort)value).CopyTo(Data, 0x22); }
|
|
|
|
|
public override int Stat_ATK { get => BigEndian.ToUInt16(Data, 0x24); set => BigEndian.GetBytes((ushort)value).CopyTo(Data, 0x24); }
|
|
|
|
|
public override int Stat_DEF { get => BigEndian.ToUInt16(Data, 0x26); set => BigEndian.GetBytes((ushort)value).CopyTo(Data, 0x26); }
|
|
|
|
|
public override int Stat_SPE { get => BigEndian.ToUInt16(Data, 0x28); set => BigEndian.GetBytes((ushort)value).CopyTo(Data, 0x28); }
|
|
|
|
|
public int Stat_SPC { get => BigEndian.ToUInt16(Data, 0x2A); set => BigEndian.GetBytes((ushort)value).CopyTo(Data, 0x2A); }
|
2016-08-27 08:52:34 +00:00
|
|
|
|
// Leave SPA and SPD as alias for SPC
|
2017-05-13 03:32:36 +00:00
|
|
|
|
public override int Stat_SPA { get => Stat_SPC; set => Stat_SPC = value; }
|
|
|
|
|
public override int Stat_SPD { get => Stat_SPC; set { } }
|
2016-08-27 08:52:34 +00:00
|
|
|
|
#endregion
|
|
|
|
|
|
2017-05-19 16:22:12 +00:00
|
|
|
|
public override int getMovePP(int move, int ppup) => Math.Min(61, base.getMovePP(move, ppup));
|
2016-08-28 10:18:22 +00:00
|
|
|
|
public override ushort[] getStats(PersonalInfo p)
|
|
|
|
|
{
|
|
|
|
|
ushort[] Stats = new ushort[6];
|
|
|
|
|
for (int i = 0; i < Stats.Length; i++)
|
|
|
|
|
{
|
|
|
|
|
ushort L = (ushort)Stat_Level;
|
|
|
|
|
ushort B = (ushort)p.Stats[i];
|
|
|
|
|
ushort I = (ushort)IVs[i];
|
|
|
|
|
ushort E = // Fixed formula via http://www.smogon.com/ingame/guides/rby_gsc_stats
|
|
|
|
|
(ushort)Math.Floor(Math.Min(255, Math.Floor(Math.Sqrt(Math.Max(0, EVs[i] - 1)) + 1)) / 4.0);
|
|
|
|
|
Stats[i] = (ushort)Math.Floor((2 * (B + I) + E) * L / 100.0 + 5);
|
|
|
|
|
}
|
|
|
|
|
Stats[0] += (ushort)(5 + Stat_Level); // HP
|
|
|
|
|
|
|
|
|
|
return Stats;
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-27 08:52:34 +00:00
|
|
|
|
#region Future, Unused Attributes
|
|
|
|
|
public override bool getGenderIsValid()
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2017-05-13 03:32:36 +00:00
|
|
|
|
public override uint EncryptionConstant { get => 0; set { } }
|
|
|
|
|
public override uint PID { get => 0; set { } }
|
|
|
|
|
public override int Met_Level { get => 0; set { } }
|
|
|
|
|
public override int Nature { get => 0; set { } }
|
|
|
|
|
public override int AltForm { get => 0; set { } }
|
|
|
|
|
public override bool IsEgg { get => false; set { } }
|
|
|
|
|
public override int Gender { get => 0; set { } }
|
|
|
|
|
public override int HeldItem { get => 0; set { } }
|
|
|
|
|
public override bool CanHoldItem(ushort[] ValidArray) => false;
|
2017-01-25 05:28:29 +00:00
|
|
|
|
public override bool IsShiny => IV_ATK == 10 && IV_SPE == 10 && IV_SPC == 10 && (IV_DEF & 2) == 2;
|
2017-05-13 03:32:36 +00:00
|
|
|
|
public override ushort Sanity { get => 0; set { } }
|
2016-08-28 10:18:22 +00:00
|
|
|
|
public override bool ChecksumValid => true;
|
2017-05-13 03:32:36 +00:00
|
|
|
|
public override ushort Checksum { get => 0; set { } }
|
|
|
|
|
public override int Language { get => 0; set { } }
|
|
|
|
|
public override bool FatefulEncounter { get => false; set { } }
|
2016-08-27 09:48:04 +00:00
|
|
|
|
public override int TSV => 0x0000;
|
|
|
|
|
public override int PSV => 0xFFFF;
|
2016-08-27 08:52:34 +00:00
|
|
|
|
public override int Characteristic => -1;
|
2017-05-13 03:32:36 +00:00
|
|
|
|
public override int MarkValue { get => 0; protected set { } }
|
|
|
|
|
public override int CurrentFriendship { get => 0; set { } }
|
|
|
|
|
public override int Ability { get => 0; set { } }
|
|
|
|
|
public override int CurrentHandler { get => 0; set { } }
|
|
|
|
|
public override int Met_Location { get => 0; set { } }
|
|
|
|
|
public override int Egg_Location { get => 0; set { } }
|
|
|
|
|
public override int OT_Friendship { get => 0; set { } }
|
|
|
|
|
public override int OT_Gender { get => 0; set { } }
|
|
|
|
|
public override int Ball { get => 0; set { } }
|
|
|
|
|
public override int Version { get => (int)GameVersion.RBY; set { } }
|
|
|
|
|
public override int SID { get => 0; set { } }
|
|
|
|
|
public override int PKRS_Strain { get => 0; set { } }
|
|
|
|
|
public override int PKRS_Days { get => 0; set { } }
|
|
|
|
|
public override int CNT_Cool { get => 0; set { } }
|
|
|
|
|
public override int CNT_Beauty { get => 0; set { } }
|
|
|
|
|
public override int CNT_Cute { get => 0; set { } }
|
|
|
|
|
public override int CNT_Smart { get => 0; set { } }
|
|
|
|
|
public override int CNT_Tough { get => 0; set { } }
|
|
|
|
|
public override int CNT_Sheen { get => 0; set { } }
|
2016-08-27 08:52:34 +00:00
|
|
|
|
#endregion
|
Generation 1 and 2 legal Improvements (#1099)
* Refactor parseMovesForEncounter to gather valid moves for species encounter, some Pokemon can have valid encounters with different source species from the encounter, the valid moves change if the encounter species change because some preevolutions moves are illegal if pokemon caught already evolved.
Example, generation 1 Pikachu that can have a RBY Pikachu encounter and GSC Pichu encounter, the valid moves for the first encounters should not have any Pichu exclusive evolution moves
Also assign the encounter match from gb when parsing moves like the variable Encounter Match, to store the encounter that is valid for the pokemon moves instead the first encounter.
Store the species encounter, this will be needed to check if the evolution is valid for species that evolve leveling with a given learned move
* Add Tradeback Status to the pokemon, this variable for generations 1 and 2 use data like the catch rate to determine if trade between generations 1 and 2 was possible.
If analysis is for VC games tradeback have value NotTradeback for every gen 1 pokemon, but for cart saves some pokemon can be determine that have not been tradeback, if catch rate match species catch rate but do not match a valid generation 2 held item that means the pokemon habe been never traded to generation 2 games, that allow to discart encounters and moves from generation 2.
Also if is not tradeback catch rate is used to filter encounters, catch rate determine in what species was captured the pokemon discarting some preevolutions moves
Also add option for generation 1 cart save analysis to check legal status not allowing generation 2 games, like VC games but with Stadium allowed, like the generation 1 non tradeback rules from Smogon
Also change evolution chains to included generation 2 preevolutions for gen 1 pokemon if tradeback was possible, it is needed to avoid parsemoves to check illegal pokemon like Hitmonchan with Tyrogue level up moves
* Check legal values of generation 1 type and catch rate
Replace pokemon catch rate after changind pokemon species always if pokemon was not tradeback from generation 2, the catch rate will keep unchanged only if it can be a held item and do not match species catch rate (default item)
Also if catch rate is changed use base species catch rate to avoid legal errors if the catch rate of the evolution species if is not possible with the current moves
* Filter ingame trades and static encounters with catch rate for generation 1 non tradeback
* Fix min moves for generation 1 metapod encounter
* Clean up
* Fix encounter level for generation 1, valid moves are those with one level after the encounter level, pokemon can not learn a new move until level up
Clean up type validation
Fix generation 3 fatefull encounter eggs, the pokemon lost the fatefull mark when it hatch
* Clean-up
* Use new variable EncounterSpecies when it is needed to detect the species of the encounter, the old code wont work if the encounter is a wild slots array
* Fix generation 1 evolution chains and catch rate as default held item
* Fix Generation 1 Yellow Pikachu and Kadabra catch rates
2017-04-27 04:27:59 +00:00
|
|
|
|
public bool CatchRateIsItem = false;
|
2016-09-04 22:03:40 +00:00
|
|
|
|
|
2017-05-23 04:55:05 +00:00
|
|
|
|
// Maximums
|
|
|
|
|
public override int MaxMoveID => Legal.MaxMoveID_1;
|
|
|
|
|
public override int MaxSpeciesID => Legal.MaxSpeciesID_1;
|
|
|
|
|
public override int MaxAbilityID => Legal.MaxAbilityID_1;
|
|
|
|
|
public override int MaxItemID => Legal.MaxItemID_1;
|
|
|
|
|
public override int MaxBallID => -1;
|
|
|
|
|
public override int MaxGameID => -1;
|
|
|
|
|
public override int MaxIV => 15;
|
|
|
|
|
public override int MaxEV => ushort.MaxValue;
|
|
|
|
|
public override int OTLength => Japanese ? 5 : 7;
|
|
|
|
|
public override int NickLength => Japanese ? 5 : 10;
|
|
|
|
|
|
2016-09-04 22:03:40 +00:00
|
|
|
|
public PK2 convertToPK2()
|
|
|
|
|
{
|
2016-10-10 00:41:44 +00:00
|
|
|
|
PK2 pk2 = new PK2(null, Identifier, Japanese) {Species = Species};
|
2016-09-04 22:03:40 +00:00
|
|
|
|
Array.Copy(Data, 0x7, pk2.Data, 0x1, 0x1A);
|
|
|
|
|
// https://github.com/pret/pokecrystal/blob/master/engine/link.asm#L1132
|
|
|
|
|
if (!Legal.HeldItems_GSC.Contains((ushort)pk2.HeldItem))
|
|
|
|
|
switch (pk2.HeldItem)
|
|
|
|
|
{
|
|
|
|
|
case 0x19:
|
|
|
|
|
pk2.HeldItem = 0x92; // Leftovers
|
|
|
|
|
break;
|
|
|
|
|
case 0x2D:
|
|
|
|
|
pk2.HeldItem = 0x53; // Bitter Berry
|
|
|
|
|
break;
|
|
|
|
|
case 0x32:
|
|
|
|
|
pk2.HeldItem = 0xAE; // Leftovers
|
|
|
|
|
break;
|
|
|
|
|
case 0x5A:
|
|
|
|
|
case 0x64:
|
|
|
|
|
case 0x78:
|
|
|
|
|
case 0x87:
|
|
|
|
|
case 0xBE:
|
|
|
|
|
case 0xC3:
|
|
|
|
|
case 0xDC:
|
|
|
|
|
case 0xFA:
|
|
|
|
|
case 0xFF:
|
|
|
|
|
pk2.HeldItem = 0xAD; // Berry
|
|
|
|
|
break;
|
|
|
|
|
}
|
2016-10-29 16:39:11 +00:00
|
|
|
|
pk2.CurrentFriendship = pk2.PersonalInfo.BaseFriendship;
|
2016-09-04 22:03:40 +00:00
|
|
|
|
// Pokerus = 0
|
|
|
|
|
// Caught Data = 0
|
2016-09-05 22:50:09 +00:00
|
|
|
|
pk2.Stat_Level = PKX.getLevel(Species, EXP);
|
2016-09-04 22:03:40 +00:00
|
|
|
|
Array.Copy(otname, 0, pk2.otname, 0, otname.Length);
|
|
|
|
|
Array.Copy(nick, 0, pk2.nick, 0, nick.Length);
|
|
|
|
|
|
|
|
|
|
return pk2;
|
|
|
|
|
}
|
2017-01-25 11:29:38 +00:00
|
|
|
|
|
|
|
|
|
public PK7 convertToPK7()
|
|
|
|
|
{
|
|
|
|
|
var pk7 = new PK7
|
|
|
|
|
{
|
|
|
|
|
EncryptionConstant = Util.rnd32(),
|
|
|
|
|
Species = Species,
|
|
|
|
|
TID = TID,
|
|
|
|
|
CurrentLevel = CurrentLevel,
|
2017-01-26 06:51:52 +00:00
|
|
|
|
EXP = EXP,
|
2017-01-25 11:29:38 +00:00
|
|
|
|
Met_Level = CurrentLevel,
|
|
|
|
|
Nature = (int) (EXP%25),
|
|
|
|
|
PID = Util.rnd32(),
|
|
|
|
|
Ball = 4,
|
|
|
|
|
MetDate = DateTime.Now,
|
|
|
|
|
Version = (int)GameVersion.RD, // Default to red, for now?
|
|
|
|
|
Move1 = Move1,
|
|
|
|
|
Move2 = Move2,
|
|
|
|
|
Move3 = Move3,
|
|
|
|
|
Move4 = Move4,
|
|
|
|
|
Move1_PPUps = Move1_PPUps,
|
|
|
|
|
Move2_PPUps = Move2_PPUps,
|
|
|
|
|
Move3_PPUps = Move3_PPUps,
|
|
|
|
|
Move4_PPUps = Move4_PPUps,
|
|
|
|
|
Move1_PP = Move1_PP,
|
|
|
|
|
Move2_PP = Move2_PP,
|
|
|
|
|
Move3_PP = Move3_PP,
|
|
|
|
|
Move4_PP = Move4_PP,
|
|
|
|
|
Met_Location = 30013, // "Kanto region", hardcoded.
|
|
|
|
|
Gender = PersonalTable.SM[Species].RandomGender,
|
|
|
|
|
OT_Name = PKX.getG1ConvertedString(otname, Japanese),
|
2017-01-26 06:51:52 +00:00
|
|
|
|
IsNicknamed = false,
|
|
|
|
|
|
|
|
|
|
Country = PKMConverter.Country,
|
|
|
|
|
Region = PKMConverter.Region,
|
|
|
|
|
ConsoleRegion = PKMConverter.ConsoleRegion,
|
|
|
|
|
CurrentHandler = 1,
|
|
|
|
|
HT_Name = PKMConverter.OT_Name,
|
|
|
|
|
HT_Gender = PKMConverter.OT_Gender,
|
2017-01-26 07:01:20 +00:00
|
|
|
|
Language = PKMConverter.Language,
|
2017-01-28 17:48:00 +00:00
|
|
|
|
Geo1_Country = PKMConverter.Country,
|
|
|
|
|
Geo1_Region = PKMConverter.Region
|
2017-01-26 06:51:52 +00:00
|
|
|
|
};
|
2017-02-05 02:28:34 +00:00
|
|
|
|
pk7.Nickname = PKX.getSpeciesNameGeneration(pk7.Species, pk7.Language, pk7.Format);
|
2017-02-13 23:44:24 +00:00
|
|
|
|
if (otname[0] == 0x5D) // Ingame Trade
|
|
|
|
|
{
|
|
|
|
|
var s = PKX.getG1Char(0x5D, Japanese);
|
|
|
|
|
pk7.OT_Name = s.Substring(0, 1) + s.Substring(1).ToLower();
|
|
|
|
|
}
|
2017-01-26 06:51:52 +00:00
|
|
|
|
pk7.OT_Friendship = pk7.HT_Friendship = PersonalTable.SM[Species].BaseFriendship;
|
|
|
|
|
|
2017-01-25 11:29:38 +00:00
|
|
|
|
// IVs
|
|
|
|
|
var new_ivs = new int[6];
|
2017-01-26 06:51:52 +00:00
|
|
|
|
int flawless = Species == 151 ? 5 : 3;
|
2017-01-25 11:29:38 +00:00
|
|
|
|
for (var i = 0; i < new_ivs.Length; i++) new_ivs[i] = (int)(Util.rnd32() & 31);
|
2017-01-26 06:51:52 +00:00
|
|
|
|
for (var i = 0; i < flawless; i++) new_ivs[i] = 31;
|
2017-01-25 11:29:38 +00:00
|
|
|
|
Util.Shuffle(new_ivs);
|
|
|
|
|
pk7.IVs = new_ivs;
|
|
|
|
|
|
|
|
|
|
// Really? :(
|
|
|
|
|
if (IsShiny)
|
|
|
|
|
pk7.setShinyPID();
|
|
|
|
|
|
2017-01-26 06:51:52 +00:00
|
|
|
|
int abil = 2; // Hidden
|
2017-01-27 05:35:26 +00:00
|
|
|
|
if (Legal.TransferSpeciesDefaultAbility_1.Contains(Species))
|
2017-01-26 06:51:52 +00:00
|
|
|
|
abil = 0; // Reset
|
|
|
|
|
pk7.RefreshAbility(abil); // 0/1/2 (not 1/2/4)
|
2017-01-25 11:29:38 +00:00
|
|
|
|
|
2017-01-26 06:51:52 +00:00
|
|
|
|
if (Species == 151) // Mew gets special treatment.
|
|
|
|
|
pk7.FatefulEncounter = true;
|
|
|
|
|
else if (IsNicknamedBank)
|
2017-01-25 11:29:38 +00:00
|
|
|
|
{
|
|
|
|
|
pk7.IsNicknamed = true;
|
|
|
|
|
pk7.Nickname = PKX.getG1ConvertedString(nick, Japanese);
|
|
|
|
|
}
|
2017-01-26 06:51:52 +00:00
|
|
|
|
|
|
|
|
|
pk7.TradeMemory(Bank:true); // oh no, memories on gen7 pkm
|
2017-02-13 06:40:47 +00:00
|
|
|
|
|
|
|
|
|
if (pk7.Species == 150) // Pay Day Mewtwo
|
|
|
|
|
{
|
|
|
|
|
var moves = pk7.Moves;
|
|
|
|
|
var index = Array.IndexOf(moves, 6);
|
|
|
|
|
if (index != -1)
|
|
|
|
|
{
|
|
|
|
|
moves[index] = 0;
|
|
|
|
|
pk7.Moves = moves;
|
|
|
|
|
pk7.FixMoves();
|
|
|
|
|
}
|
|
|
|
|
}
|
2017-01-26 06:51:52 +00:00
|
|
|
|
|
2017-01-25 11:29:38 +00:00
|
|
|
|
pk7.RefreshChecksum();
|
|
|
|
|
return pk7;
|
|
|
|
|
}
|
2016-08-27 08:52:34 +00:00
|
|
|
|
}
|
|
|
|
|
|
2016-09-04 06:54:11 +00:00
|
|
|
|
public class PokemonList1
|
2016-08-27 08:52:34 +00:00
|
|
|
|
{
|
2016-09-04 06:54:11 +00:00
|
|
|
|
private const int CAPACITY_DAYCARE = 1;
|
|
|
|
|
private const int CAPACITY_PARTY = 6;
|
|
|
|
|
private const int CAPACITY_STORED = 20;
|
|
|
|
|
private const int CAPACITY_STORED_JP = 30;
|
2016-08-27 08:52:34 +00:00
|
|
|
|
|
2016-09-04 06:54:11 +00:00
|
|
|
|
private readonly bool Japanese;
|
2016-08-27 08:52:34 +00:00
|
|
|
|
|
|
|
|
|
private int StringLength => Japanese ? PK1.STRLEN_J : PK1.STRLEN_U;
|
|
|
|
|
|
|
|
|
|
public enum CapacityType
|
|
|
|
|
{
|
|
|
|
|
Daycare = CAPACITY_DAYCARE,
|
|
|
|
|
Party = CAPACITY_PARTY,
|
|
|
|
|
Stored = CAPACITY_STORED,
|
|
|
|
|
StoredJP = CAPACITY_STORED_JP,
|
|
|
|
|
Single
|
|
|
|
|
}
|
|
|
|
|
|
2017-05-13 03:32:36 +00:00
|
|
|
|
private static int getEntrySize(CapacityType c) => c == CapacityType.Single || c == CapacityType.Party
|
|
|
|
|
? PKX.SIZE_1PARTY
|
|
|
|
|
: PKX.SIZE_1STORED;
|
|
|
|
|
private static byte getCapacity(CapacityType c) => c == CapacityType.Single ? (byte)1 : (byte)c;
|
2016-08-27 08:52:34 +00:00
|
|
|
|
|
2017-05-13 03:32:36 +00:00
|
|
|
|
private static byte[] getEmptyList(CapacityType c, bool is_JP = false)
|
2016-08-27 08:52:34 +00:00
|
|
|
|
{
|
|
|
|
|
int cap = getCapacity(c);
|
|
|
|
|
return new[] { (byte)0 }.Concat(Enumerable.Repeat((byte)0xFF, cap + 1)).Concat(Enumerable.Repeat((byte)0, getEntrySize(c) * cap)).Concat(Enumerable.Repeat((byte)0x50, (is_JP ? PK1.STRLEN_J : PK1.STRLEN_U) * 2 * cap)).ToArray();
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-27 11:33:21 +00:00
|
|
|
|
public PokemonList1(byte[] d, CapacityType c = CapacityType.Single, bool jp = false)
|
2016-08-27 08:52:34 +00:00
|
|
|
|
{
|
|
|
|
|
Japanese = jp;
|
|
|
|
|
Data = d ?? getEmptyList(c, Japanese);
|
|
|
|
|
Capacity = getCapacity(c);
|
|
|
|
|
Entry_Size = getEntrySize(c);
|
|
|
|
|
|
|
|
|
|
if (Data.Length != DataSize)
|
|
|
|
|
Array.Resize(ref Data, DataSize);
|
|
|
|
|
|
|
|
|
|
Pokemon = new PK1[Capacity];
|
|
|
|
|
for (int i = 0; i < Capacity; i++)
|
|
|
|
|
{
|
|
|
|
|
int base_ofs = 2 + Capacity;
|
|
|
|
|
byte[] dat = Data.Skip(base_ofs + Entry_Size * i).Take(Entry_Size).ToArray();
|
2016-09-04 06:54:11 +00:00
|
|
|
|
Pokemon[i] = new PK1(dat, null, jp)
|
|
|
|
|
{
|
|
|
|
|
otname = Data.Skip(base_ofs + Capacity*Entry_Size + StringLength*i).Take(StringLength).ToArray(),
|
|
|
|
|
nick = Data.Skip(base_ofs + Capacity*Entry_Size + StringLength*Capacity + StringLength*i)
|
|
|
|
|
.Take(StringLength).ToArray()
|
|
|
|
|
};
|
2016-08-27 08:52:34 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-27 11:33:21 +00:00
|
|
|
|
public PokemonList1(CapacityType c = CapacityType.Single, bool jp = false)
|
2017-05-13 03:32:36 +00:00
|
|
|
|
: this(null, c, jp) => Count = 1;
|
2016-08-27 08:52:34 +00:00
|
|
|
|
|
2016-08-27 11:33:21 +00:00
|
|
|
|
public PokemonList1(PK1 pk)
|
2016-08-27 08:52:34 +00:00
|
|
|
|
: this(CapacityType.Single, pk.Japanese)
|
|
|
|
|
{
|
|
|
|
|
this[0] = pk;
|
|
|
|
|
Count = 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private readonly byte[] Data;
|
|
|
|
|
private readonly byte Capacity;
|
|
|
|
|
private readonly int Entry_Size;
|
|
|
|
|
|
|
|
|
|
public byte Count
|
|
|
|
|
{
|
2017-05-13 03:32:36 +00:00
|
|
|
|
get => Data[0];
|
|
|
|
|
set => Data[0] = value > Capacity ? Capacity : value;
|
2016-08-27 08:52:34 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public readonly PK1[] Pokemon;
|
|
|
|
|
|
|
|
|
|
public PK1 this[int i]
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
if (i > Capacity || i < 0) throw new IndexOutOfRangeException($"Invalid PokemonList Access: {i}");
|
|
|
|
|
return Pokemon[i];
|
|
|
|
|
}
|
|
|
|
|
set
|
|
|
|
|
{
|
|
|
|
|
if (value == null) return;
|
2016-09-04 06:54:11 +00:00
|
|
|
|
Pokemon[i] = (PK1)value.Clone();
|
2016-08-27 08:52:34 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void Update()
|
|
|
|
|
{
|
2016-09-04 06:54:11 +00:00
|
|
|
|
if (Pokemon.Any(pk => pk.Species == 0))
|
|
|
|
|
Count = (byte) Array.FindIndex(Pokemon, pk => pk.Species == 0);
|
2016-08-29 20:27:17 +00:00
|
|
|
|
else
|
|
|
|
|
Count = Capacity;
|
2016-08-27 08:52:34 +00:00
|
|
|
|
for (int i = 0; i < Count; i++)
|
|
|
|
|
{
|
2016-08-29 05:21:55 +00:00
|
|
|
|
Data[1 + i] = (byte)PKX.setG1Species(Pokemon[i].Species);
|
2016-08-27 08:52:34 +00:00
|
|
|
|
Array.Copy(Pokemon[i].Data, 0, Data, 2 + Capacity + Entry_Size * i, Entry_Size);
|
2016-08-28 10:18:22 +00:00
|
|
|
|
Array.Copy(Pokemon[i].OT_Name_Raw, 0, Data, 2 + Capacity + Capacity * Entry_Size + StringLength * i, StringLength);
|
|
|
|
|
Array.Copy(Pokemon[i].Nickname_Raw, 0, Data, 2 + Capacity + Capacity * Entry_Size + StringLength * Capacity + StringLength * i, StringLength);
|
2016-08-27 08:52:34 +00:00
|
|
|
|
}
|
|
|
|
|
Data[1 + Count] = byte.MaxValue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public byte[] GetBytes()
|
|
|
|
|
{
|
|
|
|
|
Update();
|
|
|
|
|
return Data;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private int DataSize => Capacity * (Entry_Size + 1 + 2 * StringLength) + 2;
|
2017-05-13 03:32:36 +00:00
|
|
|
|
public static int GetDataLength(CapacityType c, bool jp = false) => getCapacity(c) * (getEntrySize(c) + 1 + 2 * (jp ? PK1.STRLEN_J : PK1.STRLEN_U)) + 2;
|
2016-08-27 08:52:34 +00:00
|
|
|
|
}
|
|
|
|
|
}
|