Added a non-RNG, PID-preserving way to modify pokemon nature.

(wip) Preserve shiny value when changing nature.

(WIP) Preserve shiny value.

(WIP) Preserve nature.

(WIP) Removed some debugging statements.

(WIP) Removed more debugging statements.

(WIP) Nature changing now supports Unown.
This commit is contained in:
Ariel Antonitis 2021-05-22 02:10:12 -04:00
parent 7d420b22e8
commit e9d01b4808
2 changed files with 87 additions and 4 deletions

View File

@ -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

View File

@ -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)
{