level caps

This commit is contained in:
cawtds 2024-07-22 18:35:42 +02:00
parent dd757af042
commit fe39593c85
6 changed files with 145 additions and 41 deletions

20
include/level_caps.h Normal file
View File

@ -0,0 +1,20 @@
#ifndef GUARD_LEVEL_CAP_H
#define GUARD_LEVEL_CAP_H
#if B_EXP_CAP_TYPE != EXP_CAP_NONE && B_EXP_CAP_TYPE != EXP_CAP_HARD && B_EXP_CAP_TYPE != EXP_CAP_SOFT
#error "Invalid choice for B_EXP_CAP_TYPE, must be of [EXP_CAP_NONE, EXP_CAP_HARD, EXP_CAP_SOFT]"
#endif
#if B_EXP_CAP_TYPE == EXP_CAP_HARD || B_EXP_CAP_TYPE == EXP_CAP_SOFT
#if B_LEVEL_CAP_TYPE != LEVEL_CAP_FLAG_LIST && B_LEVEL_CAP_TYPE != LEVEL_CAP_VARIABLE
#error "Invalid choice for B_LEVEL_CAP_TYPE, must be of [LEVEL_CAP_FLAG_LIST, LEVEL_CAP_VARIABLE]"
#endif
#if B_LEVEL_CAP_TYPE == LEVEL_CAP_VARIABLE && B_LEVEL_CAP_VARIABLE == 0
#error "B_LEVEL_CAP_TYPE set to LEVEL_CAP_VARIABLE, but no variable chosen for B_LEVEL_CAP_VARIABLE, set B_LEVEL_CAP_VARIABLE to a valid event variable"
#endif
#endif
u32 GetCurrentLevelCap(void);
u32 GetSoftLevelCapExpValue(u32 level, u32 expValue);
#endif /* GUARD_LEVEL_CAP_H */

View File

@ -28,7 +28,7 @@
#include "bg.h"
#include "string_util.h"
#include "pokemon_icon.h"
// #include "level_caps.h"
#include "level_caps.h"
#include "m4a.h"
#include "mail.h"
#include "event_data.h"
@ -4236,29 +4236,29 @@ static void Cmd_getexp(void)
if (IsValidForBattle(&gPlayerParty[*expMonId]))
{
if (wasSentOut)
gBattleMoveDamage = gBattleStruct->expValue; // GetSoftLevelCapExpValue(gPlayerParty[*expMonId].level, gBattleStruct->expValue); TODO: Level caps?
gBattleMoveDamage = GetSoftLevelCapExpValue(gPlayerParty[*expMonId].level, gBattleStruct->expValue);
else
gBattleMoveDamage = 0;
if ((holdEffect == HOLD_EFFECT_EXP_SHARE || IsGen6ExpShareEnabled())
&& (B_SPLIT_EXP < GEN_6 || gBattleMoveDamage == 0)) // only give exp share bonus in later gens if the mon wasn't sent out
{
gBattleMoveDamage += gBattleStruct->expValue; // GetSoftLevelCapExpValue(gPlayerParty[*expMonId].level, gBattleStruct->expShareExpValue); TODO: Level caps?
gBattleMoveDamage += GetSoftLevelCapExpValue(gPlayerParty[*expMonId].level, gBattleStruct->expShareExpValue);
}
ApplyExperienceMultipliers(&gBattleMoveDamage, *expMonId, gBattlerFainted);
// if (B_EXP_CAP_TYPE == EXP_CAP_HARD && gBattleMoveDamage != 0)
// {
// u32 growthRate = gSpeciesInfo[GetMonData(&gPlayerParty[*expMonId], MON_DATA_SPECIES)].growthRate;
// u32 currentExp = GetMonData(&gPlayerParty[*expMonId], MON_DATA_EXP);
// u32 levelCap = GetCurrentLevelCap();
if (B_EXP_CAP_TYPE == EXP_CAP_HARD && gBattleMoveDamage != 0)
{
u32 growthRate = gSpeciesInfo[GetMonData(&gPlayerParty[*expMonId], MON_DATA_SPECIES)].growthRate;
u32 currentExp = GetMonData(&gPlayerParty[*expMonId], MON_DATA_EXP);
u32 levelCap = GetCurrentLevelCap();
// if (GetMonData(&gPlayerParty[*expMonId], MON_DATA_LEVEL) >= levelCap)
// gBattleMoveDamage = 0;
// else if (gExperienceTables[growthRate][levelCap] < currentExp + gBattleMoveDamage)
// gBattleMoveDamage = gExperienceTables[growthRate][levelCap] - currentExp;
// }
if (GetMonData(&gPlayerParty[*expMonId], MON_DATA_LEVEL) >= levelCap)
gBattleMoveDamage = 0;
else if (gExperienceTables[growthRate][levelCap] < currentExp + gBattleMoveDamage)
gBattleMoveDamage = gExperienceTables[growthRate][levelCap] - currentExp;
}
if (IsTradedMon(&gPlayerParty[*expMonId]))
{

View File

@ -10,6 +10,7 @@
#include "event_data.h"
#include "random.h"
#include "constants/moves.h"
#include "level_caps.h"
#include "menu.h"
#include "new_menu_helpers.h"
#include "script.h"
@ -619,7 +620,7 @@ static u16 TakeSelectedPokemonFromDaycare(struct DaycareMon *daycareMon)
species = GetBoxMonData(&daycareMon->mon, MON_DATA_SPECIES);
BoxMonToMon(&daycareMon->mon, &pokemon);
if (GetMonData(&pokemon, MON_DATA_LEVEL) != MAX_LEVEL)
if (GetMonData(&pokemon, MON_DATA_LEVEL) < GetCurrentLevelCap())
{
experience = GetMonData(&pokemon, MON_DATA_EXP) + daycareMon->steps;
SetMonData(&pokemon, MON_DATA_EXP, &experience);
@ -668,6 +669,8 @@ static u8 GetNumLevelsGainedFromSteps(struct DaycareMon *daycareMon)
levelBefore = GetLevelFromBoxMonExp(&daycareMon->mon);
levelAfter = GetLevelAfterDaycareSteps(&daycareMon->mon, daycareMon->steps);
if (levelAfter > GetCurrentLevelCap())
levelAfter = GetCurrentLevelCap();
return levelAfter - levelBefore;
}

83
src/level_caps.c Normal file
View File

@ -0,0 +1,83 @@
#include "global.h"
#include "battle.h"
#include "event_data.h"
#include "level_caps.h"
#include "pokemon.h"
u32 GetCurrentLevelCap(void)
{
static const u32 sLevelCapFlagMap[][2] =
{
{FLAG_BADGE01_GET, 14},
{FLAG_BADGE02_GET, 21},
{FLAG_BADGE03_GET, 24},
{FLAG_BADGE04_GET, 29},
{FLAG_BADGE05_GET, 43},
{FLAG_BADGE06_GET, 43},
{FLAG_BADGE07_GET, 47},
{FLAG_BADGE08_GET, 50},
{FLAG_SYS_GAME_CLEAR, 63},
};
u32 i;
if (B_LEVEL_CAP_TYPE == LEVEL_CAP_FLAG_LIST)
{
for (i = 0; i < ARRAY_COUNT(sLevelCapFlagMap); i++)
{
if (!FlagGet(sLevelCapFlagMap[i][0]))
return sLevelCapFlagMap[i][1];
}
}
else if (B_LEVEL_CAP_TYPE == LEVEL_CAP_VARIABLE)
{
return VarGet(B_LEVEL_CAP_VARIABLE);
}
return MAX_LEVEL;
}
u32 GetSoftLevelCapExpValue(u32 level, u32 expValue)
{
static const u32 sExpScalingDown[5] = { 4, 8, 16, 32, 64 };
static const u32 sExpScalingUp[5] = { 16, 8, 4, 2, 1 };
u32 levelDifference;
u32 currentLevelCap = GetCurrentLevelCap();
if (B_EXP_CAP_TYPE == EXP_CAP_NONE)
return expValue;
if (level < currentLevelCap)
{
if (B_LEVEL_CAP_EXP_UP)
{
levelDifference = currentLevelCap - level;
if (levelDifference > ARRAY_COUNT(sExpScalingUp))
return expValue + (expValue / sExpScalingUp[ARRAY_COUNT(sExpScalingUp) - 1]);
else
return expValue + (expValue / sExpScalingUp[levelDifference]);
}
else
{
return expValue;
}
}
else if (B_EXP_CAP_TYPE == EXP_CAP_HARD)
{
return 0;
}
else if (B_EXP_CAP_TYPE == EXP_CAP_SOFT)
{
levelDifference = level - currentLevelCap;
if (levelDifference > ARRAY_COUNT(sExpScalingDown))
return expValue / sExpScalingDown[ARRAY_COUNT(sExpScalingDown) - 1];
else
return expValue / sExpScalingDown[levelDifference];
}
else
{
return expValue;
}
}

View File

@ -24,6 +24,7 @@
#include "item.h"
#include "item_menu.h"
#include "item_use.h"
#include "level_caps.h"
#include "link.h"
#include "link_rfu.h"
#include "load_save.h"
@ -5616,7 +5617,7 @@ void ItemUseCB_RareCandy(u8 taskId, TaskFunc func)
u8 holdEffectParam = ItemId_GetHoldEffectParam(*itemPtr);
sInitialLevel = GetMonData(mon, MON_DATA_LEVEL);
if (GetMonData(mon, MON_DATA_LEVEL) != MAX_LEVEL)
if (!(B_RARE_CANDY_CAP && sInitialLevel >= GetCurrentLevelCap()))
{
GetMonLevelUpWindowStats(mon, sLevelUpStatsBefore);
cannotUseEffect = ExecuteTableBasedItemEffect(mon, *itemPtr, gPartyMenu.slotId, 0);

View File

@ -20,6 +20,7 @@
#include "battle_message.h"
#include "battle_util.h"
#include "link.h"
#include "level_caps.h"
#include "pokemon_animation.h"
#include "m4a.h"
#include "pokedex.h"
@ -3585,8 +3586,17 @@ bool8 PokemonUseItemEffects(struct Pokemon *mon, u16 item, u8 partyIndex, u8 mov
{
u16 species = GetMonData(mon, MON_DATA_SPECIES, NULL);
dataUnsigned = sExpCandyExperienceTable[param - 1] + GetMonData(mon, MON_DATA_EXP, NULL);
if (dataUnsigned > gExperienceTables[gSpeciesInfo[species].growthRate][MAX_LEVEL])
if (B_RARE_CANDY_CAP && B_EXP_CAP_TYPE == EXP_CAP_HARD)
{
u32 currentLevelCap = GetCurrentLevelCap();
if (dataUnsigned > gExperienceTables[gSpeciesInfo[species].growthRate][currentLevelCap])
dataUnsigned = gExperienceTables[gSpeciesInfo[species].growthRate][currentLevelCap];
}
else if (dataUnsigned > gExperienceTables[gSpeciesInfo[species].growthRate][MAX_LEVEL])
{
dataUnsigned = gExperienceTables[gSpeciesInfo[species].growthRate][MAX_LEVEL];
}
}
if (dataUnsigned != 0) // Failsafe
@ -5127,37 +5137,24 @@ void PartySpreadPokerus(struct Pokemon *party)
}
}
static void SetMonExpWithMaxLevelCheck(struct Pokemon *mon, int species, u8 unused, u32 data)
{
if (data > gExperienceTables[gSpeciesInfo[species].growthRate][MAX_LEVEL])
{
data = gExperienceTables[gSpeciesInfo[species].growthRate][MAX_LEVEL];
SetMonData(mon, MON_DATA_EXP, &data);
}
}
bool8 TryIncrementMonLevel(struct Pokemon *mon)
{
u16 species = GetMonData(mon, MON_DATA_SPECIES, NULL);
u8 level = GetMonData(mon, MON_DATA_LEVEL, NULL);
u8 newLevel = level + 1;
u32 exp = GetMonData(mon, MON_DATA_EXP, NULL);
if (level < MAX_LEVEL)
u16 species = GetMonData(mon, MON_DATA_SPECIES, 0);
u8 nextLevel = GetMonData(mon, MON_DATA_LEVEL, 0) + 1;
u32 expPoints = GetMonData(mon, MON_DATA_EXP, 0);
if (expPoints > gExperienceTables[gSpeciesInfo[species].growthRate][MAX_LEVEL])
{
if (exp > gExperienceTables[gSpeciesInfo[species].growthRate][newLevel])
{
SetMonData(mon, MON_DATA_LEVEL, &newLevel);
SetMonExpWithMaxLevelCheck(mon, species, newLevel, exp);
return TRUE;
}
else
return FALSE;
expPoints = gExperienceTables[gSpeciesInfo[species].growthRate][MAX_LEVEL];
SetMonData(mon, MON_DATA_EXP, &expPoints);
}
if (nextLevel > GetCurrentLevelCap() || expPoints < gExperienceTables[gSpeciesInfo[species].growthRate][nextLevel])
{
return FALSE;
}
else
{
SetMonExpWithMaxLevelCheck(mon, species, level, exp);
return FALSE;
SetMonData(mon, MON_DATA_LEVEL, &nextLevel);
return TRUE;
}
}