GBA Pokémon now supported

Added some fields to PokemonUI
StrategyMemoUI now working properly
Other minor fixes
This commit is contained in:
Elouan Appéré 2015-09-12 22:50:05 +02:00
parent 3c863d7f5e
commit e73e92debd
40 changed files with 2661 additions and 715 deletions

View File

@ -27,7 +27,8 @@
namespace LibPkmGC {
LIBPKMGC_FWD_DECL_GC_CLS(Pokemon)
namespace GC { class Pokemon; }
namespace GBA { class Pokemon; }
namespace Base {
@ -75,7 +76,7 @@ public:
char getUnownForm(void) const;
bool isSecondAbilityDefined(void) const;
virtual PokemonAbilityIndex getAbility(void) const = 0;
PokemonAbilityIndex getAbility(void) const;
virtual bool isEmptyOrInvalid(void) const;
PokemonSpeciesIndex species; //u16
@ -98,10 +99,12 @@ public:
u16 TID;
u32 PID;
// u8 encounterType;
u8 encounterType;
VersionInfo version;
bool obedient;
bool specialRibbons[12];
u8 unimplementedRibbons;
//u32 statusFlags;
@ -112,20 +115,36 @@ public:
u8 contestStats[5];
ContestAchievementLevel contestAchievements[5];
bool usesPartyData; // we will avoid using ptrs here
u16 unk1;
u16 unk2;
virtual bool isEgg(void) const = 0;
virtual bool hasSecondAbility(void) const = 0;
virtual void setEggFlag(bool flag) = 0;
virtual void setSecondAbilityFlag(bool flag) = 0;
struct PokemonComputedPartyData {
s8 pkrsDaysRemaining;
u16 currentHP;
u8 level;
PokemonStatus status;
s8 turnsOfBadPoison, turnsOfSleepRemaining;
u16 stats[6];
};
PokemonComputedPartyData partyData;
void normalizePkrs(void);
void normalizeStatus(void);
void resetPartyData(void);
protected:
Pokemon(Pokemon const& other);
virtual void deleteFields(void);
private:
void copyNonVirtual(Pokemon const& other);
};
}

View File

@ -22,7 +22,40 @@
#include <LibPkmGC/Core/IntegerTypes.h>
#include <algorithm>
#if defined(LIBPKMGC_SOURCE) && !defined(RET_ILSEQ)
/* Return code if invalid. (xxx_mbtowc) */
# define RET_ILSEQ -1
/* Return code if no bytes were read. (xxx_mbtowc) */
//# define RET_TOOFEW -2
# define RET_TOOFEW(c) -2
/* Return code if invalid. (xxx_wctomb) */
# define RET_ILUNI -1
/* Return code if output buffer is too small. (xxx_wctomb, xxx_reset) */
# define RET_TOOSMALL -2
#endif
namespace LibPkmGC {
namespace Detail {
typedef void* conv_t;
typedef u32 ucs4_t;
int ucs2be_mbtowc(conv_t conv, ucs4_t *pwc, const unsigned char *s, int n);
int ucs2be_wctomb(conv_t conv, unsigned char *r, ucs4_t wc, int n);
int utf8_mbtowc(conv_t conv, ucs4_t *pwc, const unsigned char *s, int n);
int utf8_wctomb(conv_t conv, unsigned char *r, ucs4_t wc, int n);
int pkmgba_mbtowc(conv_t conv, ucs4_t *pwc, const unsigned char* s, int n, bool jap = false);
int pkmgba_wctomb(conv_t conv, unsigned char *r, ucs4_t wc, int n, bool jap = false);
}
namespace GC { class PokemonString; } namespace GBA { class PokemonString; }
namespace Base {
// Commands (scroll, color etc...) are NOT supported
@ -45,8 +78,12 @@ public:
virtual void load(u8* data, size_t nb) = 0; // nb: number of characters, not counting NULL
virtual void save(u8* data, size_t nb) const = 0;
virtual bool isGBA(void) const = 0;
bool usesJapaneseCharset(void) const;
void setCharset(bool jap);
protected:
bool _japanese;
PokemonString(PokemonString const& other);
@ -55,6 +92,13 @@ protected:
mutable size_t strSz, strCapacity;
void resizeStr(void) const;
u8* _data;
size_t dataSz;
size_t dataCapacity;
void resizeData(void);
};
}

View File

@ -25,7 +25,6 @@ namespace LibPkmGC {
namespace Colosseum {
/*
pkm
0x00: u16 index
0x02 : u16 ? ? ? ? (0 on shadow pkm)
0x04 : u32 PID
@ -44,10 +43,11 @@ pkm
0x5c : u32 experience
0x60 : u8 currentLevel
0x61 -- 0x64 : ? ?
0x65 : u16 status (u8 on XD)
0x65 -- 0x67 : ? ?
0x68 : u32 ? ?
0x6c--0x78 ? ?
0x65 -- 0x77: status info
0x65 : u16 status
0x69 : s8 turnsOfSleepRemaining
0x6b : s8 turnsOfBadPoison
0x74 : u32 = pokemonStatusToBitField(status, 0, turnsOfSleepRemaining)
0x78 : moves info
0x88 : u16 itemHeld
0x8a : u16 currentHP
@ -59,21 +59,27 @@ pkm
0xb7 : u8 contestsRibbons[5]
0xbc : u8 contestLuster
0xbd : u8 specialRibbons[12]
0xc9 : u8 unused ?
0xc9 : u8 unimplentedRibbons (max. 15)
0xca : u8 pkrsStatus
0xcb : u8 flags[3] : egg, special ability, invalid pkm
0xce : u8 GCUnk
0xcf : u8 marks
// shadow pkm data ?
0xd0--0xd7 : ? ?
0xd0: s8 pkrsRemainingDays
0xd1--0xd7 : ? ?
0xd2: u16 unk2
0xd4: u16 unk1
0xd8 : u16 shadowPkmID
0xda--0xdb : padding ?
0xdc : s32 purificationCounter
0xe0 : u32 expStored
0xe4 : u16 ? ?
0xe6 : u16 ? ?
0xf8: u8 obedient
0xfb : u8 encounterType
0xfc--0x138 : ? ? ? ? ? ? ? ? ? ?
*/
class LIBPKMGC_DECL Pokemon : public GC::Pokemon {
public:
static const size_t size = 0x138;
@ -84,14 +90,13 @@ public:
Pokemon* clone(void) const;
Pokemon* create(void) const;
bool isEmptyOrInvalid(void) const;
void save(void);
void swap(Pokemon& other);
Pokemon& operator=(Pokemon const& other);
Pokemon(XD::Pokemon const& other);
Pokemon(GBA::Pokemon const& other);
Pokemon& operator=(GC::Pokemon const& other);
void swap(GC::Pokemon & other);
protected:

View File

@ -19,17 +19,16 @@
#ifndef _LIBPKMGC_CONFIG_H
#define _LIBPKMGC_CONFIG_H
// _LICENSE_
#include <boost/config/warning_disable.hpp>
#include <boost/config.hpp>
#include <boost/predef.h>
#define LIBPKMGC_VERSION 1000000
#define LIBPKMGC_VERSION 1001000
#define LIBPKMGC_VERSION_MAJOR ((LIBPKMGC_VERSION / 1000000) % 1000)
#define LIBPKMGC_VERSION_MINOR ((LIBPKMGC_VERSION / 1000) % 1000)
#define LIBPKMGC_VERSION_BUILD (LIBPKMGC_VERSION % 1000)
#if defined(LIBPKMGC_DYN_LIB) && !defined(LIBPKMGC_STATIC_LIB)
#if defined(LIBPKMGC_DYN_LIB)
# ifdef LIBPKMGC_SOURCE
# define LIBPKMGC_DECL BOOST_SYMBOL_EXPORT
# else

View File

@ -37,29 +37,52 @@
#ifndef BUFFER_NAME
#define BUFFER_NAME data
#endif
/*
#ifndef TARGET_ENDIANNESS
#define TARGET_ENDINANNESS BE
#endif
*/
#define SM_H_TMP_NS_EVAL() TARGET_ENDINANNESS
#define SM_H_TMP_NS() LibPkmGC::IntegerManip::SM_H_TMP_NS_EVAL()
using namespace LibPkmGC::IntegerManip;
#if !defined(TARGET_ENDIANNESS_LE)
using namespace BE;
#else
using namespace LE;
#endif
#define LD_FIELD(type,fld,off) fld = SM_H_TMP_NS()::toInteger<type, u8*>(BUFFER_NAME+off)
#define LD_FIELD_E(type,fld,off,etype) fld = SM_H_TMP_NS()::toEnumInteger<type, etype, u8*>(BUFFER_NAME+off)
#define LD_FIELD_B(type,fld,off) fld = SM_H_TMP_NS()::toBoolInteger<type,u8*>(BUFFER_NAME+off)
#define LD_ARRAY(type,ar,sz,off) SM_H_TMP_NS()::toArrayOfIntegers<u8*,type*>(ar, BUFFER_NAME+off, BUFFER_NAME+off+(sizeof(type)*sz))
#define LD_ARRAY_E(type,ar,sz,off,etype) SM_H_TMP_NS()::toArrayOfEnumIntegers<type,u8*,etype*>(ar, BUFFER_NAME+off, BUFFER_NAME+off+(sizeof(type)*sz))
#define LD_ARRAY_B(type,ar,sz,off) SM_H_TMP_NS()::toArrayOfBoolIntegers<type,u8*,bool*>(ar, BUFFER_NAME+off, BUFFER_NAME+off+(sizeof(type)*sz))
#define LD_FIELD(type,fld,off) fld = toInteger<type, u8*>(BUFFER_NAME+off)
#define LD_FIELD_MAX(type,fld,off,mx) fld = toInteger<type, u8*>(BUFFER_NAME+off); fld = (fld > mx) ? mx : fld
#define LD_FIELD_CONV(type,fld,off,type2) type fld##_tmp; LD_FIELD_MAX(type,fld##_tmp,off,(type2)-1); fld = (type2) fld##_tmp;
#define LD_FIELD_E(type,fld,off,etype) fld = toEnumInteger<type, etype, u8*>(BUFFER_NAME+off)
#define LD_FIELD_E_MAX(type,fld,off,etype,mx) fld = toEnumInteger<type, etype, u8*>(BUFFER_NAME+off); fld = ((u32)fld > (u32)mx) ? (etype)0 : fld
#define LD_FIELD_B(type,fld,off) fld = toBoolInteger<type,u8*>(BUFFER_NAME+off)
#define LD_ARRAY(type,ar,sz,off) toArrayOfIntegers<u8*,type*>(ar, BUFFER_NAME+off, BUFFER_NAME+off+(sizeof(type)*sz))
#define LD_ARRAY_MAX(type,ar,sz,off,mx) toArrayOfIntegers<u8*,type*>(ar, BUFFER_NAME+off, BUFFER_NAME+off+(sizeof(type)*sz));\
for(size_t i__ = 0; i__ < sz; ++i__) ar[i__] = (ar[i__] > mx) ? mx : ar[i__];
#define LD_ARRAY_CONV(type,ar,sz,off,type2) type ar##_tmp[sz]; toArrayOfIntegers<u8*,type*>(ar, BUFFER_NAME+off, BUFFER_NAME+off+(sizeof(type)*sz));\
for(size_t i__ = 0; i__ < sz; ++i__) ar[i__] = (ar##_tmp[i__] > mx) ? mx : ar##_tmp[i__];
#define LD_ARRAY_E(type,ar,sz,off,etype) toArrayOfEnumIntegers<type,u8*,etype*>(ar, BUFFER_NAME+off, BUFFER_NAME+off+(sizeof(type)*sz))
#define LD_ARRAY_E_MAX(type,ar,sz,off,etype,mx) toArrayOfEnumIntegers<type,u8*,etype*>(ar, BUFFER_NAME+off, BUFFER_NAME+off+(sizeof(type)*sz));\
for(size_t i__ = 0; i__ < sz; ++i__) ar[i__] = ((u32)ar[i__] > (u32)mx) ? (etype)0 : ar[i__];
#define LD_ARRAY_B(type,ar,sz,off) toArrayOfBoolIntegers<type,u8*,bool*>(ar, BUFFER_NAME+off, BUFFER_NAME+off+(sizeof(type)*sz))
#define LD_BIT_ARRAY2(type,ar,sz,off,st) type ar##_tmp; LD_FIELD(type, ar##_tmp, off); for(int i__ = 0; i__ < sz; ++i__) ar[i__] = (ar##_tmp & (1U << (8*sizeof(type) - 1 - st - i__))) != 0;
#define LD_BIT_ARRAY(type, ar, sz, off) LD_BIT_ARRAY2(type,ar,sz,off,0)
#define SV_FIELD(type,fld,off) SM_H_TMP_NS()::fromInteger<type, u8*>(BUFFER_NAME+off, fld)
#define SV_FIELD_E(type,fld,off,etype) SM_H_TMP_NS()::fromEnumInteger<type, etype, u8*>(BUFFER_NAME+off, fld)
#define SV_FIELD_B(type,fld,off) SM_H_TMP_NS()::fromBoolInteger<type,u8*>(BUFFER_NAME+off, fld)
#define SV_ARRAY(type,ar,sz,off) SM_H_TMP_NS()::fromArrayOfIntegers<type*, u8*>(BUFFER_NAME+off, ar, ar+sz)
#define SV_ARRAY_E(type,ar,sz,off,etype) SM_H_TMP_NS()::fromArrayOfEnumIntegers<type,etype*, u8*>(BUFFER_NAME+off, ar, ar+sz)
#define SV_ARRAY_B(type,ar,sz,off) SM_H_TMP_NS()::toArrayOfBoolIntegers<type, bool*, u8*>(BUFFER_NAME+off, ar, ar+sz)
#define SV_FIELD(type,fld,off) fromInteger<type, u8*>(BUFFER_NAME+off, fld)
#define SV_FIELD_MAX(type,fld,off,mx) fld = (fld > mx) ? mx : fld; fromInteger<type, u8*>(BUFFER_NAME+off, fld)
#define SV_FIELD_CONV(type,fld,off,type2) fld = (fld > (type2)-1) ? (type2)-1 : fld; fromInteger<type, u8*>(BUFFER_NAME+off, (type)fld)
#define SV_FIELD_E(type,fld,off,etype) fromEnumInteger<type, etype, u8*>(BUFFER_NAME+off, fld)
#define SV_FIELD_E_MAX(type,fld,off,etype,mx) fld = ((u32)fld > (u32)mx) ? (etype)0 : fld; fromEnumInteger<type, etype, u8*>(BUFFER_NAME+off, fld)
#define SV_FIELD_B(type,fld,off) fromBoolInteger<type,u8*>(BUFFER_NAME+off, fld)
#define SV_ARRAY(type,ar,sz,off) fromArrayOfIntegers<type*, u8*>(BUFFER_NAME+off, ar, ar+sz)
#define SV_ARRAY_MAX(type,ar,sz,off,mx) for(size_t i__ = 0; i__ < sz; ++i__) ar[i__] = (ar[i__] > mx) ? mx : ar[i__];\
fromArrayOfIntegers<type*, u8*>(BUFFER_NAME+off, ar, ar+sz)
#define SV_ARRAY_CONV(type,ar,sz,off,type2) type ar##_tmp[sz]; for(size_t i__=0;i__<sz;++i__) ar##_tmp[i__] = (ar[i__] > mx) ? mx : (type) ar[i__];\
fromArrayOfIntegers<type*, u8*>(BUFFER_NAME+off, ar, ar+sz)
#define SV_ARRAY_E(type,ar,sz,off,etype) fromArrayOfEnumIntegers<type,etype*, u8*>(BUFFER_NAME+off, ar, ar+sz)
#define SV_ARRAY_E_MAX(type,ar,sz,off,etype,mx) for(size_t i__ = 0; i__ < sz; ++i__) ar[i__] = ((u32)ar[i__] > (u32)mx) ? (etype)0 : ar[i__];\
fromArrayOfEnumIntegers<type,etype*, u8*>(BUFFER_NAME+off, ar, ar+sz)
#define SV_ARRAY_B(type,ar,sz,off) toArrayOfBoolIntegers<type, bool*, u8*>(BUFFER_NAME+off, ar, ar+sz)
#define SV_BIT_ARRAY2(type, ar, sz, off, st) type ar##_tmp; LD_FIELD(type, ar##_tmp, off); ar##_tmp &= ~(((1U << sz) - 1) << (8*sizeof(type) - 1 - st - sz));\
for(int i__ = 0; i__ < sz; ++i__) ar##_tmp |= ((ar[i__]) ? 1U : 0U) << (8*sizeof(type) - 1 - st - i__); SV_FIELD(type, ar##_tmp, off);
#define SV_BIT_ARRAY(type, ar, sz, off) SV_BIT_ARRAY2(type,ar,sz,off,0)
@ -99,18 +122,20 @@ XD::cls::cls(Colosseum::cls const& other) : GC::cls(XD::cls::size){\
#define LIBPKMGC_GEN_CONVERTER_CTOR(cls) LIBPKMGC_GEN_CONVERTER_CTOR2(cls, 0)
#define LIBPKMGC_GEN_UNIMPLEMENTED_CONVERTER_CTOR(cls)\
Colosseum::cls::cls(XD::cls const& other) : GC::cls(Colosseum::cls::size, 0){}\
XD::cls::cls(Colosseum::cls const& other) : GC::cls(XD::cls::size, 0){}
#define LIBPKMGC_GEN_UNIMPLEMENTED_SAVE_EDITING_CONVERTER_CTOR(cls)\
Colosseum::SaveEditing::cls::cls(XD::SaveEditing::cls const& other) : GC::SaveEditing::cls(Colosseum::SaveEditing::cls::size, 0){}\
XD::SaveEditing::cls::cls(Colosseum::SaveEditing::cls const& other) : GC::SaveEditing::cls(XD::SaveEditing::cls::size, 0){}
#define LIBPKMGC_GEN_CONVERTER_CTOR_W_GBA(cls) LIBPKMGC_GEN_CONVERTER_CTOR(cls)\
XD::cls::cls(GBA::cls const& other) : GC::cls(XD::cls::size){\
initWithEmptyData(0);\
GC::cls::operator=(other);\
}\
Colosseum::cls::cls(GBA::cls const& other) : GC::cls(XD::cls::size){\
initWithEmptyData(0);\
GC::cls::operator=(other);\
}
#define LIBPKMGC_GC_GEN_XD_VTF2(cls, flgs) \
cls& cls::operator=(GC::cls const& other){\
if(LIBPKMGC_IS_XD(cls,&other)) return (cls&) operator=((cls const&)other);\
else { deleteFields(); initWithEmptyData(flgs); return (cls&) GC::cls::operator=(other); }\
else { if (this == &other) return *this; deleteFields(); initWithEmptyData(flgs); return (cls&) GC::cls::operator=(other); }\
}\
void cls::swap(GC::cls & other){\
if(LIBPKMGC_IS_XD(cls,&other)) swap((cls&)other);\
@ -120,7 +145,7 @@ else {cls obj((Colosseum::cls&)other); swap(obj); other.swap(obj);}\
#define LIBPKMGC_GC_GEN_COL_VTF2(cls, flgs) \
cls& cls::operator=(GC::cls const& other){\
if(LIBPKMGC_IS_COLOSSEUM(cls,&other)) return operator=((cls const&)other);\
else { deleteFields(); initWithEmptyData(flgs); return (cls&) GC::cls::operator=(other); }\
else { if (this == &other) return *this; deleteFields(); initWithEmptyData(flgs); return (cls&) GC::cls::operator=(other); }\
}\
void cls::swap(GC::cls & other){\
if(LIBPKMGC_IS_COLOSSEUM(cls,&other)) swap((cls&)other);\
@ -169,7 +194,7 @@ template<typename T> bool test_isXD_or_true(T* obj, typename boost::enable_if<De
#define LIBPKMGC_IS_XD(cls, obj) ((obj)->fixedSize == LibPkmGC::XD::cls::size && LibPkmGC::Detail::test_isXD_or_true(obj))
#define LIBPKMGC_IS_COLOSSEUM(cls, obj) ((obj)->fixedSize == LibPkmGC::Colosseum::cls::size && LibPkmGC::Detail::test_isXD_or_true(obj))
#define LIBPKMGC_IS_GBA(cls, obj) ((obj)->fixedSize == LibPkmGC::GBA::cls::size)
#endif

View File

@ -47,7 +47,7 @@ I toInteger(IteratorType const& _bufferIterator, size_t _integerSize = sizeof(I)
size_t shift = 0;
IteratorType it(_bufferIterator);
for (; shift <= 8 * _integerSize - 8; ++it) {
ret |= (I(*it) << shift);
ret |= (I((u8)*it) << shift);
shift += 8;
}
return ret;
@ -80,7 +80,7 @@ I toInteger(IteratorType const& _bufferIterator, size_t _integerSize = sizeof(I)
IteratorType it(_bufferIterator);
size_t shift = 8 * _integerSize - 8;
for (;; ++it) {
ret |= (I(*it) << shift);
ret |= (I((u8)*it) << shift);
if (shift == 0) break;
else shift -= 8;
}

View File

@ -31,8 +31,9 @@ struct LIBPKMGC_DECL VersionInfo {
LanguageIndex language;
void load(u8* data);
void load(u8 lg, u8 gm); // GBA
void save(u8* data);
void save(u8& lg, u8& gm); // GBA
bool isIncomplete(void) const;
@ -964,6 +965,9 @@ enum PokemonStatus {
NoStatus = 0, Poisoned = 3, BadlyPoisoned = 4, Paralyzed = 5, Burnt = 6, Frozen = 7, Asleep = 8
};
LIBPKMGC_DECL u16 pokemonStatusToBitField(PokemonStatus status, s8 turnsOfBadPoison = 0, s8 turnsOfSleepRemaining = 0);
LIBPKMGC_DECL PokemonStatus pokemonStatusFromBitField(u16 status, s8* turnsOfBadPoison = NULL, s8* turnsOfSleepRemaining = NULL);
struct LIBPKMGC_DECL PokemonSpeciesData {
bool isValid;
PokemonSpeciesExpGrowthType expGrowthType;
@ -983,7 +987,7 @@ LIBPKMGC_DECL u16 getPokedexIndexOf(PokemonSpeciesIndex speciesIndex);
LIBPKMGC_DECL PokemonSpeciesIndex getSpeciesIndexOf(u16 pokedexIndex);
struct LIBPKMGC_DECL PokemonMove {
PokemonMoveIndex moveIndex;
PokemonMoveIndex move;
u8 currentPPs;
u8 nbPPUpsUsed;

View File

@ -0,0 +1,75 @@
/*
* Copyright (C) TuxSH 2015
* This file is part of LibPkmGC.
*
* LibPkmGC is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* LibPkmGC is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with LibPkmGC. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _LIBPKMGC_GBA_POKEMON_H
#define _LIBPKMGC_GBA_POKEMON_H
#include <LibPkmGC/Base/Pokemon.h>
#include <LibPkmGC/GBA/PokemonString.h>
namespace LibPkmGC {
namespace GBA {
class LIBPKMGC_DECL Pokemon :
public Base::Pokemon {
public:
static const size_t size = 100;
Pokemon(const u8* inData, u32 flags = 0);
static Pokemon* load80(const u8* inData, u32 flags = 0);
Pokemon(void);
Pokemon(Pokemon const& other);
~Pokemon(void);
Pokemon* clone(void) const;
Pokemon* create(void) const;
bool checkChecksum(bool fix = false);
bool isEmptyOrInvalid(void) const;
void save(void);
void saveEncrypted(u8* outData);
void swap(Pokemon& other);
Pokemon& operator=(Pokemon const& other);
bool hasSecondAbility(void) const;
void setSecondAbilityFlag(bool status);
bool isEgg(void) const;
void setEggFlag(bool status);
void swap(Base::Pokemon& other);
Pokemon& operator=(Base::Pokemon const& other);
Pokemon(GC::Pokemon const& other);
void reload(const u8* data = NULL, u32 inFlags = 0);
u16 checksum;
u8 GCFlags;
protected:
void load(u32 flags = 0);
void loadData(u32 flags = 0);
void loadFields(void);
private:
u32 _flags;
bool _egg, _secondAbility;
void decryptOrEncrypt(u8* outData);
};
}
}
#endif

View File

@ -0,0 +1,55 @@
/*
* Copyright (C) TuxSH 2015
* This file is part of LibPkmGC.
*
* LibPkmGC is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* LibPkmGC is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with LibPkmGC. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _LIBPKMGC_GBA_POKEMON_STRING_H
#define _LIBPKMGC_GBA_POKEMON_STRING_H
#include <LibPkmGC/Base/PokemonString.h>
namespace LibPkmGC {
namespace GBA {
class LIBPKMGC_DECL PokemonString : public Base::PokemonString {
public:
PokemonString(const char* str = NULL, bool jap = false);
PokemonString(u8* data, size_t nb, bool jap = false);
PokemonString(PokemonString const& other);
~PokemonString(void);
bool isGBA(void) const;
PokemonString* clone(void) const;
PokemonString* create(void) const;
PokemonString& operator=(PokemonString const& other);
PokemonString& operator=(Base::PokemonString const& other);
void fromUTF8(const char* str = NULL);
const char* toUTF8(void) const;
size_t size(void) const;
void load(u8* data, size_t nb);
void save(u8* data, size_t nb) const;
PokemonString(GC::PokemonString const& other);
};
}
}
#endif

View File

@ -38,15 +38,18 @@ public:
virtual void swap(Pokemon& other);
virtual Pokemon& operator=(Pokemon const& other);
/*bool hasSecondAbility(void) const;
void setSpecialAbilityStatus(bool status);*/
virtual PokemonAbilityIndex getAbility(void) const;
bool hasSecondAbility(void) const;
void setSecondAbilityFlag(bool status);
bool isEgg(void) const;
void setEggFlag(bool status);
u8 GCUnk;
u16 shadowPkmID;
bool pkmFlags[3];
virtual void swap(Base::Pokemon& other);
virtual Pokemon& operator=(Base::Pokemon const& other);
void swap(Base::Pokemon& other);
Pokemon& operator=(Base::Pokemon const& other);
protected:
Pokemon(Pokemon const& other);
};

View File

@ -44,12 +44,10 @@ public:
void load(u8* data, size_t nb);
void save(u8* data, size_t nb) const;
private:
u8* _data;
size_t dataSz;
size_t dataCapacity;
bool isGBA(void) const;
PokemonString(GBA::PokemonString const& other);
void resizeData(void);
};
}

View File

@ -51,8 +51,8 @@ public:
virtual void save(void);
virtual bool registerSpecies(PokemonSpeciesIndex index, u32 PID, u16 SID = 0, u16 TID = 0);
virtual bool registerSpecies(Pokemon* pkm);
virtual size_t registerSpecies(PokemonSpeciesIndex index, u32 PID, u16 SID = 0, u16 TID = 0);
virtual size_t registerSpecies(Pokemon* pkm);
void deleteEntry(size_t index);
size_t recount(void) const;

View File

@ -25,12 +25,15 @@ namespace LibPkmGC {
namespace XD {
/*
0x00: u16 species
0x02: u16 itemHeld
XD::Pokemon
0x00: u16 species (cf PokemonInfo.h)
0x03: u8 itemHeld (ItemInfo.h)
0x04: u16 currentHP
0x06: u16 happiness
0x08: u16 locationCaught
// 0x09 -- 0xd :: ??
0x0a: u16 unk1
0x0c: u16 unk2
0x0e: u8 levelMet
0x0f: u8 ballCaughtWith
0x10: u8 OTGender (00 male 01 female 02 genderless=none)
@ -38,11 +41,12 @@ namespace XD {
0x12: u8 Contest Luster
0x13: u8 pkrsStatus
0x14: u8 marks (bitfield)
0x15: 0xff ?
0x15: s8 pkrsRemainingDays
0x16: u16 status (3 psn, 4 psn (toxic ?), 5 par, 6 brn, 7 frzn, 8 slp)
0x17: ?
0x18 -- 0x1b : ? (0x50)
0x1d: u8 pkmFlags
0x17: s8 turnsOfBadPoison (max 15.)
0x18: s8 turnsOfSleepRemaining (max. 8)
0x19 -- 0x1b : ? (0x50)
0x1d: u8 pkmFlags | XDPkmFlags
bit 7: egg flag
bit 6: special (second) ability flag. Pokémon XD's catchable Pkms have a 50% chance to have their special ability
bit 5: invalidity flag. MUST **NOT** BE SET for the Pokémon to be considered as valid ("not empty")
@ -54,15 +58,16 @@ namespace XD {
0x24: u16 SID
0x26: u16 TID
0x28: u32 PID
0x2c: u32 12_status_bits appended at the most significant positions ...
0x32 : ?? (0 on shadow pkm)
0x2c: u32 = pokemonStatusToBitField(status, 0, turnsOfSleepRemaining)
0x30: u8 obedient
0x31, 0x32: ??
0x33: u8 encounterType
0x34 -- 0x37 : Version info (actual region, original region, original language)
0x38: GC::PokemonString OTName (10+1 chars = 22 bytes)
0x4e: GC::PokemonString name (10+1 chars)
0x64: pkm name backup
0x7a -- 0x7b: ??
0x7c: u16 specialRibbons
0x7c: u16 specialRibbons | unimplementedRibbons
0x7e -- 0x7f: ??
0x80: moves[4]{u16 moveID, u8 basePP (?), u8 nbPPUps}
0x90: u16 stats[6]
@ -74,8 +79,7 @@ namespace XD {
0xb8 : u16 ??
0xba: shadow pkm id
0xbc -- 0xbf : ??? ????
0xc0 -- 0xc1 : unused ?
0xc2: party identify (lead = 00, 01 otherwise)
0xc0 -- 0xc4 : unused ?
*/
class LIBPKMGC_DECL Pokemon : public GC::Pokemon {
@ -87,18 +91,19 @@ public:
~Pokemon(void);
Pokemon* clone(void) const;
Pokemon* create(void) const;
bool isEmptyOrInvalid(void) const;
void save(void);
void swap(Pokemon& other);
Pokemon& operator=(Pokemon const& other);
Pokemon(Colosseum::Pokemon const& other);
Pokemon(GBA::Pokemon const& other);
Pokemon& operator=(GC::Pokemon const& other);
void swap(GC::Pokemon & other);
bool XDPkmFlags[3];
private:
protected:
void loadFields(void);
};

View File

@ -17,6 +17,7 @@
*/
#include <LibPkmGC/Base/Pokemon.h>
#include <string>
namespace LibPkmGC {
@ -69,11 +70,11 @@ u32 Pokemon::fixExperienceProportionally(PokemonSpeciesIndex oldSpecies, u32 old
}
Pokemon::Pokemon(size_t inSize, const u8* inData) : DataStruct(inSize, inData) {
Pokemon::Pokemon(size_t inSize, const u8* inData) : DataStruct(inSize, inData) {
}
Pokemon::~Pokemon(void) {
Pokemon::deleteFields();
}
@ -154,25 +155,52 @@ char Pokemon::getUnownForm(void) const {
return getUnownForm(PID);
}
void Pokemon::normalizePkrs(void) {
u8 st = pkrsStatus & 0xf, dr = pkrsStatus >> 4;
if (st == 0) {
dr = 0;
partyData.pkrsDaysRemaining = -1;
}
else {
u8 mx = 1 + (st & 0x3);
dr = (dr > mx) ? mx : dr;
partyData.pkrsDaysRemaining = (partyData.pkrsDaysRemaining > mx) ? mx : partyData.pkrsDaysRemaining;
}
pkrsStatus = (dr << 4) | st;
}
void Pokemon::normalizeStatus(void) {
partyData.status = (partyData.status != NoStatus && partyData.status < Poisoned && partyData.status > Asleep) ? NoStatus : partyData.status;
if (partyData.status != Asleep) partyData.turnsOfSleepRemaining = 0;
if (partyData.status != BadlyPoisoned) partyData.turnsOfBadPoison = 0;
partyData.turnsOfSleepRemaining = ((u8)partyData.turnsOfSleepRemaining > 7) ? 7 : partyData.turnsOfSleepRemaining;
partyData.turnsOfBadPoison = ((u8)partyData.turnsOfBadPoison > 15) ? 15 : partyData.turnsOfBadPoison;
}
void Pokemon::resetPartyData(void) {
updateStats();
updateLevelFromExp();
partyData.status = NoStatus;
partyData.currentHP = partyData.stats[0];
partyData.pkrsDaysRemaining = ((pkrsStatus & 0xf0) != 0) ? pkrsStatus & 0xf : -1;
}
Pokemon::Pokemon(Pokemon const & other) : Base::DataStruct(other.fixedSize, NULL, true){
data = new u8[other.fixedSize];
Pokemon::operator=(other);
Pokemon::Pokemon(Pokemon const & other) : Base::DataStruct(other), OTName(NULL), name(NULL){
copyNonVirtual(other);
}
void Pokemon::deleteFields(void){
delete OTName;
delete name;
}
PokemonAbilityIndex Pokemon::getAbility(void) const {
const PokemonSpeciesData dt = getThisSpeciesData();
return (hasSecondAbility()) ? dt.possibleAbilities[1] : dt.possibleAbilities[0];
}
/*
void Pokemon::calculateSpindaSpotsPosition(std::pair<u8,u8>[4]) const{
u32 PID_2 = PID;
}*/
bool Pokemon::isEmptyOrInvalid(void) const {
return (species > 0x19e) || (species == 0) || !getSpeciesData(species).isValid || version.isIncomplete();
return (species >= Bonsly) || (species == NoSpecies) || !getSpeciesData(species).isValid || version.isIncomplete();
}
bool Pokemon::isSecondAbilityDefined(void) const{
@ -188,8 +216,20 @@ void Pokemon::swap(Pokemon& other) {
SW(ballCaughtWith);
SW(levelMet);
SW(OTGender);
SW(OTName);
SW(name);
if (OTName->isGBA() == other.OTName->isGBA())
SW(OTName);
else {
std::string s1(OTName->toUTF8());
OTName->fromUTF8(other.OTName->toUTF8());
other.OTName->fromUTF8(s1.c_str());
}
if (name->isGBA() == other.name->isGBA())
SW(name);
else {
std::string s1(name->toUTF8());
name->fromUTF8(other.name->toUTF8());
other.name->fromUTF8(s1.c_str());
}
SW(contestLuster);
SW(pkrsStatus);
SW(markings);
@ -199,13 +239,14 @@ void Pokemon::swap(Pokemon& other) {
SW(TID);
SW(PID);
// SW(encounterType);
if(fixedSize == other.fixedSize) SW(encounterType);
SW(version);
SW(usesPartyData);
SW(partyData);
SW_ARRAY(specialRibbons, 12)
SW_ARRAY(specialRibbons, 12);
SW(unimplementedRibbons);
SW_ARRAY(moves, 4);
SW_ARRAY(EVs, 6);
SW_ARRAY(IVs, 6);
@ -213,43 +254,63 @@ void Pokemon::swap(Pokemon& other) {
SW_ARRAY(contestStats, 5);
SW_ARRAY(contestAchievements, 5);
SW(obedient);
SW(unk1);
SW(unk2);
bool e1 = isEgg(), e2 = other.isEgg();
setEggFlag(e2); other.setEggFlag(e1);
bool a1 = hasSecondAbility(), a2 = other.hasSecondAbility();
setSecondAbilityFlag(a2); setSecondAbilityFlag(a1);
}
void Pokemon::copyNonVirtual(Pokemon const& other) {
//Pokemon::deleteFields(); nope, don't do that
CP(species);
CP(heldItem);
CP(happiness);
CP(locationCaught);
CP(ballCaughtWith);
CP(levelMet);
CP(OTGender);
CP(contestLuster);
CP(pkrsStatus);
CP(markings);
CP(experience);
CP(SID);
CP(TID);
CP(PID);
if (fixedSize == other.fixedSize) CP(encounterType);
CP(version);
CP_ARRAY(specialRibbons, 12);
CP(unimplementedRibbons);
CP_ARRAY(moves, 4);
CP_ARRAY(EVs, 6);
CP_ARRAY(IVs, 6);
CP(partyData);
CP_ARRAY(contestStats, 5);
CP_ARRAY(contestAchievements, 5);
CP(obedient);
CP(unk1);
CP(unk2);
}
Pokemon & Pokemon::operator=(Pokemon const & other){
if (this != &other) {
Base::DataStruct::operator=(other);
CP(species);
CP(heldItem);
CP(happiness);
CP(locationCaught);
CP(ballCaughtWith);
CP(levelMet);
CP(OTGender);
CL(OTName)
CL(name);
CP(contestLuster);
CP(pkrsStatus);
CP(markings);
CP(experience);
CP(SID);
CP(TID);
CP(PID);
// CP(encounterType);
CP(version);
CP_ARRAY(specialRibbons, 12);
CP(usesPartyData);
CP(partyData);
CP_ARRAY(moves, 4);
CP_ARRAY(EVs, 6);
CP_ARRAY(IVs, 6);
CP_ARRAY(contestStats, 5);
CP_ARRAY(contestAchievements, 5);
copyNonVirtual(other);
*OTName = *(other.OTName);
*name = *(other.name);
setEggFlag(other.isEgg());
setSecondAbilityFlag(other.hasSecondAbility());
}
return *this;
}

View File

@ -26,6 +26,7 @@ PokemonBox::PokemonBox(size_t inSize, const u8* inData) : DataStruct(inSize, inD
}
void PokemonBox::deleteFields(void) {
delete name;
for (size_t i = 0; i < 30; ++i)
delete pkm[i];
}

View File

@ -16,25 +16,53 @@
* along with LibPkmGC. If not, see <http://www.gnu.org/licenses/>.
*/
// This file uses code from libiconv :
/*
* Copyright (C) 1999-2001, 2004 Free Software Foundation, Inc.
* This file is part of the GNU LIBICONV Library.
*
* The GNU LIBICONV Library is free software; you can redistribute it
* and/or modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* The GNU LIBICONV Library is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with the GNU LIBICONV Library; see the file COPYING.LIB.
* If not, write to the Free Software Foundation, Inc., 51 Franklin Street,
* Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <LibPkmGC/Base/PokemonString.h>
namespace LibPkmGC {
namespace Base {
PokemonString::PokemonString(void) : hasChanged(true), _str(NULL), strSz(0), strCapacity(0) {
PokemonString::PokemonString(void) : hasChanged(true), _str(NULL), strSz(0), strCapacity(0), _data(NULL), dataSz(0), dataCapacity(0), _japanese(false) {
}
PokemonString::~PokemonString(void) {
delete[] _str;
delete[] _data;
}
PokemonString & PokemonString::operator=(PokemonString const & other) {
if (this != &other) {
hasChanged = other.hasChanged;
assert(isGBA() == other.isGBA());
hasChanged = true;
strSz = other.strSz;
_japanese = other._japanese;
dataSz = other.dataSz;
dataCapacity = other.dataCapacity;
resizeStr();
std::copy(other._str, other._str + strSz, _str);
resizeData();
std::copy(other._data, other._data + dataSz, _data);
}
return *this;
}
@ -44,9 +72,20 @@ PokemonString::operator const char*(void) const {
return toUTF8();
}
PokemonString::PokemonString(PokemonString const & other) : hasChanged(other.hasChanged), strSz(other.strSz), strCapacity(0), _str(NULL) {
bool PokemonString::usesJapaneseCharset(void) const {
return _japanese;
}
void PokemonString::setCharset(bool jap) {
if (jap != _japanese) hasChanged = true;
_japanese = jap;
}
PokemonString::PokemonString(PokemonString const & other) : hasChanged(true), strSz(other.strSz), strCapacity(0), _str(NULL),
dataSz(other.dataSz), dataCapacity(0), _data(NULL), _japanese(other._japanese) {
resizeStr();
std::copy(other._str, other._str + strSz, _str);
resizeData();
std::copy(other._data, other._data + dataSz, _data);
}
void PokemonString::resizeStr(void) const {
@ -57,5 +96,132 @@ void PokemonString::resizeStr(void) const {
}
}
void PokemonString::resizeData(void) {
if (dataCapacity < dataSz) {
dataCapacity = dataSz;
delete[] _data;
_data = new u8[dataSz];
}
}
}
namespace Detail {
/*
* UTF-8
*/
/* Specification: RFC 3629 */
int
utf8_mbtowc(conv_t conv, ucs4_t *pwc, const unsigned char *s, int n)
{
unsigned char c = s[0];
if (c < 0x80) {
*pwc = c;
return 1;
}
else if (c < 0xc2) {
return RET_ILSEQ;
}
else if (c < 0xe0) {
if (n < 2)
return RET_TOOFEW(0);
if (!((s[1] ^ 0x80) < 0x40))
return RET_ILSEQ;
*pwc = ((ucs4_t)(c & 0x1f) << 6)
| (ucs4_t)(s[1] ^ 0x80);
return 2;
}
else if (c < 0xf0) {
if (n < 3)
return RET_TOOFEW(0);
if (!((s[1] ^ 0x80) < 0x40 && (s[2] ^ 0x80) < 0x40
&& (c >= 0xe1 || s[1] >= 0xa0)))
return RET_ILSEQ;
*pwc = ((ucs4_t)(c & 0x0f) << 12)
| ((ucs4_t)(s[1] ^ 0x80) << 6)
| (ucs4_t)(s[2] ^ 0x80);
return 3;
}
else if (c < 0xf8 && sizeof(ucs4_t) * 8 >= 32) {
if (n < 4)
return RET_TOOFEW(0);
if (!((s[1] ^ 0x80) < 0x40 && (s[2] ^ 0x80) < 0x40
&& (s[3] ^ 0x80) < 0x40
&& (c >= 0xf1 || s[1] >= 0x90)))
return RET_ILSEQ;
*pwc = ((ucs4_t)(c & 0x07) << 18)
| ((ucs4_t)(s[1] ^ 0x80) << 12)
| ((ucs4_t)(s[2] ^ 0x80) << 6)
| (ucs4_t)(s[3] ^ 0x80);
return 4;
}
else if (c < 0xfc && sizeof(ucs4_t) * 8 >= 32) {
if (n < 5)
return RET_TOOFEW(0);
if (!((s[1] ^ 0x80) < 0x40 && (s[2] ^ 0x80) < 0x40
&& (s[3] ^ 0x80) < 0x40 && (s[4] ^ 0x80) < 0x40
&& (c >= 0xf9 || s[1] >= 0x88)))
return RET_ILSEQ;
*pwc = ((ucs4_t)(c & 0x03) << 24)
| ((ucs4_t)(s[1] ^ 0x80) << 18)
| ((ucs4_t)(s[2] ^ 0x80) << 12)
| ((ucs4_t)(s[3] ^ 0x80) << 6)
| (ucs4_t)(s[4] ^ 0x80);
return 5;
}
else if (c < 0xfe && sizeof(ucs4_t) * 8 >= 32) {
if (n < 6)
return RET_TOOFEW(0);
if (!((s[1] ^ 0x80) < 0x40 && (s[2] ^ 0x80) < 0x40
&& (s[3] ^ 0x80) < 0x40 && (s[4] ^ 0x80) < 0x40
&& (s[5] ^ 0x80) < 0x40
&& (c >= 0xfd || s[1] >= 0x84)))
return RET_ILSEQ;
*pwc = ((ucs4_t)(c & 0x01) << 30)
| ((ucs4_t)(s[1] ^ 0x80) << 24)
| ((ucs4_t)(s[2] ^ 0x80) << 18)
| ((ucs4_t)(s[3] ^ 0x80) << 12)
| ((ucs4_t)(s[4] ^ 0x80) << 6)
| (ucs4_t)(s[5] ^ 0x80);
return 6;
}
else
return RET_ILSEQ;
}
int
utf8_wctomb(conv_t conv, unsigned char *r, ucs4_t wc, int n) /* n == 0 is acceptable */ {
int count;
if (wc < 0x80)
count = 1;
else if (wc < 0x800)
count = 2;
else if (wc < 0x10000)
count = 3;
else if (wc < 0x200000)
count = 4;
else if (wc < 0x4000000)
count = 5;
else if (wc <= 0x7fffffff)
count = 6;
else
return RET_ILUNI;
if (n < count)
return RET_TOOSMALL;
switch (count) { /* note: code falls through cases! */
case 6: r[5] = 0x80 | (wc & 0x3f); wc = wc >> 6; wc |= 0x4000000;
case 5: r[4] = 0x80 | (wc & 0x3f); wc = wc >> 6; wc |= 0x200000;
case 4: r[3] = 0x80 | (wc & 0x3f); wc = wc >> 6; wc |= 0x10000;
case 3: r[2] = 0x80 | (wc & 0x3f); wc = wc >> 6; wc |= 0x800;
case 2: r[1] = 0x80 | (wc & 0x3f); wc = wc >> 6; wc |= 0xc0;
case 1: r[0] = wc;
}
return count;
}
}
}

View File

@ -32,17 +32,17 @@ Pokemon::~Pokemon(void) {
Pokemon::Pokemon(Pokemon const& other) : GC::Pokemon(other){}
Pokemon* Pokemon::clone(void) const { return new Pokemon(*this); }
Pokemon* Pokemon::create(void) const { return new Pokemon; }
Pokemon* Pokemon::clone(void) const {
return new Pokemon(*this);
}
Pokemon* Pokemon::create(void) const {
return new Pokemon;
}
void Pokemon::swap(Pokemon& other) {
GC::Pokemon::swap(other);
}
bool Pokemon::isEmptyOrInvalid(void) const {
return GC::Pokemon::isEmptyOrInvalid() && species == Bonsly;
}
void Pokemon::loadFields(void) {
u8 marksTmp = 0;
@ -50,27 +50,31 @@ void Pokemon::loadFields(void) {
LD_FIELD(u32, PID, 0x04);
version.load(data + 0x08);
u16 locationCaught_tmp;
LD_FIELD(u16, locationCaught_tmp, 0x0c);
locationCaught = (u8)((locationCaught_tmp > 255) ? 255 : locationCaught_tmp);
LD_FIELD_CONV(u16, locationCaught, 0x0c, u8);
LD_FIELD(u8, levelMet, 0x0e);
LD_FIELD_E(u8, ballCaughtWith, 0x0f, ItemIndex);
LD_FIELD_E(u8, OTGender, 0x10, Gender);
LD_FIELD_MAX(u8, levelMet, 0x0e, 100);
LD_FIELD_E_MAX(u8, ballCaughtWith, 0x0f, ItemIndex, PremierBall);
if (ballCaughtWith == NoItem) ballCaughtWith = PokeBall;
LD_FIELD_E_MAX(u8, OTGender, 0x10, Gender, Female);
LD_FIELD(u16, SID, 0x14);
LD_FIELD(u16, TID, 0x16);
OTName = new GC::PokemonString(data + 0x18, 10);
name = new GC::PokemonString(data + 0x2e, 10);
LD_FIELD(u32, experience, 0x5c);
LD_FIELD_MAX(u32, experience, 0x5c, getSpeciesExpTable(species)[100]);
LD_FIELD(u8, partyData.level, 0x60);
if (partyData.level > 100) partyData.level = 100;
LD_FIELD_E(u16, partyData.status, 0x65, PokemonStatus);
partyData.status = (partyData.status != NoStatus && partyData.status < Poisoned && partyData.status > Asleep) ? NoStatus : partyData.status;
LD_FIELD(s8, partyData.turnsOfSleepRemaining, 0x69);
LD_FIELD(s8, partyData.turnsOfBadPoison, 0x6b);
u32 st = pokemonStatusToBitField(partyData.status, 0, partyData.turnsOfSleepRemaining);
SV_FIELD(u32, st, 0x74);
LD_FIELD_E(u16, heldItem, 0x88, ItemIndex);
LD_FIELD(u16, partyData.currentHP, 0x8a);
LD_ARRAY(u16, partyData.stats, 6, 0x8c);
LD_FIELD_MAX(u16, partyData.currentHP, 0x8a, partyData.stats[0]);
u16 EVs_tmp[6]; // EVs are internally stored as u16
LD_ARRAY(u16, EVs_tmp, 6, 0x98);
@ -79,56 +83,64 @@ void Pokemon::loadFields(void) {
LD_ARRAY(u8, IVs, 6, 0xa4);
for (size_t i = 0; i < 6; ++i) IVs[i] = (IVs[i] > 31) ? 31 : IVs[i];
u16 happiness_tmp;
LD_FIELD(u16, happiness_tmp, 0xb0);
happiness = (happiness_tmp > 255) ? 255 : happiness_tmp;
LD_FIELD_CONV(u16, happiness, 0xb0, u8);
LD_ARRAY(u8, contestStats, 5, 0xb2);
LD_ARRAY_E(u8, contestAchievements, 5, 0xb7, ContestAchievementLevel);
LD_ARRAY_E_MAX(u8, contestAchievements, 5, 0xb7, ContestAchievementLevel, MasterContestWon);
LD_FIELD(u8, contestLuster, 0xbc);
LD_ARRAY_B(u8, specialRibbons, 12, 0xbd);
LD_FIELD_MAX(u8, unimplementedRibbons, 0xc9, 15);
LD_FIELD(u8, pkrsStatus, 0xca);
LD_ARRAY_B(u8, pkmFlags, 3, 0xcb);
LD_FIELD(u8, GCUnk, 0xce);
LD_FIELD(u8, marksTmp, 0xcf);
LD_FIELD_MAX(s8, partyData.pkrsDaysRemaining, 0xd0, 4);
LD_FIELD(u16, unk2, 0xd2);
LD_FIELD(u16, unk1, 0xd4);
LD_FIELD(u16, shadowPkmID, 0xd8);
SV_FIELD_B(u8, obedient, 0xf8);
SV_FIELD(u8, encounterType, 0xfb);
markings.load(marksTmp);
for (size_t i = 0; i < 4; ++i)
moves[i].load(data + 0x78 + 4 * i);
pkmFlags[LIBPKMGC_GC_SECOND_ABILITY_FLAG] = isSecondAbilityDefined() && pkmFlags[LIBPKMGC_GC_SECOND_ABILITY_FLAG];
normalizePkrs();
normalizeStatus();
}
void Pokemon::save(void) {
normalizePkrs();
normalizeStatus();
pkmFlags[LIBPKMGC_GC_SECOND_ABILITY_FLAG] = isSecondAbilityDefined() && pkmFlags[LIBPKMGC_GC_SECOND_ABILITY_FLAG];
SV_FIELD_E(u16, species, 0x00, PokemonSpeciesIndex);
SV_FIELD(u32, PID, 0x04);
version.save(data + 0x08);
SV_FIELD(u16, (u16) locationCaught, 0x0c);
SV_FIELD(u8, levelMet, 0x0e);
SV_FIELD_E(u8, ballCaughtWith, 0x0f, ItemIndex);
SV_FIELD_E(u8, OTGender, 0x10, Gender);
SV_FIELD_CONV(u16, locationCaught, 0x0c, u8);
SV_FIELD_MAX(u8, levelMet, 0x0e, 100);
if (ballCaughtWith == NoItem || ballCaughtWith > PremierBall) ballCaughtWith = PokeBall;
SV_FIELD_E_MAX(u8, ballCaughtWith, 0x0f, ItemIndex, PremierBall);
SV_FIELD_E_MAX(u8, OTGender, 0x10, Gender, Female);
SV_FIELD(u16, SID, 0x14);
SV_FIELD(u16, TID, 0x16);
OTName->save(data + 0x18, 10);
name->save(data + 0x2e, 10);
name->save(data + 0x44, 10);
SV_FIELD(u32, experience, 0x5c);
SV_FIELD_MAX(u32, experience, 0x5c, getSpeciesExpTable(species)[100]);
if (partyData.level > 100) partyData.level = 100;
SV_FIELD(u8, partyData.level, 0x60);
partyData.status = (partyData.status != NoStatus && partyData.status < Poisoned && partyData.status > Asleep) ? NoStatus : partyData.status;
SV_FIELD_E(u16, partyData.status, 0x65, PokemonStatus);
LD_FIELD(s8, partyData.turnsOfSleepRemaining, 0x69);
LD_FIELD(s8, partyData.turnsOfBadPoison, 0x6b);
SV_FIELD_E(u16, heldItem, 0x88, ItemIndex);
SV_FIELD(u16, partyData.currentHP, 0x8a);
SV_FIELD_MAX(u16, partyData.currentHP, 0x8a, partyData.stats[0]);
SV_ARRAY(u16, partyData.stats, 6, 0x8c);
u16 EVs_tmp[6]; for (size_t i = 0; i < 6; ++i) EVs_tmp[i] = (u16)EVs[i];
@ -142,14 +154,20 @@ void Pokemon::save(void) {
SV_FIELD(u8, contestLuster, 0xbc);
SV_ARRAY_B(u8, specialRibbons, 12, 0xbd);
SV_FIELD_MAX(u8, unimplementedRibbons, 0xc9, 15);
SV_FIELD(u8, pkrsStatus, 0xca);
LD_ARRAY_B(u8, pkmFlags, 3, 0xcb);
SV_FIELD_MAX(u8, GCUnk, 0xce, 31);
SV_FIELD(u8, markings.save(), 0xcf);
SV_FIELD_MAX(s8, partyData.pkrsDaysRemaining, 0xd0, 4);
SV_FIELD(u16, unk2, 0xd2);
SV_FIELD(u16, unk1, 0xd4);
SV_FIELD(u16, shadowPkmID, 0xd8);
SV_FIELD_B(u8, obedient, 0xf8);
SV_FIELD(u8, encounterType, 0xfb);
for (size_t i = 0; i < 4; ++i)
moves[i].save(data + 0x78 + 4 * i);

View File

@ -4,17 +4,45 @@
namespace LibPkmGC{
void VersionInfo::load(u8 * data) {
LD_FIELD_E(u8, game, 0, GameIndex);
LD_FIELD_E(u8, currentRegion, 1, RegionIndex);
LD_FIELD_E(u8, originalRegion, 2, RegionIndex);
LD_FIELD_E(u8, language, 3, LanguageIndex);
LD_FIELD_E_MAX(u8, game, 0, GameIndex, Colosseum_XD);
LD_FIELD_E_MAX(u8, currentRegion, 1, RegionIndex, PAL);
LD_FIELD_E_MAX(u8, originalRegion, 2, RegionIndex, PAL);
LD_FIELD_E_MAX(u8, language, 3, LanguageIndex, Spanish);
}
void VersionInfo::load(u8 lg, u8 gm) {
const LanguageIndex L[] = { NoLanguage, Japanese, English, French, Italian, German, NoLanguage, Spanish };
GameIndex G[16] = { NoGame, Sapphire, Ruby, Emerald, FireRed, LeafGreen }; G[15] = Colosseum_XD;
game = G[(gm > 7) ? 0 : gm];
language = L[(lg > 15) ? 0 : lg];
switch (language){
case Japanese: originalRegion = NTSC_J; break;
case English: originalRegion = NTSC_U; break;
case NoLanguage: originalRegion = NoRegion; break;
default: originalRegion = PAL; break;
}
currentRegion = originalRegion;
}
void VersionInfo::save(u8& lg, u8& gm) {
const u8 L[] = { 0, 1, 2, 5, 3, 4, 7 };
u8 G[12] = { 0, 4, 5, 1, 2, 3 }; G[11] = 15;
game = (game > Colosseum_XD) ? NoGame : game;
language = (language > Spanish) ? NoLanguage : language;
gm = G[game];
lg = L[language];
}
void VersionInfo::save(u8 * data) {
SV_FIELD_E(u8, game, 0, GameIndex);
SV_FIELD_E(u8, currentRegion, 1, RegionIndex);
SV_FIELD_E(u8, originalRegion, 2, RegionIndex);
SV_FIELD_E(u8, language, 3, LanguageIndex);
SV_FIELD_E_MAX(u8, game, 0, GameIndex, Colosseum_XD);
SV_FIELD_E_MAX(u8, currentRegion, 1, RegionIndex, PAL);
SV_FIELD_E_MAX(u8, originalRegion, 2, RegionIndex, PAL);
SV_FIELD_E_MAX(u8, language, 3, LanguageIndex, Spanish);
}
bool VersionInfo::isIncomplete(void) const {
@ -22,19 +50,19 @@ bool VersionInfo::isIncomplete(void) const {
}
void PokemonMove::load(u8 * data) {
LD_FIELD_E(u16, moveIndex, 0, PokemonMoveIndex);
LD_FIELD_E_MAX(u16, move, 0, PokemonMoveIndex, PsychoBoost);
LD_FIELD(u8, currentPPs, 2);
LD_FIELD(u8, nbPPUpsUsed, 3);
LD_FIELD_MAX(u8, nbPPUpsUsed, 3, 3);
}
void PokemonMove::save(u8 * data) {
SV_FIELD_E(u16, moveIndex, 0, PokemonMoveIndex);
SV_FIELD_E_MAX(u16, move, 0, PokemonMoveIndex, PsychoBoost);
SV_FIELD(u8, currentPPs, 2);
SV_FIELD(u8, nbPPUpsUsed, 3);
SV_FIELD_MAX(u8, nbPPUpsUsed, 3, 3);
}
u8 PokemonMove::calculateMaxPP(void) const {
u32 baseMaxPP = (moveIndex > PsychoBoost) ? 0 : (u32)getBaseMoveMaxPPs(moveIndex);
u32 baseMaxPP = (move > PsychoBoost) ? 0 : (u32)getBaseMoveMaxPPs(move);
return (u8)(baseMaxPP*(100 + (u32)nbPPUpsUsed * 20) / 100);
}
@ -51,6 +79,40 @@ u8 PokemonMarkings::save(void) const {
return m;
}
u16 pokemonStatusToBitField(PokemonStatus status, s8 turnsOfBadPoison, s8 turnsOfSleepRemaining) {
static const u8 reverseStatuses[] = { 3, 7, 6, 4, 5 };
u16 st;
status = (status != NoStatus && status < Poisoned && status > Asleep) ? NoStatus : status;
if (status == Asleep) st = turnsOfSleepRemaining;
else if (status != NoStatus) st = reverseStatuses[status - 3];
return st;
}
PokemonStatus pokemonStatusFromBitField(u16 status, s8 * turnsOfBadPoison, s8 * turnsOfSleepRemaining)
{
static const PokemonStatus statuses[] = { Poisoned, Burnt, Frozen, Paralyzed, BadlyPoisoned };
PokemonStatus ret;
s8 tobp = 0, tosr = 0;
tosr = (s8)(status & 7);
tobp = (s8)((status >> 8) & 0xf);
if (tobp != 0) ret = Asleep;
status >>= 3;
for (size_t i = 0; i < 5 && ret == NoStatus; ++i) {
if ((status & 1) != 0) status = statuses[i];
status >>= 1;
}
if (ret != BadlyPoisoned) tobp = 0;
if (turnsOfBadPoison != NULL) *turnsOfBadPoison = tobp;
if (turnsOfSleepRemaining != NULL) *turnsOfSleepRemaining = tosr;
return ret;
}
u16 getPokedexIndexOf(PokemonSpeciesIndex speciesIndex) {
static const u16 remaining[] = {
290, 291, 292, 276, 277, 285, 286, 327, 278, 279, 283, 284, 320, 321, 300, 301, 352, 343, 344, 299, 324,
@ -5608,8 +5670,9 @@ PokemonSpeciesData getSpeciesData(PokemonSpeciesIndex index) {
return speciesData[(size_t)index];
}
const u32* getSpeciesExpTable(PokemonSpeciesIndex index) {
if (index > Munchlax) return NULL;
if (index > Munchlax) return getSpeciesExpTable(NoSpecies);
return expTables[(size_t)getSpeciesData(index).expGrowthType];
}

View File

@ -0,0 +1,111 @@
/*
* Copyright (C) TuxSH 2015
* This file is part of LibPkmGC.
*
* LibPkmGC is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* LibPkmGC is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with LibPkmGC. If not, see <http://www.gnu.org/licenses/>.
*/
#include <LibPkmGC/Colosseum/SaveEditing/Save.h>
#include <LibPkmGC/XD/SaveEditing/Save.h>
#include <LibPkmGC/GBA/Pokemon.h>
namespace LibPkmGC {
LIBPKMGC_GEN_CONVERTER_CTOR(DaycareData)
LIBPKMGC_GEN_CONVERTER_CTOR_W_GBA(Pokemon)
LIBPKMGC_GEN_CONVERTER_CTOR(StrategyMemoData)
LIBPKMGC_GEN_CONVERTER_CTOR(PokemonBox)
namespace GBA {
PokemonString::PokemonString(GC::PokemonString const& other) : Base::PokemonString() {
fromUTF8(other.toUTF8());
}
void Pokemon::swap(Base::Pokemon & other) {
if (LIBPKMGC_IS_GBA(Pokemon, &other)) swap((Pokemon&)other);
else {
GC::Pokemon& gco = static_cast<GC::Pokemon&>(other);
//bool inval = (GCFlags & 1) != 0; by default always true until the Pkm is traded to Colo/XD
bool inval = !checkChecksum(false);
u8 GCUnk = GCFlags >> 3;
Base::Pokemon::swap(other);
std::swap(GCUnk, gco.GCUnk);
std::swap(inval, gco.pkmFlags[LIBPKMGC_GC_INVALID_POKEMON_FLAG]);
bool tradedFromColoXD = true;
bool flgs[] = { _egg, inval, tradedFromColoXD };
if (GCUnk > 31) GCUnk = 31;
GCFlags = GCUnk << 3;
for (size_t i = 0; i < 3; ++i)
GCFlags |= flgs[i] << (2 - i);
}
}
Pokemon& Pokemon::operator=(Base::Pokemon const& other) {
if (LIBPKMGC_IS_GBA(Pokemon, &other)) return operator=((Pokemon const&)other);
else {
if (this == &other) return *this;
deleteFields();
_flags = 1;
initWithEmptyData(1);
Base::Pokemon::operator=(other);
GC::Pokemon const& gco = static_cast<GC::Pokemon const&>(other);
bool tradedFromColoXD = true;
bool flgs[] = { _egg, gco.pkmFlags[LIBPKMGC_GC_INVALID_POKEMON_FLAG], tradedFromColoXD };
GCFlags = gco.GCUnk << 3;
for (size_t i = 0; i < 3; ++i)
GCFlags |= flgs[i] << (2 - i);
return *this;
}
}
Pokemon::Pokemon(GC::Pokemon const& other) : Base::Pokemon(100) {
_flags = 1;
initWithEmptyData(1);
*this = other;
}
}
namespace GC {
PokemonString::PokemonString(GBA::PokemonString const& other) : Base::PokemonString(){
fromUTF8(other.toUTF8());
}
Pokemon& Pokemon::operator=(Base::Pokemon const& other) {
if (LIBPKMGC_IS_GBA(Pokemon, &other)) {
if (this == &other) return *this;
deleteFields();
initWithEmptyData();
Base::Pokemon::operator=(other);
GBA::Pokemon const& gbao = static_cast<GBA::Pokemon const&>(other);
GCUnk = gbao.GCFlags >> 3;
pkmFlags[LIBPKMGC_GC_INVALID_POKEMON_FLAG] = !(((GBA::Pokemon&)(other)).checkChecksum(false));
return *this;
}
else return operator=((Pokemon const&)other);
}
void Pokemon::swap(Base::Pokemon& other) {
if (LIBPKMGC_IS_GBA(Pokemon, &other))
static_cast<GBA::Pokemon&>(other).swap(*this);
else
swap((Pokemon&)other);
}
}
}

View File

@ -0,0 +1,492 @@
/*
* Copyright (C) TuxSH 2015
* This file is part of LibPkmGC.
*
* LibPkmGC is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* LibPkmGC is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with LibPkmGC. If not, see <http://www.gnu.org/licenses/>.
*/
#include <LibPkmGC/GBA/Detail/GBACharTables.h>
#include <boost/bimap/unordered_set_of.hpp>
#include <boost/bimap.hpp>
namespace LibPkmGC {
namespace Detail {
typedef boost::bimap< boost::bimaps::unordered_set_of<u8>, boost::bimaps::unordered_set_of<u32> > chartable_t;
typedef chartable_t::value_type charset_t;
inline chartable_t initEurCharTable(void) {
// Some characters have no Unicode equivalents
chartable_t tbl;
tbl.insert(charset_t(0x00, 0x0020));
tbl.insert(charset_t(0x01, 0x00C0));
tbl.insert(charset_t(0x02, 0x00C1));
tbl.insert(charset_t(0x03, 0x00C2));
tbl.insert(charset_t(0x04, 0x00C7));
tbl.insert(charset_t(0x05, 0x00C8));
tbl.insert(charset_t(0x06, 0x00C9));
tbl.insert(charset_t(0x07, 0x00CA));
tbl.insert(charset_t(0x08, 0x00CB));
tbl.insert(charset_t(0x09, 0x00CC));
tbl.insert(charset_t(0x0B, 0x00CE));
tbl.insert(charset_t(0x0C, 0x00CF));
tbl.insert(charset_t(0x0D, 0x00D2));
tbl.insert(charset_t(0x0E, 0x00D3));
tbl.insert(charset_t(0x0F, 0x00D4));
tbl.insert(charset_t(0x10, 0x0152));
tbl.insert(charset_t(0x11, 0x00D9));
tbl.insert(charset_t(0x12, 0x00DA));
tbl.insert(charset_t(0x13, 0x00DB));
tbl.insert(charset_t(0x14, 0x00D1));
tbl.insert(charset_t(0x15, 0x00DF));
tbl.insert(charset_t(0x16, 0x00E0));
tbl.insert(charset_t(0x17, 0x00E1));
tbl.insert(charset_t(0x19, 0x00E7));
tbl.insert(charset_t(0x1A, 0x00E8));
tbl.insert(charset_t(0x1B, 0x00E9));
tbl.insert(charset_t(0x1C, 0x00EA));
tbl.insert(charset_t(0x1D, 0x00EB));
tbl.insert(charset_t(0x1E, 0x00EC));
tbl.insert(charset_t(0x20, 0x00EE));
tbl.insert(charset_t(0x21, 0x00EF));
tbl.insert(charset_t(0x22, 0x00F2));
tbl.insert(charset_t(0x23, 0x00F3));
tbl.insert(charset_t(0x24, 0x00F4));
tbl.insert(charset_t(0x25, 0x0153));
tbl.insert(charset_t(0x26, 0x00F9));
tbl.insert(charset_t(0x27, 0x00FA));
tbl.insert(charset_t(0x28, 0x00FB));
tbl.insert(charset_t(0x29, 0x00F1));
tbl.insert(charset_t(0x2A, 0x00BA));
tbl.insert(charset_t(0x2B, 0x01AA));
tbl.insert(charset_t(0x2D, 0x0026));
tbl.insert(charset_t(0x2E, 0x002B));
tbl.insert(charset_t(0x35, 0x003D));
tbl.insert(charset_t(0x36, 0x003B));
tbl.insert(charset_t(0x50, 0x25AF));
tbl.insert(charset_t(0x51, 0x00BF));
tbl.insert(charset_t(0x52, 0x00A1));
tbl.insert(charset_t(0x5A, 0x00CD));
tbl.insert(charset_t(0x5B, 0x0025));
tbl.insert(charset_t(0x5C, 0x0028));
tbl.insert(charset_t(0x5D, 0x0029));
tbl.insert(charset_t(0x68, 0x00E2));
tbl.insert(charset_t(0x6F, 0x00ED));
tbl.insert(charset_t(0x79, 0x2191));
tbl.insert(charset_t(0x7A, 0x2193));
tbl.insert(charset_t(0x7B, 0x2190));
tbl.insert(charset_t(0x7C, 0x2192));
tbl.insert(charset_t(0x85, 0x003C));
tbl.insert(charset_t(0x86, 0x003E));
tbl.insert(charset_t(0xA1, 0x0030));
tbl.insert(charset_t(0xA2, 0x0031));
tbl.insert(charset_t(0xA3, 0x0032));
tbl.insert(charset_t(0xA4, 0x0033));
tbl.insert(charset_t(0xA5, 0x0034));
tbl.insert(charset_t(0xA6, 0x0035));
tbl.insert(charset_t(0xA7, 0x0036));
tbl.insert(charset_t(0xA8, 0x0037));
tbl.insert(charset_t(0xA9, 0x0038));
tbl.insert(charset_t(0xAA, 0x0039));
tbl.insert(charset_t(0xAB, 0x0021));
tbl.insert(charset_t(0xAC, 0x003F));
tbl.insert(charset_t(0xAD, 0x002E));
tbl.insert(charset_t(0xAE, 0x002D));
tbl.insert(charset_t(0xAF, 0x00B7));
tbl.insert(charset_t(0xB0, 0x2026));
tbl.insert(charset_t(0xB1, 0x00AB));
tbl.insert(charset_t(0xB2, 0x00BB));
tbl.insert(charset_t(0xB3, 0x2018));
tbl.insert(charset_t(0xB4, 0x2019));
tbl.insert(charset_t(0xB5, 0x2642));
tbl.insert(charset_t(0xB6, 0x2640));
tbl.insert(charset_t(0xB7, 0x0024));
tbl.insert(charset_t(0xB8, 0x002C));
tbl.insert(charset_t(0xB9, 0x00D7));
tbl.insert(charset_t(0xBA, 0x002F));
tbl.insert(charset_t(0xBB, 0x0041));
tbl.insert(charset_t(0xBC, 0x0042));
tbl.insert(charset_t(0xBD, 0x0043));
tbl.insert(charset_t(0xBE, 0x0044));
tbl.insert(charset_t(0xBF, 0x0045));
tbl.insert(charset_t(0xC0, 0x0046));
tbl.insert(charset_t(0xC1, 0x0047));
tbl.insert(charset_t(0xC2, 0x0048));
tbl.insert(charset_t(0xC3, 0x0049));
tbl.insert(charset_t(0xC4, 0x004A));
tbl.insert(charset_t(0xC5, 0x004B));
tbl.insert(charset_t(0xC6, 0x004C));
tbl.insert(charset_t(0xC7, 0x004D));
tbl.insert(charset_t(0xC8, 0x004E));
tbl.insert(charset_t(0xC9, 0x004F));
tbl.insert(charset_t(0xCA, 0x0050));
tbl.insert(charset_t(0xCB, 0x0051));
tbl.insert(charset_t(0xCC, 0x0052));
tbl.insert(charset_t(0xCD, 0x0053));
tbl.insert(charset_t(0xCE, 0x0054));
tbl.insert(charset_t(0xCF, 0x0055));
tbl.insert(charset_t(0xD0, 0x0056));
tbl.insert(charset_t(0xD1, 0x0057));
tbl.insert(charset_t(0xD2, 0x0058));
tbl.insert(charset_t(0xD3, 0x0059));
tbl.insert(charset_t(0xD4, 0x005A));
tbl.insert(charset_t(0xD5, 0x0061));
tbl.insert(charset_t(0xD6, 0x0062));
tbl.insert(charset_t(0xD7, 0x0063));
tbl.insert(charset_t(0xD8, 0x0064));
tbl.insert(charset_t(0xD9, 0x0065));
tbl.insert(charset_t(0xDA, 0x0066));
tbl.insert(charset_t(0xDB, 0x0067));
tbl.insert(charset_t(0xDC, 0x0068));
tbl.insert(charset_t(0xDD, 0x0069));
tbl.insert(charset_t(0xDE, 0x006A));
tbl.insert(charset_t(0xDF, 0x006B));
tbl.insert(charset_t(0xE0, 0x006C));
tbl.insert(charset_t(0xE1, 0x006D));
tbl.insert(charset_t(0xE2, 0x006E));
tbl.insert(charset_t(0xE3, 0x006F));
tbl.insert(charset_t(0xE4, 0x0070));
tbl.insert(charset_t(0xE5, 0x0071));
tbl.insert(charset_t(0xE6, 0x0072));
tbl.insert(charset_t(0xE7, 0x0073));
tbl.insert(charset_t(0xE8, 0x0074));
tbl.insert(charset_t(0xE9, 0x0075));
tbl.insert(charset_t(0xEA, 0x0076));
tbl.insert(charset_t(0xEB, 0x0077));
tbl.insert(charset_t(0xEC, 0x0078));
tbl.insert(charset_t(0xED, 0x0079));
tbl.insert(charset_t(0xEE, 0x007A));
tbl.insert(charset_t(0xEF, 0x2023));
tbl.insert(charset_t(0xF0, 0x003A));
tbl.insert(charset_t(0xF1, 0x00C4));
tbl.insert(charset_t(0xF2, 0x00D6));
tbl.insert(charset_t(0xF3, 0x00DC));
tbl.insert(charset_t(0xF4, 0x00E4));
tbl.insert(charset_t(0xF5, 0x00F6));
tbl.insert(charset_t(0xF6, 0x00FC));
//F7 ... FF : commands
return tbl;
}
inline chartable_t initJapCharTable(void) {
chartable_t tbl;
tbl.insert(charset_t(0x00, 0x3000));
//----------------------------------------------------------
// Medium-sized hirgananas
//----------------------------------------------------------
tbl.insert(charset_t(0x01, 0x3042));
tbl.insert(charset_t(0x02, 0x3044));
tbl.insert(charset_t(0x03, 0x3046));
tbl.insert(charset_t(0x04, 0x3048));
tbl.insert(charset_t(0x05, 0x304A));
tbl.insert(charset_t(0x06, 0x304B));
tbl.insert(charset_t(0x07, 0x304D));
tbl.insert(charset_t(0x08, 0x304F));
tbl.insert(charset_t(0x09, 0x3051));
tbl.insert(charset_t(0x0A, 0x3053));
tbl.insert(charset_t(0x0B, 0x3055));
tbl.insert(charset_t(0x0C, 0x3057));
tbl.insert(charset_t(0x0D, 0x3059));
tbl.insert(charset_t(0x0E, 0x305B));
tbl.insert(charset_t(0x0F, 0x305D));
tbl.insert(charset_t(0x10, 0x305F));
tbl.insert(charset_t(0x11, 0x3061));
tbl.insert(charset_t(0x12, 0x3064));
tbl.insert(charset_t(0x13, 0x3066));
tbl.insert(charset_t(0x14, 0x3068));
tbl.insert(charset_t(0x15, 0x306A));
tbl.insert(charset_t(0x16, 0x306B));
tbl.insert(charset_t(0x17, 0x306C));
tbl.insert(charset_t(0x18, 0x306D));
tbl.insert(charset_t(0x19, 0x306E));
tbl.insert(charset_t(0x1A, 0x307F));
tbl.insert(charset_t(0x1B, 0x3072));
tbl.insert(charset_t(0x1C, 0x3075));
tbl.insert(charset_t(0x1D, 0x3078));
tbl.insert(charset_t(0x1E, 0x307B));
tbl.insert(charset_t(0x1F, 0x307E));
tbl.insert(charset_t(0x20, 0x307F));
tbl.insert(charset_t(0x21, 0x3080));
tbl.insert(charset_t(0x22, 0x3081));
tbl.insert(charset_t(0x23, 0x3082));
tbl.insert(charset_t(0x24, 0x3084));
tbl.insert(charset_t(0x25, 0x3086));
tbl.insert(charset_t(0x26, 0x3088));
tbl.insert(charset_t(0x27, 0x3089));
tbl.insert(charset_t(0x28, 0x308A));
tbl.insert(charset_t(0x29, 0x308B));
tbl.insert(charset_t(0x2A, 0x308C));
tbl.insert(charset_t(0x2B, 0x308D));
tbl.insert(charset_t(0x2C, 0x308F));
tbl.insert(charset_t(0x2D, 0x3092));
tbl.insert(charset_t(0x2E, 0x3093));
//--------------------------------------------------------
// Small-sized hiraganas
//--------------------------------------------------------
tbl.insert(charset_t(0x2F, 0x3041));
tbl.insert(charset_t(0x30, 0x3043));
tbl.insert(charset_t(0x31, 0x3045));
tbl.insert(charset_t(0x32, 0x3047));
tbl.insert(charset_t(0x33, 0x3049));
tbl.insert(charset_t(0x34, 0x3083));
tbl.insert(charset_t(0x35, 0x3085));
tbl.insert(charset_t(0x36, 0x3087));
//------------------------------------------------------------
// Medium-sized hiraganas with dakuten
//------------------------------------------------------------
tbl.insert(charset_t(0x37, 0x304C));
tbl.insert(charset_t(0x38, 0x304E));
tbl.insert(charset_t(0x39, 0x3050));
tbl.insert(charset_t(0x3A, 0x3052));
tbl.insert(charset_t(0x3B, 0x3054));
tbl.insert(charset_t(0x3C, 0x3056));
tbl.insert(charset_t(0x3D, 0x3058));
tbl.insert(charset_t(0x3E, 0x305A));
tbl.insert(charset_t(0x3F, 0x305C));
tbl.insert(charset_t(0x40, 0x305E));
tbl.insert(charset_t(0x41, 0x3060));
tbl.insert(charset_t(0x42, 0x3062));
tbl.insert(charset_t(0x43, 0x3065));
tbl.insert(charset_t(0x44, 0x3067));
tbl.insert(charset_t(0x45, 0x3069));
tbl.insert(charset_t(0x46, 0x3070));
tbl.insert(charset_t(0x47, 0x3073));
tbl.insert(charset_t(0x48, 0x3076));
tbl.insert(charset_t(0x49, 0x3079));
tbl.insert(charset_t(0x4A, 0x307C));
//----------------------------------------------------------
// Medium-sized hiraganas with handakuten
//----------------------------------------------------------
tbl.insert(charset_t(0x4B, 0x3071));
tbl.insert(charset_t(0x4C, 0x3074));
tbl.insert(charset_t(0x4D, 0x3077));
tbl.insert(charset_t(0x4E, 0x307A));
tbl.insert(charset_t(0x4F, 0x307D));
//--------------------------------------------------------
// Small-sized hiragana
//--------------------------------------------------------
tbl.insert(charset_t(0x50, 0x3063));
//----------------------------------------------------------
// Medium-sized katakanas
//----------------------------------------------------------
tbl.insert(charset_t(0x51, 0x30A2));
tbl.insert(charset_t(0x52, 0x30A4));
tbl.insert(charset_t(0x53, 0x30A6));
tbl.insert(charset_t(0x54, 0x30A8));
tbl.insert(charset_t(0x55, 0x30AA));
tbl.insert(charset_t(0x56, 0x30AB));
tbl.insert(charset_t(0x57, 0x30AD));
tbl.insert(charset_t(0x58, 0x30AF));
tbl.insert(charset_t(0x59, 0x30B1));
tbl.insert(charset_t(0x5A, 0x30B3));
tbl.insert(charset_t(0x5B, 0x30B5));
tbl.insert(charset_t(0x5C, 0x30B7));
tbl.insert(charset_t(0x5D, 0x30B9));
tbl.insert(charset_t(0x5E, 0x30BB));
tbl.insert(charset_t(0x5F, 0x30BD));
tbl.insert(charset_t(0x60, 0x30BF));
tbl.insert(charset_t(0x61, 0x30C1));
tbl.insert(charset_t(0x62, 0x30C4));
tbl.insert(charset_t(0x63, 0x30C6));
tbl.insert(charset_t(0x64, 0x30C8));
tbl.insert(charset_t(0x65, 0x30CA));
tbl.insert(charset_t(0x66, 0x30CB));
tbl.insert(charset_t(0x67, 0x30CC));
tbl.insert(charset_t(0x68, 0x30CD));
tbl.insert(charset_t(0x69, 0x30CE));
tbl.insert(charset_t(0x6A, 0x30CF));
tbl.insert(charset_t(0x6B, 0x30D2));
tbl.insert(charset_t(0x6C, 0x30D5));
tbl.insert(charset_t(0x6D, 0x30D8));
tbl.insert(charset_t(0x6E, 0x30DB));
tbl.insert(charset_t(0x6F, 0x30DE));
tbl.insert(charset_t(0x70, 0x30DF));
tbl.insert(charset_t(0x71, 0x30E0));
tbl.insert(charset_t(0x72, 0x30E1));
tbl.insert(charset_t(0x73, 0x30E2));
tbl.insert(charset_t(0x74, 0x30E4));
tbl.insert(charset_t(0x75, 0x30E6));
tbl.insert(charset_t(0x76, 0x30E8));
tbl.insert(charset_t(0x77, 0x30E9));
tbl.insert(charset_t(0x78, 0x30EA));
tbl.insert(charset_t(0x79, 0x30EB));
tbl.insert(charset_t(0x7A, 0x30EC));
tbl.insert(charset_t(0x7B, 0x30ED));
tbl.insert(charset_t(0x7C, 0x30EF));
tbl.insert(charset_t(0x7D, 0x30F2));
tbl.insert(charset_t(0x7E, 0x30F3));
//----------------------------------------------------------
// Small-sized katakanas
//----------------------------------------------------------
tbl.insert(charset_t(0x7F, 0x30A1));
tbl.insert(charset_t(0x80, 0x30A3));
tbl.insert(charset_t(0x81, 0x30A5));
tbl.insert(charset_t(0x82, 0x30A7));
tbl.insert(charset_t(0x83, 0x30A9));
tbl.insert(charset_t(0x84, 0x30E3));
tbl.insert(charset_t(0x85, 0x30E5));
tbl.insert(charset_t(0x86, 0x30E7));
//------------------------------------------------------------
// Medium-sized katakanas with dakuten
//------------------------------------------------------------
tbl.insert(charset_t(0x87, 0x30AC));
tbl.insert(charset_t(0x88, 0x30AE));
tbl.insert(charset_t(0x89, 0x30B0));
tbl.insert(charset_t(0x8A, 0x30B2));
tbl.insert(charset_t(0x8B, 0x30B4));
tbl.insert(charset_t(0x8C, 0x30B6));
tbl.insert(charset_t(0x8D, 0x30B8));
tbl.insert(charset_t(0x8E, 0x30BA));
tbl.insert(charset_t(0x8F, 0x30BC));
tbl.insert(charset_t(0x90, 0x30BE));
tbl.insert(charset_t(0x91, 0x30C0));
tbl.insert(charset_t(0x92, 0x30C2));
tbl.insert(charset_t(0x93, 0x30C5));
tbl.insert(charset_t(0x94, 0x30C7));
tbl.insert(charset_t(0x95, 0x30C9));
tbl.insert(charset_t(0x96, 0x30D0));
tbl.insert(charset_t(0x97, 0x30D3));
tbl.insert(charset_t(0x98, 0x30D6));
tbl.insert(charset_t(0x99, 0x30D9));
tbl.insert(charset_t(0x9A, 0x30DC));
//------------------------------------------------------------
// Medium-sized katakanas with handakuten
//------------------------------------------------------------
tbl.insert(charset_t(0x9B, 0x30D1));
tbl.insert(charset_t(0x9C, 0x30D4));
tbl.insert(charset_t(0x9D, 0x30D7));
tbl.insert(charset_t(0x9E, 0x30DA));
tbl.insert(charset_t(0x9F, 0x30DD));
//------------------------------------------------------------
// Small-sized katakana
//------------------------------------------------------------
tbl.insert(charset_t(0xA0, 0x30C3));
//--------------------------------------------------------------------------------------------------
// Full-width Roman characters (or equivalent), ideographic characters,
// and other common symbols
//--------------------------------------------------------------------------------------------------
tbl.insert(charset_t(0xA1, 0xFF10));
tbl.insert(charset_t(0xA2, 0xFF11));
tbl.insert(charset_t(0xA3, 0xFF12));
tbl.insert(charset_t(0xA4, 0xFF13));
tbl.insert(charset_t(0xA5, 0xFF14));
tbl.insert(charset_t(0xA6, 0xFF15));
tbl.insert(charset_t(0xA7, 0xFF16));
tbl.insert(charset_t(0xA8, 0xFF17));
tbl.insert(charset_t(0xA9, 0xFF18));
tbl.insert(charset_t(0xAA, 0xFF19));
tbl.insert(charset_t(0xAB, 0xFF01));
tbl.insert(charset_t(0xAC, 0xFF1F));
tbl.insert(charset_t(0xAD, 0x3002));
tbl.insert(charset_t(0xAE, 0xFF0D));
tbl.insert(charset_t(0xAF, 0x30FB));
tbl.insert(charset_t(0xB0, 0x2025));
tbl.insert(charset_t(0xB1, 0x300E));
tbl.insert(charset_t(0xB2, 0x300F));
tbl.insert(charset_t(0xB3, 0x300C));
tbl.insert(charset_t(0xB4, 0x300D));
tbl.insert(charset_t(0xB5, 0x2642));
tbl.insert(charset_t(0xB6, 0x2640));
tbl.insert(charset_t(0xB7, 0x5186));
tbl.insert(charset_t(0xB8, 0xFF0E));
tbl.insert(charset_t(0xB9, 0x00D7));
tbl.insert(charset_t(0xBA, 0xFF0F));
tbl.insert(charset_t(0xBB, 0xFF21));
tbl.insert(charset_t(0xBC, 0xFF22));
tbl.insert(charset_t(0xBD, 0xFF23));
tbl.insert(charset_t(0xBE, 0xFF24));
tbl.insert(charset_t(0xBF, 0xFF25));
tbl.insert(charset_t(0xC0, 0xFF26));
tbl.insert(charset_t(0xC1, 0xFF27));
tbl.insert(charset_t(0xC2, 0xFF28));
tbl.insert(charset_t(0xC3, 0xFF29));
tbl.insert(charset_t(0xC4, 0xFF2A));
tbl.insert(charset_t(0xC5, 0xFF2B));
tbl.insert(charset_t(0xC6, 0xFF2C));
tbl.insert(charset_t(0xC7, 0xFF2D));
tbl.insert(charset_t(0xC8, 0xFF2E));
tbl.insert(charset_t(0xC9, 0xFF2F));
tbl.insert(charset_t(0xCA, 0xFF30));
tbl.insert(charset_t(0xCB, 0xFF31));
tbl.insert(charset_t(0xCC, 0xFF32));
tbl.insert(charset_t(0xCD, 0xFF33));
tbl.insert(charset_t(0xCE, 0xFF34));
tbl.insert(charset_t(0xCF, 0xFF35));
tbl.insert(charset_t(0xD0, 0xFF36));
tbl.insert(charset_t(0xD1, 0xFF37));
tbl.insert(charset_t(0xD2, 0xFF38));
tbl.insert(charset_t(0xD3, 0xFF39));
tbl.insert(charset_t(0xD4, 0xFF3A));
tbl.insert(charset_t(0xD5, 0xFF41));
tbl.insert(charset_t(0xD6, 0xFF42));
tbl.insert(charset_t(0xD7, 0xFF43));
tbl.insert(charset_t(0xD8, 0xFF44));
tbl.insert(charset_t(0xD9, 0xFF45));
tbl.insert(charset_t(0xDA, 0xFF46));
tbl.insert(charset_t(0xDB, 0xFF47));
tbl.insert(charset_t(0xDC, 0xFF48));
tbl.insert(charset_t(0xDD, 0xFF49));
tbl.insert(charset_t(0xDE, 0xFF4A));
tbl.insert(charset_t(0xDF, 0xFF4B));
tbl.insert(charset_t(0xE0, 0xFF4C));
tbl.insert(charset_t(0xE1, 0xFF4D));
tbl.insert(charset_t(0xE2, 0xFF4E));
tbl.insert(charset_t(0xE3, 0xFF4F));
tbl.insert(charset_t(0xE4, 0xFF50));
tbl.insert(charset_t(0xE5, 0xFF51));
tbl.insert(charset_t(0xE6, 0xFF52));
tbl.insert(charset_t(0xE7, 0xFF53));
tbl.insert(charset_t(0xE8, 0xFF54));
tbl.insert(charset_t(0xE9, 0xFF55));
tbl.insert(charset_t(0xEA, 0xFF56));
tbl.insert(charset_t(0xEB, 0xFF57));
tbl.insert(charset_t(0xEC, 0xFF58));
tbl.insert(charset_t(0xED, 0xFF59));
tbl.insert(charset_t(0xEE, 0xFF5A));
//--------------------------------------------------------------------------------------------------
//Symbols and accentued (fullwidth in-game) roman characters
//--------------------------------------------------------------------------------------------------
tbl.insert(charset_t(0xEF, 0x25BA));
tbl.insert(charset_t(0xF0, 0xFF1A));
tbl.insert(charset_t(0xF1, 0x00C4));
tbl.insert(charset_t(0xF2, 0x00D6));
tbl.insert(charset_t(0xF3, 0x00DC));
tbl.insert(charset_t(0xF4, 0x00E4));
tbl.insert(charset_t(0xF5, 0x00F6));
tbl.insert(charset_t(0xF6, 0x00FC));
return tbl;
}
static const chartable_t eurCharTable = initEurCharTable(), japCharTable = initJapCharTable();
u32 GBAToUCS4(u8 val, bool jp, u32 deflt) {
if (jp && deflt == '?') deflt = 0xff1f; // (fullwidth)
chartable_t const& tbl = (jp) ? japCharTable : eurCharTable;
chartable_t::left_const_iterator it = tbl.left.find(val);
return (it == tbl.left.end()) ? deflt : it->get_right();
}
u8 UCS4ToGBA(u32 val, bool jp, u8 deflt) {
chartable_t const& tbl = (jp) ? japCharTable : eurCharTable;
chartable_t::right_const_iterator it = tbl.right.find(val);
return (it == tbl.right.end()) ? deflt : it->get_left();
}
}
}

View File

@ -0,0 +1,393 @@
/*
* Copyright (C) TuxSH 2015
* This file is part of LibPkmGC.
*
* LibPkmGC is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* LibPkmGC is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with LibPkmGC. If not, see <http://www.gnu.org/licenses/>.
*/
#define TARGET_ENDIANNESS_LE
#include <LibPkmGC/GBA/Pokemon.h>
namespace LibPkmGC {
namespace GBA {
Pokemon::Pokemon(const u8* inData, u32 flags) : Base::Pokemon(100, inData) {
_flags = flags;
load(flags);
}
Pokemon* Pokemon::load80(const u8 * inData, u32 flags){
u8 dta[100] = { 0 };
std::copy(inData, inData + 80, dta);
Pokemon* ret = new Pokemon(dta, flags);
return ret;
}
Pokemon::Pokemon(void) : Base::Pokemon(100) {
_flags = 1; // decrypted, unshuffled
initWithEmptyData(1);
}
Pokemon::~Pokemon(void) {
}
Pokemon::Pokemon(Pokemon const& other) : Base::Pokemon(other) {
CP(checksum);
CP(GCFlags);
CP(_flags);
CP(_egg);
CP(_secondAbility);
CL(OTName);
CL(name);
setEggFlag(other.isEgg());
setSecondAbilityFlag(other.hasSecondAbility());
}
void Pokemon::swap(Pokemon& other) {
Base::Pokemon::swap(other);
SW(checksum);
SW(GCFlags);
SW(_flags);
SW(_egg);
SW(_secondAbility);
}
Pokemon* Pokemon::clone(void) const {
return new Pokemon(*this);
}
Pokemon* Pokemon::create(void) const {
return new Pokemon;
}
Pokemon& Pokemon::operator=(Pokemon const& other) {
Base::Pokemon::operator=(other);
if (this != &other) {
CP(checksum);
CP(GCFlags);
CP(_flags);
CP(_egg);
CP(_secondAbility);
}
return *this;
}
bool Pokemon::hasSecondAbility(void) const {
return _secondAbility;
}
void Pokemon::setSecondAbilityFlag(bool status) {
_secondAbility = status;
}
bool Pokemon::isEgg(void) const {
return _egg;
}
void Pokemon::setEggFlag(bool status) {
_egg = status;
}
void Pokemon::reload(const u8 * data, u32 inFlags) {
if (data == NULL) return;
}
static const size_t shuffleTable[24][4] = {
{ 0,1,2,3 },{ 0,1,3,2 },{ 0,2,1,3 },{ 0,2,3,1 },
{ 0,3,1,2 },{ 0,3,2,1 },{ 1,0,2,3 },{ 1,0,3,2 },
{ 1,2,0,3 },{ 1,2,3,0 },{ 1,3,0,2 },{ 1,3,2,0 },
{ 2,0,1,3 },{ 2,0,3,1 },{ 2,1,0,3 },{ 2,1,3,0 },
{ 2,3,0,1 },{ 2,3,1,0 },{ 3,0,1,2 },{ 3,0,2,1 },
{ 3,1,0,2 },{ 3,1,2,0 },{ 3,2,0,1 },{ 3,2,1,0 }
};
inline void crypt_impl(u32 key, u8* data, u8* outData) {
u32 D;
for (size_t i = 0; i < 48; i += 4) {
std::copy(data + 32 + i, data + 36 + i, (u8*)&D);
D ^= key;
std::copy((u8*)&D, 4 + (u8*)&D, outData + 32 + i);
}
}
void Pokemon::decryptOrEncrypt(u8 * outData) {
u32 key = PID ^ (((u32)SID << 16) | TID);
u8 buf[48];
const size_t *P = shuffleTable[PID % 24];
if (outData == data) { // when unshuffling
for (size_t i = 0; i < 4; ++i)
std::copy(data + 32 + 12*i, data + 32 + 12*i + 12, buf + 12 * P[i]);
std::copy(buf, buf + 48, outData + 32);
}
else { // shuffling
for (size_t i = 0; i < 4; ++i)
std::copy(data + 32 + 12 * P[i], data + 32 + 12 * P[i] + 12, buf + 12 * i);
std::copy(buf, buf + 48, outData + 32);
}
crypt_impl(key, outData, outData);
}
void Pokemon::load(u32 flags) {
if (flags == 0) {
u8 buf[48];
std::copy(data + 32, data + 80, buf);
load(1); // assume it is unencrypted by default
if (!checkChecksum(false)) {
deleteFields();
load(2);
if (!checkChecksum(false)) {
std::copy(buf, buf + 48, data + 32);
load(1);
}
}
}
else {
loadData(flags);
loadFields();
}
}
void Pokemon::loadData(u32 flags) {
LD_FIELD(u32, PID, 0);
LD_FIELD(u16, TID, 4);
LD_FIELD(u16, SID, 6);
if(flags == 2)
decryptOrEncrypt(data);
_flags = 1;
}
static const size_t statsOrder[] = { 0, 1, 2, 5, 3, 4 };
void Pokemon::loadFields(void) {
u8 lg = data[18];
markings.load(data[27]);
LD_FIELD(u8, GCFlags, 19);
LD_FIELD(u16, checksum, 28);
LD_FIELD(u16, unk1, 30);
LD_FIELD_E(u16, species, 32, PokemonSpeciesIndex);
LD_FIELD_E(u16, heldItem, 34, ItemIndex);
LD_FIELD_MAX(u32, experience, 36, getSpeciesExpTable(species)[100]);
LD_FIELD(u8, happiness, 41);
LD_FIELD(u16, unk2, 42);
for (size_t i = 0; i < 6; ++i) EVs[i] = data[56 + statsOrder[i]];
LD_ARRAY(u8, contestStats, 5, 62);
LD_FIELD(u8, contestLuster, 67);
LD_FIELD(u8, pkrsStatus, 68);
LD_FIELD(u8, locationCaught, 69);
u16 origins;
LD_FIELD(u16, origins, 70);
encounterType = (u8)(origins & 0x7f);
origins >>= 7;
u8 gm = (u8)(origins & 0xf);
origins >>= 4;
u16 pkb = origins & 0xf;
ballCaughtWith = (pkb > 12 || pkb == 0) ? PokeBall : (ItemIndex) pkb;
origins >>= 4;
OTGender = (Gender)(origins & 1);
u32 iea;
LD_FIELD(u32, iea, 72);
for (size_t i = 0; i < 6; ++i) {
IVs[statsOrder[i]] = (u8)(iea & 0x1f);
iea >>= 5;
}
_egg = (iea & 1) != 0;
_secondAbility = (iea & 2) != 0;
u32 ribbons;
LD_FIELD(u32, ribbons, 76);
for (size_t i = 0; i < 5; ++i) {
contestAchievements[i] = (ContestAchievementLevel)(ribbons & 7);
if (contestAchievements[i] > MasterContestWon) contestAchievements[i] = NoContestWon;
ribbons >>= 3;
}
for (size_t i = 0; i < 12; ++i) {
specialRibbons[i] = (ribbons & 1) != 0;
ribbons >>= 1;
}
unimplementedRibbons = (u8)(ribbons & 15);
ribbons >>= 4;
obedient = ribbons != 0;
u8 PPBonuses = data[40];
PokemonMoveIndex mvs[4];
LD_ARRAY_E_MAX(u16, mvs, 4, 44, PokemonMoveIndex, PsychoBoost);
for (size_t i = 0; i < 4; ++i) {
moves[i].move = mvs[i];
moves[i].currentPPs = data[52 + i];
moves[i].nbPPUpsUsed = (PPBonuses & 3);
PPBonuses >>= 2;
}
u32 st;
LD_FIELD(u32, st, 80);
pokemonStatusFromBitField((u16)st, &(partyData.turnsOfBadPoison), &(partyData.turnsOfSleepRemaining));
LD_FIELD_MAX(u8, partyData.level, 84, 100);
LD_FIELD_MAX(s8, partyData.pkrsDaysRemaining, 85, 4);
LD_FIELD(u16, partyData.currentHP, 86);
u16 sta[6];
LD_ARRAY(u16, sta, 6, 88);
bool regen = true;
for (size_t i = 0; i < 6; ++i) {
partyData.stats[statsOrder[i]] = sta[i];
if (sta[i] != 0) regen = false;
}
if (regen) resetPartyData();
if (partyData.currentHP > partyData.stats[0]) partyData.currentHP = partyData.stats[0];
version.load(lg, gm);
name = new PokemonString(data + 8, 10, version.language == Japanese);
OTName = new PokemonString(data + 20, 7, version.language == Japanese);
normalizePkrs();
normalizeStatus();
}
bool Pokemon::checkChecksum(bool fix) {
u16 newChecksum = 0;
for (size_t i = 0; i < 48; i += 2)
newChecksum += toInteger<u16, u8*>(data + 32 + i);
bool ret = newChecksum == checksum;
if (fix) checksum = newChecksum;
return ret;
}
bool Pokemon::isEmptyOrInvalid(void) const {
return Base::Pokemon::isEmptyOrInvalid() || !const_cast<Pokemon*>(this)->checkChecksum(false);
}
void Pokemon::save(void) {
u8 lg, gm;
data[27] = markings.save();
version.save(lg, gm);
normalizePkrs();
name->save(data + 8, 10);
OTName->save(data + 20, 7);
data[18] = lg;
SV_FIELD(u32, PID, 0);
SV_FIELD(u16, TID, 4);
SV_FIELD(u16, SID, 6);
SV_FIELD(u8, GCFlags, 19);
SV_FIELD(u16, unk1, 30);
SV_FIELD_E(u16, species, 32, PokemonSpeciesIndex);
SV_FIELD_E(u16, heldItem, 34, ItemIndex);
SV_FIELD_MAX(u32, experience, 36, getSpeciesExpTable(species)[100]);
SV_FIELD(u8, happiness, 41);
SV_FIELD(u16, unk2, 42);
for (size_t i = 0; i < 6; ++i) data[56 + statsOrder[i]] = EVs[i];
SV_ARRAY(u8, contestStats, 5, 62);
SV_FIELD(u8, contestLuster, 67);
SV_FIELD(u8, pkrsStatus, 68);
SV_FIELD(u8, locationCaught, 69);
u16 origins = 0;
if (encounterType > 0x7f) encounterType = 0x7f;
origins |= encounterType;
origins |= (u16) gm << 7;
if (ballCaughtWith == 0 || ballCaughtWith > PremierBall) ballCaughtWith = PokeBall;
origins |= (u16)ballCaughtWith << 11;
if ((u32)OTGender > (u32)Female) OTGender = Male;
origins |= (u16)OTGender << 15;
SV_FIELD(u16, origins, 70);
u32 iea = 0;
for (size_t i = 0; i < 6; ++i) {
if (IVs[statsOrder[i]] > 31) IVs[statsOrder[i]] = 31;
iea |= IVs[statsOrder[i]] << (5 * i);
}
iea |= ((_egg) ? 1 : 0) << 30;
iea |= ((_secondAbility) ? 1 : 0) << 31;
SV_FIELD(u32, iea, 72);
u32 ribbons = 0;
for (size_t i = 0; i < 5; ++i) {
if ((u32)contestAchievements[i] >(u32) MasterContestWon) contestAchievements[i] = NoContestWon;
ribbons |= (u32)contestAchievements[i] << (3 * i);
}
for (size_t i = 0; i < 12; ++i)
ribbons |= ((specialRibbons[i]) ? 1 : 0) << (15 + i);
unimplementedRibbons = (unimplementedRibbons > 15) ? 15 : unimplementedRibbons;
ribbons |= (u32)unimplementedRibbons << 27;
ribbons |= ((obedient) ? 1 : 0) << 31;
SV_FIELD(u32, ribbons, 76);
u8 PPBonuses = 0;
for (size_t i = 0; i < 4; ++i) {
if ((u32)moves[i].move >(u32)PsychoBoost) moves[i].move = NoMove;
SV_FIELD(u16, (u16)moves[i].move, 44 + 2 * i);
SV_FIELD(u8, moves[i].currentPPs, 52 + i);
if (moves[i].nbPPUpsUsed > 3) moves[i].nbPPUpsUsed = 3;
PPBonuses |= moves[i].nbPPUpsUsed << (2 * i);
}
SV_FIELD(u8, PPBonuses, 40);
normalizeStatus();
u32 st = pokemonStatusToBitField(partyData.status, partyData.turnsOfBadPoison, partyData.turnsOfSleepRemaining);
SV_FIELD(u32, st, 80);
SV_FIELD_MAX(u8, partyData.level, 84, 100);
SV_FIELD_MAX(s8, partyData.pkrsDaysRemaining, 85, 4);
if (partyData.pkrsDaysRemaining < -1) partyData.pkrsDaysRemaining = -1;
SV_FIELD_MAX(u16, partyData.currentHP, 86, partyData.stats[0]);
u16 sta[6];
for (size_t i = 0; i < 6; ++i) sta[i] = partyData.stats[statsOrder[i]];
SV_ARRAY(u16, sta, 6, 88);
checkChecksum(true);
SV_FIELD(u32, checksum, 28);
}
void Pokemon::saveEncrypted(u8 * outData) {
save();
std::copy(data, data + 32, outData);
std::copy(data + 80, data + 100, outData + 80);
if (outData == NULL || outData == data) return;
decryptOrEncrypt(outData);
}
}
}
#undef TARGET_ENDIANNESS_LE

View File

@ -0,0 +1,182 @@
/*
* Copyright (C) TuxSH 2015
* This file is part of LibPkmGC.
*
* LibPkmGC is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* LibPkmGC is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with LibPkmGC. If not, see <http://www.gnu.org/licenses/>.
*/
#include <LibPkmGC/GBA/PokemonString.h>
#include <LibPkmGC/GBA/Detail/GBACharTables.h>
#include <algorithm>
#include <cstring>
using namespace LibPkmGC::Detail;
namespace LibPkmGC {
namespace GBA {
PokemonString::PokemonString(const char* str, bool jap) : Base::PokemonString() {
_japanese = jap;
fromUTF8(str);
}
PokemonString::PokemonString(u8 * data, size_t nb, bool jap) : Base::PokemonString() {
_japanese = jap;
load(data, nb);
}
PokemonString::PokemonString(PokemonString const& other) : Base::PokemonString(other) {
}
PokemonString::~PokemonString(void) {
}
bool PokemonString::isGBA(void) const {
return true;
}
PokemonString * PokemonString::clone(void) const {
return new PokemonString(*this);
}
PokemonString * PokemonString::create(void) const {
return new PokemonString;
}
PokemonString & PokemonString::operator=(PokemonString const & other) {
return (PokemonString&)Base::PokemonString::operator=(other);
}
PokemonString& PokemonString::operator=(Base::PokemonString const& other) {
if (!other.isGBA()) {
_japanese = other.usesJapaneseCharset();
fromUTF8(other.toUTF8());
return *this;
}
else return operator=((PokemonString const&)other);
}
}
}
namespace LibPkmGC {
namespace Detail {
int pkmgba_mbtowc(conv_t conv, ucs4_t *pwc, const unsigned char* s, int n, bool jap) {
if (n < 1) return RET_TOOFEW(0);
if (*s == 0xff) *pwc = 0;
else if (*s >= 0xf7 && *s <= 0xfe) return RET_ILSEQ; // commands
else *pwc = GBAToUCS4(*s, jap);
return 1;
}
int pkmgba_wctomb(conv_t conv, unsigned char *r, ucs4_t wc, int n, bool jap) {
if (n < 1) return RET_TOOSMALL;
if (wc == 0) *r = 0xff;
else *r = UCS4ToGBA(wc, jap);
return 1;
}
}
}
namespace LibPkmGC {
namespace GBA {
void PokemonString::fromUTF8(const char * str) {
str = (str == NULL) ? "" : str;
strSz = std::strlen(str) + 1;
resizeStr();
dataSz = strSz;
resizeData();
dataSz = 0;
int s = 0;
size_t offset = 0;
while (offset < strSz - 1) {
u32 c;
s = utf8_mbtowc(NULL, &c, (const unsigned char*)str + offset, strSz - 1);
if (s < 0) break;
offset += s;
if (c == 0) break;
s = pkmgba_wctomb(NULL, _data + dataSz, c, 2, _japanese);
if (s < 0) break;
dataSz += s;
}
_data[dataSz++] = 0xff;
hasChanged = true;
}
const char * PokemonString::toUTF8(void) const {
if (!hasChanged) return _str;
strSz = 3 * dataSz + 3;
resizeStr();
strSz = 0;
int s = 0;
size_t offset = 0;
while (offset < dataSz) {
u32 c;
s = pkmgba_mbtowc(NULL, &c, (const unsigned char*)_data + offset, 2, _japanese);
if (s < 0) break;
offset += s;
if (c == 0) break;
s = utf8_wctomb(NULL, (unsigned char*)_str + strSz, c, 6);
if (s < 0) break;
strSz += s;
}
_str[strSz++] = 0;
hasChanged = false;
return _str;
}
size_t PokemonString::size(void) const {
size_t i = 0;
while ((i < dataSz) && (_data[i] != 0xff)) ++i;
return i;
}
void PokemonString::load(u8 * data, size_t nb) {
dataSz = nb;
resizeData();
std::copy(data, data + dataSz, _data);
}
void PokemonString::save(u8 * data, size_t nb) const {
size_t sz = size(), m = ((nb <= sz) ? nb : sz); // how much characters should we write ?
std::copy(_data, _data + m, data);
if (sz < nb) {
data[sz] = 0xff;
if(sz+1 < nb) std::fill(data + sz + 1, data + nb, 0);
}
}
}
}

View File

@ -29,11 +29,11 @@ GroupBattleRule::GroupBattleRule(GroupBattleRule const& other) : Base::DataStruc
*this = other;
}
void GroupBattleRule::deleteFields(void) {
delete bannedItems;
delete[] bannedItems;
}
GroupBattleRule::~GroupBattleRule(void) {
delete bannedItems;
GroupBattleRule::deleteFields();
}
void GroupBattleRule::swap(GroupBattleRule & other) {

View File

@ -23,7 +23,6 @@ namespace LibPkmGC {
namespace GC {
Pokemon::Pokemon(size_t inSize, const u8* inData) : Base::Pokemon(inSize, inData) {
usesPartyData = true;
}
@ -31,35 +30,45 @@ Pokemon::~Pokemon(void)
{
}
Pokemon::Pokemon(Pokemon const& other) : Base::Pokemon(other), shadowPkmID(other.shadowPkmID) {
Pokemon::Pokemon(Pokemon const& other) : Base::Pokemon(other), shadowPkmID(other.shadowPkmID), GCUnk(other.GCUnk) {
CL(OTName);
CL(name);
CP_ARRAY(pkmFlags, 3);
setEggFlag(other.isEgg());
setSecondAbilityFlag(other.hasSecondAbility());
}
void Pokemon::swap(Pokemon& other) {
Base::Pokemon::swap(other);
SW(shadowPkmID);
Base::Pokemon::swap(other);
SW(GCUnk);
if (other.fixedSize == fixedSize) SW(shadowPkmID);
SW_ARRAY(pkmFlags, 3);
}
PokemonAbilityIndex Pokemon::getAbility(void) const {
const PokemonSpeciesData dt = getThisSpeciesData();
return (pkmFlags[LIBPKMGC_GC_SECOND_ABILITY_FLAG]) ? dt.possibleAbilities[1] : dt.possibleAbilities[0];
}
Pokemon& Pokemon::operator=(Pokemon const& other) {
if (this != &other) {
Base::Pokemon::operator=(other);
CP(shadowPkmID);
CP(GCUnk);
if(other.fixedSize == fixedSize) CP(shadowPkmID);
else shadowPkmID = 0;
CP_ARRAY(pkmFlags, 3);
}
return *this;
}
void Pokemon::swap(Base::Pokemon & other) {
return swap((Pokemon&)other);
bool Pokemon::hasSecondAbility(void) const {
return pkmFlags[LIBPKMGC_GC_SECOND_ABILITY_FLAG];
}
Pokemon& Pokemon::operator=(Base::Pokemon const& other) {
return operator=((Pokemon const&)other);
void Pokemon::setSecondAbilityFlag(bool status) {
pkmFlags[LIBPKMGC_GC_SECOND_ABILITY_FLAG] = status;
}
bool Pokemon::isEgg(void) const {
return pkmFlags[LIBPKMGC_GC_EGG_FLAG];
}
void Pokemon::setEggFlag(bool status) {
pkmFlags[LIBPKMGC_GC_EGG_FLAG] = status;
}
}

View File

@ -1,3 +1,20 @@
/*
* Copyright (C) TuxSH 2015
* This file is part of LibPkmGC.
*
* LibPkmGC is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* LibPkmGC is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with LibPkmGC. If not, see <http://www.gnu.org/licenses/>.
*/
// This file uses code from libiconv :
@ -27,24 +44,27 @@
#include <cstring>
using namespace LibPkmGC::Detail;
namespace LibPkmGC {
namespace GC {
PokemonString::PokemonString(const char* str) : Base::PokemonString(), _data(NULL), dataSz(0), dataCapacity(0) {
PokemonString::PokemonString(const char* str) : Base::PokemonString() {
fromUTF8(str);
}
PokemonString::PokemonString(u8 * data, size_t nb) : Base::PokemonString(), _data(NULL), dataSz(0), dataCapacity(0){
PokemonString::PokemonString(u8 * data, size_t nb) : Base::PokemonString(){
load(data, nb);
}
PokemonString::PokemonString(PokemonString const& other) : Base::PokemonString(other), dataSz(other.dataSz), dataCapacity(0), _data(NULL) {
resizeData();
std::copy(other._data, other._data + dataSz, _data);
PokemonString::PokemonString(PokemonString const& other) : Base::PokemonString(other) {
}
PokemonString::~PokemonString(void) {
delete[] _data;
}
bool PokemonString::isGBA(void) const {
return false;
}
PokemonString * PokemonString::clone(void) const {
@ -56,32 +76,23 @@ PokemonString * PokemonString::create(void) const {
}
PokemonString & PokemonString::operator=(PokemonString const & other) {
if (this != &other) {
Base::PokemonString::operator=(other);
delete[] _data;
std::copy(other._data, other._data + dataSz, _data);
}
return *this;
return (PokemonString&) Base::PokemonString::operator=(other);
}
PokemonString& PokemonString::operator=(Base::PokemonString const& other) {
return operator=((PokemonString const&)other);
if (other.isGBA()) {
_japanese = other.usesJapaneseCharset();
fromUTF8(other.toUTF8());
return *this;
}
else return operator=((PokemonString const&)other);
}
}
}
namespace {
using namespace LibPkmGC;
typedef void* conv_t;
typedef u32 ucs4_t;
// Custom :
#define RET_ILSEQ -1
#define RET_ILUNI -2
#define RET_TOOSMALL -3
#define RET_TOOFEW(c) (-4*(c+1))
namespace LibPkmGC { namespace Detail {
// Adapted from libiconv (see license above)
@ -90,7 +101,7 @@ typedef u32 ucs4_t;
* UCS-2BE = UCS-2 big endian
*/
static int
int
ucs2be_mbtowc(conv_t conv, ucs4_t *pwc, const unsigned char *s, int n)
{
if (n >= 2) {
@ -108,7 +119,7 @@ ucs2be_mbtowc(conv_t conv, ucs4_t *pwc, const unsigned char *s, int n)
return RET_TOOFEW(0);
}
static int
int
ucs2be_wctomb(conv_t conv, unsigned char *r, ucs4_t wc, int n)
{
if (wc < 0x10000 && !(wc >= 0xd800 && wc < 0xe000) && wc != 0xffff) { // [LibPkmGC]
@ -123,123 +134,10 @@ ucs2be_wctomb(conv_t conv, unsigned char *r, ucs4_t wc, int n)
return RET_ILUNI;
}
/*
* UTF-8
*/
/* Specification: RFC 3629 */
static int
utf8_mbtowc(conv_t conv, ucs4_t *pwc, const unsigned char *s, int n)
{
unsigned char c = s[0];
if (c < 0x80) {
*pwc = c;
return 1;
}
else if (c < 0xc2) {
return RET_ILSEQ;
}
else if (c < 0xe0) {
if (n < 2)
return RET_TOOFEW(0);
if (!((s[1] ^ 0x80) < 0x40))
return RET_ILSEQ;
*pwc = ((ucs4_t)(c & 0x1f) << 6)
| (ucs4_t)(s[1] ^ 0x80);
return 2;
}
else if (c < 0xf0) {
if (n < 3)
return RET_TOOFEW(0);
if (!((s[1] ^ 0x80) < 0x40 && (s[2] ^ 0x80) < 0x40
&& (c >= 0xe1 || s[1] >= 0xa0)))
return RET_ILSEQ;
*pwc = ((ucs4_t)(c & 0x0f) << 12)
| ((ucs4_t)(s[1] ^ 0x80) << 6)
| (ucs4_t)(s[2] ^ 0x80);
return 3;
}
else if (c < 0xf8 && sizeof(ucs4_t) * 8 >= 32) {
if (n < 4)
return RET_TOOFEW(0);
if (!((s[1] ^ 0x80) < 0x40 && (s[2] ^ 0x80) < 0x40
&& (s[3] ^ 0x80) < 0x40
&& (c >= 0xf1 || s[1] >= 0x90)))
return RET_ILSEQ;
*pwc = ((ucs4_t)(c & 0x07) << 18)
| ((ucs4_t)(s[1] ^ 0x80) << 12)
| ((ucs4_t)(s[2] ^ 0x80) << 6)
| (ucs4_t)(s[3] ^ 0x80);
return 4;
}
else if (c < 0xfc && sizeof(ucs4_t) * 8 >= 32) {
if (n < 5)
return RET_TOOFEW(0);
if (!((s[1] ^ 0x80) < 0x40 && (s[2] ^ 0x80) < 0x40
&& (s[3] ^ 0x80) < 0x40 && (s[4] ^ 0x80) < 0x40
&& (c >= 0xf9 || s[1] >= 0x88)))
return RET_ILSEQ;
*pwc = ((ucs4_t)(c & 0x03) << 24)
| ((ucs4_t)(s[1] ^ 0x80) << 18)
| ((ucs4_t)(s[2] ^ 0x80) << 12)
| ((ucs4_t)(s[3] ^ 0x80) << 6)
| (ucs4_t)(s[4] ^ 0x80);
return 5;
}
else if (c < 0xfe && sizeof(ucs4_t) * 8 >= 32) {
if (n < 6)
return RET_TOOFEW(0);
if (!((s[1] ^ 0x80) < 0x40 && (s[2] ^ 0x80) < 0x40
&& (s[3] ^ 0x80) < 0x40 && (s[4] ^ 0x80) < 0x40
&& (s[5] ^ 0x80) < 0x40
&& (c >= 0xfd || s[1] >= 0x84)))
return RET_ILSEQ;
*pwc = ((ucs4_t)(c & 0x01) << 30)
| ((ucs4_t)(s[1] ^ 0x80) << 24)
| ((ucs4_t)(s[2] ^ 0x80) << 18)
| ((ucs4_t)(s[3] ^ 0x80) << 12)
| ((ucs4_t)(s[4] ^ 0x80) << 6)
| (ucs4_t)(s[5] ^ 0x80);
return 6;
}
else
return RET_ILSEQ;
}
static int
utf8_wctomb(conv_t conv, unsigned char *r, ucs4_t wc, int n) /* n == 0 is acceptable */ {
int count;
if (wc < 0x80)
count = 1;
else if (wc < 0x800)
count = 2;
else if (wc < 0x10000)
count = 3;
else if (wc < 0x200000)
count = 4;
else if (wc < 0x4000000)
count = 5;
else if (wc <= 0x7fffffff)
count = 6;
else
return RET_ILUNI;
if (n < count)
return RET_TOOSMALL;
switch (count) { /* note: code falls through cases! */
case 6: r[5] = 0x80 | (wc & 0x3f); wc = wc >> 6; wc |= 0x4000000;
case 5: r[4] = 0x80 | (wc & 0x3f); wc = wc >> 6; wc |= 0x200000;
case 4: r[3] = 0x80 | (wc & 0x3f); wc = wc >> 6; wc |= 0x10000;
case 3: r[2] = 0x80 | (wc & 0x3f); wc = wc >> 6; wc |= 0x800;
case 2: r[1] = 0x80 | (wc & 0x3f); wc = wc >> 6; wc |= 0xc0;
case 1: r[0] = wc;
}
return count;
}
}
}
namespace LibPkmGC {
namespace GC {
@ -250,28 +148,32 @@ void PokemonString::fromUTF8(const char * str) {
resizeStr();
dataSz = 2 * strSz;
resizeStr();
resizeData();
dataSz = 0;
int s = 0;
size_t offset = 0;
while (offset < strSz) {
while (offset < strSz - 1) {
u32 c;
s = utf8_mbtowc(NULL, &c, (const unsigned char*)str + offset, 6);
if (s < 0) break;
offset += s;
if (c == 0) break;
s = ucs2be_wctomb(NULL, _data + dataSz, c, 2);
if (s < 0) break;
dataSz += s;
if (c == 0) break;
}
assert(dataSz % 2 == 0);
_data[dataSz++] = 0;
_data[dataSz++] = 0;
hasChanged = true;
}
const char * PokemonString::toUTF8(void) const {
if (!hasChanged) return _str;
assert(dataSz % 2 == 0);
strSz = 3 * (dataSz / 2);
resizeStr();
@ -281,6 +183,8 @@ const char * PokemonString::toUTF8(void) const {
size_t offset = 0;
while (offset < dataSz) {
assert(strSz < 3 * (dataSz / 2));
u32 c;
s = ucs2be_mbtowc(NULL, &c, (const unsigned char*)_data + offset, 2);
if (s < 0) break;
@ -296,10 +200,11 @@ const char * PokemonString::toUTF8(void) const {
size_t PokemonString::size(void) const {
size_t i = 0;
while ((2 * i < dataSz) && (_data[2 * i] != 0 || _data[2 * i + 1] != 0)) i += 2;
while ((2 * i < dataSz) && (_data[2 * i] != 0 || _data[2 * i + 1] != 0)) ++i;
return i;
}
void PokemonString::load(u8 * data, size_t nb) {
dataSz = 2 * nb + 2;
resizeData();
@ -310,15 +215,8 @@ void PokemonString::save(u8 * data, size_t nb) const {
size_t sz = size(), m = ((nb <= sz) ? nb : sz); // how much characters should we write ?
std::copy(_data, _data + 2*m, data);
std::fill(data + 2 * m, data + 2 * (nb + 1), 0);
}
void PokemonString::resizeData(void) {
if (dataCapacity < dataSz) {
dataCapacity = dataSz;
delete[] _data;
_data = new u8[dataSz];
}
if(m <= nb)
std::fill(data + 2 * m, data + 2 * (nb + 1), 0);
}

View File

@ -60,13 +60,15 @@ void StrategyMemoData::save(void) {
SV_FIELD(u16, nbEntries, 0);
}
bool StrategyMemoData::registerSpecies(PokemonSpeciesIndex index, u32 PID, u16 SID, u16 TID) {
size_t StrategyMemoData::registerSpecies(PokemonSpeciesIndex index, u32 PID, u16 SID, u16 TID) {
u16 i = 0;
while ((i < nbEntries) && (index != entries[i++]->species));
if ((i == nbEntries) || (nbEntries == 0x1f4)) return false;
if (!getSpeciesData(index).isValid) return 501;
while (i < nbEntries && index != NoSpecies && index != entries[i++]->species);
if (i == nbEntries || nbEntries == 500) return 501;
StrategyMemoEntry* entry = entries[++nbEntries - 1];
i = ++nbEntries - 1;
StrategyMemoEntry* entry = entries[i];
entry->setInfoCompleteness(true);
entry->species = index;
@ -74,10 +76,10 @@ bool StrategyMemoData::registerSpecies(PokemonSpeciesIndex index, u32 PID, u16 S
entry->firstTID = TID;
entry->firstPID = PID;
return true;
return i;
}
bool StrategyMemoData::registerSpecies(Pokemon * pkm) {
size_t StrategyMemoData::registerSpecies(Pokemon * pkm) {
return registerSpecies(pkm->species, pkm->PID, pkm->SID, pkm->TID);
}
@ -95,7 +97,7 @@ void StrategyMemoData::deleteEntry(size_t index) {
size_t StrategyMemoData::recount(void) const {
size_t i = 0;
while (i < 500 && getSpeciesData(entries[i++]->species).isValid);
while (i < 500 && getSpeciesData(entries[i]->species).isValid) ++i;
return i;
}

View File

@ -43,6 +43,11 @@ Pokemon* Pokemon::create(void) const { return new Pokemon; }
void Pokemon::swap(Pokemon& other) {
GC::Pokemon::swap(other);
SW_ARRAY(XDPkmFlags, 3);
}
bool Pokemon::isEmptyOrInvalid(void) const {
return (species >= Munchlax) || (species == NoSpecies) || !getSpeciesData(species).isValid || version.isIncomplete();
}
Pokemon& Pokemon::operator=(Pokemon const& other) {
@ -56,20 +61,19 @@ Pokemon& Pokemon::operator=(Pokemon const& other) {
void Pokemon::loadFields(void) {
u8 marksTmp = 0;
LD_FIELD_E(u16, species, 0x00, PokemonSpeciesIndex);
LD_FIELD_E(u16, heldItem, 0x02, ItemIndex);
LD_FIELD_E(u8, heldItem, 0x03, ItemIndex);
LD_FIELD(u16, partyData.currentHP, 0x04);
u16 happiness_tmp;
LD_FIELD(u16, happiness_tmp, 0x06);
happiness = (happiness_tmp > 255) ? 255 : happiness_tmp;
LD_FIELD_CONV(u16, happiness, 0x06, u8);
u16 locationCaught_tmp;
LD_FIELD(u16, locationCaught_tmp, 0x08);
locationCaught = (u8)((locationCaught_tmp > 255) ? 255 : locationCaught_tmp);
LD_FIELD(u8, levelMet, 0x0e);
LD_FIELD_E(u8, ballCaughtWith, 0x0f, ItemIndex);
LD_FIELD_E(u8, OTGender, 0x10, Gender);
LD_FIELD_CONV(u16, locationCaught, 0x08, u8);
LD_FIELD(u16, unk1, 0xa);
LD_FIELD(u16, unk2, 0xc);
LD_FIELD_MAX(u8, levelMet, 0x0e, 100);
LD_FIELD_E_MAX(u8, ballCaughtWith, 0x0f, ItemIndex, PremierBall);
if (ballCaughtWith == NoItem) ballCaughtWith = PokeBall;
LD_FIELD_E_MAX(u8, OTGender, 0x10, Gender, Female);
LD_FIELD(u8, partyData.level, 0x11);
if (partyData.level > 100) partyData.level = 100;
@ -77,19 +81,25 @@ void Pokemon::loadFields(void) {
LD_FIELD(u8, pkrsStatus, 0x13);
LD_FIELD(u8, marksTmp, 0x14);
LD_FIELD_MAX(s8, partyData.pkrsDaysRemaining, 0x15, 4);
LD_FIELD_E(u8, partyData.status, 0x16, PokemonStatus);
partyData.status = (partyData.status != NoStatus && partyData.status < Poisoned && partyData.status > Asleep) ? NoStatus : partyData.status;
LD_FIELD(s8, partyData.turnsOfBadPoison, 0x17);
LD_FIELD(s8, partyData.turnsOfSleepRemaining, 0x18);
LD_FIELD_MAX(u8, GCUnk, 0x1a, 31);
LD_BIT_ARRAY(u8, pkmFlags, 3, 0x1d);
LD_BIT_ARRAY2(u8, XDPkmFlags, 3, 0x1d, 3);
LD_FIELD(u32, experience, 0x20);
LD_FIELD_MAX(u32, experience, 0x20, getSpeciesExpTable(species)[100]);
LD_FIELD(u16, SID, 0x24);
LD_FIELD(u16, TID, 0x26);
LD_FIELD(u32, PID, 0x28);
LD_FIELD_B(u8, obedient, 0x30);
LD_FIELD(u8, encounterType, 0x33);
OTName = new GC::PokemonString(data + 0x38, 10);
name = new GC::PokemonString(data + 0x4e, 10);
LD_BIT_ARRAY(u16, specialRibbons, 12, 0x7c);
unimplementedRibbons = specialRibbons_tmp & 15; // specialRibbons_tmp is defined by LD_BIT_ARRAY
LD_ARRAY(u16, partyData.stats, 6, 0x90);
u16 EVs_tmp[6]; // EVs are internally stored as u16
@ -99,8 +109,8 @@ void Pokemon::loadFields(void) {
LD_ARRAY(u8, IVs, 6, 0xa8);
for (size_t i = 0; i < 6; ++i) IVs[i] = (IVs[i] > 31) ? 31 : IVs[i];
LD_ARRAY(u8, contestStats, 6, 0xae);
LD_ARRAY_E(u8, contestAchievements, 5, 0xb3, ContestAchievementLevel);
LD_ARRAY(u8, contestStats, 5, 0xae);
LD_ARRAY_E_MAX(u8, contestAchievements, 5, 0xb3, ContestAchievementLevel, MasterContestWon);
LD_FIELD(u16, shadowPkmID, 0xba);
@ -110,20 +120,34 @@ void Pokemon::loadFields(void) {
for (size_t i = 0; i < 4; ++i)
moves[i].load(data + 0x80 + 4 * i);
if (partyData.currentHP > partyData.stats[0]) partyData.currentHP = partyData.stats[0];
pkmFlags[LIBPKMGC_GC_SECOND_ABILITY_FLAG] = isSecondAbilityDefined() && pkmFlags[LIBPKMGC_GC_SECOND_ABILITY_FLAG];
normalizePkrs();
normalizeStatus();
}
void Pokemon::save(void) {
normalizePkrs();
normalizeStatus();
pkmFlags[LIBPKMGC_GC_SECOND_ABILITY_FLAG] = isSecondAbilityDefined() && pkmFlags[LIBPKMGC_GC_SECOND_ABILITY_FLAG];
if (partyData.currentHP > partyData.stats[0]) partyData.currentHP = partyData.stats[0];
SV_FIELD_E(u16, species, 0x00, PokemonSpeciesIndex);
SV_FIELD_E(u16, heldItem, 0x02, ItemIndex);
SV_FIELD_E(u8, heldItem, 0x03, ItemIndex);
SV_FIELD(u16, partyData.currentHP, 0x04);
SV_FIELD(u16, (u16)happiness, 0x06);
SV_FIELD(u16, (u16)locationCaught, 0x08);
SV_FIELD(u8, levelMet, 0x0e);
SV_FIELD_E(u8, ballCaughtWith, 0x0f, ItemIndex);
SV_FIELD_E(u8, OTGender, 0x10, Gender);
SV_FIELD_CONV(u16, happiness, 0x06, u8);
SV_FIELD_CONV(u16, locationCaught, 0x08, u8);
SV_FIELD(u16, unk1, 0xa);
SV_FIELD(u16, unk2, 0xc);
SV_FIELD_MAX(u8, levelMet, 0x0e, 100);
if (ballCaughtWith == NoItem || ballCaughtWith > PremierBall) ballCaughtWith = PokeBall;
SV_FIELD_E_MAX(u8, ballCaughtWith, 0x0f, ItemIndex, PremierBall);
SV_FIELD_E_MAX(u8, OTGender, 0x10, Gender, Female);
if (partyData.level > 100) partyData.level = 100;
SV_FIELD(u8, partyData.level, 0x11);
@ -131,21 +155,29 @@ void Pokemon::save(void) {
SV_FIELD(u8, pkrsStatus, 0x13);
SV_FIELD(u8, markings.save(), 0x14);
partyData.status = (partyData.status != NoStatus && partyData.status < Poisoned && partyData.status > Asleep) ? NoStatus : partyData.status;
SV_FIELD_MAX(s8, partyData.pkrsDaysRemaining, 0x15, 4);
SV_FIELD_E(u8, partyData.status, 0x16, PokemonStatus);
SV_FIELD(s8, partyData.turnsOfBadPoison, 0x17);
SV_FIELD(s8, partyData.turnsOfSleepRemaining, 0x18);
SV_FIELD_MAX(u8, GCUnk, 0x1a, 31);
SV_BIT_ARRAY(u8, pkmFlags, 3, 0x1d);
SV_BIT_ARRAY2(u8, XDPkmFlags, 3, 0x1d, 3);
SV_FIELD(u32, experience, 0x20);
SV_FIELD_MAX(u32, experience, 0x20, getSpeciesExpTable(species)[100]);
SV_FIELD(u16, SID, 0x24);
SV_FIELD(u16, TID, 0x26);
SV_FIELD(u32, PID, 0x28);
u32 st = pokemonStatusToBitField(partyData.status, 0, partyData.turnsOfSleepRemaining);
SV_FIELD(u32, st, 0x2c);
SV_FIELD_B(u8, obedient, 0x30);
SV_FIELD(u8, encounterType, 0x33);
OTName->save(data + 0x38, 10);
name->save(data + 0x4e, 10);
name->save(data + 0x64, 10);
SV_BIT_ARRAY(u16, specialRibbons, 12, 0x7c);
if (unimplementedRibbons > 15) unimplementedRibbons = 15;
data[0x7d] = (data[0x7d] & 0xf0) | unimplementedRibbons;
SV_ARRAY(u16, partyData.stats, 6, 0x90);
u16 EVs_tmp[6]; for (size_t i = 0; i < 6; ++i) EVs_tmp[i] = (u16)EVs[i];
@ -154,8 +186,8 @@ void Pokemon::save(void) {
SV_ARRAY(u8, IVs, 6, 0xa8);
SV_ARRAY(u8, contestStats, 6, 0xae);
SV_ARRAY_E(u8, contestAchievements, 5, 0xb3, ContestAchievementLevel);
SV_ARRAY(u8, contestStats, 5, 0xae);
SV_ARRAY_E_MAX(u8, contestAchievements, 5, 0xb3, ContestAchievementLevel, MasterContestWon);
SV_FIELD(u16, shadowPkmID, 0xba);

View File

@ -19,7 +19,7 @@
#ifndef _PKMGCSAVEEDITOR_GLOBALS_H
#define _PKMGCSAVEEDITOR_GLOBALS_H
#define PKMGCSAVEEDITOR_VERSION 1000000
#define PKMGCSAVEEDITOR_VERSION 1001000
#define PKMGCSAVEEDITOR_VERSION_MAJOR ((PKMGCSAVEEDITOR_VERSION / 1000000) % 1000)
#define PKMGCSAVEEDITOR_VERSION_MINOR ((PKMGCSAVEEDITOR_VERSION / 1000) % 1000)
#define PKMGCSAVEEDITOR_VERSION_BUILD (PKMGCSAVEEDITOR_VERSION % 1000)
@ -28,6 +28,7 @@
#include <LibPkmGC/XD/SaveEditing/Save.h>
#include <LibPkmGC/Colosseum/SaveEditing/Save.h>
#include <LibPkmGC/Core/Localization.h>
#include <LibPkmGC/GBA/Pokemon.h>
#include <QLocale>
#include <QMap>

View File

@ -64,7 +64,7 @@ void GameConfigUI::parseData(void) {
SaveSlot* sl = saveSlot_;
isXD = LIBPKMGC_IS_XD(SaveEditing::SaveSlot, sl);
versionFld->disconnect(SIGNAL(versionChanged()));
versionFld->disconnect(SIGNAL(versionChanged()), this);
versionFld->setInfo(sl->version);
connect(versionFld, SIGNAL(versionChanged()), this, SLOT(versionChangeHandler()));

View File

@ -136,72 +136,45 @@ void PokemonDisplayWidget::deletePkm(void) {
QString PokemonDisplayWidget::selectFilters(void) {
QString PokemonDisplayWidget::selectFilters(bool op) {
const QString allsupportedfilesfilter = tr("All supported files (*.colopkm *.xdpkm *.pkm *.3gpkm)");
const QString colofilter = tr("Colosseum Pok\xc3\xa9mon files (*.colopkm)");
const QString xdfilter = tr("XD Pok\xc3\xa9mon files (*.xdpkm)");
const QString gbafilter = tr("GBA Pok\xc3\xa9mon files (*.pkm *.3gpkm)");
const QString gbaencfilter = tr("Encrypted GBA Pok\xc3\xa9mon files (*.pkm *.3gpkm)");
const QString allfilesfilter = tr("All files (*)");
return ((pkm == NULL || LIBPKMGC_IS_COLOSSEUM(Pokemon, pkm)) ?
colofilter + ";;" + xdfilter + ";;" + allfilesfilter :
xdfilter + ";;" + colofilter + ";;" + allfilesfilter);
QString F[] = { colofilter, xdfilter, gbafilter };
if (pkm != NULL) {
if (LIBPKMGC_IS_GBA(Pokemon, pkm)) std::swap(F[0], F[2]);
else if (LIBPKMGC_IS_XD(Pokemon, pkm)) std::swap(F[0], F[1]);
}
return (op) ? (allsupportedfilesfilter + ";;" + F[0] + ";;" + F[1] + ";;" + F[2]) :
(F[0] + ";;" + F[1] + ";;" + F[2] + ";;" + gbaencfilter);
}
void PokemonDisplayWidget::openImportPkmDialog(void) {
const QString errmsg = tr("Could not open file.");
const QString errmsg2 = tr("An error occured while reading the specified Pok\xc3\xa9mon file.");
QString fileName = QFileDialog::getOpenFileName(this, tr("Open Pok\xc3\xa9mon file"), lastPkmDirectory, selectFilters());
void PokemonDisplayWidget::openImportPkmDialog(void) {
QString fileName = QFileDialog::getOpenFileName(this, tr("Open Pok\xc3\xa9mon file"), lastPkmDirectory, selectFilters(true));
if (fileName.isEmpty()) return;
QFileInfo fileInfo(fileName);
size_t fileSize = (size_t) fileInfo.size();
if (fileSize == 0x138) { // Colosseum Pokémon
QFile file(fileName);
if (!file.open(QIODevice::ReadOnly)) {
QMessageBox::critical(this, tr("Error"), errmsg);
return;
}
QByteArray ba = file.readAll();
if (ba.size() != 0x138) {
QMessageBox::critical(this, tr("Error"), errmsg2);
return;
}
Colosseum::Pokemon importedPkm((u8*)ba.data());
if (pkm == NULL) pkm = importedPkm.clone();
else { *pkm = importedPkm; }
parseData();
lastPkmDirectory = fileInfo.canonicalPath();
switch (fileSize) {
case 0x138: readExpected<Colosseum::Pokemon>(fileName); break;
case 0xc4: readExpected<XD::Pokemon>(fileName); break;
case 100: case 80: readExpected<GBA::Pokemon>(fileName, fileSize); break;
default: QMessageBox::critical(this, tr("Error"), tr("Invalid file size.")); break;
}
else if (fileSize == 0xc4) {
QFile file(fileName);
if (!file.open(QIODevice::ReadOnly)) {
QMessageBox::critical(this, tr("Error"), errmsg);
return;
}
QByteArray ba = file.readAll();
if (ba.size() != 0xc4) {
QMessageBox::critical(this, tr("Error"), errmsg2);
return;
}
XD::Pokemon importedPkm((const u8*)ba.data());
if (pkm == NULL) pkm = importedPkm.clone();
else { *pkm = importedPkm; }
parseData();
lastPkmDirectory = fileInfo.canonicalPath();
}
else {
QMessageBox::critical(this, tr("Error"), tr("Invalid file size."));
}
}
void PokemonDisplayWidget::openExportPkmDialog(void) {
const QString errmsg = tr("Could not write to file.");
const QString errmsg2 = tr("An error occured while writing to the specified Pok\xc3\xa9mon file.");
const QString gbaencfilter = tr("Encrypted GBA Pok\xc3\xa9mon files (*.pkm *.3gpkm)");
QString fileName = QFileDialog::getSaveFileName(this, tr("Save Pok\xc3\xa9mon file"), lastPkmDirectory, selectFilters());
QString selectedFilter;
QString fileName = QFileDialog::getSaveFileName(this, tr("Save Pok\xc3\xa9mon file"), lastPkmDirectory, selectFilters(false), &selectedFilter);
if (fileName.isEmpty()) return;
QFile file(fileName);
@ -213,7 +186,7 @@ void PokemonDisplayWidget::openExportPkmDialog(void) {
QString selectedExt = fileName.section(".", -1);
GC::Pokemon* exportedPkm = pkm;
Base::Pokemon* exportedPkm = pkm;
bool created = false;
if ((selectedExt == "colopkm") && !LIBPKMGC_IS_COLOSSEUM(Pokemon, pkm)) {
@ -224,10 +197,22 @@ void PokemonDisplayWidget::openExportPkmDialog(void) {
exportedPkm = new XD::Pokemon(*(Colosseum::Pokemon*)pkm);
created = true;
}
else if ((selectedExt == "3gpkm" || selectedExt == "pkm") && !LIBPKMGC_IS_GBA(Pokemon, pkm)) {
exportedPkm = new GBA::Pokemon(*pkm);
created = true;
}
exportedPkm->save();
if (file.write((const char*)exportedPkm->data, exportedPkm->fixedSize) != (qint64)exportedPkm->fixedSize)
char* dta = (char*)exportedPkm->data;
QByteArray dt(100, 0);
if (selectedFilter == gbaencfilter) {
static_cast<GBA::Pokemon*>(exportedPkm)->saveEncrypted((u8*)dt.data());
dta = dt.data();
}
if (file.write(dta, exportedPkm->fixedSize) != (qint64)exportedPkm->fixedSize)
QMessageBox::critical(this, tr("Error"), errmsg2);
else
lastPkmDirectory = QFileInfo(fileName).canonicalPath();

View File

@ -43,7 +43,50 @@ private:
QPushButton *importButton;
QPushButton *exportButton;
QString selectFilters(void);
QString selectFilters(bool op = true);
template<typename P>
void readExpected(QString fileName, size_t sz = P::size) {
const QString errmsg = tr("Could not open file.");
const QString errmsg2 = tr("An error occured while reading the specified Pok\xc3\xa9mon file.");
QFile file(fileName);
if (!file.open(QIODevice::ReadOnly)) {
QMessageBox::critical(this, tr("Error"), errmsg);
return;
}
QByteArray ba = file.readAll();
if (ba.size() != sz) {
QMessageBox::critical(this, tr("Error"), errmsg2);
return;
}
P* importedPkm = NULL;
if (sz != 80)
importedPkm = new P((const u8*)ba.data());
else {
GBA::Pokemon* pk2 = GBA::Pokemon::load80((const u8*)ba.data());
importedPkm = new P(*pk2);
delete pk2;
}
if (pkm == NULL) {
if (LIBPKMGC_IS_XD(Pokemon, importedPkm) || (currentSaveSlot != NULL && LIBPKMGC_IS_XD(SaveEditing::SaveSlot, currentSaveSlot)))
pkm = new XD::Pokemon(*importedPkm);
else
pkm = new Colosseum::Pokemon(*importedPkm);
}
else *pkm = *importedPkm;
if (P::size == 100 && currentSaveSlot != NULL)
pkm->version.currentRegion = currentSaveSlot->version.currentRegion;
parseData();
lastPkmDirectory = QFileInfo(fileName).canonicalPath();
delete importedPkm;
}
};

View File

@ -16,12 +16,18 @@ PokemonMoveLayout::PokemonMoveLayout(PokemonMove const& inMove) : QHBoxLayout(){
currentPPsFld->setRange(0, 64);
this->addWidget(moveNameFld);
this->addWidget(currentPPsFld);
this->addWidget(maxPPsFld);
this->addWidget(nbPPUpsUsedFld, 0, Qt::AlignRight);
this->addWidget(nbPPUpsUsedText, 0, Qt::AlignRight);
QHBoxLayout* w1 = new QHBoxLayout;
w1->addWidget(moveNameFld);
w1->addWidget(currentPPsFld);
w1->addWidget(maxPPsFld);
QHBoxLayout* w2 = new QHBoxLayout;
w2->addWidget(nbPPUpsUsedFld);
w2->addWidget(nbPPUpsUsedText);
w2->setAlignment(Qt::AlignRight);
this->addLayout(w1, 3);
this->addLayout(w2, 1);
for (size_t i = 0; i <= (size_t)PsychoBoost; ++i)
moveNameFld->addItem(getPokemonMoveName(lg, (PokemonMoveIndex)i));
@ -38,12 +44,17 @@ PokemonMove PokemonMoveLayout::move(void) const {
}
void PokemonMoveLayout::setMove(PokemonMove const& inMove) {
blockSignals(true);
moveNameFld->disconnect(SIGNAL(currentIndexChanged(int)), this);
nbPPUpsUsedFld->disconnect(SIGNAL(valueChanged(int)), this);
currentPPsFld->setUnsignedRange(0, 64);
currentPPsFld->setUnsignedValue(inMove.currentPPs);
moveNameFld->setCurrentIndex((inMove.moveIndex > PsychoBoost) ? 0 : (int) inMove.moveIndex);
moveNameFld->setCurrentIndex((inMove.move > PsychoBoost) ? 0 : (int) inMove.move);
nbPPUpsUsedFld->setUnsignedValue(inMove.nbPPUpsUsed);
blockSignals(false);
connect(moveNameFld, SIGNAL(currentIndexChanged(int)), this, SLOT(updateFields()));
connect(nbPPUpsUsedFld, SIGNAL(valueChanged(int)), this, SLOT(updateFields()));
updateFields();
}
@ -59,9 +70,9 @@ PokemonStatLayout::PokemonStatLayout(u8 inIV, u8 inEV, u16 inStat) : QHBoxLayout
EVFld = new UnsignedSpinbox<8>;
statFld = new UnsignedSpinbox<16>;
IVFld->setValue((int)inIV);
EVFld->setValue((int)inEV);
statFld->setValue((int)inStat);
IVFld->setUnsignedValue(inIV);
EVFld->setUnsignedValue(inEV);
statFld->setUnsignedValue(inStat);
this->addWidget(IVFld);
this->addWidget(EVFld);
this->addWidget(statFld);
@ -111,13 +122,19 @@ void PokemonUI::initWidget(void){
movesTab = new QWidget;
ribbonsTab = new QWidget;
generalTabLayout = new QFormLayout;
generalTabLayout = new QVBoxLayout;
metTabLayout = new QVBoxLayout;
statsTabLayout = new QVBoxLayout;
movesTabLayout = new QVBoxLayout;
ribbonsTabLayout = new QVBoxLayout;
//-----------------------------"General" tab:-----------------------------------------------
generalSubTabs = new QTabWidget;
generalCoreSubTab = new QWidget;
generalCoreSubTabLayout = new QFormLayout;
generalStatusSubTab = new QWidget;
generalStatusSubTabLayout = new QFormLayout;
speciesFld = new QComboBox;
nameLayout = new QHBoxLayout;
@ -134,14 +151,14 @@ void PokemonUI::initWidget(void){
heldItemFld = new ItemComboBox;
happinessFld = new UnsignedSpinbox<8>;
pkrsStatusFld = new UnsignedSpinbox<8>;
statusFld = new QComboBox;
pkrsStatusLayout = new QHBoxLayout;
pkrsDaysRemainingFld = new UnsignedSpinbox<3>;
pkrsStrainFld = new UnsignedSpinbox<4>;
flagsLayout = new QGridLayout;
flagsButtonGroup = new QButtonGroup;
markingsLayout = new QHBoxLayout;
markingsButtonGroup = new QButtonGroup;
statusFld->addItems(statusNames());
for (size_t i = 0; i < 387; ++i)
speciesFld->addItem(Localization::getPokemonSpeciesNameByPkdxIndex(lg, i));
@ -155,6 +172,8 @@ void PokemonUI::initWidget(void){
levelFld->setRange(1, 100);
syncLevelAndExpFldsCheckBox->setChecked(true);
pkrsDaysRemainingFld->setUnsignedRange(0, 4);
experienceLevelAndSyncLayout->addWidget(experienceFld,2);
levelAndSyncLayout->addWidget(levelFld,1);
@ -162,6 +181,9 @@ void PokemonUI::initWidget(void){
levelAndSyncLayout->setAlignment(Qt::AlignRight);
experienceLevelAndSyncLayout->addLayout(levelAndSyncLayout);
pkrsStatusLayout->addWidget(pkrsDaysRemainingFld);
pkrsStatusLayout->addWidget(pkrsStrainFld);
eggFlagCheckBox = new QCheckBox(tr("Egg")); secondAbilityFlagCheckBox = new QCheckBox(tr("Second ability"));
invalidPokemonCheckBox = new QCheckBox(tr("Invalid Pok\xc3\xa9mon"));
notTradableInGameFlagCheckBox = new QCheckBox(tr("Not tradable in-game")); unknownFlagCheckBox = new QCheckBox(tr("Unknown"));
@ -190,20 +212,43 @@ void PokemonUI::initWidget(void){
markingsLayout->addWidget(g2[i]);
}
generalTabLayout->addRow(tr("Species"), speciesFld);
generalTabLayout->addRow(tr("Name or nickname"), nameLayout);
generalTabLayout->addRow(tr("PID"), PIDFld);
generalTabLayout->addRow(tr("Attributes"), attributesFld);
generalTabLayout->addRow(tr("Ability"), abilityFld);
generalTabLayout->addRow(tr("Experience and level"), experienceLevelAndSyncLayout);
generalTabLayout->addRow(tr("Held item"), heldItemFld);
generalTabLayout->addRow(tr("Happiness"), happinessFld);
generalTabLayout->addRow(tr("Pok\xc3\xa9rus"), pkrsStatusFld);
generalTabLayout->addRow(tr("Status"), statusFld);
generalTabLayout->addRow(tr("Flags"), flagsLayout);
generalTabLayout->addRow(tr("Markings"), markingsLayout);
generalCoreSubTabLayout->addRow(tr("Species"), speciesFld);
generalCoreSubTabLayout->addRow(tr("Name or nickname"), nameLayout);
generalCoreSubTabLayout->addRow(tr("PID"), PIDFld);
generalCoreSubTabLayout->addRow(tr("Attributes"), attributesFld);
generalCoreSubTabLayout->addRow(tr("Ability"), abilityFld);
generalCoreSubTabLayout->addRow(tr("Experience and level"), experienceLevelAndSyncLayout);
generalCoreSubTabLayout->addRow(tr("Held item"), heldItemFld);
generalCoreSubTabLayout->addRow(tr("Happiness"), happinessFld);
generalCoreSubTabLayout->addRow(tr("Pok\xc3\xa9rus (days remaing and strain)"), pkrsStatusLayout);
generalCoreSubTabLayout->addRow(tr("Flags"), flagsLayout);
generalCoreSubTabLayout->addRow(tr("Markings"), markingsLayout);
statusFld = new QComboBox;
partyPrksDaysRemainingFld = new QSpinBox;
turnsOfBadPoisonFld = new QSpinBox;
turnsOfSleepRemainingFld = new QSpinBox;
statusFld->addItems(statusNames());
partyPrksDaysRemainingFld->setRange(-1, 4);
turnsOfBadPoisonFld->setRange(0, 15);
turnsOfSleepRemainingFld->setRange(0, 7);
generalStatusSubTabLayout->addRow(tr("Status"), statusFld);
generalStatusSubTabLayout->addRow(tr("Pok\xc3\xa9rus days remaining"), partyPrksDaysRemainingFld);
generalStatusSubTabLayout->addRow(tr("Turns of sleep remaining"), turnsOfSleepRemainingFld);
generalStatusSubTabLayout->addRow(tr("Turns of bad poison"), turnsOfBadPoisonFld);
generalCoreSubTab->setLayout(generalCoreSubTabLayout);
generalStatusSubTab->setLayout(generalStatusSubTabLayout);
generalSubTabs->addTab(generalCoreSubTab, tr("Core"));
generalSubTabs->addTab(generalStatusSubTab, tr("Status"));
generalTabLayout->addWidget(generalSubTabs);
generalTab->setLayout(generalTabLayout);
//----------------------------------------------------------------------------------------
@ -217,16 +262,23 @@ void PokemonUI::initWidget(void){
OTField = new TrainerInfoLayout;
versionFld = new VersionInfoLayout;
ballCaughtWithFld = new ItemComboBox(POKEBALLS_ALLOWED | EMPTY_ITEM_FORBIDDEN);
locationCaughtFld = new UnsignedSpinbox<8>;
levelMetFld = new UnsignedSpinbox<7>;
obedientFld = new QCheckBox;
ballCaughtWithFld = new ItemComboBox(POKEBALLS_ALLOWED | EMPTY_ITEM_FORBIDDEN);
metActionsLayout = new QHBoxLayout;
copyInfoFromSaveButton = new QPushButton(tr("Copy info from save"));
generateShinyIDsButton = new QPushButton(tr("Generate shiny IDs"));
coreCaptureInfoLayout->addRow(tr("Ball caught with"), ballCaughtWithFld);
coreCaptureInfoLayout->addRow(tr("Location caught"), locationCaughtFld);
levelMetFld->setUnsignedRange(1, 100);
coreCaptureInfoLayout->addRow(tr("Location caught"), locationCaughtFld);
coreCaptureInfoLayout->addRow(tr("Level met"), levelMetFld);
coreCaptureInfoLayout->addRow(tr("Fateful encounter (obedient)"), obedientFld);
coreCaptureInfoLayout->addRow(tr("Ball caught with"), ballCaughtWithFld);
coreCaptureInfoLayout->labelForField(obedientFld)->setToolTip(tr("Mew and Deoxys need this field to be checked so they can obey"));
coreCaptureInfoBox->setLayout(coreCaptureInfoLayout);
OTBox->setLayout(OTField);
versionBox->setLayout(versionFld);
@ -343,7 +395,6 @@ void PokemonUI::initWidget(void){
generalTab->setLayout(generalTabLayout);
metTab->setLayout(metTabLayout);
statsTab->setLayout(statsTabLayout);
movesTab->setLayout(movesTabLayout);
@ -364,6 +415,8 @@ void PokemonUI::initWidget(void){
connect(abilityFld, SIGNAL(currentIndexChanged(int)), this, SLOT(updateFlags()));
connect(experienceFld, SIGNAL(valueChanged(int)), this, SLOT(updateLevelFromExperience()));
connect(levelFld, SIGNAL(valueChanged(int)), this, SLOT(updateExperienceFromLevel()));
connect(statusFld, SIGNAL(currentIndexChanged(int)), SLOT(statusChangeHandler()));
connect(pkrsStrainFld, SIGNAL(valueChanged(int)), this, SLOT(updatePkrsDaysRemaining()));
connect(OTField, SIGNAL(TIDorSIDChanged()), this, SLOT(updatePkmAttributes()));
connect(versionFld, SIGNAL(versionChanged()), this, SLOT(versionChangeHandler()));
connect(copyInfoFromSaveButton, SIGNAL(clicked()), this, SLOT(copyInfoFromSave()));
@ -376,7 +429,7 @@ void PokemonUI::parseData(void){
if (pkm == NULL) return;
copyInfoFromSaveButton->setDisabled(currentSaveSlot == NULL);
// Blocking signals have a strange yet enormous cost on the main window when loading the save
// Blocking signals have a strange yet enormous cost on the main window when loading the save file
autoUpdateMainStatsCheckBox->setChecked(false);
syncLevelAndExpFldsCheckBox->setChecked(false);
@ -408,8 +461,37 @@ void PokemonUI::parseData(void){
heldItemFld->setCurrentItemIndex(pkm->heldItem);
happinessFld->setUnsignedValue(pkm->happiness);
pkrsStatusFld->setUnsignedValue(pkm->pkrsStatus);
statusFld->disconnect(SIGNAL(currentIndexChanged(int)), this);
statusFld->setCurrentIndex((pkm->partyData.status == NoStatus) ? 0 : (int)pkm->partyData.status - 2);
turnsOfBadPoisonFld->setValue(pkm->partyData.turnsOfBadPoison);
turnsOfSleepRemainingFld->setValue(pkm->partyData.turnsOfSleepRemaining);
statusChangeHandler();
connect(statusFld, SIGNAL(currentIndexChanged(int)), SLOT(statusChangeHandler()));
pkrsStrainFld->disconnect(SIGNAL(valueChanged(int)), this);
pkrsStrainFld->setUnsignedValue(pkm->pkrsStatus & 0xf);
pkrsDaysRemainingFld->setUnsignedValue(pkm->pkrsStatus >> 4);
partyPrksDaysRemainingFld->setValue(pkm->pkrsStatus >> 4);
updatePkrsDaysRemaining();
/*if ((pkm->pkrsStatus & 0xf) == 0) {
pkrsDaysRemainingFld->setValue(0);
pkrsDaysRemainingFld->setDisabled(true);
partyPrksDaysRemainingFld->setValue(-1);
partyPrksDaysRemainingFld->setDisabled(true);
}
else {
pkrsDaysRemainingFld->setUnsignedRange(0, (pkm->pkrsStatus & 0x3) + 1);
partyPrksDaysRemainingFld->setRange(0, (pkm->pkrsStatus & 0x3) + 1);
pkrsDaysRemainingFld->setUnsignedValue(pkm->pkrsStatus >> 4);
partyPrksDaysRemainingFld->setValue(pkm->pkrsStatus >> 4);
}*/
connect(pkrsStrainFld, SIGNAL(valueChanged(int)), this, SLOT(updatePkrsDaysRemaining()));
QCheckBox* g1[] = { eggFlagCheckBox, secondAbilityFlagCheckBox, invalidPokemonCheckBox,
notTradableInGameFlagCheckBox, unknownFlagCheckBox, caughtFlagCheckBox };
@ -425,12 +507,14 @@ void PokemonUI::parseData(void){
squareMarkingCheckBox->setChecked(pkm->markings.square);
triangleMarkingCheckBox->setChecked(pkm->markings.triangle);
heartMarkingCheckBox->setChecked(pkm->markings.heart);
ballCaughtWithFld->setCurrentItemIndex(pkm->ballCaughtWith);
locationCaughtFld->setUnsignedValue(pkm->locationCaught);
levelMetFld->setUnsignedValue(pkm->levelMet);
ballCaughtWithFld->setCurrentItemIndex(pkm->ballCaughtWith);
obedientFld->setChecked(pkm->obedient);
OTField->set(pkm->OTName, pkm->TID, pkm->SID, pkm->OTGender);
versionFld->disconnect(SIGNAL(versionChanged()));
versionFld->disconnect(SIGNAL(versionChanged()), this);
versionFld->setInfo(pkm->version);
connect(versionFld, SIGNAL(versionChanged()), this, SLOT(versionChangeHandler()));
@ -454,7 +538,7 @@ void PokemonUI::parseData(void){
autoUpdateMainStatsCheckBox->setChecked(true);
versionChangeHandler();
abilityFld->setCurrentIndex((pkm->pkmFlags[LIBPKMGC_GC_SECOND_ABILITY_FLAG]) ? 1 : 0);
abilityFld->setCurrentIndex((pkm->hasSecondAbility()) ? 1 : 0);
oldSpecies = pkm->species;
}
@ -464,13 +548,14 @@ void PokemonUI::saveChanges(void){
pkm->name->fromUTF8(nameFld->text().toUtf8().data());
pkm->PID = PIDFld->unsignedValue();
pkm->pkmFlags[LIBPKMGC_GC_SECOND_ABILITY_FLAG] = (abilityFld->currentIndex() != 0);
pkm->setSecondAbilityFlag(abilityFld->currentIndex() != 0);
pkm->experience = experienceFld->unsignedValue();
pkm->partyData.level = (u8)levelFld->unsignedValue();
pkm->heldItem = heldItemFld->currentItemIndex();
pkm->happiness = (u8)happinessFld->unsignedValue();
pkm->pkrsStatus = (u8)pkrsStatusFld->unsignedValue();
pkm->pkrsStatus = (u8)((pkrsDaysRemainingFld->unsignedValue() << 4) | pkrsStrainFld->unsignedValue());
pkm->partyData.pkrsDaysRemaining = (s8)(partyPrksDaysRemainingFld->value());
pkm->partyData.status = (statusFld->currentIndex() == 0) ? NoStatus : (PokemonStatus)(2 + statusFld->currentIndex());
QCheckBox* g1[] = { eggFlagCheckBox, secondAbilityFlagCheckBox, invalidPokemonCheckBox,
@ -487,8 +572,10 @@ void PokemonUI::saveChanges(void){
pkm->markings.triangle = triangleMarkingCheckBox->isChecked();
pkm->markings.heart = heartMarkingCheckBox->isChecked();
pkm->ballCaughtWith = ballCaughtWithFld->currentItemIndex();
pkm->locationCaught = (u8)locationCaughtFld->unsignedValue();
pkm->levelMet = (u8)levelMetFld->unsignedValue();
pkm->ballCaughtWith = ballCaughtWithFld->currentItemIndex();
pkm->obedient = obedientFld->isChecked();
OTField->trainerName(pkm->OTName);
pkm->TID = OTField->TID();
@ -631,8 +718,8 @@ void PokemonUI::updateAbilityList(void) {
const PokemonAbilityIndex* ab = getSpeciesData(id).possibleAbilities;
bool sec = abilityFld->currentIndex() == 1;
disconnect(abilityFld, SIGNAL(currentIndexChanged(int)));
disconnect(secondAbilityFlagCheckBox, SIGNAL(stateChanged(int)));
abilityFld->disconnect(SIGNAL(currentIndexChanged(int)), this);
secondAbilityFlagCheckBox->disconnect(SIGNAL(stateChanged(int)), this);
abilityFld->clear();
abilityFld->addItem(Localization::getPokemonAbilityName(lg, ab[0]));
@ -652,7 +739,6 @@ void PokemonUI::updateAbilityList(void) {
void PokemonUI::updateExperienceFromLevel(bool proportionally) {
proportionally = false; // not working a.t.m
if (syncLevelAndExpFldsCheckBox->isChecked()) {
u32 experience = 0;
if (!proportionally) {
@ -663,7 +749,7 @@ void PokemonUI::updateExperienceFromLevel(bool proportionally) {
else {
experience = Base::Pokemon::fixExperienceProportionally(oldSpecies, experienceFld->unsignedValue(), nameIndexToPkmSpeciesIndex(speciesFld->currentIndex()));
}
experienceFld->disconnect(SIGNAL(valueChanged(int)));
experienceFld->disconnect(SIGNAL(valueChanged(int)), this);
experienceFld->setValue((int)experience);
connect(experienceFld, SIGNAL(valueChanged(int)), this, SLOT(updateLevelFromExperience()));
}
@ -673,7 +759,7 @@ void PokemonUI::updateLevelFromExperience(void) {
if (syncLevelAndExpFldsCheckBox->isChecked()) {
u8 lvl = Pokemon::calculateLevelFromExp(nameIndexToPkmSpeciesIndex((size_t)speciesFld->currentIndex()), (u32)experienceFld->value());
levelFld->disconnect(SIGNAL(valueChanged(int)));
levelFld->disconnect(SIGNAL(valueChanged(int)), this);
levelFld->setValue((int)lvl);
connect(levelFld, SIGNAL(valueChanged(int)), this, SLOT(updateExperienceFromLevel()));
}
@ -694,6 +780,42 @@ void PokemonUI::PIDChangeHandler(void) {
updateMainStats();
}
void PokemonUI::updatePkrsDaysRemaining(void) {
if (pkrsStrainFld->unsignedValue() == 0) {
pkrsDaysRemainingFld->setValue(0);
pkrsDaysRemainingFld->setDisabled(true);
partyPrksDaysRemainingFld->setRange(-1, -1);
partyPrksDaysRemainingFld->setValue(-1);
partyPrksDaysRemainingFld->setDisabled(true);
}
else {
pkrsDaysRemainingFld->setDisabled(false);
partyPrksDaysRemainingFld->setDisabled(false);
pkrsDaysRemainingFld->setUnsignedRange(0, (pkrsStrainFld->unsignedValue() & 0x3) + 1);
partyPrksDaysRemainingFld->setRange(0, (pkrsStrainFld->unsignedValue() & 0x3) + 1);
}
}
void PokemonUI::statusChangeHandler(void) {
PokemonStatus status = (statusFld->currentIndex() == 0) ? NoStatus : (PokemonStatus)(2 + statusFld->currentIndex());
if (status != BadlyPoisoned) {
turnsOfBadPoisonFld->setValue(0);
turnsOfBadPoisonFld->setDisabled(true);
}
else {
turnsOfBadPoisonFld->setDisabled(false);
}
if (status != Asleep) {
turnsOfSleepRemainingFld->setValue(0);
turnsOfSleepRemainingFld->setDisabled(true);
}
else {
turnsOfSleepRemainingFld->setDisabled(false);
}
}
void PokemonUI::updateFlags(void) {
secondAbilityFlagCheckBox->setDisabled(abilityFld->count() == 1);
secondAbilityFlagCheckBox->setChecked(abilityFld->currentIndex() == 1);

View File

@ -100,11 +100,17 @@ protected:
private:
QTabWidget* tabs;
QWidget *generalTab, *metTab;
QFormLayout *generalTabLayout;
QWidget *generalTab;
QWidget *metTab;
QVBoxLayout *metTabLayout;
// "General" tab:
QVBoxLayout *generalTabLayout;
QTabWidget *generalSubTabs;
QWidget *generalCoreSubTab, *generalStatusSubTab;
QFormLayout *generalCoreSubTabLayout, *generalStatusSubTabLayout;
QComboBox *speciesFld;
QHBoxLayout* nameLayout;
QLineEdit* nameFld;
@ -123,9 +129,15 @@ private:
ItemComboBox* heldItemFld;
UnsignedSpinbox<8>* happinessFld;
UnsignedSpinbox<8>* pkrsStatusFld;
QHBoxLayout* pkrsStatusLayout;
UnsignedSpinbox<3>* pkrsDaysRemainingFld;
UnsignedSpinbox<4>* pkrsStrainFld;
QComboBox* statusFld;
QSpinBox* turnsOfBadPoisonFld;
QSpinBox* turnsOfSleepRemainingFld;
QSpinBox* partyPrksDaysRemainingFld;
QGridLayout *flagsLayout;
QButtonGroup *flagsButtonGroup;
@ -140,8 +152,10 @@ private:
// "Met" tab:
QGroupBox* coreCaptureInfoBox;
QFormLayout* coreCaptureInfoLayout;
ItemComboBox* ballCaughtWithFld;
UnsignedSpinbox<8>* locationCaughtFld;
ItemComboBox* ballCaughtWithFld;
UnsignedSpinbox<7>* levelMetFld;
QCheckBox* obedientFld;
QGroupBox* OTBox;
TrainerInfoLayout* OTField;
@ -172,7 +186,6 @@ private:
// "Moves" tab:
QWidget* movesTab;
QVBoxLayout* movesTabLayout;
//QHBoxLayout* movesTitleLayout;
PokemonMoveLayout* moveLayouts[4];
// "Ribbons" tab:
@ -197,6 +210,8 @@ public slots:
void updateLevelFromExperience(void);
void speciesChangeHandler(void);
void PIDChangeHandler(void);
void updatePkrsDaysRemaining(void);
void statusChangeHandler(void);
void updateFlags(void);
void flagsStateChangeHandler(void);

View File

@ -49,6 +49,10 @@ void StrategyMemoEntryWidget::generateShinyIDs(void) {
firstSIDFld->setUnsignedValue(PID & 0xffff);
}
void StrategyMemoEntryWidget::truncateMemoFromHere(void) {
speciesSelector->setCurrentIndex(0);
}
void StrategyMemoEntryWidget::initWidget(void) {
LanguageIndex lg = generateDumpedNamesLanguage();
mainLayout = new QVBoxLayout;
@ -63,6 +67,7 @@ void StrategyMemoEntryWidget::initWidget(void) {
firstPIDFld = new UnsignedSpinbox<32>;
PIDText = new QLabel;
generateShinyIDsButton = new QPushButton(tr("Generate shiny IDs"));
truncateMemoFromHereButton = new QPushButton(tr("Truncate memo from here"));
for (size_t i = 0; i <= 386; ++i)
speciesSelector->addItem(getPokemonSpeciesNameByPkdxIndex(lg, (u16)i));
@ -77,6 +82,7 @@ void StrategyMemoEntryWidget::initWidget(void) {
mainLayout2->addRow(tr("Partial information"), partialInfoCheckBox);
mainLayout->addLayout(mainLayout2);
mainLayout->addWidget(generateShinyIDsButton);
mainLayout->addWidget(truncateMemoFromHereButton);
mainLayout2->setHorizontalSpacing(20);
this->setLayout(mainLayout);
@ -87,6 +93,7 @@ void StrategyMemoEntryWidget::initWidget(void) {
connect(firstTIDFld, SIGNAL(valueChanged(int)), this, SLOT(updatePIDText()));
connect(firstSIDFld, SIGNAL(valueChanged(int)), this, SLOT(updatePIDText()));
connect(generateShinyIDsButton, SIGNAL(clicked()), this, SLOT(generateShinyIDs()));
connect(truncateMemoFromHereButton, SIGNAL(clicked()), this, SLOT(truncateMemoFromHere()));
}
StrategyMemoEntryWidget::~StrategyMemoEntryWidget(void) {

View File

@ -47,10 +47,11 @@ public:
signals:
void speciesChanged(int index, size_t nameIndex);
public slots:
public slots:
void speciesChangeHandler(int nameIndex);
void updatePIDText(void);
void generateShinyIDs(void);
void truncateMemoFromHere(void);
protected:
void initWidget(void);
@ -67,6 +68,7 @@ private:
UnsignedSpinbox<32> *firstPIDFld;
QLabel* PIDText;
QPushButton* generateShinyIDsButton;
QPushButton* truncateMemoFromHereButton;
};

View File

@ -39,6 +39,7 @@ void StrategyMemoUI::initWidget(void) {
entrySelector = new QComboBox;
nbEntriesFld = new UnsignedSpinbox<16>;
nbEntriesFld->setDisabled(true);
currentEntry = new StrategyMemoEntryWidget;
connect(currentEntry, SIGNAL(speciesChanged(int, size_t)), this, SLOT(updateEntryNameAndNbEntries(int, size_t)));

View File

@ -231,62 +231,76 @@
</message>
<message>
<location filename="../src/GCUIs/PokemonDisplayWidget.cpp" line="140"/>
<source>All supported files (*.colopkm *.xdpkm *.pkm *.3gpkm)</source>
<translation>All supported files (*.colopkm *.xdpkm *.pkm *.3gpkm)</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonDisplayWidget.cpp" line="141"/>
<source>Colosseum Pokémon files (*.colopkm)</source>
<translation>Colosseum Pokémon files (*.colopkm)</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonDisplayWidget.cpp" line="141"/>
<location filename="../src/GCUIs/PokemonDisplayWidget.cpp" line="142"/>
<source>XD Pokémon files (*.xdpkm)</source>
<translation>XD Pokémon files (*.xdpkm)</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonDisplayWidget.cpp" line="142"/>
<location filename="../src/GCUIs/PokemonDisplayWidget.cpp" line="143"/>
<source>GBA Pokémon files (*.pkm *.3gpkm)</source>
<translation>GBA Pokémon files (*.pkm *.3gpkm)</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonDisplayWidget.cpp" line="144"/>
<location filename="../src/GCUIs/PokemonDisplayWidget.cpp" line="174"/>
<source>Encrypted GBA Pokémon files (*.pkm *.3gpkm)</source>
<translation>Encrypted GBA Pokémon files (*.pkm *.3gpkm)</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonDisplayWidget.cpp" line="145"/>
<source>All files (*)</source>
<translation>All files (*)</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonDisplayWidget.cpp" line="149"/>
<location filename="../src/GCUIs/PokemonDisplayWidget.h" line="50"/>
<source>Could not open file.</source>
<translation>Could not open file.</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonDisplayWidget.cpp" line="150"/>
<location filename="../src/GCUIs/PokemonDisplayWidget.h" line="51"/>
<source>An error occured while reading the specified Pokémon file.</source>
<translation>An error occured while reading the specified Pokémon file.</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonDisplayWidget.cpp" line="152"/>
<location filename="../src/GCUIs/PokemonDisplayWidget.cpp" line="156"/>
<source>Open Pokémon file</source>
<translation>Open Pokémon file</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonDisplayWidget.cpp" line="160"/>
<location filename="../src/GCUIs/PokemonDisplayWidget.h" line="54"/>
<location filename="../src/GCUIs/PokemonDisplayWidget.h" line="60"/>
<location filename="../src/GCUIs/PokemonDisplayWidget.cpp" line="166"/>
<location filename="../src/GCUIs/PokemonDisplayWidget.cpp" line="179"/>
<location filename="../src/GCUIs/PokemonDisplayWidget.cpp" line="185"/>
<location filename="../src/GCUIs/PokemonDisplayWidget.cpp" line="196"/>
<location filename="../src/GCUIs/PokemonDisplayWidget.cpp" line="209"/>
<location filename="../src/GCUIs/PokemonDisplayWidget.cpp" line="231"/>
<location filename="../src/GCUIs/PokemonDisplayWidget.cpp" line="182"/>
<location filename="../src/GCUIs/PokemonDisplayWidget.cpp" line="216"/>
<source>Error</source>
<translation>Error</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonDisplayWidget.cpp" line="196"/>
<location filename="../src/GCUIs/PokemonDisplayWidget.cpp" line="166"/>
<source>Invalid file size.</source>
<translation>Invalid file size.</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonDisplayWidget.cpp" line="201"/>
<location filename="../src/GCUIs/PokemonDisplayWidget.cpp" line="172"/>
<source>Could not write to file.</source>
<translation>Could not write to file.</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonDisplayWidget.cpp" line="202"/>
<location filename="../src/GCUIs/PokemonDisplayWidget.cpp" line="173"/>
<source>An error occured while writing to the specified Pokémon file.</source>
<translation>An error occured while writing to the specified Pokémon file.</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonDisplayWidget.cpp" line="204"/>
<location filename="../src/GCUIs/PokemonDisplayWidget.cpp" line="177"/>
<source>Save Pokémon file</source>
<translation>Save Pokémon file</translation>
</message>
@ -295,7 +309,7 @@
<name>GCUIs::PokemonMoveLayout</name>
<message numerus="yes">
<location filename="../src/GCUIs/PokemonUI.cpp" line="13"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="53"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="64"/>
<source>(max. %n)</source>
<translation>
<numerusform>(max. %n)</numerusform>
@ -311,445 +325,481 @@
<context>
<name>GCUIs::PokemonUI</name>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="83"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="94"/>
<source>None</source>
<comment>Status</comment>
<translation>None</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="83"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="94"/>
<source>Poisoned</source>
<translation>Poisoned</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="83"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="94"/>
<source>Badly poisoned</source>
<translation>Badly poisoned</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="84"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="95"/>
<source>Paralyzed</source>
<translation>Paralyzed</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="84"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="95"/>
<source>Burnt</source>
<translation>Burnt</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="84"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="95"/>
<source>Frozen</source>
<translation>Frozen</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="84"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="95"/>
<source>Asleep</source>
<translation>Asleep</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="88"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="99"/>
<source>Coolness</source>
<translation>Coolness</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="88"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="99"/>
<source>Beauty</source>
<translation>Beauty</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="88"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="99"/>
<source>Cuteness</source>
<translation>Cuteness</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="89"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="100"/>
<source>Cleverness</source>
<translation>Cleverness</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="89"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="100"/>
<source>Toughness</source>
<translation>Toughness</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="91"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="102"/>
<source>None</source>
<comment>Contest</comment>
<translation>None</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="91"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="102"/>
<source>Normal</source>
<comment>Contest</comment>
<translation>Normal</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="92"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="103"/>
<source>Super</source>
<comment>Contest</comment>
<translation>Super</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="92"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="103"/>
<source>Hyper</source>
<comment>Contest</comment>
<translation>Hyper</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="93"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="104"/>
<source>Master</source>
<comment>Contest</comment>
<translation>Master</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="95"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="106"/>
<source>HP</source>
<translation>HP</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="95"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="106"/>
<source>Attack</source>
<translation>Attack</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="95"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="106"/>
<source>Defense</source>
<translation>Defense</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="96"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="107"/>
<source>S. Attack</source>
<translation>S. Attack</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="96"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="107"/>
<source>S. Defense</source>
<translation>S. Defense</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="96"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="107"/>
<source>Speed</source>
<translation>Speed</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="98"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="109"/>
<source>Champion</source>
<translation>Champion</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="98"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="109"/>
<source>Winning</source>
<translation>Winning</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="98"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="109"/>
<source>Victory</source>
<translation>Victory</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="98"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="109"/>
<source>Artist</source>
<translation>Artist</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="99"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="110"/>
<source>Effort</source>
<translation>Effort</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="99"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="110"/>
<source>Marine</source>
<translation>Marine</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="99"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="110"/>
<source>Land</source>
<translation>Land</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="99"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="110"/>
<source>Sky</source>
<translation>Sky</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="100"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="111"/>
<source>Country</source>
<translation>Country</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="100"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="111"/>
<source>National</source>
<translation>National</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="100"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="111"/>
<source>Earth</source>
<translation>Earth</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="100"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="111"/>
<source>World</source>
<translation>World</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="125"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="142"/>
<source>Reset</source>
<translation>Reset</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="165"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="187"/>
<source>Egg</source>
<translation>Egg</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="165"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="187"/>
<source>Second ability</source>
<translation>Second ability</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="166"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="188"/>
<source>Invalid Pokémon</source>
<translation>Invalid Pokémon</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="167"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="189"/>
<source>Not tradable in-game</source>
<translation>Not tradable in-game</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="167"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="189"/>
<source>Unknown</source>
<translation>Unknown</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="168"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="190"/>
<source>Caught</source>
<translation>Caught</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="193"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="215"/>
<source>Species</source>
<translation>Species</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="194"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="216"/>
<source>Name or nickname</source>
<translation>Name or nickname</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="195"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="217"/>
<source>PID</source>
<translation>PID</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="196"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="218"/>
<source>Attributes</source>
<translation>Attributes</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="197"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="219"/>
<source>Ability</source>
<translation>Ability</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="198"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="220"/>
<source>Experience and level</source>
<translation>Experience and level</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="199"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="221"/>
<source>Held item</source>
<translation>Held item</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="200"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="222"/>
<source>Happiness</source>
<translation>Happiness</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="201"/>
<source>Pokérus</source>
<translation>Pokérus</translation>
<location filename="../src/GCUIs/PokemonUI.cpp" line="281"/>
<source>Mew and Deoxys need this field to be checked so they can obey</source>
<translation>Mew and Deoxys need this field to be checked so they can obey</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="202"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="239"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="248"/>
<source>Status</source>
<translation>Status</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="203"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="224"/>
<source>Flags</source>
<translation>Flags</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="204"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="225"/>
<source>Markings</source>
<translation>Markings</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="212"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="240"/>
<source>Pokérus days remaining</source>
<translation>Pokérus days remaining</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="241"/>
<source>Turns of sleep remaining</source>
<translation>Turns of sleep remaining</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="242"/>
<source>Turns of bad poison</source>
<translation>Turns of bad poison</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="247"/>
<source>Core</source>
<translation>Core</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="257"/>
<source>Core information</source>
<translation>Core information</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="213"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="258"/>
<source>Original trainer</source>
<translation>Original trainer</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="214"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="259"/>
<source>Game version</source>
<translation>Game version</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="224"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="271"/>
<source>Copy info from save</source>
<translation>Copy info from save</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="225"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="272"/>
<source>Generate shiny IDs</source>
<translation>Generate shiny IDs</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="227"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="279"/>
<source>Ball caught with</source>
<translation>Ball caught with</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="228"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="276"/>
<source>Location caught</source>
<translation>Location caught</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="257"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="223"/>
<source>Pokérus (days remaing and strain)</source>
<translation>Pokérus (days remaing and strain)</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="277"/>
<source>Level met</source>
<translation>Level met</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="278"/>
<source>Fateful encounter (obedient)</source>
<translation>Fateful encounter (obedient)</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="309"/>
<source>IV</source>
<translation>IV</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="258"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="310"/>
<source>EV</source>
<translation>EV</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="259"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="311"/>
<source>Stat</source>
<translation>Stat</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="262"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="314"/>
<source>Current HP</source>
<translation>Current HP</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="269"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="321"/>
<source>Update stats automatically</source>
<translation>Update stats automatically</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="281"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="333"/>
<source>Luster</source>
<translation>Luster</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="288"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="340"/>
<source>Main stats</source>
<translation>Main stats</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="289"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="341"/>
<source>Contest stats</source>
<translation>Contest stats</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="308"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="360"/>
<source>Contest ribbons</source>
<translation>Contest ribbons</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="321"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="373"/>
<source>Contest type</source>
<translation>Contest type</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="322"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="374"/>
<source>Achievement</source>
<translation>Achievement</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="326"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="378"/>
<source>Special ribbons</source>
<translation>Special ribbons</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="352"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="403"/>
<source>General</source>
<translation>General</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="353"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="404"/>
<source>Met/OT</source>
<translation>Met/OT</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="354"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="405"/>
<source>Stats</source>
<translation>Stats</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="355"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="406"/>
<source>Moves</source>
<translation>Moves</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="356"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="407"/>
<source>Ribbons</source>
<translation>Ribbons</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="533"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="620"/>
<source>Genderless</source>
<translation>Genderless</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="549"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="636"/>
<source>Unown form: </source>
<translation>Unown form: </translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="554"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="641"/>
<source>will evolve into: </source>
<translation>will evolve into: </translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="566"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="590"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="653"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="677"/>
<source>Invalid version info</source>
<translation>Invalid version info</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="569"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="593"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="656"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="680"/>
<source>&quot;Invalid Pokémon&quot; flag set</source>
<translation>&quot;Invalid Pokémon&quot; flag set</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="719"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="841"/>
<source>Location caught (see &lt;a href=&apos;http://bulbapedia.bulbagarden.net/wiki/List_of_locations_by_index_number_(Generation_III)&apos;&gt;here&lt;/a&gt;)</source>
<translation>Location caught (see &lt;a href=&apos;http://bulbapedia.bulbagarden.net/wiki/List_of_locations_by_index_number_(Generation_III)&apos;&gt;here&lt;/a&gt;)</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="721"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="843"/>
<source>Location caught (see &lt;a href=&apos;http://bulbapedia.bulbagarden.net/wiki/List_of_locations_by_index_number_(GCN)&apos;&gt;here&lt;/a&gt;)</source>
<translation>Location caught (see &lt;a href=&apos;http://bulbapedia.bulbagarden.net/wiki/List_of_locations_by_index_number_(GCN)&apos;&gt;here&lt;/a&gt;)</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="726"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="848"/>
<source>Warning</source>
<translation>Warning</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="726"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="848"/>
<source>The version info you specified is invalid. The game will therefore consider this Pokémon invalid.</source>
<translation>The version info you specified is invalid. The game will therefore consider this Pokémon invalid.</translation>
</message>
@ -762,32 +812,37 @@
<translation>(randomly generated)</translation>
</message>
<message>
<location filename="../src/GCUIs/StrategyMemoEntryWidget.cpp" line="65"/>
<location filename="../src/GCUIs/StrategyMemoEntryWidget.cpp" line="69"/>
<source>Generate shiny IDs</source>
<translation>Generate shiny IDs</translation>
</message>
<message>
<location filename="../src/GCUIs/StrategyMemoEntryWidget.cpp" line="73"/>
<location filename="../src/GCUIs/StrategyMemoEntryWidget.cpp" line="70"/>
<source>Truncate memo from here</source>
<translation>Truncate memo from here</translation>
</message>
<message>
<location filename="../src/GCUIs/StrategyMemoEntryWidget.cpp" line="78"/>
<source>Species</source>
<translation>Species</translation>
</message>
<message>
<location filename="../src/GCUIs/StrategyMemoEntryWidget.cpp" line="74"/>
<location filename="../src/GCUIs/StrategyMemoEntryWidget.cpp" line="79"/>
<source>First TID</source>
<translation>First TID</translation>
</message>
<message>
<location filename="../src/GCUIs/StrategyMemoEntryWidget.cpp" line="75"/>
<location filename="../src/GCUIs/StrategyMemoEntryWidget.cpp" line="80"/>
<source>First SID</source>
<translation>First SID</translation>
</message>
<message>
<location filename="../src/GCUIs/StrategyMemoEntryWidget.cpp" line="76"/>
<location filename="../src/GCUIs/StrategyMemoEntryWidget.cpp" line="81"/>
<source>First PID</source>
<translation>First PID</translation>
</message>
<message>
<location filename="../src/GCUIs/StrategyMemoEntryWidget.cpp" line="77"/>
<location filename="../src/GCUIs/StrategyMemoEntryWidget.cpp" line="82"/>
<source>Partial information</source>
<translation>Partial information</translation>
</message>
@ -795,18 +850,18 @@
<context>
<name>GCUIs::StrategyMemoUI</name>
<message>
<location filename="../src/GCUIs/StrategyMemoUI.cpp" line="45"/>
<location filename="../src/GCUIs/StrategyMemoUI.cpp" line="63"/>
<location filename="../src/GCUIs/StrategyMemoUI.cpp" line="46"/>
<location filename="../src/GCUIs/StrategyMemoUI.cpp" line="64"/>
<source>#%1: %2</source>
<translation>#%1: %2</translation>
</message>
<message>
<location filename="../src/GCUIs/StrategyMemoUI.cpp" line="50"/>
<location filename="../src/GCUIs/StrategyMemoUI.cpp" line="51"/>
<source>Number of entries</source>
<translation>Number of entries</translation>
</message>
<message>
<location filename="../src/GCUIs/StrategyMemoUI.cpp" line="51"/>
<location filename="../src/GCUIs/StrategyMemoUI.cpp" line="52"/>
<source>Entry</source>
<translation>Entry</translation>
</message>

View File

@ -231,62 +231,76 @@
</message>
<message>
<location filename="../src/GCUIs/PokemonDisplayWidget.cpp" line="140"/>
<source>All supported files (*.colopkm *.xdpkm *.pkm *.3gpkm)</source>
<translation>Tous les fichiers pris en charge (*.colopkm *.xdpkm *.pkm *.3gpkm)</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonDisplayWidget.cpp" line="141"/>
<source>Colosseum Pokémon files (*.colopkm)</source>
<translation>Fichiers Pokémon de Colosseum (*.colopkm)</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonDisplayWidget.cpp" line="141"/>
<location filename="../src/GCUIs/PokemonDisplayWidget.cpp" line="142"/>
<source>XD Pokémon files (*.xdpkm)</source>
<translation>Fichier Pokémon d&apos;XD (*.xdpkm)</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonDisplayWidget.cpp" line="142"/>
<location filename="../src/GCUIs/PokemonDisplayWidget.cpp" line="143"/>
<source>GBA Pokémon files (*.pkm *.3gpkm)</source>
<translation>Fichiers Pokémon GBA (*.pkm *.3gpkm)</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonDisplayWidget.cpp" line="144"/>
<location filename="../src/GCUIs/PokemonDisplayWidget.cpp" line="174"/>
<source>Encrypted GBA Pokémon files (*.pkm *.3gpkm)</source>
<translation>Fichiers Pokémon GBA cryptés (*.pkm *.3gpkm)</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonDisplayWidget.cpp" line="145"/>
<source>All files (*)</source>
<translation>Tous les fichiers (*)</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonDisplayWidget.cpp" line="149"/>
<location filename="../src/GCUIs/PokemonDisplayWidget.h" line="50"/>
<source>Could not open file.</source>
<translation>Impossible d&apos;ouvrir le fichier.</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonDisplayWidget.cpp" line="150"/>
<location filename="../src/GCUIs/PokemonDisplayWidget.h" line="51"/>
<source>An error occured while reading the specified Pokémon file.</source>
<translation>Une erreur s&apos;est produite durant la lecture du fichier Pokémon.</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonDisplayWidget.cpp" line="152"/>
<location filename="../src/GCUIs/PokemonDisplayWidget.cpp" line="156"/>
<source>Open Pokémon file</source>
<translation>Ouvrir fichier Pokémon</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonDisplayWidget.cpp" line="160"/>
<location filename="../src/GCUIs/PokemonDisplayWidget.h" line="54"/>
<location filename="../src/GCUIs/PokemonDisplayWidget.h" line="60"/>
<location filename="../src/GCUIs/PokemonDisplayWidget.cpp" line="166"/>
<location filename="../src/GCUIs/PokemonDisplayWidget.cpp" line="179"/>
<location filename="../src/GCUIs/PokemonDisplayWidget.cpp" line="185"/>
<location filename="../src/GCUIs/PokemonDisplayWidget.cpp" line="196"/>
<location filename="../src/GCUIs/PokemonDisplayWidget.cpp" line="209"/>
<location filename="../src/GCUIs/PokemonDisplayWidget.cpp" line="231"/>
<location filename="../src/GCUIs/PokemonDisplayWidget.cpp" line="182"/>
<location filename="../src/GCUIs/PokemonDisplayWidget.cpp" line="216"/>
<source>Error</source>
<translation>Erreur</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonDisplayWidget.cpp" line="196"/>
<location filename="../src/GCUIs/PokemonDisplayWidget.cpp" line="166"/>
<source>Invalid file size.</source>
<translation>Taille de fichier invalide.</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonDisplayWidget.cpp" line="201"/>
<location filename="../src/GCUIs/PokemonDisplayWidget.cpp" line="172"/>
<source>Could not write to file.</source>
<translation>Impossible d&apos;écrire dans le fichier.</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonDisplayWidget.cpp" line="202"/>
<location filename="../src/GCUIs/PokemonDisplayWidget.cpp" line="173"/>
<source>An error occured while writing to the specified Pokémon file.</source>
<translation>Une erreur s&apos;est produite pendant l&apos;écriture des données sur le fichier Pokémon.</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonDisplayWidget.cpp" line="204"/>
<location filename="../src/GCUIs/PokemonDisplayWidget.cpp" line="177"/>
<source>Save Pokémon file</source>
<translation>Sauvegarder fichier Pokémon</translation>
</message>
@ -295,7 +309,7 @@
<name>GCUIs::PokemonMoveLayout</name>
<message numerus="yes">
<location filename="../src/GCUIs/PokemonUI.cpp" line="13"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="53"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="64"/>
<source>(max. %n)</source>
<translation>
<numerusform>(max. %n)</numerusform>
@ -311,445 +325,481 @@
<context>
<name>GCUIs::PokemonUI</name>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="83"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="94"/>
<source>None</source>
<comment>Status</comment>
<translation>Aucun</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="83"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="94"/>
<source>Poisoned</source>
<translation>Empoisonné</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="83"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="94"/>
<source>Badly poisoned</source>
<translation>Gravement empoisonné</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="84"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="95"/>
<source>Paralyzed</source>
<translation>Paralysé</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="84"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="95"/>
<source>Burnt</source>
<translation>Brûlé</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="84"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="95"/>
<source>Frozen</source>
<translation>Gelé</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="84"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="95"/>
<source>Asleep</source>
<translation>Endormi</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="88"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="99"/>
<source>Coolness</source>
<translation>Sang-froid</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="88"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="99"/>
<source>Beauty</source>
<translation>Beauté</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="88"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="99"/>
<source>Cuteness</source>
<translation>Grâce</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="89"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="100"/>
<source>Cleverness</source>
<translation>Intelligence</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="89"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="100"/>
<source>Toughness</source>
<translation>Robustesse</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="91"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="102"/>
<source>None</source>
<comment>Contest</comment>
<translation>Aucun</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="91"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="102"/>
<source>Normal</source>
<comment>Contest</comment>
<translation>Normal</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="92"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="103"/>
<source>Super</source>
<comment>Contest</comment>
<translation>Super</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="92"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="103"/>
<source>Hyper</source>
<comment>Contest</comment>
<translation>Hyper</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="93"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="104"/>
<source>Master</source>
<comment>Contest</comment>
<translation>Master</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="95"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="106"/>
<source>HP</source>
<translation>PV</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="95"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="106"/>
<source>Attack</source>
<translation>Attaque</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="95"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="106"/>
<source>Defense</source>
<translation>Défense</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="96"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="107"/>
<source>S. Attack</source>
<translation>Attaque Spé.</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="96"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="107"/>
<source>S. Defense</source>
<translation>Défense spé.</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="96"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="107"/>
<source>Speed</source>
<translation>Vitesse</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="98"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="109"/>
<source>Champion</source>
<translation>Maître</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="98"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="109"/>
<source>Winning</source>
<translation>Victoire 1</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="98"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="109"/>
<source>Victory</source>
<translation>Victoire 2</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="98"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="109"/>
<source>Artist</source>
<translation>Artiste</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="99"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="110"/>
<source>Effort</source>
<translation></translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="99"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="110"/>
<source>Marine</source>
<translation>Marin</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="99"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="110"/>
<source>Land</source>
<translation>Terrestre</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="99"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="110"/>
<source>Sky</source>
<translation>Céleste</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="100"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="111"/>
<source>Country</source>
<translation>Régional</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="100"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="111"/>
<source>National</source>
<translation>National</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="100"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="111"/>
<source>Earth</source>
<translation>Terre</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="100"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="111"/>
<source>World</source>
<translation>Monde</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="125"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="142"/>
<source>Reset</source>
<translation>RaZ</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="165"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="187"/>
<source>Egg</source>
<translation>Œuf</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="165"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="187"/>
<source>Second ability</source>
<translation>Second talent</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="166"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="188"/>
<source>Invalid Pokémon</source>
<translation>Pokémon invalide</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="167"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="189"/>
<source>Not tradable in-game</source>
<translation>Non échangeable en interne</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="167"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="189"/>
<source>Unknown</source>
<translation>Inconnu</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="168"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="190"/>
<source>Caught</source>
<translation>Capturé</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="193"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="215"/>
<source>Species</source>
<translation>Espèce</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="194"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="216"/>
<source>Name or nickname</source>
<translation>Nom ou surnom</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="195"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="217"/>
<source>PID</source>
<translation>PID</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="196"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="218"/>
<source>Attributes</source>
<translation>Caractéristiques</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="197"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="219"/>
<source>Ability</source>
<translation>Talent</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="198"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="220"/>
<source>Experience and level</source>
<translation>Expérience et niveau</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="199"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="221"/>
<source>Held item</source>
<translation>Objet tenu</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="200"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="222"/>
<source>Happiness</source>
<translation>Bonheur</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="201"/>
<source>Pokérus</source>
<translation>Pokérus</translation>
<location filename="../src/GCUIs/PokemonUI.cpp" line="281"/>
<source>Mew and Deoxys need this field to be checked so they can obey</source>
<translation>Cette case doit être cochée afin que Mew et Deoxys puissent obéir</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="202"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="239"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="248"/>
<source>Status</source>
<translation>Statut</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="203"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="224"/>
<source>Flags</source>
<translation>Drapeaux</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="204"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="225"/>
<source>Markings</source>
<translation>Marques</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="212"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="240"/>
<source>Pokérus days remaining</source>
<translation>Jours restants de Pokérus</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="241"/>
<source>Turns of sleep remaining</source>
<translation>Tours de sommeil restants</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="242"/>
<source>Turns of bad poison</source>
<translation>Tours de poison grave</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="247"/>
<source>Core</source>
<translation>Essentiel</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="257"/>
<source>Core information</source>
<translation>Informations essentielles</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="213"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="258"/>
<source>Original trainer</source>
<translation>Dresseur d&apos;origine</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="214"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="259"/>
<source>Game version</source>
<translation>Version du jeu</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="224"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="271"/>
<source>Copy info from save</source>
<translation>Recopier les infos à partir de la sauvegarde</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="225"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="272"/>
<source>Generate shiny IDs</source>
<translation>Générer des IDs rendant ce Pokémon shiny</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="227"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="279"/>
<source>Ball caught with</source>
<translation>Pokéball utilisée</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="228"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="276"/>
<source>Location caught</source>
<translation>Lieu de capture</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="257"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="223"/>
<source>Pokérus (days remaing and strain)</source>
<translation>Pokérus (jours restants et forme)</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="277"/>
<source>Level met</source>
<translation>Rencontré au niveau</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="278"/>
<source>Fateful encounter (obedient)</source>
<translation>Rencontré par hasard (obéissant)</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="309"/>
<source>IV</source>
<translation>IV</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="258"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="310"/>
<source>EV</source>
<translation>EV</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="259"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="311"/>
<source>Stat</source>
<translation>Statistique</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="262"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="314"/>
<source>Current HP</source>
<translation>PVs actuels</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="269"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="321"/>
<source>Update stats automatically</source>
<translation>Mettre à jour les statistiques automatiquement</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="281"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="333"/>
<source>Luster</source>
<translation>Lustre</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="288"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="340"/>
<source>Main stats</source>
<translation>Statistiques principales</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="289"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="341"/>
<source>Contest stats</source>
<translation>Statistiques de concours</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="308"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="360"/>
<source>Contest ribbons</source>
<translation>Rubans de concours</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="321"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="373"/>
<source>Contest type</source>
<translation>Type de concours</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="322"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="374"/>
<source>Achievement</source>
<translation>Avancement</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="326"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="378"/>
<source>Special ribbons</source>
<translation>Rubans spéciaux</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="352"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="403"/>
<source>General</source>
<translation>Général</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="353"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="404"/>
<source>Met/OT</source>
<translation>Infos de rencontre/D.O</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="354"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="405"/>
<source>Stats</source>
<translation>Statistiques</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="355"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="406"/>
<source>Moves</source>
<translation>Attaques</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="356"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="407"/>
<source>Ribbons</source>
<translation>Rubans</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="533"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="620"/>
<source>Genderless</source>
<translation>Asexué</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="549"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="636"/>
<source>Unown form: </source>
<translation>Forme Zarbi : </translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="554"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="641"/>
<source>will evolve into: </source>
<translation>évoluera en : </translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="566"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="590"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="653"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="677"/>
<source>Invalid version info</source>
<translation>Infos de version invalides</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="569"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="593"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="656"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="680"/>
<source>&quot;Invalid Pokémon&quot; flag set</source>
<translation>Drapeau &quot;Pokémon invalide&quot; activé</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="719"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="841"/>
<source>Location caught (see &lt;a href=&apos;http://bulbapedia.bulbagarden.net/wiki/List_of_locations_by_index_number_(Generation_III)&apos;&gt;here&lt;/a&gt;)</source>
<translation>Lieu de capture (cf. &lt;a href=&apos;http://bulbapedia.bulbagarden.net/wiki/List_of_locations_by_index_number_(Generation_III)&apos;&gt;Bulbapedia&lt;/a&gt;)</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="721"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="843"/>
<source>Location caught (see &lt;a href=&apos;http://bulbapedia.bulbagarden.net/wiki/List_of_locations_by_index_number_(GCN)&apos;&gt;here&lt;/a&gt;)</source>
<translation>Lieu de capture (cf. &lt;a href=&apos;http://bulbapedia.bulbagarden.net/wiki/List_of_locations_by_index_number_(GCN)&apos;&gt;Bulbapedia&lt;/a&gt;)</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="726"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="848"/>
<source>Warning</source>
<translation>Avertissement</translation>
</message>
<message>
<location filename="../src/GCUIs/PokemonUI.cpp" line="726"/>
<location filename="../src/GCUIs/PokemonUI.cpp" line="848"/>
<source>The version info you specified is invalid. The game will therefore consider this Pokémon invalid.</source>
<translation>Les informations sur la version du jeu que vous avez entrées sont invalides. Le jeu considérera de ce fait ce Pokémon invalide.</translation>
</message>
@ -762,32 +812,37 @@
<translation>(géneré aléatoirement)</translation>
</message>
<message>
<location filename="../src/GCUIs/StrategyMemoEntryWidget.cpp" line="65"/>
<location filename="../src/GCUIs/StrategyMemoEntryWidget.cpp" line="69"/>
<source>Generate shiny IDs</source>
<translation>Générer des IDs rendant ce Pokémon shiny</translation>
</message>
<message>
<location filename="../src/GCUIs/StrategyMemoEntryWidget.cpp" line="73"/>
<location filename="../src/GCUIs/StrategyMemoEntryWidget.cpp" line="70"/>
<source>Truncate memo from here</source>
<translation>Tronquer le Mémo à partir d&apos;ici</translation>
</message>
<message>
<location filename="../src/GCUIs/StrategyMemoEntryWidget.cpp" line="78"/>
<source>Species</source>
<translation>Espèce</translation>
</message>
<message>
<location filename="../src/GCUIs/StrategyMemoEntryWidget.cpp" line="74"/>
<location filename="../src/GCUIs/StrategyMemoEntryWidget.cpp" line="79"/>
<source>First TID</source>
<translation>Premier TID</translation>
</message>
<message>
<location filename="../src/GCUIs/StrategyMemoEntryWidget.cpp" line="75"/>
<location filename="../src/GCUIs/StrategyMemoEntryWidget.cpp" line="80"/>
<source>First SID</source>
<translation>Premier SID</translation>
</message>
<message>
<location filename="../src/GCUIs/StrategyMemoEntryWidget.cpp" line="76"/>
<location filename="../src/GCUIs/StrategyMemoEntryWidget.cpp" line="81"/>
<source>First PID</source>
<translation>Premier PID</translation>
</message>
<message>
<location filename="../src/GCUIs/StrategyMemoEntryWidget.cpp" line="77"/>
<location filename="../src/GCUIs/StrategyMemoEntryWidget.cpp" line="82"/>
<source>Partial information</source>
<translation>Informations partielles</translation>
</message>
@ -795,18 +850,18 @@
<context>
<name>GCUIs::StrategyMemoUI</name>
<message>
<location filename="../src/GCUIs/StrategyMemoUI.cpp" line="45"/>
<location filename="../src/GCUIs/StrategyMemoUI.cpp" line="63"/>
<location filename="../src/GCUIs/StrategyMemoUI.cpp" line="46"/>
<location filename="../src/GCUIs/StrategyMemoUI.cpp" line="64"/>
<source>#%1: %2</source>
<translation>#%1 : %2</translation>
</message>
<message>
<location filename="../src/GCUIs/StrategyMemoUI.cpp" line="50"/>
<location filename="../src/GCUIs/StrategyMemoUI.cpp" line="51"/>
<source>Number of entries</source>
<translation>Nombre d&apos;entrées</translation>
</message>
<message>
<location filename="../src/GCUIs/StrategyMemoUI.cpp" line="51"/>
<location filename="../src/GCUIs/StrategyMemoUI.cpp" line="52"/>
<source>Entry</source>
<translation>Entrée</translation>
</message>