diff --git a/include/constants/pokemon.h b/include/constants/pokemon.h index 51ef0c015b..a6b150e9e0 100644 --- a/include/constants/pokemon.h +++ b/include/constants/pokemon.h @@ -181,6 +181,7 @@ #define MON_DATA_SPEED2 86 #define MON_DATA_SPATK2 87 #define MON_DATA_SPDEF2 88 +#define MON_DATA_NATURE 89 // Ribbon IDs used by TV and Pokénav #define CHAMPION_RIBBON 0 diff --git a/src/pokemon.c b/src/pokemon.c index b4eb6f01af..da3b80baf0 100644 --- a/src/pokemon.c +++ b/src/pokemon.c @@ -3980,6 +3980,9 @@ u32 GetBoxMonData(struct BoxPokemon *boxMon, s32 field, u8 *data) | (substruct3->worldRibbon << 26); } break; + case MON_DATA_NATURE: + return boxMon->personality % 25; + break; default: break; } @@ -4032,6 +4035,10 @@ void SetMonData(struct Pokemon *mon, s32 field, const void *dataArg) break; case MON_DATA_SPECIES2: break; + case MON_DATA_NATURE: // Calculate stats after settings + SetBoxMonData(&mon->box, field, data); + CalculateMonStats(mon); + break; default: SetBoxMonData(&mon->box, field, data); break; @@ -4298,6 +4305,81 @@ void SetBoxMonData(struct BoxPokemon *boxMon, s32 field, const void *dataArg) substruct3->spDefenseIV = (ivs >> 25) & MAX_IV_MASK; break; } + case MON_DATA_NATURE: + { + u32 pid = boxMon->personality; + u32 otId = boxMon->otId; + s8 diff = (data[0] % 25) - (pid % 25); // difference between new nature and current nature, [-24,24] + bool8 preserveShiny = FALSE; + bool8 preserveLetter = FALSE; + u16 shinyValue = HIHALF(pid) ^ LOHALF(pid); + s32 tweak; + u32 pidTemp; + // See https://bulbapedia.bulbagarden.net/wiki/Personality_value#Nature + // Goal here is to preserve as much of the PID as possible + // To preserve gender & substruct order, we add/subtract multiples of 5376 that is 0 % 256, 0 % 24, 1 % 25 + // i.e, to increase the nature by n % 25, we add n*5376 % 19200 (LCM of 24, 25, 256) to the pid + // Ability number is determined by parity and so adding multiples of 5376 preserves it + // TODO: For genderless pokemon, 576/600 can be used instead of 5376/19200 + if (diff == 0) // No change + break; + else if (diff < 0) + diff = 25+diff; + tweak = (diff*5376) % 19200; + pidTemp = pid + tweak; + // If the pokemon is shiny or if changing the PID would make it shiny, preserve its shiny value + if (IsShinyOtIdPersonality(otId, pid) || IsShinyOtIdPersonality(otId, pidTemp)) + preserveShiny = TRUE; + if (substruct0->species == SPECIES_UNOWN) // Preserve Unown letter + preserveLetter = TRUE; + if (preserveShiny && preserveLetter) { // honestly though, how many shiny Unown are out there ? + while (pidTemp > pid) { + if ((HIHALF(pidTemp) ^ LOHALF(pidTemp) ^ shinyValue) < SHINY_ODDS) + if (GET_UNOWN_LETTER(pidTemp) == GET_UNOWN_LETTER(pid)) + break; + pidTemp += 19200; + } + } else if (preserveShiny) { + while (pidTemp > pid) { + if ((HIHALF(pidTemp) ^ LOHALF(pidTemp) ^ shinyValue) < SHINY_ODDS) + break; + pidTemp += 19200; + } + } else if (preserveLetter) { + while (pidTemp > pid) { + if (GET_UNOWN_LETTER(pidTemp) == GET_UNOWN_LETTER(pid)) + break; + pidTemp += 19200; + } + } + if (pidTemp < pid) { // overflow; search backwards + tweak -= 19200; + pidTemp = pid + tweak; + if (preserveShiny && preserveLetter) { + while (pidTemp < pid) { + if ((HIHALF(pidTemp) ^ LOHALF(pidTemp) ^ shinyValue) < SHINY_ODDS) + if (GET_UNOWN_LETTER(pidTemp) == GET_UNOWN_LETTER(pid)) + break; + pidTemp -= 19200; + } + } else if (preserveShiny) { + while (pidTemp < pid) { + if ((HIHALF(pidTemp) ^ LOHALF(pidTemp) ^ shinyValue) < SHINY_ODDS) + break; + pidTemp -= 19200; + } + } else if (preserveLetter) { + while (pidTemp < pid) { + if (GET_UNOWN_LETTER(pidTemp) == GET_UNOWN_LETTER(pid)) + break; + pidTemp -= 19200; + } + } + } + if (pid % 24 == pidTemp % 24 || pid % 256 == pidTemp % 256) + boxMon->personality = pidTemp; + break; + } default: break; } @@ -4878,7 +4960,7 @@ bool8 PokemonUseItemEffects(struct Pokemon *mon, u16 item, u8 partyIndex, u8 mov temp2 = itemEffect[itemEffectParam]; dataSigned = GetMonData(mon, sGetMonDataEVConstants[temp1], NULL); evChange = temp2; - + if (evChange > 0) // Increasing EV (HP or Atk) { // Has EV increase limit already been reached? @@ -4976,7 +5058,7 @@ bool8 PokemonUseItemEffects(struct Pokemon *mon, u16 item, u8 partyIndex, u8 mov { if (!usedByAI) { - // Restore HP + // Restore HP dataUnsigned = GetMonData(mon, MON_DATA_HP, NULL) + dataUnsigned; if (dataUnsigned > GetMonData(mon, MON_DATA_MAX_HP, NULL)) dataUnsigned = GetMonData(mon, MON_DATA_MAX_HP, NULL); @@ -5055,7 +5137,7 @@ bool8 PokemonUseItemEffects(struct Pokemon *mon, u16 item, u8 partyIndex, u8 mov dataUnsigned = CalculatePPWithBonus(moveId, GetMonData(mon, MON_DATA_PP_BONUSES, NULL), moveIndex); } SetMonData(mon, MON_DATA_PP1 + moveIndex, &dataUnsigned); - + // Heal battler PP too (if applicable) if (gMain.inBattle && battlerId != MAX_BATTLERS_COUNT && !(gBattleMons[battlerId].status2 & STATUS2_TRANSFORMED) @@ -5092,7 +5174,7 @@ bool8 PokemonUseItemEffects(struct Pokemon *mon, u16 item, u8 partyIndex, u8 mov case 5: effectFlags = itemEffect[i]; temp1 = 0; - + // Loop through and try each of the ITEM5 effects while (effectFlags != 0) {