"Final checkpoint" EXP bonus

This commit is contained in:
Antonio Martinez 2025-09-18 18:16:05 -04:00 committed by AJ Martinez
parent 7109cd8c13
commit 60fca5210d
4 changed files with 78 additions and 24 deletions

View file

@ -757,8 +757,8 @@ extern int
#define EXP_STABLERATE 3*FRACUNIT/10 // how low is your placement before losing XP? 4*FRACUNIT/10 = top 40% of race will gain
#define EXP_POWER 3*FRACUNIT/100 // adjust to change overall xp volatility
#define EXP_MIN 25 // The min value target
#define EXP_TARGET 120 // Used for grading ...
#define EXP_MAX 120 // The max value displayed by the hud and in the tally screen and GP results screen
#define EXP_TARGET 150 // Used for grading ...
#define EXP_MAX 150 // The max value displayed by the hud and in the tally screen and GP results screen
#ifdef __cplusplus
} // extern "C"

View file

@ -4500,6 +4500,15 @@ void K_SpawnEXP(player_t *player, UINT8 exp, mobj_t *impact)
if (exp == 0)
return;
boolean special = false;
if (player->gradingpointnum == K_GetNumGradingPoints())
{
exp *= FINAL_CHECK_POWER;
special = true;
}
for (int i = 0; i < exp; i++)
{
mobj_t *pickup = P_SpawnMobj(impact->x, impact->y, impact->z, MT_EXP);
@ -4510,6 +4519,14 @@ void K_SpawnEXP(player_t *player, UINT8 exp, mobj_t *impact)
pickup->momy += P_RandomRange(PR_ITEM_DEBRIS, -20*mapobjectscale, 20*mapobjectscale);
pickup->momz += P_RandomRange(PR_ITEM_DEBRIS, -20*mapobjectscale, 20*mapobjectscale);
// pickup->color = player->skincolor;
if (special)
{
P_InstaScale(pickup, 3*pickup->scale/2);
pickup->color = SKINCOLOR_SAPPHIRE;
pickup->colorized = true;
}
P_SetTarget(&pickup->target, player->mo);
}
}
@ -4719,7 +4736,7 @@ void K_CheckpointCrossAward(player_t *player)
K_HandleRaceSplits(player, leveltime - starttime, player->gradingpointnum);
}
player->gradingfactor += K_GetGradingFactorAdjustment(player);
player->gradingfactor += K_GetGradingFactorAdjustment(player, player->gradingpointnum);
player->gradingpointnum++;
player->exp = K_GetEXP(player);
//CONS_Printf("player: %s factor: %.2f exp: %d\n", player_names[player-players], FIXED_TO_FLOAT(player->gradingfactor), player->exp);
@ -17095,7 +17112,7 @@ static UINT8 K_Opponents(player_t *player)
return opponents;
}
static fixed_t K_GradingFactorPower(player_t *player)
static fixed_t K_GradingFactorPower(player_t *player, UINT32 gradingpoint)
{
fixed_t power = EXP_POWER; // adjust to change overall exp volatility
UINT8 opponents = K_Opponents(player);
@ -17109,23 +17126,30 @@ static fixed_t K_GradingFactorPower(player_t *player)
if (opponents > 8)
power -= (opponents - 8) * (power/24);
UINT32 gp = K_GetNumGradingPoints();
if (gradingpoint-1 == gp)
{
power *= FINAL_CHECK_POWER;
}
return power;
}
static fixed_t K_GradingFactorGainPerWin(player_t *player)
static fixed_t K_GradingFactorGainPerWin(player_t *player, UINT32 gradingpoint)
{
return K_GradingFactorPower(player);
return K_GradingFactorPower(player, gradingpoint);
}
static fixed_t K_GradingFactorDrainPerCheckpoint(player_t *player)
static fixed_t K_GradingFactorDrainPerCheckpoint(player_t *player, UINT32 gradingpoint)
{
// EXP_STABLERATE: How low do you have to place before losing gradingfactor? 4*FRACUNIT/10 = top 40% of race gains, 60% loses.
UINT8 opponents = K_Opponents(player);
fixed_t power = K_GradingFactorPower(player);
fixed_t power = K_GradingFactorPower(player, gradingpoint);
return FixedMul(power, FixedMul(opponents*FRACUNIT, FRACUNIT - EXP_STABLERATE));
}
fixed_t K_GetGradingFactorAdjustment(player_t *player)
fixed_t K_GetGradingFactorAdjustment(player_t *player, UINT32 gradingpoint)
{
fixed_t result = 0;
@ -17136,13 +17160,13 @@ fixed_t K_GetGradingFactorAdjustment(player_t *player)
continue;
if (player->position < players[i].position)
result += K_GradingFactorGainPerWin(player);
result += K_GradingFactorGainPerWin(player, gradingpoint);
}
// ...then take all of the gradingfactor you could possibly have earned,
// and lose it proportional to the stable rate. If you're below
// the stable threshold, this results in you losing gradingfactor
result -= K_GradingFactorDrainPerCheckpoint(player);
result -= K_GradingFactorDrainPerCheckpoint(player, gradingpoint);
return result;
}
@ -17156,8 +17180,8 @@ fixed_t K_GetGradingFactorMinMax(player_t *player, boolean max)
for (UINT8 i = 0; i < player->gradingpointnum; i++) // For each gradingpoint you've reached...
{
for (UINT8 j = 0; j < winning; j++)
factor += K_GradingFactorGainPerWin(player); // If max, increase gradingfactor for each player you could have been beating.
factor -= K_GradingFactorDrainPerCheckpoint(player); // Then, drain like usual.
factor += K_GradingFactorGainPerWin(player, i); // If max, increase gradingfactor for each player you could have been beating.
factor -= K_GradingFactorDrainPerCheckpoint(player, i); // Then, drain like usual.
}
return factor;
@ -17165,16 +17189,24 @@ fixed_t K_GetGradingFactorMinMax(player_t *player, boolean max)
UINT16 K_GetEXP(player_t *player)
{
UINT32 gpn = player->gradingpointnum;
UINT32 numgradingpoints = K_GetNumGradingPoints();
fixed_t targetminexp = (EXP_MIN*player->gradingpointnum<<FRACBITS) / max(1,numgradingpoints); // about what a last place player should be at this stage of the race
fixed_t targetmaxexp = (EXP_MAX*player->gradingpointnum<<FRACBITS) / max(1,numgradingpoints); // about what a 1.0 factor should be at this stage of the race
UINT32 effgradingpoints = K_GetNumEffectiveGradingPoints();
// Account for Final Check bonus
if (gpn == numgradingpoints)
gpn = effgradingpoints;
fixed_t targetminexp = (EXP_MIN*gpn<<FRACBITS) / max(1,effgradingpoints); // about what a last place player should be at this stage of the race
fixed_t targetmaxexp = (EXP_MAX*gpn<<FRACBITS) / max(1,effgradingpoints); // about what a 1.0 factor should be at this stage of the race
fixed_t factormin = K_GetGradingFactorMinMax(player, false);
fixed_t factormax = K_GetGradingFactorMinMax(player, true);
UINT16 exp = FixedRescale(player->gradingfactor, factormin, factormax, Easing_Linear, targetminexp, targetmaxexp)>>FRACBITS;
if (modeattacking)
exp = 100 * player->gradingpointnum / numgradingpoints;
exp = 100 * player->gradingpointnum / max(1, numgradingpoints); // No Final Check here, just a linear slide
// CONS_Printf("Player %s numgradingpoints=%d gradingpoint=%d targetminexp=%d targetmaxexp=%d factor=%.2f factormin=%.2f factormax=%.2f exp=%d\n",
// player_names[player - players], numgradingpoints, player->gradingpointnum, targetminexp, targetmaxexp, FIXED_TO_FLOAT(player->gradingfactor), FIXED_TO_FLOAT(factormin), FIXED_TO_FLOAT(factormax), exp);
@ -17190,6 +17222,16 @@ UINT32 K_GetNumGradingPoints(void)
return numlaps * (1 + Obj_GetCheckpointCount());
}
// Final check counts for extra, used for EXP minmax etc
UINT32 K_GetNumEffectiveGradingPoints(void)
{
UINT32 gp = K_GetNumGradingPoints();
if (gp == 0)
return 0;
else
return gp + FINAL_CHECK_POWER - 1;
}
// ===
// END EXP ZONE
// ===

View file

@ -123,6 +123,9 @@ Make sure this matches the actual number of states
#define AUTORESPAWN_TIME (10*TICRATE)
#define AUTORESPAWN_THRESHOLD (7*TICRATE)
// How many checkpoints is the last checkpoint worth?
#define FINAL_CHECK_POWER (3)
angle_t K_ReflectAngle(angle_t angle, angle_t against, fixed_t maxspeed, fixed_t yourspeed);
void K_PopBubbleShield(player_t *player);
@ -347,11 +350,12 @@ boolean K_ThunderDome(void);
boolean K_PlayerCanUseItem(player_t *player);
fixed_t K_GetGradingFactorAdjustment(player_t *player);
fixed_t K_GetGradingFactorAdjustment(player_t *player, UINT32 gradingpoint);
fixed_t K_GetGradingFactorMinMax(player_t *player, boolean max);
UINT16 K_GetEXP(player_t *player);
UINT32 K_GetNumGradingPoints(void);
UINT32 K_GetNumEffectiveGradingPoints(void);
boolean K_LegacyRingboost(const player_t *player);

View file

@ -384,14 +384,20 @@ void K_UpdatePowerLevels(player_t *player, UINT8 gradingpoint, boolean forfeit)
}
else
{
if (exitBonus == false)
fixed_t prevInc = ourinc;
INT16 dvs = max(K_GetNumGradingPoints(), 1);
ourinc = FixedDiv(ourinc, dvs*FRACUNIT);
theirinc = FixedDiv(theirinc, dvs*FRACUNIT);
if (exitBonus)
{
ourinc *= FINAL_CHECK_POWER;
theirinc *= FINAL_CHECK_POWER;
CONS_Debug(DBG_PWRLV, "Final check bonus (%d / %d * %d = %d)\n", prevInc/FRACUNIT, dvs, FINAL_CHECK_POWER, ourinc/FRACUNIT);
}
else
{
fixed_t prevInc = ourinc;
INT16 dvs = max(K_GetNumGradingPoints(), 1);
ourinc = FixedDiv(ourinc, dvs*FRACUNIT);
theirinc = FixedDiv(theirinc, dvs*FRACUNIT);
CONS_Debug(DBG_PWRLV, "Reduced (%d / %d = %d) because it's not the end of the race\n", prevInc/FRACUNIT, dvs, ourinc/FRACUNIT);
}
}
@ -432,6 +438,8 @@ void K_UpdatePowerLevelsFinalize(player_t *player, boolean onForfeit)
if (checksleft <= 0)
{
if (!(gametyperules & GTR_CHECKPOINTS)) // We should probably do at least _one_ PWR update.
K_UpdatePowerLevels(player, player->gradingpointnum, onForfeit);
// We've done every checkpoint already.
return;
}