Merge branch 'display-exp-fix-3' into 'master'

Exp Fixes

See merge request kart-krew-dev/ring-racers-internal!2513
This commit is contained in:
Oni VelocitOni 2025-05-18 18:52:48 +00:00
commit 146f427dc2
24 changed files with 209 additions and 225 deletions

View file

@ -950,8 +950,8 @@ struct player_t
tic_t laptime[LAP__MAX];
UINT8 laps; // Number of laps (optional)
UINT8 latestlap;
UINT32 lapPoints; // Points given from laps
INT32 exp;
UINT32 exp; // Points given from laps and checkpoints
fixed_t gradingfactor;
UINT16 gradingpointnum; // how many grading points, checkpoint and finishline, you've passed
INT32 cheatchecknum; // The number of the last cheatcheck you hit
INT32 checkpointId; // Players respawn here, objects/checkpoint.cpp

View file

@ -744,6 +744,11 @@ extern int
// Amp scaling
#define MAXAMPSCALINGDIST 18000
// Exp
#define MINEXP 50 // The min value target
#define TARGETEXP 100 // The target value needed for A rank
#define MAXEXP 125 // The max value displayed by the hud and in the tally screen and GP results screen
#ifdef __cplusplus
} // extern "C"
#endif

View file

@ -2211,8 +2211,8 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
INT16 totalring;
UINT8 laps;
UINT8 latestlap;
UINT32 lapPoints;
INT32 exp;
UINT32 exp;
INT32 gradingfactor;
UINT16 gradingpointnum;
UINT16 skincolor;
@ -2417,8 +2417,8 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
khudfault = 0;
laps = 0;
latestlap = 0;
lapPoints = 0;
exp = FRACUNIT;
exp = 0;
gradingfactor = FRACUNIT;
gradingpointnum = 0;
roundscore = 0;
exiting = 0;
@ -2463,8 +2463,8 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
laps = players[player].laps;
latestlap = players[player].latestlap;
lapPoints = players[player].lapPoints;
exp = players[player].exp;
gradingfactor = players[player].gradingfactor;
gradingpointnum = players[player].gradingpointnum;
roundscore = players[player].roundscore;
@ -2589,8 +2589,8 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
p->laps = laps;
p->latestlap = latestlap;
p->lapPoints = lapPoints;
p->exp = exp;
p->gradingfactor = gradingfactor;
p->gradingpointnum = gradingpointnum;
p->totalring = totalring;
@ -4716,8 +4716,8 @@ static void G_DoCompleted(void)
if (grandprixinfo.eventmode == GPEVENT_NONE)
{
grandprixinfo.rank.winPoints += K_CalculateGPRankPoints(player->position, grandprixinfo.rank.totalPlayers);
grandprixinfo.rank.laps += player->lapPoints;
grandprixinfo.rank.winPoints += K_CalculateGPRankPoints(player->exp, grandprixinfo.rank.position, grandprixinfo.rank.totalPlayers);
grandprixinfo.rank.exp += player->exp;
}
else if (grandprixinfo.eventmode == GPEVENT_SPECIAL)
{

View file

@ -51,11 +51,11 @@ UINT8 K_BotStartingDifficulty(SINT8 value)
}
/*--------------------------------------------------
INT16 K_CalculateGPRankPoints(UINT8 position, UINT8 numplayers)
INT16 K_CalculateGPRankPoints(UINT16 diplayexp, UINT8 position, UINT8 numplayers)
See header file for description.
--------------------------------------------------*/
INT16 K_CalculateGPRankPoints(UINT8 position, UINT8 numplayers)
INT16 K_CalculateGPRankPoints(UINT16 exp, UINT8 position, UINT8 numplayers)
{
INT16 points;
@ -65,7 +65,7 @@ INT16 K_CalculateGPRankPoints(UINT8 position, UINT8 numplayers)
return 0;
}
points = numplayers - position;
points = exp;
// Give bonus to high-ranking players, depending on player count
// This rounds out the point gain when you get 1st every race,
@ -79,16 +79,16 @@ INT16 K_CalculateGPRankPoints(UINT8 position, UINT8 numplayers)
case 0: case 1: case 2: // 1v1
break; // No bonus needed.
case 3: case 4: // 3-4P
if (position == 1) { points += 1; } // 1st gets +1 extra point
if (position == 1) { points += 5; } // 1st gets +1 extra point
break;
case 5: case 6: // 5-6P
if (position == 1) { points += 3; } // 1st gets +3 extra points
else if (position == 2) { points += 1; } // 2nd gets +1 extra point
if (position == 1) { points += 10; } // 1st gets +3 extra points
// else if (position == 2) { points += 4; } // 2nd gets +1 extra point
break;
default: // Normal matches
if (position == 1) { points += 5; } // 1st gets +5 extra points
else if (position == 2) { points += 3; } // 2nd gets +3 extra points
else if (position == 3) { points += 1; } // 3rd gets +1 extra point
if (position == 1) { points += 10; } // 1st gets +5 extra points
// else if (position == 2) { points += 5; } // 2nd gets +3 extra points
// else if (position == 3) { points += 2; } // 3rd gets +1 extra point
break;
}

View file

@ -60,7 +60,7 @@ UINT8 K_BotStartingDifficulty(SINT8 value);
/*--------------------------------------------------
INT16 K_CalculateGPRankPoints(UINT8 position, UINT8 numplayers);
INT16 K_CalculateGPRankPoints(player_t* player, UINT8 numplayers);
Calculates the number of points that a player would
recieve if they won the round.
@ -73,7 +73,7 @@ UINT8 K_BotStartingDifficulty(SINT8 value);
Number of points to give.
--------------------------------------------------*/
INT16 K_CalculateGPRankPoints(UINT8 position, UINT8 numplayers);
INT16 K_CalculateGPRankPoints(UINT16 exp, UINT8 position, UINT8 numplayers);
/*--------------------------------------------------

View file

@ -3246,7 +3246,7 @@ static boolean K_drawKartLaps(void)
INT32 bump = 0;
boolean drewsticker = false;
UINT16 displayEXP = K_GetDisplayEXP(stplyr);
UINT16 displayEXP = stplyr->exp;
// Jesus Christ.
// I do not understand the way this system of offsets is laid out at all,
@ -3365,8 +3365,8 @@ static boolean K_drawKartLaps(void)
// WHAT IS THIS?
// WHAT ARE YOU FUCKING TALKING ABOUT?
V_DrawMappedPatch(fr, fy, V_HUDTRANS|V_SLIDEIN|splitflags, kp_exp[1], R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_MUSTARD, GTC_CACHE));
auto transflag = K_GetTransFlagFromFixed(stplyr->exp);
skincolornum_t overlaycolor = stplyr->exp < FRACUNIT ? SKINCOLOR_RUBY : SKINCOLOR_ULTRAMARINE ;
auto transflag = K_GetTransFlagFromFixed(stplyr->gradingfactor);
skincolornum_t overlaycolor = stplyr->gradingfactor < FRACUNIT ? SKINCOLOR_RUBY : SKINCOLOR_ULTRAMARINE ;
auto colormap = R_GetTranslationColormap(TC_RAINBOW, overlaycolor, GTC_CACHE);
V_DrawMappedPatch(fr, fy, transflag|V_SLIDEIN|splitflags, kp_exp[1], colormap);
@ -3382,8 +3382,8 @@ static boolean K_drawKartLaps(void)
V_DrawMappedPatch(LAPS_X+bump, LAPS_Y, V_HUDTRANS|V_SLIDEIN|splitflags, kp_exp[0], R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_MUSTARD, GTC_CACHE));
auto transflag = K_GetTransFlagFromFixed(stplyr->exp);
skincolornum_t overlaycolor = stplyr->exp < FRACUNIT ? SKINCOLOR_RUBY : SKINCOLOR_ULTRAMARINE ;
auto transflag = K_GetTransFlagFromFixed(stplyr->gradingfactor);
skincolornum_t overlaycolor = stplyr->gradingfactor < FRACUNIT ? SKINCOLOR_RUBY : SKINCOLOR_ULTRAMARINE ;
auto colormap = R_GetTranslationColormap(TC_RAINBOW, overlaycolor, GTC_CACHE);
V_DrawMappedPatch(LAPS_X+bump, LAPS_Y, transflag|V_SLIDEIN|splitflags, kp_exp[0], colormap);
@ -6422,7 +6422,7 @@ static void K_DrawGPRankDebugger(void)
V_DrawThinString(0, 10, V_SNAPTOTOP|V_SNAPTOLEFT,
va("PTS: %d / %d", grandprixinfo.rank.winPoints, grandprixinfo.rank.totalPoints));
V_DrawThinString(0, 20, V_SNAPTOTOP|V_SNAPTOLEFT,
va("LAPS: %d / %d", grandprixinfo.rank.laps, grandprixinfo.rank.totalLaps));
va("LAPS: %d / %d", grandprixinfo.rank.exp, grandprixinfo.rank.totalExp));
V_DrawThinString(0, 30, V_SNAPTOTOP|V_SNAPTOLEFT,
va("CONTINUES: %d", grandprixinfo.rank.continuesUsed));
V_DrawThinString(0, 40, V_SNAPTOTOP|V_SNAPTOLEFT,

View file

@ -63,6 +63,7 @@ void K_drawButton(fixed_t x, fixed_t y, INT32 flags, patch_t *button[2], boolean
void K_drawButtonAnim(INT32 x, INT32 y, INT32 flags, patch_t *button[2], tic_t animtic);
void K_DrawSticker(INT32 x, INT32 y, INT32 width, INT32 flags, boolean isSmall);
void K_DrawMarginSticker(INT32 x, INT32 y, INT32 width, INT32 flags, boolean isSmall, boolean leftedge);
INT32 K_GetTransFlagFromFixed(fixed_t value);
void K_DrawKartPositionNumXY(
UINT8 num,

View file

@ -4234,9 +4234,13 @@ void K_CheckpointCrossAward(player_t *player)
if (gametype != GT_RACE)
return;
player->exp += K_GetExpAdjustment(player);
player->gradingfactor += K_GetGradingMultAdjustment(player);
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);
if (!player->cangrabitems)
player->cangrabitems = 1;
K_AwardPlayerRings(player, (player->bot ? 20 : 10), true);
}
@ -13290,7 +13294,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
else
{
UINT32 behind = K_GetItemRouletteDistance(player, player->itemRoulette.playing);
behind = FixedMul(behind, max(player->exp, FRACUNIT/2));
behind = FixedMul(behind, max(player->gradingfactor, FRACUNIT/2));
UINT32 behindMulti = behind / 500;
behindMulti = min(behindMulti, 60);
award = award * (behindMulti + 10) / 10;
@ -15448,10 +15452,10 @@ boolean K_PlayerCanUseItem(player_t *player)
return (player->mo->health > 0 && !player->spectator && !P_PlayerInPain(player) && !mapreset && leveltime > introtime);
}
fixed_t K_GetExpAdjustment(player_t *player)
fixed_t K_GetGradingMultAdjustment(player_t *player)
{
fixed_t exp_power = 3*FRACUNIT/100; // adjust to change overall xp volatility
fixed_t exp_stablerate = 3*FRACUNIT/10; // how low is your placement before losing XP? 4*FRACUNIT/10 = top 40% of race will gain
fixed_t power = 3*FRACUNIT/100; // adjust to change overall xp volatility
fixed_t stablerate = 3*FRACUNIT/10; // how low is your placement before losing XP? 4*FRACUNIT/10 = top 40% of race will gain
fixed_t result = 0;
INT32 live_players = 0; // players we are competing against
@ -15472,7 +15476,7 @@ fixed_t K_GetExpAdjustment(player_t *player)
if (live_players < 8)
{
exp_power += (8 - live_players) * exp_power/4;
power += (8 - live_players) * power/4;
}
// Increase XP for each player you're beating...
@ -15488,30 +15492,25 @@ fixed_t K_GetExpAdjustment(player_t *player)
}
if (player->position < players[i].position)
result += exp_power;
result += power;
}
// ...then take all of the XP 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 XP.
result -= FixedMul(exp_power, FixedMul(live_players*FRACUNIT, FRACUNIT - exp_stablerate));
result -= FixedMul(power, FixedMul(live_players*FRACUNIT, FRACUNIT - stablerate));
return result;
}
UINT16 K_GetDisplayEXP(player_t *player)
UINT16 K_GetEXP(player_t *player)
{
UINT32 numgradingpoints = K_GetNumGradingPoints();
if (!numgradingpoints)
return UINT16_MAX;
// target is where you should be if you're doing good and at a 1.0 mult
fixed_t clampedexp = max(FRACUNIT/2, min(FRACUNIT*7/5, player->exp)); // clamp between 0.5 and 1.4
fixed_t targetdisplayexp = (500*player->gradingpointnum/numgradingpoints)<<FRACBITS;
UINT16 displayexp = FixedMul(clampedexp, targetdisplayexp)>>FRACBITS;
return displayexp;
fixed_t clampedmult = max(FRACUNIT/2, min(FRACUNIT*5/4, player->gradingfactor)); // clamp between 0.5 and 1.25
fixed_t targetexp = (TARGETEXP*player->gradingpointnum/max(1,numgradingpoints))<<FRACBITS;
UINT16 exp = FixedMul(clampedmult, targetexp)>>FRACBITS;
return exp;
}
UINT32 K_GetNumGradingPoints(void)

View file

@ -308,9 +308,9 @@ boolean K_ThunderDome(void);
boolean K_PlayerCanUseItem(player_t *player);
fixed_t K_GetExpAdjustment(player_t *player);
fixed_t K_GetGradingMultAdjustment(player_t *player);
UINT16 K_GetDisplayEXP(player_t *player);
UINT16 K_GetEXP(player_t *player);
UINT32 K_GetNumGradingPoints(void);

View file

@ -138,14 +138,14 @@ void podiumData_s::Init(void)
constexpr INT32 numRaces = 5;
for (INT32 i = 0; i < rank.numPlayers; i++)
{
rank.totalPoints += numRaces * K_CalculateGPRankPoints(i + 1, rank.totalPlayers);
rank.totalPoints += numRaces * K_CalculateGPRankPoints(MAXEXP, i+1, rank.totalPlayers);
}
rank.totalRings = numRaces * rank.numPlayers * 20;
// Randomized winnings
INT32 rgs = 0;
INT32 laps = 0;
INT32 tlaps = 0;
INT32 exp = 0;
INT32 texp = 0;
INT32 prs = 0;
INT32 tprs = 0;
@ -156,7 +156,7 @@ void podiumData_s::Init(void)
gpRank_level_t *const lvl = &rank.levels[i];
UINT8 specialWinner = 0;
UINT16 pprs = 0;
UINT16 plaps = 0;
UINT16 pexp = 0;
lvl->id = M_RandomRange(4, nummapheaders);
@ -179,8 +179,8 @@ void podiumData_s::Init(void)
}
default:
{
lvl->totalLapPoints = M_RandomRange(2, 5) * 2;
tlaps += lvl->totalLapPoints;
lvl->totalExp = TARGETEXP;
texp += lvl->totalExp * rank.numPlayers;
break;
}
}
@ -198,8 +198,8 @@ void podiumData_s::Init(void)
dta->rings = M_RandomRange(0, 20);
rgs += dta->rings;
dta->lapPoints = M_RandomRange(0, lvl->totalLapPoints);
plaps = std::max(plaps, dta->lapPoints);
dta->exp = M_RandomRange(MINEXP, MAXEXP);
pexp += dta->exp;
}
if (lvl->event == GPEVENT_BONUS)
@ -223,13 +223,13 @@ void podiumData_s::Init(void)
}
}
laps += plaps;
exp += pexp;
prs += pprs;
}
rank.rings = rgs;
rank.laps = laps;
rank.totalLaps = tlaps;
rank.exp = exp;
rank.totalExp = texp;
rank.prisons = prs;
rank.totalPrisons = tprs;
}
@ -510,22 +510,22 @@ void podiumData_s::Draw(void)
.font(srb2::Draw::Font::kZVote)
.text(va("%c%d", (rank.scorePosition > 0 ? '+' : ' '), rank.scorePosition));
drawer_winner
.xy(64, 19)
.patch("K_POINT4");
// drawer_winner
// .xy(64, 19)
// .patch("K_POINT4");
drawer_winner
.xy(88, 21)
.align(srb2::Draw::Align::kLeft)
.font(srb2::Draw::Font::kPing)
.colormap(TC_RAINBOW, SKINCOLOR_GOLD)
.text(va("%d", rank.winPoints));
// drawer_winner
// .xy(88, 21)
// .align(srb2::Draw::Align::kLeft)
// .font(srb2::Draw::Font::kPing)
// .colormap(TC_RAINBOW, SKINCOLOR_GOLD)
// .text(va("%d", rank.winPoints));
drawer_winner
.xy(75, 31)
.align(srb2::Draw::Align::kCenter)
.font(srb2::Draw::Font::kZVote)
.text(va("%c%d", (rank.scoreGPPoints > 0 ? '+' : ' '), rank.scoreGPPoints));
// drawer_winner
// .xy(75, 31)
// .align(srb2::Draw::Align::kCenter)
// .font(srb2::Draw::Font::kZVote)
// .text(va("%c%d", (rank.scoreGPPoints > 0 ? '+' : ' '), rank.scoreGPPoints));
srb2::Draw drawer_trophy = drawer.xy(272, 10);
@ -683,15 +683,27 @@ void podiumData_s::Draw(void)
}
default:
{
drawer_gametype
.xy(0, 1)
.patch("K_SPTLAP");
drawer_gametype
.xy(22, 1)
.xy(0, 1)
.colorize(static_cast<skincolornum_t>(SKINCOLOR_MUSTARD))
.patch("K_SPTEXP");
// Colorize the crystal, just like we do for hud
fixed_t factor = FixedDiv(dta->exp*FRACUNIT, lvl->totalExp*FRACUNIT);
skincolornum_t overlaycolor = factor < FRACUNIT ? SKINCOLOR_RUBY : SKINCOLOR_ULTRAMARINE;
if (factor >= FRACUNIT) {factor += factor-FRACUNIT;} // exaggerate the positive side, since reverse engineering the factor like this results in half the translucency range
auto transflag = K_GetTransFlagFromFixed(factor);
drawer_gametype
.xy(0, 1)
.colorize(static_cast<skincolornum_t>(overlaycolor))
.flags(transflag)
.patch("K_SPTEXP");
drawer_gametype
.xy(23, 1)
.align(srb2::Draw::Align::kCenter)
.font(srb2::Draw::Font::kPing)
.text(va("%d/%d", dta->lapPoints, lvl->totalLapPoints));
.text(va("%d", dta->exp));
break;
}
}
@ -751,7 +763,7 @@ void podiumData_s::Draw(void)
.x(-144.0);
srb2::Draw drawer_totals_right = drawer_totals
.x(78.0);
.x(72.0);
if (state == PODIUM_ST_TOTALS_SLIDEIN)
{
@ -807,35 +819,46 @@ void podiumData_s::Draw(void)
.text(va("%c%d", (rank.scoreRings > 0 ? '+' : ' '), rank.scoreRings));
drawer_totals_right
.xy(10.0, 46.0)
.xy(16.0, 49.0)
.patch("CAPS_ZB");
drawer_totals_right
.xy(44.0, 24.0)
.xy(50.0, 24.0)
.align(srb2::Draw::Align::kCenter)
.font(srb2::Draw::Font::kThinTimer)
.text(va("%d / %d", rank.prisons, rank.totalPrisons));
drawer_totals_right
.xy(44.0, 38.0)
.xy(50.0, 38.0)
.align(srb2::Draw::Align::kCenter)
.font(srb2::Draw::Font::kZVote)
.text(va("%c%d", (rank.scorePrisons > 0 ? '+' : ' '), rank.scorePrisons));
drawer_totals_right
.patch("RANKLAPS");
.colorize(static_cast<skincolornum_t>(SKINCOLOR_MUSTARD))
.patch("K_STEXP");
// Colorize the crystal for the totals, just like we do for in race hud
fixed_t factor = FixedDiv((rank.exp+(35*rank.numPlayers-1))*FRACUNIT, rank.totalExp*FRACUNIT); // bump the calc a bit, because its probably not possible for every human to get 125 on every race
skincolornum_t overlaycolor = factor < FRACUNIT ? SKINCOLOR_RUBY : SKINCOLOR_ULTRAMARINE;
if (factor >= FRACUNIT) {factor += factor-FRACUNIT;} // exaggerate the positive side, since reverse engineering the factor like this results in half the translucency range
auto transflag = K_GetTransFlagFromFixed(factor);
drawer_totals_right
.colorize(static_cast<skincolornum_t>(overlaycolor))
.flags(transflag)
.patch("K_STEXP");
drawer_totals_right
.xy(44.0, 0.0)
.xy(50.0, 0.0)
.align(srb2::Draw::Align::kCenter)
.font(srb2::Draw::Font::kThinTimer)
.text(va("%d / %d", rank.laps, rank.totalLaps));
.text(va("%d / %d", rank.exp, rank.totalExp));
drawer_totals_right
.xy(44.0, 14.0)
.xy(50.0, 14.0)
.align(srb2::Draw::Align::kCenter)
.font(srb2::Draw::Font::kZVote)
.text(va("%c%d", (rank.scoreLaps > 0 ? '+' : ' '), rank.scoreLaps));
.text(va("%c%d", (rank.scoreExp > 0 ? '+' : ' '), rank.scoreExp));
}
if ((state == PODIUM_ST_GRADE_APPEAR && delay == 0)

View file

@ -289,7 +289,7 @@ static UINT32 RankCapsules_CountFromMap(const INT32 cupLevelNum)
void gpRank_t::Init(void)
{
UINT8 numHumans = 0;
UINT32 laps = 0;
UINT32 exp = 0;
INT32 i;
memset(this, 0, sizeof(gpRank_t));
@ -322,7 +322,7 @@ void gpRank_t::Init(void)
// (Should this account for all coop players?)
for (i = 0; i < numHumans; i++)
{
totalPoints += grandprixinfo.cup->numlevels * K_CalculateGPRankPoints(i + 1, totalPlayers);
totalPoints += grandprixinfo.cup->numlevels * K_CalculateGPRankPoints(MAXEXP, i+1, totalPlayers);
}
totalRings = grandprixinfo.cup->numlevels * numHumans * 20;
@ -332,14 +332,13 @@ void gpRank_t::Init(void)
const INT32 cupLevelNum = grandprixinfo.cup->cachedlevels[i];
if (cupLevelNum < nummapheaders && mapheaderinfo[cupLevelNum] != NULL)
{
laps += K_RaceLapCount(cupLevelNum);
exp += TARGETEXP;
}
}
// +1, since 1st place laps are worth 2 pts.
for (i = 0; i < numHumans+1; i++)
for (i = 0; i < numHumans; i++)
{
totalLaps += laps;
totalExp += exp;
}
// Search through all of the cup's bonus levels
@ -373,9 +372,8 @@ void gpRank_t::Rejigger(UINT16 removedmap, UINT16 removedgt, UINT16 addedmap, UI
{
for (i = 0; i < numPlayers; i++)
{
deltaPoints += K_CalculateGPRankPoints(i + 1, totalPlayers);
deltaPoints += K_CalculateGPRankPoints(MAXEXP, i + 1, totalPlayers);
}
if (addedgt == GT_RACE)
totalPoints += deltaPoints;
else if (totalPoints > deltaPoints)
@ -384,7 +382,7 @@ void gpRank_t::Rejigger(UINT16 removedmap, UINT16 removedgt, UINT16 addedmap, UI
totalPoints = 0;
}
INT32 deltaLaps = 0;
INT32 deltaExp = 0;
INT32 deltaPrisons = 0;
INT32 deltaRings = 0;
@ -393,12 +391,7 @@ void gpRank_t::Rejigger(UINT16 removedmap, UINT16 removedgt, UINT16 addedmap, UI
{
if (removedgt == GT_RACE)
{
// AGH CAN'T USE, gametype already possibly not GT_RACE...
//deltaLaps -= K_RaceLapCount(removedmap);
if (cv_numlaps.value == -1)
deltaLaps -= mapheaderinfo[removedmap]->numlaps;
else
deltaLaps -= cv_numlaps.value;
deltaExp -= TARGETEXP;
}
if ((gametypes[removedgt]->rules & GTR_SPHERES) == 0)
{
@ -415,7 +408,7 @@ void gpRank_t::Rejigger(UINT16 removedmap, UINT16 removedgt, UINT16 addedmap, UI
{
if (addedgt == GT_RACE)
{
deltaLaps += K_RaceLapCount(addedmap);
deltaExp += TARGETEXP;
}
if ((gametypes[addedgt]->rules & GTR_SPHERES) == 0)
{
@ -427,26 +420,13 @@ void gpRank_t::Rejigger(UINT16 removedmap, UINT16 removedgt, UINT16 addedmap, UI
}
}
if (deltaLaps)
if (deltaExp)
{
INT32 workingTotalLaps = totalLaps;
// +1, since 1st place laps are worth 2 pts.
for (i = 0; i < numPlayers+1; i++)
{
workingTotalLaps += deltaLaps;
}
if (workingTotalLaps > 0)
totalLaps = workingTotalLaps;
deltaExp += totalExp;
if (deltaExp > 0)
totalExp = deltaExp;
else
totalLaps = 0;
deltaLaps += laps;
if (deltaLaps > 0)
laps = deltaLaps;
else
laps = 0;
totalExp = 0;
}
if (deltaPrisons)
@ -512,7 +492,7 @@ void gpRank_t::Update(void)
lvl->time = UINT32_MAX;
lvl->totalLapPoints = 500;
lvl->totalExp = TARGETEXP;
lvl->totalPrisons = maptargets;
UINT8 i;
@ -554,7 +534,7 @@ void gpRank_t::Update(void)
dta->position = player->tally.position;
dta->rings = player->tally.rings;
dta->lapPoints = player->tally.laps;
dta->exp = player->tally.exp;
dta->prisons = player->tally.prisons;
dta->gotSpecialPrize = !!!(player->pflags & PF_NOCONTEST);
dta->grade = static_cast<gp_rank_e>(player->tally.rank);
@ -595,16 +575,16 @@ gp_rank_e K_CalculateGPGrade(gpRank_t *rankData)
rankData->scorePosition = 0;
rankData->scoreGPPoints = 0;
rankData->scoreLaps = 0;
rankData->scoreExp = 0;
rankData->scorePrisons = 0;
rankData->scoreRings = 0;
rankData->scoreContinues = 0;
rankData->scoreTotal = 0;
const INT32 lapsWeight = (rankData->totalLaps > 0) ? RANK_WEIGHT_LAPS : 0;
const INT32 expWeight = (rankData->totalExp > 0) ? RANK_WEIGHT_EXP : 0;
const INT32 prisonsWeight = (rankData->totalPrisons > 0) ? RANK_WEIGHT_PRISONS : 0;
const INT32 total = RANK_WEIGHT_POSITION + RANK_WEIGHT_SCORE + lapsWeight + prisonsWeight + RANK_WEIGHT_RINGS;
const INT32 total = RANK_WEIGHT_POSITION + expWeight + prisonsWeight + RANK_WEIGHT_RINGS;
const INT32 continuesPenalty = total / RANK_CONTINUE_PENALTY_DIV;
if (rankData->position > 0)
@ -619,9 +599,9 @@ gp_rank_e K_CalculateGPGrade(gpRank_t *rankData)
rankData->scoreGPPoints += (rankData->winPoints * RANK_WEIGHT_SCORE) / rankData->totalPoints;
}
if (rankData->totalLaps > 0)
if (rankData->totalExp > 0)
{
rankData->scoreLaps += (rankData->laps * lapsWeight) / rankData->totalLaps;
rankData->scoreExp += (std::min(rankData->exp, rankData->totalExp) * expWeight) / rankData->totalExp;
}
if (rankData->totalPrisons > 0)
@ -638,8 +618,8 @@ gp_rank_e K_CalculateGPGrade(gpRank_t *rankData)
rankData->scoreTotal =
rankData->scorePosition +
rankData->scoreGPPoints +
rankData->scoreLaps +
// rankData->scoreGPPoints +
rankData->scoreExp +
rankData->scorePrisons +
rankData->scoreRings +
rankData->scoreContinues;

View file

@ -21,7 +21,7 @@ struct gpRank_level_perplayer_t
{
UINT8 position;
UINT8 rings;
UINT16 lapPoints;
UINT16 exp;
UINT16 prisons;
boolean gotSpecialPrize;
gp_rank_e grade;
@ -32,7 +32,7 @@ struct gpRank_level_t
UINT16 id;
INT32 event;
UINT32 time;
UINT16 totalLapPoints;
UINT16 totalExp;
UINT16 totalPrisons;
gpRank_level_perplayer_t perPlayer[MAXSPLITSCREENPLAYERS];
};
@ -49,8 +49,8 @@ struct gpRank_t
UINT32 winPoints;
UINT32 totalPoints;
UINT32 laps;
UINT32 totalLaps;
UINT32 exp;
UINT32 totalExp;
UINT32 continuesUsed;
@ -64,7 +64,7 @@ struct gpRank_t
INT32 scorePosition;
INT32 scoreGPPoints;
INT32 scoreLaps;
INT32 scoreExp;
INT32 scorePrisons;
INT32 scoreRings;
INT32 scoreContinues;
@ -91,7 +91,7 @@ extern "C" {
#define RANK_WEIGHT_POSITION (150)
#define RANK_WEIGHT_SCORE (100)
#define RANK_WEIGHT_LAPS (100)
#define RANK_WEIGHT_EXP (100)
#define RANK_WEIGHT_PRISONS (100)
#define RANK_WEIGHT_RINGS (50)

View file

@ -486,8 +486,8 @@ static UINT32 K_ScaleItemDistance(const player_t *player, UINT32 distance, UINT8
FRACUNIT + (K_ItemOddsScale(numPlayers) / 2)
);
// Distance is reduced based on the player's exp
// distance = FixedMul(distance, player->exp);
// Distance is reduced based on the player's gradingfactor
// distance = FixedMul(distance, player->gradingfactor);
return distance;
}
@ -1382,7 +1382,7 @@ void K_FillItemRouletteData(const player_t *player, itemroulette_t *const roulet
if ((gametyperules & GTR_CIRCUIT) && !K_Cooperative())
{
roulette->dist = FixedMul(roulette->preexpdist, max(player->exp, FRACUNIT/2));
roulette->dist = FixedMul(roulette->preexpdist, max(player->gradingfactor, FRACUNIT/2));
}
// ===============================================================================

View file

@ -92,11 +92,11 @@ void level_tally_t::DetermineBonuses(void)
}
}
if (totalLaps > 0)
if (totalExp > 0)
{
// Give circuit gamemodes a consolation bonus
// for getting good placements on each lap.
temp_bonuses.push_back(TALLY_BONUS_LAP);
// for getting good placements on each grading point.
temp_bonuses.push_back(TALLY_BONUS_EXP);
}
if (totalPrisons > 0)
@ -203,7 +203,7 @@ INT32 level_tally_t::CalculateGrade(void)
bonusWeights[i] = ((pointLimit != 0) ? 100 : 0);
break;
}
case TALLY_BONUS_LAP:
case TALLY_BONUS_EXP:
case TALLY_BONUS_PRISON:
case TALLY_BONUS_POWERSTONES:
{
@ -240,12 +240,13 @@ INT32 level_tally_t::CalculateGrade(void)
ours += (rings * bonusWeights[i]) / 20;
break;
}
case TALLY_BONUS_LAP:
case TALLY_BONUS_EXP:
{
// Use a special curve for this.
// Low Exp amounts are guaranteed, higher than half is where skill expression starts
const fixed_t frac = std::min(FRACUNIT, (laps * FRACUNIT) / std::max(1, static_cast<int>(totalLaps + 80))); // Magic number here is to ensure A ranks only go to those that can maintain positive EXP
ours += Easing_InCubic(frac, 0, bonusWeights[i]);
// Magic numbers here are to reduce the range from 50-125 to 0-75 and compare with a max of 58, 85% of which is 49.3, which should put an even 100 or higher exp at A rank
const fixed_t frac = std::min(FRACUNIT, ((exp-50) * FRACUNIT) / std::max(1, static_cast<int>(totalExp-42)));
ours += Easing_Linear(frac, 0, bonusWeights[i]);
break;
}
case TALLY_BONUS_PRISON:
@ -309,7 +310,7 @@ void level_tally_t::Init(player_t *player)
position = numPlayers = 0;
rings = 0;
laps = totalLaps = 0;
exp = totalExp = 0;
points = pointLimit = 0;
powerStones = 0;
releasedFastForward = false;
@ -342,12 +343,10 @@ void level_tally_t::Init(player_t *player)
if ((gametypes[gt]->rules & GTR_CIRCUIT) == GTR_CIRCUIT)
{
UINT16 displayEXP = K_GetDisplayEXP(player);
if (displayEXP != UINT16_MAX)
if (player->exp)
{
laps = displayEXP;
totalLaps = 500;
exp = player->exp;
totalExp = TARGETEXP;
}
}
@ -663,8 +662,8 @@ boolean level_tally_t::IncrementLine(void)
amount = 1;
freq = 1;
break;
case TALLY_BONUS_LAP:
dest = laps;
case TALLY_BONUS_EXP:
dest = exp;
amount = 20;
freq = 1;
break;
@ -1189,7 +1188,7 @@ void level_tally_t::Draw(void)
case TALLY_BONUS_RING:
bonus_code = "RB";
break;
case TALLY_BONUS_LAP:
case TALLY_BONUS_EXP:
bonus_code = "LA";
break;
case TALLY_BONUS_PRISON:
@ -1320,12 +1319,12 @@ void level_tally_t::Draw(void)
.text(va("%d / 20", displayBonus[i]));
break;
}
case TALLY_BONUS_LAP:
case TALLY_BONUS_EXP:
{
drawer_text
.x(197.0 * frac)
.align(srb2::Draw::Align::kCenter)
.text(va("%d / %d", displayBonus[i], totalLaps));
.text(va("%d / %d", displayBonus[i], totalExp));
break;
}
case TALLY_BONUS_PRISON:

View file

@ -33,7 +33,7 @@ typedef enum
{
TALLY_BONUS_NA,
TALLY_BONUS_RING,
TALLY_BONUS_LAP,
TALLY_BONUS_EXP,
TALLY_BONUS_PRISON,
TALLY_BONUS_SCORE,
TALLY_BONUS_POWERSTONES,
@ -77,7 +77,7 @@ struct level_tally_t
// Possible grade metrics
UINT8 position, numPlayers;
UINT8 rings;
UINT16 laps, totalLaps;
UINT16 exp, totalExp;
UINT16 prisons, totalPrisons;
INT32 points, pointLimit;
UINT8 powerStones;

View file

@ -1817,8 +1817,8 @@ boolean M_CheckCondition(condition_t *cn, player_t *player)
&& M_NotFreePlay()
&& (gamespeed != KARTSPEED_EASY)
&& (player->tally.active == true)
&& (player->tally.totalLaps > 0) // Only true if not Time Attack
&& (player->tally.laps >= player->tally.totalLaps));
&& (player->tally.totalExp > 0) // Only true if not Time Attack
&& (player->tally.exp >= player->tally.totalExp));
case UCRP_FINISHALLPRISONS:
return (battleprisons
&& !(player->pflags & PF_NOCONTEST)

View file

@ -37,7 +37,6 @@ struct MobjList
{
ptr->next(front());
front(ptr);
count_++;
}
void erase(T* node)
@ -46,7 +45,6 @@ struct MobjList
{
front(node->next());
node->next(nullptr);
count_--;
return;
}
@ -71,21 +69,25 @@ struct MobjList
{
prev->next(node->next());
node->next(nullptr);
count_--;
break;
}
}
}
void clear()
{
while (!empty())
{
erase(front());
}
}
auto begin() const { return view().begin(); }
auto end() const { return view().end(); }
auto count() { return count_; }
private:
void front(T* ptr) { Mobj::ManagedPtr {Head} = ptr; }
auto view() const { return MobjListView(front(), [](T* node) { return node->next(); }); }
UINT32 count_ = 0;
};
}; // namespace srb2

View file

@ -497,14 +497,20 @@ struct CheckpointManager
if (chk->linetag())
lines_.try_emplace(chk->linetag(), std::move(tagged_lines(chk->linetag())));
list_.push_front(chk);
count_ += 1; // Mobjlist can't have a count on it, so we keep it here
}
chk->gingerbread();
}
void clear() { lines_.clear(); }
void clear()
{
lines_.clear();
list_.clear();
count_ = 0;
}
auto count() { return list_.count(); }
auto count() { return count_; }
const srb2::Vector<line_t*>* lines_for(const Checkpoint* chk) const
{
@ -513,6 +519,7 @@ struct CheckpointManager
}
private:
INT32 count_;
srb2::MobjList<Checkpoint, svg_checkpoints> list_;
srb2::HashMap<INT32, srb2::Vector<line_t*>> lines_;
@ -558,7 +565,7 @@ void Obj_CheckpointThink(mobj_t* end)
chk->animate();
}
void __attribute__((optimize("O0"))) Obj_CrossCheckpoints(player_t* player, fixed_t old_x, fixed_t old_y)
void Obj_CrossCheckpoints(player_t* player, fixed_t old_x, fixed_t old_y)
{
LineOnDemand ray(old_x, old_y, player->mo->x, player->mo->y, player->mo->radius);
@ -658,20 +665,7 @@ void __attribute__((optimize("O0"))) Obj_CrossCheckpoints(player_t* player, fixe
player->checkpointId = chk->id();
if (D_NumPlayersInRace() > 1 && !K_IsPlayerLosing(player))
{
if (player->position == 1)
{
player->lapPoints += 2;
}
else
{
player->lapPoints += 1;
}
}
K_CheckpointCrossAward(player);
player->gradingpointnum++;
K_UpdatePowerLevels(player, player->laps, false);
}

View file

@ -430,10 +430,6 @@ void Obj_PlayerUsedRingShooter(mobj_t *base, player_t *player)
return;
}
// The original player should no longer have control over it,
// if they are using it via releasing.
RemoveRingShooterPointer(base);
// Respawn using the respawner's karted value.
if (rs_base_karted(base) > 0)
{

View file

@ -206,7 +206,7 @@ void Obj_playerWPZTurbine(player_t *p)
fixed_t momz;
if (!t || P_MobjWasRemoved(t) || p->respawn.state != RESPAWNST_NONE)
if (!t || P_MobjWasRemoved(t) || t->type != MT_WATERPALACETURBINE || !t->spawnpoint || p->respawn.state != RESPAWNST_NONE)
{
p->turbine = false;
P_SetTarget(&pmo->tracer, NULL);

View file

@ -9081,8 +9081,8 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
(newplayer != NULL)
&& (gamespeed != KARTSPEED_EASY)
&& (newplayer->tally.active == true)
&& (newplayer->tally.totalLaps > 0) // Only true if not Time Attack
&& (newplayer->tally.laps >= newplayer->tally.totalLaps)
&& (newplayer->tally.totalExp > 0) // Only true if not Time Attack
&& (newplayer->tally.exp >= newplayer->tally.totalExp)
)
{
UINT8 pnum = (newplayer-players);

View file

@ -288,8 +288,8 @@ static void P_NetArchivePlayers(savebuffer_t *save)
}
WRITEUINT8(save->p, players[i].laps);
WRITEUINT8(save->p, players[i].latestlap);
WRITEUINT32(save->p, players[i].lapPoints);
WRITEINT32(save->p, players[i].exp);
WRITEUINT32(save->p, players[i].exp);
WRITEINT32(save->p, players[i].gradingfactor);
WRITEUINT16(save->p, players[i].gradingpointnum);
WRITEINT32(save->p, players[i].cheatchecknum);
WRITEINT32(save->p, players[i].checkpointId);
@ -846,8 +846,8 @@ static void P_NetArchivePlayers(savebuffer_t *save)
WRITEUINT8(save->p, players[i].tally.position);
WRITEUINT8(save->p, players[i].tally.numPlayers);
WRITEUINT8(save->p, players[i].tally.rings);
WRITEUINT16(save->p, players[i].tally.laps);
WRITEUINT16(save->p, players[i].tally.totalLaps);
WRITEUINT16(save->p, players[i].tally.exp);
WRITEUINT16(save->p, players[i].tally.totalExp);
WRITEUINT16(save->p, players[i].tally.prisons);
WRITEUINT16(save->p, players[i].tally.totalPrisons);
WRITEINT32(save->p, players[i].tally.points);
@ -980,8 +980,8 @@ static void P_NetUnArchivePlayers(savebuffer_t *save)
}
players[i].laps = READUINT8(save->p); // Number of laps (optional)
players[i].latestlap = READUINT8(save->p);
players[i].lapPoints = READUINT32(save->p);
players[i].exp = READINT32(save->p);
players[i].exp = READUINT32(save->p);
players[i].gradingfactor = READINT32(save->p);
players[i].gradingpointnum = READUINT16(save->p);
players[i].cheatchecknum = READINT32(save->p);
players[i].checkpointId = READINT32(save->p);
@ -1505,8 +1505,8 @@ static void P_NetUnArchivePlayers(savebuffer_t *save)
players[i].tally.position = READUINT8(save->p);
players[i].tally.numPlayers = READUINT8(save->p);
players[i].tally.rings = READUINT8(save->p);
players[i].tally.laps = READUINT16(save->p);
players[i].tally.totalLaps = READUINT16(save->p);
players[i].tally.exp = READUINT16(save->p);
players[i].tally.totalExp = READUINT16(save->p);
players[i].tally.prisons = READUINT16(save->p);
players[i].tally.totalPrisons = READUINT16(save->p);
players[i].tally.points = READINT32(save->p);
@ -6359,8 +6359,8 @@ static inline void P_ArchiveMisc(savebuffer_t *save)
WRITEUINT32(save->p, rank->winPoints);
WRITEUINT32(save->p, rank->totalPoints);
WRITEUINT32(save->p, rank->laps);
WRITEUINT32(save->p, rank->totalLaps);
WRITEUINT32(save->p, rank->exp);
WRITEUINT32(save->p, rank->totalExp);
WRITEUINT32(save->p, (rank->continuesUsed + 1));
@ -6374,7 +6374,7 @@ static inline void P_ArchiveMisc(savebuffer_t *save)
WRITEINT32(save->p, rank->scorePosition);
WRITEINT32(save->p, rank->scoreGPPoints);
WRITEINT32(save->p, rank->scoreLaps);
WRITEINT32(save->p, rank->scoreExp);
WRITEINT32(save->p, rank->scorePrisons);
WRITEINT32(save->p, rank->scoreRings);
WRITEINT32(save->p, rank->scoreContinues);
@ -6397,7 +6397,7 @@ static inline void P_ArchiveMisc(savebuffer_t *save)
WRITEINT32(save->p, lvl->event);
WRITEUINT32(save->p, lvl->time);
WRITEUINT16(save->p, lvl->totalLapPoints);
WRITEUINT16(save->p, lvl->totalExp);
WRITEUINT16(save->p, lvl->totalPrisons);
UINT8 j;
@ -6407,7 +6407,7 @@ static inline void P_ArchiveMisc(savebuffer_t *save)
WRITEUINT8(save->p, plr->position);
WRITEUINT8(save->p, plr->rings);
WRITEUINT16(save->p, plr->lapPoints);
WRITEUINT16(save->p, plr->exp);
WRITEUINT16(save->p, plr->prisons);
WRITEUINT8(save->p, (UINT8)plr->gotSpecialPrize);
WRITESINT8(save->p, (SINT8)plr->grade);
@ -6621,8 +6621,8 @@ static boolean P_UnArchiveSPGame(savebuffer_t *save)
rank->winPoints = READUINT32(save->p);
rank->totalPoints = READUINT32(save->p);
rank->laps = READUINT32(save->p);
rank->totalLaps = READUINT32(save->p);
rank->exp = READUINT32(save->p);
rank->totalExp = READUINT32(save->p);
rank->continuesUsed = READUINT32(save->p);
@ -6636,7 +6636,7 @@ static boolean P_UnArchiveSPGame(savebuffer_t *save)
rank->scorePosition = READINT32(save->p);
rank->scoreGPPoints = READINT32(save->p);
rank->scoreLaps = READINT32(save->p);
rank->scoreExp = READINT32(save->p);
rank->scorePrisons = READINT32(save->p);
rank->scoreRings = READINT32(save->p);
rank->scoreContinues = READINT32(save->p);
@ -6685,7 +6685,7 @@ static boolean P_UnArchiveSPGame(savebuffer_t *save)
lvl->event = READINT32(save->p);
lvl->time = READUINT32(save->p);
lvl->totalLapPoints = READUINT16(save->p);
lvl->totalExp = READUINT16(save->p);
lvl->totalPrisons = READUINT16(save->p);
for (j = 0; j < rank->numPlayers; j++)
@ -6694,7 +6694,7 @@ static boolean P_UnArchiveSPGame(savebuffer_t *save)
plr->position = READUINT8(save->p);
plr->rings = READUINT8(save->p);
plr->lapPoints = READUINT16(save->p);
plr->exp = READUINT16(save->p);
plr->prisons = READUINT16(save->p);
plr->gotSpecialPrize = (boolean)READUINT8(save->p);
plr->grade = (gp_rank_e)READSINT8(save->p);

View file

@ -2109,20 +2109,7 @@ static void K_HandleLapIncrement(player_t *player)
// Update power levels for this lap.
K_UpdatePowerLevels(player, player->laps, false);
if (nump > 1 && K_IsPlayerLosing(player) == false)
{
if (inDuel == false && player->position == 1) // 1st place in 1v1 uses thumbs up
{
player->lapPoints += 2;
}
else
{
player->lapPoints++;
}
}
K_CheckpointCrossAward(player);
player->gradingpointnum++;
if (player->position == 1 && !(gametyperules & GTR_CHECKPOINTS))
{

View file

@ -50,6 +50,7 @@
#include "k_hud.h" // K_DrawMapThumbnail
#include "k_battle.h"
#include "k_boss.h"
#include "k_kart.h"
#include "k_pwrlv.h"
#include "k_grandprix.h"
#include "k_serverstats.h" // SV_BumpMatchStats
@ -308,7 +309,7 @@ static void Y_CalculateMatchData(UINT8 rankingsmode, void (*comparison)(INT32))
if (data.pos[data.numplayers] < pointgetters
&& !(players[i].pflags & PF_NOCONTEST))
{
data.increase[i] = K_CalculateGPRankPoints(data.pos[data.numplayers], pointgetters);
data.increase[i] = K_CalculateGPRankPoints((&players[i])->exp, data.pos[data.numplayers], pointgetters);
}
}
@ -2195,10 +2196,7 @@ static UINT32 Y_EstimatePodiumScore(player_t *const player, UINT8 numPlaying)
UINT8 pos = Y_PlayersBestPossiblePosition(player);
UINT32 ourScore = player->score;
if (pos < numPlaying)
{
ourScore += K_CalculateGPRankPoints(pos, numPlaying);
}
ourScore += K_CalculateGPRankPoints(player->exp, pos, numPlaying);
return ourScore;
}