Backwards-compatible BoxPokémon Refactor (#3438)

* Check progress in non-battle PARAMETRIZEd tests

* Overworld Script Tests

* Backward-compatible BoxPokemon Refactor

Reuses space that contains zeros to provide space for:
- HP/status in the box
- 12-character nicknames
- Up to 63 PokéBalls
- Shininess separate from PID
- Hidden Nature
- Hyper Training
- Dynamax Level
- Gigantamax Factor
- Terastallization Types
- Shadow

Implements:
- OW_PC_HEAL to switch between Gen7- and Gen8+ behavior
- Nature Mints
- Dynamax Candy
- Hyper Training commands (canhypertrain/hypertrain)
- Gigantamax Factor commands (hasgigantamaxfactor/togglegigantamaxfactor)
- Terastallization Type on the summary screen
- Prevents Gigantamax Factor Pokémon from evolving into a species without a Gigantamax form

* fixup! Backward-compatible BoxPokemon Refactor

* displaydexinfo fix from Jasper
This commit is contained in:
Martin Griffin 2023-12-27 16:48:17 +00:00 committed by GitHub
parent a9d6832908
commit 3ad66028e9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
66 changed files with 1437 additions and 514 deletions

View File

@ -2025,3 +2025,33 @@
callnative CreateTrainerPartyForPlayer
trainerbattle_no_intro \trainer2, NULL
.endm
@ Sets VAR_RESULT to TRUE if stat can be hyper trained, or to
@ FALSE otherwise.
.macro canhypertrain stat:req, slot:req
callnative CanHyperTrain
.byte \stat
.2byte \slot
.endm
@ Hyper Trains a stat.
.macro hypertrain stat:req, slot:req
callnative HyperTrain
.byte \stat
.2byte \slot
.endm
@ Sets VAR_RESULT to TRUE if the Pokemon has the Gigantamax Factor,
@ or to FALSE otherwise.
.macro hasgigantamaxfactor slot:req
callnative HasGigantamaxFactor
.2byte \slot
.endm
@ Toggles the Gigantamax Factor for a Pokemon.
@ Fails for Melmetal (vanilla behavior).
@ Sets VAR_RESULT to TRUE if it succeeds, and FALSE otherwise.
.macro togglegigantamaxfactor slot:req
callnative ToggleGigantamaxFactor
.2byte \slot
.endm

View File

@ -65,7 +65,7 @@ struct ResourceFlags
struct DisableStruct
{
u32 transformedMonPersonality;
u32 transformedMonOtId;
bool8 transformedMonShininess;
u16 disabledMove;
u16 encoredMove;
u8 protectUses:4;
@ -1066,7 +1066,7 @@ extern u8 gBattlerStatusSummaryTaskId[MAX_BATTLERS_COUNT];
extern u8 gBattlerInMenuId;
extern bool8 gDoingBattleAnim;
extern u32 gTransformedPersonalities[MAX_BATTLERS_COUNT];
extern u32 gTransformedOtIds[MAX_BATTLERS_COUNT];
extern bool8 gTransformedShininess[MAX_BATTLERS_COUNT];
extern u8 gPlayerDpadHoldFrames;
extern struct BattleSpriteData *gBattleSpritesDataPtr;
extern struct MonSpritesGfx *gMonSpritesGfxPtr;

View File

@ -159,7 +159,7 @@ void PrepareAffineAnimInTaskData(struct Task *task, u8 spriteId, const union Aff
bool8 RunAffineAnimFromTaskData(struct Task *task);
void AnimThrowProjectile(struct Sprite *sprite);
void GetBgDataForTransform(struct BattleAnimBgData *dest, u8 battlerId);
u8 CreateAdditionalMonSpriteForMoveAnim(u16 species, bool8 isBackpic, u8 id, s16 x, s16 y, u8 subpriority, u32 personality, u32 trainerId, u32 battlerId);
u8 CreateAdditionalMonSpriteForMoveAnim(u16 species, bool8 isBackpic, u8 id, s16 x, s16 y, u8 subpriority, u32 personality, bool8 isShiny, u32 battlerId);
void ResetSpriteRotScale_PreserveAffine(struct Sprite *sprite);
void Trade_MoveSelectedMonToTarget(struct Sprite *sprite);
void DestroyAnimVisualTaskAndDisableBlend(u8 taskId);

View File

@ -11,6 +11,7 @@
// PC settings
#define OW_PC_PRESS_B GEN_LATEST // In Gen4, pressing B when holding a Pokémon is equivalent to placing it. In Gen3, it gives the "You're holding a Pokémon!" error.
#define OW_PC_JAPAN_WALDA_ICONS TRUE // In the US release of Emerald, the Cross, Bolt, and Plusle icons for Walda's wallpapers were left blank from the Japan release. Setting this to TRUE will restore them.
#define OW_PC_HEAL GEN_LATEST // In Gen8+, Pokémon are not healed when deposited in the PC.
// Out-of-battle Ability effects
#define OW_SYNCHRONIZE_NATURE GEN_LATEST // In Gen8, if a Pokémon with Synchronize is leading the party, it's 100% guaranteed that wild Pokémon will have the same Nature, as opposed to 50% previously. Stationary Pokémon are excluded in Gen3. In Gen6, all No Eggs Discovered gift Pokémon will have the same Nature, while in Gen7 all gift Pokémon will, regardless of Egg Group - In Gen 8, no gift Pokémon are affected. In Gen9, this ability has no out-of-battle effect.

View File

@ -32,6 +32,7 @@
#define P_LEGENDARY_PERFECT_IVS GEN_LATEST // Since Gen 6, Legendaries, Mythicals and Ultra Beasts found in the wild or given through gifts have at least 3 perfect IVs.
#define P_EV_CAP GEN_LATEST // Since Gen 6, the max EVs per stat is 252 instead of 255.
#define P_CATCH_CURVE GEN_LATEST // Since Gen 6, the capture rate curve was changed to make pokeballs more effective on lower level pokemon
#define P_SHOW_TERA_TYPE GEN_LATEST // Since Gen 9, the Tera Type is shown on the summary screen.
// Flag settings
// To use the following features in scripting, replace the 0s with the flag ID you're assigning it to.

View File

@ -104,7 +104,10 @@
#define B_OUTCOME_LINK_BATTLE_RAN (1 << 7) // 128
// Non-volatile status conditions
// These persist remain outside of battle and after switching out
// These remain outside of battle and after switching out.
// If a new STATUS1 is added here, it should also be added to
// sCompressedStatuses in src/pokemon.c or else it will be lost outside
// of battle.
#define STATUS1_NONE 0
#define STATUS1_SLEEP (1 << 0 | 1 << 1 | 1 << 2) // First 3 bits (Number of turns to sleep)
#define STATUS1_SLEEP_TURN(num) ((num) << 0) // Just for readability (or if rearranging statuses)

View File

@ -24,6 +24,8 @@
#define VERSION_PLATINUM 12
#define VERSION_GAMECUBE 15
#define NUM_VERSIONS 15
#define LANGUAGE_JAPANESE 1
#define LANGUAGE_ENGLISH 2
#define LANGUAGE_FRENCH 3

View File

@ -1014,6 +1014,8 @@
#define MOVES_COUNT_DYNAMAX (LAST_MAX_MOVE + 1)
#define MOVES_COUNT_ALL MOVES_COUNT_DYNAMAX
// Used for checks for moves affected by Disable, Mimic, etc.
#define MOVE_UNAVAILABLE 0xFFFF

View File

@ -146,6 +146,8 @@
#define MIN_LEVEL 1
#define MAX_LEVEL 100
#define MAX_DYNAMAX_LEVEL 10
#define OT_ID_PLAYER_ID 0
#define OT_ID_PRESET 1
#define OT_ID_RANDOM_NO_SHINY 2

View File

@ -107,7 +107,9 @@ struct ContestPokemon
u8 sheen;
u8 highestRank;
bool8 gameCleared;
u8 unused[10];
u8 isShiny:1;
u8 unused1:7;
u8 unused2[9];
u32 personality;
u32 otId;
};
@ -125,6 +127,8 @@ struct ContestMoveAnimData
u16 species;
u16 targetSpecies;
bool8 hasTargetAnim:1;
u8 isShiny:1;
u8 targetIsShiny:1;
u8 contestant;
u32 personality;
u32 otId;

View File

@ -66,6 +66,8 @@ struct TrainerMon
u8 nature : 5;
bool8 gender : 2;
bool8 isShiny : 1;
u8 dynamaxLevel : 4;
bool8 gigantamaxFactor : 1;
};
#define TRAINER_PARTY(partyArray) partyArray, .partySize = ARRAY_COUNT(partyArray)

View File

@ -129,8 +129,8 @@
#define CAT(a, b) CAT_(a, b)
#define CAT_(a, b) a ## b
#define STR(a) STR_(a)
#define STR_(a) #a
#define STR(...) STR_(__VA_ARGS__)
#define STR_(...) #__VA_ARGS__
// Converts a string to a compound literal, essentially making it a pointer to const u8
#define COMPOUND_STRING(str) (const u8[]) _(str)
@ -738,7 +738,8 @@ struct ContestWinner
u8 contestCategory;
u8 monName[POKEMON_NAME_LENGTH + 1];
u8 trainerName[PLAYER_NAME_LENGTH + 1];
u8 contestRank;
u8 contestRank:7;
bool8 isShiny:1;
//u8 padding;
};

View File

@ -13,12 +13,14 @@ void ItemUseOutOfBattle_WailmerPail(u8);
void ItemUseOutOfBattle_Medicine(u8);
void ItemUseOutOfBattle_AbilityCapsule(u8);
void ItemUseOutOfBattle_AbilityPatch(u8);
void ItemUseOutOfBattle_Mint(u8);
void ItemUseOutOfBattle_ResetEVs(u8);
void ItemUseOutOfBattle_ReduceEV(u8);
void ItemUseOutOfBattle_SacredAsh(u8);
void ItemUseOutOfBattle_PPRecovery(u8);
void ItemUseOutOfBattle_PPUp(u8);
void ItemUseOutOfBattle_RareCandy(u8);
void ItemUseOutOfBattle_DynamaxCandy(u8);
void ItemUseOutOfBattle_TMHM(u8);
void ItemUseOutOfBattle_Repel(u8);
void ItemUseOutOfBattle_Lure(u8);

View File

@ -53,6 +53,7 @@ void ItemUseCB_BattleChooseMove(u8 taskId, TaskFunc task);
void ItemUseCB_Medicine(u8 taskId, TaskFunc task);
void ItemUseCB_AbilityCapsule(u8 taskId, TaskFunc task);
void ItemUseCB_AbilityPatch(u8 taskId, TaskFunc task);
void ItemUseCB_Mint(u8 taskId, TaskFunc task);
void ItemUseCB_ResetEVs(u8 taskId, TaskFunc task);
void ItemUseCB_ReduceEV(u8 taskId, TaskFunc task);
void ItemUseCB_PPRecovery(u8 taskId, TaskFunc task);
@ -62,6 +63,7 @@ bool8 MonKnowsMove(struct Pokemon *mon, u16 move);
bool8 BoxMonKnowsMove(struct BoxPokemon *boxMon, u16 move);
void ItemUseCB_TMHM(u8 taskId, TaskFunc task);
void ItemUseCB_RareCandy(u8 taskId, TaskFunc task);
void ItemUseCB_DynamaxCandy(u8 taskId, TaskFunc task);
void ItemUseCB_SacredAsh(u8 taskId, TaskFunc task);
void ItemUseCB_EvolutionStone(u8 taskId, TaskFunc task);
void ItemUseCB_FormChange(u8 taskId, TaskFunc task);

View File

@ -21,7 +21,7 @@ enum
void ResetPokedex(void);
u16 GetNationalPokedexCount(u8);
u16 GetHoennPokedexCount(u8);
u8 DisplayCaughtMonDexPage(u16 species, u32 otId, u32 personality);
u8 DisplayCaughtMonDexPage(u16 species, bool32 isShiny, u32 personality);
s8 GetSetPokedexFlag(u16 nationalNum, u8 caseId);
u16 CreateMonSpriteFromNationalDexNumber(u16, s16, s16, u16);
bool16 HasAllHoennMons(void);

View File

@ -12,8 +12,8 @@
// Property labels for Get(Box)MonData / Set(Box)MonData
enum {
MON_DATA_PERSONALITY,
MON_DATA_STATUS,
MON_DATA_OT_ID,
MON_DATA_NICKNAME,
MON_DATA_LANGUAGE,
MON_DATA_SANITY_IS_BAD_EGG,
MON_DATA_SANITY_HAS_SPECIES,
@ -21,7 +21,12 @@ enum {
MON_DATA_OT_NAME,
MON_DATA_MARKINGS,
MON_DATA_CHECKSUM,
MON_DATA_HP,
MON_DATA_IS_SHINY,
MON_DATA_HIDDEN_NATURE,
MON_DATA_HP_LOST,
MON_DATA_ENCRYPT_SEPARATOR,
MON_DATA_NICKNAME,
MON_DATA_SPECIES,
MON_DATA_HELD_ITEM,
MON_DATA_MOVE1,
@ -66,9 +71,7 @@ enum {
MON_DATA_CUTE_RIBBON,
MON_DATA_SMART_RIBBON,
MON_DATA_TOUGH_RIBBON,
MON_DATA_STATUS,
MON_DATA_LEVEL,
MON_DATA_HP,
MON_DATA_MAX_HP,
MON_DATA_ATK,
MON_DATA_DEF,
@ -90,7 +93,6 @@ enum {
MON_DATA_NATIONAL_RIBBON,
MON_DATA_EARTH_RIBBON,
MON_DATA_WORLD_RIBBON,
MON_DATA_UNUSED_RIBBONS,
MON_DATA_MODERN_FATEFUL_ENCOUNTER,
MON_DATA_KNOWN_MOVES,
MON_DATA_RIBBON_COUNT,
@ -100,87 +102,116 @@ enum {
MON_DATA_SPEED2,
MON_DATA_SPATK2,
MON_DATA_SPDEF2,
MON_DATA_HYPER_TRAINED_HP,
MON_DATA_HYPER_TRAINED_ATK,
MON_DATA_HYPER_TRAINED_DEF,
MON_DATA_HYPER_TRAINED_SPEED,
MON_DATA_HYPER_TRAINED_SPATK,
MON_DATA_HYPER_TRAINED_SPDEF,
MON_DATA_IS_SHADOW,
MON_DATA_DYNAMAX_LEVEL,
MON_DATA_GIGANTAMAX_FACTOR,
MON_DATA_TERA_TYPE,
};
struct PokemonSubstruct0
{
/*0x00*/ u16 species;
/*0x02*/ u16 heldItem;
/*0x04*/ u32 experience;
/*0x08*/ u8 ppBonuses;
/*0x09*/ u8 friendship;
/*0x0A*/ u16 pokeball:5; //31 balls
u16 filler:11;
}; /* size = 12 */
u16 species:11; // 2047 species.
u16 teraType:5; // 30 types.
u16 heldItem:10; // 1023 items.
u16 unused_02:6;
u32 experience:21;
u32 nickname11:8; // 11th character of nickname.
u32 unused_04:3;
u8 ppBonuses;
u8 friendship;
u16 pokeball:6; // 63 balls.
u16 nickname12:8; // 12th character of nickname.
u16 unused_0A:2;
};
struct PokemonSubstruct1
{
/*0x00*/ u16 moves[MAX_MON_MOVES];
/*0x08*/ u8 pp[MAX_MON_MOVES];
}; /* size = 12 */
u16 move1:11; // 2047 moves.
u16 unused_00:5;
u16 move2:11; // 2047 moves.
u16 unused_02:5;
u16 move3:11; // 2047 moves.
u16 unused_04:5;
u16 move4:11; // 2047 moves.
u16 unused_06:3;
u16 hyperTrainedHP:1;
u16 hyperTrainedAttack:1;
u8 pp1:7; // 127 PP.
u8 hyperTrainedDefense:1;
u8 pp2:7; // 127 PP.
u8 hyperTrainedSpeed:1;
u8 pp3:7; // 127 PP.
u8 hyperTrainedSpAttack:1;
u8 pp4:7; // 127 PP.
u8 hyperTrainedSpDefense:1;
};
struct PokemonSubstruct2
{
/*0x00*/ u8 hpEV;
/*0x01*/ u8 attackEV;
/*0x02*/ u8 defenseEV;
/*0x03*/ u8 speedEV;
/*0x04*/ u8 spAttackEV;
/*0x05*/ u8 spDefenseEV;
/*0x06*/ u8 cool;
/*0x07*/ u8 beauty;
/*0x08*/ u8 cute;
/*0x09*/ u8 smart;
/*0x0A*/ u8 tough;
/*0x0B*/ u8 sheen;
}; /* size = 12 */
u8 hpEV;
u8 attackEV;
u8 defenseEV;
u8 speedEV;
u8 spAttackEV;
u8 spDefenseEV;
u8 cool;
u8 beauty;
u8 cute;
u8 smart;
u8 tough;
u8 sheen;
};
struct PokemonSubstruct3
{
/* 0x00 */ u8 pokerus;
/* 0x01 */ u8 metLocation;
u8 pokerus;
u8 metLocation;
u16 metLevel:7;
u16 metGame:4;
u16 dynamaxLevel:4;
u16 otGender:1;
u32 hpIV:5;
u32 attackIV:5;
u32 defenseIV:5;
u32 speedIV:5;
u32 spAttackIV:5;
u32 spDefenseIV:5;
u32 isEgg:1;
u32 gigantamaxFactor:1;
u32 coolRibbon:3; // Stores the highest contest rank achieved in the Cool category.
u32 beautyRibbon:3; // Stores the highest contest rank achieved in the Beauty category.
u32 cuteRibbon:3; // Stores the highest contest rank achieved in the Cute category.
u32 smartRibbon:3; // Stores the highest contest rank achieved in the Smart category.
u32 toughRibbon:3; // Stores the highest contest rank achieved in the Tough category.
u32 championRibbon:1; // Given when defeating the Champion. Because both RSE and FRLG use it, later generations don't specify from which region it comes from.
u32 winningRibbon:1; // Given at the Battle Tower's Level 50 challenge by winning a set of seven battles that extends the current streak to 56 or more.
u32 victoryRibbon:1; // Given at the Battle Tower's Level 100 challenge by winning a set of seven battles that extends the current streak to 56 or more.
u32 artistRibbon:1; // Given at the Contest Hall by winning a Master Rank contest with at least 800 points, and agreeing to have the Pokémon's portrait placed in the museum after being offered.
u32 effortRibbon:1; // Given at Slateport's market to Pokémon with maximum EVs.
u32 marineRibbon:1; // Never distributed.
u32 landRibbon:1; // Never distributed.
u32 skyRibbon:1; // Never distributed.
u32 countryRibbon:1; // Distributed during Pokémon Festa '04 and '05 to tournament winners.
u32 nationalRibbon:1; // Given to purified Shadow Pokémon in Colosseum/XD.
u32 earthRibbon:1; // Given to teams that have beaten Mt. Battle's 100-battle challenge in Colosseum/XD.
u32 worldRibbon:1; // Distributed during Pokémon Festa '04 and '05 to tournament winners.
u32 isShadow:1;
u32 unused_0B:1;
u32 abilityNum:2;
/* 0x02 */ u16 metLevel:7;
/* 0x02 */ u16 metGame:4;
/* 0x03 */ u16 unused1:4;
/* 0x03 */ u16 otGender:1;
/* 0x04 */ u32 hpIV:5;
/* 0x04 */ u32 attackIV:5;
/* 0x05 */ u32 defenseIV:5;
/* 0x05 */ u32 speedIV:5;
/* 0x05 */ u32 spAttackIV:5;
/* 0x06 */ u32 spDefenseIV:5;
/* 0x07 */ u32 isEgg:1;
/* 0x07 */ u32 unused2:1;
/* 0x08 */ u32 coolRibbon:3; // Stores the highest contest rank achieved in the Cool category.
/* 0x08 */ u32 beautyRibbon:3; // Stores the highest contest rank achieved in the Beauty category.
/* 0x08 */ u32 cuteRibbon:3; // Stores the highest contest rank achieved in the Cute category.
/* 0x09 */ u32 smartRibbon:3; // Stores the highest contest rank achieved in the Smart category.
/* 0x09 */ u32 toughRibbon:3; // Stores the highest contest rank achieved in the Tough category.
/* 0x09 */ u32 championRibbon:1; // Given when defeating the Champion. Because both RSE and FRLG use it, later generations don't specify from which region it comes from.
/* 0x0A */ u32 winningRibbon:1; // Given at the Battle Tower's Level 50 challenge by winning a set of seven battles that extends the current streak to 56 or more.
/* 0x0A */ u32 victoryRibbon:1; // Given at the Battle Tower's Level 100 challenge by winning a set of seven battles that extends the current streak to 56 or more.
/* 0x0A */ u32 artistRibbon:1; // Given at the Contest Hall by winning a Master Rank contest with at least 800 points, and agreeing to have the Pokémon's portrait placed in the museum after being offered.
/* 0x0A */ u32 effortRibbon:1; // Given at Slateport's market to Pokémon with maximum EVs.
/* 0x0A */ u32 marineRibbon:1; // Never distributed.
/* 0x0A */ u32 landRibbon:1; // Never distributed.
/* 0x0A */ u32 skyRibbon:1; // Never distributed.
/* 0x0A */ u32 countryRibbon:1; // Distributed during Pokémon Festa '04 and '05 to tournament winners.
/* 0x0B */ u32 nationalRibbon:1; // Given to purified Shadow Pokémon in Colosseum/XD.
/* 0x0B */ u32 earthRibbon:1; // Given to teams that have beaten Mt. Battle's 100-battle challenge in Colosseum/XD.
/* 0x0B */ u32 worldRibbon:1; // Distributed during Pokémon Festa '04 and '05 to tournament winners.
/* 0x0B */ u32 unusedRibbons:2; // Discarded in Gen 4.
/* 0x0B */ u32 abilityNum:2;
// The functionality of this bit changed in FRLG:
// In RS, this bit does nothing, is never set, & is accidentally unset when hatching Eggs.
// In FRLG & Emerald, this controls Mew & Deoxys obedience and whether they can be traded.
// If set, a Pokémon is a fateful encounter in FRLG's summary screen if hatched & for all Pokémon in Gen 4+ summary screens.
// Set for in-game event island legendaries, events distributed after a certain date, & Pokémon from XD: Gale of Darkness.
// Not to be confused with METLOC_FATEFUL_ENCOUNTER.
/* 0x0B */ u32 modernFatefulEncounter:1;
// The functionality of this bit changed in FRLG:
// In RS, this bit does nothing, is never set, & is accidentally unset when hatching Eggs.
// In FRLG & Emerald, this controls Mew & Deoxys obedience and whether they can be traded.
// If set, a Pokémon is a fateful encounter in FRLG's summary screen if hatched & for all Pokémon in Gen 4+ summary screens.
// Set for in-game event island legendaries, events distributed after a certain date, & Pokémon from XD: Gale of Darkness.
// Not to be confused with METLOC_FATEFUL_ENCOUNTER.
u32 modernFatefulEncounter:1;
};
// Number of bytes in the largest Pokémon substruct.
@ -205,17 +236,21 @@ struct BoxPokemon
{
u32 personality;
u32 otId;
u8 nickname[POKEMON_NAME_LENGTH];
u8 language;
u8 nickname[min(10, POKEMON_NAME_LENGTH)];
u8 language:3;
u8 hiddenNatureModifier:5; // 31 natures.
u8 isBadEgg:1;
u8 hasSpecies:1;
u8 isEgg:1;
u8 blockBoxRS:1; // Unused, but Pokémon Box Ruby & Sapphire will refuse to deposit a Pokémon with this flag set
u8 unused:4;
u8 blockBoxRS:1; // Unused, but Pokémon Box Ruby & Sapphire will refuse to deposit a Pokémon with this flag set.
u8 unused_13:4;
u8 otName[PLAYER_NAME_LENGTH];
u8 markings;
u8 markings:4;
u8 compressedStatus:4;
u16 checksum;
u16 unknown;
u16 hpLost:14; // 16383 HP.
u16 shinyModifier:1;
u16 unused_1E:1;
union
{
@ -301,6 +336,7 @@ struct BattlePokemon
/*0x51*/ u32 status2;
/*0x55*/ u32 otId;
/*0x59*/ u8 metLevel;
/*0x5A*/ bool8 isShiny;
};
struct Evolution
@ -673,7 +709,7 @@ void PlayBattleBGM(void);
void PlayMapChosenOrBattleBGM(u16 songId);
void CreateTask_PlayMapChosenOrBattleBGM(u16 songId);
const u32 *GetMonFrontSpritePal(struct Pokemon *mon);
const u32 *GetMonSpritePalFromSpeciesAndPersonality(u16 species, u32 otId, u32 personality);
const u32 *GetMonSpritePalFromSpeciesAndPersonality(u16 species, bool32 isShiny, u32 personality);
bool8 IsMoveHM(u16 move);
bool8 IsMonSpriteNotFlipped(u16 species);
s8 GetMonFlavorRelation(struct Pokemon *mon, u8 flavor);
@ -685,7 +721,6 @@ void BoxMonRestorePP(struct BoxPokemon *boxMon);
void SetMonPreventsSwitchingString(void);
void SetWildMonHeldItem(void);
bool8 IsMonShiny(struct Pokemon *mon);
bool8 IsShinyOtIdPersonality(u32 otId, u32 personality);
const u8 *GetTrainerPartnerName(void);
void BattleAnimateFrontSprite(struct Sprite *sprite, u16 species, bool8 noCry, u8 panMode);
void DoMonFrontSpriteAnimation(struct Sprite *sprite, u16 species, bool8 noCry, u8 panModeAnimFlag);
@ -719,5 +754,7 @@ u16 SanitizeSpeciesId(u16 species);
bool32 IsSpeciesEnabled(u16 species);
u16 GetCryIdBySpecies(u16 species);
u16 GetSpeciesPreEvolution(u16 species);
void HealPokemon(struct Pokemon *mon);
void HealBoxPokemon(struct BoxPokemon *boxMon);
#endif // GUARD_POKEMON_H

View File

@ -849,6 +849,10 @@ struct moveWithPP {
#define Friendship(friendship) Friendship_(__LINE__, friendship)
#define Status1(status1) Status1_(__LINE__, status1)
#define OTName(otName) do {static const u8 otName_[] = _(otName); OTName_(__LINE__, otName_);} while (0)
#define DynamaxLevel(dynamaxLevel) DynamaxLevel_(__LINE__, dynamaxLevel)
#define GigantamaxFactor(gigantamaxFactor) GigantamaxFactor_(__LINE__, gigantamaxFactor)
#define TeraType(teraType) TeraType_(__LINE__, teraType)
#define Shadow(isShadow) Shadow_(__LINE__, shadow)
void SetFlagForTest(u32 sourceLine, u16 flagId);
void ClearFlagAfterTest(void);
@ -875,6 +879,10 @@ void MovesWithPP_(u32 sourceLine, struct moveWithPP moveWithPP[MAX_MON_MOVES]);
void Friendship_(u32 sourceLine, u32 friendship);
void Status1_(u32 sourceLine, u32 status1);
void OTName_(u32 sourceLine, const u8 *otName);
void DynamaxLevel_(u32 sourceLine, u32 dynamaxLevel);
void GigantamaxFactor_(u32 sourceLine, bool32 gigantamaxFactor);
void TeraType_(u32 sourceLine, u32 teraType);
void Shadow_(u32 sourceLine, bool32 isShadow);
// Created for easy use of EXPECT_MOVES, so the user can provide 1, 2, 3 or 4 moves for AI which can pass the test.
struct FourMoves

View File

@ -0,0 +1,48 @@
/* Embedded DSL for testing overworld scripts in isolation.
* The overworld is not available, so it is only possible to test
* commands which don't affect the overworld itself, e.g. givemon can
* be tested because it only alters gPlayerParty, but addobject cannot
* because it affects object events (which aren't loaded).
*
* OVERWORLD_SCRIPT(instructions...)
* Returns a pointer to a compiled overworld script. Cannot be used to
* initialize global const data, although the pointer IS to const data.
* Note that each script command must be followed by a ;, e.g.:
* const u8 *myScript = OVERWORLD_SCRIPT(
* random 2;
* addvar VAR_RESULT, 1;
* );
*
* RUN_OVERWORLD_SCRIPT(instructions...)
* Runs an overworld script in the immediate script context, which means
* that commands like waitstate are not supported.
* RUN_OVERWORLD_SCRIPT(
* setvar VAR_RESULT, 3;
* );
* EXPECT_EQ(GetVar(VAR_RESULT), 3); */
#ifndef GUARD_TEST_OVERWORLD_SCRIPT
#define GUARD_TEST_OVERWORLD_SCRIPT
#include "script.h"
#include "test/test.h"
#define OVERWORLD_SCRIPT(...) \
({ \
const u8 *_script; \
asm("mov %0, pc\n" \
"b .Lend" STR(__LINE__) "\n" \
STR(__VA_ARGS__) \
"\n" \
"end\n" \
".balign 2\n" \
".Lend" STR(__LINE__) ":\n" \
: "=r" (_script)); \
_script; \
})
#define RUN_OVERWORLD_SCRIPT(...) RunScriptImmediately(OVERWORLD_SCRIPT(__VA_ARGS__))
// Make overworld script macros available.
asm(".include \"asm/macros/event.inc\"\n");
#endif

View File

@ -59,8 +59,9 @@ extern const struct TestRunner gAssumptionsRunner;
struct FunctionTestRunnerState
{
u8 parameters;
u8 runParameter;
u16 parameters;
u16 runParameter;
u16 checkProgressParameter;
};
extern const struct TestRunner gFunctionTestRunner;

View File

@ -8,8 +8,8 @@
#define F_MON_PIC_NO_AFFINE (1 << 7)
bool16 ResetAllPicSprites(void);
u16 CreateMonPicSprite_Affine(u16 species, u32 otId, u32 personality, u8 flags, s16 x, s16 y, u8 paletteSlot, u16 paletteTag);
u16 CreateMonPicSprite(u16 species, u32 otId, u32 personality, bool8 isFrontPic, s16 x, s16 y, u8 paletteSlot, u16 paletteTag);
u16 CreateMonPicSprite_Affine(u16 species, bool8 isShiny, u32 personality, u8 flags, s16 x, s16 y, u8 paletteSlot, u16 paletteTag);
u16 CreateMonPicSprite(u16 species, bool8 isShiny, u32 personality, bool8 isFrontPic, s16 x, s16 y, u8 paletteSlot, u16 paletteTag);
u16 FreeAndDestroyMonPicSprite(u16 spriteId);
u16 CreateTrainerPicSprite(u16 species, bool8 isFrontPic, s16 x, s16 y, u8 paletteSlot, u16 paletteTag);
u16 FreeAndDestroyTrainerPicSprite(u16 spriteId);

View File

@ -6576,7 +6576,7 @@ static void AnimTask_AllySwitchDataSwap(u8 taskId)
SwapStructData(&gBattleSpritesDataPtr->battlerData[battlerAtk], &gBattleSpritesDataPtr->battlerData[battlerPartner], data, sizeof(struct BattleSpriteInfo));
SWAP(gTransformedPersonalities[battlerAtk], gTransformedPersonalities[battlerPartner], temp);
SWAP(gTransformedOtIds[battlerAtk], gTransformedOtIds[battlerPartner], temp);
SWAP(gTransformedShininess[battlerAtk], gTransformedShininess[battlerPartner], temp);
SWAP(gStatuses3[battlerAtk], gStatuses3[battlerPartner], temp);
SWAP(gStatuses4[battlerAtk], gStatuses4[battlerPartner], temp);
SWAP(gBattleStruct->chosenMovePositions[battlerAtk], gBattleStruct->chosenMovePositions[battlerPartner], temp);

View File

@ -3255,9 +3255,8 @@ static void AnimReversalOrb_Step(struct Sprite *sprite)
// Copies the target mon's sprite, and makes a white silhouette that shrinks away.
void AnimTask_RolePlaySilhouette(u8 taskId)
{
bool8 isBackPic;
bool8 isBackPic, isShiny;
u32 personality;
u32 otId;
u16 species;
s16 xOffset;
u32 priority;
@ -3269,7 +3268,7 @@ void AnimTask_RolePlaySilhouette(u8 taskId)
{
isBackPic = TRUE;
personality = gContestResources->moveAnim->targetPersonality;
otId = gContestResources->moveAnim->otId;
isShiny = gContestResources->moveAnim->targetIsShiny;
species = gContestResources->moveAnim->targetSpecies;
xOffset = 20;
priority = GetBattlerSpriteBGPriority(gBattleAnimAttacker);
@ -3280,7 +3279,7 @@ void AnimTask_RolePlaySilhouette(u8 taskId)
{
isBackPic = FALSE;
personality = GetMonData(&gPlayerParty[gBattlerPartyIndexes[gBattleAnimTarget]], MON_DATA_PERSONALITY);
otId = GetMonData(&gPlayerParty[gBattlerPartyIndexes[gBattleAnimTarget]], MON_DATA_OT_ID);
isShiny = GetMonData(&gPlayerParty[gBattlerPartyIndexes[gBattleAnimTarget]], MON_DATA_IS_SHINY);
if (gBattleSpritesDataPtr->battlerData[gBattleAnimTarget].transformSpecies == SPECIES_NONE)
{
if (GetBattlerSide(gBattleAnimTarget) == B_SIDE_PLAYER)
@ -3300,7 +3299,7 @@ void AnimTask_RolePlaySilhouette(u8 taskId)
{
isBackPic = TRUE;
personality = GetMonData(&gEnemyParty[gBattlerPartyIndexes[gBattleAnimTarget]], MON_DATA_PERSONALITY);
otId = GetMonData(&gEnemyParty[gBattlerPartyIndexes[gBattleAnimTarget]], MON_DATA_OT_ID);
isShiny = GetMonData(&gEnemyParty[gBattlerPartyIndexes[gBattleAnimTarget]], MON_DATA_IS_SHINY);
if (gBattleSpritesDataPtr->battlerData[gBattleAnimTarget].transformSpecies == SPECIES_NONE)
{
if (GetBattlerSide(gBattleAnimTarget) == B_SIDE_PLAYER)
@ -3320,7 +3319,7 @@ void AnimTask_RolePlaySilhouette(u8 taskId)
coord1 = GetBattlerSpriteCoord(gBattleAnimAttacker, BATTLER_COORD_X);
coord2 = GetBattlerSpriteCoord(gBattleAnimAttacker, BATTLER_COORD_Y);
spriteId = CreateAdditionalMonSpriteForMoveAnim(species, isBackPic, 0, coord1 + xOffset, coord2, 5, personality, otId, gBattleAnimTarget);
spriteId = CreateAdditionalMonSpriteForMoveAnim(species, isBackPic, 0, coord1 + xOffset, coord2, 5, personality, isShiny, gBattleAnimTarget);
gSprites[spriteId].oam.priority = priority;
gSprites[spriteId].oam.objMode = ST_OAM_OBJ_BLEND;
@ -5162,10 +5161,9 @@ void AnimTask_SnatchOpposingMonMove(u8 taskId)
{
u8 spriteId, spriteId2;
int personality;
int otId;
u16 species;
u8 subpriority;
bool8 isBackPic;
bool8 isBackPic, isShiny;
s16 x;
switch (gTasks[taskId].data[0])
@ -5190,7 +5188,7 @@ void AnimTask_SnatchOpposingMonMove(u8 taskId)
if (IsContest())
{
personality = gContestResources->moveAnim->personality;
otId = gContestResources->moveAnim->otId;
isShiny = gContestResources->moveAnim->isShiny;
species = gContestResources->moveAnim->species;
subpriority = GetBattlerSpriteSubpriority(gBattleAnimAttacker);
isBackPic = FALSE;
@ -5201,7 +5199,7 @@ void AnimTask_SnatchOpposingMonMove(u8 taskId)
if (GetBattlerSide(gBattleAnimAttacker) == B_SIDE_PLAYER)
{
personality = GetMonData(&gPlayerParty[gBattlerPartyIndexes[gBattleAnimAttacker]], MON_DATA_PERSONALITY);
otId = GetMonData(&gPlayerParty[gBattlerPartyIndexes[gBattleAnimAttacker]], MON_DATA_OT_ID);
isShiny = GetMonData(&gPlayerParty[gBattlerPartyIndexes[gBattleAnimAttacker]], MON_DATA_IS_SHINY);
if (gBattleSpritesDataPtr->battlerData[gBattleAnimAttacker].transformSpecies == SPECIES_NONE)
species = GetMonData(&gPlayerParty[gBattlerPartyIndexes[gBattleAnimAttacker]], MON_DATA_SPECIES);
else
@ -5214,7 +5212,7 @@ void AnimTask_SnatchOpposingMonMove(u8 taskId)
else
{
personality = GetMonData(&gEnemyParty[gBattlerPartyIndexes[gBattleAnimAttacker]], MON_DATA_PERSONALITY);
otId = GetMonData(&gEnemyParty[gBattlerPartyIndexes[gBattleAnimAttacker]], MON_DATA_OT_ID);
isShiny = GetMonData(&gEnemyParty[gBattlerPartyIndexes[gBattleAnimAttacker]], MON_DATA_IS_SHINY);
if (gBattleSpritesDataPtr->battlerData[gBattleAnimAttacker].transformSpecies == SPECIES_NONE)
species = GetMonData(&gEnemyParty[gBattlerPartyIndexes[gBattleAnimAttacker]], MON_DATA_SPECIES);
else
@ -5226,7 +5224,7 @@ void AnimTask_SnatchOpposingMonMove(u8 taskId)
}
}
spriteId2 = CreateAdditionalMonSpriteForMoveAnim(species, isBackPic, 0, x, GetBattlerSpriteCoord(gBattleAnimTarget, BATTLER_COORD_Y), subpriority, personality, otId, gBattleAnimAttacker);
spriteId2 = CreateAdditionalMonSpriteForMoveAnim(species, isBackPic, 0, x, GetBattlerSpriteCoord(gBattleAnimTarget, BATTLER_COORD_Y), subpriority, personality, isShiny, gBattleAnimAttacker);
if (gBattleSpritesDataPtr->battlerData[gBattleAnimAttacker].transformSpecies != SPECIES_NONE)
BlendPalette(OBJ_PLTT_ID(gSprites[spriteId2].oam.paletteNum), 16, 6, RGB_WHITE);

View File

@ -2053,7 +2053,7 @@ u8 GetBattlerSpriteBGPriorityRank(u8 battlerId)
}
// Create pokemon sprite to be used for a move animation effect (e.g. Role Play / Snatch)
u8 CreateAdditionalMonSpriteForMoveAnim(u16 species, bool8 isBackpic, u8 id, s16 x, s16 y, u8 subpriority, u32 personality, u32 trainerId, u32 battlerId)
u8 CreateAdditionalMonSpriteForMoveAnim(u16 species, bool8 isBackpic, u8 id, s16 x, s16 y, u8 subpriority, u32 personality, bool8 isShiny, u32 battlerId)
{
u8 spriteId;
u16 sheet = LoadSpriteSheet(&sSpriteSheets_MoveEffectMons[id]);
@ -2063,7 +2063,7 @@ u8 CreateAdditionalMonSpriteForMoveAnim(u16 species, bool8 isBackpic, u8 id, s16
gMonSpritesGfxPtr->buffer = AllocZeroed(MON_PIC_SIZE * MAX_MON_PIC_FRAMES);
if (!isBackpic)
{
LoadCompressedPalette(GetMonSpritePalFromSpeciesAndPersonality(species, trainerId, personality), OBJ_PLTT_ID(palette), PLTT_SIZE_4BPP);
LoadCompressedPalette(GetMonSpritePalFromSpeciesAndPersonality(species, isShiny, personality), OBJ_PLTT_ID(palette), PLTT_SIZE_4BPP);
LoadSpecialPokePic(gMonSpritesGfxPtr->buffer,
species,
personality,
@ -2071,7 +2071,7 @@ u8 CreateAdditionalMonSpriteForMoveAnim(u16 species, bool8 isBackpic, u8 id, s16
}
else
{
LoadCompressedPalette(GetMonSpritePalFromSpeciesAndPersonality(species, trainerId, personality), OBJ_PLTT_ID(palette), PLTT_SIZE_4BPP);
LoadCompressedPalette(GetMonSpritePalFromSpeciesAndPersonality(species, isShiny, personality), OBJ_PLTT_ID(palette), PLTT_SIZE_4BPP);
LoadSpecialPokePic(gMonSpritesGfxPtr->buffer,
species,
personality,

View File

@ -2481,26 +2481,17 @@ void AnimTask_SetTargetToEffectBattler(u8 taskId)
void TryShinyAnimation(u8 battler, struct Pokemon *mon)
{
bool8 isShiny;
u32 otId, personality;
u32 shinyValue;
u8 taskCirc, taskDgnl;
struct Pokemon* illusionMon;
isShiny = FALSE;
isShiny = GetMonData(mon, MON_DATA_IS_SHINY);
gBattleSpritesDataPtr->healthBoxesData[battler].triedShinyMonAnim = TRUE;
illusionMon = GetIllusionMonPtr(battler);
if (illusionMon != NULL)
mon = illusionMon;
otId = GetMonData(mon, MON_DATA_OT_ID);
personality = GetMonData(mon, MON_DATA_PERSONALITY);
if (IsBattlerSpriteVisible(battler) && IsValidForBattle(mon))
{
shinyValue = GET_SHINY_VALUE(otId, personality);
if (shinyValue < SHINY_ODDS)
isShiny = TRUE;
if (isShiny)
{
if (GetSpriteTileStartByTag(ANIM_TAG_GOLD_STARS) == 0xFFFF)

View File

@ -2649,7 +2649,7 @@ void BtlController_HandleMoveAnimation(u32 battler, bool32 updateTvData)
gWeatherMoveAnim = gBattleResources->bufferA[battler][12] | (gBattleResources->bufferA[battler][13] << 8);
gAnimDisableStructPtr = (struct DisableStruct *)&gBattleResources->bufferA[battler][16];
gTransformedPersonalities[battler] = gAnimDisableStructPtr->transformedMonPersonality;
gTransformedOtIds[battler] = gAnimDisableStructPtr->transformedMonOtId;
gTransformedShininess[battler] = gAnimDisableStructPtr->transformedMonShininess;
gBattleSpritesDataPtr->healthBoxesData[battler].animationState = 0;
gBattlerControllerFuncs[battler] = Controller_DoMoveAnimation;
if (updateTvData)

View File

@ -801,7 +801,7 @@ static void Task_ShowAiPoints(u8 taskId)
}
}
data->aiMonSpriteId = CreateMonPicSprite(gBattleMons[data->aiBattlerId].species,
gBattleMons[data->aiBattlerId].otId,
gBattleMons[data->aiBattlerId].isShiny,
gBattleMons[data->aiBattlerId].personality,
TRUE,
39, 130, 15, TAG_NONE);
@ -958,7 +958,7 @@ static void Task_ShowAiKnowledge(u8 taskId)
}
}
data->aiMonSpriteId = CreateMonPicSprite(gBattleMons[data->aiBattlerId].species,
gBattleMons[data->aiBattlerId].otId,
gBattleMons[data->aiBattlerId].isShiny,
gBattleMons[data->aiBattlerId].personality,
TRUE,
39, 130, 15, TAG_NONE);

View File

@ -149,8 +149,8 @@ bool32 CanDynamax(u16 battlerId)
// Returns whether a battler is transformed into a Gigantamax form.
bool32 IsGigantamaxed(u16 battlerId)
{
// TODO: Incorporate Gigantamax factor.
if ((gSpeciesInfo[gBattleMons[battlerId].species].isGigantamax))
struct Pokemon *mon = &GetSideParty(GetBattlerSide(battlerId))[gBattlerPartyIndexes[battlerId]];
if ((gSpeciesInfo[gBattleMons[battlerId].species].isGigantamax) && GetMonData(mon, MON_DATA_GIGANTAMAX_FACTOR))
return TRUE;
return FALSE;
}
@ -162,9 +162,9 @@ void ApplyDynamaxHPMultiplier(u32 battler, struct Pokemon* mon)
return;
else
{
u16 mult = UQ_4_12(1.5); // placeholder
u16 hp = UQ_4_12_TO_INT((GetMonData(mon, MON_DATA_HP) * mult) + UQ_4_12_ROUND);
u16 maxHP = UQ_4_12_TO_INT((GetMonData(mon, MON_DATA_MAX_HP) * mult) + UQ_4_12_ROUND);
u32 scale = 150 + 5 * GetMonData(mon, MON_DATA_DYNAMAX_LEVEL);
u32 hp = (GetMonData(mon, MON_DATA_HP) * scale + 99) / 100;
u32 maxHP = (GetMonData(mon, MON_DATA_MAX_HP) * scale + 99) / 100;
SetMonData(mon, MON_DATA_HP, &hp);
SetMonData(mon, MON_DATA_MAX_HP, &maxHP);
}

View File

@ -2017,9 +2017,9 @@ static void Select_CreateMonSprite(void)
struct Pokemon *mon = &sFactorySelectScreen->mons[monId].monData;
u16 species = GetMonData(mon, MON_DATA_SPECIES, NULL);
u32 personality = GetMonData(mon, MON_DATA_PERSONALITY, NULL);
u32 otId = GetMonData(mon, MON_DATA_OT_ID, NULL);
bool8 isShiny = GetMonData(mon, MON_DATA_IS_SHINY, NULL);
sFactorySelectScreen->monPics[1].monSpriteId = CreateMonPicSprite(species, otId, personality, TRUE, 88, 32, 15, TAG_NONE);
sFactorySelectScreen->monPics[1].monSpriteId = CreateMonPicSprite(species, isShiny, personality, TRUE, 88, 32, 15, TAG_NONE);
gSprites[sFactorySelectScreen->monPics[1].monSpriteId].centerToCornerVecX = 0;
gSprites[sFactorySelectScreen->monPics[1].monSpriteId].centerToCornerVecY = 0;
@ -2035,7 +2035,8 @@ static void Select_ReshowMonSprite(void)
{
struct Pokemon *mon;
u16 species;
u32 personality, otId;
u32 personality;
bool8 isShiny;
sFactorySelectScreen->monPics[1].bgSpriteId = CreateSprite(&sSpriteTemplate_Select_MonPicBgAnim, 120, 64, 1);
StartSpriteAffineAnim(&gSprites[sFactorySelectScreen->monPics[1].bgSpriteId], 2);
@ -2043,9 +2044,9 @@ static void Select_ReshowMonSprite(void)
mon = &sFactorySelectScreen->mons[sFactorySelectScreen->cursorPos].monData;
species = GetMonData(mon, MON_DATA_SPECIES, NULL);
personality = GetMonData(mon, MON_DATA_PERSONALITY, NULL);
otId = GetMonData(mon, MON_DATA_OT_ID, NULL);
isShiny = GetMonData(mon, MON_DATA_IS_SHINY, NULL);
sFactorySelectScreen->monPics[1].monSpriteId = CreateMonPicSprite(species, otId, personality, TRUE, 88, 32, 15, TAG_NONE);
sFactorySelectScreen->monPics[1].monSpriteId = CreateMonPicSprite(species, isShiny, personality, TRUE, 88, 32, 15, TAG_NONE);
gSprites[sFactorySelectScreen->monPics[1].monSpriteId].centerToCornerVecX = 0;
gSprites[sFactorySelectScreen->monPics[1].monSpriteId].centerToCornerVecY = 0;
@ -2065,9 +2066,9 @@ static void Select_CreateChosenMonsSprites(void)
struct Pokemon *mon = &sFactorySelectScreen->mons[j].monData;
u16 species = GetMonData(mon, MON_DATA_SPECIES, NULL);
u32 personality = GetMonData(mon, MON_DATA_PERSONALITY, NULL);
u32 otId = GetMonData(mon, MON_DATA_OT_ID, NULL);
bool8 isShiny = GetMonData(mon, MON_DATA_IS_SHINY, NULL);
sFactorySelectScreen->monPics[i].monSpriteId = CreateMonPicSprite(species, otId, personality, TRUE, (i * 72) + 16, 32, i + 13, TAG_NONE);
sFactorySelectScreen->monPics[i].monSpriteId = CreateMonPicSprite(species, isShiny, personality, TRUE, (i * 72) + 16, 32, i + 13, TAG_NONE);
gSprites[sFactorySelectScreen->monPics[i].monSpriteId].centerToCornerVecX = 0;
gSprites[sFactorySelectScreen->monPics[i].monSpriteId].centerToCornerVecY = 0;
break;
@ -4076,7 +4077,8 @@ static void Swap_ShowSummaryMonSprite(void)
{
struct Pokemon *mon;
u16 species;
u32 personality, otId;
u32 personality;
bool8 isShiny;
sFactorySwapScreen->monPic.bgSpriteId = CreateSprite(&sSpriteTemplate_Swap_MonPicBgAnim, 120, 64, 1);
StartSpriteAffineAnim(&gSprites[sFactorySwapScreen->monPic.bgSpriteId], 2);
@ -4084,13 +4086,9 @@ static void Swap_ShowSummaryMonSprite(void)
mon = &gPlayerParty[sFactorySwapScreen->cursorPos];
species = GetMonData(mon, MON_DATA_SPECIES, NULL);
personality = GetMonData(mon, MON_DATA_PERSONALITY, NULL);
otId = GetMonData(mon, MON_DATA_OT_ID, NULL);
isShiny = GetMonData(mon, MON_DATA_IS_SHINY, NULL);
#ifdef BUGFIX
sFactorySwapScreen->monPic.monSpriteId = CreateMonPicSprite(species, otId, personality, TRUE, 88, 32, 15, TAG_NONE);
#else
sFactorySwapScreen->monPic.monSpriteId = CreateMonPicSprite(species, personality, otId, TRUE, 88, 32, 15, TAG_NONE);
#endif
sFactorySwapScreen->monPic.monSpriteId = CreateMonPicSprite(species, isShiny, personality, TRUE, 88, 32, 15, TAG_NONE);
gSprites[sFactorySwapScreen->monPic.monSpriteId].centerToCornerVecX = 0;
gSprites[sFactorySwapScreen->monPic.monSpriteId].centerToCornerVecY = 0;
@ -4295,7 +4293,8 @@ static void Swap_CreateMonSprite(void)
{
struct Pokemon *mon;
u16 species;
u32 personality, otId;
u32 personality;
bool8 isShiny;
if (!sFactorySwapScreen->inEnemyScreen)
mon = &gPlayerParty[sFactorySwapScreen->cursorPos];
@ -4304,9 +4303,9 @@ static void Swap_CreateMonSprite(void)
species = GetMonData(mon, MON_DATA_SPECIES, NULL);
personality = GetMonData(mon, MON_DATA_PERSONALITY, NULL);
otId = GetMonData(mon, MON_DATA_OT_ID, NULL);
isShiny = GetMonData(mon, MON_DATA_IS_SHINY, NULL);
sFactorySwapScreen->monPic.monSpriteId = CreateMonPicSprite(species, otId, personality, TRUE, 88, 32, 15, TAG_NONE);
sFactorySwapScreen->monPic.monSpriteId = CreateMonPicSprite(species, isShiny, personality, TRUE, 88, 32, 15, TAG_NONE);
gSprites[sFactorySwapScreen->monPic.monSpriteId].centerToCornerVecX = 0;
gSprites[sFactorySwapScreen->monPic.monSpriteId].centerToCornerVecY = 0;

View File

@ -570,7 +570,7 @@ bool8 IsBattleSEPlaying(u8 battler)
void BattleLoadMonSpriteGfx(struct Pokemon *mon, u32 battler)
{
u32 monsPersonality, currentPersonality, otId, currentOtId, species, paletteOffset, position;
u32 monsPersonality, currentPersonality, isShiny, species, paletteOffset, position;
const void *lzPaletteData;
struct Pokemon *illusionMon = GetIllusionMonPtr(battler);
if (illusionMon != NULL)
@ -580,13 +580,12 @@ void BattleLoadMonSpriteGfx(struct Pokemon *mon, u32 battler)
return;
monsPersonality = GetMonData(mon, MON_DATA_PERSONALITY);
otId = GetMonData(mon, MON_DATA_OT_ID);
isShiny = GetMonData(mon, MON_DATA_IS_SHINY);
if (gBattleSpritesDataPtr->battlerData[battler].transformSpecies == SPECIES_NONE)
{
species = GetMonData(mon, MON_DATA_SPECIES);
currentPersonality = monsPersonality;
currentOtId = otId;
}
else
{
@ -594,12 +593,10 @@ void BattleLoadMonSpriteGfx(struct Pokemon *mon, u32 battler)
if (B_TRANSFORM_SHINY >= GEN_4)
{
currentPersonality = gTransformedPersonalities[battler];
currentOtId = gTransformedOtIds[battler];
}
else
{
currentPersonality = monsPersonality;
currentOtId = otId;
}
}
@ -622,7 +619,7 @@ void BattleLoadMonSpriteGfx(struct Pokemon *mon, u32 battler)
if (gBattleSpritesDataPtr->battlerData[battler].transformSpecies == SPECIES_NONE)
lzPaletteData = GetMonFrontSpritePal(mon);
else
lzPaletteData = GetMonSpritePalFromSpeciesAndPersonality(species, currentOtId, currentPersonality);
lzPaletteData = GetMonSpritePalFromSpeciesAndPersonality(species, isShiny, currentPersonality);
LZDecompressWram(lzPaletteData, gDecompressionBuffer);
LoadPalette(gDecompressionBuffer, paletteOffset, PLTT_SIZE_4BPP);
@ -867,7 +864,8 @@ void CopyBattleSpriteInvisibility(u8 battler)
void HandleSpeciesGfxDataChange(u8 battlerAtk, u8 battlerDef, bool32 megaEvo, bool8 trackEnemyPersonality)
{
u32 personalityValue, otId, position, paletteOffset, targetSpecies;
u32 personalityValue, position, paletteOffset, targetSpecies;
bool8 isShiny;
const void *lzPaletteData, *src;
void *dst;
@ -876,7 +874,7 @@ void HandleSpeciesGfxDataChange(u8 battlerAtk, u8 battlerDef, bool32 megaEvo, bo
position = B_POSITION_PLAYER_LEFT;
targetSpecies = gContestResources->moveAnim->targetSpecies;
personalityValue = gContestResources->moveAnim->personality;
otId = gContestResources->moveAnim->otId;
isShiny = gContestResources->moveAnim->isShiny;
HandleLoadSpecialPokePic(FALSE,
gMonSpritesGfxPtr->sprites.ptr[position],
@ -897,14 +895,13 @@ void HandleSpeciesGfxDataChange(u8 battlerAtk, u8 battlerDef, bool32 megaEvo, bo
if (B_TRANSFORM_SHINY >= GEN_4 && trackEnemyPersonality)
{
personalityValue = GetMonData(&gEnemyParty[gBattlerPartyIndexes[battlerAtk]], MON_DATA_PERSONALITY);
otId = GetMonData(&gEnemyParty[gBattlerPartyIndexes[battlerAtk]], MON_DATA_OT_ID);
isShiny = GetMonData(&gEnemyParty[gBattlerPartyIndexes[battlerAtk]], MON_DATA_IS_SHINY);
}
else
{
personalityValue = GetMonData(&gPlayerParty[gBattlerPartyIndexes[battlerAtk]], MON_DATA_PERSONALITY);
otId = GetMonData(&gPlayerParty[gBattlerPartyIndexes[battlerAtk]], MON_DATA_OT_ID);
isShiny = GetMonData(&gPlayerParty[gBattlerPartyIndexes[battlerAtk]], MON_DATA_IS_SHINY);
}
otId = GetMonData(&gPlayerParty[gBattlerPartyIndexes[battlerAtk]], MON_DATA_OT_ID);
HandleLoadSpecialPokePic(FALSE,
gMonSpritesGfxPtr->sprites.ptr[position],
@ -916,13 +913,12 @@ void HandleSpeciesGfxDataChange(u8 battlerAtk, u8 battlerDef, bool32 megaEvo, bo
if (B_TRANSFORM_SHINY >= GEN_4 && trackEnemyPersonality)
{
personalityValue = GetMonData(&gPlayerParty[gBattlerPartyIndexes[battlerAtk]], MON_DATA_PERSONALITY);
otId = GetMonData(&gPlayerParty[gBattlerPartyIndexes[battlerAtk]], MON_DATA_OT_ID);
isShiny = GetMonData(&gPlayerParty[gBattlerPartyIndexes[battlerAtk]], MON_DATA_IS_SHINY);
}
else
{
personalityValue = GetMonData(&gEnemyParty[gBattlerPartyIndexes[battlerAtk]], MON_DATA_PERSONALITY);
otId = GetMonData(&gEnemyParty[gBattlerPartyIndexes[battlerAtk]], MON_DATA_OT_ID);
isShiny = GetMonData(&gEnemyParty[gBattlerPartyIndexes[battlerAtk]], MON_DATA_IS_SHINY);
}
HandleLoadSpecialPokePic(TRUE,
@ -935,7 +931,7 @@ void HandleSpeciesGfxDataChange(u8 battlerAtk, u8 battlerDef, bool32 megaEvo, bo
dst = (void *)(OBJ_VRAM0 + gSprites[gBattlerSpriteIds[battlerAtk]].oam.tileNum * 32);
DmaCopy32(3, src, dst, MON_PIC_SIZE);
paletteOffset = OBJ_PLTT_ID(battlerAtk);
lzPaletteData = GetMonSpritePalFromSpeciesAndPersonality(targetSpecies, otId, personalityValue);
lzPaletteData = GetMonSpritePalFromSpeciesAndPersonality(targetSpecies, isShiny, personalityValue);
LZDecompressWram(lzPaletteData, gDecompressionBuffer);
LoadPalette(gDecompressionBuffer, paletteOffset, PLTT_SIZE_4BPP);

View File

@ -214,7 +214,7 @@ EWRAM_DATA u8 gBattlerStatusSummaryTaskId[MAX_BATTLERS_COUNT] = {0};
EWRAM_DATA u8 gBattlerInMenuId = 0;
EWRAM_DATA bool8 gDoingBattleAnim = FALSE;
EWRAM_DATA u32 gTransformedPersonalities[MAX_BATTLERS_COUNT] = {0};
EWRAM_DATA u32 gTransformedOtIds[MAX_BATTLERS_COUNT] = {0};
EWRAM_DATA bool8 gTransformedShininess[MAX_BATTLERS_COUNT] = {0};
EWRAM_DATA u8 gPlayerDpadHoldFrames = 0;
EWRAM_DATA struct BattleSpriteData *gBattleSpritesDataPtr = NULL;
EWRAM_DATA struct MonSpritesGfx *gMonSpritesGfxPtr = NULL;
@ -2018,6 +2018,21 @@ u8 CreateNPCTrainerPartyFromTrainer(struct Pokemon *party, const struct Trainer
{
SetMonData(&party[i], MON_DATA_NICKNAME, partyData[i].nickname);
}
if (partyData[i].isShiny)
{
u32 data = TRUE;
SetMonData(&party[i], MON_DATA_IS_SHINY, &data);
}
if (partyData[i].dynamaxLevel > 0)
{
u32 data = partyData[i].dynamaxLevel;
SetMonData(&party[i], MON_DATA_DYNAMAX_LEVEL, &data);
}
if (partyData[i].gigantamaxFactor)
{
u32 data = partyData[i].gigantamaxFactor;
SetMonData(&party[i], MON_DATA_GIGANTAMAX_FACTOR, &data);
}
CalculateMonStats(&party[i]);
#if B_TRAINER_CLASS_POKE_BALLS >= GEN_7

View File

@ -12308,7 +12308,7 @@ static void Cmd_transformdataexecution(void)
gDisableStructs[gBattlerAttacker].disabledMove = MOVE_NONE;
gDisableStructs[gBattlerAttacker].disableTimer = 0;
gDisableStructs[gBattlerAttacker].transformedMonPersonality = gBattleMons[gBattlerTarget].personality;
gDisableStructs[gBattlerAttacker].transformedMonOtId = gBattleMons[gBattlerTarget].otId;
gDisableStructs[gBattlerAttacker].transformedMonShininess = gBattleMons[gBattlerTarget].isShiny;
gDisableStructs[gBattlerAttacker].mimickedMoves = 0;
gDisableStructs[gBattlerAttacker].usedMoves = 0;
@ -15171,10 +15171,11 @@ static void Cmd_displaydexinfo(void)
case 1:
if (!gPaletteFade.active)
{
struct Pokemon *mon = &gEnemyParty[gBattlerPartyIndexes[GetCatchingBattler()]];
FreeAllWindowBuffers();
gBattleCommunication[TASK_ID] = DisplayCaughtMonDexPage(species,
gBattleMons[GetCatchingBattler()].otId,
gBattleMons[GetCatchingBattler()].personality);
GetMonData(mon, MON_DATA_IS_SHINY),
GetMonData(mon, MON_DATA_PERSONALITY));
gBattleCommunication[0]++;
}
break;

View File

@ -2990,21 +2990,17 @@ static void FillPartnerParty(u16 trainerId)
else
otID = ((firstIdPart % 72) * 1000) + ((secondIdPart % 23) * 10) + (thirdIdPart % 37) % 65536;
do
{
personality = Random32();
} while (IsShinyOtIdPersonality(otID, personality));
personality = Random32();
if (partyData[i].gender == TRAINER_MON_MALE)
personality = (personality & 0xFFFFFF00) | GeneratePersonalityForGender(MON_MALE, partyData[i].species);
else if (partyData[i].gender == TRAINER_MON_FEMALE)
personality = (personality & 0xFFFFFF00) | GeneratePersonalityForGender(MON_FEMALE, partyData[i].species);
if (partyData[i].nature != 0)
ModifyPersonalityForNature(&personality, partyData[i].nature - 1);
if (partyData[i].isShiny)
otID ^= GET_SHINY_VALUE(otID, personality) << 16;
CreateMon(&gPlayerParty[i + 3], partyData[i].species, partyData[i].lvl, 0, TRUE, personality, OT_ID_PRESET, otID);
j = partyData[i].isShiny;
SetMonData(&gPlayerParty[i + 3], MON_DATA_IS_SHINY, &j);
SetMonData(&gPlayerParty[i + 3], MON_DATA_HELD_ITEM, &partyData[i].heldItem);
CustomTrainerPartyAssignMoves(&gPlayerParty[i + 3], &partyData[i]);

View File

@ -10555,6 +10555,7 @@ u16 GetBattleFormChangeTargetSpecies(u32 battler, u16 method)
u16 targetSpecies = SPECIES_NONE;
u16 species = gBattleMons[battler].species;
const struct FormChange *formChanges = GetSpeciesFormChanges(species);
struct Pokemon *mon = &GetBattlerParty(battler)[gBattlerPartyIndexes[battler]];
u16 heldItem;
if (formChanges != NULL)
@ -10602,8 +10603,8 @@ u16 GetBattleFormChangeTargetSpecies(u32 battler, u16 method)
}
break;
case FORM_CHANGE_BATTLE_GIGANTAMAX:
// TODO: check Gigantamax factor
targetSpecies = formChanges[i].targetSpecies;
if (GetMonData(mon, MON_DATA_GIGANTAMAX_FACTOR))
targetSpecies = formChanges[i].targetSpecies;
break;
case FORM_CHANGE_BATTLE_WEATHER:
// Check if there is a required ability and if the battler's ability does not match it

View File

@ -98,7 +98,7 @@ static void PrintContestantMonName(u8);
static void PrintContestantMonNameWithColor(u8, u8);
static u8 CreateJudgeSprite(void);
static u8 CreateJudgeSpeechBubbleSprite(void);
static u8 CreateContestantSprite(u16, u32, u32, u32);
static u8 CreateContestantSprite(u16, bool8, u32, u32);
static void PrintContestMoveDescription(u16);
static u16 SanitizeSpecies(u16);
static void ContestClearGeneralTextWindow(void);
@ -1781,7 +1781,7 @@ static void Task_DoAppeals(u8 taskId)
SetMoveAnimAttackerData(eContest.currentContestant);
spriteId = CreateContestantSprite(
gContestMons[eContest.currentContestant].species,
gContestMons[eContest.currentContestant].otId,
gContestMons[eContest.currentContestant].isShiny,
gContestMons[eContest.currentContestant].personality,
eContest.currentContestant);
gSprites[spriteId].x2 = 120;
@ -2811,6 +2811,7 @@ void CreateContestMonFromParty(u8 partyIndex)
gContestMons[gContestPlayerMonIndex].moves[3] = GetMonData(&gPlayerParty[partyIndex], MON_DATA_MOVE4);
gContestMons[gContestPlayerMonIndex].personality = GetMonData(&gPlayerParty[partyIndex], MON_DATA_PERSONALITY);
gContestMons[gContestPlayerMonIndex].otId = GetMonData(&gPlayerParty[partyIndex], MON_DATA_OT_ID);
gContestMons[gContestPlayerMonIndex].isShiny = GetMonData(&gPlayerParty[partyIndex], MON_DATA_IS_SHINY);
heldItem = GetMonData(&gPlayerParty[partyIndex], MON_DATA_HELD_ITEM);
cool = gContestMons[gContestPlayerMonIndex].cool;
@ -3114,14 +3115,14 @@ static u8 CreateJudgeSpeechBubbleSprite(void)
return spriteId;
}
static u8 CreateContestantSprite(u16 species, u32 otId, u32 personality, u32 index)
static u8 CreateContestantSprite(u16 species, bool8 isShiny, u32 personality, u32 index)
{
u8 spriteId;
species = SanitizeSpecies(species);
HandleLoadSpecialPokePic(FALSE, gMonSpritesGfxPtr->sprites.ptr[B_POSITION_PLAYER_LEFT], species, personality);
LoadCompressedPalette(GetMonSpritePalFromSpeciesAndPersonality(species, otId, personality), OBJ_PLTT_ID(2), PLTT_SIZE_4BPP);
LoadCompressedPalette(GetMonSpritePalFromSpeciesAndPersonality(species, isShiny, personality), OBJ_PLTT_ID(2), PLTT_SIZE_4BPP);
SetMultiuseSpriteTemplateToPokemon(species, B_POSITION_PLAYER_LEFT);
spriteId = CreateSprite(&gMultiuseSpriteTemplate, 0x70, GetBattlerSpriteFinal_Y(2, species, FALSE), 30);
@ -5354,6 +5355,7 @@ static void SetMoveAnimAttackerData(u8 contestant)
gContestResources->moveAnim->species = SanitizeSpecies(gContestMons[contestant].species);
gContestResources->moveAnim->personality = gContestMons[contestant].personality;
gContestResources->moveAnim->otId = gContestMons[contestant].otId;
gContestResources->moveAnim->isShiny = gContestMons[contestant].isShiny;
}
static void CreateInvisibleBattleTargetSprite(void)
@ -5565,6 +5567,7 @@ bool8 SaveContestWinner(u8 rank)
{
// Set the most recent winner so the artist can show the player their painting
gCurContestWinner.personality = gContestMons[i].personality;
gCurContestWinner.isShiny = gContestMons[i].isShiny;
gCurContestWinner.trainerId = gContestMons[i].otId;
gCurContestWinner.species = gContestMons[i].species;
StringCopy(gCurContestWinner.monName, gContestMons[i].nickname);

View File

@ -363,7 +363,7 @@ static void VBlankCB_ContestPainting(void)
static void InitContestMonPixels(u16 species, bool8 backPic)
{
const void *pal = GetMonSpritePalFromSpeciesAndPersonality(species, gContestPaintingWinner->trainerId, gContestPaintingWinner->personality);
const void *pal = GetMonSpritePalFromSpeciesAndPersonality(species, gContestPaintingWinner->isShiny, gContestPaintingWinner->personality);
LZDecompressVram(pal, gContestPaintingMonPalette);
if (!backPic)
{

View File

@ -879,7 +879,7 @@ static void Task_ShowWinnerMonBanner(u8 taskId)
int i;
u8 spriteId;
u16 species;
u32 otId;
bool8 isShiny;
u32 personality;
switch (gTasks[taskId].tState)
@ -891,13 +891,13 @@ static void Task_ShowWinnerMonBanner(u8 taskId)
GET_CONTEST_WINNER_ID(i);
species = gContestMons[i].species;
personality = gContestMons[i].personality;
otId = gContestMons[i].otId;
isShiny = gContestMons[i].isShiny;
HandleLoadSpecialPokePic(TRUE,
gMonSpritesGfxPtr->sprites.ptr[B_POSITION_OPPONENT_LEFT],
species,
personality);
LoadCompressedSpritePaletteWithTag(GetMonSpritePalFromSpeciesAndPersonality(species, otId, personality), species);
LoadCompressedSpritePaletteWithTag(GetMonSpritePalFromSpeciesAndPersonality(species, isShiny, personality), species);
SetMultiuseSpriteTemplateToPokemon(species, B_POSITION_OPPONENT_LEFT);
gMultiuseSpriteTemplate.paletteTag = species;
spriteId = CreateSprite(&gMultiuseSpriteTemplate, DISPLAY_WIDTH + 32, DISPLAY_HEIGHT / 2, 10);
@ -2552,11 +2552,12 @@ bool8 IsContestDebugActive(void)
void ShowContestEntryMonPic(void)
{
u32 personality, otId;
u32 personality;
u16 species;
u8 spriteId;
u8 taskId;
u8 left, top;
bool32 isShiny;
if (FindTaskIdByFunc(Task_ShowContestEntryMonPic) == TASK_NONE)
{
@ -2565,13 +2566,13 @@ void ShowContestEntryMonPic(void)
top = 3;
species = gContestMons[gSpecialVar_0x8006].species;
personality = gContestMons[gSpecialVar_0x8006].personality;
otId = gContestMons[gSpecialVar_0x8006].otId;
isShiny = gContestMons[gSpecialVar_0x8006].isShiny;
taskId = CreateTask(Task_ShowContestEntryMonPic, 0x50);
gTasks[taskId].data[0] = 0;
gTasks[taskId].data[1] = species;
HandleLoadSpecialPokePic(TRUE, gMonSpritesGfxPtr->sprites.ptr[B_POSITION_OPPONENT_LEFT], species, personality);
LoadCompressedSpritePaletteWithTag(GetMonSpritePalFromSpeciesAndPersonality(species, otId, personality), species);
LoadCompressedSpritePaletteWithTag(GetMonSpritePalFromSpeciesAndPersonality(species, isShiny, personality), species);
SetMultiuseSpriteTemplateToPokemon(species, B_POSITION_OPPONENT_LEFT);
gMultiuseSpriteTemplate.paletteTag = species;
spriteId = CreateSprite(&gMultiuseSpriteTemplate, (left + 1) * 8 + 32, (top * 8) + 40, 0);

View File

@ -1272,8 +1272,9 @@ const struct Item gItems[] =
"ups Attack, but\n"
"reduces Defense."),
.pocket = POCKET_ITEMS,
.type = ITEM_USE_BAG_MENU,
.fieldUseFunc = ItemUseOutOfBattle_CannotUse, // Todo
.type = ITEM_USE_PARTY_MENU,
.fieldUseFunc = ItemUseOutOfBattle_Mint,
.secondaryId = NATURE_LONELY,
.flingPower = 10,
},
@ -1285,8 +1286,9 @@ const struct Item gItems[] =
"ups Attack, but\n"
"reduces Sp. Atk."),
.pocket = POCKET_ITEMS,
.type = ITEM_USE_BAG_MENU,
.fieldUseFunc = ItemUseOutOfBattle_CannotUse, // Todo
.type = ITEM_USE_PARTY_MENU,
.fieldUseFunc = ItemUseOutOfBattle_Mint,
.secondaryId = NATURE_ADAMANT,
.flingPower = 10,
},
@ -1298,8 +1300,9 @@ const struct Item gItems[] =
"ups Attack, but\n"
"reduces Sp. Def."),
.pocket = POCKET_ITEMS,
.type = ITEM_USE_BAG_MENU,
.fieldUseFunc = ItemUseOutOfBattle_CannotUse, // Todo
.type = ITEM_USE_PARTY_MENU,
.fieldUseFunc = ItemUseOutOfBattle_Mint,
.secondaryId = NATURE_NAUGHTY,
.flingPower = 10,
},
@ -1311,8 +1314,9 @@ const struct Item gItems[] =
"ups Attack, but\n"
"reduces Speed."),
.pocket = POCKET_ITEMS,
.type = ITEM_USE_BAG_MENU,
.fieldUseFunc = ItemUseOutOfBattle_CannotUse, // Todo
.type = ITEM_USE_PARTY_MENU,
.fieldUseFunc = ItemUseOutOfBattle_Mint,
.secondaryId = NATURE_BRAVE,
.flingPower = 10,
},
@ -1324,8 +1328,9 @@ const struct Item gItems[] =
"ups Defense, but\n"
"reduces Attack."),
.pocket = POCKET_ITEMS,
.type = ITEM_USE_BAG_MENU,
.fieldUseFunc = ItemUseOutOfBattle_CannotUse, // Todo
.type = ITEM_USE_PARTY_MENU,
.fieldUseFunc = ItemUseOutOfBattle_Mint,
.secondaryId = NATURE_BOLD,
.flingPower = 10,
},
@ -1337,8 +1342,9 @@ const struct Item gItems[] =
"ups Defense, but\n"
"reduces Sp. Atk."),
.pocket = POCKET_ITEMS,
.type = ITEM_USE_BAG_MENU,
.fieldUseFunc = ItemUseOutOfBattle_CannotUse, // Todo
.type = ITEM_USE_PARTY_MENU,
.fieldUseFunc = ItemUseOutOfBattle_Mint,
.secondaryId = NATURE_IMPISH,
.flingPower = 10,
},
@ -1350,8 +1356,9 @@ const struct Item gItems[] =
"ups Defense, but\n"
"reduces Sp. Def."),
.pocket = POCKET_ITEMS,
.type = ITEM_USE_BAG_MENU,
.fieldUseFunc = ItemUseOutOfBattle_CannotUse, // Todo
.type = ITEM_USE_PARTY_MENU,
.fieldUseFunc = ItemUseOutOfBattle_Mint,
.secondaryId = NATURE_LAX,
.flingPower = 10,
},
@ -1363,8 +1370,9 @@ const struct Item gItems[] =
"ups Defense, but\n"
"reduces Speed."),
.pocket = POCKET_ITEMS,
.type = ITEM_USE_BAG_MENU,
.fieldUseFunc = ItemUseOutOfBattle_CannotUse, // Todo
.type = ITEM_USE_PARTY_MENU,
.fieldUseFunc = ItemUseOutOfBattle_Mint,
.secondaryId = NATURE_RELAXED,
.flingPower = 10,
},
@ -1376,8 +1384,9 @@ const struct Item gItems[] =
"ups Sp. Atk, but\n"
"reduces Attack."),
.pocket = POCKET_ITEMS,
.type = ITEM_USE_BAG_MENU,
.fieldUseFunc = ItemUseOutOfBattle_CannotUse, // Todo
.type = ITEM_USE_PARTY_MENU,
.fieldUseFunc = ItemUseOutOfBattle_Mint,
.secondaryId = NATURE_MODEST,
.flingPower = 10,
},
@ -1389,8 +1398,9 @@ const struct Item gItems[] =
"ups Sp. Atk, but\n"
"reduces Defense."),
.pocket = POCKET_ITEMS,
.type = ITEM_USE_BAG_MENU,
.fieldUseFunc = ItemUseOutOfBattle_CannotUse, // Todo
.type = ITEM_USE_PARTY_MENU,
.fieldUseFunc = ItemUseOutOfBattle_Mint,
.secondaryId = NATURE_MILD,
.flingPower = 10,
},
@ -1402,8 +1412,9 @@ const struct Item gItems[] =
"ups Sp. Atk, but\n"
"reduces Sp. Def."),
.pocket = POCKET_ITEMS,
.type = ITEM_USE_BAG_MENU,
.fieldUseFunc = ItemUseOutOfBattle_CannotUse, // Todo
.type = ITEM_USE_PARTY_MENU,
.fieldUseFunc = ItemUseOutOfBattle_Mint,
.secondaryId = NATURE_RASH,
.flingPower = 10,
},
@ -1415,8 +1426,9 @@ const struct Item gItems[] =
"ups Sp. Atk, but\n"
"reduces Speed."),
.pocket = POCKET_ITEMS,
.type = ITEM_USE_BAG_MENU,
.fieldUseFunc = ItemUseOutOfBattle_CannotUse, // Todo
.type = ITEM_USE_PARTY_MENU,
.fieldUseFunc = ItemUseOutOfBattle_Mint,
.secondaryId = NATURE_QUIET,
.flingPower = 10,
},
@ -1428,8 +1440,9 @@ const struct Item gItems[] =
"ups Sp. Def, but\n"
"reduces Attack."),
.pocket = POCKET_ITEMS,
.type = ITEM_USE_BAG_MENU,
.fieldUseFunc = ItemUseOutOfBattle_CannotUse, // Todo
.type = ITEM_USE_PARTY_MENU,
.fieldUseFunc = ItemUseOutOfBattle_Mint,
.secondaryId = NATURE_CALM,
.flingPower = 10,
},
@ -1441,8 +1454,9 @@ const struct Item gItems[] =
"ups Sp. Def, but\n"
"reduces Defense."),
.pocket = POCKET_ITEMS,
.type = ITEM_USE_BAG_MENU,
.fieldUseFunc = ItemUseOutOfBattle_CannotUse, // Todo
.type = ITEM_USE_PARTY_MENU,
.fieldUseFunc = ItemUseOutOfBattle_Mint,
.secondaryId = NATURE_GENTLE,
.flingPower = 10,
},
@ -1454,8 +1468,9 @@ const struct Item gItems[] =
"ups Sp. Def, but\n"
"reduces Sp. Atk."),
.pocket = POCKET_ITEMS,
.type = ITEM_USE_BAG_MENU,
.fieldUseFunc = ItemUseOutOfBattle_CannotUse, // Todo
.type = ITEM_USE_PARTY_MENU,
.fieldUseFunc = ItemUseOutOfBattle_Mint,
.secondaryId = NATURE_CAREFUL,
.flingPower = 10,
},
@ -1467,8 +1482,9 @@ const struct Item gItems[] =
"ups Sp. Def, but\n"
"reduces Speed."),
.pocket = POCKET_ITEMS,
.type = ITEM_USE_BAG_MENU,
.fieldUseFunc = ItemUseOutOfBattle_CannotUse, // Todo
.type = ITEM_USE_PARTY_MENU,
.fieldUseFunc = ItemUseOutOfBattle_Mint,
.secondaryId = NATURE_SASSY,
.flingPower = 10,
},
@ -1480,8 +1496,9 @@ const struct Item gItems[] =
"ups Speed, but\n"
"reduces Attack."),
.pocket = POCKET_ITEMS,
.type = ITEM_USE_BAG_MENU,
.fieldUseFunc = ItemUseOutOfBattle_CannotUse, // Todo
.type = ITEM_USE_PARTY_MENU,
.fieldUseFunc = ItemUseOutOfBattle_Mint,
.secondaryId = NATURE_TIMID,
.flingPower = 10,
},
@ -1493,8 +1510,9 @@ const struct Item gItems[] =
"ups Speed, but\n"
"reduces Defense."),
.pocket = POCKET_ITEMS,
.type = ITEM_USE_BAG_MENU,
.fieldUseFunc = ItemUseOutOfBattle_CannotUse, // Todo
.type = ITEM_USE_PARTY_MENU,
.fieldUseFunc = ItemUseOutOfBattle_Mint,
.secondaryId = NATURE_HASTY,
.flingPower = 10,
},
@ -1506,8 +1524,9 @@ const struct Item gItems[] =
"ups Speed, but\n"
"reduces Sp. Atk."),
.pocket = POCKET_ITEMS,
.type = ITEM_USE_BAG_MENU,
.fieldUseFunc = ItemUseOutOfBattle_CannotUse, // Todo
.type = ITEM_USE_PARTY_MENU,
.fieldUseFunc = ItemUseOutOfBattle_Mint,
.secondaryId = NATURE_JOLLY,
.flingPower = 10,
},
@ -1519,8 +1538,9 @@ const struct Item gItems[] =
"ups Speed, but\n"
"reduces Sp. Def."),
.pocket = POCKET_ITEMS,
.type = ITEM_USE_BAG_MENU,
.fieldUseFunc = ItemUseOutOfBattle_CannotUse, // Todo
.type = ITEM_USE_PARTY_MENU,
.fieldUseFunc = ItemUseOutOfBattle_Mint,
.secondaryId = NATURE_NAIVE,
.flingPower = 10,
},
@ -1532,8 +1552,9 @@ const struct Item gItems[] =
"makes each stat\n"
"grow equally."),
.pocket = POCKET_ITEMS,
.type = ITEM_USE_BAG_MENU,
.fieldUseFunc = ItemUseOutOfBattle_CannotUse, // Todo
.type = ITEM_USE_PARTY_MENU,
.fieldUseFunc = ItemUseOutOfBattle_Mint,
.secondaryId = NATURE_SERIOUS,
.flingPower = 10,
},
@ -1630,8 +1651,8 @@ const struct Item gItems[] =
"Level of a single\n"
"Pokémon by one."),
.pocket = POCKET_ITEMS,
.type = ITEM_USE_BAG_MENU,
.fieldUseFunc = ItemUseOutOfBattle_CannotUse, // Todo
.type = ITEM_USE_PARTY_MENU,
.fieldUseFunc = ItemUseOutOfBattle_DynamaxCandy,
.flingPower = 30,
},

View File

@ -229,7 +229,6 @@ static void StorePokemonInDaycare(struct Pokemon *mon, struct DaycareMon *daycar
}
daycareMon->mon = mon->box;
BoxMonRestorePP(&daycareMon->mon);
daycareMon->steps = 0;
ZeroMonData(mon);
CompactPartySlots();

View File

@ -2938,7 +2938,7 @@ static void ResetMonDataStruct(struct DebugMonData *sDebugMonData)
{
sDebugMonData->species = 1;
sDebugMonData->level = MIN_LEVEL;
sDebugMonData->isShiny = 0;
sDebugMonData->isShiny = FALSE;
sDebugMonData->nature = 0;
sDebugMonData->abilityNum = 0;
sDebugMonData->mon_iv_hp = 0;
@ -3608,7 +3608,7 @@ static void DebugAction_Give_Pokemon_ComplexCreateMon(u8 taskId) //https://githu
u8 iv_val;
u16 species = sDebugMonData->species;
u8 level = sDebugMonData->level;
u8 isShiny = sDebugMonData->isShiny; //Shiny: no 0, yes 1
bool8 isShiny = sDebugMonData->isShiny;
u8 nature = sDebugMonData->nature;
u8 abilityNum = sDebugMonData->abilityNum;
moves[0] = sDebugMonData->mon_move_0;
@ -3625,26 +3625,10 @@ static void DebugAction_Give_Pokemon_ComplexCreateMon(u8 taskId) //https://githu
//Nature
if (nature == NUM_NATURES || nature == 0xFF)
nature = Random() % NUM_NATURES;
CreateMonWithNature(&mon, species, level, 32, nature);
//Shininess
if (isShiny == 1)
{
u32 personality;
u32 otid = gSaveBlock2Ptr->playerTrainerId[0]
| (gSaveBlock2Ptr->playerTrainerId[1] << 8)
| (gSaveBlock2Ptr->playerTrainerId[2] << 16)
| (gSaveBlock2Ptr->playerTrainerId[3] << 24);
do
{
personality = Random32();
personality = ((((Random() % 8) ^ (HIHALF(otid) ^ LOHALF(otid))) ^ LOHALF(personality)) << 16) | LOHALF(personality);
} while (nature != GetNatureFromPersonality(personality));
CreateMon(&mon, species, level, 32, 1, personality, OT_ID_PRESET, otid);
}
else
CreateMonWithNature(&mon, species, level, 32, nature);
SetMonData(&mon, MON_DATA_IS_SHINY, &isShiny);
//IVs
for (i = 0; i < NUM_STATS; i++)

View File

@ -209,7 +209,8 @@ void EvolutionScene(struct Pokemon *mon, u16 postEvoSpecies, bool8 canStopEvo, u
{
u8 name[POKEMON_NAME_BUFFER_SIZE];
u16 currSpecies;
u32 trainerId, personality;
u32 personality;
bool32 isShiny;
u8 id;
SetHBlankCallback(NULL);
@ -255,13 +256,13 @@ void EvolutionScene(struct Pokemon *mon, u16 postEvoSpecies, bool8 canStopEvo, u
// preEvo sprite
currSpecies = GetMonData(mon, MON_DATA_SPECIES);
trainerId = GetMonData(mon, MON_DATA_OT_ID);
isShiny = GetMonData(mon, MON_DATA_IS_SHINY);
personality = GetMonData(mon, MON_DATA_PERSONALITY);
LoadSpecialPokePic(gMonSpritesGfxPtr->sprites.ptr[B_POSITION_OPPONENT_LEFT],
currSpecies,
personality,
TRUE);
LoadCompressedPalette(GetMonSpritePalFromSpeciesAndPersonality(currSpecies, trainerId, personality), OBJ_PLTT_ID(1), PLTT_SIZE_4BPP);
LoadCompressedPalette(GetMonSpritePalFromSpeciesAndPersonality(currSpecies, isShiny, personality), OBJ_PLTT_ID(1), PLTT_SIZE_4BPP);
SetMultiuseSpriteTemplateToPokemon(currSpecies, B_POSITION_OPPONENT_LEFT);
gMultiuseSpriteTemplate.affineAnims = gDummySpriteAffineAnimTable;
@ -276,7 +277,7 @@ void EvolutionScene(struct Pokemon *mon, u16 postEvoSpecies, bool8 canStopEvo, u
postEvoSpecies,
personality,
TRUE);
LoadCompressedPalette(GetMonSpritePalFromSpeciesAndPersonality(postEvoSpecies, trainerId, personality), OBJ_PLTT_ID(2), PLTT_SIZE_4BPP);
LoadCompressedPalette(GetMonSpritePalFromSpeciesAndPersonality(postEvoSpecies, isShiny, personality), OBJ_PLTT_ID(2), PLTT_SIZE_4BPP);
SetMultiuseSpriteTemplateToPokemon(postEvoSpecies, B_POSITION_OPPONENT_RIGHT);
gMultiuseSpriteTemplate.affineAnims = gDummySpriteAffineAnimTable;
@ -310,11 +311,12 @@ static void CB2_EvolutionSceneLoadGraphics(void)
{
u8 id;
u16 postEvoSpecies;
u32 trainerId, personality;
u32 personality;
struct Pokemon *mon = &gPlayerParty[gTasks[sEvoStructPtr->evoTaskId].tPartyId];
bool8 isShiny;
postEvoSpecies = gTasks[sEvoStructPtr->evoTaskId].tPostEvoSpecies;
trainerId = GetMonData(mon, MON_DATA_OT_ID);
isShiny = GetMonData(mon, MON_DATA_IS_SHINY);
personality = GetMonData(mon, MON_DATA_PERSONALITY);
SetHBlankCallback(NULL);
@ -352,7 +354,7 @@ static void CB2_EvolutionSceneLoadGraphics(void)
postEvoSpecies,
personality,
TRUE);
LoadCompressedPalette(GetMonSpritePalFromSpeciesAndPersonality(postEvoSpecies, trainerId, personality), OBJ_PLTT_ID(2), PLTT_SIZE_4BPP);
LoadCompressedPalette(GetMonSpritePalFromSpeciesAndPersonality(postEvoSpecies, isShiny, personality), OBJ_PLTT_ID(2), PLTT_SIZE_4BPP);
SetMultiuseSpriteTemplateToPokemon(postEvoSpecies, B_POSITION_OPPONENT_RIGHT);
gMultiuseSpriteTemplate.affineAnims = gDummySpriteAffineAnimTable;
@ -416,13 +418,13 @@ static void CB2_TradeEvolutionSceneLoadGraphics(void)
break;
case 4:
{
u32 trainerId = GetMonData(mon, MON_DATA_OT_ID);
bool8 isShiny = GetMonData(mon, MON_DATA_IS_SHINY);
u32 personality = GetMonData(mon, MON_DATA_PERSONALITY);
LoadSpecialPokePic(gMonSpritesGfxPtr->sprites.ptr[B_POSITION_OPPONENT_RIGHT],
postEvoSpecies,
personality,
TRUE);
LoadCompressedPalette(GetMonSpritePalFromSpeciesAndPersonality(postEvoSpecies, trainerId, personality), OBJ_PLTT_ID(2), PLTT_SIZE_4BPP);
LoadCompressedPalette(GetMonSpritePalFromSpeciesAndPersonality(postEvoSpecies, isShiny, personality), OBJ_PLTT_ID(2), PLTT_SIZE_4BPP);
gMain.state++;
}
break;
@ -464,8 +466,9 @@ void TradeEvolutionScene(struct Pokemon *mon, u16 postEvoSpecies, u8 preEvoSprit
{
u8 name[POKEMON_NAME_BUFFER_SIZE];
u16 currSpecies;
u32 trainerId, personality;
u32 personality;
u8 id;
bool8 isShiny;
GetMonData(mon, MON_DATA_NICKNAME, name);
StringCopy_Nickname(gStringVar1, name);
@ -476,7 +479,7 @@ void TradeEvolutionScene(struct Pokemon *mon, u16 postEvoSpecies, u8 preEvoSprit
// preEvo sprite
currSpecies = GetMonData(mon, MON_DATA_SPECIES);
personality = GetMonData(mon, MON_DATA_PERSONALITY);
trainerId = GetMonData(mon, MON_DATA_OT_ID);
isShiny = GetMonData(mon, MON_DATA_IS_SHINY);
sEvoStructPtr = AllocZeroed(sizeof(struct EvoInfo));
sEvoStructPtr->preEvoSpriteId = preEvoSpriteId;
@ -486,7 +489,7 @@ void TradeEvolutionScene(struct Pokemon *mon, u16 postEvoSpecies, u8 preEvoSprit
personality,
TRUE);
LoadCompressedPalette(GetMonSpritePalFromSpeciesAndPersonality(postEvoSpecies, trainerId, personality), OBJ_PLTT_ID(2), PLTT_SIZE_4BPP);
LoadCompressedPalette(GetMonSpritePalFromSpeciesAndPersonality(postEvoSpecies, isShiny, personality), OBJ_PLTT_ID(2), PLTT_SIZE_4BPP);
SetMultiuseSpriteTemplateToPokemon(postEvoSpecies, B_POSITION_OPPONENT_LEFT);
gMultiuseSpriteTemplate.affineAnims = gDummySpriteAffineAnimTable;
@ -564,8 +567,6 @@ static void CreateShedinja(u16 preEvoSpecies, struct Pokemon *mon)
SetMonData(&gPlayerParty[gPlayerPartyCount], MON_DATA_NICKNAME, GetSpeciesName(evolutions[1].targetSpecies));
SetMonData(&gPlayerParty[gPlayerPartyCount], MON_DATA_HELD_ITEM, &data);
SetMonData(&gPlayerParty[gPlayerPartyCount], MON_DATA_MARKINGS, &data);
SetMonData(&gPlayerParty[gPlayerPartyCount], MON_DATA_ENCRYPT_SEPARATOR, &data);
#if P_SHEDINJA_BALL >= GEN_4
SetMonData(&gPlayerParty[gPlayerPartyCount], MON_DATA_POKEBALL, &ball);
RemoveBagItem(ball, 1);
@ -573,7 +574,7 @@ static void CreateShedinja(u16 preEvoSpecies, struct Pokemon *mon)
for (i = MON_DATA_COOL_RIBBON; i < MON_DATA_COOL_RIBBON + CONTEST_CATEGORIES_COUNT; i++)
SetMonData(&gPlayerParty[gPlayerPartyCount], i, &data);
for (i = MON_DATA_CHAMPION_RIBBON; i <= MON_DATA_UNUSED_RIBBONS; i++)
for (i = MON_DATA_CHAMPION_RIBBON; i <= MON_DATA_WORLD_RIBBON; i++)
SetMonData(&gPlayerParty[gPlayerPartyCount], i, &data);
SetMonData(&gPlayerParty[gPlayerPartyCount], MON_DATA_STATUS, &data);

View File

@ -183,7 +183,7 @@ static void AnimateIndoorShowMonBg(struct Task *);
static bool8 SlideIndoorBannerOnscreen(struct Task *);
static bool8 SlideIndoorBannerOffscreen(struct Task *);
static u8 InitFieldMoveMonSprite(u32, u32, u32);
static u8 InitFieldMoveMonSprite(u32, bool8, u32);
static void SpriteCB_FieldMoveMonSlideOnscreen(struct Sprite *);
static void SpriteCB_FieldMoveMonWaitAfterCry(struct Sprite *);
static void SpriteCB_FieldMoveMonSlideOffscreen(struct Sprite *);
@ -919,7 +919,7 @@ u8 AddNewGameBirchObject(s16 x, s16 y, u8 subpriority)
u8 CreateMonSprite_PicBox(u16 species, s16 x, s16 y, u8 subpriority)
{
s32 spriteId = CreateMonPicSprite(species, 0, 0x8000, TRUE, x, y, 0, species);
s32 spriteId = CreateMonPicSprite(species, FALSE, 0x8000, TRUE, x, y, 0, species);
PreservePaletteInWeather(IndexOfSpritePaletteTag(species) + 0x10);
if (spriteId == 0xFFFF)
return MAX_SPRITES;
@ -927,10 +927,10 @@ u8 CreateMonSprite_PicBox(u16 species, s16 x, s16 y, u8 subpriority)
return spriteId;
}
u8 CreateMonSprite_FieldMove(u16 species, u32 otId, u32 personality, s16 x, s16 y, u8 subpriority)
u8 CreateMonSprite_FieldMove(u16 species, bool8 isShiny, u32 personality, s16 x, s16 y, u8 subpriority)
{
u16 spriteId = CreateMonPicSprite(species, otId, personality, TRUE, x, y, 0, species);
PreservePaletteInWeather(IndexOfSpritePaletteTag(species) + 0x10);
u16 spriteId = CreateMonPicSprite(species, isShiny, personality, TRUE, x, y, 0, species);
PreservePaletteInWeather(gSprites[spriteId].oam.paletteNum + 0x10);
if (spriteId == 0xFFFF)
return MAX_SPRITES;
else
@ -2586,7 +2586,7 @@ bool8 FldEff_FieldMoveShowMonInit(void)
bool32 noDucking = gFieldEffectArguments[0] & SHOW_MON_CRY_NO_DUCKING;
pokemon = &gPlayerParty[(u8)gFieldEffectArguments[0]];
gFieldEffectArguments[0] = GetMonData(pokemon, MON_DATA_SPECIES);
gFieldEffectArguments[1] = GetMonData(pokemon, MON_DATA_OT_ID);
gFieldEffectArguments[1] = GetMonData(pokemon, MON_DATA_IS_SHINY);
gFieldEffectArguments[2] = GetMonData(pokemon, MON_DATA_PERSONALITY);
gFieldEffectArguments[0] |= noDucking;
FieldEffectStart(FLDEFF_FIELD_MOVE_SHOW_MON);
@ -2926,14 +2926,14 @@ static bool8 SlideIndoorBannerOffscreen(struct Task *task)
#undef tBgOffset
#undef tMonSpriteId
static u8 InitFieldMoveMonSprite(u32 species, u32 otId, u32 personality)
static u8 InitFieldMoveMonSprite(u32 species, bool8 isShiny, u32 personality)
{
bool16 noDucking;
u8 monSprite;
struct Sprite *sprite;
noDucking = (species & SHOW_MON_CRY_NO_DUCKING) >> 16;
species &= ~SHOW_MON_CRY_NO_DUCKING;
monSprite = CreateMonSprite_FieldMove(species, otId, personality, 320, 80, 0);
monSprite = CreateMonSprite_FieldMove(species, isShiny, personality, 320, 80, 0);
sprite = &gSprites[monSprite];
sprite->callback = SpriteCallbackDummy;
sprite->oam.priority = 0;

View File

@ -2462,10 +2462,7 @@ void CreateFrontierBrainPokemon(void)
do
{
do
{
j = Random32(); //should just be one while loop, but that doesn't match
} while (IsShinyOtIdPersonality(FRONTIER_BRAIN_OTID, j));
j = Random32(); //should just be one while loop, but that doesn't match
} while (sFrontierBrainsMons[facility][symbol][i].nature != GetNatureFromPersonality(j));
CreateMon(&gEnemyParty[monPartyId],
sFrontierBrainsMons[facility][symbol][i].species,
@ -2484,6 +2481,8 @@ void CreateFrontierBrainPokemon(void)
friendship = 0;
}
SetMonData(&gEnemyParty[monPartyId], MON_DATA_FRIENDSHIP, &friendship);
j = FALSE;
SetMonData(&gPlayerParty[MULTI_PARTY_SIZE + i], MON_DATA_IS_SHINY, &j);
CalculateMonStats(&gEnemyParty[monPartyId]);
monPartyId++;
}

View File

@ -42,7 +42,8 @@ struct HallofFameMon
{
u32 tid;
u32 personality;
u16 species;
u16 isShiny:1;
u16 species:15;
u8 lvl;
u8 nickname[POKEMON_NAME_LENGTH];
};
@ -336,6 +337,7 @@ static const struct HallofFameMon sDummyFameMon =
{
.tid = 0x3EA03EA,
.personality = 0,
.isShiny = FALSE,
.species = SPECIES_NONE,
.lvl = 0,
.nickname = {0}
@ -447,6 +449,7 @@ static void Task_Hof_InitMonData(u8 taskId)
{
sHofMonPtr->mon[i].species = GetMonData(&gPlayerParty[i], MON_DATA_SPECIES_OR_EGG);
sHofMonPtr->mon[i].tid = GetMonData(&gPlayerParty[i], MON_DATA_OT_ID);
sHofMonPtr->mon[i].isShiny = GetMonData(&gPlayerParty[i], MON_DATA_IS_SHINY);
sHofMonPtr->mon[i].personality = GetMonData(&gPlayerParty[i], MON_DATA_PERSONALITY);
sHofMonPtr->mon[i].lvl = GetMonData(&gPlayerParty[i], MON_DATA_LEVEL);
GetMonData(&gPlayerParty[i], MON_DATA_NICKNAME, nickname);
@ -458,6 +461,7 @@ static void Task_Hof_InitMonData(u8 taskId)
{
sHofMonPtr->mon[i].species = SPECIES_NONE;
sHofMonPtr->mon[i].tid = 0;
sHofMonPtr->mon[i].isShiny = FALSE;
sHofMonPtr->mon[i].personality = 0;
sHofMonPtr->mon[i].lvl = 0;
sHofMonPtr->mon[i].nickname[0] = EOS;
@ -583,7 +587,7 @@ static void Task_Hof_DisplayMon(u8 taskId)
if (currMon->species == SPECIES_EGG)
destY += 10;
spriteId = CreateMonPicSprite_Affine(currMon->species, currMon->tid, currMon->personality, MON_PIC_AFFINE_FRONT, startX, startY, currMonId, TAG_NONE);
spriteId = CreateMonPicSprite_Affine(currMon->species, currMon->isShiny, currMon->personality, MON_PIC_AFFINE_FRONT, startX, startY, currMonId, TAG_NONE);
gSprites[spriteId].tDestinationX = destX;
gSprites[spriteId].tDestinationY = destY;
gSprites[spriteId].data[0] = 0;
@ -929,7 +933,7 @@ static void Task_HofPC_DrawSpritesPrintText(u8 taskId)
if (currMon->species == SPECIES_EGG)
posY += 10;
spriteId = CreateMonPicSprite(currMon->species, currMon->tid, currMon->personality, TRUE, posX, posY, i, TAG_NONE);
spriteId = CreateMonPicSprite(currMon->species, currMon->isShiny, currMon->personality, TRUE, posX, posY, i, TAG_NONE);
gSprites[spriteId].oam.priority = 1;
gTasks[taskId].tMonSpriteId(i) = spriteId;
}

View File

@ -797,6 +797,12 @@ void ItemUseOutOfBattle_AbilityPatch(u8 taskId)
SetUpItemUseCallback(taskId);
}
void ItemUseOutOfBattle_Mint(u8 taskId)
{
gItemUseCB = ItemUseCB_Mint;
SetUpItemUseCallback(taskId);
}
void ItemUseOutOfBattle_ResetEVs(u8 taskId)
{
gItemUseCB = ItemUseCB_ResetEVs;
@ -833,6 +839,12 @@ void ItemUseOutOfBattle_RareCandy(u8 taskId)
SetUpItemUseCallback(taskId);
}
void ItemUseOutOfBattle_DynamaxCandy(u8 taskId)
{
gItemUseCB = ItemUseCB_DynamaxCandy;
SetUpItemUseCallback(taskId);
}
void ItemUseOutOfBattle_TMHM(u8 taskId)
{
if (gSpecialVar_ItemId >= ITEM_HM01)

View File

@ -175,7 +175,17 @@ void LoadPlayerParty(void)
gPlayerPartyCount = gSaveBlock1Ptr->playerPartyCount;
for (i = 0; i < PARTY_SIZE; i++)
{
u32 data;
gPlayerParty[i] = gSaveBlock1Ptr->playerParty[i];
// TODO: Turn this into a save migration once those are available.
// At which point we can remove hp and status from Pokemon entirely.
data = gPlayerParty[i].maxHP - gPlayerParty[i].hp;
SetBoxMonData(&gPlayerParty[i].box, MON_DATA_HP_LOST, &data);
data = gPlayerParty[i].status;
SetBoxMonData(&gPlayerParty[i].box, MON_DATA_STATUS, &data);
}
}
void SaveObjectEvents(void)

View File

@ -1876,7 +1876,7 @@ static void SpriteCB_MovePlayerDownWhileShrinking(struct Sprite *sprite)
static u8 NewGameBirchSpeech_CreateLotadSprite(u8 x, u8 y)
{
return CreateMonPicSprite_Affine(SPECIES_LOTAD, SHINY_ODDS, 0, MON_PIC_AFFINE_FRONT, x, y, 14, TAG_NONE);
return CreateMonPicSprite_Affine(SPECIES_LOTAD, FALSE, 0, MON_PIC_AFFINE_FRONT, x, y, 14, TAG_NONE);
}
static void AddBirchSpeechObjects(u8 taskId)

View File

@ -1075,11 +1075,11 @@ void GetConditionMenuMonGfx(void *tilesDst, void *palDst, u16 boxId, u16 monId,
if (partyId != numMons)
{
u16 species = GetBoxOrPartyMonData(boxId, monId, MON_DATA_SPECIES_OR_EGG, NULL);
u32 trainerId = GetBoxOrPartyMonData(boxId, monId, MON_DATA_OT_ID, NULL);
bool8 isShiny = GetBoxOrPartyMonData(boxId, monId, MON_DATA_IS_SHINY, NULL);
u32 personality = GetBoxOrPartyMonData(boxId, monId, MON_DATA_PERSONALITY, NULL);
LoadSpecialPokePic(tilesDst, species, personality, TRUE);
LZ77UnCompWram(GetMonSpritePalFromSpeciesAndPersonality(species, trainerId, personality), palDst);
LZ77UnCompWram(GetMonSpritePalFromSpeciesAndPersonality(species, isShiny, personality), palDst);
}
}

View File

@ -4851,6 +4851,104 @@ void ItemUseCB_AbilityPatch(u8 taskId, TaskFunc task)
#undef tMonId
#undef tOldFunc
#define tState data[0]
#define tMonId data[1]
#define tOldNature data[2]
#define tNewNature data[3]
#define tOldFunc 4
void Task_Mint(u8 taskId)
{
static const u8 askText[] = _("It might affect {STR_VAR_1}'s stats.\nAre you sure you want to use it?");
static const u8 doneText[] = _("{STR_VAR_1}'s stats may have changed due\nto the effects of the {STR_VAR_2}!{PAUSE_UNTIL_PRESS}");
s16 *data = gTasks[taskId].data;
switch (tState)
{
case 0:
// Can't use.
if (tOldNature == tNewNature)
{
gPartyMenuUseExitCallback = FALSE;
PlaySE(SE_SELECT);
DisplayPartyMenuMessage(gText_WontHaveEffect, 1);
ScheduleBgCopyTilemapToVram(2);
gTasks[taskId].func = Task_ClosePartyMenuAfterText;
return;
}
gPartyMenuUseExitCallback = TRUE;
GetMonNickname(&gPlayerParty[tMonId], gStringVar1);
CopyItemName(gSpecialVar_ItemId, gStringVar2);
StringExpandPlaceholders(gStringVar4, askText);
PlaySE(SE_SELECT);
DisplayPartyMenuMessage(gStringVar4, 1);
ScheduleBgCopyTilemapToVram(2);
tState++;
break;
case 1:
if (!IsPartyMenuTextPrinterActive())
{
PartyMenuDisplayYesNoMenu();
tState++;
}
break;
case 2:
switch (Menu_ProcessInputNoWrapClearOnChoose())
{
case 0:
tState++;
break;
case 1:
case MENU_B_PRESSED:
gPartyMenuUseExitCallback = FALSE;
PlaySE(SE_SELECT);
ScheduleBgCopyTilemapToVram(2);
// Don't exit party selections screen, return to choosing a mon.
ClearStdWindowAndFrameToTransparent(6, 0);
ClearWindowTilemap(6);
DisplayPartyMenuStdMessage(5);
gTasks[taskId].func = (void *)GetWordTaskArg(taskId, tOldFunc);
return;
}
break;
case 3:
PlaySE(SE_USE_ITEM);
StringExpandPlaceholders(gStringVar4, doneText);
DisplayPartyMenuMessage(gStringVar4, 1);
ScheduleBgCopyTilemapToVram(2);
tState++;
break;
case 4:
if (!IsPartyMenuTextPrinterActive())
tState++;
break;
case 5:
SetMonData(&gPlayerParty[tMonId], MON_DATA_HIDDEN_NATURE, &tNewNature);
CalculateMonStats(&gPlayerParty[tMonId]);
RemoveBagItem(gSpecialVar_ItemId, 1);
gTasks[taskId].func = Task_ClosePartyMenu;
break;
}
}
void ItemUseCB_Mint(u8 taskId, TaskFunc task)
{
s16 *data = gTasks[taskId].data;
tState = 0;
tMonId = gPartyMenu.slotId;
tOldNature = GetMonData(&gPlayerParty[tMonId], MON_DATA_HIDDEN_NATURE);
tNewNature = ItemId_GetSecondaryId(gSpecialVar_ItemId);
SetWordTaskArg(taskId, tOldFunc, (uintptr_t)(gTasks[taskId].func));
gTasks[taskId].func = Task_Mint;
}
#undef tState
#undef tMonId
#undef tOldNature
#undef tNewNature
#undef tOldFunc
static void Task_DisplayHPRestoredMessage(u8 taskId)
{
GetMonNickname(&gPlayerParty[gPartyMenu.slotId], gStringVar1);
@ -5672,6 +5770,70 @@ static void BufferMonStatsToTaskData(struct Pokemon *mon, s16 *data)
data[3] = GetMonData(mon, MON_DATA_SPEED);
}
#define tState data[0]
#define tMonId data[1]
#define tDynamaxLevel data[2]
#define tOldFunc 4
void Task_DynamaxCandy(u8 taskId)
{
static const u8 doneText[] = _("{STR_VAR_1}'s Dynamax Level\nincreased by 1!{PAUSE_UNTIL_PRESS}");
s16 *data = gTasks[taskId].data;
switch (tState)
{
case 0:
// Can't use.
if (tDynamaxLevel == MAX_DYNAMAX_LEVEL)
{
gPartyMenuUseExitCallback = FALSE;
PlaySE(SE_SELECT);
DisplayPartyMenuMessage(gText_WontHaveEffect, 1);
ScheduleBgCopyTilemapToVram(2);
gTasks[taskId].func = Task_ClosePartyMenuAfterText;
return;
}
gPartyMenuUseExitCallback = TRUE;
GetMonNickname(&gPlayerParty[tMonId], gStringVar1);
CopyItemName(gSpecialVar_ItemId, gStringVar2);
tState++;
break;
case 1:
PlaySE(SE_USE_ITEM);
StringExpandPlaceholders(gStringVar4, doneText);
DisplayPartyMenuMessage(gStringVar4, 1);
ScheduleBgCopyTilemapToVram(2);
tState++;
break;
case 2:
if (!IsPartyMenuTextPrinterActive())
tState++;
break;
case 3:
tDynamaxLevel++;
SetMonData(&gPlayerParty[tMonId], MON_DATA_DYNAMAX_LEVEL, &tDynamaxLevel);
RemoveBagItem(gSpecialVar_ItemId, 1);
gTasks[taskId].func = Task_ClosePartyMenu;
break;
}
}
void ItemUseCB_DynamaxCandy(u8 taskId, TaskFunc task)
{
s16 *data = gTasks[taskId].data;
tState = 0;
tMonId = gPartyMenu.slotId;
tDynamaxLevel = GetMonData(&gPlayerParty[tMonId], MON_DATA_DYNAMAX_LEVEL);
SetWordTaskArg(taskId, tOldFunc, (uintptr_t)(gTasks[taskId].func));
gTasks[taskId].func = Task_DynamaxCandy;
}
#undef tState
#undef tMonId
#undef tDynamaxLevel
#undef tOldFunc
#define tUsedOnSlot data[0]
#define tHadEffect data[1]
#define tLastSlotUsed data[2]

View File

@ -718,7 +718,8 @@ static void HandleInitBackgrounds(void)
static bool8 LoadMonAndSceneGfx(struct Pokemon *mon)
{
u16 species;
u32 personality, trainerId;
u32 personality;
bool32 isShiny;
switch (sPokeblockFeed->loadGfxState)
{
@ -733,8 +734,8 @@ static bool8 LoadMonAndSceneGfx(struct Pokemon *mon)
// Load mon palette
species = GetMonData(mon, MON_DATA_SPECIES_OR_EGG);
personality = GetMonData(mon, MON_DATA_PERSONALITY);
trainerId = GetMonData(mon, MON_DATA_OT_ID);
LoadCompressedSpritePaletteWithTag(GetMonSpritePalFromSpeciesAndPersonality(species, trainerId, personality), species);
isShiny = GetMonData(mon, MON_DATA_IS_SHINY);
LoadCompressedSpritePaletteWithTag(GetMonSpritePalFromSpeciesAndPersonality(species, isShiny, personality), species);
SetMultiuseSpriteTemplateToPokemon(species, B_POSITION_OPPONENT_LEFT);
sPokeblockFeed->loadGfxState++;
break;

View File

@ -3971,12 +3971,11 @@ static void HighlightSubmenuScreenSelectBarItem(u8 a, u16 b)
#define tSpecies data[1]
#define tPalTimer data[2]
#define tMonSpriteId data[3]
#define tOtIdLo data[12]
#define tOtIdHi data[13]
#define tIsShiny data[13]
#define tPersonalityLo data[14]
#define tPersonalityHi data[15]
u8 DisplayCaughtMonDexPage(u16 species, u32 otId, u32 personality)
u8 DisplayCaughtMonDexPage(u16 species, bool32 isShiny, u32 personality)
{
u8 taskId = 0;
if (POKEDEX_PLUS_HGSS)
@ -3986,8 +3985,7 @@ u8 DisplayCaughtMonDexPage(u16 species, u32 otId, u32 personality)
gTasks[taskId].tState = 0;
gTasks[taskId].tSpecies = species;
gTasks[taskId].tOtIdLo = otId;
gTasks[taskId].tOtIdHi = otId >> 16;
gTasks[taskId].tIsShiny = isShiny;
gTasks[taskId].tPersonalityLo = personality;
gTasks[taskId].tPersonalityHi = personality >> 16;
return taskId;
@ -4039,7 +4037,7 @@ static void Task_DisplayCaughtMonDexPage(u8 taskId)
gTasks[taskId].tState++;
break;
case 4:
spriteId = CreateMonPicSprite(NationalPokedexNumToSpecies(dexNum), 0, ((u16)gTasks[taskId].tPersonalityHi << 16) | (u16)gTasks[taskId].tPersonalityLo, TRUE, MON_PAGE_X, MON_PAGE_Y, 0, TAG_NONE);
spriteId = CreateMonPicSprite(NationalPokedexNumToSpecies(dexNum), FALSE, ((u16)gTasks[taskId].tPersonalityHi << 16) | (u16)gTasks[taskId].tPersonalityLo, TRUE, MON_PAGE_X, MON_PAGE_Y, 0, TAG_NONE);
gSprites[spriteId].oam.priority = 0;
BeginNormalPaletteFade(PALETTES_ALL, 0, 0x10, 0, RGB_BLACK);
SetVBlankCallback(gPokedexVBlankCB);
@ -4089,7 +4087,7 @@ static void Task_ExitCaughtMonPage(u8 taskId)
{
if (!gPaletteFade.active)
{
u32 otId;
bool32 isShiny;
u32 personality;
u8 paletteNum;
const u32 *lzPaletteData;
@ -4104,10 +4102,10 @@ static void Task_ExitCaughtMonPage(u8 taskId)
if (buffer)
Free(buffer);
otId = ((u16)gTasks[taskId].tOtIdHi << 16) | (u16)gTasks[taskId].tOtIdLo;
isShiny = (bool8)gTasks[taskId].tIsShiny;
personality = ((u16)gTasks[taskId].tPersonalityHi << 16) | (u16)gTasks[taskId].tPersonalityLo;
paletteNum = gSprites[gTasks[taskId].tMonSpriteId].oam.paletteNum;
lzPaletteData = GetMonSpritePalFromSpeciesAndPersonality(gTasks[taskId].tSpecies, otId, personality);
lzPaletteData = GetMonSpritePalFromSpeciesAndPersonality(gTasks[taskId].tSpecies, isShiny, personality);
LoadCompressedPalette(lzPaletteData, OBJ_PLTT_ID(paletteNum), PLTT_SIZE_4BPP);
DestroyTask(taskId);
}
@ -4654,7 +4652,7 @@ static u32 GetPokedexMonPersonality(u16 species)
u16 CreateMonSpriteFromNationalDexNumber(u16 nationalNum, s16 x, s16 y, u16 paletteSlot)
{
nationalNum = NationalPokedexNumToSpecies(nationalNum);
return CreateMonPicSprite(nationalNum, SHINY_ODDS, GetPokedexMonPersonality(nationalNum), TRUE, x, y, paletteSlot, TAG_NONE);
return CreateMonPicSprite(nationalNum, FALSE, GetPokedexMonPersonality(nationalNum), TRUE, x, y, paletteSlot, TAG_NONE);
}
static u16 GetPokemonScaleFromNationalDexNumber(u16 nationalNum)

View File

@ -673,6 +673,63 @@ static const struct SpriteTemplate sSpriteTemplate_64x64 =
.callback = SpriteCallbackDummy,
};
// NOTE: Reordering this array will break compatibility with existing
// saves.
static const u32 sCompressedStatuses[] =
{
STATUS1_NONE,
STATUS1_SLEEP_TURN(1),
STATUS1_SLEEP_TURN(2),
STATUS1_SLEEP_TURN(3),
STATUS1_SLEEP_TURN(4),
STATUS1_SLEEP_TURN(5),
STATUS1_POISON,
STATUS1_BURN,
STATUS1_FREEZE,
STATUS1_PARALYSIS,
STATUS1_TOXIC_POISON,
STATUS1_FROSTBITE,
};
// Attempt to detect situations where the BoxPokemon struct is unable to
// contain all the values.
// TODO: Is it possible to compute:
// - The maximum experience.
// - The maximum PP.
// - The maximum HP.
// - The maximum form countdown.
STATIC_ASSERT(NUM_SPECIES < (1 << 11), PokemonSubstruct0_species_TooSmall);
STATIC_ASSERT(NUMBER_OF_MON_TYPES + 1 <= (1 << 5), PokemonSubstruct0_teraType_TooSmall);
STATIC_ASSERT(ITEMS_COUNT < (1 << 10), PokemonSubstruct0_heldItem_TooSmall);
STATIC_ASSERT(MAX_LEVEL <= 100, PokemonSubstruct0_experience_PotentiallTooSmall); // Maximum of ~2 million exp.
STATIC_ASSERT(LAST_BALL < (1 << 6), PokemonSubstruct0_pokeball_TooSmall);
STATIC_ASSERT(MOVES_COUNT_ALL < (1 << 11), PokemonSubstruct1_moves_TooSmall);
STATIC_ASSERT(ARRAY_COUNT(sCompressedStatuses) <= (1 << 4), PokemonSubstruct3_compressedStatus_TooSmall);
STATIC_ASSERT(MAX_LEVEL < (1 << 7), PokemonSubstruct3_metLevel_TooSmall);
STATIC_ASSERT(NUM_VERSIONS < (1 << 4), PokemonSubstruct3_metGame_TooSmall);
STATIC_ASSERT(MAX_DYNAMAX_LEVEL < (1 << 4), PokemonSubstruct3_dynamaxLevel_TooSmall);
STATIC_ASSERT(MAX_PER_STAT_IVS < (1 << 5), PokemonSubstruct3_ivs_TooSmall);
STATIC_ASSERT(NUM_NATURES <= (1 << 5), BoxPokemon_hiddenNatureModifier_TooSmall);
static u32 CompressStatus(u32 status)
{
s32 i;
for (i = 0; i < ARRAY_COUNT(sCompressedStatuses); i++)
{
if (sCompressedStatuses[i] == status)
return i;
}
return 0; // STATUS1_NONE
}
static u32 UncompressStatus(u32 compressedStatus)
{
if (compressedStatus < ARRAY_COUNT(sCompressedStatuses))
return sCompressedStatuses[compressedStatus];
else
return STATUS1_NONE;
}
void ZeroBoxMonData(struct BoxPokemon *boxMon)
{
u8 *raw = (u8 *)boxMon;
@ -733,6 +790,7 @@ void CreateBoxMon(struct BoxPokemon *boxMon, u16 species, u8 level, u8 fixedIV,
u8 i;
u8 availableIVs[NUM_STATS];
u8 selectedIvs[LEGENDARY_PERFECT_IV_COUNT];
bool32 isShiny;
ZeroBoxMonData(boxMon);
@ -744,17 +802,13 @@ void CreateBoxMon(struct BoxPokemon *boxMon, u16 species, u8 level, u8 fixedIV,
// Determine original trainer ID
if (otIdType == OT_ID_RANDOM_NO_SHINY)
{
u32 shinyValue;
do
{
// Choose random OT IDs until one that results in a non-shiny Pokémon
value = Random32();
shinyValue = GET_SHINY_VALUE(value, personality);
} while (shinyValue < SHINY_ODDS);
value = Random32();
isShiny = FALSE;
}
else if (otIdType == OT_ID_PRESET)
{
value = fixedOtId;
isShiny = GET_SHINY_VALUE(value, personality) < SHINY_ODDS;
}
else // Player is the OT
{
@ -763,26 +817,15 @@ void CreateBoxMon(struct BoxPokemon *boxMon, u16 species, u8 level, u8 fixedIV,
| (gSaveBlock2Ptr->playerTrainerId[2] << 16)
| (gSaveBlock2Ptr->playerTrainerId[3] << 24);
#if P_FLAG_FORCE_NO_SHINY != 0
if (FlagGet(P_FLAG_FORCE_NO_SHINY))
if (P_FLAG_FORCE_NO_SHINY != 0 && FlagGet(P_FLAG_FORCE_NO_SHINY))
{
while (GET_SHINY_VALUE(value, personality) < SHINY_ODDS)
personality = Random32();
isShiny = FALSE;
}
#endif
#if P_FLAG_FORCE_SHINY != 0
#if P_FLAG_FORCE_NO_SHINY != 0
else
#endif
if (FlagGet(P_FLAG_FORCE_SHINY))
else if (P_FLAG_FORCE_SHINY != 0 && FlagGet(P_FLAG_FORCE_SHINY))
{
while (GET_SHINY_VALUE(value, personality) >= SHINY_ODDS)
personality = Random32();
isShiny = TRUE;
}
#endif
#if P_FLAG_FORCE_SHINY != 0 || P_FLAG_FORCE_NO_SHINY != 0
else
#endif
{
u32 totalRerolls = 0;
if (CheckBagHasItem(ITEM_SHINY_CHARM, 1))
@ -795,6 +838,8 @@ void CreateBoxMon(struct BoxPokemon *boxMon, u16 species, u8 level, u8 fixedIV,
personality = Random32();
totalRerolls--;
}
isShiny = GET_SHINY_VALUE(value, personality) < SHINY_ODDS;
}
}
@ -804,6 +849,7 @@ void CreateBoxMon(struct BoxPokemon *boxMon, u16 species, u8 level, u8 fixedIV,
checksum = CalculateBoxMonChecksum(boxMon);
SetBoxMonData(boxMon, MON_DATA_CHECKSUM, &checksum);
EncryptBoxMon(boxMon);
SetBoxMonData(boxMon, MON_DATA_IS_SHINY, &isShiny);
StringCopy(speciesName, GetSpeciesName(species));
SetBoxMonData(boxMon, MON_DATA_NICKNAME, speciesName);
SetBoxMonData(boxMon, MON_DATA_LANGUAGE, &gGameLanguage);
@ -1382,7 +1428,6 @@ static u16 CalculateBoxMonChecksum(struct BoxPokemon *boxMon)
{ \
u8 baseStat = gSpeciesInfo[species].base; \
s32 n = (((2 * baseStat + iv + ev / 4) * level) / 100) + 5; \
u8 nature = GetNature(mon); \
n = ModifyStatByNature(nature, n, statIndex); \
if (B_FRIENDSHIP_BOOST == TRUE) \
n = n + ((n * 10 * friendship) / (MAX_FRIENDSHIP * 100));\
@ -1393,23 +1438,25 @@ void CalculateMonStats(struct Pokemon *mon)
{
s32 oldMaxHP = GetMonData(mon, MON_DATA_MAX_HP, NULL);
s32 currentHP = GetMonData(mon, MON_DATA_HP, NULL);
s32 hpIV = GetMonData(mon, MON_DATA_HP_IV, NULL);
s32 hpIV = GetMonData(mon, MON_DATA_HYPER_TRAINED_HP) ? MAX_PER_STAT_IVS : GetMonData(mon, MON_DATA_HP_IV, NULL);
s32 hpEV = GetMonData(mon, MON_DATA_HP_EV, NULL);
s32 attackIV = GetMonData(mon, MON_DATA_ATK_IV, NULL);
s32 attackIV = GetMonData(mon, MON_DATA_HYPER_TRAINED_ATK) ? MAX_PER_STAT_IVS : GetMonData(mon, MON_DATA_ATK_IV, NULL);
s32 attackEV = GetMonData(mon, MON_DATA_ATK_EV, NULL);
s32 defenseIV = GetMonData(mon, MON_DATA_DEF_IV, NULL);
s32 defenseIV = GetMonData(mon, MON_DATA_HYPER_TRAINED_DEF) ? MAX_PER_STAT_IVS : GetMonData(mon, MON_DATA_DEF_IV, NULL);
s32 defenseEV = GetMonData(mon, MON_DATA_DEF_EV, NULL);
s32 speedIV = GetMonData(mon, MON_DATA_SPEED_IV, NULL);
s32 speedIV = GetMonData(mon, MON_DATA_HYPER_TRAINED_SPEED) ? MAX_PER_STAT_IVS : GetMonData(mon, MON_DATA_SPEED_IV, NULL);
s32 speedEV = GetMonData(mon, MON_DATA_SPEED_EV, NULL);
s32 spAttackIV = GetMonData(mon, MON_DATA_SPATK_IV, NULL);
s32 spAttackIV = GetMonData(mon, MON_DATA_HYPER_TRAINED_SPATK) ? MAX_PER_STAT_IVS : GetMonData(mon, MON_DATA_SPATK_IV, NULL);
s32 spAttackEV = GetMonData(mon, MON_DATA_SPATK_EV, NULL);
s32 spDefenseIV = GetMonData(mon, MON_DATA_SPDEF_IV, NULL);
s32 spDefenseIV = GetMonData(mon, MON_DATA_HYPER_TRAINED_SPDEF) ? MAX_PER_STAT_IVS : GetMonData(mon, MON_DATA_SPDEF_IV, NULL);
s32 spDefenseEV = GetMonData(mon, MON_DATA_SPDEF_EV, NULL);
u16 species = GetMonData(mon, MON_DATA_SPECIES, NULL);
u8 friendship = GetMonData(mon, MON_DATA_FRIENDSHIP, NULL);
s32 level = GetLevelFromMonExp(mon);
s32 newMaxHP;
u8 nature = GetMonData(mon, MON_DATA_HIDDEN_NATURE, NULL);
SetMonData(mon, MON_DATA_LEVEL, &level);
if (species == SPECIES_SHEDINJA)
@ -1465,12 +1512,15 @@ void BoxMonToMon(const struct BoxPokemon *src, struct Pokemon *dest)
{
u32 value = 0;
dest->box = *src;
SetMonData(dest, MON_DATA_STATUS, &value);
SetMonData(dest, MON_DATA_HP, &value);
SetMonData(dest, MON_DATA_MAX_HP, &value);
dest->status = GetBoxMonData(&dest->box, MON_DATA_STATUS, NULL);
dest->hp = 0;
dest->maxHP = 0;
value = MAIL_NONE;
SetMonData(dest, MON_DATA_MAIL, &value);
value = GetBoxMonData(&dest->box, MON_DATA_HP_LOST);
CalculateMonStats(dest);
value = GetMonData(dest, MON_DATA_MAX_HP) - value;
SetMonData(dest, MON_DATA_HP, &value);
}
u8 GetLevelFromMonExp(struct Pokemon *mon)
@ -2044,6 +2094,76 @@ u32 GetBoxMonData3(struct BoxPokemon *boxMon, s32 field, u8 *data)
switch (field)
{
case MON_DATA_NICKNAME:
{
if (boxMon->isBadEgg)
{
for (retVal = 0;
retVal < POKEMON_NAME_LENGTH && gText_BadEgg[retVal] != EOS;
data[retVal] = gText_BadEgg[retVal], retVal++) {}
data[retVal] = EOS;
}
else if (boxMon->isEgg)
{
StringCopy(data, gText_EggNickname);
retVal = StringLength(data);
}
else if (boxMon->language == LANGUAGE_JAPANESE)
{
data[0] = EXT_CTRL_CODE_BEGIN;
data[1] = EXT_CTRL_CODE_JPN;
for (retVal = 2, i = 0;
i < 5 && boxMon->nickname[i] != EOS;
data[retVal] = boxMon->nickname[i], retVal++, i++) {}
data[retVal++] = EXT_CTRL_CODE_BEGIN;
data[retVal++] = EXT_CTRL_CODE_ENG;
data[retVal] = EOS;
}
else
{
retVal = 0;
while (retVal < min(sizeof(boxMon->nickname), POKEMON_NAME_LENGTH))
{
data[retVal] = boxMon->nickname[retVal];
retVal++;
}
// Vanilla Pokémon have 0s in nickname11 and nickname12
// so if both are 0 we assume that this is a vanilla
// Pokémon and replace them with EOS. This means that
// two CHAR_SPACE at the end of a nickname are trimmed.
if (POKEMON_NAME_LENGTH >= 12)
{
if (substruct0->nickname11 == 0 && substruct0->nickname12 == 0)
{
data[retVal++] = EOS;
data[retVal++] = EOS;
}
else
{
data[retVal++] = substruct0->nickname11;
data[retVal++] = substruct0->nickname12;
}
}
else if (POKEMON_NAME_LENGTH >= 11)
{
if (substruct0->nickname11 == 0)
{
data[retVal++] = EOS;
}
else
{
data[retVal++] = substruct0->nickname11;
}
}
data[retVal] = EOS;
}
break;
}
case MON_DATA_SPECIES:
retVal = boxMon->isBadEgg ? SPECIES_EGG : substruct0->species;
break;
@ -2060,16 +2180,28 @@ u32 GetBoxMonData3(struct BoxPokemon *boxMon, s32 field, u8 *data)
retVal = substruct0->friendship;
break;
case MON_DATA_MOVE1:
retVal = substruct1->move1;
break;
case MON_DATA_MOVE2:
retVal = substruct1->move2;
break;
case MON_DATA_MOVE3:
retVal = substruct1->move3;
break;
case MON_DATA_MOVE4:
retVal = substruct1->moves[field - MON_DATA_MOVE1];
retVal = substruct1->move4;
break;
case MON_DATA_PP1:
retVal = substruct1->pp1;
break;
case MON_DATA_PP2:
retVal = substruct1->pp2;
break;
case MON_DATA_PP3:
retVal = substruct1->pp3;
break;
case MON_DATA_PP4:
retVal = substruct1->pp[field - MON_DATA_PP1];
retVal = substruct1->pp4;
break;
case MON_DATA_HP_EV:
retVal = substruct2->hpEV;
@ -2200,9 +2332,6 @@ u32 GetBoxMonData3(struct BoxPokemon *boxMon, s32 field, u8 *data)
case MON_DATA_WORLD_RIBBON:
retVal = substruct3->worldRibbon;
break;
case MON_DATA_UNUSED_RIBBONS:
retVal = substruct3->unusedRibbons;
break;
case MON_DATA_MODERN_FATEFUL_ENCOUNTER:
retVal = substruct3->modernFatefulEncounter;
break;
@ -2228,10 +2357,10 @@ u32 GetBoxMonData3(struct BoxPokemon *boxMon, s32 field, u8 *data)
while (moves[i] != MOVES_COUNT)
{
u16 move = moves[i];
if (substruct1->moves[0] == move
|| substruct1->moves[1] == move
|| substruct1->moves[2] == move
|| substruct1->moves[3] == move)
if (substruct1->move1 == move
|| substruct1->move2 == move
|| substruct1->move3 == move
|| substruct1->move4 == move)
retVal |= gBitTable[i];
i++;
}
@ -2283,6 +2412,46 @@ u32 GetBoxMonData3(struct BoxPokemon *boxMon, s32 field, u8 *data)
| (substruct3->worldRibbon << 26);
}
break;
case MON_DATA_HYPER_TRAINED_HP:
retVal = substruct1->hyperTrainedHP;
break;
case MON_DATA_HYPER_TRAINED_ATK:
retVal = substruct1->hyperTrainedAttack;
break;
case MON_DATA_HYPER_TRAINED_DEF:
retVal = substruct1->hyperTrainedDefense;
break;
case MON_DATA_HYPER_TRAINED_SPEED:
retVal = substruct1->hyperTrainedSpeed;
break;
case MON_DATA_HYPER_TRAINED_SPATK:
retVal = substruct1->hyperTrainedSpAttack;
break;
case MON_DATA_HYPER_TRAINED_SPDEF:
retVal = substruct1->hyperTrainedSpDefense;
break;
case MON_DATA_IS_SHADOW:
retVal = substruct3->isShadow;
break;
case MON_DATA_DYNAMAX_LEVEL:
retVal = substruct3->dynamaxLevel;
break;
case MON_DATA_GIGANTAMAX_FACTOR:
retVal = substruct3->gigantamaxFactor;
break;
case MON_DATA_TERA_TYPE:
{
if (substruct0->teraType == 0)
{
const u8 *types = gSpeciesInfo[substruct0->species].types;
retVal = (boxMon->personality & 0x1) == 0 ? types[0] : types[1];
}
else
{
retVal = substruct0->teraType - 1;
}
break;
}
default:
break;
}
@ -2291,50 +2460,18 @@ u32 GetBoxMonData3(struct BoxPokemon *boxMon, s32 field, u8 *data)
{
switch (field)
{
case MON_DATA_STATUS:
retVal = UncompressStatus(boxMon->compressedStatus);
break;
case MON_DATA_HP_LOST:
retVal = boxMon->hpLost;
break;
case MON_DATA_PERSONALITY:
retVal = boxMon->personality;
break;
case MON_DATA_OT_ID:
retVal = boxMon->otId;
break;
case MON_DATA_NICKNAME:
{
if (boxMon->isBadEgg)
{
for (retVal = 0;
retVal < POKEMON_NAME_LENGTH && gText_BadEgg[retVal] != EOS;
data[retVal] = gText_BadEgg[retVal], retVal++) {}
data[retVal] = EOS;
}
else if (boxMon->isEgg)
{
StringCopy(data, gText_EggNickname);
retVal = StringLength(data);
}
else if (boxMon->language == LANGUAGE_JAPANESE)
{
data[0] = EXT_CTRL_CODE_BEGIN;
data[1] = EXT_CTRL_CODE_JPN;
for (retVal = 2, i = 0;
i < 5 && boxMon->nickname[i] != EOS;
data[retVal] = boxMon->nickname[i], retVal++, i++) {}
data[retVal++] = EXT_CTRL_CODE_BEGIN;
data[retVal++] = EXT_CTRL_CODE_ENG;
data[retVal] = EOS;
}
else
{
for (retVal = 0;
retVal < POKEMON_NAME_LENGTH;
data[retVal] = boxMon->nickname[retVal], retVal++){}
data[retVal] = EOS;
}
break;
}
case MON_DATA_LANGUAGE:
retVal = boxMon->language;
break;
@ -2366,9 +2503,18 @@ u32 GetBoxMonData3(struct BoxPokemon *boxMon, s32 field, u8 *data)
case MON_DATA_CHECKSUM:
retVal = boxMon->checksum;
break;
case MON_DATA_ENCRYPT_SEPARATOR:
retVal = boxMon->unknown;
case MON_DATA_IS_SHINY:
{
u32 shinyValue = GET_SHINY_VALUE(boxMon->otId, boxMon->personality);
retVal = (shinyValue < SHINY_ODDS) ^ boxMon->shinyModifier;
break;
}
case MON_DATA_HIDDEN_NATURE:
{
u32 nature = GetNatureFromPersonality(boxMon->personality);
retVal = nature ^ boxMon->hiddenNatureModifier;
break;
}
default:
break;
}
@ -2397,13 +2543,27 @@ void SetMonData(struct Pokemon *mon, s32 field, const void *dataArg)
{
case MON_DATA_STATUS:
SET32(mon->status);
SetBoxMonData(&mon->box, MON_DATA_STATUS, dataArg);
break;
case MON_DATA_LEVEL:
SET8(mon->level);
break;
case MON_DATA_HP:
{
u32 hpLost;
SET16(mon->hp);
hpLost = mon->maxHP - mon->hp;
SetBoxMonData(&mon->box, MON_DATA_HP_LOST, &hpLost);
break;
}
case MON_DATA_HP_LOST:
{
u32 hpLost;
SET16(hpLost);
mon->hp = mon->maxHP - hpLost;
SetBoxMonData(&mon->box, MON_DATA_HP_LOST, &hpLost);
break;
}
case MON_DATA_MAX_HP:
SET16(mon->maxHP);
break;
@ -2462,6 +2622,17 @@ void SetBoxMonData(struct BoxPokemon *boxMon, s32 field, const void *dataArg)
switch (field)
{
case MON_DATA_NICKNAME:
{
s32 i;
for (i = 0; i < min(sizeof(boxMon->nickname), POKEMON_NAME_LENGTH); i++)
boxMon->nickname[i] = data[i];
if (POKEMON_NAME_LENGTH >= 11)
substruct0->nickname11 = data[10];
if (POKEMON_NAME_LENGTH >= 12)
substruct0->nickname12 = data[11];
break;
}
case MON_DATA_SPECIES:
{
SET16(substruct0->species);
@ -2484,16 +2655,28 @@ void SetBoxMonData(struct BoxPokemon *boxMon, s32 field, const void *dataArg)
SET8(substruct0->friendship);
break;
case MON_DATA_MOVE1:
SET16(substruct1->move1);
break;
case MON_DATA_MOVE2:
SET16(substruct1->move2);
break;
case MON_DATA_MOVE3:
SET16(substruct1->move3);
break;
case MON_DATA_MOVE4:
SET16(substruct1->moves[field - MON_DATA_MOVE1]);
SET16(substruct1->move4);
break;
case MON_DATA_PP1:
SET8(substruct1->pp1);
break;
case MON_DATA_PP2:
SET8(substruct1->pp2);
break;
case MON_DATA_PP3:
SET8(substruct1->pp3);
break;
case MON_DATA_PP4:
SET8(substruct1->pp[field - MON_DATA_PP1]);
SET8(substruct1->pp4);
break;
case MON_DATA_HP_EV:
SET8(substruct2->hpEV);
@ -2634,9 +2817,6 @@ void SetBoxMonData(struct BoxPokemon *boxMon, s32 field, const void *dataArg)
case MON_DATA_WORLD_RIBBON:
SET8(substruct3->worldRibbon);
break;
case MON_DATA_UNUSED_RIBBONS:
SET8(substruct3->unusedRibbons);
break;
case MON_DATA_MODERN_FATEFUL_ENCOUNTER:
SET8(substruct3->modernFatefulEncounter);
break;
@ -2651,6 +2831,40 @@ void SetBoxMonData(struct BoxPokemon *boxMon, s32 field, const void *dataArg)
substruct3->spDefenseIV = (ivs >> 25) & MAX_IV_MASK;
break;
}
case MON_DATA_HYPER_TRAINED_HP:
SET8(substruct1->hyperTrainedHP);
break;
case MON_DATA_HYPER_TRAINED_ATK:
SET8(substruct1->hyperTrainedAttack);
break;
case MON_DATA_HYPER_TRAINED_DEF:
SET8(substruct1->hyperTrainedDefense);
break;
case MON_DATA_HYPER_TRAINED_SPEED:
SET8(substruct1->hyperTrainedSpeed);
break;
case MON_DATA_HYPER_TRAINED_SPATK:
SET8(substruct1->hyperTrainedSpAttack);
break;
case MON_DATA_HYPER_TRAINED_SPDEF:
SET8(substruct1->hyperTrainedSpDefense);
break;
case MON_DATA_IS_SHADOW:
SET8(substruct3->isShadow);
break;
case MON_DATA_DYNAMAX_LEVEL:
SET8(substruct3->dynamaxLevel);
break;
case MON_DATA_GIGANTAMAX_FACTOR:
SET8(substruct3->gigantamaxFactor);
break;
case MON_DATA_TERA_TYPE:
{
u32 teraType;
SET8(teraType);
substruct0->teraType = 1 + teraType;
break;
}
default:
break;
}
@ -2659,19 +2873,22 @@ void SetBoxMonData(struct BoxPokemon *boxMon, s32 field, const void *dataArg)
{
switch (field)
{
case MON_DATA_STATUS:
{
u32 status;
SET32(status);
boxMon->compressedStatus = CompressStatus(status);
break;
}
case MON_DATA_HP_LOST:
SET16(boxMon->hpLost);
break;
case MON_DATA_PERSONALITY:
SET32(boxMon->personality);
break;
case MON_DATA_OT_ID:
SET32(boxMon->otId);
break;
case MON_DATA_NICKNAME:
{
s32 i;
for (i = 0; i < POKEMON_NAME_LENGTH; i++)
boxMon->nickname[i] = data[i];
break;
}
case MON_DATA_LANGUAGE:
SET8(boxMon->language);
break;
@ -2697,10 +2914,23 @@ void SetBoxMonData(struct BoxPokemon *boxMon, s32 field, const void *dataArg)
case MON_DATA_CHECKSUM:
SET16(boxMon->checksum);
break;
case MON_DATA_ENCRYPT_SEPARATOR:
SET16(boxMon->unknown);
case MON_DATA_IS_SHINY:
{
u32 shinyValue = GET_SHINY_VALUE(boxMon->otId, boxMon->personality);
bool32 isShiny;
SET8(isShiny);
boxMon->shinyModifier = (shinyValue < SHINY_ODDS) ^ isShiny;
break;
}
case MON_DATA_HIDDEN_NATURE:
{
u32 nature = GetNatureFromPersonality(boxMon->personality);
u32 hiddenNature;
SET8(hiddenNature);
boxMon->hiddenNatureModifier = nature ^ hiddenNature;
break;
}
}
}
if (field > MON_DATA_ENCRYPT_SEPARATOR)
@ -3764,6 +3994,18 @@ u8 GetNatureFromPersonality(u32 personality)
return personality % NUM_NATURES;
}
static u32 GetGMaxTargetSpecies(u32 species)
{
const struct FormChange *formChanges = GetSpeciesFormChanges(species);
u32 i;
for (i = 0; formChanges[i].method != FORM_CHANGE_TERMINATOR; i++)
{
if (formChanges[i].method == FORM_CHANGE_BATTLE_GIGANTAMAX)
return formChanges[i].targetSpecies;
}
return SPECIES_NONE;
}
u16 GetEvolutionTargetSpecies(struct Pokemon *mon, u8 mode, u16 evolutionItem, struct Pokemon *tradePartner)
{
int i, j;
@ -3776,6 +4018,7 @@ u16 GetEvolutionTargetSpecies(struct Pokemon *mon, u8 mode, u16 evolutionItem, s
u8 beauty = GetMonData(mon, MON_DATA_BEAUTY, 0);
u16 upperPersonality = personality >> 16;
u32 holdEffect, currentMap, partnerSpecies, partnerHeldItem, partnerHoldEffect;
bool32 consumeItem = FALSE;
const struct Evolution *evolutions = GetSpeciesEvolutions(species);
if (evolutions == NULL)
@ -3848,17 +4091,15 @@ u16 GetEvolutionTargetSpecies(struct Pokemon *mon, u8 mode, u16 evolutionItem, s
case EVO_ITEM_HOLD_NIGHT:
if (GetTimeOfDay() == TIME_NIGHT && heldItem == evolutions[i].param)
{
heldItem = ITEM_NONE;
SetMonData(mon, MON_DATA_HELD_ITEM, &heldItem);
targetSpecies = evolutions[i].targetSpecies;
consumeItem = TRUE;
}
break;
case EVO_ITEM_HOLD_DAY:
if (GetTimeOfDay() != TIME_NIGHT && heldItem == evolutions[i].param)
{
heldItem = ITEM_NONE;
SetMonData(mon, MON_DATA_HELD_ITEM, &heldItem);
targetSpecies = evolutions[i].targetSpecies;
consumeItem = TRUE;
}
break;
case EVO_LEVEL_DUSK:
@ -4037,9 +4278,8 @@ u16 GetEvolutionTargetSpecies(struct Pokemon *mon, u8 mode, u16 evolutionItem, s
case EVO_ITEM_HOLD:
if (heldItem == evolutions[i].param)
{
heldItem = 0;
SetMonData(mon, MON_DATA_HELD_ITEM, &heldItem);
targetSpecies = evolutions[i].targetSpecies;
consumeItem = TRUE;
}
break;
}
@ -4059,9 +4299,8 @@ u16 GetEvolutionTargetSpecies(struct Pokemon *mon, u8 mode, u16 evolutionItem, s
case EVO_TRADE_ITEM:
if (evolutions[i].param == heldItem)
{
heldItem = ITEM_NONE;
SetMonData(mon, MON_DATA_HELD_ITEM, &heldItem);
targetSpecies = evolutions[i].targetSpecies;
consumeItem = TRUE;
}
break;
case EVO_TRADE_SPECIFIC_MON:
@ -4150,6 +4389,22 @@ u16 GetEvolutionTargetSpecies(struct Pokemon *mon, u8 mode, u16 evolutionItem, s
break;
}
// Pikachu, Meowth, and Eevee cannot evolve if they have the
// Gigantamax Factor. We assume that is because their evolutions
// do not have a Gigantamax Form.
if (GetMonData(mon, MON_DATA_GIGANTAMAX_FACTOR, NULL)
&& GetGMaxTargetSpecies(species) != SPECIES_NONE
&& GetGMaxTargetSpecies(targetSpecies) == SPECIES_NONE)
{
return SPECIES_NONE;
}
if (consumeItem)
{
heldItem = ITEM_NONE;
SetMonData(mon, MON_DATA_HELD_ITEM, &heldItem);
}
return targetSpecies;
}
@ -5067,20 +5322,17 @@ static void Task_PlayMapChosenOrBattleBGM(u8 taskId)
const u32 *GetMonFrontSpritePal(struct Pokemon *mon)
{
u16 species = GetMonData(mon, MON_DATA_SPECIES_OR_EGG, 0);
u32 otId = GetMonData(mon, MON_DATA_OT_ID, 0);
u32 personality = GetMonData(mon, MON_DATA_PERSONALITY, 0);
return GetMonSpritePalFromSpeciesAndPersonality(species, otId, personality);
u16 species = GetMonData(mon, MON_DATA_SPECIES_OR_EGG, NULL);
bool32 isShiny = GetMonData(mon, MON_DATA_IS_SHINY, NULL);
u32 personality = GetMonData(mon, MON_DATA_PERSONALITY, NULL);
return GetMonSpritePalFromSpeciesAndPersonality(species, isShiny, personality);
}
const u32 *GetMonSpritePalFromSpeciesAndPersonality(u16 species, u32 otId, u32 personality)
const u32 *GetMonSpritePalFromSpeciesAndPersonality(u16 species, bool32 isShiny, u32 personality)
{
u32 shinyValue;
species = SanitizeSpeciesId(species);
shinyValue = GET_SHINY_VALUE(otId, personality);
if (shinyValue < SHINY_ODDS)
if (isShiny)
{
if (gSpeciesInfo[species].shinyPaletteFemale != NULL && IsPersonalityFemale(species, personality))
return gSpeciesInfo[species].shinyPaletteFemale;
@ -5278,18 +5530,7 @@ void SetWildMonHeldItem(void)
bool8 IsMonShiny(struct Pokemon *mon)
{
u32 otId = GetMonData(mon, MON_DATA_OT_ID, 0);
u32 personality = GetMonData(mon, MON_DATA_PERSONALITY, 0);
return IsShinyOtIdPersonality(otId, personality);
}
bool8 IsShinyOtIdPersonality(u32 otId, u32 personality)
{
bool8 retVal = FALSE;
u32 shinyValue = GET_SHINY_VALUE(otId, personality);
if (shinyValue < SHINY_ODDS)
retVal = TRUE;
return retVal;
return GetMonData(mon, MON_DATA_IS_SHINY, NULL);
}
const u8 *GetTrainerPartnerName(void)
@ -6072,6 +6313,10 @@ void UpdateMonPersonality(struct BoxPokemon *boxMon, u32 personality)
struct PokemonSubstruct3 *old3, *new3;
struct BoxPokemon old;
bool32 isShiny = GetBoxMonData(boxMon, MON_DATA_IS_SHINY, NULL);
u32 hiddenNature = GetBoxMonData(boxMon, MON_DATA_HIDDEN_NATURE, NULL);
u32 teraType = GetBoxMonData(boxMon, MON_DATA_TERA_TYPE, NULL);
old = *boxMon;
old0 = &(GetSubstruct(&old, old.personality, 0)->type0);
old1 = &(GetSubstruct(&old, old.personality, 1)->type1);
@ -6091,6 +6336,36 @@ void UpdateMonPersonality(struct BoxPokemon *boxMon, u32 personality)
*new3 = *old3;
boxMon->checksum = CalculateBoxMonChecksum(boxMon);
EncryptBoxMon(boxMon);
SetBoxMonData(boxMon, MON_DATA_IS_SHINY, &isShiny);
SetBoxMonData(boxMon, MON_DATA_HIDDEN_NATURE, &hiddenNature);
SetBoxMonData(boxMon, MON_DATA_TERA_TYPE, &teraType);
}
void HealPokemon(struct Pokemon *mon)
{
u32 data;
data = GetMonData(mon, MON_DATA_MAX_HP);
SetMonData(mon, MON_DATA_HP, &data);
data = STATUS1_NONE;
SetMonData(mon, MON_DATA_STATUS, &data);
MonRestorePP(mon);
}
void HealBoxPokemon(struct BoxPokemon *boxMon)
{
u32 data;
data = 0;
SetBoxMonData(boxMon, MON_DATA_HP_LOST, &data);
data = STATUS1_NONE;
SetBoxMonData(boxMon, MON_DATA_STATUS, &data);
BoxMonRestorePP(boxMon);
}
u16 GetCryIdBySpecies(u16 species)

View File

@ -157,7 +157,8 @@ enum {
struct PokemonJump_MonInfo
{
u16 species;
u16 isShiny:1;
u16 species:15;
u32 otId;
u32 personality;
};
@ -894,6 +895,7 @@ static void InitJumpMonInfo(struct PokemonJump_MonInfo *monInfo, struct Pokemon
{
monInfo->species = GetMonData(mon, MON_DATA_SPECIES);
monInfo->otId = GetMonData(mon, MON_DATA_OT_ID);
monInfo->isShiny = GetMonData(mon, MON_DATA_IS_SHINY);
monInfo->personality = GetMonData(mon, MON_DATA_PERSONALITY);
}
@ -2970,7 +2972,7 @@ static void CreateJumpMonSprite(struct PokemonJumpGfx *jumpGfx, struct PokemonJu
spriteSheet.size = MON_PIC_SIZE;
LoadSpriteSheet(&spriteSheet);
spritePalette.data = GetMonSpritePalFromSpeciesAndPersonality(monInfo->species, monInfo->otId, monInfo->personality);
spritePalette.data = GetMonSpritePalFromSpeciesAndPersonality(monInfo->species, monInfo->isShiny, monInfo->personality);
spritePalette.tag = multiplayerId;
LoadCompressedSpritePalette(&spritePalette);
@ -4161,7 +4163,8 @@ static void Task_UpdateBonus(u8 taskId)
struct MonInfoPacket
{
u8 id;
u16 species;
u16 isShiny:1;
u16 species:15;
u32 personality;
u32 otId;
};
@ -4170,6 +4173,7 @@ static void SendPacket_MonInfo(struct PokemonJump_MonInfo *monInfo)
{
struct MonInfoPacket packet;
packet.id = PACKET_MON_INFO,
packet.isShiny = monInfo->isShiny,
packet.species = monInfo->species,
packet.otId = monInfo->otId,
packet.personality = monInfo->personality,
@ -4187,6 +4191,7 @@ static bool32 RecvPacket_MonInfo(int multiplayerId, struct PokemonJump_MonInfo *
if (packet.id == PACKET_MON_INFO)
{
monInfo->species = packet.species;
monInfo->isShiny = packet.isShiny;
monInfo->otId = packet.otId;
monInfo->personality = packet.personality;
return TRUE;

View File

@ -6414,15 +6414,13 @@ static void SetMovingMonData(u8 boxId, u8 position)
static void SetPlacedMonData(u8 boxId, u8 position)
{
if (OW_PC_HEAL <= GEN_7)
HealPokemon(&sStorage->movingMon);
if (boxId == TOTAL_BOXES_COUNT)
{
gPlayerParty[position] = sStorage->movingMon;
}
else
{
BoxMonRestorePP(&sStorage->movingMon.box);
SetBoxMonAt(boxId, position, &sStorage->movingMon.box);
}
}
static void PurgeMonOrBoxMon(u8 boxId, u8 position)
@ -6964,7 +6962,7 @@ static void SetDisplayMonData(void *pokemon, u8 mode)
sStorage->displayMonSpecies = GetBoxMonData(pokemon, MON_DATA_SPECIES_OR_EGG);
if (sStorage->displayMonSpecies != SPECIES_NONE)
{
u32 otId = GetBoxMonData(boxMon, MON_DATA_OT_ID);
bool8 isShiny = GetBoxMonData(boxMon, MON_DATA_IS_SHINY);
sanityIsBadEgg = GetBoxMonData(boxMon, MON_DATA_SANITY_IS_BAD_EGG);
if (sanityIsBadEgg)
sStorage->displayMonIsEgg = TRUE;
@ -6977,7 +6975,7 @@ static void SetDisplayMonData(void *pokemon, u8 mode)
sStorage->displayMonLevel = GetLevelFromBoxMonExp(boxMon);
sStorage->displayMonMarkings = GetBoxMonData(boxMon, MON_DATA_MARKINGS);
sStorage->displayMonPersonality = GetBoxMonData(boxMon, MON_DATA_PERSONALITY);
sStorage->displayMonPalette = GetMonSpritePalFromSpeciesAndPersonality(sStorage->displayMonSpecies, otId, sStorage->displayMonPersonality);
sStorage->displayMonPalette = GetMonSpritePalFromSpeciesAndPersonality(sStorage->displayMonSpecies, isShiny, sStorage->displayMonPersonality);
gender = GetGenderFromSpeciesAndPersonality(sStorage->displayMonSpecies, sStorage->displayMonPersonality);
sStorage->displayMonItemId = GetBoxMonData(boxMon, MON_DATA_HELD_ITEM);
}
@ -8653,6 +8651,8 @@ static void MultiMove_SetPlacedMonData(void)
u8 boxPosition = (IN_BOX_COLUMNS * i) + sMultiMove->minColumn;
for (j = sMultiMove->minColumn; j < columnCount; j++)
{
if (OW_PC_HEAL <= GEN_7)
HealBoxPokemon(&sMultiMove->boxMons[monArrayId]);
if (GetBoxMonData(&sMultiMove->boxMons[monArrayId], MON_DATA_SANITY_HAS_SPECIES))
SetBoxMonAt(boxId, boxPosition, &sMultiMove->boxMons[monArrayId]);
boxPosition++;
@ -10147,12 +10147,12 @@ static void UnkUtil_DmaRun(struct UnkUtilData *data)
void UpdateSpeciesSpritePSS(struct BoxPokemon *boxMon)
{
u16 species = GetBoxMonData(boxMon, MON_DATA_SPECIES);
u32 otId = GetBoxMonData(boxMon, MON_DATA_OT_ID);
bool8 isShiny = GetBoxMonData(boxMon, MON_DATA_IS_SHINY);
u32 pid = GetBoxMonData(boxMon, MON_DATA_PERSONALITY);
// Update front sprite
sStorage->displayMonSpecies = species;
sStorage->displayMonPalette = GetMonSpritePalFromSpeciesAndPersonality(species, otId, pid);
sStorage->displayMonPalette = GetMonSpritePalFromSpeciesAndPersonality(species, isShiny, pid);
if (!sJustOpenedBag)
{
LoadDisplayMonGfx(species, pid);

View File

@ -141,7 +141,9 @@ static EWRAM_DATA struct PokemonSummaryScreenData
{
u16 species; // 0x0
u16 species2; // 0x2
u8 isEgg; // 0x4
u8 isEgg:1; // 0x4
u8 isShiny:1;
u8 padding:6;
u8 level; // 0x5
u8 ribbonCount; // 0x6
u8 ailment; // 0x7
@ -168,6 +170,7 @@ static EWRAM_DATA struct PokemonSummaryScreenData
u8 sanity; // 0x35
u8 OTName[17]; // 0x36
u32 OTID; // 0x48
u8 teraType;
} summary;
u16 bgTilemapBuffers[PSS_PAGE_COUNT][2][0x400];
u8 mode;
@ -1541,6 +1544,8 @@ static bool8 ExtractMonDataToSummaryStruct(struct Pokemon *mon)
break;
default:
sum->ribbonCount = GetMonData(mon, MON_DATA_RIBBON_COUNT);
sum->teraType = GetMonData(mon, MON_DATA_TERA_TYPE);
sum->isShiny = GetMonData(mon, MON_DATA_IS_SHINY);
return TRUE;
}
sMonSummaryScreen->switchCounter++;
@ -3938,6 +3943,10 @@ static void SetMonTypeIcons(void)
{
SetSpriteInvisibility(SPRITE_ARR_ID_TYPE + 1, TRUE);
}
if (P_SHOW_TERA_TYPE >= GEN_9)
{
SetTypeSpritePosAndPal(summary->teraType, 200, 48, SPRITE_ARR_ID_TYPE + 2);
}
}
}
@ -4042,7 +4051,7 @@ static u8 LoadMonGfxAndSprite(struct Pokemon *mon, s16 *state)
(*state)++;
return 0xFF;
case 1:
LoadCompressedSpritePaletteWithTag(GetMonSpritePalFromSpeciesAndPersonality(summary->species2, summary->OTID, summary->pid), summary->species2);
LoadCompressedSpritePaletteWithTag(GetMonSpritePalFromSpeciesAndPersonality(summary->species2, summary->isShiny, summary->pid), summary->species2);
SetMultiuseSpriteTemplateToPokemon(summary->species2, B_POSITION_OPPONENT_LEFT);
(*state)++;
return 0xFF;

View File

@ -522,7 +522,8 @@ static void GetMonConditionGraphData(s16 listId, u8 loadId)
static void ConditionGraphDrawMonPic(s16 listId, u8 loadId)
{
u16 boxId, monId, species;
u32 personality, tid;
u32 personality;
bool8 isShiny;
struct Pokenav_ConditionMenu *menu = GetSubstructPtr(POKENAV_SUBSTRUCT_CONDITION_GRAPH_MENU);
struct PokenavMonList *monListPtr = GetSubstructPtr(POKENAV_SUBSTRUCT_MON_LIST);
@ -532,10 +533,10 @@ static void ConditionGraphDrawMonPic(s16 listId, u8 loadId)
boxId = monListPtr->monData[listId].boxId;
monId = monListPtr->monData[listId].monId;
species = GetBoxOrPartyMonData(boxId, monId, MON_DATA_SPECIES_OR_EGG, NULL);
tid = GetBoxOrPartyMonData(boxId, monId, MON_DATA_OT_ID, NULL);
isShiny = GetBoxOrPartyMonData(boxId, monId, MON_DATA_IS_SHINY, NULL);
personality = GetBoxOrPartyMonData(boxId, monId, MON_DATA_PERSONALITY, NULL);
LoadSpecialPokePic(menu->monPicGfx[loadId], species, personality, TRUE);
LZ77UnCompWram(GetMonSpritePalFromSpeciesAndPersonality(species, tid, personality), menu->monPal[loadId]);
LZ77UnCompWram(GetMonSpritePalFromSpeciesAndPersonality(species, isShiny, personality), menu->monPal[loadId]);
}
u16 GetMonListCount(void)

View File

@ -401,7 +401,7 @@ static void GetMonNicknameLevelGender(u8 *nick, u8 *level, u8 *gender)
StringGet_Nickname(nick);
}
static void GetMonSpeciesPersonalityOtId(u16 *species, u32 *personality, u32 *otId)
static void GetMonSpeciesPersonalityShiny(u16 *species, u32 *personality, bool8 *isShiny)
{
struct Pokenav_RibbonsSummaryList *list = GetSubstructPtr(POKENAV_SUBSTRUCT_RIBBONS_SUMMARY_LIST);
struct PokenavMonList *mons = list->monList;
@ -413,7 +413,7 @@ static void GetMonSpeciesPersonalityOtId(u16 *species, u32 *personality, u32 *ot
struct Pokemon *mon = &gPlayerParty[monInfo->monId];
*species = GetMonData(mon, MON_DATA_SPECIES);
*personality = GetMonData(mon, MON_DATA_PERSONALITY);
*otId = GetMonData(mon, MON_DATA_OT_ID);
*isShiny = GetMonData(mon, MON_DATA_IS_SHINY);
}
else
{
@ -421,7 +421,7 @@ static void GetMonSpeciesPersonalityOtId(u16 *species, u32 *personality, u32 *ot
struct BoxPokemon *boxMon = GetBoxedMonPtr(monInfo->boxId, monInfo->monId);
*species = GetBoxMonData(boxMon, MON_DATA_SPECIES);
*personality = GetBoxMonData(boxMon, MON_DATA_PERSONALITY);
*otId = GetBoxMonData(boxMon, MON_DATA_OT_ID);
*isShiny = GetBoxMonData(boxMon, MON_DATA_IS_SHINY);
}
}
@ -941,9 +941,10 @@ static void PrintRibbonsMonListIndex(struct Pokenav_RibbonsSummaryMenu *menu)
static void ResetSpritesAndDrawMonFrontPic(struct Pokenav_RibbonsSummaryMenu *menu)
{
u16 species;
u32 personality, otId;
u32 personality;
bool8 isShiny;
GetMonSpeciesPersonalityOtId(&species, &personality, &otId);
GetMonSpeciesPersonalityShiny(&species, &personality, &isShiny);
ResetAllPicSprites();
menu->monSpriteId = DrawRibbonsMonFrontPic(MON_SPRITE_X_ON, MON_SPRITE_Y);
PokenavFillPalette(15, 0);
@ -960,10 +961,11 @@ static void DestroyRibbonsMonFrontPic(struct Pokenav_RibbonsSummaryMenu *menu)
static u16 DrawRibbonsMonFrontPic(s32 x, s32 y)
{
u16 species, spriteId;
u32 personality, otId;
u32 personality;
bool8 isShiny;
GetMonSpeciesPersonalityOtId(&species, &personality, &otId);
spriteId = CreateMonPicSprite(species, otId, personality, TRUE, MON_SPRITE_X_ON, MON_SPRITE_Y, 15, TAG_NONE);
GetMonSpeciesPersonalityShiny(&species, &personality, &isShiny);
spriteId = CreateMonPicSprite(species, isShiny, personality, TRUE, MON_SPRITE_X_ON, MON_SPRITE_Y, 15, TAG_NONE);
gSprites[spriteId].oam.priority = 0;
return spriteId;
}

View File

@ -16,6 +16,7 @@
#include "party_menu.h"
#include "pokedex.h"
#include "pokemon.h"
#include "pokemon_storage_system.h"
#include "random.h"
#include "script.h"
#include "sprite.h"
@ -27,35 +28,30 @@
static void CB2_ReturnFromChooseHalfParty(void);
static void CB2_ReturnFromChooseBattleFrontierParty(void);
static void HealPlayerBoxes(void);
void HealPlayerParty(void)
{
u8 i, j;
u8 ppBonuses;
u8 arg[4];
u32 i;
for (i = 0; i < gPlayerPartyCount; i++)
HealPokemon(&gPlayerParty[i]);
if (OW_PC_HEAL >= GEN_8)
HealPlayerBoxes();
}
// restore HP.
for(i = 0; i < gPlayerPartyCount; i++)
static void HealPlayerBoxes(void)
{
int boxId, boxPosition;
struct BoxPokemon *boxMon;
for (boxId = 0; boxId < TOTAL_BOXES_COUNT; boxId++)
{
u16 maxHP = GetMonData(&gPlayerParty[i], MON_DATA_MAX_HP);
arg[0] = maxHP;
arg[1] = maxHP >> 8;
SetMonData(&gPlayerParty[i], MON_DATA_HP, arg);
ppBonuses = GetMonData(&gPlayerParty[i], MON_DATA_PP_BONUSES);
// restore PP.
for(j = 0; j < MAX_MON_MOVES; j++)
for (boxPosition = 0; boxPosition < IN_BOX_COUNT; boxPosition++)
{
arg[0] = CalculatePPWithBonus(GetMonData(&gPlayerParty[i], MON_DATA_MOVE1 + j), ppBonuses, j);
SetMonData(&gPlayerParty[i], MON_DATA_PP1 + j, arg);
boxMon = &gPokemonStoragePtr->boxes[boxId][boxPosition];
if (GetBoxMonData(boxMon, MON_DATA_SANITY_HAS_SPECIES))
HealBoxPokemon(boxMon);
}
// since status is u32, the four 0 assignments here are probably for safety to prevent undefined data from reaching SetMonData.
arg[0] = 0;
arg[1] = 0;
arg[2] = 0;
arg[3] = 0;
SetMonData(&gPlayerParty[i], MON_DATA_STATUS, arg);
}
}
@ -273,3 +269,72 @@ void ReducePlayerPartyToSelectedMons(void)
CalculatePlayerPartyCount();
}
void CanHyperTrain(struct ScriptContext *ctx)
{
u32 stat = ScriptReadByte(ctx);
u32 partyIndex = VarGet(ScriptReadHalfword(ctx));
if (stat < NUM_STATS
&& partyIndex < PARTY_SIZE
&& !GetMonData(&gPlayerParty[partyIndex], MON_DATA_HYPER_TRAINED_HP + stat)
&& GetMonData(&gPlayerParty[partyIndex], MON_DATA_HP_IV + stat) < MAX_PER_STAT_IVS)
{
gSpecialVar_Result = TRUE;
}
else
{
gSpecialVar_Result = FALSE;
}
}
void HyperTrain(struct ScriptContext *ctx)
{
u32 stat = ScriptReadByte(ctx);
u32 partyIndex = VarGet(ScriptReadHalfword(ctx));
if (stat < NUM_STATS && partyIndex < PARTY_SIZE)
{
bool32 data = TRUE;
SetMonData(&gPlayerParty[partyIndex], MON_DATA_HYPER_TRAINED_HP + stat, &data);
CalculateMonStats(&gPlayerParty[partyIndex]);
}
}
void HasGigantamaxFactor(struct ScriptContext *ctx)
{
u32 partyIndex = VarGet(ScriptReadHalfword(ctx));
if (partyIndex < PARTY_SIZE)
gSpecialVar_Result = GetMonData(&gPlayerParty[partyIndex], MON_DATA_GIGANTAMAX_FACTOR);
else
gSpecialVar_Result = FALSE;
}
static const u16 sGigantaxFactorLockedSpecies[] =
{
SPECIES_MELMETAL,
};
void ToggleGigantamaxFactor(struct ScriptContext *ctx)
{
u32 i;
u32 partyIndex = VarGet(ScriptReadHalfword(ctx));
u32 species;
gSpecialVar_Result = FALSE;
if (partyIndex < PARTY_SIZE)
{
bool32 gigantamaxFactor;
species = GetMonData(&gPlayerParty[partyIndex], MON_DATA_SPECIES);
for (i = 0; i < ARRAY_COUNT(sGigantaxFactorLockedSpecies); i++)
{
if (species == sGigantaxFactorLockedSpecies[i])
return;
}
gigantamaxFactor = GetMonData(&gPlayerParty[partyIndex], MON_DATA_GIGANTAMAX_FACTOR);
gigantamaxFactor = !gigantamaxFactor;
SetMonData(&gPlayerParty[partyIndex], MON_DATA_GIGANTAMAX_FACTOR, &gigantamaxFactor);
gSpecialVar_Result = TRUE;
}
}

View File

@ -630,7 +630,7 @@ static u8 CreatePokemonFrontSprite(u16 species, u8 x, u8 y)
{
u8 spriteId;
spriteId = CreateMonPicSprite_Affine(species, SHINY_ODDS, 0, MON_PIC_AFFINE_FRONT, x, y, 14, TAG_NONE);
spriteId = CreateMonPicSprite_Affine(species, FALSE, 0, MON_PIC_AFFINE_FRONT, x, y, 14, TAG_NONE);
gSprites[spriteId].oam.priority = 0;
return spriteId;
}

View File

@ -4842,7 +4842,7 @@ static void CheckPartnersMonForRibbons(void)
{
u8 i;
u8 numRibbons = 0;
for (i = 0; i < (MON_DATA_UNUSED_RIBBONS - MON_DATA_CHAMPION_RIBBON); i++)
for (i = 0; i < (MON_DATA_WORLD_RIBBON - MON_DATA_CHAMPION_RIBBON + 1); i++)
numRibbons += GetMonData(&gEnemyParty[gSelectedTradeMonPositions[TRADE_PARTNER] % PARTY_SIZE], MON_DATA_CHAMPION_RIBBON + i);
if (numRibbons != 0)

View File

@ -73,19 +73,19 @@ static bool16 DecompressPic(u16 species, u32 personality, bool8 isFrontPic, u8 *
return FALSE;
}
static void LoadPicPaletteByTagOrSlot(u16 species, u32 otId, u32 personality, u8 paletteSlot, u16 paletteTag, bool8 isTrainer)
static void LoadPicPaletteByTagOrSlot(u16 species, bool8 isShiny, u32 personality, u8 paletteSlot, u16 paletteTag, bool8 isTrainer)
{
if (!isTrainer)
{
if (paletteTag == TAG_NONE)
{
sCreatingSpriteTemplate.paletteTag = TAG_NONE;
LoadCompressedPalette(GetMonSpritePalFromSpeciesAndPersonality(species, otId, personality), OBJ_PLTT_ID(paletteSlot), PLTT_SIZE_4BPP);
LoadCompressedPalette(GetMonSpritePalFromSpeciesAndPersonality(species, isShiny, personality), OBJ_PLTT_ID(paletteSlot), PLTT_SIZE_4BPP);
}
else
{
sCreatingSpriteTemplate.paletteTag = paletteTag;
LoadCompressedSpritePaletteWithTag(GetMonSpritePalFromSpeciesAndPersonality(species, otId, personality), species);
LoadCompressedSpritePaletteWithTag(GetMonSpritePalFromSpeciesAndPersonality(species, isShiny, personality), species);
}
}
else
@ -103,10 +103,10 @@ static void LoadPicPaletteByTagOrSlot(u16 species, u32 otId, u32 personality, u8
}
}
static void LoadPicPaletteBySlot(u16 species, u32 otId, u32 personality, u8 paletteSlot, bool8 isTrainer)
static void LoadPicPaletteBySlot(u16 species, bool8 isShiny, u32 personality, u8 paletteSlot, bool8 isTrainer)
{
if (!isTrainer)
LoadCompressedPalette(GetMonSpritePalFromSpeciesAndPersonality(species, otId, personality), PLTT_ID(paletteSlot), PLTT_SIZE_4BPP);
LoadCompressedPalette(GetMonSpritePalFromSpeciesAndPersonality(species, isShiny, personality), PLTT_ID(paletteSlot), PLTT_SIZE_4BPP);
else
LoadCompressedPalette(gTrainerSprites[species].palette.data, PLTT_ID(paletteSlot), PLTT_SIZE_4BPP);
}
@ -119,7 +119,7 @@ static void AssignSpriteAnimsTable(bool8 isTrainer)
sCreatingSpriteTemplate.anims = gTrainerSprites[0].animation;
}
static u16 CreatePicSprite(u16 species, u32 otId, u32 personality, bool8 isFrontPic, s16 x, s16 y, u8 paletteSlot, u16 paletteTag, bool8 isTrainer)
static u16 CreatePicSprite(u16 species, bool8 isShiny, u32 personality, bool8 isFrontPic, s16 x, s16 y, u8 paletteSlot, u16 paletteTag, bool8 isTrainer)
{
u8 i;
u8 *framePics;
@ -161,7 +161,7 @@ static u16 CreatePicSprite(u16 species, u32 otId, u32 personality, bool8 isFront
sCreatingSpriteTemplate.images = images;
sCreatingSpriteTemplate.affineAnims = gDummySpriteAffineAnimTable;
sCreatingSpriteTemplate.callback = DummyPicSpriteCallback;
LoadPicPaletteByTagOrSlot(species, otId, personality, paletteSlot, paletteTag, isTrainer);
LoadPicPaletteByTagOrSlot(species, isShiny, personality, paletteSlot, paletteTag, isTrainer);
spriteId = CreateSprite(&sCreatingSpriteTemplate, x, y, 0);
if (paletteTag == TAG_NONE)
gSprites[spriteId].oam.paletteNum = paletteSlot;
@ -173,7 +173,7 @@ static u16 CreatePicSprite(u16 species, u32 otId, u32 personality, bool8 isFront
return spriteId;
}
u16 CreateMonPicSprite_Affine(u16 species, u32 otId, u32 personality, u8 flags, s16 x, s16 y, u8 paletteSlot, u16 paletteTag)
u16 CreateMonPicSprite_Affine(u16 species, bool8 isShiny, u32 personality, u8 flags, s16 x, s16 y, u8 paletteSlot, u16 paletteTag)
{
u8 *framePics;
struct SpriteFrameImage *images;
@ -239,7 +239,7 @@ u16 CreateMonPicSprite_Affine(u16 species, u32 otId, u32 personality, u8 flags,
sCreatingSpriteTemplate.affineAnims = gDummySpriteAffineAnimTable;
}
sCreatingSpriteTemplate.callback = DummyPicSpriteCallback;
LoadPicPaletteByTagOrSlot(species, otId, personality, paletteSlot, paletteTag, FALSE);
LoadPicPaletteByTagOrSlot(species, isShiny, personality, paletteSlot, paletteTag, FALSE);
spriteId = CreateSprite(&sCreatingSpriteTemplate, x, y, 0);
if (paletteTag == TAG_NONE)
gSprites[spriteId].oam.paletteNum = paletteSlot;
@ -276,16 +276,16 @@ static u16 FreeAndDestroyPicSpriteInternal(u16 spriteId)
return 0;
}
static u16 LoadPicSpriteInWindow(u16 species, u32 otId, u32 personality, bool8 isFrontPic, u8 paletteSlot, u8 windowId, bool8 isTrainer)
static u16 LoadPicSpriteInWindow(u16 species, bool8 isShiny, u32 personality, bool8 isFrontPic, u8 paletteSlot, u8 windowId, bool8 isTrainer)
{
if (DecompressPic(species, personality, isFrontPic, (u8 *)GetWindowAttribute(windowId, WINDOW_TILE_DATA), FALSE))
return 0xFFFF;
LoadPicPaletteBySlot(species, otId, personality, paletteSlot, isTrainer);
LoadPicPaletteBySlot(species, isShiny, personality, paletteSlot, isTrainer);
return 0;
}
static u16 CreateTrainerCardSprite(u16 species, u32 otId, u32 personality, bool8 isFrontPic, u16 destX, u16 destY, u8 paletteSlot, u8 windowId, bool8 isTrainer)
static u16 CreateTrainerCardSprite(u16 species, bool8 isShiny, u32 personality, bool8 isFrontPic, u16 destX, u16 destY, u8 paletteSlot, u8 windowId, bool8 isTrainer)
{
u8 *framePics;
@ -293,16 +293,16 @@ static u16 CreateTrainerCardSprite(u16 species, u32 otId, u32 personality, bool8
if (framePics && !DecompressPic(species, personality, isFrontPic, framePics, isTrainer))
{
BlitBitmapRectToWindow(windowId, framePics, 0, 0, TRAINER_PIC_WIDTH, TRAINER_PIC_HEIGHT, destX, destY, TRAINER_PIC_WIDTH, TRAINER_PIC_HEIGHT);
LoadPicPaletteBySlot(species, otId, personality, paletteSlot, isTrainer);
LoadPicPaletteBySlot(species, isShiny, personality, paletteSlot, isTrainer);
Free(framePics);
return 0;
}
return 0xFFFF;
}
u16 CreateMonPicSprite(u16 species, u32 otId, u32 personality, bool8 isFrontPic, s16 x, s16 y, u8 paletteSlot, u16 paletteTag)
u16 CreateMonPicSprite(u16 species, bool8 isShiny, u32 personality, bool8 isFrontPic, s16 x, s16 y, u8 paletteSlot, u16 paletteTag)
{
return CreatePicSprite(species, otId, personality, isFrontPic, x, y, paletteSlot, paletteTag, FALSE);
return CreatePicSprite(species, isShiny, personality, isFrontPic, x, y, paletteSlot, paletteTag, FALSE);
}
u16 FreeAndDestroyMonPicSprite(u16 spriteId)
@ -310,20 +310,20 @@ u16 FreeAndDestroyMonPicSprite(u16 spriteId)
return FreeAndDestroyPicSpriteInternal(spriteId);
}
static u16 UNUSED LoadMonPicInWindow(u16 species, u32 otId, u32 personality, bool8 isFrontPic, u8 paletteSlot, u8 windowId)
static u16 UNUSED LoadMonPicInWindow(u16 species, bool8 isShiny, u32 personality, bool8 isFrontPic, u8 paletteSlot, u8 windowId)
{
return LoadPicSpriteInWindow(species, otId, personality, isFrontPic, paletteSlot, windowId, FALSE);
return LoadPicSpriteInWindow(species, isShiny, personality, isFrontPic, paletteSlot, windowId, FALSE);
}
// Unused, FRLG only
u16 CreateTrainerCardMonIconSprite(u16 species, u32 otId, u32 personality, bool8 isFrontPic, u16 destX, u16 destY, u8 paletteSlot, u8 windowId)
u16 CreateTrainerCardMonIconSprite(u16 species, bool8 isShiny, u32 personality, bool8 isFrontPic, u16 destX, u16 destY, u8 paletteSlot, u8 windowId)
{
return CreateTrainerCardSprite(species, otId, personality, isFrontPic, destX, destY, paletteSlot, windowId, FALSE);
return CreateTrainerCardSprite(species, isShiny, personality, isFrontPic, destX, destY, paletteSlot, windowId, FALSE);
}
u16 CreateTrainerPicSprite(u16 species, bool8 isFrontPic, s16 x, s16 y, u8 paletteSlot, u16 paletteTag)
{
return CreatePicSprite(species, 0, 0, isFrontPic, x, y, paletteSlot, paletteTag, TRUE);
return CreatePicSprite(species, FALSE, 0, isFrontPic, x, y, paletteSlot, paletteTag, TRUE);
}
u16 FreeAndDestroyTrainerPicSprite(u16 spriteId)
@ -333,12 +333,12 @@ u16 FreeAndDestroyTrainerPicSprite(u16 spriteId)
static u16 UNUSED LoadTrainerPicInWindow(u16 species, bool8 isFrontPic, u8 paletteSlot, u8 windowId)
{
return LoadPicSpriteInWindow(species, 0, 0, isFrontPic, paletteSlot, windowId, TRUE);
return LoadPicSpriteInWindow(species, FALSE, 0, isFrontPic, paletteSlot, windowId, TRUE);
}
u16 CreateTrainerCardTrainerPicSprite(u16 species, bool8 isFrontPic, u16 destX, u16 destY, u8 paletteSlot, u8 windowId)
{
return CreateTrainerCardSprite(species, 0, 0, isFrontPic, destX, destY, paletteSlot, windowId, TRUE);
return CreateTrainerCardSprite(species, FALSE, 0, isFrontPic, destX, destY, paletteSlot, windowId, TRUE);
}
u16 PlayerGenderToFrontTrainerPicId_Debug(u8 gender, bool8 getClass)

View File

@ -27,7 +27,8 @@ static const struct TrainerMon sTestParty1[] =
.lvl = 67,
.moves = {MOVE_AIR_SLASH, MOVE_BARRIER, MOVE_SOLAR_BEAM, MOVE_EXPLOSION},
.nature = TRAINER_PARTY_NATURE(NATURE_HASTY),
.nickname = COMPOUND_STRING("Bubbles")
.nickname = COMPOUND_STRING("Bubbles"),
.dynamaxLevel = 5,
},
{
.species = SPECIES_WOBBUFFET,
@ -110,6 +111,9 @@ TEST("CreateNPCTrainerPartyForTrainer generates customized Pokémon")
EXPECT(GetMonGender(&testParty[0]) == MON_FEMALE);
EXPECT(GetNature(&testParty[0]) == NATURE_HASTY);
EXPECT_EQ(GetMonData(&testParty[0], MON_DATA_DYNAMAX_LEVEL), 5);
EXPECT_EQ(GetMonData(&testParty[1], MON_DATA_DYNAMAX_LEVEL), 0);
Free(testParty);
}

View File

@ -465,16 +465,19 @@ DOUBLE_BATTLE_TEST("(DYNAMAX) Dynamaxed Pokemon are immune to Instruct")
}
}
// TODO: Gigantamax factor
SINGLE_BATTLE_TEST("(DYNAMAX) Pokemon with Gigantamax forms change upon Dynamaxing")
{
u32 species;
bool32 gigantamaxFactor;
PARAMETRIZE { gigantamaxFactor = FALSE; species = SPECIES_VENUSAUR; }
PARAMETRIZE { gigantamaxFactor = TRUE; species = SPECIES_VENUSAUR_GIGANTAMAX; }
GIVEN {
PLAYER(SPECIES_VENUSAUR);
PLAYER(SPECIES_VENUSAUR) { GigantamaxFactor(gigantamaxFactor); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_TACKLE, dynamax: TRUE); }
} THEN {
EXPECT_EQ(player->species, SPECIES_VENUSAUR_GIGANTAMAX);
EXPECT_EQ(player->species, species);
}
}
@ -870,7 +873,7 @@ SINGLE_BATTLE_TEST("(DYNAMAX) G-Max Stonesurge sets up Stealth Rocks")
{
GIVEN {
ASSUME(gBattleMoves[MOVE_G_MAX_STONESURGE].argument == MAX_EFFECT_STEALTH_ROCK);
PLAYER(SPECIES_DREDNAW);
PLAYER(SPECIES_DREDNAW) { GigantamaxFactor(TRUE); }
OPPONENT(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
@ -890,7 +893,7 @@ SINGLE_BATTLE_TEST("(DYNAMAX) G-Max Steelsurge sets up sharp steel")
{
GIVEN {
ASSUME(gBattleMoves[MOVE_G_MAX_STEELSURGE].argument == MAX_EFFECT_STEELSURGE);
PLAYER(SPECIES_COPPERAJAH);
PLAYER(SPECIES_COPPERAJAH) { GigantamaxFactor(TRUE); }
OPPONENT(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_HATTERENE);
} WHEN {
@ -921,7 +924,7 @@ SINGLE_BATTLE_TEST("(DYNAMAX) G-Max Hydrosnipe has fixed power and ignores abili
PARAMETRIZE { move = MOVE_HYDRO_CANNON; }
GIVEN {
ASSUME(gBattleMoves[MOVE_G_MAX_HYDROSNIPE].argument == MAX_EFFECT_FIXED_POWER);
PLAYER(SPECIES_INTELEON);
PLAYER(SPECIES_INTELEON) { GigantamaxFactor(TRUE); }
OPPONENT(SPECIES_ARCTOVISH) { Ability(ABILITY_WATER_ABSORB); }
} WHEN {
TURN { MOVE(player, move, dynamax: TRUE); }
@ -937,7 +940,7 @@ DOUBLE_BATTLE_TEST("(DYNAMAX) G-Max Volt Crash paralyzes both opponents")
{
GIVEN {
ASSUME(gBattleMoves[MOVE_G_MAX_VOLT_CRASH].argument == MAX_EFFECT_PARALYZE_FOES);
PLAYER(SPECIES_PIKACHU);
PLAYER(SPECIES_PIKACHU) { GigantamaxFactor(TRUE); }
PLAYER(SPECIES_PICHU);
OPPONENT(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WYNAUT);
@ -964,7 +967,7 @@ DOUBLE_BATTLE_TEST("(DYNAMAX) G-Max Stun Shock paralyzes or poisons both opponen
PARAMETRIZE { statusAnim = B_ANIM_STATUS_PSN; rng = STATUS1_POISON; }
GIVEN {
ASSUME(gBattleMoves[MOVE_G_MAX_STUN_SHOCK].argument == MAX_EFFECT_POISON_PARALYZE_FOES);
PLAYER(SPECIES_TOXTRICITY);
PLAYER(SPECIES_TOXTRICITY) { GigantamaxFactor(TRUE); }
PLAYER(SPECIES_TOXEL);
OPPONENT(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WYNAUT);
@ -1001,7 +1004,7 @@ DOUBLE_BATTLE_TEST("(DYNAMAX) G-Max Stun Shock chooses statuses before consideri
{
GIVEN {
ASSUME(gBattleMoves[MOVE_G_MAX_STUN_SHOCK].argument == MAX_EFFECT_POISON_PARALYZE_FOES);
PLAYER(SPECIES_TOXTRICITY);
PLAYER(SPECIES_TOXTRICITY) { GigantamaxFactor(TRUE); }
PLAYER(SPECIES_TOXEL);
OPPONENT(SPECIES_GARBODOR);
OPPONENT(SPECIES_TRUBBISH);
@ -1034,7 +1037,7 @@ DOUBLE_BATTLE_TEST("(DYNAMAX) G-Max Befuddle paralyzes, poisons, or sleeps both
PARAMETRIZE { statusAnim = B_ANIM_STATUS_SLP; rng = STATUS1_SLEEP; }
GIVEN {
ASSUME(gBattleMoves[MOVE_G_MAX_BEFUDDLE].argument == MAX_EFFECT_EFFECT_SPORE_FOES);
PLAYER(SPECIES_BUTTERFREE);
PLAYER(SPECIES_BUTTERFREE) { GigantamaxFactor(TRUE); }
PLAYER(SPECIES_CATERPIE);
OPPONENT(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
@ -1078,7 +1081,7 @@ DOUBLE_BATTLE_TEST("(DYNAMAX) G-Max Gold Rush confuses both opponents and genera
{
GIVEN {
ASSUME(gBattleMoves[MOVE_G_MAX_GOLD_RUSH].argument == MAX_EFFECT_CONFUSE_FOES_PAY_DAY);
PLAYER(SPECIES_MEOWTH);
PLAYER(SPECIES_MEOWTH) { GigantamaxFactor(TRUE); }
PLAYER(SPECIES_PERSIAN);
OPPONENT(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
@ -1098,7 +1101,7 @@ DOUBLE_BATTLE_TEST("(DYNAMAX) G-Max Smite confuses both opponents")
{
GIVEN {
ASSUME(gBattleMoves[MOVE_G_MAX_SMITE].argument == MAX_EFFECT_CONFUSE_FOES);
PLAYER(SPECIES_HATTERENE);
PLAYER(SPECIES_HATTERENE) { GigantamaxFactor(TRUE); }
PLAYER(SPECIES_HATENNA);
OPPONENT(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
@ -1117,7 +1120,7 @@ DOUBLE_BATTLE_TEST("(DYNAMAX) G-Max Cuddle infatuates both opponents, if possibl
{
GIVEN {
ASSUME(gBattleMoves[MOVE_G_MAX_CUDDLE].argument == MAX_EFFECT_INFATUATE_FOES);
PLAYER(SPECIES_EEVEE) { Gender(MON_MALE); }
PLAYER(SPECIES_EEVEE) { Gender(MON_MALE); GigantamaxFactor(TRUE); }
PLAYER(SPECIES_EEVEE);
OPPONENT(SPECIES_WOBBUFFET) { Gender(MON_FEMALE); }
OPPONENT(SPECIES_WOBBUFFET) { Gender(MON_MALE); }
@ -1138,7 +1141,7 @@ DOUBLE_BATTLE_TEST("(DYNAMAX) G-Max Terror traps both opponents")
{
GIVEN {
ASSUME(gBattleMoves[MOVE_G_MAX_TERROR].argument == MAX_EFFECT_MEAN_LOOK);
PLAYER(SPECIES_GENGAR);
PLAYER(SPECIES_GENGAR) { GigantamaxFactor(TRUE); }
PLAYER(SPECIES_GASTLY);
OPPONENT(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
@ -1157,7 +1160,7 @@ DOUBLE_BATTLE_TEST("(DYNAMAX) G-Max Meltdown torments both opponents for 3 turns
{
GIVEN {
ASSUME(gBattleMoves[MOVE_G_MAX_MELTDOWN].argument == MAX_EFFECT_TORMENT_FOES);
PLAYER(SPECIES_MELMETAL);
PLAYER(SPECIES_MELMETAL) { GigantamaxFactor(TRUE); }
PLAYER(SPECIES_MELTAN);
OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_SPLASH, MOVE_CELEBRATE); }
OPPONENT(SPECIES_WYNAUT) { Moves(MOVE_SPLASH, MOVE_CELEBRATE); }
@ -1194,7 +1197,7 @@ DOUBLE_BATTLE_TEST("(DYNAMAX) G-Max Wildfire sets a field effect that damages no
s16 damage;
GIVEN {
ASSUME(gBattleMoves[MOVE_G_MAX_WILDFIRE].argument == MAX_EFFECT_WILDFIRE);
PLAYER(SPECIES_CHARIZARD);
PLAYER(SPECIES_CHARIZARD) { GigantamaxFactor(TRUE); }
PLAYER(SPECIES_CHARMANDER);
OPPONENT(SPECIES_WOBBUFFET) { HP(600); MaxHP(600); }
OPPONENT(SPECIES_WYNAUT);
@ -1240,7 +1243,7 @@ DOUBLE_BATTLE_TEST("(DYNAMAX) G-Max Replenish recycles allies' berries 50\% of t
PASSES_RANDOMLY(1, 2, RNG_G_MAX_REPLENISH);
GIVEN {
ASSUME(gBattleMoves[MOVE_G_MAX_REPLENISH].argument == MAX_EFFECT_RECYCLE_BERRIES);
PLAYER(SPECIES_SNORLAX) { Item(ITEM_APICOT_BERRY); }
PLAYER(SPECIES_SNORLAX) { Item(ITEM_APICOT_BERRY); GigantamaxFactor(TRUE); }
PLAYER(SPECIES_MUNCHLAX) { Item(ITEM_APICOT_BERRY); }
OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_APICOT_BERRY); }
OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_APICOT_BERRY); }
@ -1268,7 +1271,7 @@ DOUBLE_BATTLE_TEST("(DYNAMAX) G-Max Snooze makes only the target drowsy")
PASSES_RANDOMLY(1, 2, RNG_G_MAX_SNOOZE);
GIVEN {
ASSUME(gBattleMoves[MOVE_G_MAX_SNOOZE].argument == MAX_EFFECT_YAWN_FOE);
PLAYER(SPECIES_GRIMMSNARL);
PLAYER(SPECIES_GRIMMSNARL) { GigantamaxFactor(TRUE); }
PLAYER(SPECIES_IMPIDIMP);
OPPONENT(SPECIES_BLISSEY);
OPPONENT(SPECIES_CHANSEY);
@ -1291,7 +1294,7 @@ DOUBLE_BATTLE_TEST("(DYNAMAX) G-Max Finale heals allies by 1/6 of their health")
s16 damage1, damage2;
GIVEN {
ASSUME(gBattleMoves[MOVE_G_MAX_FINALE].argument == MAX_EFFECT_HEAL_TEAM);
PLAYER(SPECIES_ALCREMIE) { HP(1); }
PLAYER(SPECIES_ALCREMIE) { HP(1); GigantamaxFactor(TRUE); }
PLAYER(SPECIES_MILCERY) { HP(1); }
OPPONENT(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
@ -1311,7 +1314,7 @@ DOUBLE_BATTLE_TEST("(DYNAMAX) G-Max Sweetness cures allies' status conditions")
{
GIVEN {
ASSUME(gBattleMoves[MOVE_G_MAX_SWEETNESS].argument == MAX_EFFECT_AROMATHERAPY);
PLAYER(SPECIES_APPLETUN) { Status1(STATUS1_POISON); }
PLAYER(SPECIES_APPLETUN) { Status1(STATUS1_POISON); GigantamaxFactor(TRUE); }
PLAYER(SPECIES_APPLIN) { Status1(STATUS1_POISON); }
OPPONENT(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
@ -1331,7 +1334,7 @@ DOUBLE_BATTLE_TEST("(DYNAMAX) G-Max Centiferno traps both opponents in Fire Spin
{
GIVEN {
ASSUME(gBattleMoves[MOVE_G_MAX_CENTIFERNO].argument == MAX_EFFECT_FIRE_SPIN_FOES);
PLAYER(SPECIES_CENTISKORCH);
PLAYER(SPECIES_CENTISKORCH) { GigantamaxFactor(TRUE); }
PLAYER(SPECIES_SIZZLIPEDE);
PLAYER(SPECIES_SIZZLIPEDE);
OPPONENT(SPECIES_WOBBUFFET);
@ -1360,7 +1363,7 @@ DOUBLE_BATTLE_TEST("(DYNAMAX) G-Max Chi Strike boosts allies' crit chance")
GIVEN {
ASSUME(B_CRIT_CHANCE >= GEN_6);
ASSUME(gBattleMoves[MOVE_G_MAX_CHI_STRIKE].argument == MAX_EFFECT_CRIT_PLUS);
PLAYER(SPECIES_MACHAMP);
PLAYER(SPECIES_MACHAMP) { GigantamaxFactor(TRUE); }
PLAYER(SPECIES_MACHOP);
OPPONENT(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
@ -1389,7 +1392,7 @@ DOUBLE_BATTLE_TEST("(DYNAMAX) G-Max Depletion takes away 2 PP from the target's
{
GIVEN {
ASSUME(gBattleMoves[MOVE_G_MAX_DEPLETION].argument == MAX_EFFECT_SPITE);
PLAYER(SPECIES_DURALUDON);
PLAYER(SPECIES_DURALUDON) { GigantamaxFactor(TRUE); }
PLAYER(SPECIES_WYNAUT);
// Dynamax behaves weird with test turn order because stats are recalculated.
OPPONENT(SPECIES_SABLEYE) { Ability(ABILITY_PRANKSTER); }
@ -1411,7 +1414,7 @@ DOUBLE_BATTLE_TEST("(DYNAMAX) G-Max One Blow bypasses Max Guard for full damage"
PARAMETRIZE { protect = FALSE; }
GIVEN {
ASSUME(gBattleMoves[MOVE_G_MAX_ONE_BLOW].argument == MAX_EFFECT_BYPASS_PROTECT);
PLAYER(SPECIES_URSHIFU);
PLAYER(SPECIES_URSHIFU) { GigantamaxFactor(TRUE); }
PLAYER(SPECIES_KUBFU);
OPPONENT(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WYNAUT);

182
test/pokemon.c Normal file
View File

@ -0,0 +1,182 @@
#include "global.h"
#include "battle.h"
#include "event_data.h"
#include "pokemon.h"
#include "test/overworld_script.h"
#include "test/test.h"
TEST("Nature independent from Hidden Nature")
{
u32 i, j, nature = 0, hiddenNature = 0;
struct Pokemon mon;
for (i = 0; i < NUM_NATURES; i++)
{
for (j = 0; j < NUM_NATURES; j++)
{
PARAMETRIZE { nature = i; hiddenNature = j; }
}
}
CreateMonWithNature(&mon, SPECIES_WOBBUFFET, 100, 0, nature);
SetMonData(&mon, MON_DATA_HIDDEN_NATURE, &hiddenNature);
EXPECT_EQ(GetNature(&mon), nature);
EXPECT_EQ(GetMonData(&mon, MON_DATA_HIDDEN_NATURE), hiddenNature);
}
TEST("Terastallization type defaults to primary or secondary type")
{
u32 i, teraType;
struct Pokemon mon;
for (i = 0; i < 128; i++) PARAMETRIZE {}
CreateMon(&mon, SPECIES_PIDGEY, 100, 0, FALSE, 0, OT_ID_PRESET, 0);
teraType = GetMonData(&mon, MON_DATA_TERA_TYPE);
EXPECT(teraType == gSpeciesInfo[SPECIES_PIDGEY].types[0]
|| teraType == gSpeciesInfo[SPECIES_PIDGEY].types[1]);
}
TEST("Terastallization type can be set to any type")
{
u32 i, teraType;
struct Pokemon mon;
for (i = 0; i < NUMBER_OF_MON_TYPES; i++)
{
PARAMETRIZE { teraType = i; }
}
CreateMon(&mon, SPECIES_WOBBUFFET, 100, 0, FALSE, 0, OT_ID_PRESET, 0);
SetMonData(&mon, MON_DATA_TERA_TYPE, &teraType);
EXPECT_EQ(teraType, GetMonData(&mon, MON_DATA_TERA_TYPE));
}
TEST("Shininess independent from PID and OTID")
{
u32 pid, otId, data;
bool32 isShiny;
struct Pokemon mon;
PARAMETRIZE { pid = 0; otId = 0; }
CreateMon(&mon, SPECIES_WOBBUFFET, 100, 0, TRUE, pid, OT_ID_PRESET, otId);
isShiny = IsMonShiny(&mon);
data = !isShiny;
SetMonData(&mon, MON_DATA_IS_SHINY, &data);
EXPECT_EQ(pid, GetMonData(&mon, MON_DATA_PERSONALITY));
EXPECT_EQ(otId, GetMonData(&mon, MON_DATA_OT_ID));
EXPECT_EQ(!isShiny, GetMonData(&mon, MON_DATA_IS_SHINY));
}
TEST("Hyper Training increases stats without affecting IVs")
{
u32 data, hp, atk, def, speed, spatk, spdef;
struct Pokemon mon;
CreateMon(&mon, SPECIES_WOBBUFFET, 100, 3, TRUE, 0, OT_ID_PRESET, 0);
hp = GetMonData(&mon, MON_DATA_HP);
atk = GetMonData(&mon, MON_DATA_ATK);
def = GetMonData(&mon, MON_DATA_DEF);
speed = GetMonData(&mon, MON_DATA_SPEED);
spatk = GetMonData(&mon, MON_DATA_SPATK);
spdef = GetMonData(&mon, MON_DATA_SPDEF);
data = TRUE;
SetMonData(&mon, MON_DATA_HYPER_TRAINED_HP, &data);
SetMonData(&mon, MON_DATA_HYPER_TRAINED_ATK, &data);
SetMonData(&mon, MON_DATA_HYPER_TRAINED_DEF, &data);
SetMonData(&mon, MON_DATA_HYPER_TRAINED_SPEED, &data);
SetMonData(&mon, MON_DATA_HYPER_TRAINED_SPATK, &data);
SetMonData(&mon, MON_DATA_HYPER_TRAINED_SPDEF, &data);
CalculateMonStats(&mon);
EXPECT_EQ(GetMonData(&mon, MON_DATA_HP_IV), 3);
EXPECT_EQ(GetMonData(&mon, MON_DATA_ATK_IV), 3);
EXPECT_EQ(GetMonData(&mon, MON_DATA_DEF_IV), 3);
EXPECT_EQ(GetMonData(&mon, MON_DATA_SPEED_IV), 3);
EXPECT_EQ(GetMonData(&mon, MON_DATA_SPATK_IV), 3);
EXPECT_EQ(GetMonData(&mon, MON_DATA_SPDEF_IV), 3);
EXPECT_EQ(GetMonData(&mon, MON_DATA_SPEED_IV), 3);
EXPECT_EQ(hp - 3 + MAX_PER_STAT_IVS, GetMonData(&mon, MON_DATA_HP));
EXPECT_EQ(atk - 3 + MAX_PER_STAT_IVS, GetMonData(&mon, MON_DATA_ATK));
EXPECT_EQ(def - 3 + MAX_PER_STAT_IVS, GetMonData(&mon, MON_DATA_DEF));
EXPECT_EQ(speed - 3 + MAX_PER_STAT_IVS, GetMonData(&mon, MON_DATA_SPEED));
EXPECT_EQ(spatk - 3 + MAX_PER_STAT_IVS, GetMonData(&mon, MON_DATA_SPATK));
EXPECT_EQ(spdef - 3 + MAX_PER_STAT_IVS, GetMonData(&mon, MON_DATA_SPDEF));
}
TEST("Status1 round-trips through BoxPokemon")
{
u32 status1;
struct Pokemon mon1, mon2;
PARAMETRIZE { status1 = STATUS1_NONE; }
PARAMETRIZE { status1 = STATUS1_SLEEP_TURN(1); }
PARAMETRIZE { status1 = STATUS1_SLEEP_TURN(2); }
PARAMETRIZE { status1 = STATUS1_SLEEP_TURN(3); }
PARAMETRIZE { status1 = STATUS1_SLEEP_TURN(4); }
PARAMETRIZE { status1 = STATUS1_SLEEP_TURN(5); }
PARAMETRIZE { status1 = STATUS1_POISON; }
PARAMETRIZE { status1 = STATUS1_BURN; }
PARAMETRIZE { status1 = STATUS1_FREEZE; }
PARAMETRIZE { status1 = STATUS1_PARALYSIS; }
PARAMETRIZE { status1 = STATUS1_TOXIC_POISON; }
PARAMETRIZE { status1 = STATUS1_FROSTBITE; }
CreateMon(&mon1, SPECIES_WOBBUFFET, 100, 0, FALSE, 0, OT_ID_PRESET, 0);
SetMonData(&mon1, MON_DATA_STATUS, &status1);
BoxMonToMon(&mon1.box, &mon2);
EXPECT_EQ(GetMonData(&mon2, MON_DATA_STATUS), status1);
}
TEST("canhypertrain/hypertrain affect MON_DATA_HYPER_TRAINED_* and recalculate stats")
{
u32 atk;
CreateMon(&gPlayerParty[0], SPECIES_WOBBUFFET, 100, 0, FALSE, 0, OT_ID_PRESET, 0);
atk = GetMonData(&gPlayerParty[0], MON_DATA_ATK);
RUN_OVERWORLD_SCRIPT(
canhypertrain STAT_ATK, 0;
);
EXPECT(VarGet(VAR_RESULT));
RUN_OVERWORLD_SCRIPT(
hypertrain STAT_ATK, 0;
canhypertrain STAT_ATK, 0;
);
EXPECT(GetMonData(&gPlayerParty[0], MON_DATA_HYPER_TRAINED_ATK));
EXPECT_EQ(atk + 31, GetMonData(&gPlayerParty[0], MON_DATA_ATK));
EXPECT(!VarGet(VAR_RESULT));
}
TEST("hasgigantamaxfactor/togglegigantamaxfactor affect MON_DATA_GIGANTAMAX_FACTOR")
{
CreateMon(&gPlayerParty[0], SPECIES_WOBBUFFET, 100, 0, FALSE, 0, OT_ID_PRESET, 0);
RUN_OVERWORLD_SCRIPT(
hasgigantamaxfactor 0;
);
EXPECT(!VarGet(VAR_RESULT));
RUN_OVERWORLD_SCRIPT(
togglegigantamaxfactor 0;
hasgigantamaxfactor 0;
);
EXPECT(VarGet(VAR_RESULT));
EXPECT(GetMonData(&gPlayerParty[0], MON_DATA_GIGANTAMAX_FACTOR));
RUN_OVERWORLD_SCRIPT(
togglegigantamaxfactor 0;
hasgigantamaxfactor 0;
);
EXPECT(!VarGet(VAR_RESULT));
EXPECT(!GetMonData(&gPlayerParty[0], MON_DATA_GIGANTAMAX_FACTOR));
}
TEST("togglegigantamaxfactor fails for Melmetal")
{
CreateMon(&gPlayerParty[0], SPECIES_MELMETAL, 100, 0, FALSE, 0, OT_ID_PRESET, 0);
RUN_OVERWORLD_SCRIPT(
hasgigantamaxfactor 0;
);
EXPECT(!VarGet(VAR_RESULT));
RUN_OVERWORLD_SCRIPT(
togglegigantamaxfactor 0;
);
EXPECT(!VarGet(VAR_RESULT));
EXPECT(!GetMonData(&gPlayerParty[0], MON_DATA_GIGANTAMAX_FACTOR));
}

View File

@ -34,6 +34,8 @@ TEST("Form change tables contain only forms in the form species ID table")
for (i = 0; formChangeTable[i].method != FORM_CHANGE_TERMINATOR; i++)
{
if (formChangeTable[i].targetSpecies == SPECIES_NONE)
continue;
for (j = 0; formSpeciesIdTable[j] != FORM_SPECIES_END; j++)
{
if (formChangeTable[i].targetSpecies == formSpeciesIdTable[j])

View File

@ -398,11 +398,21 @@ static void FunctionTest_TearDown(void *data)
FREE_AND_SET_NULL(gFunctionTestRunnerState);
}
static bool32 FunctionTest_CheckProgress(void *data)
{
bool32 madeProgress;
(void)data;
madeProgress = gFunctionTestRunnerState->checkProgressParameter < gFunctionTestRunnerState->runParameter;
gFunctionTestRunnerState->checkProgressParameter = gFunctionTestRunnerState->runParameter;
return madeProgress;
}
const struct TestRunner gFunctionTestRunner =
{
.setUp = FunctionTest_SetUp,
.run = FunctionTest_Run,
.tearDown = FunctionTest_TearDown,
.checkProgress = FunctionTest_CheckProgress,
};
static void Assumptions_Run(void *data)

View File

@ -1587,6 +1587,7 @@ static u32 GenerateNature(u32 nature, u32 offset)
void ClosePokemon(u32 sourceLine)
{
s32 i;
u32 data;
INVALID_IF(DATA.hasExplicitSpeeds && !(DATA.explicitSpeeds[DATA.currentSide] & (1 << DATA.currentPartyIndex)), "Speed required");
for (i = 0; i < STATE->battlersCount; i++)
{
@ -1596,6 +1597,8 @@ void ClosePokemon(u32 sourceLine)
INVALID_IF(GetMonData(DATA.currentMon, MON_DATA_HP) == 0, "Battlers cannot be fainted");
}
}
data = FALSE;
SetMonData(DATA.currentMon, MON_DATA_IS_SHINY, &data);
UpdateMonPersonality(&DATA.currentMon->box, GenerateNature(DATA.nature, DATA.gender % NUM_NATURES) | DATA.gender);
DATA.currentMon = NULL;
}
@ -1766,10 +1769,34 @@ void Status1_(u32 sourceLine, u32 status1)
void OTName_(u32 sourceLine, const u8 *otName)
{
INVALID_IF(!DATA.currentMon, "Traded outside of PLAYER/OPPONENT");
INVALID_IF(!DATA.currentMon, "OTName outside of PLAYER/OPPONENT");
SetMonData(DATA.currentMon, MON_DATA_OT_NAME, &otName);
}
void DynamaxLevel_(u32 sourceLine, u32 dynamaxLevel)
{
INVALID_IF(!DATA.currentMon, "DynamaxLevel outside of PLAYER/OPPONENT");
SetMonData(DATA.currentMon, MON_DATA_DYNAMAX_LEVEL, &dynamaxLevel);
}
void GigantamaxFactor_(u32 sourceLine, bool32 gigantamaxFactor)
{
INVALID_IF(!DATA.currentMon, "GigantamaxFactor outside of PLAYER/OPPONENT");
SetMonData(DATA.currentMon, MON_DATA_GIGANTAMAX_FACTOR, &gigantamaxFactor);
}
void TeraType_(u32 sourceLine, u32 teraType)
{
INVALID_IF(!DATA.currentMon, "TeraType outside of PLAYER/OPPONENT");
SetMonData(DATA.currentMon, MON_DATA_TERA_TYPE, &teraType);
}
void Shadow_(u32 sourceLine, bool32 isShadow)
{
INVALID_IF(!DATA.currentMon, "Shadow outside of PLAYER/OPPONENT");
SetMonData(DATA.currentMon, MON_DATA_IS_SHADOW, &isShadow);
}
static const char *const sBattlerIdentifiersSingles[] =
{
"player",