diff --git a/include/config/ev_caps.h b/include/config/ev_caps.h new file mode 100644 index 0000000000..0513ff086e --- /dev/null +++ b/include/config/ev_caps.h @@ -0,0 +1,16 @@ +#ifndef GUARD_CONFIG_EV_CAP_H +#define GUARD_CONFIG_EV_CAP_H + +// Constants for EV Cap Types +#define EV_CAP_NONE 0 // Regular behavior, no EV caps are applied +#define EV_CAP_FLAG_LIST 1 // EV cap is chosen according to the first unset flag in `sEVCapFlagMap` +#define EV_CAP_VARIABLE 2 // EV cap is chosen according to the contents of the event variable specified by B_EV_CAP_VARIABLE +#define EV_CAP_NO_GAIN 3 // No EVs can be gained + +// Configs for EV Cap +#define B_EV_CAP_TYPE EV_CAP_NONE // [EV_CAP_NONE, EV_CAP_FLAG_LIST, EV_CAP_VARIABLE, EV_CAP_NO_GAIN] choose the type of EV cap to apply#define B_EV_CAP_VARIABLE 12 // event variable used to derive EV cap if B_EV_CAP_TYPE is set to EV_CAP_VARIABLE +#define B_EV_CAP_VARIABLE 8 // event variable used to derive EV cap if B_EV_CAP_TYPE is set to EV_CAP_VARIABLE + +#define B_EV_ITEMS_CAP FALSE // If set to true, EV-boosting items can't be used to go over the EV cap + +#endif /*GUARD_CONFIG_EV_CAP_H*/ diff --git a/include/constants/global.h b/include/constants/global.h index 7e26bd5a0d..a4623c9d8b 100644 --- a/include/constants/global.h +++ b/include/constants/global.h @@ -8,6 +8,7 @@ #include "config/level_caps.h" #include "config/pokemon.h" #include "config/overworld.h" +#include "config/ev_caps.h" // Invalid Versions show as "----------" in Gen 4 and Gen 5's summary screen. // In Gens 6 and 7, invalid versions instead show "a distant land" in the summary screen. diff --git a/include/ev_caps.h b/include/ev_caps.h new file mode 100644 index 0000000000..2b2dd0b02b --- /dev/null +++ b/include/ev_caps.h @@ -0,0 +1,10 @@ +#ifndef GUARD_EV_CAP_H +#define GUARD_EV_CAP_H + +#if B_EV_CAP_TYPE != EV_CAP_NONE && B_EV_CAP_TYPE != EV_CAP_FLAG_LIST && B_EV_CAP_TYPE != EV_CAP_VARIABLE && B_EV_CAP_TYPE != EV_CAP_NO_GAIN +#error "Invalid choice for B_EV_CAP_TYPE, must be one of [EV_CAP_NONE, EV_CAP_FLAG_LIST, EV_CAP_VARIABLE, EV_CAP_NO_GAIN]" +#endif + +u32 GetCurrentEVCap(void); + +#endif /* GUARD_EV_CAP_H */ diff --git a/src/ev_caps.c b/src/ev_caps.c new file mode 100644 index 0000000000..8eb3531ca4 --- /dev/null +++ b/src/ev_caps.c @@ -0,0 +1,41 @@ +#include "global.h" +#include "battle.h" +#include "event_data.h" +#include "ev_caps.h" +#include "pokemon.h" + +u32 GetCurrentEVCap(void) +{ + + static const u16 sEvCapFlagMap[][2] = { + // Define EV caps for each milestone + {FLAG_BADGE01_GET, 30}, + {FLAG_BADGE02_GET, 90}, + {FLAG_BADGE03_GET, 150}, + {FLAG_BADGE04_GET, 210}, + {FLAG_BADGE05_GET, 270}, + {FLAG_BADGE06_GET, 330}, + {FLAG_BADGE07_GET, 390}, + {FLAG_BADGE08_GET, 450}, + {FLAG_IS_CHAMPION, MAX_TOTAL_EVS}, + }; + + if (B_EV_CAP_TYPE == EV_CAP_FLAG_LIST) + { + for (u32 evCap = 0; evCap < ARRAY_COUNT(sEvCapFlagMap); evCap++) + { + if (!FlagGet(sEvCapFlagMap[evCap][0])) + return sEvCapFlagMap[evCap][1]; + } + } + else if (B_EV_CAP_TYPE == EV_CAP_VARIABLE) + { + return VarGet(B_EV_CAP_VARIABLE); + } + else if (B_EV_CAP_TYPE == EV_CAP_NO_GAIN) + { + return 0; + } + + return MAX_TOTAL_EVS; +} diff --git a/src/pokemon.c b/src/pokemon.c index 718ce00c65..165c430d96 100644 --- a/src/pokemon.c +++ b/src/pokemon.c @@ -60,6 +60,7 @@ #include "constants/union_room.h" #include "constants/weather.h" #include "wild_encounter.h" +#include "ev_caps.h" #define FRIENDSHIP_EVO_THRESHOLD ((P_FRIENDSHIP_EVO_THRESHOLD >= GEN_9) ? 160 : 220) @@ -3752,6 +3753,9 @@ bool8 PokemonUseItemEffects(struct Pokemon *mon, u16 item, u8 partyIndex, u8 mov s8 evChange; u16 evCount; + // Determine the EV cap to use + u32 maxAllowedEVs = !B_EV_ITEMS_CAP ? MAX_TOTAL_EVS : GetCurrentEVCap(); + // Get item hold effect heldItem = GetMonData(mon, MON_DATA_HELD_ITEM, NULL); if (heldItem == ITEM_ENIGMA_BERRY_E_READER) @@ -3879,27 +3883,31 @@ bool8 PokemonUseItemEffects(struct Pokemon *mon, u16 item, u8 partyIndex, u8 mov if (evChange > 0) // Increasing EV (HP or Atk) { - // Has EV increase limit already been reached? - if (evCount >= MAX_TOTAL_EVS) + // Check if the total EV limit is reached + if (evCount >= maxAllowedEVs) return TRUE; - if (itemEffect[10] & ITEM10_IS_VITAMIN) - evCap = EV_ITEM_RAISE_LIMIT; - else - evCap = MAX_PER_STAT_EVS; - + // Ensure the increase does not exceed the max EV per stat (252) + evCap = (itemEffect[10] & ITEM10_IS_VITAMIN) ? EV_ITEM_RAISE_LIMIT : MAX_PER_STAT_EVS; + + // Check if the per-stat limit is reached if (dataSigned >= evCap) - break; - - // Limit the increase + return TRUE; // Prevents item use if the per-stat cap is already reached + if (dataSigned + evChange > evCap) - temp2 = evCap - (dataSigned + evChange) + evChange; + temp2 = evCap - dataSigned; else temp2 = evChange; - if (evCount + temp2 > MAX_TOTAL_EVS) - temp2 += MAX_TOTAL_EVS - (evCount + temp2); + // Ensure the total EVs do not exceed the maximum allowed (510) + if (evCount + temp2 > maxAllowedEVs) + temp2 = maxAllowedEVs - evCount; + // Prevent item use if no EVs can be increased + if (temp2 == 0) + return TRUE; + + // Apply the EV increase dataSigned += temp2; } else if (evChange < 0) // Decreasing EV (HP or Atk) @@ -4064,27 +4072,31 @@ bool8 PokemonUseItemEffects(struct Pokemon *mon, u16 item, u8 partyIndex, u8 mov evChange = temp2; if (evChange > 0) // Increasing EV { - // Has EV increase limit already been reached? - if (evCount >= MAX_TOTAL_EVS) + // Check if the total EV limit is reached + if (evCount >= maxAllowedEVs) return TRUE; - if (itemEffect[10] & ITEM10_IS_VITAMIN) - evCap = EV_ITEM_RAISE_LIMIT; - else - evCap = MAX_PER_STAT_EVS; - + // Ensure the increase does not exceed the max EV per stat (252) + evCap = (itemEffect[10] & ITEM10_IS_VITAMIN) ? EV_ITEM_RAISE_LIMIT : MAX_PER_STAT_EVS; + + // Check if the per-stat limit is reached if (dataSigned >= evCap) - break; - - // Limit the increase + return TRUE; // Prevents item use if the per-stat cap is already reached + if (dataSigned + evChange > evCap) - temp2 = evCap - (dataSigned + evChange) + evChange; + temp2 = evCap - dataSigned; else temp2 = evChange; - if (evCount + temp2 > MAX_TOTAL_EVS) - temp2 += MAX_TOTAL_EVS - (evCount + temp2); + // Ensure the total EVs do not exceed the maximum allowed (510) + if (evCount + temp2 > maxAllowedEVs) + temp2 = maxAllowedEVs - evCount; + // Prevent item use if no EVs can be increased + if (temp2 == 0) + return TRUE; + + // Apply the EV increase dataSigned += temp2; } else if (evChange < 0) // Decreasing EV @@ -5195,6 +5207,7 @@ void MonGainEVs(struct Pokemon *mon, u16 defeatedSpecies) int i, multiplier; u8 stat; u8 bonus; + u32 currentEVCap = GetCurrentEVCap(); heldItem = GetMonData(mon, MON_DATA_HELD_ITEM, 0); if (heldItem == ITEM_ENIGMA_BERRY_E_READER) @@ -5224,7 +5237,7 @@ void MonGainEVs(struct Pokemon *mon, u16 defeatedSpecies) for (i = 0; i < NUM_STATS; i++) { - if (totalEVs >= MAX_TOTAL_EVS) + if (totalEVs >= currentEVCap) break; if (CheckPartyHasHadPokerus(mon, 0)) @@ -5275,8 +5288,8 @@ void MonGainEVs(struct Pokemon *mon, u16 defeatedSpecies) if (holdEffect == HOLD_EFFECT_MACHO_BRACE) evIncrease *= 2; - if (totalEVs + (s16)evIncrease > MAX_TOTAL_EVS) - evIncrease = ((s16)evIncrease + MAX_TOTAL_EVS) - (totalEVs + evIncrease); + if (totalEVs + (s16)evIncrease > currentEVCap) + evIncrease = ((s16)evIncrease + currentEVCap) - (totalEVs + evIncrease); if (evs[i] + (s16)evIncrease > MAX_PER_STAT_EVS) {