From 91c7bd9e53464ee78f9bf26758de93607ce5bba5 Mon Sep 17 00:00:00 2001 From: Eduardo Quezada Date: Thu, 26 Dec 2024 17:22:45 -0300 Subject: [PATCH] Fixed givemon not respecting perfect IVs for species (#5873) --- include/pokemon.h | 1 + src/daycare.c | 21 ----------------- src/pokemon.c | 5 ++-- src/script_pokemon_util.c | 49 ++++++++++++++++++++++++++++++++++----- test/pokemon.c | 44 +++++++++++++++++++++++++++++++++++ 5 files changed, 91 insertions(+), 29 deletions(-) diff --git a/include/pokemon.h b/include/pokemon.h index 069290b363b3..8aca6c58d589 100644 --- a/include/pokemon.h +++ b/include/pokemon.h @@ -891,6 +891,7 @@ u16 GetFormChangeTargetSpecies(struct Pokemon *mon, u16 method, u32 arg); u16 GetFormChangeTargetSpeciesBoxMon(struct BoxPokemon *boxMon, u16 method, u32 arg); bool32 DoesSpeciesHaveFormChangeMethod(u16 species, u16 method); u16 MonTryLearningNewMoveEvolution(struct Pokemon *mon, bool8 firstMove); +void RemoveIVIndexFromList(u8 *ivs, u8 selectedIv); bool32 SpeciesHasGenderDifferences(u16 species); bool32 TryFormChange(u32 monId, u32 side, u16 method); void TryToSetBattleFormChangeMoves(struct Pokemon *mon, u16 method); diff --git a/src/daycare.c b/src/daycare.c index 912537af567a..4997f4efe913 100644 --- a/src/daycare.c +++ b/src/daycare.c @@ -590,27 +590,6 @@ static void UNUSED TriggerPendingDaycareMaleEgg(void) _TriggerPendingDaycareMaleEgg(&gSaveBlock1Ptr->daycare); } -// Removes the selected index from the given IV list and shifts the remaining -// elements to the left. -static void RemoveIVIndexFromList(u8 *ivs, u8 selectedIv) -{ - s32 i, j; - u8 temp[NUM_STATS]; - - ivs[selectedIv] = 0xFF; - for (i = 0; i < NUM_STATS; i++) - { - temp[i] = ivs[i]; - } - - j = 0; - for (i = 0; i < NUM_STATS; i++) - { - if (temp[i] != 0xFF) - ivs[j++] = temp[i]; - } -} - static void InheritIVs(struct Pokemon *egg, struct DayCare *daycare) { u16 motherItem = GetBoxMonData(&daycare->mons[0].mon, MON_DATA_HELD_ITEM); diff --git a/src/pokemon.c b/src/pokemon.c index 72aa2c7c627d..c60e95cc6af4 100644 --- a/src/pokemon.c +++ b/src/pokemon.c @@ -75,7 +75,6 @@ static void EncryptBoxMon(struct BoxPokemon *boxMon); static void DecryptBoxMon(struct BoxPokemon *boxMon); static void Task_PlayMapChosenOrBattleBGM(u8 taskId); static bool8 ShouldSkipFriendshipChange(void); -static void RemoveIVIndexFromList(u8 *ivs, u8 selectedIv); void TrySpecialOverworldEvo(); EWRAM_DATA static u8 sLearningMoveTableID = 0; @@ -6659,7 +6658,9 @@ u16 MonTryLearningNewMoveEvolution(struct Pokemon *mon, bool8 firstMove) return 0; } -static void RemoveIVIndexFromList(u8 *ivs, u8 selectedIv) +// Removes the selected index from the given IV list and shifts the remaining +// elements to the left. +void RemoveIVIndexFromList(u8 *ivs, u8 selectedIv) { s32 i, j; u8 temp[NUM_STATS]; diff --git a/src/script_pokemon_util.c b/src/script_pokemon_util.c index 020094389a70..fc248435a90d 100644 --- a/src/script_pokemon_util.c +++ b/src/script_pokemon_util.c @@ -487,12 +487,49 @@ void ScrCmd_createmon(struct ScriptContext *ctx) u8 speedEv = PARSE_FLAG(8, 0); u8 spAtkEv = PARSE_FLAG(9, 0); u8 spDefEv = PARSE_FLAG(10, 0); - u8 hpIv = PARSE_FLAG(11, Random() % (MAX_PER_STAT_IVS + 1)); - u8 atkIv = PARSE_FLAG(12, Random() % (MAX_PER_STAT_IVS + 1)); - u8 defIv = PARSE_FLAG(13, Random() % (MAX_PER_STAT_IVS + 1)); - u8 speedIv = PARSE_FLAG(14, Random() % (MAX_PER_STAT_IVS + 1)); - u8 spAtkIv = PARSE_FLAG(15, Random() % (MAX_PER_STAT_IVS + 1)); - u8 spDefIv = PARSE_FLAG(16, Random() % (MAX_PER_STAT_IVS + 1)); + u8 hpIv = Random() % (MAX_PER_STAT_IVS + 1); + u8 atkIv = Random() % (MAX_PER_STAT_IVS + 1); + u8 defIv = Random() % (MAX_PER_STAT_IVS + 1); + u8 speedIv = Random() % (MAX_PER_STAT_IVS + 1); + u8 spAtkIv = Random() % (MAX_PER_STAT_IVS + 1); + u8 spDefIv = Random() % (MAX_PER_STAT_IVS + 1); + + // Perfect IV calculation + u32 i; + u8 availableIVs[NUM_STATS]; + u8 selectedIvs[NUM_STATS]; + if (gSpeciesInfo[species].perfectIVCount != 0) + { + // Initialize a list of IV indices. + for (i = 0; i < NUM_STATS; i++) + availableIVs[i] = i; + + // Select the IVs that will be perfected. + for (i = 0; i < NUM_STATS && i < gSpeciesInfo[species].perfectIVCount; i++) + { + u8 index = Random() % (NUM_STATS - i); + selectedIvs[i] = availableIVs[index]; + RemoveIVIndexFromList(availableIVs, index); + } + for (i = 0; i < NUM_STATS && i < gSpeciesInfo[species].perfectIVCount; i++) + { + switch (selectedIvs[i]) + { + case STAT_HP: hpIv = MAX_PER_STAT_IVS; break; + case STAT_ATK: atkIv = MAX_PER_STAT_IVS; break; + case STAT_DEF: defIv = MAX_PER_STAT_IVS; break; + case STAT_SPEED: speedIv = MAX_PER_STAT_IVS; break; + case STAT_SPATK: spAtkIv = MAX_PER_STAT_IVS; break; + case STAT_SPDEF: spDefIv = MAX_PER_STAT_IVS; break; + } + } + } + hpIv = PARSE_FLAG(11, hpIv); + atkIv = PARSE_FLAG(12, atkIv); + defIv = PARSE_FLAG(13, defIv); + speedIv = PARSE_FLAG(14, speedIv); + spAtkIv = PARSE_FLAG(15, spAtkIv); + spDefIv = PARSE_FLAG(16, spDefIv); u16 move1 = PARSE_FLAG(17, MOVE_NONE); u16 move2 = PARSE_FLAG(18, MOVE_NONE); u16 move3 = PARSE_FLAG(19, MOVE_NONE); diff --git a/test/pokemon.c b/test/pokemon.c index f5431559ee55..00b08ebb79c7 100644 --- a/test/pokemon.c +++ b/test/pokemon.c @@ -210,6 +210,50 @@ TEST("givemon [simple]") EXPECT_EQ(GetMonData(&gPlayerParty[0], MON_DATA_LEVEL), 100); } +TEST("givemon respects perfectIVCount") +{ + ZeroPlayerPartyMons(); + u32 perfectIVs[6] = {0}; + + ASSUME(gSpeciesInfo[SPECIES_MEW].perfectIVCount == 3); + ASSUME(gSpeciesInfo[SPECIES_CELEBI].perfectIVCount == 3); + ASSUME(gSpeciesInfo[SPECIES_JIRACHI].perfectIVCount == 3); + ASSUME(gSpeciesInfo[SPECIES_MANAPHY].perfectIVCount == 3); + ASSUME(gSpeciesInfo[SPECIES_VICTINI].perfectIVCount == 3); + ASSUME(gSpeciesInfo[SPECIES_DIANCIE].perfectIVCount == 3); + + RUN_OVERWORLD_SCRIPT( + givemon SPECIES_MEW, 100; + givemon SPECIES_CELEBI, 100; + givemon SPECIES_JIRACHI, 100; + givemon SPECIES_MANAPHY, 100; + givemon SPECIES_VICTINI, 100; + givemon SPECIES_DIANCIE, 100; + ); + + EXPECT_EQ(GetMonData(&gPlayerParty[0], MON_DATA_SPECIES), SPECIES_MEW); + EXPECT_EQ(GetMonData(&gPlayerParty[1], MON_DATA_SPECIES), SPECIES_CELEBI); + EXPECT_EQ(GetMonData(&gPlayerParty[2], MON_DATA_SPECIES), SPECIES_JIRACHI); + EXPECT_EQ(GetMonData(&gPlayerParty[3], MON_DATA_SPECIES), SPECIES_MANAPHY); + EXPECT_EQ(GetMonData(&gPlayerParty[4], MON_DATA_SPECIES), SPECIES_VICTINI); + EXPECT_EQ(GetMonData(&gPlayerParty[5], MON_DATA_SPECIES), SPECIES_DIANCIE); + EXPECT_EQ(GetMonData(&gPlayerParty[0], MON_DATA_LEVEL), 100); + EXPECT_EQ(GetMonData(&gPlayerParty[1], MON_DATA_LEVEL), 100); + EXPECT_EQ(GetMonData(&gPlayerParty[2], MON_DATA_LEVEL), 100); + EXPECT_EQ(GetMonData(&gPlayerParty[3], MON_DATA_LEVEL), 100); + EXPECT_EQ(GetMonData(&gPlayerParty[4], MON_DATA_LEVEL), 100); + EXPECT_EQ(GetMonData(&gPlayerParty[5], MON_DATA_LEVEL), 100); + for (u32 j = 0; j < 6; j++) + { + for (u32 k = 0; k < NUM_STATS; k++) + { + if (GetMonData(&gPlayerParty[j], MON_DATA_HP_IV + k) == MAX_PER_STAT_IVS) + perfectIVs[j]++; + } + EXPECT_GE(perfectIVs[j], 3); + } +} + TEST("givemon [moves]") { ZeroPlayerPartyMons();